廊下の電灯を自動でOn / OffするデバイスをRaspberry Piで作った(スイッチ操作側)
自分が住んでる部屋の廊下の電灯はスイッチは玄関側に付いていて、部屋から廊下の電灯を付けるのにわざわざ玄関まで行く必要があって面倒だった。
とくに仕事から帰ってきたときが面倒で、
- 玄関から入ってすぐの廊下の電灯を点ける
- 廊下の先まで行って部屋の電灯を点ける
- 玄関まで戻って廊下の電灯を消す
- 部屋に行く
と、廊下を1.5往復する必要があった。
そこでセンサーを使って廊下に人がいるのを検知して、電灯スイッチを操作できるシステムをRaspberry Piで作ってみた。 今回は廊下の電灯スイッチを操作する側について書く。(センサー側は後日書く予定。)
設計
構成はこんな感じにした。
人の動きを検知するセンサーを、スイッチのある場所から離れた所に設置する必要があったので、センサー側と電灯のスイッチを操作する側を分けて構成した。
今回は右の赤い枠の部分の話。
廊下に入ったことをセンサー側のRaspberry PiからHTTPで通知されたら電灯をOnにする。ただし既にOnならそのまま維持して、一定時間経ったら自動で電灯をOffにする。
ハードウェア
HTTPで通知を受けるのにLANケーブルを引っ張りたくはなかったのでWifiアダプタを使った。スイッチの切替は構成図にある通りサーボで行う。
それとマイコンとサーボ剥き出しだと常用するには見た目が良くないので、モールドケースというのがスイッチカバーと同じ大きさで高さもちょうどよく、安かったので使うことにした。
左はRaspberry Piを取り付ける前。モールドケース(のフタ側)に電灯のスイッチとが入る大きさの穴を開けて、そこに合わせてプラ版でサーボを固定した。サーボは1個で電力に余裕があるのでRaspberry Piと直接接続した。高さを抑えるためにGPIOピンを横向きにするピンソケットを使ってケーブルが横に出るようにしている。
真ん中はRaspberry Piをプラ版に取り付けた後。小さいのでケースにギリギリ入る大きさ。
右は裏側の様子。この面が壁と接する。上下の穴は壁にあるスイッチカバー取り付け用のネジ穴に合わせて開けたネジ穴。
左は斜めから見た様子。ケースの高さに収まるようにRaspberry Piを上下逆さまに取り付けてる。
右はケースに収めた状態。Raspberry Pi自体はケースにギリギリ収まったけど、USBの電源コネクタがModel A+は横(HDMIコネクタと同じ辺)についてるのでケースに収まらなかったのでケースに穴を開けてUSBケーブルを接続してる。
使ったもの
- マイコン:Raspberry Pi Model A+
- サーボ:Tower Pro SG90
- Wifiアダプタ:BUFFALO 無線LAN子機 WLI-UC-GNM
- microSDカード:東芝 microSDHC 16GB(Class10 30MB/s UHS-I 防水 耐X線)
- ケース:テイシン モールドケース TB54B
- その他:
- USBケーブル
- Raspberry Pi用 L字ピンソケット2×13(26P)
- リード線
- Qiコネクタ
- 熱収縮チューブ
- プラバン
- ネジ
- ナット
- スペーサー
回路図
回路はこんな感じで作成した。サーボのVCCと5V、GND同士、信号線とGPIO18を繋いでいる。
GPIO18はPWM出力をできるピンだ。
(図のRaspberry PiはModel A+がなかったのでB+のものを使った。)
ソフトウェア
HTTPで通知を受けるためのサーバーはflask-restfulというPythonのライブラリを使って実装した。
flask-restfulは簡単にREST APIのサーバーを書けるフレームワークで、今回もサーバー部分はAPIが少ないのもあって20行程度でサクッと実装できた。 マイコンで動かすサーバープログラムは小規模なもので済むものも多いだろうからこれくらいサクッと書けるのはうれしい。
また、サーボの制御はWiringPi2-Pythonを使った。
サーボの制御は拙著でまとめてる(言語はC++だけども)ので、そのままのやり方で行った。
RaspberryPiとWiringPiでサーボを動かす - Qiita
REST API
APIは今のところスイッチのOn / Off状態の取得と設定を行うものだけ定義した。
スイッチをOnにするときは、
[URL] http://example.com/Switch
[POSTデータ] {'state': 'on'}
というリクエストを送るとサーボがスイッチをOnにして電気が点いて、自動Offまでのタイマーをスタートする。 ただし既にOn状態ならサーボは動かさず、自動Offまでのタイマーをリスタートする。 また、'on'を'off'にすればスイッチをOffにして電気が消える。
スイッチの状態を取得するときは、
[URL] http://example.com/Switch
というリクエストを送ると {'state': 'on'} というJSONデータが返ってくる。
ソースコード
https://github.com/locatw/autonek-halitch.git
設置
光が入らないので少し暗いけど、設置した様子はこんな感じ。
廊下の電灯のスイッチカバーを外した所と、設置してケースを被せる前と、ケースを被せて電源ケーブルを接続した所。
(スイッチカバーを外した状態がずいぶん雑だったんだけど、どこの家もこんなものなのか気になる。)
実際に動作してる様子。
廊下の電灯を自動On / Offするデバイス - YouTube
課題
動作音が意外と大きい
ケースに入れててもサーボの動作音とスイッチの切り替え音が結構大きくて少し気になる。ケースを密閉したりして防音する方法もあるかもしれないけど、Raspberry Piが出した熱が籠もってしまう。
ただRaspberry Pi Model A+は発熱が少なめで、ヒートシンクをつけた旧式のModel Bはアイドル状態でも触ると結構熱いけど、Model A+はヒートシンクなしでも40℃で温かい程度だった。夏はどうなるか分からないけど熱対策はやりやすそう。
REST API以外のインターフェースがない
実際に24時間動かして使ってみたら、料理したりするために台所に立つと、まだいるのに自動で電灯がOffになったり、動くとまたOnになったりして十数回スイッチが切り替わってしまってうるさかった。
人感センサーは動いた人間を検知するものなので、じっと立ってるだけだど検知しないのが原因。なので常時点灯モードみたいなのを作って切り替える機能を付ければ解決できるんだけど、この装置には現状HTTPアクセスしないと操作できないのでスマホかPCからアクセスする以外に方法がないが、わざわざスマホやPCを操作するのは少し面倒だ。
解決策として物理ボタンを付ける、タッチディスプレイをつける(PiTFTとか)、音声認識やジェスチャー認識機能をつけるとかが思いつく。
Raspberry Piの長期運用の対策
上の2つの課題があるけれどうまく動いてるのでずっと動かしておくつもり。けど、そうするとmicroSDカードの寿命が気になってくる。Linuxが動いているのでmicroSDカードにログが書き込まれるから、セルの書き換え寿命が来たらmicroSDカードを交換しないといけない。
対策としてRAMディスクを作ったり、ファイルシステムをリードオンリーにしたりする方法があるみたいなので、これもその内やっておきたい。
PiTFTを使ってみた
部屋の電気のスイッチに液晶つけて、操作パネル表示させたら面白いかなと思ってこれを買ってみた。タッチに対応してる。
https://learn.adafruit.com/adafruit-pitft-28-inch-resistive-touchscreen-display-raspberry-pi
セットアップ
セットアップ方法もリンク先に書いてある。
ただ開発に使ってるRaspberry Piではうまくセットアップできなかったので、新しくSDカードにOSをインストールしてからセットアップした。
Raspberry Piに接続するPiTFTって液晶買ってひと通りセットアップしたんだけど画面が真っ白でGUIが表示できない。一筋縄じゃいかないのか。
— loca (@locatw) 2015, 1月 10
PiTFT、OS再インストールしてセットアップしたらGUI表示されるようになったな。でも開発環境だから再インストール前の状態で使えるようにしたい。
— loca (@locatw) 2015, 1月 11
既存のRaspberry Piの環境へのPiTFTのインストールがうまくいかないから、結局新しくOSインストールしてPiTFT使うことにした。
— loca (@locatw) 2015, 1月 11
既存の環境はwin32diskimagerを使ってバックアップした。
読み込みと書き込みに少し時間かかるけど、新しいデバイスのセットアップする時にやるくらいならあまり手間にならない。
[Raspberry Pi]SDカードのディスクイメージを複製する – o24ブログ
GUIを表示してみる
セットアップができたのでwxPythonでボタンを表示してみた。
ようやくここまで出来た。ボタンをタッチすると"点灯"に変わる。GUIはwxPython使った。 https://t.co/A48JoidFfN
— loca (@locatw) 2015, 1月 11
スイッチ代わりだから大きめのボタンを表示したんだけど、どうも描画が遅くてちらつきが目立つ感じだった。
Raspberry PiでwxPython使ってトグルボタン表示させてるんだけど、どうもフリッカーが発生する。ダブルバッファリングもしてるのに。320x240のボタンだから描画に時間かかるんだろうか。
— loca (@locatw) 2015, 1月 12
Raspberry PiだとX windowは重いらしい。OpenGL使うとかしないと改善はなさそうだ。
— loca (@locatw) 2015, 1月 12
CPUで描画して遅いならGPU使えばいいじゃんと思って色々調べたら、Raspberry PiはOpenGLES2に対応してるらしい。
なのでOpenGLで描画してくれるGUIライブラリを探したらKivyというPythonのライブラリを見つけた。
Kivy: Cross-platform Python Framework for NUI Development
kivyっていうpythonのライブラリがいい感じでGUI書けそう。まだRaspberry Piでビルド終わってないからWindowsで試してるけど。
— loca (@locatw) 2015, 1月 12
でもRaspberry Piだとうまく動かなくて、また色々調べた結果、SPI接続のディスプレイにはGPUを使って描画ができないということだった。
Raspberry Piでkivyがうまく動かないな。exampleにあるやつを起動しても起動プロセスの途中で止まっちゃう。
— loca (@locatw) 2015, 1月 12
HDMIでディスプレイに繋いだらRaspberry Piでkivyの3DRenderingのexample動いた。さっき動かなかった時はHDMI繋がずにPiTFTで表示してたんだけど原因が分からん。エラー出してたわけでもないし。
— loca (@locatw) 2015, 1月 12
Raspberry PiとPiTFTでkivyが起動できない問題、やっと結論出た。PiTFTはSPIで接続してるからOpenGLES使うkivyは動かせないということらしい。HDMIでディスプレイに接続した時は動いたからあってるっぽい。https://t.co/Ad2Trut3d1
— loca (@locatw) 2015, 1月 13
結局操作パネルとして使うのは今回は見送ることにした。
はぁ、Raspberry PiでwxPython使うと描画が遅くてOpenGLES使おうとするとPiTFTだと動かせないとは。うまくいかないねぇ。
— loca (@locatw) 2015, 1月 13
PiTFTの所感
色々試して使ってみた感想としては、
- Raspberry Piのデスクトップを操作した感じではメニューなんかはパッと表示される。
- 一定時間経つと液晶のバックライトがOFFになるのは良い。
- 指だと少し強めにタッチしないと反応しないのでそこを設定で調整できたらよかったかも。スタイラスなら普通にタッチしても反応する。
- 1回タッチしただけでも2回以上選択したと判定されることが多くて、選んだつもりがないのに指の下にあったアプリケーションが起ち上がったりするのが不便。
- SPI接続だと描画が遅くて使い所が限られる気がする。HDMI接続ならOpenGLESが使えるので問題はなさそうなのに残念。
SPI接続だと描画が遅いのが一番ネックだと感じた。
今回はGUIコントロールを表示してみたけど、インフォメーションボード的な使い方だとどうなるかは興味ある。
その他
Kivyは見た目が洗練されてたのでWindowsなどで使うときは良さそうだと思った。
ブログの方針変更
今このブログとQiitaを併用していて、メインはこのブログ、Qiitaは技術Tipsという使い分けをしていたんですが、方針を変更してQiitaをメインにしようと思います。
それでこのブログは自分の考えや勉強会の感想、個人的なメモといった事を書く場にしようと思います。(技術関連の話になることは変わりません。)
自分のQiitaのページです。 https://qiita.com/locatw
今後もよろしくお願いします。
VimのフォントをConsolas+Migu1Mにする
githubで表示されるソースコードのフォントが見やすかったのでVimに設定する方法を調べてみました。
環境はWindows7 x64です。
githubのフォントを調べる
githubのソースコードのフォントを調べてみるとConsolasみたいですね。
(見た目で判断したので違うかもしれません。)
早速vimrcに設定してみると、英数字はきちんと表示されますが日本語が文字化けします。
どうもConsolasには日本語用フォントが入ってないみたいです。
日本語の表示に対応する
Windowsのフォントリンクという機能を使うと、Consolasを使いつつ日本語には別のフォントを指定できるようなのでこれを使います。
日本語フォントはMigu 1Mにしました。
フォントリンクの方法はこのページを参考にしました。
http://yutorialudra.blogspot.jp/2013/03/migu-1m-consolas.html(更新:リンク切れ)
設定手順:
- レジストリエディタで"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontLink\SystemLink"を開く
- 右クリックして「新規」→「複数行文字列値」を選択する
- 名前を「Consolas」、値を「migu-1m-regular.ttf,Migu 1M」に設定する
- PCを再起動する
これで無事に日本語も表示されるようになりました。
ちょっと日本語が横に伸びてるのが気になりますけど、プログラム書いてる時はコメントくらいしか日本語はないので妥協します。
RakeでC++をビルドする
ちょっとC++のソースコード書きたいときにVisual Studio立ち上げるのが億劫になったので、Vimでさくっと書ける環境を整えてます。
ただ、ビルドするのにmakefileを書きたくなかったので色々調べてたら、RakeでC++をビルドできるみたいなので書いてみました。
環境
Rakefile
一番単純なものはネットで検索すると出てくるんですが、少し物足りなかったので機能を追加しました。
- ビルド, リビルド, クリーンを実装
- 中間生成物(オブジェクトファイルなど)はビルド用ディレクトリに格納
- 依存情報ファイル(.mf)を使ってヘッダファイルの依存関係に対応
rakefile for C++ source build.
解説
使い方は最初にRakefile内の定数を編集して、
CPPFLAGS = %w[] # コンパイルオプション
LDFLAGS = %w[] # リンクオプション
INC_DIRS = [] # インクルードディレクトリ
LIB_DIRS = [] # ライブラリディレクトリ
TARGET = "app" # 生成する実行ファイル名
SRC_ROOT = "." # ソースファイルが格納されているディレクトリ
LIBS = FileList[] # ライブラリファイル
ビルドするときは、
$ rake
生成したファイルを削除したいときは、
$ rake clean # オブジェクトファイルなどの中間生成物のみ削除する
$ rake clobber # 実行ファイルとビルド用ディレクトリも削除する
リビルドしたいときは、
$ rake rebuild
という感じです。
今回はヘッダーファイルを含めた依存関係を扱いたかったのでその情報を"gcc -MM"でファイルに出力してるんですが、そのファイルの情報を使うときに問題が出て苦労しました。
Rakeにはimportというメソッドがあってこれで出力したファイルを読み込めるんですが、どうもソースファイルとオブジェクトファイルが同じディレクトリにないとうまく動かないようです。
でも今回はオブジェクトファイルなんかのビルド用中間ファイルは別ディレクトリに出力したかったので、自前でファイルを読み込んで依存関係を設定してます。
その設定はオブジェクトファイルの依存ファイルをdependenciesメソッドを呼び出して(154行目)動的に行っています。
dependenciesメソッドでは、
- file(depfile).invokeで、対象のオブジェクトファイルと対応する依存情報ファイルとの間に依存関係を設定して解決する。(95行目)
- load_depfileメソッドを呼び出して対象のオブジェクトファイルが依存しているファイル名のリストを取得する。(97行目)
という処理をしていて、1で依存情報ファイルを更新する必要があるときはそのファイルのルール(160行目)が呼び出されてファイルが更新される、という仕組みです。
わかると難しくないんですが、Rubyはほとんど書いたことがない上にRakeの仕組みを勉強しつつやってたら1週間くらいかかりました。 おかげでだいぶRubyにもRakeに慣れたんですが、まだまだ腕が足りないですね。がんばります。