いきさつ
少し前にタ○ラト○ーのおもちゃハッカソンに申し込んだのですが、抽選に受からず。。。
「ならば自力でOH○NASの対抗馬を作ってやる!」と思いたったのがきっかけで、簡易会話ロボをRasタソを作ってみました。笑
(*実際の人物や団体等とは一切関係ありません)
やりたい事
・マイクからの音声入力に対して、合成音声で返答をする O○aN○Sもどきの作成
スペック
・Raspberry Pi B+
・raspbian 8 Jessie
・SANWA SUPPLY MM-MCUSB16 USBマイクロホン
・イヤフォンはiphoneのやつ
役者
・requests (PythonのHTTPライブラリ)
・pyaudio (pythonでマイク入力)
・AquesTalkPi (合成音声)
・docomo雑談API (会話するためのAPI)
・docomo音声認識API (音声を認識してTEXTに変換するAPI)
※ はじめはJuliusを使おうかと思っていたのですが、軽く触った印象で処理速度と正確さがdocomo音声認識APIの方が良かったのでdocomo音声認識APIを使用する事にしました。
マイクの設定
まずはRaspberryPiでマイクを使用する為の準備を行います。(こちらを参考にしました)
マイクをさした状態でRaspberryPiを起動して、ちゃんと認識されているかを確認します。
$ lsusb
Bus 001 Device 005: ID 056e:4008 Elecom Co., Ltd
Bus 001 Device 004: ID 0d8c:0134 C-Media Electronics, Inc.
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. SMSC9512/9514 Fast Ethernet Adapter
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
良くわからないけど、今回の例だと Bus 001 Device 004: ID 0d8c:0134 C-Media Electronics, Inc.
の部分がマイクの事らしいです。
USBオーディオアダプタの優先度を確認します。
$ cat /proc/asound/modules
0 snd_bcm2835
1 snd_usb_audio
このsnd_usb_audio
がマイクの事っぽいので、これを最優先にしないといけません。
ちなみにRaspberryPiはALSAを使用しているので、設定を変えるにはalsa-base.confを書き換えます。
ふむふむ、ではalsa-base.confを書き換えますか。。。ん?!
そして事件がおきました!!
なんと/etc/modprobe.d/alsa-base.conf
を開こうとすると、ファイルが存在していない!
これ結構ハマりましたorz
Jessie(OS)はalsa-base.confの代わりに/usr/share/alsa/alsa.conf
で修正するんやで、みたいな記事を見つけて、やってみるものの全くうまく行かず、調べても全然わからずにかなりハマりましたorz
結局、「無いのなら作ればよろし、confファイル(字余り)」という事で、alsa-base.confを作成したら解決できました。笑
$ sudo cat /etc/modprobe.d/alsa-base.conf
options snd slots=snd_usb_audio,snd_bcm2835
options snd_usb_audio index=0
options snd_bcm2835 index=1
上記のようにalsa-base.confを新規に作成し、RaspberryPiを再起動します。
そして再度、USBオーディオアダプタの優先度を確認します。
すると、ちゃんと優先度が変更されてるよー!(´∀`)
$ cat /proc/asound/modules
0 snd_usb_audio
1 snd_bcm2835
解決できたおかげで、モチベーションが一気に復活しました。笑
さて、次に一応マイクの感度を調整しておきます。
$ amixer sset Mic 50
Simple mixer control 'Mic',0
Capabilities: cvolume cvolume-joined cswitch cswitch-joined
Capture channels: Mono
Limits: Capture 0 - 62
Mono: Capture 50 [81%] [16.59dB] [on]
では実際に録音して、マイクに問題が無いか確認します。
arecordコマンドで録音を開始して 、Ctrl + Cで終了します。
$ arecord -r 16000 -f S16_LE test.wav
録音中 WAVE 'test.wav' : Signed 16 bit Little Endian, レート 16000 Hz, モノラル
^C
シグナル 割り込み で中断...
lsコマンドなどで、ファイルができている事を確認したら、実際に再生してみます。
再生コマンドでは下記の様にサウンドカードナンバーとデバイスナンバーを指定する必要があります。
aplay -Dhw:[カードナンバー, デバイスナンバー] test.wav
RaspberryPi B+には標準でイヤホンジャックがついているので、イヤホンジャックのサウンドカードナンバーとデバイスナンバーを確認します。
$ aplay -l
**** ハードウェアデバイス PLAYBACK のリスト ****
カード 1: ALSA [bcm2835 ALSA], デバイス 0: bcm2835 ALSA [bcm2835 ALSA]
サブデバイス: 8/8
サブデバイス #0: subdevice #0
サブデバイス #1: subdevice #1
サブデバイス #2: subdevice #2
サブデバイス #3: subdevice #3
サブデバイス #4: subdevice #4
サブデバイス #5: subdevice #5
サブデバイス #6: subdevice #6
サブデバイス #7: subdevice #7
カード 1: ALSA [bcm2835 ALSA], デバイス 1: bcm2835 ALSA [bcm2835 IEC958/HDMI]
サブデバイス: 1/1
サブデバイス #0: subdevice #0
上記の内容だと
カード:1 デバイス:0 が 【スピーカ出力のオーディオ】
カード:1 デバイス:1 が 【HDMI出力のオーディオ】
の事らしいです。
なので今回使用するのは カード:1 デバイス:0 のですね。
では再生してみます。
$ aplay -Dhw:1,0 test.wav
再生中 WAVE 'test.wav' : Signed 16 bit Little Endian, レート 16000 Hz, モノラル
再生されました!
これで無事に、録音から再生まで一通り問題無い事が確認できました。
docomoAPI
次にdocomoAPIを使ってみます。
まずはdocomo Developer supportに登録します。
登録するとAPIKEYが発行されるので、今後はそのAPIKEYを使ってAPIを使用します。
では、まずは雑談APIから試してみます。
$ python
>>> import requests
>>> import json
>>> url = "https://api.apigw.smt.docomo.ne.jp/dialogue/v1/dialogue?APIKEY={}".format(APIKEY)
>>> payload = {
"utt": "こんにちは",
"context": "",
"nickname": "光",
"nickname_y": "ヒカリ",
"sex": "女",
"bloodtype": "B",
"birthdateY": "1997",
"birthdateM": "5",
"birthdateD": "30",
"age": "16",
"constellations": "双子座",
"place": "東京",
"mode": "dialog",
}
>>> r = requests.post(url, data=json.dumps(payload))
>>> print r.json()['utt']
こんちは
上記の例は「こんにちは」っていう話しかけに対してAPIが「こんちは」って返してます。
簡単ですね!
次に音声認識APIを試します。
こちらは音声データを渡す必要があるので、もう一度ドキュメントを見てみます。
音声データのフォーマット:PCM(MSB)16khz/16bit
とあります。
PCMというのは非圧縮の音声データで、wikiには下記のようにあります
圧縮しない音声フォーマットはPCMそのものであり、Windowsでは .wavとして、Mac OS では .aiffとして格納される。
ちょうど先ほど作成したtest.wav(16khz/16bit)と条件も一致しているので、test.wavを使って試してみます。
ちなみにtest.wavには「なんでやねん」と言っている音声が入っています。
音声認識APIなので、この音声を認識して「なんでやねん」というテキストが返ってきたら良い訳ですね。
$ python
>>> import requests
>>> path = '/home/pi/test.wav'
>>> url = "https://api.apigw.smt.docomo.ne.jp/amiVoice/v1/recognize?APIKEY={}".format(APIKEY)
>>>files = {"a": open(path, 'rb'), "v":"on"}
>>>r = requests.post(url, files=files)
>>> print r.json()['text']
なんでやねん。
返ってきました!成功です!
これでdocomoAPIの使用は問題無さそうですね。
pyaudioで録音する
さて、さきほどマイク入力のテストをしましたが、やはり制御ができないと厳しいので、Pythonでオーディオ制御ができるpyaudioを使って録音を行ってみます。
pyaudioに関してはこちらを参考にさせて頂きました。
ではまず、pyaudioをインストールします。
$ sudo apt-get install python-pyaudio
参考サイトのソースをほぼそのまんまコピーして、動作確認します。
$ python pyaudio_test.py
Please input recoding time>>> 3
ALSA lib pcm_dmix.c:1022:(snd_pcm_dmix_open) unable to open slave
ALSA lib pcm.c:2239:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.rear
ALSA lib pcm.c:2239:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.center_lfe
ALSA lib pcm.c:2239:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.side
ALSA lib pcm.c:2239:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.hdmi
ALSA lib pcm.c:2239:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.hdmi
ALSA lib pcm.c:2239:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.modem
ALSA lib pcm.c:2239:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.modem
ALSA lib pcm.c:2239:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.phoneline
ALSA lib pcm.c:2239:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.phoneline
ALSA lib pcm_dmix.c:1022:(snd_pcm_dmix_open) unable to open slave
Cannot connect to server socket err = No such file or directory
Cannot connect to server request channel
jack server is not running or cannot be started
ここでマイク入力を行います。
では、録音したらmono.wavファイルができている事を確認します。
ファイルができていれば先ほどと同じコマンドで、下記のように再生してみて録音ができてればOKです。
$ aplay -Dhw:1,0 mono.wav
うむ、ばっちり録音されておるわ!
AquesTalkで合成音声
さてさて、これで 音声入力 からの 音声認識 からの 雑談 まではできる様になりました。
あとは雑談APIにて、返ってきた返答をRaspberryPiことRasタソに発声させます。
まずはAquesTalkを公式サイトからダウンロードし、RaspberryPiにコピーします。
localpc ~ $ scp ~/Desktop/aquestalkpi-20130827.tgz user@host:/home/pi/
aquestalkpi-20130827.tgz
RaspberryPiにコピーできたら、RaspberryPi内で解凍します。
$ tar xvf aquestalkpi-20130827.tar
解凍ができたら試しに実行してみます。
イヤホンから合成音声が聞こえてきたらOKです。
$ cd aquestalkpi
$ ./AquesTalkPi "オンギャーオンギャー" | aplay -Dhw:1,0
再生!!
\オンギャーオンギャー/
き。。。聞こえました。。。
Rasタソが初めての自ら発声しました。。。泣
命が吹き込まれた瞬間です。笑
Rasタソと会話するの巻
さて、今のRasタソは脳に直接書き込まれた文章を発声するだけですが、こんなRasタソに知性を与えて「聞く、考える、発声する」という会話能力を与えます。
といっても上でやってきた事をまとめるだけなので、やる事は簡単です。
こんな感じでdialogue_test.pyを作成します。
復習がてらにdialogue_test.pyの内容を説明すると、
1.pyaudioでマイク入力を受付。
2.その音声をdocomo音声認識APIで認識してTextにします。
3.そのTextを元にdocomo雑談APIを叩きます
4.その結果を合成音声でしゃべらせます。
というものですね。
では実行してみます。
$ python dialogue_test.py
Please input recoding time>>>3
~~snip~~
元気ですか? ←マイクから入力した内容
元気でちゅ ←Rasタソの回答
$ python dialogue_test.py
Please input recoding time>>>3
~~snip~~
何歳ですか。←マイクから入力した内容
ところで、気になるニュースがあるんだが、カルビーと阪急そばがコラボレーションして「関西だししょうゆポテトチップスそば・うどん」を期間限定で販売、関西だしの旨みと斬新な食感が味わえるそうでちゅ←Rasタソの回答
$ python dialogue_test.py
Please input recoding time>>>3
~~snip~~
誕生おめでとう。←マイクから入力した内容
楽しみに待ってるか? ←Rasタソの回答
赤ちゃんなので、ちょっと会話が成り立たない事もありますが、そこは御愛嬌です!
ちゃんとdocomoAPIを使いこなせば、もっと賢くなるそうですが、それは今後の課題にしていきます。
最後に
こんな事まで簡単にできてしまう世の中にビックリですね。
今後はもっと賢くして、Siriみたいにして、顔認識機能とかもつけてとか夢は広がります^^
という事で、今後も時間と根気などがあればRasタソを成長させていきますので楽しみに待っていてください。