Top/Devel/電子工作/irMagician/赤外線学習リモコンR2-D2

赤外線学習リモコンR2-D2はてなブックマーク

r2d2.jpg

夏は暑い。


外が暑い中を帰ってきて、自宅も暑いとうんざりする。
帰宅途中にエアコンをオンにできたらいいのに。
…そうだ!R2-D2に頼もう!
ということで、赤外線で色々な機器を操作するR2-D2を作ることに。


今回は、外出先からはスマホのアプリで自宅の家電を操作できるように、
自宅ではR2-D2に話しかけることで家電を操作できるようにします。


いわゆるホームオートメーションシステム、あるいはホームコントローラーと呼ばれるような仕組みです。
最近で言えば、鬼奴が帰らないことで有名なやつですね。


これまで、下記のように色々な赤外線学習リモコンを作ってきましたが、いずれも今一歩という感じでしたので、
今回は非常に便利で安価な小型赤外線モジュールirMagicianと小型コンピュータRaspberry Piを使って作ってみることにしました。

irmagician.jpg

必要なもの

ハードウェア

項目説明
Raspberry Pi名刺サイズの超小型コンピュータ。Linuxなどが動作する。
irMagicianWindows、Mac OS X、Linux、Androidなどで使える小型赤外線リモコンアダプタ。
microUSBケーブルRaspberry PiとirMagicianを接続するため。
今回はTIMELY 好きな位置に固定できるフレキシブル型USB2.0ケーブル 60cm TM-microUSB-Fを使用しました。
USBマイク音声コマンドで操作できるようにするため。
今回はPLANEX USBオーディオ変換アダプタ PL-US35APSANWA 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大語彙連続音声認識エンジン。音声コマンドを認識するために使用します。
file赤外線学習リモコンR2-D2一式私が実装した赤外線送信HTTPサーバと音声コマンド式HTTPクライアントなどのPythonスクリプトです。Raspberry Pi上で動作させます。
fileHTTPクライアントアプリ for Androidソースコード上記赤外線送信サーバ用のHTTPクライアントアプリのソースコードです。Androidスマホ上で動作します。

手順

次の手順で進めます。

  1. Raspberry PiへのOSのインストールやWiFiドングルのセットアップなどの初期設定
  2. irMagicianのセットアップと動作確認
  3. Raspberry PiにGETリクエストすると赤外線信号が送信されるようなHTTPサーバの準備
  4. 前述のHTTPサーバにGETリクエストするHTTPクライアントアプリ for Androidの準備
  5. 日本語音声認識環境の準備
  6. Raspberry Piに話しかけると、前述のHTTPサーバにGETリクエストするHTTPクライアントの準備
  7. Star Wars Bank R2-D2へのハードウェアの格納

1.Raspberry PiへのOSのインストールやWiFiドングルのセットアップなどの初期設定 Permalinkはてなブックマーク

こちらをご覧ください。

2.irMagicianのセットアップと動作確認 Permalinkはてなブックマーク

irmagician.jpg
  1. irMagicianをRaspberry PiにmicroUSBケーブルで接続する。
  2. シリアル接続して動作確認する。(詳細はこちらを参照)

3.Raspberry PiにGETリクエストすると赤外線信号が送信されるようなHTTPサーバの準備 Permalinkはてなブックマーク

http://【Raspberry PiのIPアドレス】/【予め赤外線信号を記録したファイル】 にGETリクエストを送ると、任意の赤外線信号を送信できるようにします。

  1. Raspberry PiにirMagicianを接続します。
  2. あらかじめ次のようにしてpySerialをインストールしておきます。
    sudo aptitude install python-serial
  3. irMagicianの公式ページの「取得したデータの保存 (Save)」Pythonスクリプトで赤外線信号をJSON形式でファイルに保存します。
    (下記ではexample.jsonに保存したとして説明します)
  4. 前述の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()
  5. irMagicianHTTPServer.pyを実行する。
  6. ウェブブラウザからJSON形式の赤外線信号ファイルを次のようにリクエストすると赤外線信号が送信されるかどうかを確認する。
    ("192.168.0.100"はRaspberry PiのプライベートIPアドレスに読み替えてください。また、"example.json"部分は前述のJSONファイルです。)
    http://192.168.0.100:8000/example.json
  7. irMagicianHTTPServer.pyを停止する。


ポート番号は適宜変えたほうがよいでしょう。

4.前述のHTTPサーバにGETリクエストするHTTPクライアントアプリ for Androidの準備 Permalinkはてなブックマーク

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

5.日本語音声認識環境の準備 Permalinkはてなブックマーク

julius.png

こちらをご覧ください。

6.Raspberry Piに話しかけると、前述のHTTPサーバにGETリクエストするHTTPクライアントの準備 Permalinkはてなブックマーク

  1. 前述のr2d2.tar.gzから下記のcommand.yomiを取り出す。
    command.yomi
    テレビ電源	てれびでんげん
    テレビ電源	てれびつけて
    テレビ電源	てれびけして
    テレビ電源	てれびきって
    テレビ電源	てれびをつけて
    テレビ電源	てれびをけして
    テレビ電源	てれびをきって
    テレビ音量UP	てれびおんりょーあっぷ
    テレビ音量DOWN	てれびおんりょーだうん
    コンポ電源	こんぽでんげん
    コンポ電源	こんぽつけて
    コンポ電源	こんぽけして
    コンポ電源	こんぽきって
    コンポ電源	こんぽをつけて
    コンポ電源	こんぽをけして
    コンポ電源	こんぽをきって
    コンポCD再生	こんぽさいせー
    コンポCD再生	しーでぃーさいせー
    コンポMD再生	えむでぃーさいせー
    コンポ停止	しーでぃーとめて
    コンポ停止	えむでぃーとめて
    コンポ音量UP	こんぽおんりょーあっぷ
    コンポ音量DOWN	こんぽおんりょーだうん
    電気電源	でんきでんげん
    電気電源	でんきつけて
    電気消して	でんきけして
    電気消して	でんききって
    電気電源	でんきをつけて
    電気消して	でんきをけして
    電気消して	でんきをきって
    エアコン電源	えあこんでんげん
    エアコン電源	えあこんつけて
    エアコン消して	えあこんけして
    エアコン消して	えあこんきって
    エアコン電源	えあこんをつけて
    エアコン消して	えあこんをけして
    エアコン消して	えあこんをきって
    NHK総合	えぬえっちけー
    NHK総合	えぬえいちけー
    NHK総合	そーごー
    NHK教育	きょーいく
    日本テレビ	にほんてれび
    日本テレビ	にってれ
    テレビ朝日	てれびあさひ
    テレビ朝日	てれあさ
    TBS	てぃーびーえす
    テレビ東京	てれびとーきょー
    テレビ東京	てれとー
    フジテレビ	ふじてれび
    レコーダーホーム	れこーだーほーむ
    レコーダー戻る	もどる
    レコーダー前のチャプター	まえのちゃぷたー
    レコーダー次のチャプター	つぎのちゃぷたー
    レコーダー巻き戻し	まきもどし
    レコーダー早送り	はやおくり
    レコーダー再生	れこーだーさいせー
    レコーダー停止	れこーだーてーし
    レコーダー停止	れこーだーていし
    R2-D2ダンス	あーるつーだんす
    R2-D2ダンス	あーるつーにぎやかし
  2. ご家庭の環境に合わせて適宜カスタマイズする。
  3. yomi2voca.plでcommand.dicに変換する。(詳細はこちらを参照)
  4. 前述のr2d2.tar.gzからhomeautomation.jconfを取り出す。
  5. command.dicとhomeautomation.jconfをJuliusの実行ディレクトリに移動する。
  6. 前述の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')
  7. ご家庭の機器環境に合わせて適宜カスタマイズする。
    (command.dicの単語とJSONファイルを対応付けるようにします)
  8. 前述のr2d2.tar.gzからstart_ha.shとstop_ha.shを取り出す。
  9. screenコマンドを実行する。
  10. start_ha.shを実行し、Julius、HTTPサーバ、HTTPクライアントの順で起動する。
  11. command.yomiで登録した単語を発し、irMagicianの緑LEDが点灯し、機器側が反応することを確認する。
  12. Ctrl+a dでscreenをデタッチする。


上記ではscreenで起動しデタッチすることでログアウト後も実行され続けるようにしていますが、安定動作するようになったらstart_ha.shをinsservできるような起動スクリプトにするとよいかもしれません。

7.Star Wars Bank R2-D2へのハードウェアの格納 Permalinkはてなブックマーク

上記ハードウェアをお好みで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とか持ってないんだけど…

そんなあなたのために既製品が色々あります。

コメント等ありましたらどうぞ :)

最新の10件を表示しています。 コメントページを参照

  • 超時空伝説研究所 at 2014-07-28 (Mon) 20:36

    こんばんは。参考になります。http://blogs.yahoo.co.jp/ryo_hirayanagi

    • 超時空伝説研究所 at 2014-07-28 (Mon) 20:46

      こんばんは。早速質問があります。今回のシステムで、音声コマンドの処理もHTTPクライアントで行っている理由は、何かあるのでしょうか?

  • 超時空伝説研究所 at 2014-07-28 (Mon) 20:41

    すみません。コメント途中で、ポストされてしまいました。当方、Hasbro社製のInteractive R2-D2という機体をベースに、音声認識便利ロボットに改造しようというプロジェクトを推進しております。RPiでlircを動かし、エアコン、TVを自作の赤外線リモコンモジュールで操作するところまではできました。今後、こちらのブログを参考にして音声でリモコン・コマンドを発動させたいと思います。また、WEBからの操作もできるようにしたいですね。よろしければ、情報交換させて下さい。ではまた。

  • きゅーこん(管理者) at 2014-07-30 (Wed) 00:58

    おおー!憧れのマシンです!音声認識時にわざわざHTTPリクエストしている理由の大半は、過去に音声認識ハードと赤外線送信ハードが分かれていたことの名残です。その他にJSONパース部分などの処理を分散させたくなかったという意図もあります。情報交換楽しみにしてます! :)

name:

参考

関連

Amazon

差分 一覧