静音モーター見つけたので カーテン開閉器 自作3号機 に使用 | ドタバッタンのブログ

ドタバッタンのブログ

DIY、電子工作系

2017年、市販のカーテン開閉器「モーニン」 を購入。

2019年、自作しましたが、作動音についてはほとんど改善できませんでした。

2021年 今回、いいモーターを見つけたので、また自作しました。

 

安価で小型で低速回転するモーターを、ネット(ブログや動画)で調べ、Amazonで購入しました。

 「KKHMF  28BYJ-48 5V ステッピングモーター

  + ULN2003ステッピングモーター駆動テストモジュールボード

  2個セット599円」

 


ESP32で動かすためのプログラムは、

https://stupiddog.jp/note/archives/1235

「ステッピングモーター(28BYJ-48)の動かし方 (ULN2003A使用)」からコピペさせてもらいました。自分では作れないので、助かります。


モーターの音ですが、静音というか、ほぼ無音です。

カーテン開閉器を組み立ててでカーテンを引いたとき、

モーター音よりもカーテンランナーの「カチャ、カチャ」という音のほうが気になるぐらいです。(静音のランナーを買おうかと思っています。)


1.ハードウェア

 

バラ部品

・ステッピングモータ 28BYJ-48

 (モータ2個+ドライバ回路2個のセットで599円)

・ゴムタイヤ(タミヤ TRUCK TIRE SET 36mm DIA)

・PPワッシャ(クリアフォルダを円形にカット。

 タイヤがアクリルと接触したときの摩擦を減らす)

・シリコン輪ゴム

・パッチリランナー(ホームセンターなどのカーテン売り場で。

 とびこみランナー、SCランナー 等の商品名)

・タイヤとモータをつなぐ部品(3Dプリンタで自作)

・ランナーを保持する部品(3Dプリンタで自作)

・アクリル板にドリルで穴を開けたもの 2枚

・ほか ボルト、ナット、スペーサ、インシュロック など。

 

組立後の写真

制御回路 バラ部品

・ESP32-DevKitC ESP-WROOM-32開発ボード(秋月電子)

・ULN2003ステッピングモーター駆動テストモジュールボード

 (Amazonでモータとセット販売)

・電源用マイクロUSBコネクタDIP化キット(秋月電子)

・ピンソケット (秋月電子)

 

モーターとドライバボードを接続する延長コード

・電線 (Amazonにて 耐熱通信機器用ビニル電線 白 10m H-PVC 0.65mm)

・XHコネクタ ベース付ポスト トップ型 5P B5B-XH-A(秋月電子)

・XHP-5XHコネクタ ハウジング (秋月電子)

・XHコネクタ ハウジング用コンタクト SXH-001T-P0.6 (秋月電子)

 

制御回路 接続後の写真

回路図(部品が少なく、ブレッドボードがなくてもいいです)


2.プログラム

1つめのタブ 
#include <WiFi.h>
#include <ESPmDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>

const char* ssid = "●SSIDを入れる";   //WiFi用 
const char* password = "●パスをいれる";  //WiFi用 

void setup() {
  Serial.begin(115200);
  Serial.println("Booting");
  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);
  while (WiFi.waitForConnectResult() != WL_CONNECTED) {
    Serial.println("Connection Failed! Rebooting...");
    delay(5000);
    ESP.restart();
  }

  ArduinoOTA
    .onStart([]() {
      String type;
      if (ArduinoOTA.getCommand() == U_FLASH)
        type = "sketch";
      else // U_SPIFFS
        type = "filesystem";
      Serial.println("Start updating " + type);
    })
    .onEnd([]() {
      Serial.println("\nEnd");
    })
    .onProgress([](unsigned int progress, unsigned int total) {
      Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
    })
    .onError([](ota_error_t error) {
      Serial.printf("Error[%u]: ", error);
      if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
      else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
      else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
      else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
      else if (error == OTA_END_ERROR) Serial.println("End Failed");
    });

  ArduinoOTA.begin();

  Serial.println("Ready");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  motor_setup();
}

void loop() {
  ArduinoOTA.handle();
  motor_loop();
}
2つめのタブ
#include <esp_deep_sleep.h> //スリープのための
#include <stdio.h>     //曜日を計算
#include <string>     //文字列が一致するか比較
#include <Stepper.h>   //ステッピングモータ用
#include <ArduinoJson.h>
#include <esp_deep_sleep.h> //ディープスリープのための

const int MOTOR_1 = 32;  //ピン
const int MOTOR_2 = 33;
const int MOTOR_3 = 25;
const int MOTOR_4 = 26;

#define MOTOR_STEPS (2048)

char* yyk_L="06:30"; //"05:30";     //朝、起床前に開ける時刻。
char* yyk_asaR = "07:30"; //朝、出かける前にちょっと閉める時刻
char* yyk_yoruR[] = {"0","17:30","18:00","18:30",
        "19:00","19:30","19:30",
        "19:30","19:00","18:30",
        "18:00","17:00","17:00"};  //夜 閉める時刻 1~12月
struct tm timeInfo;//時刻を格納するオブジェクト
char datetime[25];//日付と時刻文字格納用
char hhmm1[20];//時刻文字格納用

// ライブラリが想定している配線が異なるので2番、3番を入れ替える
Stepper myStepper(MOTOR_STEPS, MOTOR_1, MOTOR_3, MOTOR_2, MOTOR_4);

void motor_setup() {
  Serial.begin(115200);  // シリアルモニタのウインドウ 115200bpsの画面にてログを表示。
  Serial.println("Start ---------------");  
  configTime(9 * 3600L, 0, "ntp.nict.jp", "time.google.com", "ntp.jst.mfeed.ad.jp");//NTPの設定
  pinMode(MOTOR_1, OUTPUT);
  pinMode(MOTOR_2, OUTPUT);
  pinMode(MOTOR_3, OUTPUT);
  pinMode(MOTOR_4, OUTPUT);
  myStepper.setSpeed(10);

   // ここから スリープに必要な記述
  esp_deep_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_OFF);
  esp_deep_sleep_pd_config(ESP_PD_DOMAIN_RTC_SLOW_MEM, ESP_PD_OPTION_OFF);
  esp_deep_sleep_pd_config(ESP_PD_DOMAIN_RTC_FAST_MEM, ESP_PD_OPTION_OFF);
  esp_deep_sleep_pd_config(ESP_PD_DOMAIN_MAX, ESP_PD_OPTION_OFF); 
}


// モーターへの電流を止める
void stopMotor() {
  digitalWrite(MOTOR_1, LOW);
  digitalWrite(MOTOR_2, LOW);
  digitalWrite(MOTOR_3, LOW);
  digitalWrite(MOTOR_4, LOW);
}

void kaiten(float r1){   //何cm動かすか を受け取る
  int r2=r1 * 178;    // cm指示値✕係数178で回転実行の数値を出す。2048でモーターを360°回転させる。
  Serial.println(r2);
  myStepper.step(r2);  // 回転実行 2048で360度。タミヤのタイヤで115mm進む。
  stopMotor();   // 電流を止める
  delay(60*1000);   //すぐにLoopに戻ると、また指定時刻に該当して動いてしまうので、待つ。
}


//時刻合わせを行う関数
void syncTime() {
  configTime(-9 * 3600L, 0, "ntp.nict.jp", "time.google.com", "ntp.jst.mfeed.ad.jp");
}


// Zeller の公式で週の何日目か調べる。 0が日曜。
int subZeller( int y, int m, int d )
{
    if( m < 3 ) {
        y--; m += 12;
    }
    return ( y + y/4 - y/100 + y/400 + ( 13*m + 8 )/5 + d )%7;
}

// Zeller の公式で週の何日目か調べる。 0が日曜。
int subSatSun( int y, int m, int d )
{
  int yobicode=subZeller(y,m,d); //日付より、曜日コード。
  if( yobicode==0||yobicode==6 ) {    //日曜または土曜ならば
    return 1;
  } else {
    return 0; //平日はゼロを返す
  }
}

void motor_loop() {
  getLocalTime(&timeInfo);//tmオブジェクトのtimeInfoに現在時刻を入れ込む
  sprintf(datetime, " %04d/%02d/%02d %02d:%02d_%02d",
          timeInfo.tm_year + 1900, timeInfo.tm_mon + 1, timeInfo.tm_mday,
          timeInfo.tm_hour, timeInfo.tm_min, timeInfo.tm_sec); //人間が読める形式に変換 文字列に書き込む
  Serial.print(datetime);  //時間をシリアルモニタへ出力
  Serial.println(".");  //
  sprintf(hhmm1, "%02d:%02d",
          timeInfo.tm_hour, timeInfo.tm_min); //人間が読める形式に変換 文字列に書き込む
  Serial.print(".");  //
  int month1=timeInfo.tm_mon + 1;
  Serial.print(".");  //
  int min1=timeInfo.tm_min; //現在時刻の中の分。
  int SatSun=subSatSun(timeInfo.tm_year + 1900, timeInfo.tm_mon + 1, timeInfo.tm_mday); //土日が1となる
  delay(1000);

  if ("TEST MODE"=="xxxTEST MODE"){  //メンテ・開発用。繰り返す。
      myStepper.step(-10680);  // 回転実行 10680は理論上60cm進むが、スリップするので実際45cmぐらい。
      ArduinoOTA.handle();
      delay(10000);  //10秒停止
      ArduinoOTA.handle();
      myStepper.step(10680);  // 回転実行。
      ArduinoOTA.handle();
      delay(10000);  //停止
  }
  
  if (min1==5 || min1==35){    //1時間に2回スリープに入る
    Serial.println("good night!");
    uint64_t sleepTime= uint64_t(60*20);// 20分間 と設定
    esp_deep_sleep_enable_timer_wakeup(uint64_t(sleepTime*1000000L));
    esp_deep_sleep_start();   //スリープに
  }

  if (!strcmp(hhmm1,yyk_L)) {                  //朝の開ける時刻なら
    kaiten(-60); //左に動かす cm
    String msg1 = datetime + String(" Open ");
  } else if (!strcmp(hhmm1,yyk_asaR) && SatSun==0) {  //出かける前にちょっと閉める時刻、平日なら
    kaiten(30); //右に動かす cm
    String msg1 = datetime + String(" Half Close ");
  } else if (!strcmp(hhmm1,yyk_yoruR[month1]) && SatSun==0) {  //夜に閉める時刻 が含まれ、平日なら
    kaiten(30); //右に動かす cm
    String msg1 = datetime + String(" Half Close ");
  } else if (!strcmp(hhmm1,yyk_yoruR[month1]) && SatSun==1) {  //夜に閉める時刻 が含まれ、土日なら
    kaiten(60); //右に動かす cm  ←21年4月19日 誤記訂正
    String msg1 = datetime + String(" Full Close ");
  }

  delay(5000);  //長いスリープやディレイにせず、プログラム上書き可能なよう待機。

}

 

 

.