Juliusのマイクデバイスの問題

juliusを使うとき、マイクデバイスが見つからないというエラーはよく出る。これは、新しいraspiのosで、/dev/dspデバイスが使えないからだった気がするが、これはjuliusのコンパイル時に、alsaのマイクデバイスを使うことを指定して困ぱいすれば回避できるようだ。具体的には、
Juliusのコンパイル時に、
./configure –with-mictype=alsa
を指定すれば良い。ただ、alsaのヘッダーがないと言われるので、事前に、
sudo apt-get install libasound2-dev libesd0-dev libsndfile1-dev
を実行しておかなければならない。
さらにJuliusを立ち上げる時に
export ALSADEV=”plughw:1,0″
の環境変数をしてしなければならない。1,0の箇所は、マイクデバイスの番号を
arecord -l
で確認しなければならない。

ロボットの音声認識システムの調整

この間、1000行あまりのemilyスクリプトを処理しているが、色々な問題を解決してそれはできるようになった。

ただ、juliusは、すべてスクリプトのどれかの言葉に一致させてしまうので、全然関係ない言葉でも、それに反応してしまうという問題が前から気づいていた。それでは実際のネタでは使えない。(今は、サリーからtelepathyでもらった言葉で反応するようにしているので問題はないが)

そこで、通常のjuliusのディクテーションセットを同時に読み込ませて、そちらにも一致させれば問題ないだろうと思った。実際、juliusは、複数のモデルを組み込んで認識する能力を持っているということなので、それを実際に組み込もうというものだ。

まず、Juliusのサイトにあるディクテーションキットから必要なファイルを取ってくる。言語モデルを、main2.jconfとしよう。main.jconf 余計なものを切り取ってついのようなものにする。

# main2.jconf
-input mic
-LM emily-l1
# mkbingramで作成したバイナリ形式
-d bccwj.60k.bingram
## 単語辞書ファイル
-v bccwj.60k.htkdic

ここに記載してあるbingramファイルとhtkdicファイルを、この場合は同じフォルダに置いておかなければならない。パスを指定すれば良いのだが。注意点として、-input micはグローバルオプションなので、何よりも早い位置に置いておかなければならない。最初の設定ファイルのその頭という意味のようである。
-LM emily-l1
言語モデルのセクション開始の宣言である。名前をemily-l1はセクション名で、後で効いていくる
ディクテーションキットの言語モデルは巨大なのでバイナリファイル化している。
続いて、ディクテーションキットの音響モデルである。ファイル名を、am-gmm2.jconf としよう。

# ディクテーションキット GMM-HMM版音響モデル・入力設定
##
-AM emily-a1
# 音響モデル: GMM-HMM
-h jnas-tri-3k16-gid.binhmm
-hlist logicalTri-3k16-gid.bin

-AMは音響モデルのセクション開始を表しそのあとに、名前が続いている。二つのファイルも同じフォルダに用意しておかなければならない。

続いて、emily.jconfである。

##############
-LM emily-l2
-gram SALLYHAL2180809
-AM emily-a2
-h hmmdefs_ptm_gid.binhmm
-hlist logicalTri
-SR SR1 emily-a1 emily-l1
#### 探索パラメータ
-b 1500 # 第1パスのビーム幅(ノード数) triphone,PTM,engine=v2.1
-b2 100 # 第2パスの仮説数ビームの幅(仮説数)
-s 500 # 第2パスの最大スタック数 (仮説数)
-m 10000 # 第2パスの仮説オーバフローのしきい値
-n 1 # 第2パスで見つける文の数(文数)
-output 1 # 第2パスで見つかった文のうち出力する数 (文数)
-SR SR2 emily-a2 emily-l2
#### 探索パラメータ
-b 1500 # 第1パスのビーム幅(ノード数) triphone,PTM,engine=v2.1
-b2 100 # 第2パスの仮説数ビームの幅(仮説数)
-s 500 # 第2パスの最大スタック数 (仮説数)
-m 10000 # 第2パスの仮説オーバフローのしきい値
-n 1 # 第2パスで見つける文の数(文数)
-output 1 # 第2パスで見つかった文のうち出力する数 (文数)

モデルは、SALLYHAL2180809という名前になっていて、この名前と、.dfaというサフィックスのファイルおよび.dictという辞書ファイルを用意しなければならない。言語モデルと音響モデルを指定する。

さらに -SRは、これまでのモデルをまとめて指定するものである。名前と、どの言語モデルと音響モデルのセットなのかを指定する。この-SRのセクションの中で、それぞれのモデルの副次的パラメータを指定する。

emilyの作成するファイルをeucファイルとなっているのだが、ディクテーションキットはUTF-8になっている。だから、emily作成ファイルは、nkf -u などでUTF-8に返還しなければならない。違う文字コードではだめなのである。

これで、
julius -C main2.jconf -C am-gmm2.jconf -C emily.jconf
とすれば、起動できる。

ただ、これでは、当初の思い通りの結果にはならない。確かに、それぞれで認識結果を同時に出してくるので、いいのだが、どちらのものが、どれだけ一致しているかが、スコアから判定できないような感じなのだ。

だから、やはり、emilyのスクリプトで、他の言葉の可能性を受け止めるようにしなければならないようだ。

HAL2の設計

新しいロボットHAL2を作り始めている。HAL1から何を改善したいのか。

(1)何よりも、音声出力をモーター制御から分離する。HAL1の場合、モーターを動かしているときは、雑音が極端に大きく、音声を出せなかった。だから、リレーを使って、アンプをオンオフさせていた。最初は、電源から雑音のせいかと思ったが、よくよく調べると、音を作るところからくる雑音だった。最もあり得るのは、DCモーターにパルス電源 PWMをソフトウェアで送っているのだが、そのパルス作成に絡むものだ。だから、どうしてもモーター系と音声出力系を切り離す必要があった。だから、HAL2では、音声出力をもう一台のコンピュータ RaspberryPI Zeroに任せる予定だ。こうすれば、走りながらでも喋らせることができるはずである。

(2)実際使えない、超音波距離センサーをやめる。

(3)電源系がまとまりがなく、雑然としていたのをスッキリさせる。可能であれば、充電制御をソフトウェでさせたい。

(4)それと決定的に大きなもののもう一つは、ホイールをメカナムホイールから、ゴムタイヤに変えること。メカナムホイール は、横に動くなど面白い動きができそうなので使ったが、タイヤの回転に滑りが入って、回転数と位置の対応に、誤差がかなり出て困ったので。ゴムタイヤは、グリップがいいので、動きも機敏になり概略の位置を把握しやすくなるはずである。正確なところは、距離センサーをレーダーにして把握させる。

テレパシーの制御

ネタ見せで一番失敗しているのは、テレパシーの問題。テレパシーは、ロボットどうしのコミュニケーションのプロトコルである。ロボットどうしのテレパシーが機能しないとネタが成立しない。最近は、テレパシーをチェックするダイアローグをいれて、サリーに「テレパシーチェック」と語りかける。これで、サリーがHALにテレパシーを送り、レスポンスが返ってきたら、サリーが「大丈夫です」とこたえるというシステムにしていた。

しかし、ロボットに話しかけるというのがまわりに迷惑をかける。そこで、スクリプトは無関係にスマホのコントローラー場で確認できるようにした。

電源問題

常に心配なことの一番は、電源問題である。ロボットHALには12V2000mAhのニッケル水素バッテリーが4つ並列に乗っている。大きすぎるかもしれないとは思うが、モーターは結構電気を食うので、しかたがない。ただ、充電をどうするかが悩ましい。ニッケル水素電池は、リチウムイオン電池より安全だとはいわれている。継ぎ足し充電ができないとも言われる。過充電は避けなければならない。

充電用には、24Vのアダプタ経由で15Vに落として、電池に持っていっている。この電圧を13Vより下げたら充電効果がなくなった。逆流防止のためにダイオード(60V)をはさんだ。過充電を避けるために、スイッチ経由で電池の両端の電圧を測れるようにした。スイッチを入れると表示する。使っているニッケル水素バッテリーは、充電すると電圧が13V付近で安定するので、充電完了のタイミングをとらえるのが難しい。

なんどもやっているうちに、電池の特性がわかるのではないかと思っている。

サリーの顔を識別させる

ロボット用のcomputerであるraspberrypi3にインストールしたopencvには、人の顔や瞳を自動で認識する識別器がすでに付属している。それは大変便利で、raspberrypiに接続したカメラで、すぐに識別が可能になる。

もし、サリーの顔が識別できれば、ロボットはサリーに向けて自動で近づいたり離れたりできるようになる。これはとても便利だ。しかし、opencv付属の人の顔の識別器では、サリーの顔を識別できないことがわかった。だから、サリーの顔を識別する識別器を自作した。

参考にさせていただいたサイトは、こちらである。

今後、サリー以外の物体認識にも使いたいのでメモしておく。

(1)positive画像とnegative画像:検索画像のダウンロード
フリーのツールはたくさんあるので、なんでもいいと思うが、私は、こちらのを使わせていただいた。どのサイトか、使えないサイトもあったが、特に大きな問題はなかった。このダウンロードソフトを使って、ワードをrobot naoで検索して得られた画像、positive画像約650枚ほどを使った。ただし、gifは使えない、pngは使えるのかもしれないが、削除したので100枚ほど少なくなった。jpgは、jpegとしてもJPGと拡張子が違っていてもOKのようだ。
naoの顔が入っていないnegative画像も、このソフトで、確か「人形 部屋」とかいう検索をかけてダウンロードして、500ほどで打ち切った。

(2)顔画像の位置の指定
positive画像のそれぞれについて、naoの顔がある位置を指定するのがとても面倒だった。600枚ほどの位置指定に3,4時間かかったような気がする。TrainingAssistantというフリーのソフトを使わせていただいた。超便利だった。指示通りにアプリを組み込む。そして、先ほどダウンロードした画像を、上記サイトに指示されているフォルダーに放り込む。
% python views.py
で、自前のウェッブサーバーを立ち上げて、ブラウザで
http://localhost:5000
を表示させると、画像が順番に出てくるので、naoの顔の部分の座標をマウスをスライドさせて指定する。それらは、info.datファイルに次のような感じで自動的に保存される。
static/img/Nao_robot.jpg 1 434 2 316 271
static/img/29437446525_059b230e13_z.jpg 2 324 93 86 67 219 148 38 30
・・・・・・
最初が画像のパスで、次がその画像の中の顔の数、そして座標とサイズである。

(3)positive.datとnegative.datの作成
画像リストデータファイルを作成する。positive.datは、新しい場所に置き換えた場合も元々の場合も、そのフォルダーの絶対パスを冒頭のパスに全て書き換える。私の場合は、次のステップのvectorファイルの作成が、macではうまくいかず、raspberrypi に全部移したので、そちらのパスに書き換えた。negative.datは、単にその画像のある絶対パスのリストで良い。

(4)positiveベクトルの作成
Macのopencvでは、opencv_createsamplesがうまく機能しなかった。原因は不明。で、raspberrypiのopencvで作成することにした。linuxmintでもよかったかと思う。どのosのopencvでもいいのだ。
Raspberrypiのopencvは、cameraを使用する関係で、少し手の込んだインストールが必要で、。次のサイトに基づいている。
https://qiita.com/NaotakaSaito/items/f1f1548c8b760629cd26
あとは、positive.datが置いてあるフォルダでopencv_createsampleコマンドを実行すればいい。私の場合は次のようにした。
opencv_createsamples -info positive.dat -vec positive.vec -num 574 -w 40 -h 40
-numは、positive画像数である。-w 40 -h 40は、ベクトルサイズらしく、よくわからない。ただ、認識対象の映像の中で最小認識可能な画像サイズと考えればいいようだ。私の場合、画像サイズを、3320X240にしているので、その中で、顔が最小限どのくらいのサイズで映った時に認識して欲しいかという基準でやったが、もっと大きくてもいいかもしれない。(その後、60X60でやってみた。この60X60の方がnaoの顔を安定して識別しつずける可能性があるように思えた)

(5)学習器の作成
私の場合のコマンドは次のようになった。
opencv_traincascade -data /home/pi/Project/ObjectRecognition/data/model -vec /home/pi/Project/ObjectRecognition/src/positive.vec -bg /home/pi/Project/ObjectRecognition/src/negative.dat -numPos 450 -numNeg 400 -featureType HOG -maxFalseAlarmRate 0.1 -w 40 -h 40 -minHitRate 0.97 -numStages 17
絶対パスで指定しなくても良いかと思う。
途中までやったのは生かされる。

最終の出力は以下のようである。
———————————————
Training parameters are pre-loaded from the parameter file in data folder!
Please empty this folder if you want to use a NEW set of training parameters.
——————————————–
PARAMETERS:
cascadeDirName: /home/pi/Project/ObjectRecognition/data/model
vecFileName: /home/pi/Project/ObjectRecognition/src/positive.vec
bgFileName: /home/pi/Project/ObjectRecognition/src/negative.dat
numPos: 450
numNeg: 400
numStages: 17
precalcValBufSize[Mb] : 1024
precalcIdxBufSize[Mb] : 1024
acceptanceRatioBreakValue : -1
stageType: BOOST
featureType: HOG
sampleWidth: 40
sampleHeight: 40
boostType: GAB
minHitRate: 0.97
maxFalseAlarmRate: 0.1
weightTrimRate: 0.95
maxDepth: 1
maxWeakCount: 100
Number of unique features given windowSize [40,40] : 100

Stages 0-4 are loaded

===== TRAINING 5-stage =====

Training until now has taken 0 days 0 hours 7 minutes 23 seconds.

===== TRAINING 6-stage =====
<BEGIN
POS count : consumed 450 : 522

衝突を回避しながらランダムウォーク

これはあまり舞台上で必要な機能ではないのですが、Lidar Lite V3を使って、衝突を回避しながら、壁沿いをランダムに歩くシミュレーションです。

残されたログはこれである。測定した距離に障害物があったら、それをMap情報にしたほうがいいよね。今は、全然地図を使っていないので、無駄な動きがある。

超音波距離センサーの問題

Lidar Lite V3の赤外線距離センサーを前方につけて、自己位置を同定したり、それをもとに、位置調整をしたりはできるようになった。

そこで、残りの三方についている超音波距離センサーでも、できるようにプログラムはくんだ。ただ、センサーがすぐに働かない。C++で書いたセンサーのプログラムを、JAVAのコアシステムから呼び出すようにしてあるのだが、少し、C++の方のプログラムを動かしてからじゃないと、距離が取れない。以下の写真の、右上のように直接何度か動かすと、左下のようにコアシステムから距離が取れて、どこまで正しいか検証はしていないが、自己位置を推定している。

Lidar Lite V3の時のような、電源問題ではないかと思った。ので、Lidar Lite V3と同じように、GPIOから電源をとってテストしようかと思ったが、そもそも、超音波センサーをあまり信頼していないのに、いじっても仕方がないなと思い。これはここで凍結しておこうと思う。

絶対使わないならば、センサーそのものを外しても良いのだが、まあ、その選択肢も睨みながらの保留だ。

自己位置認識とターゲットへの移動

Lidar Lite v3で測定された距離センサーデータ、方位センサーで認識した絶対ロボット角度、さらに舞台角度情報をもとにロボットが自己位置を認識し、目標指定位置へ移動するテスト。

まずその位置を舞台上の座標で、推定する。その後、指定位置方向へ向きを変えて(動画の場合、ほとんど変わっていない)移動するテスト。うまく動いているかどうかはこれからチェック。