話題の記事

Amazon AVS開発キット「Conexant AudioSmart™ 4-Mic Development Kit」でAlexaのプロトタイプを作ってみる

2017.12.27

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

いまだにEcho/Echo Dotの招待が来ません。すでに多くの人が試しているのに、この祭りに参加できないのはちょっと悔しいですね。そこで自前でAVS対応デバイスのプロトタイプを作成できる開発キット「Conexant AudioSmart™ 4-Mic Development Kit for Amazon AVS」を入手し、実際に試してみたのでレポートします。

先週木曜にArrow Electronicsに注文したところ、即日発送で三日後の月曜に到着しました。FedexのPriorityは迅速でした。

AVSの開発キットについては、すでに先日Microsemiのキットを市田がレポートしておりますが、今回は違うメーカーのものとなります。AVSの開発キットの一覧については、AmazonのWebで紹介されていますので、そちらをご覧ください。

Amazon AVS 開発キット

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

セットアップは下記のガイドを参考にしながら作業しました。

Conexant4Mic Raspberry Pi

キットの中身とセットアップ

キットはこのような箱で届きました。

中身は以下です。

  • 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で試してみました。結果から言うと、いくつかのトラップにひっかかりました。素直に指定バージョンを使用したほうが良さそうです。今後のチャレンジャーの参考のため、ワークアラウンドもふくめてレポートします。

手順のアウトラインは以下の通りです。

  1. SDカードにイメージを書き込む
  2. Raspberry Piとキットの基板のケーブルを接続して組み立てる
  3. ドライバを組み込むため、カーネルをコンパイルする
  4. 開発者ポータルで、クライアントID、クラアントキー、セキュリティポリシーを作成する
  5. conexantのキット向けにforkされたalexa-avs-sample-appをgit cloneする
  6. クライアントID、クラアントキーを設定する
  7. auto_install.shスクリプトを走らせる
  8. サンプルアプリを実行する

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
これだけでも遊べそうです。Pythonで記述されていますので、改造も容易だと思います。こんな感じで光ります。

 

次に認証用サーバーです。ポート3000で待受をするプロセスです。
$ cd ~/alexa-avs-sample-app/samples/companionService && npm start
本体です。最初一度だけ、サウンドデバイスの設定ファイルをコピーしておく必要があります。
$ cp ~/leftarc ~/.asoundrc</div>
$ cd ~/alexa-avs-sample-app/samples/javaclient && mvn exec:exec
ウェイクワードから制御を受け取るためのエージェントを起動します。GPIOピンからトリガーを受け取ります。Conexant4Micのキットは、ボード上のチップでウェイクワードの認識を行っており、ウェイクワードを検出するとGPIOピンをトリガーしてくれます。
$ 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
C++のプロジェクトでたまに起きるリンクエラーです。このエラーは、下記のようにCMakeLists.txtファイルを修正して、オプションを追加することで対応できます。
$ cd alexa-avs-sample-app/samples/wakeWordAgent/src
$ vi CMakeLists.txt
add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0)
参考:

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オーディオデバイスとして動作させることができますので、汎用性も高そうです。いろいろと遊べるかもしれません。中身を研究してみたいですね!

このレポートは以上です。