目次
概要
Raspberry Pi 2を使ってブラウザから制御可能な学習リモコンを作りました.
Raspberry Piファミリとマイコンを組み合わせた工作の一例としてまとめておきます.
動機
私の部屋には赤外線リモコンで制御できる家電製品として,シーリングライトとエアコンがあります.
夏場に冷房をかけたまま寝てしまうと喉を悪くしたり風邪を引いたりしてしまうし,
かといってOFFのまま寝てしまうと暑くて寝苦しく,目覚めも悪いということがあり,
これをどうにか改善したいと考えていました.
寝苦しいという問題は寝入るくらいの適当なタイミングで
エアコンの標準機能のタイマーを使ってエアコンをOFFにすることで解決できるのですが,私の部屋のエアコンのタイマーは
何時間後にOFFにするか,何時間後にONにするかのどちらかしか一度に設定できません.
つまり,寝苦しいのを解決するためにOFFタイマーを使うと,朝にONするようなタイマーを設定できないのです.
これを解決するために,タイマー機能付きの学習リモコンを自分で作って,エアコンを制御しようと考えました.
さらに,せっかくリモコン対応のシーリングライトもあるので,起きるべき時間よりも
少し早めに冷房と照明をONすることで,快適に目覚めることができるのではないか…
と考えたのも製作に踏み切った理由だったりします.
製作方針
要件定義
まず,学習リモコンを作るにあたり,上に書いた動機を勘案しつつ,要件を整理しました.
- 今あるリモコンの信号を記録する機能
- 記録した信号を送信する機能
- 設定した時刻にリモコンの信号を送信する機能
- リモコンの信号の送信やタイマー設定のためのGUI
- それなりに丈夫・安定であること
- できるだけコンパクトであること
1.と2.はいうまでもなく,というか学習リモコンの定義といえるでしょう.
3.と4.については上に書いた動機から必要な機能であると考えました.
4.については特に,日常的に(それもこれから寝るという眠い時に!)使っていくためには
できるだけ操作の手間を減らすために設定用のGUIが必要だろうと考えました.
5.も当たり前といえば当たり前なのですが,実はこの記事で扱う学習リモコンを作る前に
プロトタイプを作っていたりするのですが,あまりに雑に作りすぎて電源ケーブルが
断線するといった問題が何度か起きていました.なので,これも機能というか,
要件として念頭において作成を始めました.
6.も毎日使う上で大事な条件です.邪魔だと使わなくなる可能性大です.
実装方法の検討
上に書いた要件定義を基に,どのような方法で実装するか具体的に検討していきました.
ざっくりまとめると,以下のようになります.
表1 今回のシステムの構成
管理用GUI | HTML+Bootstrap+JavaScript | |
REST API提供のためのサーバ | node.js+Express | |
定期実行の管理 | cron | |
リモコン信号の管理プログラム | Python+pySerial | |
送受信の制御のためのコンピュータ | Raspberry Pi 2 | |
リモコン信号の送受信 | STM32F030F4P6搭載自作マイコンボード |
要件定義の1.と2.に関しては,至って普通の学習リモコンの要件なので,
Googleで検索すると出てくる学習リモコンの作例が参考になります.
特に今回は橋本商会さんの「ArduinoとRubyで赤外線リモコン作ってWebから操作できるようにした」を参考にしました.
この作例はArduinoでリモコン信号の送受を行い,リモコン信号データの管理はPCで行うという構成になっています.
このような構成にするメリットとしては,Arduinoのようなマイコンを使うことで,
通常のPCでは難しい,数十~数百マイクロ秒単位で変化するリモコンの信号の送受信を比較的容易に実現しつつ,
通常のPCが持つ拡張性を享受できる点が挙げられると思います.
今回はGUIも用意したいので,同じような構成を取ることにしました.
しかし,学習リモコンのためにPCを常に動かしている,というのはちょっと
邪魔だったり,ファンの音がするのも嫌だったので,今回は通常のPCではなく,
ちょうど他の用途で常時稼働させていたこともあり,Raspberry Pi 2を使うことにしました.
また,マイコン側もArduinoでも良かったのですが,せっかくなのでコンパクトに作るために,
いろいろな用途に使うために自作していたSTM32F030F4P6マイコン搭載のボードを使うことにしました.
図1 自作STM32F030F4P6マイコンボード
先ほどの作例ではUSB-UART(シリアル)変換器経由でArduinoとPC間の通信を行っていましたが,
このボードにはUSB-UART変換器は搭載されていないことと,Raspberry Piファミリは
UARTポートがGPIOピンヘッダに引き出されていることから,このUARTポートを使って,
マイコン側とRaspberry Pi側との通信を行うことにしました.
これによって,Raspberry Pi側のUSBポート側に配線を引き回さずに済むため,
要件の6.にあるコンパクト化にも寄与しています.
また,プロトタイプでは5V動作のマイコン(Adruinoと同じATMega328Pで作っていました)
を使っていたので,UARTのレベル変換が必要でしたが,STM32マイコンは3.3V動作なので,
レベル変換を行う必要がなくなり,部品点数を減らすことができました.
マイコン側のプログラムは基本的にC言語で書く必要がありますが,Raspberry Pi側の
プログラムはいろいろな言語を使うことができます.
今回はRaspberry Pi側でのリモコン信号送受信のためのプログラムはPythonで記述しました.
Pythonを使った理由としては,単に自分が比較的使い慣れているということと,
pySerialモジュールによってUARTポートが抽象化されているということが挙げられます.
pySerialを使うことで,マイコン側のプログラム・ハードウェアのデバッグの際は
開発用のWindows PC上のPythonを使ってテストを行い,動作が確認できたら
Raspberry Pi上のLinuxに移植する,ということが簡単にできるようになります.
実際に変更したのはUARTポートの指定を行う部分1行だけで済みました.
要件の3.「設定した時刻にリモコンの信号を送信する機能」は
cronを使って実装しました.後述のGUIによって,リモコン信号送信プログラムを
何時何分に呼び出すかといったことをcrontabへ登録するような仕様になっています.
4.「リモコンの信号の送信やタイマー設定のためのGUI」ですが,
node.jsとExpressを使って,シーリングライトとエアコンのON/OFFのためのREST APIを用意し,
そのAPIにアクセスするためのページをBootstrapを使用して作成しました.
node.jsとExpressを使ったのは勉強のためというのと,Hubotを動かしていたために
node.jsはRaspberry Piにインストールしてあった,というのが理由です.
また,REST APIとしておけば,その後にいろいろと応用が効くのではないかと思い,REST APIを採用しました.
Bootstrapを使ったのは通常のPCからだけではなく,例えばスマートフォンなどの端末から
設定用ページを見た時にも使いやすくできるのではないかと思ったからです.
簡単なボタンとドロップダウンメニュー程度で済むGUIであれば,PCとスマートフォンで
GUIを作り分ける必要がないのはWebベースのGUIのメリットだと思っています.
5.「それなりに丈夫・安定であること」については,
そもそもプロトタイプではむき出しの基板からケーブルがごちゃごちゃと生えているだけだったので,
きちんとしたケースを作ることで,電源ケーブルに荷重がかからないようにしたりすることで実現できると考えました.
また,プロトタイプの時点ですでに盛り込んでいた仕様ですが,Raspberry Piへの給電が
USBのmicroBコネクタ経由ではちょっと不安なので,GPIOのピンヘッダへ給電を直接行い,
ケースの外へは通常のDCジャックを引き出すようにしました.
実装
製作方針に沿って,実装を行いました.流れとしてはだいたい,
マイコン側ハードウェア→マイコン側ソフトウェア→リモコン信号の管理プログラム→サーバ→GUI
の順で開発しました.
マイコン側ハードウェア
図2 Raspberry Pi 2と今回製作した基板
図3 今回製作した基板の裏側
上に実際に今回作ったリモコン信号送受信回路とRaspberry Pi 2の写真を示します.
2枚目の写真は1枚目の真ん中の基板の裏面です.
基本的にはリモコン信号を受信するためのモジュール(写真2枚目の基板上の銀色の部品)とリモコン信号を送信するための赤外線LED,
そしてこれらを制御するマイコンからなるのですが,プロトタイプを作成する段階で,
照明をリモコン制御する場合,照明の方向に光を照射する必要があり,
赤外線LED1つでは照明光に赤外線LEDの光が負けてしまい,
リモコン制御ができないということが判明していました.
(照明が最高輝度の場合と,豆球が点灯している時は特にきちんと認識されませんでした)
そこで,赤外線LEDを8つ接続し,これらを一斉に点滅させることで,
照明光に負けず,正しくリモコン制御できるようにしました.
LEDは2個ずつ直列に接続したものを4組用意し,1組あたり約240mAの電流が
流れる仕様としました.LEDは常時流す電流の定格だけでなく,パルス状の信号を
加える場合の電流の最大定格も定義されていることが多く,今回は最大で1Aの
電流を瞬間的に流すことができるタイプのものを使用しました.
このような比較的大きな電流をマイコンから直接制御するのは難しいことと,電源回路の都合上,
LEDは5V入力から電源を供給したかったため,これらのLEDはマイコンからの出力にFETを使った駆動回路を経由して接続されています.
その他の工夫としては,できるだけ制御対象の方に赤外線LEDを向けやすいように,
赤外線LEDのみ別基板としました.
また,電源に関しては,マイコンボードが取り付けられている基板に取り付けた端子台にDCジャックを接続しています.
ここから得られる5VはRaspberry Piと赤外線LEDに供給されています.
マイコンと赤外線リモコン信号受信モジュールはRaspberry PiのGPIOピンヘッダから得られる3.3Vで動作するようになっています.
このユニバーサル基板はRaspberry PiのGPIOピンヘッダに接続され,それによって固定されるようになっています.
重い部品もなく,これといって揺れることもないので,これでよいと考えています.
持ち運ぶ場合や重い部品が載る,外部から力がかかるといった場合には追加の固定方法を考えるとよいでしょう.
マイコン側ソフトウェア
マイコン側のソフトウェアの基本的な考え方は先程紹介した作例と同じです.
Raspberry Pi側から送られてきたコマンドに応じて,
- リモコン信号の受信
- リモコン信号受信結果をRaspberry Piへ送信
- Raspberry Piからリモコン信号データを受信
- Raspberry Piから受信したリモコン信号データを送信
のいずれかを行うようになっています.すなわち,リモコン信号データはマイコン側で
一旦バッファリングされます.
リモコン信号は信号の有無が連続している時間を4マイクロ秒単位で記録した数字列として
Raspberry Piへ送信されます.おそらく精度的にはもっと粗い時間間隔で記録しても
問題ないかとは思いますが(実際に橋本商会さんの作例は100マイクロ秒単位),
Arduinoに比べて今回使ったマイコンはRAMが2倍(2KB vs. 4KB)あるので,時間間隔を細かくした分,
リモコン信号の有無が連続している時間を記録するための変数も2byte単位とし,同程度以上の時間間隔を記録できるようにしています.
基本的にはSTM32マイコン向けのライブラリであるHALライブラリを使用して書いていますが,一部については
HALライブラリではなく直接マイコンのレジスタを制御するように書くほうがシンプルになりそうだったのでそのように書きました.
リモコン信号管理プログラム
リモコン信号管理プログラムは,リモコン信号受信プログラムとリモコン信号送信プログラムの2つに分けて開発しました.
リモコン信号受信プログラムはまず最初に,マイコンに対して,リモコン信号の受信を行うようにコマンドを発行します.
マイコン側がリモコン信号の受信を完了すると,ACKを返すので,Raspberry Pi側はACKが帰ってきた場合には
マイコン側のバッファに蓄積されていいるリモコン信号受信結果をRaspberry Pi側へ送信するようにコマンドを送信します.
こうしてRaspberry Pi側に送信されてきた受信結果を,コマンドライン引数にあるファイルに保存するようになっています.
一方,リモコン信号送信プログラムは,コマンドライン引数にあるファイルを読み込み,
そこに記述されているリモコン信号データをマイコン側へ送信します.
マイコン側への送信が完了すると,次にマイコン側に実際にリモコン信号を送出するように,コマンドを発行します.
エアコンに関しては,何故か2回信号を送出しないと反応しない場合があったため,
実際にはコマンドライン引数を使い,複数回信号を送出するオプションも付加しています.
REST API提供のためのサーバ
学習リモコン操作のためのREST APIとしては,以下の表に示すようなものを用意しました.
表2 今回実装したREST API
エンドポイント名 | 概要 |
/AC/Dry | エアコンをドライ・26度設定でON |
/AC/Cooling | エアコンを冷房・26度設定でON |
/AC/Heating | エアコンを暖房・26度設定でON |
/AC/Off | エアコンをOFF |
/CeilingLight/Toggle | シーリングライトのON/OFF |
/Resv/(タイマー予約ID) | DELETEメソッドでのアクセスによって当該タイマー予約IDの予約を削除 |
/Resv | GETメソッドでのアクセスでタイマー予約一覧をJSON形式で取得 POSTメソッドでのアクセスでタイマー予約の追加 |
上から5つの家電ON/OFFに関係するエンドポイントへは単にアクセスすれば対応する操作が行われるようになっています.
シーリングライトがON/OFFになっているのは,シーリングライトは同じリモコン信号を送るたびに
全点灯→減光→豆球点灯→消灯を繰り返すためです.
一方,エアコンに関しては運転種別,温度,風量といった情報をリモコン信号に
埋め込んでいるため,それぞれの動作ごとにエンドポイントを用意しています.
“/Resv”から始まるタイマー予約については,タイマー予約情報のJSONデータを
受信するたびに,JSONデータをパースしcrontabのフォーマットへ整形し,
crontabへの書き込みとcrondの再起動を行うような実装になっています.
あんまり賢い実装ではないような気がしますが,特に他にcrondに依存している
サービスもないので,とりあえずそういう実装になっています.
(いい方法があったら教えて下さい!)
また,タイマー情報一覧についてもcrontabをその都度パースするようになっています.
タイマー予約IDについては,予約内容からハッシュ値を求め,それぞれのタイマー予約に付番しています.
管理用GUI
以下に今回作った管理用GUIを示します.
図4 管理用GUI
管理用のGUIについては,サーバの項で述べた家電ON/OFFに関係する
エンドポイントのうち,エアコンの冷房・暖房ON,OFFとシーリングライトのON/OFFを
操作できるボタンを用意するとともに,
予約の追加,一覧表示,削除ができるようになっています.
予約時刻の入力フォームについてはHTML5から追加されたinput要素のtype属性の値”time”を使うことで,
スマートフォンからでも比較的簡単に時刻を設定できるようになっています.
ケース
最後に忘れてはいけない大事な要素,ケースについてです.
3Dプリンタで作ってもよいのですが,木材が余っていたことと,CNCフライスをたまには動かさねば,
ということもあり,今回は木材をCNCフライスで加工することで作成しました.
Raspberry Piの寸法は公開されているので適宜参照し,自作したユニバーサル基板の部分については自分で採寸してケースを設計していきます.
図5 ケース加工中の写真
レーザカッタや3Dプリンタなど,それぞれの使いやすい機材で作るのが良いかと思います.
今回は直方体状の形状とし,赤外線LEDと赤外線リモコン信号受信モジュール,
電源コネクタが外に出るような穴を用意しました.
図6 ケース前面
また,DCジャック側のパネルにはスリットを入れて,気休め程度ですがエアフローにも配慮してみました.
図7 ケース背面
ちなみにネジがやたらと多いのは直方体の各頂点に下に示すような垂直取付用ブロックを
使っているためです.
図8 垂直取付用ブロック(秋月電子で1個110円)
図9 組立途中の写真
接着や木材の組接ぎ等を考えずに比較的丈夫に作れるので個人的には気に入っています.
ネジの数が気になる場合には適宜接着・組接ぎを組み合わせるとよいと思います.
まとめ
今回はマイコンとRaspberry Pi 2,各種ソフトウェア等を組み合わせて,タイマー予約機能付き学習リモコンを製作しました.
今後の予定としては,インターネット上経由で外から操作できるようにするために,認証等を実装するといったことを考えています.
動機に書いたとおり,エアコンのタイマー予約の不便さの解消という目的は達成できたと思います.
一方で,目覚めの悪さを解消という目的ですが,こちらに関しては最初の1ヶ月程度しか効果がなく,
きちんと寝る時間もコントロールせねば睡魔には負ける,ということを実証してしまいました.
マイコンからWeb,木工など,色々なタイプの工作をするのはいろいろと勉強することも多く楽しいのですが,
まずはきちんと寝なければ,と思う今日この頃なのでした.