赤外線学習リモコンR2-D2
夏は暑い。
外が暑い中を帰ってきて、自宅も暑いとうんざりする。
帰宅途中にエアコンをオンにできたらいいのに。
…そうだ!R2-D2に頼もう!
ということで、赤外線で色々な機器を操作するR2-D2を作ることに。
今回は、外出先からはスマホのアプリで自宅の家電を操作できるように、
自宅ではR2-D2に話しかけることで家電を操作できるようにします。
いわゆるホームオートメーションシステム、あるいはホームコントローラーと呼ばれるような仕組みです。
最近で言えば、鬼奴が帰らないことで有名なやつですね。
これまで、下記のように色々な赤外線学習リモコンを作ってきましたが、いずれも今一歩という感じでしたので、
今回は非常に便利で安価な小型赤外線モジュールirMagicianと小型コンピュータRaspberry Piを使って作ってみることにしました。
- Devel/電子工作/トラ技付録78K0 USBマイコン基板/赤外線学習リモコンR2-D2
- Devel/電子工作/Arduino/赤外線学習リモコンR2-D2
- Devel/電子工作/RaspberryPi/赤外線学習リモコン
- Devel/電子工作/RaspberryPi/ホームオートメーションシステム
必要なもの
ハードウェア
項目 | 説明 |
Raspberry Pi | 名刺サイズの超小型コンピュータ。Linuxなどが動作する。 |
irMagician | Windows、Mac OS X、Linux、Androidなどで使える小型赤外線リモコンアダプタ。 |
microUSBケーブル | Raspberry PiとirMagicianを接続するため。 今回はTIMELY 好きな位置に固定できるフレキシブル型USB2.0ケーブル 60cm TM-microUSB-Fを使用しました。 |
USBマイク | 音声コマンドで操作できるようにするため。 今回はPLANEX USBオーディオ変換アダプタ PL-US35APとSANWA SUPPLY フラット型PCマイク MM-MC23を組み合わせました。 なるべく無指向性を選んだ方がよいかと思います。 |
セルフパワーUSBハブ | Raspberry Piの電源は弱いので、USB機器の安定動作のために使用。今回はiBUFFALO USB2.0ハブ BSH4A01BKを使いました。 |
WiFiドングル | Raspberry Piの通信は有線LANなので、WiFiドングルがあると配線が一本減って便利。今回はPLANEX GW-USNano2を使いました。 |
Star Wars Bank R2-D2 | 上記を格納するケースとして使用。 |
ソフトウェア
項目 | 説明 |
Julius | 大語彙連続音声認識エンジン。音声コマンドを認識するために使用します。 |
![]() | 私が実装した赤外線送信HTTPサーバと音声コマンド式HTTPクライアントなどのPythonスクリプトです。Raspberry Pi上で動作させます。 |
![]() | 上記赤外線送信サーバ用のHTTPクライアントアプリのソースコードです。Androidスマホ上で動作します。 |
手順
次の手順で進めます。
- Raspberry PiへのOSのインストールやWiFiドングルのセットアップなどの初期設定
- irMagicianのセットアップと動作確認
- Raspberry PiにGETリクエストすると赤外線信号が送信されるようなHTTPサーバの準備
- 前述のHTTPサーバにGETリクエストするHTTPクライアントアプリ for Androidの準備
- 日本語音声認識環境の準備
- Raspberry Piに話しかけると、前述のHTTPサーバにGETリクエストするHTTPクライアントの準備
- Star Wars Bank R2-D2へのハードウェアの格納
1.Raspberry PiへのOSのインストールやWiFiドングルのセットアップなどの初期設定 

こちらをご覧ください。
2.irMagicianのセットアップと動作確認 

- irMagicianをRaspberry PiにmicroUSBケーブルで接続する。
- シリアル接続して動作確認する。(詳細はこちらを参照)
3.Raspberry PiにGETリクエストすると赤外線信号が送信されるようなHTTPサーバの準備 

http://【Raspberry PiのIPアドレス】/【予め赤外線信号を記録したファイル】 にGETリクエストを送ると、任意の赤外線信号を送信できるようにします。
- Raspberry PiにirMagicianを接続します。
- あらかじめ次のようにしてpySerialをインストールしておきます。
sudo aptitude install python-serial
- irMagicianの公式ページの「取得したデータの保存 (Save)」Pythonスクリプトで赤外線信号をJSON形式でファイルに保存します。
(下記ではexample.jsonに保存したとして説明します) - 前述のr2d2.tar.gzから下記のPythonスクリプトを取り出す。
irMagicianHTTPServer.py
"""irMagician HTTP Server. This module builds on SimpleHTTPServer by implementing the standard GET and HEAD requests to json data for irMagician. """ __version__ = "0.1" __all__ = ["irMagicianHTTPRequestHandler"] import BaseHTTPServer import SimpleHTTPServer import serial import json ser = serial.Serial("/dev/ttyACM0", 9600, timeout = 1) ser.readline() class irMagicianHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): server_version = "irMagicianHTTP/" + __version__ def do_GET(self): """Serve a GET request.""" f = self.send_head() if f: self.ir_play(f); f.close() self.wfile.write("\r\n") def ir_play(self, f): """Send IR signal to irMagician.""" json_data = json.load(f) recNumber = len(json_data['data']) rawX = json_data['data'] ser.write("n,%d\r\n" % recNumber) ser.readline() postScale = json_data['postscale'] ser.write("k,%d\r\n" % postScale) ser.readline() for n in range(recNumber): bank = n / 64 pos = n % 64 if (pos == 0): ser.write("b,%d\r\n" % bank) ser.write("w,%d,%d\n\r" % (pos, rawX[n])) ser.write("p\r\n") ser.readline() def test(HandlerClass = irMagicianHTTPRequestHandler, ServerClass = BaseHTTPServer.HTTPServer): SimpleHTTPServer.test(HandlerClass, ServerClass) if __name__ == '__main__': test()
- irMagicianHTTPServer.pyを実行する。
- ウェブブラウザからJSON形式の赤外線信号ファイルを次のようにリクエストすると赤外線信号が送信されるかどうかを確認する。
("192.168.0.100"はRaspberry PiのプライベートIPアドレスに読み替えてください。また、"example.json"部分は前述のJSONファイルです。)http://192.168.0.100:8000/example.json
- irMagicianHTTPServer.pyを停止する。
ポート番号は適宜変えたほうがよいでしょう。
4.前述のHTTPサーバにGETリクエストするHTTPクライアントアプリ for Androidの準備 

- Raspberry Piの上記HTTPサーバが使っているポートのみを外部に公開する。
(NECのルータの場合は「ポートマッピング」、バッファローの場合は「アドレス変換」などと呼ばれています。) - ウェブブラウザからJSON形式の赤外線信号ファイルを次のようにリクエストすると赤外線信号が送信されるかどうかを確認する。
("172.16.0.1"はRaspberry PiのパブリックIPアドレスに読み替えてください。また、"example.json"部分は前述のJSONファイルです。)http://172.16.0.1:8000/example.json
- 前述のSampleAndroidApp.zipを解凍する。
- res\xml\pref.xmlのIPアドレスを自宅のRaspberry PiのパブリックIPアドレスに書き換える。
(これがデフォルトのIPアドレスになります。) - src\com\cubic9\android\r2d2athome\Main.javaのSSIDを自宅のWiFiのSSIDに書き換える。
- src\com\cubic9\android\r2d2athome\Main.javaのHOME_IPを自宅のRaspberry PiのプライベートIPアドレスに書き換える。
(一部のルータではLAN側からルータにアクセスすると、ポートマッピングが働かないため、前述のSSIDで接続しているときは、こちらで設定したIPアドレスを使用するようにしています。) - apkをexportする。
- Androidスマホにインストールする。
(Playストアには公開せず、ファイル転送してインストールしましょう。AirDroidを使うと便利です。) - アプリを起動する。
- IPアドレスの設定をする。
(上記pref.xmlで設定したIPアドレスを上書きする形になります。) - アプリのボタンを押すと赤外線信号が送信されるかどうかを確認する。
5.日本語音声認識環境の準備 

こちらをご覧ください。
6.Raspberry Piに話しかけると、前述のHTTPサーバにGETリクエストするHTTPクライアントの準備 

- 前述のr2d2.tar.gzから下記のcommand.yomiを取り出す。
command.yomi
テレビ電源 てれびでんげん テレビ電源 てれびつけて テレビ電源 てれびけして テレビ電源 てれびきって テレビ電源 てれびをつけて テレビ電源 てれびをけして テレビ電源 てれびをきって テレビ音量UP てれびおんりょーあっぷ テレビ音量DOWN てれびおんりょーだうん コンポ電源 こんぽでんげん コンポ電源 こんぽつけて コンポ電源 こんぽけして コンポ電源 こんぽきって コンポ電源 こんぽをつけて コンポ電源 こんぽをけして コンポ電源 こんぽをきって コンポCD再生 こんぽさいせー コンポCD再生 しーでぃーさいせー コンポMD再生 えむでぃーさいせー コンポ停止 しーでぃーとめて コンポ停止 えむでぃーとめて コンポ音量UP こんぽおんりょーあっぷ コンポ音量DOWN こんぽおんりょーだうん 電気電源 でんきでんげん 電気電源 でんきつけて 電気消して でんきけして 電気消して でんききって 電気電源 でんきをつけて 電気消して でんきをけして 電気消して でんきをきって エアコン電源 えあこんでんげん エアコン電源 えあこんつけて エアコン消して えあこんけして エアコン消して えあこんきって エアコン電源 えあこんをつけて エアコン消して えあこんをけして エアコン消して えあこんをきって NHK総合 えぬえっちけー NHK総合 えぬえいちけー NHK総合 そーごー NHK教育 きょーいく 日本テレビ にほんてれび 日本テレビ にってれ テレビ朝日 てれびあさひ テレビ朝日 てれあさ TBS てぃーびーえす テレビ東京 てれびとーきょー テレビ東京 てれとー フジテレビ ふじてれび レコーダーホーム れこーだーほーむ レコーダー戻る もどる レコーダー前のチャプター まえのちゃぷたー レコーダー次のチャプター つぎのちゃぷたー レコーダー巻き戻し まきもどし レコーダー早送り はやおくり レコーダー再生 れこーだーさいせー レコーダー停止 れこーだーてーし レコーダー停止 れこーだーていし R2-D2ダンス あーるつーだんす R2-D2ダンス あーるつーにぎやかし
- ご家庭の環境に合わせて適宜カスタマイズする。
- yomi2voca.plでcommand.dicに変換する。(詳細はこちらを参照)
- 前述のr2d2.tar.gzからhomeautomation.jconfを取り出す。
- command.dicとhomeautomation.jconfをJuliusの実行ディレクトリに移動する。
- 前述のr2d2.tar.gzから下記のPythonスクリプトを取り出す。
HomeAutomationWithVoiceCommand.py
# -*- coding: utf-8 -*- import socket import requests host = 'http://localhost:8000/' s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('localhost', 10500)) sf = s.makefile('rb') while True: line = sf.readline().decode('utf-8') if line.find('WHYPO') != -1: print line if line.find(u'テレビ電源') != -1: r = requests.get(host + 'KDL-40W900A_power.json') elif line.find(u'テレビ音量UP') != -1: r = requests.get(host + 'KDL-40W900A_vol_up.json') r = requests.get(host + 'KDL-40W900A_vol_up.json') r = requests.get(host + 'KDL-40W900A_vol_up.json') elif line.find(u'テレビ音量DOWN') != -1: r = requests.get(host + 'KDL-40W900A_vol_down.json') r = requests.get(host + 'KDL-40W900A_vol_down.json') r = requests.get(host + 'KDL-40W900A_vol_down.json') elif line.find(u'NHK総合') != -1: r = requests.get(host + 'KDL-40W900A_ch01.json') elif line.find(u'NHK教育') != -1: r = requests.get(host + 'KDL-40W900A_ch02.json') elif line.find(u'日本テレビ') != -1: r = requests.get(host + 'KDL-40W900A_ch04.json') elif line.find(u'テレビ朝日') != -1: r = requests.get(host + 'KDL-40W900A_ch05.json') elif line.find(u'TBS') != -1: r = requests.get(host + 'KDL-40W900A_ch06.json') elif line.find(u'テレビ東京') != -1: r = requests.get(host + 'KDL-40W900A_ch07.json') elif line.find(u'フジテレビ') != -1: r = requests.get(host + 'KDL-40W900A_ch08.json') elif line.find(u'コンポ電源') != -1: r = requests.get(host + 'SA-PM35MD_power.json') elif line.find(u'コンポ音量UP') != -1: r = requests.get(host + 'SA-PM35MD_vol_up.json') r = requests.get(host + 'SA-PM35MD_vol_up.json') r = requests.get(host + 'SA-PM35MD_vol_up.json') elif line.find(u'コンポ音量DOWN') != -1: r = requests.get(host + 'SA-PM35MD_vol_down.json') r = requests.get(host + 'SA-PM35MD_vol_down.json') r = requests.get(host + 'SA-PM35MD_vol_down.json') elif line.find(u'コンポCD再生') != -1: r = requests.get(host + 'SA-PM35MD_play_cd.json') elif line.find(u'コンポMD再生') != -1: r = requests.get(host + 'SA-PM35MD_play_md.json') elif line.find(u'コンポ停止') != -1: r = requests.get(host + 'SA-PM35MD_stop.json') elif line.find(u'電気電源') != -1: r = requests.get(host + 'HHFZ4290_on.json') elif line.find(u'電気消して') != -1: r = requests.get(host + 'HHFZ4290_off.json') elif line.find(u'エアコン電源') != -1: r = requests.get(host + 'DC-35CEA_cool25.json') elif line.find(u'エアコン消して') != -1: r = requests.get(host + 'DC-35CEA_off.json') elif line.find(u'レコーダーホーム') != -1: r = requests.get(host + 'BDZ-AT950W_home.json') elif line.find(u'レコーダー戻る') != -1: r = requests.get(host + 'BDZ-AT950W_return.json') elif line.find(u'レコーダー前のチャプター') != -1: r = requests.get(host + 'BDZ-AT950W_prev.json') elif line.find(u'レコーダー次のチャプター') != -1: r = requests.get(host + 'BDZ-AT950W_next.json') elif line.find(u'レコーダー巻き戻し') != -1: r = requests.get(host + 'BDZ-AT950W_reverse.json') elif line.find(u'レコーダー早送り') != -1: r = requests.get(host + 'BDZ-AT950W_forward.json') elif line.find(u'レコーダー再生') != -1: r = requests.get(host + 'BDZ-AT950W_play.json') elif line.find(u'レコーダー停止') != -1: r = requests.get(host + 'BDZ-AT950W_stop.json') elif line.find(u'R2-D2ダンス') != -1: r = requests.get(host + 'R2D2_dance.json')
- ご家庭の機器環境に合わせて適宜カスタマイズする。
(command.dicの単語とJSONファイルを対応付けるようにします) - 前述のr2d2.tar.gzからstart_ha.shとstop_ha.shを取り出す。
- screenコマンドを実行する。
- start_ha.shを実行し、Julius、HTTPサーバ、HTTPクライアントの順で起動する。
- command.yomiで登録した単語を発し、irMagicianの緑LEDが点灯し、機器側が反応することを確認する。
- Ctrl+a dでscreenをデタッチする。
上記ではscreenで起動しデタッチすることでログアウト後も実行され続けるようにしていますが、安定動作するようになったらstart_ha.shをinsservできるような起動スクリプトにするとよいかもしれません。
7.Star Wars Bank R2-D2へのハードウェアの格納 

上記ハードウェアをお好みでStar Wars Bank R2-D2に格納してください。
8.電飾で飾り付ける。
下記を参照のこと。
Devel/電子工作/RaspberryPi/マイコン内蔵LED
以上で完成です!!おつかれさまでした
今後の展望
- 誤認識が多いので、Juliusのモジュールモードで表示される単語信頼度(CM)があるしきい値に達さない限り赤外線を送信しないようにする。
- R2-D2にLEDなどの電飾をつける。
- R2-D2の頭の部分が回転するようにする。
- R2-D2にプロジェクタを内蔵する。
Tips
機器が部屋のいろいろな所に散らばっていて赤外線が届かない
上海問屋の赤外線リモコンベンダーDN-IRB530などの赤外線リモコン信号中継器を買うとよいかもしれません。
普通の電気プラグがある機器のコンセントも操作したい
オーム電気 リモコンコンセントOCR-05 07-0155を買うとよいかもしれません。
電灯も操作したい
オーム電気 天井照明器具専用 リモコンスイッチOCR-04 07-0154を買うとよいかもしれません。
そもそもRaspberry Piとか持ってないんだけど…
そんなあなたのために既製品が色々あります。
コメント等ありましたらどうぞ 
参考
- KURO-RSとJuliusで家電をコントロールしてみた : アシアルブログ
- 20.19. SimpleHTTPServer ― 簡潔な HTTP リクエストハンドラ ― Python 2.7ja1 documentation
関連
- Devel/電子工作/トラ技付録78K0 USBマイコン基板/赤外線学習リモコンR2-D2
- Devel/電子工作/Arduino/赤外線学習リモコンR2-D2
- Devel/電子工作/RaspberryPi/赤外線学習リモコン
- Devel/電子工作/RaspberryPi/ホームオートメーションシステム