作成日:2019/03/07
ドキュメント作成者:浜野遼太郎
回路製作協力:羊木堂の川野航平
「オムツ交換補助装置」の音声制御化に向け,スマートスピーカーGoogle AIY Voice Kit V2を用いた検証機作成の手順と開発メモ.
現時点(2019/03/05)では,デモとして検証時にディスプレイがなくても動作させられるように,電源投入から検証用プログラムが自動で立ち上がり音声命令でラズパイを終了できるようになっています(ただし,Wi-Fiの接続設定をする必要があるためそこでディスプレイが必要かも).以下はそのデモの流れです.
電源を投入してから1分40秒~2分待機すると本体上部のボタンが白色に光ります.これはGoogleCloudspeechの初期化のための音声入力待ちです.何か適当な単語をマイクに喋るか,10秒程度待つと初期化が終了しボタンの光が消えます.正常に動作が行われると次に,青色に光ります.これがSnowboyによるホットワードの待機状態で,"てっちゃん"と"OK Google"の2つのホットワードを待ちます.
"OK Google"と呼ぶと「なんでしょうか?」と返事が返され,ボタンが赤く光りGoogleAssistantの入力待ち状態になります."天気を教えて"など喋りかけるとそれに応じた答えを返します.答えを喋り終えるか,何もこちらがしゃべりかけずにしばらくするとボタンの光が赤から青へ戻り,Snowboyによるホットワード待ちの状態に戻ります.
"てっちゃん"と呼ばれると命令待機状態へ遷移します.命令待機状態では本体上部のボタンが緑色に光り,これがGoogleCloudspeechAPIによる音声認識待機状態で,以下のワードを認識すると,ボタンが黄色に点滅しつつそれぞれに応じた挙動を示します.(ただし,インターネットに接続できていなければ音声認識できないためボタンの光は緑色の状態から変化しません)
その後はまた,ボタンが青色に光りホットワードの待機状態に戻ります.シャットダウンはおよそ30秒~40秒で完了するので,タイミングを見計らってUSBケーブルを抜いてください.ちなみに上部のボタンは緊急停止スイッチとなっており,ロボの目を消灯し,キャタピラを強制停止します.
電源を入れるとRaspberryPiが立ち上がり,しばらくするとcrontabにより/home/pi/AIY-projects-python/AIY-projects-shell.shが実行されます.
AIY-projects-shell.shの中ではpythonプログラムである/home/pi/AIY-projects-python/src/examples/voice/plazaoita2018_190319demo.pyの実行と,そのpythonプログラムへ渡すSnowboyモデルのパス(/home/pi/AIY-projects-python/src/mod/resources/models/てっちゃん.pmdlと同フォルダのokgoogle.pmdl)を引数として指定しています.
plazaoita2018_190319demo.pyが起動すると上部のボタンが白く光り,GoogleCloudspeechの初期化のために一度音声入力関数が呼び出されます.これはプログラムが起動してから初めて音声入力関数を呼び出したときの,Googleのサーバーへの接続を確立するために時間がかかって実際に音声を受け付けるまでインターバルが生じる問題の対策として呼び出しています.この時,インターネットへの接続が正常に完了していないとCloudspeechの関数から抜けられないため,上部ボタンのLEDが白から変化しません.20秒程度待っても上部ボタンの光が変化しない場合はネット接続を疑ってください.
その後はメインループに入り上部ボタンが青色に点灯し,Snowboyによる入力待ち状態に遷移します."てっちゃん"→"シャットダウン"によるシャットダウン処理では,/home/pi/AIY-projects-python/src/examples/voice/ShutdownAfter5sec.shを呼び出しています.これは,普通にpythonプログラム内でShutdownコマンドを呼び出すとpythonプログラムが正常終了する前にシャットダウンプロセスに突入するのを回避するためです.また,shutdownコマンドには時間差でシャットダウンする機能もあるのですが指定可能な単位が分単位であり時間がかかりすぎるため,ShutdownAfter5sec.sh内でsleepコマンドにより5秒待機してからsudo shutdown -h nowを実行しています.
以上が技術的フローの概要です.以下に主要なソースコードを掲載します.
ShutdownAfter5sec.sh
plazaoita2018_190319demo.py
回路は下図に示すように2つのフォトカプラ(TLP621-2)を挟んで電源系統が分かれている.モーターやロボの目のLEDをドライブするドライバ回路側は黄色のUSBケーブルから電源供給を受ける.電源系統を分けた理由は,モーターの始動電流が大きく電源電圧が一時的に降下してGoogleAIYのRaspberryPiZeroに乗っかっているボンネット回路がリセットされてGPIOピンの出力がオフになるのを回避するためである.
プリント基板の回路図はドライブのCircuitフォルダにAIY.pcbとして保存してます.
Voice Kit本体のセットアップは基本的にGoogle AIY Voice Kit V2の公式ページの"RUN THE ASSISTANT DEMO”までの手順に従った.これで,GoogleAssistantAPIを使用したデモプログラムを動作できる.いくつかメモとして,
Voice Kit V2では5VピンとGNDピン,そしてA,B,C,Dの4本のGPIOピン計6本が使える(参考).ロボの目のLED(PIN_C,PIN_D)とモーター制御(PIN_A,PIN_B)として回路を作成した.なお,パラレルケーブルのコネクタの向きとモータードライバICの向きには気を付けること.パラレルケーブルの向きを間違えると最悪フォトカプラが壊れます.モータードライバICの向きを間違えるとおそらくモータードライバICが壊れます.モータードライバICはシールとICの印字面が揃うように,パラレルケーブルはシールと色が揃うように差し込んでください.
テスト回路の動作試験用に/home/pi/AIY-projects-python/src/examples/voice(当ドライブの/PiPrograms/home/pi/AIY-projects-python/src/examples/voice)にTestingTestBoard.pyを用意しています.実行するには.
~ $ ./AIY-projects-python/src/examples/voice/TestingTestBoard.py
2-1の手順ではGoogleAssistantAPIのデモプログラムを動作させることができるが,これは話しかけた内容に対する答えをGoogleAssistantが返すものであり,GPIO等の制御はできない.そこで話しかけた内容をテキストとして得られるGoogleCloudspeechAPIのデモプログラムを動かす.なお,こちらの音声認識処理は有料.手順は2-1で取り組んだセットアップの少し下(こちら).ここではGoogleCloudspeechAPI用の資格情報のcloud_speech.jsonを作成するが,当ドライブのjsonフォルダに保存してあるのでダウンロードして/home/piに置くと良い.
そして,日本語に対応させたのが/home/pi/AIY-projects-python/src/examples/voice/cloudspeech_demo_ja.py(当ドライブのPiPrograms/home/pi/AIY-projects-python/src/examples/voice/cloudspeech_demo_ja.py) (下記).RasPiで実行するには
~ $ ./AIY-projects-python/src/examples/voice/cloudspeech_demo_ja.py
これで音声を日本語のテキストで得られる.
cloudspeech_demo_ja.py(ver1の旧仕様のプログラムのため正しく動かすにはGPIOピンのPIN_Dを読み込んでピンアサインを変える必要がある)
2-3のGoogleCloudspeechAPIのデモプログラムでは,VoiceKit本体上部のボタンを押してから音声認識を受け付けるためハンズフリーを目指してホットワードを導入する.なお,先のプログラムにおいてボタンの入力待ち処理を取り払っただけだと,ホットワードは不要だがずっと料金が生じるらしい(参照).
SnowboyはKITT AIの提供するホットワード作成サービスであり,自分でホットワードを作成できる.1人の声によるホットワード検知モデル(pmdlファイル)を作成するにはホットワードを3つ録音するだけ.ただし,こちらとこちらによると多様な人々が使えるホットワード検知モデル(lmdlファイル)を作成するには英語は500人以上,日本語は2000人以上のサンプルが必要.なお,umdlファイルとしてKITT AIより"Alexa","Jarvis","Snowboy","SmartMirror"のホットワード検知モデルが提供されている.各モデルの詳細についてはKITTA AIのGitHubを参照
GitHubのKITT AIのSnowboyのページにはGoogleAIY向けのデモコードが配布されているが,現時点では最新のGoogleAIYのAPIに対応していないためこちらのサイト様(mongonta555様)を参考にして改変されたSnowboyのライブラリとデモコードを導入する.これでGoogleAssistantAPIのデモコードをホットワードで動作できる.実行するには,
これをベースにGoogleCloudspeechAPIが動作するように改変したのが以下.
改変の流れ.KITT AI(Apache2.0)→senyoltw(Apache2.0)→mongonta555(Apache2.0)→浜野(Apache2.0)
下記コードはApache License, Version 2.0 のライセンスで配布されている成果物を含んでいます。 http://www.apache.org/licenses/LICENSE-2.0
さらに,以下のコードには2-3のソースをなぞりつつ追加で,
処理を書き加えている.
動作させるためにモデルを引数として与える必要があるため,/home/pi/AIY-projects-python/AIY-projects-shell.sh(当ドライブのPiPrograms/home/pi/AIY-projects-python/AIY-projects-shell.sh)にあるようにスクリプトを組んでホットワードモデルファイルを指定している.実行するには,
これでホットワードを検知してから音声認識に入ることができる.
以下は検証機が自動起動するプログラム(ver1の旧バージョンのプログラム.最新版は1章に掲載)
※1 非常停止スイッチの導入にあたりRPi.GPIOによりGPIOピンの立ち上がり検出を行おうとしたところ[failed to add edge detection]エラーが発生.原因はRPi.GPIOライブラリ(0.6.4~stretch-1)のバグとのことでここを参考に最新版へとアップデートした.手順は以下.
$ sudo pip uninstall RPi.GPIO$ sudo pip3 uninstall RPi.GPIO$ sudo apt-get install python-rpi.gpio python3-rpi.gpioplazaoita2018_190131demo.py(ver1の旧仕様のプログラムのため正しく動かすにはGPIOピンのPIN_Dを読み込んでピンアサインを変える必要がある)
Snowboyが提供するumdlファイルをテストした感想
自作のモデルpmdlファイルをテストした感想
Snowboyを使った感想として,自作モデルを作る場合はイントネーションを変えてモデルを作った方が良い.その時の気分や声を張り上げるなどでピッチやイントネーション,速度が変わると認識してくれなくなる.
ディスプレイなしでも検証機を動作させられるように,先のAIY-projects-shell.shをrc.localにより呼び出す.Raspbian Stretchではこっちよりsystemdの方が推奨されてるが,うまく実装するに至らなかったためこちらを参考にrc.localにより実装した.
上記サイトを参考にして,Raspbianのバージョンが新しいとrc.localがデフォルトでは使えないため設定を少々弄る.
$ sudo rapsi-config でラズパイコンフィグを立ち上げ,[Boot Options] – [B2 Wait for Network at Boot] で [はい] を選択する.そして再起動.$ sudo reboot
/etc/rc.localには,exit 0の直前に2行付け足しただけ.自動起動を止めたい場合は,追加した2行を#でコメントアウトして再起動すればよい.
ディスプレイなしで検証機を動作させられるように,先のAIY-projects-shell.shをcrontabで呼び出す.rc.localを使わなくなった理由として,GoogleAssistantのpythonサンプルプログラムが一般ユーザーが実行することを前提に作られているようで,rc.localで立ち上げるとスーパーユーザーで実行することになりうまく動作しなくなったため.ライブラリのコードをたどるとassistant.jsonの保存先が"~/assistant.json"になっている(いた気がする)ためだろうと思われるのでそこを変更すればrc.localでも動かせるはずだが,念を入れて一般ユーザーで自動実行可能なcrontabを使用した.(raspbian jessie以降はrc.localよりもsystemdが推奨されているらしい)
ここを参考にまずcrontabの設定を行う.
その後,ここを参考に下記のようにしてcrontabによる自動実行を設定した.
$ crontab -e ←これでcrontabの設定ファイルをnanoエディターで開く
@reboot /home/pi/AIY-projects-python/AIY-projects-shell.sh ←ページ最下部へ左を追記
Ctrl + Xを押して,Yで上書き保存.
これでcrontabにより自動実行が設定できた.
rc.local(現在は使っていない)
検証機を動作させたとき,モーターを回すとその騒音により音声認識ができなくなる問題が確認できた.ノイズが大きすぎるせいだと考えられる.そこで,今後指向性マイクなどを利用することなどを合わせて考えて,外部録音機器による使用を検討してみる.
まず,SnowboyとGoogleCloudspeechがどのように音声を録音しているか調べてみた.pythonのライブラリを辿っていくとどちらも,/home/pi/AIY-projects-python/src/aiy/voice/audio.pyのRecorderクラスを利用していることが分かった.さらに見てみると,そのクラスはarecord関数を実行しており,その中でUnixコマンドのarecordコマンドを下記のように呼び出していることが確認できた.
arecord -q -D default -t raw -c 1 -f s16 -r 16000
オプションについて調べてみると以下のような感じ.
ここの"-D"オプションによるサウンドカードの指定を変更することで切り替えることができる.それに関して色々とまとめる.
ということで,今回の検証機ではPulseAudio経由でUSBマイクを使用することにした.
PulseAudioでUSBマイクを使用する方法は下記の通り.
USBマイクをRaspberryPiに接続し,RaspberryPiで"PulseAudio Volume Control"を立ち上げる(デスクトップにショートカットアイコンがある).その後,"設定"タブへ行きUSBマイクが認識されていることを確認する(今回の検証機で使用したUSBマイクは"CM108 Audio Controller"と表示され,GoogleAIYのRaspberryPiZeroにくっついてるボンネット回路のスピーカーとマイクは"aiy-voicebonnet"と表示される).その後,plazaoita2018_190319demo.pyが実行されていることを確認した上で,"録音(R)"タブをクリックして,"ALSA plug-in [aplay]:ALSA Capture から"のすぐ右のボタンをクリックして使用したいマイクを選択する.今回は"CM108 Audio Controller アナログモノ"を選択した.これでデフォルトマイクを変更できる.その後,再起動して再度"PulseAudio Volume Control"を開き,plazaoita2018_190319demo.pyが実行されていることを確認した上で"録音(R)"タブで"CM108 Audio Controller アナログモノ"が選択されていればOK.
これでUSBマイクを使用することができる.
備忘録:"PulseAudio Volume Control"の録音タブでplazaoita2018_190319demo.py実行中にリアルタイムでマイクを切り替えることができるみたいだが,結構な頻度でプログラムがバグって止まるのであまりお勧めできない.
USBマイクが使用できたので,Bluetoothヘッドセットによる使用ができないか奮闘したがうまくいかなかったのでメモ.
sudo apt-get install pi-bluetooth blueman ofono rtkit pavucontrol pulseaudio-module-bluetooth
これでBluetoothヘッドセットを使用できるようになる.ただし,ノイズが乗る.