Edited at
LIFULLDay 13

Raspberry Pi 3 でAlexaと対話する

More than 1 year has passed since last update.

re:Invent 2017AlexaをRaspberryPi経由で利用する方法のワークショップに参加した。

ワークショップでは、構成済みのMicroSDを使って、単純にコマンドを流したり、支持されたようにファイルを書き換えたりしただけだったので、まっさらなMicroSDの状態から同様に動くようになるまでをやってみたいと思う。


用意するもの

Raspberry Pi 3 Model B

USBマイク < 多分これ

イヤホン

USBキーボード

USBマウス

HDMIケーブル

ディスプレイ

MicroSD Class10 16G


事前準備(Macでの作業)


インストーラーのダウンロード

こちらからNOOBSをダウンロードする

今回ダウンロードしたバージョンは v2.4.5


MicroSDにコピーする

ダウンロードしたNOOBS_v2_4_5.zipを解凍しFAT32でフォーマット済みのMicroSDにファイルをコピーする。


コマンド例

cp -a Downloads/NOOBS_v2_4_5/* /Volumes/UNTITLED



Raspbianのインストール

先ほどのMicroSDをRaspberry Piに刺して電源を入れるとインストーラーが立ち上がるので、Raspbian [RECOMMENDED]にチェックを入れて、左上のInstallをクリックしてインストールすればOK






事前準備(Raspberry Piでの準備)


一応OSのバージョンチェック

こんな記載があるので、Raspbian Stretchかどうか一応チェック


This guide provides step-by-step instructions to set up the Alexa Voice Service (AVS) Device SDK on a Raspberry Pi running Raspbian Stretch with Desktop


$ cat /etc/os-release

PRETTY_NAME="Raspbian GNU/Linux 9 (stretch)"
NAME="Raspbian GNU/Linux"
VERSION_ID="9"
VERSION="9 (stretch)"
ID=raspbian
ID_LIKE=debian
HOME_URL="http://www.raspbian.org/"
SUPPORT_URL="http://www.raspbian.org/RaspbianForums"
BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs"


ネットワークに接続

有線LANもあるので有線でつなげる場合には、何もしなくて大丈夫

Wi-Fiを利用する場合には右上にマークがあるのでそこから接続設定する


SSH/VNCの有効化

有効化しなくてもOKだけど、リモートから行える作業はできるだけリモートで行うと楽なので有効化しておく





ビルド環境の構築+ビルド

基本的にはこちらにある通りに行う

https://github.com/alexa/avs-device-sdk


依存関係のあるライブラリ、AVS Device SDK, Sensory wake word engine のインストール

Sensory wake word engineはオープンソースは非商用限定のライセンスなので注意すること

cd /home/pi/

mkdir sdk-folder
cd sdk-folder
mkdir sdk-build sdk-source third-party application-necessities
cd application-necessities
mkdir sound-files

sudo apt-get update

sudo apt-get -y install \
git gcc cmake build-essential libsqlite3-dev libcurl4-openssl-dev \
libfaad-dev libsoup2.4-dev libgcrypt20-dev libgstreamer-plugins-bad1.0-dev \
gstreamer1.0-plugins-good libasound2-dev doxygen

cd /home/pi/sdk-folder/third-party
wget -c http://www.portaudio.com/archives/pa_stable_v190600_20161030.tgz
tar zxf pa_stable_v190600_20161030.tgz
cd portaudio
./configure --without-jack
make

pip install commentjson

cd /home/pi/sdk-folder/sdk-source
git clone git://github.com/alexa/avs-device-sdk.git

cd /home/pi/sdk-folder/third-party
git clone git://github.com/Sensory/alexa-rpi.git
cd ./alexa-rpi/bin/
./license.sh


ビルド

make のオプションは -j4までいけるけど、オーバーヒートに注意しましょう(と書いてある)

cd /home/pi/sdk-folder/sdk-build

cmake /home/pi/sdk-folder/sdk-source/avs-device-sdk \
-DSENSORY_KEY_WORD_DETECTOR=ON \
-DSENSORY_KEY_WORD_DETECTOR_LIB_PATH=/home/pi/sdk-folder/third-party/alexa-rpi/lib/libsnsr.a \
-DSENSORY_KEY_WORD_DETECTOR_INCLUDE_DIR=/home/pi/sdk-folder/third-party/alexa-rpi/include \
-DGSTREAMER_MEDIA_PLAYER=ON \
-DPORTAUDIO=ON \
-DPORTAUDIO_LIB_PATH=/home/pi/sdk-folder/third-party/portaudio/lib/.libs/libportaudio.a \
-DPORTAUDIO_INCLUDE_DIR=/home/pi/sdk-folder/third-party/portaudio/include
make SampleApp -j2


Alexa Voice Serviceへの登録

先ほどビルドしたSampleAppからAlexa Voice Serviceへ接続するためには設定を作る必要があるので作成する。


Amazon Developerに登録

こちらからログインする

日本でもEchoが発売されたのでamazon.co.jpアカウントでもログインできるらしい


Alexa Voice Service に製品を登録する

!!! 一度作成した設定は削除できないようなので注意 !!!


Alexa Voice Service を選ぶ


CREATE PRODUCTを選ぶ


プロダクト情報を入力する

Product Name: 任意

Product ID: 任意(あとで使うのでメモっておくこと)

Is your product an app or device?: Device

Will your device use -----: 任意(Deviceを選ぶと出てくる)

Product category: 任意

Brief product description: 任意

How will end users -----: Hands-free

Upload an image: 任意

Do you intend to -----: No

Is this a children's -----: No


セキュリティプロファイルの設定を作る

CREATE NEW PROFILEを選択すると、下にプロファイル名と説明を入れる欄が出るので、入力する。


URLの登録

次で使うので、Client ID, Client Secretをメモに取る

http://localhost:3000を入力してADDボタンを押す

同様にAllowed return URLsにはhttp://localhost:3000/authresponseを入力してADDボタンを押す


アプリケーション側に設定を反映


その前にvimのインストール

nano, edとかは入ってるけど辛いのでvimをインストール

sudo apt-get install -y vim


設定ファイルの書き換え

YOUR_CLIENT_SECRET, YOUR_CLIENT_ID, YOUR_PRODUCT_IDを先ほどメモったものに書き換えて以下を実行する

cat <<EOF >/home/pi/sdk-folder/sdk-build/Integration/AlexaClientSDKConfig.json

{
"authDelegate":{
"clientSecret":"YOUR_CLIENT_SECRET",
"deviceSerialNumber":"123456",
"refreshToken":"",
"clientId":"YOUR_CLIENT_ID",
"productId":"YOUR_PRODUCT_ID"
},
"alertsCapabilityAgent":{
"databaseFilePath":"/home/pi/sdk-folder/application-necessities/alertsCapabilityAgent.db"
},
"settings":{
"databaseFilePath":"/home/pi/sdk-folder/application-necessities/settings.db",
"defaultAVSClientSettings":{
"locale":"en-US"
}
},
"certifiedSender":{
"databaseFilePath":"/home/pi/sdk-folder/application-necessities/certifiedSender.db"
},
"sampleApp":{
"displayCardsSupported":false
}
}
EOF


音の設定

cat <<EOF >~/.asoundrc

pcm.!default {
type asym
playback.pcm {
type plug
slave.pcm "hw:0,0"
}
capture.pcm {
type plug
slave.pcm "hw:1,0"
}
}
EOF


リフレッシュトークンの取得

先ほど書き換えず空のままだったrefreshTokenを取得する

まずは、下記コマンドを実行して認証用Webサーバーを立ち上げる

cd /home/pi/sdk-folder/sdk-build && python AuthServer/AuthServer.py

直接もしくはVNCを利用して、Raspberry Pi内のブラウザを立ち上げて http://localhost:3000/ にアクセスするとSign in to [セキュリティプロファイル名] using your Amazon accountのページにリダイレクトされるので、ログインする

ログインが完了すると立ち上げてWebサーバーにリダイレクトされて戻ってきて、The file is written successfully.

Server is shutting down, so you can close this window.
という表示がされている


サンプルアプリケーションの実行

$ cd /home/pi/sdk-folder/sdk-build/SampleApp/src

$ TZ=UTC ./SampleApp \
/home/pi/sdk-folder/sdk-build/Integration/AlexaClientSDKConfig.json \
/home/pi/sdk-folder/third-party/alexa-rpi/models
#############################
# Connecting... #
#############################

########################################
# Alexa is currently idle! #
########################################

///ここに大量のエラーが出ているけど、一旦動作には関係なさそうなので放置///

# # # ##### ##### ###### # #
# # # # # # # # # # # #
# # # # # # # # # #
# # # # ##### ##### # # ###
####### # # # # # # # #
# # # # # # # # # # # #
# # # ##### ##### ###### # #

##### #
# # ## # # ##### # ###### # # ##### #####
# # # ## ## # # # # # # # # # #
##### # # # ## # # # # ##### # # # # # #
# ###### # # ##### # # ####### ##### #####
# # # # # # # # # # # # #
##### # # # # # ###### ###### # # # #

+----------------------------------------------------------------------------+
| Options: |
| Wake word: |
| Simply say Alexa and begin your query. |
| Tap to talk: |
| Press 't' and Enter followed by your query (no need for the 'Alexa').|
| Hold to talk: |
| Press 'h' followed by Enter to simulate holding a button. |
| Then say your query (no need for the 'Alexa'). |
| Press 'h' followed by Enter to simulate releasing a button. |
| Stop an interaction: |
| Press 's' and Enter to stop an ongoing interaction. |
| Privacy mode (microphone off): |
| Press 'm' and Enter to turn on and off the microphone. |
| Playback Controls: |
| Press '1' for a 'PLAY' button press. |
| Press '2' for a 'PAUSE' button press. |
| Press '3' for a 'NEXT' button press. |
| Press '4' for a 'PREVIOUS' button press. |
| Settings: |
| Press 'c' followed by Enter at any time to see the settings screen. |
| Speaker Control: |
| Press 'p' followed by Enter at any time to adjust speaker settings. |
| Info: |
| Press 'i' followed by Enter at any time to see the help screen. |
| Quit: |
| Press 'q' followed by Enter at any time to quit the application. |
+----------------------------------------------------------------------------+

こんな感じで動いてとりあえずひと段落、Alexaと呼びかけるか、t + EnterでLinteningモードに入る

そうすると、以下のように、ステータスが遷移して、Speakingで話してくれるはず、、、はず、、、

############################

# Listening... #
############################

###########################
# Thinking... #
###########################

###########################
# Speaking... #
###########################

########################################
# Alexa is currently idle! #
########################################


あれれ?


音が出ない

音が出ない何故???と思ったら、ディスプレイ側のピンジャックにイヤホンを繋げたら声が聞こえる

ということはHDMI側に信号が流れてしまっているみ???

インターフェイスの優先度的な問題かと思い、HDMIを抜いたり、刺したり、設定変えたりしたけれども解決の糸口が見えないのでとっても困ってます

例えば、以下を実行してもやっぱりHDMI経由で音が出力される・・・

$ amixer cset numid=3 1

numid=3,iface=MIXER,name='PCM Playback Route'
; type=INTEGER,access=rw------,values=1,min=0,max=2,step=0
: values=0

上の状況でYouTubeを確認したところ、ピンジャックからの出力になっていたので、ここの設定はAlexaには関係なさそう

また、ワークショップで使ったMicroSDを刺して起動した場合には、しっかりとピンジャックから音が出力されるので何らかの設定ミスの線が濃厚

RaspberryPiの知見も、Linuxで音を出す的な知見も全くないので、お手上げ状態です

どなたかわかる方いらっしゃったら教えてもらえたら嬉しいです


音が切れる

もう一つの問題として、Alexaの話が途中で切れることWhat's your nameときくとMy name is Aleという感じで途中で切れてしまう

これも設定で何とかできるんじゃないかと思っているけれども、今の所、どう調べたらいいものやらという感じで止まっている

音がピンジャックから出ない問題と同様に教えてもらえたら嬉しいです

助けてもらえるときのために、関連しそうな情報を末尾に載せておきます


今後のやりたいこと

単純にAlexaと声をかけて、声で操作するだけならEchoを使えばいいだけなので、すぐに思いつくようなことだけではあるけれども、以下のようなことを考えている


  • Wake word engineが独立しているので、Alexa以外の言葉に反応させられたら、専用で作る意味が出てくるので、試したい

  • Wake wordだけでなくコマンドから入力受付状態にできるので、受付システムとかできそうなので試したい


音の設定関連の情報

$ aplay -l

**** List of PLAYBACK Hardware Devices ****
card 0: ALSA [bcm2835 ALSA], device 0: bcm2835 ALSA [bcm2835 ALSA]
Subdevices: 8/8
Subdevice #0: subdevice #0
Subdevice #1: subdevice #1
Subdevice #2: subdevice #2
Subdevice #3: subdevice #3
Subdevice #4: subdevice #4
Subdevice #5: subdevice #5
Subdevice #6: subdevice #6
Subdevice #7: subdevice #7
card 0: ALSA [bcm2835 ALSA], device 1: bcm2835 ALSA [bcm2835 IEC958/HDMI]
Subdevices: 1/1
Subdevice #0: subdevice #0

$ aplay -L

null
Discard all samples (playback) or generate zero samples (capture)
default
sysdefault:CARD=ALSA
bcm2835 ALSA, bcm2835 ALSA
Default Audio Device
dmix:CARD=ALSA,DEV=0
bcm2835 ALSA, bcm2835 ALSA
Direct sample mixing device
dmix:CARD=ALSA,DEV=1
bcm2835 ALSA, bcm2835 IEC958/HDMI
Direct sample mixing device
dsnoop:CARD=ALSA,DEV=0
bcm2835 ALSA, bcm2835 ALSA
Direct sample snooping device
dsnoop:CARD=ALSA,DEV=1
bcm2835 ALSA, bcm2835 IEC958/HDMI
Direct sample snooping device
hw:CARD=ALSA,DEV=0
bcm2835 ALSA, bcm2835 ALSA
Direct hardware device without any conversions
hw:CARD=ALSA,DEV=1
bcm2835 ALSA, bcm2835 IEC958/HDMI
Direct hardware device without any conversions
plughw:CARD=ALSA,DEV=0
bcm2835 ALSA, bcm2835 ALSA
Hardware device with all software conversions
plughw:CARD=ALSA,DEV=1
bcm2835 ALSA, bcm2835 IEC958/HDMI
Hardware device with all software conversions

$ amixer cset numid=3

numid=3,iface=MIXER,name='PCM Playback Route'
; type=INTEGER,access=rw------,values=1,min=0,max=2,step=0
: values=0