うちのしゅーちゃん(9)との契約では、テレビもiPadのゲームもMacのScratchも、1回40分までということになっている。その後は20分の休憩を入れなければならない。土曜の朝にハルロック2巻を読んでた俺は、これは電子工作でなんとかしよう! と思い、その日のうちに作ったのがShu Timerだ(キッチンタイマーでいいのでは...? という言葉は禁句である)。
一番上のボタンを押すと40分タイマーが動き始め、残り時間がLEDに表示される。40分経つとテレビの電源がぱちんと切れて、さらにiPadとMacのスクリーンにもぴろんと通知が出る。
電子工作の部分はlittleBits/cloudBitを使ったので15分ほどで完成したけど、今回Arduinoを使うのが初めてだったので、思ったとおりのタイマー動作をArduinoのコードで書けるまでに3時間くらいかかってしまった。。でもArduinoおもしろい! その試行錯誤の記録を以下にまとめた。
Arduinoモジュールでクライアントロジックを書く
littleBitsのcloudBitのすばらしさは以前の投稿でも紹介したとおりだが、最近littleBitsに登場したもうひとつのファンタスティックな製品がArduinoモジュールである。
その名のとおりArduinoが入ったモジュールで、3つの入力と3つの出力を持っている。このうち4つがアナログ入出力に対応してて、littleBitsで扱う0〜99のシグナル(0〜5Vの信号)をArduinoで読んだり書いたりできる。残り2つはデジタル入出力(HIGH/LOW)用だ。
littleBitsで工作していると、いろいろと細かなロジックの実装が難しいケースがある。例えば今回のタイマーのように、
- スタートボタンを押したら40から0まで1分ごとにカウントダウン
- タイマー起動中はLEDを1秒おきに点滅
- 真ん中のストップボタンを押したらカウントダウンを一時停止、LEDは点灯状態に
- カウントダウン終了したらcloudBit経由でテレビ・iPad・Macにイベント送信
- 下のリセットボタンを押したらカウントをゼロにしてタイマー停止
といった具合の細かな状態遷移や条件分岐は、まぁLogicモジュールを買い込んでフリップフロップを組めば実現不可能ではないだろうけど、恐ろしく金がかかってしまう。Arduinoモジュールを使えば、Arduino IDE上でCライクなコードをさくっと書いてモジュールに書き込んでおしまいである。
さらにこれとcloudBitをつなげると、Arduinoモジュールはサーバーに対するクライアント側のロジックを担当する、いわばJavaScript的位置づけとして使える。つまりArduino+cloudBitは、littleBitsをIoT的に使うときの必須コンビネーションと言えよう。
Arduinoのコーディングって楽しい
今回初めてArduinoのコーディングをやってみたのだけど、OSのない世界でのプログラミングって昔のパソコンに戻ったようで楽しい。まずはLEDをチカチカさせるサンプルから試すのだけど、こんな感じ:
void loop() {
digitalWrite(1, HIGH);
delay(1000);
digitalWrite(1, LOW);
delay(1000);
}
このコードをIDE上で書いてコンパイルし、USBで接続したArduinoモジュールに書き込みして使う。loop()
というのはCのmainに相当する関数で、モジュールに電源を入れて数秒後にはこのloop()
の中のコードがひたすら繰り返し実行される。起動速っ。digitalWrite
という組み込み関数を使ってデジタルピンの1番にHIGH
やLOW
をセットすると、Arduinoモジュールのd1
出力につないだLEDがチカチカする。この単純さは子供向けのプログラミングにピッタリと思うので、しゅーちゃんがScratchを制覇したあとに教えてあげたい。
意外にむずいところ
今回のタイマー工作で書いたコードはshu_timerとしてGitHubに上げておいたが、意外に手間取ったり、なるほどな〜と思ったポイントがいくつかあった。
- イベントループの書き方で応答性が決まる
- 7セグLEDに思った数字を表示させるのむずい
Arduinoは当然シングルスレッドなので、ボタンを押した時にタイマーがぱっと動き始めたり等の応答性は、loop()
の中にどんなイベントループを書くかに大きく左右される。自分の経験で言うとFlashのActionScriptに近いのだけど、スレッドを長時間ロックするような処理を書くとUIが固まってしまう。なので基本、0.1sくらいの間隔でイベントループを回し、状態遷移を管理しつつの非同期な入出力を行う書き方になる。昔のパソコンゲームっぽいコーディングだ。
それと、littleBitsの7セグLEDに思った値をピタリを表示させるのちょっとむずい。littleBitsのシグナルは0〜5Vのアナログ信号で、それを0〜99に対応付けている。一方で、Arduinoのアナログ出力は0〜255なので、組み込み関数map
を使って両者のマッピングを行う。
analogWrite(COUNTER_LED, map(value, 0, 99, 0, 255));
こうすると、value
が0〜99の値をとるときに、それを0〜255に変換してアナログピンに出力できる。でも、7セグLED上のカウントダウン表示では、とばされる値が発生してしまう。つまりlittleBits内部で個々の値を表すアナログ電圧にはぴったりマッピングできないのだ。とりあえずの解決策としてvalue
の値を秒単位にしたところ値がとばされることはなくなったが、代わりに分と分の境い目あたりでLED表示がチラついてしまう現象が出る。こんなアナログなバグは逆に新鮮な感じがしないでもない。
IFTTTでテレビ・iPad・Macと連携
タイマーのカウントダウンが終了したら、ArduinoからcloudBitに向けてHIGH
信号を0.5sだけ送ってお知らせする。一方のcloudBitでは、IFTTTを使ってテレビ、iPad、Macへのイベントを送る以下のレシピを書いておく。
- cloudBitのイベントを受けたらWeMo Switchの電源をオフに
- cloudBitのイベントを受けたらSlackにメッセージ送信
- cloudBitのイベントを受けたらiOS通知を送信
テレビの電源にはBelkin WeMo Switchをつなげておいた。こいつはWiFi接続でコントロールできる電源スイッチだ。iOSアプリからオンオフできるけど、IFTTTに連携してるのでいろんなWebサービスから制御可能だ(高いけど)。
iOSへの通知はIFTTTアプリで可能なのだけど、Macへの通知はいろいろ考えて、しゅーちゃん用Slackアカウントを作ることにした。タイマーが切れるとIFTTT経由でSlackにメッセージが届き、Mac画面上にぴろりんと通知が出てくる仕組みである。
cloudBit+ArduinoはIoTのMEANスタックだ
というわけで、未経験者でもすぐに使えてしまうlittleBitsのArduinoモジュール、これとcloudBitを組み合わせると、わざわざ秋葉原まで行って秋月電子やaitendoをめぐってパーツ集めてハンダ付けして動かねーっ! という思いをせずに、さくっとWeb連携電子工作できるので楽しい。RasPiもいいけど、Arduinoはさらにハードル低くてlittleBits内部で動くのがすばらしいなと思った。