Arduino自動カーテンオープン目覚まし時計

計画

朝になったら自動でカーテンを開ける目覚まし時計を作りたい。
カーテンの端っこにひもを引っかけて朝になったらタイマーが作動してひもを巻き取りカーテンが開くという仕組み。

材料


消費電流

RE-260 http://www.mabuchi-motor.co.jp/motorize/branch/b_0100.html
適正電圧適正負荷で700mA
負荷によって変わるだろうから動作させながら実測する!

6速ギヤボックスHE

広いギヤ比に組み替えられるのでとりあえずこれにした。
クラッチギアが付いているので大きい負荷がかかっても少し安心。

完成品は

  • mega88 Arduino内蔵クロックで動かす。
  • 過電流で電源を止めるやつをつける。ポリスイッチ?

電源

  • 開発時はUSB 5V
  • ACアダプタ
  • 5V or 3V
http://www.switch-science.com/trac/wiki/BD62xx-Basic
モーターの定格電圧が信号系(マイコン)の電源電圧よりも低い場合は困ってしまいます。
モーターによっては、PWMで一定のデューティよりも上げないように注意すれば大丈夫な場合があります。
arduinoは3Vで動くのか?
  • モータとArduinoの電源が同じでOK?

リアルタイムクロック

  • 秋月の時計IC
  • バッテリバックアップしたい。

ユーザインターフェイス

  • 正回転/逆回転ボタン
  • タイマー時刻の設定/ロータリエンコーダ?
  • 7セグ時計表示

巻き取り終了の検出

マイクでクラッチの音?
一定の秒数の作動でよい?

製作


(1)ざっと組み立て

  • ギアボックス
  • 巻き取り部取り付け
  • ギアボックス&ブレッドボードを板に固定
  • Arduinoを固定
  • モータドライバにピン取り付け


(2)モータードライバの実験(2009/4/18)

  • 正転/逆転を実験
  • スピード&パワーを確認
  • 消費電流を確認


スイッチサイエンスさんのスケッチをちょっと改造で動作OK。
http://www.switch-science.com/trac/wiki/BD62xx-Basic
int FIN = 5;
int RIN = 6;
int LED = 13;
int OFFSET = 0.7 * 256 / 5;       // analogに255を出したら5V => 0.7V
int MAX = 3.0 * 256 / 5 - OFFSET; // RE-260なので3V 3.0V-0.7V = 2.7V
int degree10 = 0;
int i;

void setup() {
 Serial.begin(300);
 pinMode(FIN, OUTPUT);
 pinMode(RIN, OUTPUT);

 pinMode(LED, OUTPUT);
 for(i=0; i<5; i++){
   digitalWrite(LED, HIGH);
   delay(200);
   digitalWrite(LED, LOW);
   delay(200);
 }
}

void loop() {
 delay(10);
 degree10 += 3;
 degree10 %= 3600;
 long v = int(sin(degree10 * 2 * PI / 360 /10) * MAX);
 Serial.println(v);
 if (v > 0) {
   analogWrite(FIN, v + OFFSET); // v(0V..2.7V) OFFSET(=0.7V) なので 0.7V..3.0V
   analogWrite(RIN, 0);
 } else
 if (v < 0) {
   analogWrite(FIN, 0);
   analogWrite(RIN, OFFSET - v); // v(-0V..-2.7V) OFFSET(=0.7V) なので 0.7V..3.0V
 } else {
   analogWrite(FIN, 255);
   analogWrite(RIN, 255);
 }
}

正回転・逆回転をなめらかに繰り返す。
OFFSETは回転開始の最低電圧。
正:0.7V => 0.8V => ... => 2.9V => 3.0V => 2.9V => ... 0.7V
逆:0.7V => 0.8V => ... => 2.9V => 3.0V => 2.9V => ... 0.7V
を繰り返す。

ノイズ?

たぶんモーターからのノイズのせいでシリアル通信が途中でとぎれてしまう。
まともにデバッグできないと困るので対策が必要かもしれない。
http://www.picfun.com/motorframe.html
モーターの端子と金属ケースの間にコンデンサをいれるといいらしい。

(3)リアルタイムクロック確認(2009/4/19)

http://nekosan0.bake-neko.net/connection_rtc.html
nekosanのコードでOK。
よく考えたら毎日同じ時間に作動させる必要はなくて、「6時間後に作動」でいいわけだからRTCいらないや。
プログラムも簡単だ。内蔵RCで誤差はどれぐらいか?外部クリスタルつけたら誤差はどれくらい?

(4)時計表示(2009/4/19)

7セグ2桁で作動までの残り時間を出せばいい。上の桁が時間、下の桁が10分単位で十分。
いや、もっと簡単にLEDの点滅回数でいい。5回点滅なら5時間。

(5)モーターから音を出す。

普通にモーターを回すときでもPWMの周波数で微妙に音が出てしまう。
てことは、適当にメロディーになるようにモーターに信号を与えたら・・・
成功!
スピーカーなしでBEEP音によるフィードバックが可能になった。

ArduinoのPWM周波数

PWM信号の周波数は約490Hzです。 
Arduino's PWM frequency at about 500Hz
20k〜100kHz
を入力しなさいとある。


とりあえず完成

黄色ボタンを押すたびに、「ひも出し」「ひも巻き取り」「停止」
緑ボタンはタイマー時間設定。1時間単位。押すたびにモーターから音を出して操作を確認できる。
タイマー作動後は小鳥のさえずりっぽい音を出してさわやかに目覚める。


/* Curtains Timer */ 

#include <Debounce.h> // http://www.arduino.cc/playground/Code/Debounce 

int FIN = 5;
int RIN = 6;
int LED = 13;
int SW_YELLOW = 3;
int SW_GREEN  = 2;
Debounce sw_yellow = Debounce(20, SW_YELLOW); 
Debounce sw_green  = Debounce(20, SW_GREEN); 
int motorMode = 0; // 0:STOP,1:right,2:left
int timerMode = 0;
int timerHour = 0; // 0:0FF, 1:1h ... 12:12h
int ledWait   = 0; // blink interval.
unsigned long lastPushedMs = 0;
unsigned long alarmStartMs = 0;
unsigned long alarmStopMs  = 0;
unsigned long motorStopMs  = 0;
unsigned long MOTOR_RUN_DURATION_MS =   60000;
unsigned long SNOOZE_MS             =  180000;
unsigned long WAIT_MS_PER_PUSH      = 3600000;

void setup() {
 int i;
 Serial.begin(9600);
 pinMode(FIN, OUTPUT);
 pinMode(RIN, OUTPUT);
 pinMode(SW_YELLOW, INPUT);
 pinMode(SW_GREEN,  INPUT);
 digitalWrite(SW_YELLOW, HIGH); // pull-up
 digitalWrite(SW_GREEN,  HIGH); // pull-up

 // boot blink & sound!!
 for(i=0; i<3000; i++){
   analogWrite(FIN, 255*1/5);
   analogWrite(RIN, 0);
   delayMicroseconds(-i/10+350);
   analogWrite(FIN, 0);
   analogWrite(RIN, 255*1/5);
   delayMicroseconds(-i/10+350);
#define LED_WAIT 300
   if(i%LED_WAIT==0){
     if(i/LED_WAIT % 2 == 0){
       digitalWrite(LED, HIGH);
     }else{
       digitalWrite(LED, LOW);
     }
   }
 }
}

void loop(){
 motor_loop();
 timer_loop();
}

void motor_loop() {
 if(sw_yellow.update() && sw_yellow.read()==LOW) {
   motorMode = (motorMode+1) % 3;
   motorStopMs = millis() + MOTOR_RUN_DURATION_MS;
 }
 switch(motorMode){
 case 1:
   analogWrite(FIN, 255*3/5);
   analogWrite(RIN, 0);
   break;
 case 2:
   analogWrite(FIN, 0);
   analogWrite(RIN, 255*3/5);
   break;
 default:
   analogWrite(FIN, 0);
   analogWrite(RIN, 0);
   break;
 }
 if((motorStopMs!=0) && (motorStopMs<millis())){
   motorMode = 0;
   motorStopMs = 0;
 }
}
void timer_loop(){
 int i;
 int pushed = 0;
 if(sw_green.update() && sw_green.read()==LOW){
   pushed = 1;
   lastPushedMs = millis();
 }
 
 if(timerMode==0){ // nop
   ledWait = 300;
   if(pushed){
     motorBeep(100, 100);
     motorBeep(150, 100);
     motorBeep(200, 100);
     timerMode = 1;
   }
 }else
 if(timerMode==1){ // setting
   if(pushed){
     timerHour = (timerHour+1)%13;
     int beepDelay = 600;
     for(i=0; i<timerHour; i++){ beepDelay = beepDelay*20/23; };
     motorBeep(beepDelay, 100);
     if(timerHour==0){
       delay(50);
       motorBeep(beepDelay, 100);
     }
     //Serial.println(timerHour);
   }
   if((1<=timerHour) && (lastPushedMs+10000<millis())){
     int beepDelay = 600*20/23;
     for(i=0; i<timerHour; i++){
       beepDelay = beepDelay*20/23;
       motorBeep(beepDelay, 100);
       delay(100);
     }
     alarmStartMs = millis() + timerHour*WAIT_MS_PER_PUSH;
     //Serial.println(timerHour);
     timerMode = 2; // goto waiting
   }
   ledWait = 0;
 }else
 if(timerMode==2){ // waiting
   ledWait = 2000;
   if(alarmStartMs<millis()){
     for(i=0; i<10; i++){
       delay(50);
       motorBeep(100, 100);
     }
     alarmStopMs = millis() + MOTOR_RUN_DURATION_MS;
     motorStopMs = 0;
     motorMode = 2;
     timerMode = 3; // goto alarm
   }
   //if(millis()%1000==0){ Serial.println(alarmStartMs-millis()); }
 }else
 if(timerMode==3){ // alarm!!
   ledWait = 100;
   if(alarmStopMs<millis()){
     for(i=0; i<3; i++){
       delay(50);
       motorBeep(600, 100);
     }
     motorMode = 0;
     timerMode = 4; // goto stop
   }
   //if(millis()%1000==0){ Serial.println(alarmStopMs-millis()); }
 }else
 if(timerMode==4){ // stop.
   ledWait = 4000;
   if(pushed){
     motorBeep(700, 500);
   }
   if((millis()%SNOOZE_MS)==0){
     for(i=10+random(10); 0<=i; i--){
       cheep(10+random(50), 100+random(80), 10+random(10), 100+random(300));
     }
   }  
 }

 // LED 0:OFF, 1+:Nms blink  
 digitalWrite(LED, LOW);
 if(0<ledWait && (millis()/((ledWait+1)/2)%2)==0){
   digitalWrite(LED, HIGH);
 }
}

// beep from motor
void motorBeep(int beepDelay, int lenMs)
{
 digitalWrite(LED, HIGH);
 unsigned long breakMs = millis()+lenMs;
 for(;;){
   analogWrite(FIN, 255*1/5);
   analogWrite(RIN, 0);
   delayMicroseconds(beepDelay);
   analogWrite(FIN, 0);
   analogWrite(RIN, 255*1/5);
   delayMicroseconds(beepDelay);
   if(breakMs<millis()){ break; }
 }
 analogWrite(FIN, 0);
 analogWrite(RIN, 0);
 digitalWrite(LED, LOW);
}

// a cheeping little bird
void cheep(int start, int end, int sped, int dely)
{
 int i;
 for(i=start; i<end; i+=sped){
   motorBeep(i, 10);
 }
 delay(dely);
}



(6)Arduino mega88

(TODO)
Arduino2009は他の実験でも使いたいので格安「Arduino mega88 250円」で置き換える。

タグ:

+ タグ編集
  • タグ:

このサイトはreCAPTCHAによって保護されており、Googleの プライバシーポリシー利用規約 が適用されます。

最終更新:2009年04月19日 23:21
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。
添付ファイル