Alexa-Voice-Service AVS対応スマートスピーカーを作ったときのこと

去年になりますが、Alexa-Voice-Service (以下AVS)対応スマートスピーカーのプロトタイプを作ったのでメイキングです。Alexa-Skills-Kit(ASK)の記事は多く出ていますが、AVSの情報はASKにくらべて少ないので、なにか参考になる部分があれば幸いです。

ハードウェア選定

ある程度のノイズが想定される場所での展示だったため、マイクアレイでの音声方向検出は必須と考え、対応ボードを探しました。マイクアレイと指向性関係はロボスタの記事がまとまっています。(すごい人は自分でつくりますが、スキルも時間も足りないため、ボードを購入します)

robotstart.info

またハードウェアの形に制限がない場合は、AVSのサイトで動作確認済のDevKitを購入するのが良さそうです。

developer.amazon.com

今回の要件では筐体の大きさの制限が厳しく、Raspberry Piでは大きすぎたので、Raspberry Pi Zero x Seeed Studio社のReSpeaker 2 Mics Pi-HATを選定してみました。 2chマイクではありますが、1chよりはましでしょう…。

ソフトウェア選定

ソフトウェア選定にあたりこの記事を参考にしました。

Raspberry PiにAlexaを召喚する3つの方法 - Qiita

今やるならavs-device-sdk一本とのことで、こちらから取り組みはじめました。

github.com

実際に手を付けてみると、avs-device-sdkc++制でソースの量も多く、Raspberry Pi 3でのコンパイルすると1時間くらい。また、Raspberry Pi Zeroの動作は公式にはサポートされていないようでした。サンプルも複雑で、製品組み込みには使えても、Raspberry Pi Zero上での短い時間で細かくイテレーションを繰り返したい、というプロトタイプ用途としては向いていないと判断しました。

いくつかの選択肢を試した中、Seeed Studioの公開しているAVSライブラリはpython製でソースコードもシンプル。RaspberryPi Zeroでも動作したので、こちらを使用しました。(GPLライセンスなので注意)言語設定切り替えに対応していない、access_token取得方法が古いなどいくつかの問題がありましたが、ソースコードが綺麗だったため、修正は比較的簡単にできました。→この辺のやり取り。開発は止まっているようなので、今から始めるとしたら別途選択肢を探すほうがいいかもしれません。

github.com

Wake Word検出ライブラリ

Wake Wordは。Alexaなら「アレクサ」,Google Homeなら「オーケー、グーグル」という、起動時の決り文句です。変更もできます。常時サーバーに音声を送るわけではなく,Wake Wordはローカルで検出します。

  • Sensory: aws-device-sdkデフォルト。精度いまいち
  • Snowboy:精度いい感じ。商用の場合はお金かかるのでプロトタイプとして使うのにオーバースペックかも…。
  • Porcupine:精度いい感じ。カスタムのWake Word登録は商用できないが、デフォルトのモデルは使えるらしい。

以上の3ライブラリから検討し、ライセンスの関係からPorcupineを使っています。

参考にした情報

上記以外に参考にした記事です。

RaspberryPiでGPIO(I2S)を使ってマイクから録音する - キノコの自省録 Snowboy Hotword DetectionをRaspberry Piで動かす - Qiita Pi Zero Wはモバイルバッテリーでどのくらいの時間動作するか | 日記というほどでも

スピーカーづくり

まずはFusion360でスイッチサイエンスなど簡単に購入できるパーツを配置して、大きさを検討します。

あとで請求書つくるときと、自分で今回もこんなに買い物をしてしまった…と見返すためにBOMとまでは行きませんが、パーツリストもちゃんと残します。

Fusion360で最終的なパーツをちまちま作ってレイアウト。パーツを作るのをさぼった部分はなぜか組立工程で問題がでるので…。

青色の部分は、DMM 3Dプリントでナイロン素材で発注しています。この図にはありませんが、外側にプロダクトデザイナーの方が作った筐体がかぶさります。

LED基盤

光のアニメーションを凝りたいとのオーダーだったので、LEDを贅沢に配置しています。ReSpeakerには、GroveタイプのI2C端子がついていたので、それにつなげる想定の基盤のKiCadつくっていきます。回路設計は素人ですが…こんな感じです。

Gerberは紙にレイヤー毎に印刷してチェックすると何故かミスが見つかります。アナログチェックは重要。

基盤はPCBGoGoで発注。一週間もかからずに届きました。私の用途ではクオリティも十分です。

ちっちゃい…。中国でiPhone修理する人とかすごすぎる…。

Imgur

全部実装して、動作確認。うごいた!

シュミレーター

LEDのアニメーションは、普段よく使っているUnityでシュミレーターを作成してつくりました。

完成

Imgur

組み立ててこんな感じ。最終的には外側にプロダクトデザイナーの方が作った筐体がハマります。

以上こんなこともやってます。というメイキングでした。

Unity AR FoundationをEditor上でシミュレーションする方法

iOS13が公開されたことで、beta版をインストールしなくてもUnityでARKit3の新規のHuman Segmentaionなどが使えるようになりました。対応端末はiPhone X以降です。

実験としてこのようなアプリを作ってみました。

が、開発中、実機で確認するのがとても面倒でした。ARKitはiPhone搭載のカメラのセンサを使うため、実機じゃないと動きません。毎回Unityからビルド→Xcodeプロジェクトに書き出し→実機で確認。のステップを踏まなくてはいけません。毎回実機確認に5分くらいかかります。ARKit2まではARKit Remote for Unityで、Unity Editorとつなげてデバックができました。とところが、ARKit3の機能に対応しら新しいUnityライブラリである、AR Foundation (動作時点ではver 3.0.0-preview.3)ではリモートデバックができないようです。公式スレッドによれば開発中だけど難航しているようです。

なにかを作るときにはツールから作るのをモットーにしているので、Unity Editorにリモートで送信できるツールを作ってみました。現在はHuman Segmentation関係の機能しか用意していませんが、普通に動きそうです。

ソースコードはこちら。

github.com

仕組みはシンプルで、iPhoneからARに必要な情報を送ります。

  • NDI
    • RGBカメラ(YCbCr色空間) 映像
    • Depth 映像
    • Human Segmentation 映像
  • WebSocket
    • カメラmatrixとかの情報

NDIはWi-Fi経由だと遅いのですが、USB経由で接続すると0.3秒くらいの遅延で収まりました。

Hack C#でprivateプロパティだけなstructを作る

シミュレータを作るときに困った点を一つ。ARFoundationはコア部分はネイティブC++プラグイン。そちらで生成したstructをやり取りしているので、C#から見えるstructはプロパティが全部プライベートでした。

[StructLayout(LayoutKind.Sequential)]
public struct XRCameraFrame
{
    public long timestampNs
    {
        get { return m_TimestampNs; }
    }
    long m_TimestampNs;

    public Matrix4x4 projectionMatrix
    {
        get { return m_ProjectionMatrix; }
    }
    Matrix4x4 m_ProjectionMatrix;
    
    ...
}

↑このようなクラス構造。Unityでもunsafe{}を使えばこのようなstructでも作れますが、ライブラリ化を考えるとなるべくunsafe以外の方法でstructを作ったほうが良いため、以下の様な共用体をつくることで解決しました。c#で共用体って作れるんですね…。

[StructLayout(LayoutKind.Sequential)]
public struct MyCameraFrame
{
    public long timestampNs;
    public Matrix4x4 projectionMatrix;
    ...
}

[StructLayout(LayoutKind.Explicit)]
public struct CameraFrameUnion
{
    [FieldOffset(0)] public MyCameraFrame a;
    [FieldOffset(0)] public XRCameraFrame b;
}

void main()
{
    var union = new CameraFrameUnion()
    {
         a = new MyCameraFrame()
         {
               // これはいじれる!
               timestampeNS = 1000,
         }
    }
    
    // 共用体なので、aを作るとbもできる!
    XRCameraFrame b = union.b;
}

CoreMLの練習にDepth PredictionができるmacOSアプリをつくりました。

github.com

近頃macOSを開発に全く使ってなく、面白そうなアップデートに全く追従できていなかったので、サンプルが少ないCoreMLをmacOSから使うアプリを作りました。GitHubのReleasesからビルド済のアプリをダウンロードできます。PythonのMLライブラリ等と違い、ライブラリのインストール要らずで使えるのが一番の利点ですね。

Appleが既に用意してくれているFCRN-DepthPredictionモデルを使いました。 developer.apple.com

*.mlmodelファイルをXcodeにドロップするだけで、クラスとして読み込まれます。パスからファイルを読み込むなどは必要なく、非常にシンプルです。

f:id:asus4:20191014212500p:plain
CoreML model on Xcode

inputs,outputsの情報もXcodeのインスペクタから見れるのも便利。今回のモデルは低解像度で160x128pxのグレイスケール深度画像(double)を出力するのが一発でわかります。

出力される深度の値は、 0(手前)〜不定値(奥)となっているので、白黒を反転、0-255までの範囲に正規化しています。

Facebook 3D Photo

そもそもDepth Predictionを試してみた理由は、Facebookの3D Photoが簡単に対応できるようになっていることに気づいたためです。 www.oculus.com 画像と同じアスペクト比のimage_depth.pngグレイスケール画像を用意するだけで、3D Photoのポストができます。

このアプリでもFacebook 3D Photoに対応する画像を書き出します。

実験結果

iPhoneXなどで気軽にDepthつき映像が手に入るようになっているものの、Depthを持っていない画像:昔の映画や、油絵などにDepthを推定するとどうなるかという実験をしてみました。精度や出力の解像度が荒いので、まだまだな印象があります。面白そうなのでもう少し掘って見ようと思います。

UnityからWebRTCで動画を送る選択肢

Google Stadiaが発表されて、いいGPUを積むよりもレンダリングは全部サーバー側で頑張って、クライアントでは早いネットワーク表示するだけな時代が来ていますね。2019年10月時点での選択肢を調べてみました。

github.com Unity Japanチームが開発している。 - Streaming Server(送り側)はWindowsのみ。Linuxも対応予定。 - ブラウザから入力をWebRTCで送るサンプルもある。 - NVIDIA製のグラフィックカードに最適化

github.com MicrosoftがHoloLens等で使うことを想定して作った。 - Windowsのみ - iOS / Android対応したいとissueで言っているものの対応未定

tips.hecomi.com 凹みさんもNvEncを使用したNVIDIA製の高速なh264エンコードを試していた。 - Windowsのみ

…ご覧のようにWindows/Linuxからのストリーミング一択で。iOS/Androidサーバーは需要がないみたい。

assetstore.unity.com assetstore.unity.com Asset Storeからはこちらの2つを調査。どちらもフレームごとにpngエンコードして送っているので、iOSでも動いたものの遅かった。

github.com 時雨堂さんがiOS/Androidネイティブを開発しているので、UnityにWrapするのを検討中


最近はUnityからpythonへ動画飛ばしてエフェクトかける実験などをしています。

www.instagram.com

www.instagram.com

www.instagram.com

2019年前半に公開したOSS

GitHub - asus4/facial-landmark-annotation: Facial landmark annotation tool

動画の中の顔のランドマークを半自動で読み込み、ずれている部分は手作業で修正するツール。 初、Vuex - Typescript class base対応

[https://twitter.com/asus4/status/1122994785873289216:embed#Added some features: copy & paste, delete, etc... and published on GitHub Pages. https://t.co/GFXppefbrA #VueJS https://t.co/QUOmHBG8S8]

GitHub - asus4/vocabulary-book

8月から息子が現地の保育園に行くので、レストランで使えるドイツ語とか要らないから、ピンポイントでこれだけ知っておけばなんとかドイツ語の保育園を生き抜ける単語帳が欲しくて作った。マスタデータはGoogle Spread Sheetにおいて誰でも編集できるように。やっきーのママ友に手伝ってもらいました。URLを入れ替えれば、自分の独自のSperadSheetも読めますよ。

vue-cliのテンプレート生成がいい感じなので、最近ちっさなプロトタイプ作るときも、

  • Vue.js
    • class base TypeScript
    • Sass
    • Pug
  • Netlifyで公開

の構成が固まってきた。

GitHub - asus4/real-emoji

これのソースコード。思いついてから30分で作った。最近顔認識をやりすぎている…。vue-cliでテンプレート作ってNetlifyでサクッと公開お手軽〜〜

GitHub - asus4/unity-poisson-blending

Poisson Blending、OpenCVでいうSeamless CloneをUnityのCompute Shader上で実装したもの。 当初、もう少し高速なアルゴリズムなどもリサーチしていたが、これで0.5ms 以内で800イテレーションをマークしたので、GPUの速さに感謝。同じ処理をOpenCV for UnityでCPU実装すると4msかかった。

https://camo.githubusercontent.com/35ab2d62a3f479ae69e4caa66b997f1c19605166/68747470733a2f2f692e696d6775722e636f6d2f474851517777722e6a7067

GitHub - asus4/mqtt-unity

MQTTnetをUnity上で動かすサンプル。案件用に作ったものの結局違う方法を使ったので、実戦投入はしてない。

GitHub - asus4/voice2midi

声をFFTにかけて、周波数帯ごとにMIDI Noteに変換してみる実験。ちょっと動作が微妙なので、ちゃんと計算し直す。

GitHub - asus4/faust-unity-playground

Faustというオーディオプログラミング言語をUnity上で動かすサンプル。Faust自体は超初心者だが、WebAudio, iOS, Andoid, PC Native, VSTなどへ書き出し機能があり、とても可能性がある。UnityのカスタムオーディオエフェクトをFaustで作れるということ。結構エラーがあって本家FaustにPR送ってやっと動いたりしたので、深堀りしたい人以外は、Unity連携はまだ様子見かもという感じ。

GitHub - asus4/unity-speech-recognizer: iOS Speech Recognizer for Unity

iOSのSpeechRecognizer機能をUnityから使えるプラグイン。安定性は、有料Assetを買うほうが良い。私の場合はこの機能で足りた。