KURO-RSとJuliusで家電をコントロールしてみた

最近はLinuxの設定ばかりでしたが、今回は趣向を変えてLinuxを使って生活をちょっとだけ便利にする方法を書きたいと思います。

KURO-RSと言えば、玄人志向から発売された赤外線学習リモコンキット。
JuliusはOSSの音声認識エンジンです。
これらを組み合わせれば音声認識リモコンを作ってみました。

はじめに言っておきますが、私の方法では割と誤動作するので、
・ミッションクリティカルな事(医療、軍事などの人の生命に影響する事柄、多額の損害が発生する事柄など)には使用しないでください。
・誤動作しても自己責任でお願いします。
つまり、照明の操作など誤動作しても影響の少ない(電気代くらい)ものでご使用ください。

下記の環境で試しました。
・OS : Debian wheezy
   Linux pc 3.2.0-1-amd64 #1 SMP Sun Feb 5 15:17:15 UTC 2012 x86_64 GNU/Linux
・HW : ZBOXNANO-AD1
 AMD Fusionなマシン。消費電力が最大でも30W程度なので経済的です
 GPUの支援機構によりyoutubeとかニコニコの動画も普通に再生可能。
 GPUの性能がそこそこあるので、WMではCompizを使用した方がサクサク動く。

・照明リモコン: リモコンコンセントOCR-05 07-0155、リモコンスイッチOCR-04 07-0154
 http://www.amazon.co.jp/オーム電機-07-0155-リモコンコンセントOCR-05/dp/B0013L6ACM
 http://www.amazon.co.jp/オーム電機-07-0154-天井照明器具専用-リモコンスイッチOCR-04/dp/B0013L6ACC/

1・KURO-RSの設定

まずはデバイスを接続して、ドライバを組み込む。


# modprobe ftdi_sio vendor=0x0411 product=0x00b3

起動時に組み込むため、/etc/modprobe.d/設定ファイルを作成してください。
面倒ならば、上記コマンドをrc.localにに追記でも可。
※/dev/ttyUSBxの権限を一般ユーザでも書き込めるようにしておくと、一般ユーザでも操作できます。
今回は全部sudo使って作業しています。

2・KURO-RSで赤外線信号を読み取り・送信

ここでperl使ってかっこ良く書けばいいと思いますが、
すでに開発されている先人の知恵をお借りします。
作者に感謝して使います。

http://www.gcd.org/blog/2007/01/113/

そのまま上記サイトの内容を実施すれば使えるようになります。
※実は、KURO-RSについては数年前から使用していますが、今見てみるとなぜか修正している場所があるため、もしかしたら上記のサイトのものでは動かない部分があるのかもしれません。
 動かない場合は自分で修正してみてください。(自分の方はなんのために修正したかわかればその部分を公開すると思います)

以降はこちらのスクリプトを使用できるという事で話を進めます。

コードを登録、送信については実際に実行して確認します。

※私の場合は、照明を3つコントロールするため×ON,OFFということで6つ登録しています。

3・Juliusのインストール

下記から Linux版 Juliusディクテーション実行キット(4.1) をダウンロードしてきます。
私の場合はせっかくなので本体の最新版(4.2)もダウンロードしました。

http://julius.sourceforge.jp/
(ダウンロードメニューにて、Julius最新版、ディクテーションキットそれぞれ)

本体を解凍し、configureを実行します。


./configure --prefix=/usr/local/julius --enable-julian
(中略)
****************************************************************
Julius/Julian libsent library rev.4.2.1:
- Audio I/O
    primary mic device API   : alsa (Advanced Linux Sound Architecture)
    available mic device API : alsa oss
    supported audio format   : RAW and WAV only
    NetAudio support         : no
- Language Modeling
    class N-gram support     : yes
- Libraries
    file decompression by    : gzip command
- Process management
    fork on adinnet input    : no
 
  Note: compilation time flags are now stored in "libsent-config".
        If you link this library, please add output of
        "libsent-config --cflags" to CFLAGS and
        "libsent-config --libs" to LIBS.
****************************************************************

configureの結果で available mic device API の項目に対応できるエンジンが表示されます。
ですが、自分の場合はalsaで動かなかったため(マイクがモノラル16bit非対応?)OSSエミュレーションを使用しました。(後述)

4・Juliusの実行

私の場合はここでかなりハマリました。
最初はalsaにて実行しようとしましたがスピーカーから音はするのにjuliusでもarecordでも録音できず、何をやっても無音状態になりました。
結局のところpulseaudioを入れたところ、なぜか動作するように・・・。
(このあたりは環境依存になる思いますので、うまく行かないようなら別のカード挿してみる、別のエンジンを試してみるなど試行錯誤してみてください。
行き詰まったら休憩するのも手です。何かいい方法を思いつくかもしれません)


padsp julius-4.2.1/julius/julius -C dictation-kit-v4.1/fast.jconf -input mic -input oss -charconv euc-jp utf8 

※padspはpulseaudioでOSSエミュレーションをするためのコマンドです。

こちらで、マイクに話した内容が表示されれば成功です。

5・Julius設定

リモコンに使うならば、認識できる語彙は少ない方が精度が上がります。


</s>    []      silE
<s>     []      silB
光あれ:ヒカリアレ:光あれ:507        [光あれ]    h i k a r i a r e
全て消す:スベテケス:全て消す:507        [全て消す]    s u b e t e k e s u
蛍光灯つける:ケイコウトウツケル:蛍光灯つける:507        [蛍光灯つける]    k e i k o u t o u ts u k e r u
蛍光灯消す:ケイコウトウケス:蛍光灯消す:527        [蛍光灯消す]    k e i k o u t o u k e s u
ライトつける:ライトツケル:ライトつける:507        [ライトつける]    r a i t o ts u k e r u
ライト消す:ライトケス:ライト消す:507        [ライト消す]    r a i t o k e s u
スタンドつける:スタンドツケル:スタンドつける:507        [スタンドつける]    s u t a N d o ts u k e r u
スタンド消す:スタンドケス:スタンド消す:507        [スタンド消す]    s u t a N d o k e s u

辞書ファイルの書式を参考にこんな感じで専用の辞書を作成しておきます。(-wオプションで使用可能)

「光りあれ」については、前にどこかで見た動画で「なにそれかっこいい」と思ったので採用。
誤動作で全部消えてもつけやすいように短い言葉にする目的もあります。
それ以外はそのままの意味です。

これでひと通りの動作はできますが、
Juliusのオプションは全て設定ファイルに書くことができるので、fast.jconfをベースに下記のように設定します。
このファイルを-Cオプションで指定してやれば毎回他のオプションをつける必要はありません。

dictation-kit-v4.1/julius.conf


-w dictation-kit-v4.1/word.list
-h dictation-kit-v4.1/model/phone_m/hmmdefs_ptm_gid.binhmm
-n 5
-output 1
-input mic # マイク入力
-input oss # oss使用
-zmeanframe
-rejectshort 800 # しきい値より短い入力を無視
-module # サーバとして動作(後述)
-charconv euc-jp utf8 # 入出力エンコード指定(内部 euc-jp 出力 utf8)
-lv 5000 

6・Juliusに接続

Juliusはサーバとして動作させることが可能で、-moduleオプションを指定してやれば、ポート10500番で待ち受けます。
(-module ポート番号 と指定すれば変更も可能です)

この待受ポートにソケット通信で繋いでやればデータの受信ができます。

詳細な仕様はこちらをご確認ください。
http://julius.sourceforge.jp/index.php?q=doc/module.html

私の用途ではperlで書けばこんな感じです。
(特定の文字列を拾ったらirrcに命令を出すだけです)


#!/usr/bin/perl
use Switch;
use Socket;
socket(SOCK, PF_INET, SOCK_STREAM, getprotobyname('tcp')) || die;
connect(SOCK, sockaddr_in(10500, inet_aton('localhost'))) || die;
$str = '';
while(1) {
        recv(SOCK, $message, 30, MSG_WAITALL);
        $str .= $message;
        if ($str =~ /\./) {
                print $str;
                switch($str) {
                        case /光あれ/ {
                                system("./irrc -c2 lOn");
                                sleep 1;
                                system("./irrc -c1 l2On");
                                sleep 1;
                                system("./irrc -c3 l3On");
                        }
                        case /全て消す/ {
                                system("./irrc -c2 lOff");
                                sleep 1;
                                system("./irrc -c1 l2Off");
                                sleep 1;
                                system("./irrc -c3 l3Off");
                        }
                        case /蛍光灯つける/ {
                                system("./irrc -c2 lOn");
                        }
                        case /蛍光灯消す/ {
                                system("./irrc -c2 lOff");
                        }
                        case /ライトつける/ {
                                system("./irrc -c1 l2On");
                        }
                        case /ライト消す/ {
                                system("./irrc -c1 l2Off");
                        }
                        case /スタンドつける/ {
                                system("./irrc -c3 l3On");
                        }
                        case /スタンド消す/ {
                                system("./irrc -c3 l3Off");
                        }
                }
                $str = '';
        }
}
# SOCKET切断
close(SOCK);

Juliusを起動した後、上記スクリプトを実行すれば接続できるはずです。

ついでに起動スクリプトも書きます。
本当は/etc/init.d/で起動できる形式にすればかっこいいと思いますが、とりあえずこれで。


#!/bin/bash
exec padsp julius-4.2.1/julius/julius -C dictation-kit-v4.1/julius.conf 2>/dev/null  &
sleep 2
exec /usr/bin/perl socket.pl  &

以上で音声認識リモコンシステムは完成です。
この起動スクリプトを実行し、マイクに話しかければ操作できるかと思います。

7・使用感

概ね正常動作していますが、電話中はもとより、掃除機などの音や全く関係ない独り言などでも誤動作するため注意が必要です。
もしくは、通常では拾わない音(びっくりするほどユートピア!!とか)を3回唱えると操作を受け付けるか全て無視するか切り替えできるように実装してもいいかもしれません。
とはいえ、誤動作するより声で操作できる便利さの方が勝ってます。

例えば、下記のような時に便利さを実感できます。
・寝る前にベッドの上で操作
・読書するときに操作
・両手に荷物を持って家に帰った時に操作
・むしろ、荷物持ってなくても家から出入りする時に操作

半分ネタで構築しましたが、思ったより便利に使っています。

8・その他

この内容は、以前設定した内容を思い出しながら書いたため、全部動作チェックはしていないため、動作しない部分があるかもしれませんがご了承ください。
※現行動いているシステムをリセットしてもう一度構築はしたくなく、その他に実行環境が無いので・・・。