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");