Superb Garbages 2

千野純一(chinorin)のはてなダイアリーの続きです。

明るいときアラームを鳴らすマシーン

・まあくだらないものを1時間くらいで作った。

・目的はトイレの照明の消し忘れ対策。照明のスイッチが換気扇と連動しているので、ついたままだと音と空気の流れでわかるのだが消すためだけにまた立ち上がるのはめんどい。だから消し忘れないようにしたい。

PIRセンサ*1とか使って人がいなかったら自動的に消す、とかがまー普通の気の利いたシステムなんだけど、照明だけ消しても換気扇は止まらないから(主に消したいのは換気扇なので)意味ないし、電工二種も持ってないクソザコのド素人ゆえスイッチ自体に細工をするのは違法であるため、換気扇も一緒に止めるならソレノイド*2とかで壁のスイッチを押さねばならぬ。そんな押す力と精度がめちゃめちゃ要るようなものは作れようもなく、そしてそういうのは買うとアホみたいに高い。代表的なやつが↓これ。

・以上の理由で、まー音鳴らして消し忘れを防止するくらいがコストが安くていいんじゃねーのってことで。

・制御はとりあえずマイコンで、M5Stamp-C3。堂々のRISC-Vである。160MHzとかで動作してるのも馬鹿馬鹿しくて、こんなんもっと粗末なマイコンで事足りるんだけど、なんか自作のUDPIライター*3がたぶんUSBシリアルのドライバの問題だと思うけどうまく動かなくてATtiny202には書き込めないし、ATtiny13Aもあんなに買ったのになぜか一個も見当たらないのでとりあえず目の前にたまたまあったのを使った。

・これ回路図。ぐねぐねしてるのは四角い画像に効率よく納めるためである。

・見りゃわかるけど上部中央のは「明るければON、暗ければOFF」という動作目視用のLEDの部分。(6)はマイコンのGPIOに繋ぐ。

・左のは明るさを検知する部分。(4)はマイコンのGPIOに繋ぐ。可変抵抗に光が差してる記号は、明るさによって抵抗値が変わるフォトレジスタで、ここには1MΩのCdSセル*4を配置した。これはつまりマイコンのADCで抵抗分圧したCdSセルにかかる電圧を測っていて、周囲が暗いほど抵抗値が上がる=分圧された電圧値が上がる=ADCにて高い数値が得られる。抵抗の定数が無駄にでかいのは消費電力を抑えるため。

・右下のはアラーム鳴らす部分。(5)はマイコンのGPIOに繋ぐ。アラームの音量をでかくしたければ抵抗の値を小さくすればよい。3.3Vの場合、深夜に鳴っても近所迷惑にならない上限が100Ωくらいかなと思う。XC110はTO-92パッケージ*5のICで、車の防犯アラーム的な音声信号を出すやつ。

・ブレッドボード実装で廊下に設置し、給電はUSBアダプタから。トイレの扉の下の隙間からケーブルを入れて、CDsセルだけをトイレ室内の壁の低い位置に養生テープで仮固定した。

・↓ソース⋯じゃなかったスケッチ。ArduinoIDEは2.0.4、M5Stackライブラリは2.0.6。著作権は主張しません。

// CdS-Buzzer for M5Stamp-C3
// written by Chinorin. No Rights Reserved.

// 3v3 - Res(1MΩ) - Pin4 - CdScell(1MΩ) - GND
// Pin5(Bright→HIGH / Dark→LOW): Buzzer
// Pin6(Bright→HIGH / Dark→LOW): LED

#define ADC_PIN 4
#define BUZZER_PIN 5
#define LED_PIN 6

#define THRESHOLD 200 // 明るい判定の閾値。analogReadの値がこれより小さければ明るい
#define WAIT_SEC 5 // アラーム条件となる明るい判定の継続時間
#define BUZ_SEC 1 // アラームを鳴らす時間
#define SIL_SEC 3 // 次にアラームを鳴らすまでの時間。
// BUZ_SEC秒鳴らしてSIL_SEC秒休む を繰り返す。

void setup() {
  Serial.begin(115200);
  pinMode(BUZZER_PIN,OUTPUT);
  pinMode(LED_PIN,OUTPUT);
}

void loop() {
  static int count;
  delay(1000);
  int adc=analogRead(ADC_PIN);
  Serial.println(adc);
  if (adc<THRESHOLD) {
    count++;
    digitalWrite(LED_PIN,HIGH);
  } else {
    count=0;
    digitalWrite(BUZZER_PIN,LOW);
    digitalWrite(LED_PIN,LOW);
  }
 
  switch(count){
  case WAIT_SEC:
    digitalWrite(BUZZER_PIN,HIGH);
    break;
  case WAIT_SEC+BUZ_SEC:
    digitalWrite(BUZZER_PIN,LOW);
    break;
  case WAIT_SEC+BUZ_SEC+SIL_SEC:
    count=WAIT_SEC-1;
    break;
  } 
}

・loop()ではCdSセルが繋がってるピンを1秒毎にひたすらanalogReadして、判定が「明るい」だったらcountを+1、「暗い」だったらcountを0にする。countがWAIT_SEC以上⋯つまり明るい状態が5秒続いたら、それ以降暗くなるまで「ブザーをBUZ_SEC(1)秒鳴らしてSIL_SEC(3)秒休む」を繰り返す。

・M5Stamp-C3のADCの分解能は12ビットで、analogRead(ADC_PIN)は0~4095の値をとる。この値は明るければ小さく、暗ければ大きい。うちのトイレの自作照明だと閾値(THRESHOLD)を200にすると絶妙に人間の影がかかっていれば明るい判定にならないくらいの感じ。CdSセルの電源側に繋いである抵抗を小さい値にすると12ビットをもっと広く使って精度が出せる。

・明るさ検知するたびにシリアルに数値を出力する。不要なときにこれをコメントアウトするかどうかは流派による。w

・以上、まーマイコン使うとこうやってあんまり頭使わずサクッとできるんだけど、マイコンなしでもコンパレータ*6と555*7があればだいたい同じ物が作れると思う。そのようにしてM5Stamp-C3は回収する方針でいくかあ。

・なんとなく回路図だけ書いてみた。コンパレータの出力はオープンコレクタ*8で、その先のPNPはデジトラ*9にする。部品点数を減らすために前掲スケッチにおけるWAIT_SECの機能は省略したが、XC110の手前で信号を反転すれば代わりになるかもしれない。各定数も仮に適当な数値にしたのでそのへんは試行錯誤が必要であろう。ちゃんと動くのかどうかはもちろん知らん。

*1:PIRセンサ: パッシブ赤外線センサ。人体を感知するためのやつ。

*2:ソレノイド: 3次元的に巻かれたコイル(つまり今時見かけるふつうのコイル)のこと。転じて、発生する磁界によって棒などを出し入れする(直線運動させる)ような装置。

*3:UPDI: 最近のAVRマイコンに書き込むための仕組み。UPDIライターは、、USBシリアルがあれば簡単に作れる⋯⋯はずなのだが。

*4:CdS: 硫化カドミウムのこと。言うまでもなく毒物。日本では合法だけどヨーロッパとかでは違法。

*5:TO-92: よく見かけるふつーのトランジスタがこれ。

*6:コンパレータ: 現代において単にコンパレータと言った場合、それはたいてい電圧コンパレータ(デジタルコンパレータ)を指すと思う。電圧を比べるための集積回路オペアンプの親戚。

*7:555: そういう名前のタイマーIC。元祖はNE555だそうだが色んなメーカが色んな仕様で出してるので単に555と言った方が通りがよい。

*8:オープンコレクタ: 出力がバイポーラトランジスタ(普通のトランジスタ)のコレクタになっている仕組みのこと。PNPのオープンコレクタってのもあるらしいんだけどよく知らない。とりあえずこのコンパレータの出力はNPNのオープンコレクタで、Highの場合IC内部のトランジスタが導通し、IC内部でGNDに繋がる。Lowだとハイインピーダンス(非導通)となる。ちなみに出力がFETのものはオープンドレインと呼ぶ。

*9:デジトラ: デジタルトランジスタ。パッケージの中にベース抵抗とベース-エミッタ抵抗を内臓しているトランジスタのこと。つまりこの回路図はその2つの抵抗を省略している。