Amazon AVS開発キット「Conexant AudioSmart™ 4-Mic Development Kit」でAlexaのプロトタイプを作ってみる
いまだにEcho/Echo Dotの招待が来ません。すでに多くの人が試しているのに、この祭りに参加できないのはちょっと悔しいですね。そこで自前でAVS対応デバイスのプロトタイプを作成できる開発キット「Conexant AudioSmart™ 4-Mic Development Kit for Amazon AVS」を入手し、実際に試してみたのでレポートします。
先週木曜にArrow Electronicsに注文したところ、即日発送で三日後の月曜に到着しました。FedexのPriorityは迅速でした。
AVSの開発キットについては、すでに先日Microsemiのキットを市田がレポートしておりますが、今回は違うメーカーのものとなります。AVSの開発キットの一覧については、AmazonのWebで紹介されていますので、そちらをご覧ください。
Conexant AudioSmart™ 4-Mic Development Kit for Amazon AVS
今回試したのは「Conexant AudioSmart™ 4-Mic Development Kit for Amazon AVS」です。4つのマイクを搭載し、ファーフィールドと呼ばれるタイプのデバイスとなります。円形の基板の外周にカラーLEDがぐるっと配置されているのが特徴です。
今回のキットはConexantとなっていますが、現在は社名が変わって「Synaptics」となっているようです。Webサイトのアドレスが変わっています。
AudioSmart® Development Kits for Amazon AVS
セットアップは下記のガイドを参考にしながら作業しました。
キットの中身とセットアップ
キットはこのような箱で届きました。
中身は以下です。
- Raspと接続するコネクタが付いた円形の基板
- 電源(5V)
- USBケーブル
- ライセンス許諾書(2通)
円形の基板の周囲にはフルカラーLEDが並んでいます。また、矢印の先にあるのがマイクで、4つが離れて配置されています(上の一つは見切れています)。
実際に動かすためには、Raspberry Pi本体や周辺機器が必要です。
- Raspberry Pi 2
- micro SDカード(8G)
- 外部スピーカ
- HDMI接続のディスプレイ、USBキーボード、マウス
今回は手持ちのRaspberry Pi 3で試してみました。
使用するOSのバージョンですが、ガイドConexant4Mic Raspberry Pi には、Raspbian-2017-07-05 を使用すると明記されています。今回は、あえて指示に逆らって、セットアップ済みの最新版Raspbian stretch 2017-11-29
で試してみました。結果から言うと、いくつかのトラップにひっかかりました。素直に指定バージョンを使用したほうが良さそうです。今後のチャレンジャーの参考のため、ワークアラウンドもふくめてレポートします。
手順のアウトラインは以下の通りです。
- SDカードにイメージを書き込む
- Raspberry Piとキットの基板のケーブルを接続して組み立てる
- ドライバを組み込むため、カーネルをコンパイルする
- 開発者ポータルで、クライアントID、クラアントキー、セキュリティポリシーを作成する
- conexantのキット向けにforkされたalexa-avs-sample-appをgit cloneする
- クライアントID、クラアントキーを設定する
- auto_install.shスクリプトを走らせる
- サンプルアプリを実行する
RaspbianをダウンロードしmicroSDカードに書き込む
Raspbianの公式サイトから、最新版のイメージをダウンロードします。今回はデスクトップ環境が必要なので、全部入りのものを使用しました。ファイル名は、2017-11-29-raspbian-stretch.zip
でした。
Mac Book Proを使用する場合、SDカードスロットとアダプタを使って直接書き込むことができます。ターミナルを開いて、zipファイルを展開、SDカードをアンマウントして、ddコマンドでイメージを書き込みます(十数分かかります)。書き込み終わったらFATボリューム(boot)が自動マウントされるので、sshが使えるようにsshという空ファイルを作成しておきます。
$ unzip 2017-11-29-raspbian-stretch.zip $ sudo diskutil unmountDisk disk2 $ sudo dd if=2017-11-29-raspbian-stretch.img of=/dev/disk2 bs=1m $ touch /Volumes/boot/ssh
ケーブルを接続する
キットを組み立てます。この手順書に、詳細な写真入りで説明されています。注意するポイントは下記です。
- メインの基板から伸びているケーブルの向きに注意する
- micro USBのコネクタが3箇所にあるので、正しいところに差す
キットのACアダプタで、Raspberry Piにも電源が供給されますので、組み立てた後はRaspberry Pi側の電源は不要になります。
今回はこんなセットアップになりました。
Line Out端子が下の基板にあるので、これをスピーカーに接続します。
EC2インスタンスを使ってカーネルをクロスビルドする
さて、この開発キットをRaspberry Piで動作させるためには、ドライバを入れたカーネルをビルドする必要があります。カーネルをビルドするには、1)実機でビルドする、2)クロスビルドする、という選択肢があります。実機でビルドするととても時間がかかってしまいますので、やはりここはクロスビルドすることにします。クロスビルドするための環境として、今回はEC2を使ってみました。
大まかな手順は以下の通りです。
- ubuntuのAMIを使ってインスタンスを立ち上げる
- カーネルソースとツール類を用意
- リモートでクロスビルドを行う
- できあがったカーネルとモジュールを手元にコピーしてくる
ビルドをクラウドのインスタンスで行えば、ツールやソースのダウンロードも高速ですし、後始末もインスタンスを落とすだけで済みます。今回試したところ十数分でカーネル構築が完了しました。この手順を示します。
まずはインスタンスを立ち上げます。使用するOSのubuntuのAMIを指定します。インスタンスタイプとしてm4.xlarge
を、そしてスポットインスタンスを使用します。$0.1/H程度のコストで済みます。念のためセキュリティグループは、自分のIPからのみアクセスできるよう指定しておきます。インスタンスが起動したらSSHでログインします。
$ ssh -i {your-key}.pem ubuntu@ec2-xx-xx-xx-xx.ap-northeast-1.compute.amazonaws.com
あとはこちらの手順にしたがって作業を進めます。apt-getの初期アップデート、ツールのインストールを行い、gitからカーネルのソースコードを引っ張ってきます。いくつかパラメータを設定して、ビルドスクリプトbuild.sh
を使ってビルドします。並列コンパイルで高速化するために、make -j
オプションでコア数x1.5を指定するのがオススメとのことです。build.sh
を確認するとあらかじめ-j 6
が指定されていたので、4コア向けの設定となっているようです。m4.xlargeは4コアなのでちょうどでした。
$ sudo apt-get update $ sudo apt-get install git bc libncurses5-dev libncursesw5-dev gcc-arm-linux-gnueabihf $ sudo apt-get install build-essential $ git clone https://github.com/raspberrypi/tools $ PATH=$PATH:~/tools/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian/bin $ git clone --depth 10 -n --branch cnxt-rpi-4.4.y --single-branch https://github.com/conexant/rpi-linux.git $ KERNEL=kernel7 $ cd rpi-linux $ git checkout Checking out files: 100% (52763/52763), done. Your branch is up-to-date with 'origin/cnxt-rpi-4.4.y'. $ ./build.sh
ビルドが完了したら必要なファイルをまとめてから、scpで手元に持ってくることにします。そのために、まず仮のインストール先ディレクトリを作成し、一度そこにインストールします。そしてtar.gz
で固めて手元にscp
コピー。さらにそのファイルをRaspberry Piにscp
コピーすることにします。
リモートのインスタンスにて、下記の手順でtar.gz
ファイルにまとめます。サイズは20Mbyte程度になりました。
$ mkdir mnt $ mkdir mnt/ext4 $ mkdir mnt/fat32 $ mkdir mnt/fat32/overlays $ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- INSTALL_MOD_PATH=mnt/ext4 modules_install $ cp arch/arm/boot/zImage mnt/fat32/$KERNEL.img $ cp arch/arm/boot/dts/*.dtb mnt/fat32/ $ cp arch/arm/boot/dts/overlays/*.dtb* mnt/fat32/overlays/ $ cp arch/arm/boot/dts/overlays/README mnt/fat32/overlays/ $ tar cfz ../rpi-connexant4mic-kernel.tar.gz mnt
rpi-connexant4mic-kernel.tar.gz
をリモートのインスタンスから、Raspberry Piにコピーします。下記は手元のコンソールを中継してコピーした例です。
$ scp -i {your-key}.pem ubuntu@ec2-xx-xx-xx-xx.ap-northeast-1.compute.amazonaws.com:rpi-connexant4mic-kernel.tar.gz . $ scp rpi-connexant4mic-kernel.tar.gz pi@{raspberry-pi-ipaddr}:
Raspberry Pi上にコピーできたら、tar.gz
を展開し、各ファイルを適切な場所へコピーします。カーネルイメージのファイル名については、kernel7-conexant4mic.img
としました。
$ tar xfz rpi-connexant4mic-kernel.tar.gz $ cd mnt/fat32 $ sudo cp *.dtb /boot $ sudo cp overlays/*.dtb* /boot/overlays/ $ sudo cp kernel7.img /boot/kernel7-conexant4mic.img $ cd ../ext4 $ sudo cp -r lib/modules/* /lib/modules/ $ sudo cp -r lib/firmware/* /lib/firmware/
config.txt
に必要な設定を行います。カーネルのファイル名を、オリジナルとは別な名前で保存したので、それも設定しています。
$ sudo vi /boot/config.txt dtparam=audio=off dtoverlay=rpi-cxsmartspk-usb dtoverlay=i2s-mmap dtparam=i2c_arm=on program_usb_boot_mode=1 kernel=kernel7-conexant4mic.img
以上でカーネルの再構築とインストールは完了です。Raspberry Piを再起動して、新しいカーネルが動作していることを確認しておきます。
開発者ポータルで製品を登録する
Amazon開発者ポータルのアカウントを準備しておきます。ログイン後、Alexaを選んで、Alexa Voice Service の選択します。
「製品を作成する」ボタンをクリックし、必要事項を記入していきます。
- 製品名:Conexant4Mic Raspberry Pi
- 製品ID: Conexant4MicRaspberryPi
- 製品タイプ:端末
- コンパニオンアプリの使用:いいえ
- 商品カテゴリー:ワイヤレススピーカー
- 製品概要:Conexant4Mic Raspberry Pi
- ハンズフリー
- 商品:いいえ
- 子供向け:いいえ
セキュリティプロファイルが必要とのことなので、新たに作成します。 セキュリティプロファイルIDをメモしておきます。
クライアントIDと、クライアントシークレットが発行されますので、こちらもメモしておきます。
許可するURLとして、
- http://localhost:3000/
- https://localhost:3000/
応答URLとして、
- http://localhost:3000/authresponse
- https://localhost:3000/authresponse
を指定しておきます。実際に使われるのはhttpsのほうでした。
セキュリティプロファイルIDや、クライアントID、シークレットは、いつでも開発者ポータルで参照することが可能です。
これで必要な情報が揃いました。次にサンプルアプリケーションの準備と設定を行います。
alexa-sample-appのセットアップ
Raspberry Pi上で、githubからサンプルアプリケーションのソースコードをcloneします。使用するリポジトリは、オリジナルのalexaのサンプルからconexant用にフォークしたバージョンです。
$ git clone https://github.com/conexant/alexa-avs-sample-app.git
インストールスクリプトの先頭部分に、製品ID(ProductID)、クライアントID(ClientID)、クライアントシークレット(ClientSecret)を設定する箇所がありますので、さきほどポータルで設定、取得した値に書き換えます。
$ cd ~/alexa-avs-sample-app $ vi automated_install.sh ...snip... # This is the name given to your device or mobile app in the Amazon developer portal. To look this up, navigate to https://developer.amazon.com/edw/home.html. It may be labeled Device Type ID. ProductID=Conexant4MicRaspberryPi # Retrieve your client ID from the web settings tab within the developer console: https://developer.amazon.com/edw/home.html ClientID=amzn1.application-oa2-client.0baXXXXXXXXXXXXXXXXXXXXXXXXb59 # Retrieve your client secret from the web settings tab within the developer console: https://developer.amazon.com/edw/home.html ClientSecret=2daXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXa64
書き換えを行ったら、インストールスクリプトを走らせます。いくつか質問項目がありますがデフォルトのままでOKです。
$ chmod +x automated_install.sh $ . automated_install.sh
サンプルアプリケーションを起動する
サンプルを動作させてみます。いくつかのプロセスを手動で動作させる必要があります。ターミナルを5個開いて、それぞれでプロセスを起動します。
まず最初は、LEDを制御するためのLEDサーバーです。
$ cd ~/alexa-avs-sample-app/samples/tLED && sudo python tLEDServer.py
$ cd ~/alexa-avs-sample-app/samples/companionService && npm start
$ cp ~/leftarc ~/.asoundrc</div> $ cd ~/alexa-avs-sample-app/samples/javaclient && mvn exec:exec
$ cd ~/alexa-avs-sample-app/samples/wakeWordAgent/src && sudo ./wakeWordAgent -e gpio
$ cd ~/alexa-avs-sample-app/samples/recordingAgent && ./run.sh
ちょっと面倒ですが、以上の5つを起動することで、AVSサービスが動作するようになります。まとめて起動するためのスクリプトstartup.sh
が用意されているのですが、なぜか正常に動作しませんでした。
トラブルシュート&ワークアラウンド
おそらく最新版のRaspbianを使用したことが原因で、サンプルアプリをスムースに動作させることができませんでした。ここに解決方法をメモしておきます。
wakeWordAgentのビルドが失敗する
wakeWordAgentのビルドが下記のように失敗してしまいました。
[ 6%]Linking CXX executable wakeWordAgent CMakeFiles/wakeWordAgent.dir/KittAiSnowboyWakeWordEngine.cpp.o: In function `std::unique_ptr<snowboy::SnowboyDetect, std::default_delete<snowboy::SnowboyDetect> > make_unique<snowboy::SnowboyDetect, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&>(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)': KittAiSnowboyWakeWordEngine.cpp:(.text._Z11make_uniqueIN7snowboy13SnowboyDetectEJRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES9_EESt10unique_ptrIT_St14default_deleteISB_EEDpOT0_[_Z11make_uniqueIN7snowboy13SnowboyDetectEJRKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEES9_EESt10unique_ptrIT_St14default_deleteISB_EEDpOT0_]+0x4c): undefined reference to `snowboy::SnowboyDetect::SnowboyDetect(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)' collect2: error: ld returned 1 exit status CMakeFiles/wakeWordAgent.dir/build.make:436: recipe for target 'wakeWordAgent' failed make[2]: *** [wakeWordAgent] Error 1
$ cd alexa-avs-sample-app/samples/wakeWordAgent/src $ vi CMakeLists.txt add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0)
- https://github.com/alexa/alexa-avs-sample-app/issues/926
- https://github.com/alexa/alexa-avs-sample-app/issues/902
VLCのリンクエラーが生じる
mvn exec:exec
を実行したときに、vlcのエラーが生じました。
[INFO] --- exec-maven-plugin:1.2.1:exec (default-cli) @ sample-java-client ---[INFO] --- exec-maven-plugin:1.2.1:exec (default-cli) @ sample-java-client ---Exception in thread "main" java.lang.RuntimeException: Failed to load the native library. The error was "Unable to load library 'vlc': Native library (linux-arm/libvlc.so) not found in resource path ...snip...
このエラーは、共有ライブラリのファイル名が不一致なことが原因のようです。下記のように対応しました。
$ cd /usr/lib/arm-linux-gnueabihf $ sudo ln -s libvlc.so.5 libvlc.so $ sudo ldconfig
SSLに関連してそうなエラーが出る
Exception in thread "Thread-24" java.lang.NoSuchMethodError: sun.security.ssl.SupportedEllipticCurvesExtension.createExtension(Ljava/security/AlgorithmConstraints;)Lsun/security/ssl/SupportedEllipticCurvesExtension;Exception in thread "Thread-24" java.lang.NoSuchMethodError: sun.security.ssl.SupportedEllipticCurvesExtension.createExtension(Ljava/security/AlgorithmConstraints;)Lsun/security/ssl/SupportedEllipticCurvesExtension; at sun.security.ssl.ClientHandshaker.getKickstartMessage(ClientHandshaker.java:1438) ...snip...
pom.xmlに記載されているJavaのバージョンが不適合のために生じているようです。
修正前:
$ cd alexa-avs-sample-app/samples/javaclient $ vi pom.xml <alpn-boot.version>8.1.11.v20170118</alpn-boot.version>
となっている箇所を下記のように修正します。
修正後:
<alpn-boot.version>8.1.6.v20151105</alpn-boot.version>
いろいろとエラーが出てしまいましたが、github issuesを探すと、解決方法を見つけることができるようです。困った時はググりましょう。
サウンドデバイスの動作を確認する
開発ボードの音声入出力は、ALSAを使っています。aplay
/arecord
コマンドを使って動作確認することができます。
$ aplay -l **** List of PLAYBACK Hardware Devices **** card 0: cxsmtspkpiusb [cxsmtspk-pi-usb], device 0: System Playback cx2072x-dsp-0 [] Subdevices: 1/1 Subdevice #0: subdevice #0 $ arecord -l **** List of CAPTURE Hardware Devices **** card 1: CX20924?? [CX20924檀], device 0: USB Audio [USB Audio] Subdevices: 0/1 Subdevice #0: subdevice #0
設定ファイル ~/.asoundrc
は下記のように設定されていました。
$ cat ~/.asoundrc pcm.!default { type asym playback.pcm { type plug slave.pcm "hw:0,0" } capture.pcm { type plug slave.pcm "hw:1,0" } }
下記のように録音再生動作を確認することができます。
$ arecord -r 16000 -f S16_LE >rec.raw $ aplay -r 16000 -f S16_LE rec.raw
日本語化する
最後に日本語化を試してみます。
実はalexa-avs-sampleの本家では、すでに2017/12/19のアップデートで日本語に対応済みです。しかし、Conexant向けのフォークでは未対応なので、下記の修正をしてみました。
インストールスクリプトに、"ja-JP"
のロケールを追加します。
$ cd ~/alexa-avs-sample-app $ vi automated_install.sh # Select a Locale ...snip... select_option Locale "en-US" "en-GB" "de-DE" "ja-JP"
そして、クライアントアプリのロケールに、JAPANの選択肢を追加します。
$ cd alexa-avs-sample-app/samples/javaclient/src/main/java/com/amazon/alexa/avs/config $ vi DeviceConfig.java static { SUPPORTED_LOCALES.add(Locale.US); SUPPORTED_LOCALES.add(Locale.UK); SUPPORTED_LOCALES.add(Locale.GERMANY); SUPPORTED_LOCALES.add(Locale.JAPAN); }
上記の修正後、auto_install.sh
を再実行し、ロケールとしてja_JPを選択します。そしてサンプルアプリを起動したときにロケールのプルダウンでja_JP
を選択します。
以上で日本語で動作させることができます。
こちらのQiita記事を参考にさせていただきました。https://qiita.com/moritalous/items/a3e847612dd2bf4fed99
動かしてみる
動画です。ウェイクワードを認識すると、基板上のLEDが反応し、音の到来する方向を示します。Echo/Echo Dotと同じような動作が実現されています。応答の最後が切れてしまっているのが少し気になります。
最後に
AVS開発キットとRaspberry Piを使って、Alexaのプロトタイプ端末を作成することができました。遠くから話しかけて、音声が到来する方向を認識して動作するのは、なかなか興味深いです。このキットは、ドライバさえ入れてしまえば、普通にUSBオーディオデバイスとして動作させることができますので、汎用性も高そうです。いろいろと遊べるかもしれません。中身を研究してみたいですね!
このレポートは以上です。