codamaを使って俺専用 googleアシスタントデバイスを作ってみた

#はじめに
昨年末に発売された[codama](https://codama.ux-xu.com/)を入手しました!
codamaはVUI界隈の人なら垂涎のアイテムのはずなのですが・・・あまり使われていなさそう。
codamaの情報共有をもっとしたい！オリジナルスマートスピーカーで遊ぶユーザーを増やすためにcodamaで遊んでみた内容を記事にしました。

今回、codamaを使って、俺専用Googleアシスタントを作ってみました！皆さんも作ってみてください！
ちなみに下の写真は自分のcodama。専用の固定台を3Dプリンタで作っています
![IMG_7148.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324560/ee76fb9d-0701-2b4f-c321-ab0a9172e0c4.jpeg)
#codamaとは何か？
codamaはRaspberry piに取り付けて使う基板で、音声認識をするための機能を有しています。
いわば基板むき出しのスマートスピーカーのハードウェア。
複数のMEMSマイクとそれらの音から音声認識しやすいように処理をするDSPがついています。
もちろんスピーカー機能もついていて、基板上にはアンプも載っています。いい音だします。

**そして最大の特徴はウェイクアップワードを自分で作って、反応させることができるということ！**

「アレクサ」、「オーケー、グーグル」、「ねぇ、クローバ」
このようなメーカー指定のウェイクアップワードじゃないものをウェイクアップワードと認識する機能があります。
自分で考えたウェイクアップワードを４回発話して、ライブラリを生成。DSPに書き込んだら、自分の発話した言葉がウェイクアップワードになるので、いままでやってみたかった

「アスラーダ！」や「ジャービス！！」

でスマートスピーカーを起動さえることができます。
なんて面白いんだ。

ちなみに価格ですが、1万5000円程度。半導体メーカーが同じような構成の評価キットを販売していますが(ウェイクアップワード機能なし)、それがだいたい5万円。
そう考えると、このcodamaはめちゃくちゃ安いです。

#codamaとGoogle Assistantの連携システムの構成
codamaとgoogleAssistantを連携するにあたり、実際にcodamaは何の役割をして、Google Assistantは何をしているのかハードウェアのシステム構成を描いておきます。使用したラズパイは、Raspbeery Pi 3B+ です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324560/880dd327-308f-a6bc-7937-ac6411a497f3.png)

図で示すように、codamaはRaspberry Piから見ると音声の入出力装置になっていて、
ノイズキャンセリングやエコーキャンセリングの処理は、全てcodama上で行われています。
codamaの設定は公式ページににも記載があるようにI2C経由でRaspberry Piからできるようになっています。具体的にはノイズキャンセリングの強さやビームフォーミング(特定の方向の音以外を除去する処理)
の角度を設定できるようです。
また音声の入出力は全てI2Sで行われています。

そして図に示すGPIO27。これはcodama上でウェイクアップワードを認識するとHIGHになるGPIOです。
Raspberry Pi上では常にI2Cでウェイクアップワードが来たかどうかをメインループでチェックするのではなく、GPIOがHIGHになったら、声を録音し始める(認識した文章を取得する)という処理を進めることができるようになります。

この感じ、どこかで見たことありますよね...そう、Googleが出している[Google AIY Voice Kit](https://www.switch-science.com/catalog/3955/)です。
このキットはウェイクアップワードの代わりに物理ボタンを押すことでGoogle Assistantを起動し、スマートスピーカーを楽しむというものでした。
つまり、ボタンの代わりにcodamaのウェイクアップワードに紐づいたGPIOの状態を見ていれば、google Assistantと簡単に連携することができるというわけです。

#codamaをセットアップ
最初にcodamaがRaspberry Piで使えるようにセットアップ行います。
それができたらウェイクアップワードの登録。
この辺りはcodamaのgitを見れば問題なくできます。
長くなってしまうので詳細は記載しませんが、gitのwikiページを見てください。

https://github.com/YUKAI/codama-doc-r2/wiki

ちなみにハマりどころとして、RaspberryPiでウェイクアップワードはうまく作れないようです。Raspberry PiのスペックなのかChroniumが重いのかわかりませんが、録音が途切れ途切れになってしまいます。
そのため、USBオーディオとしてcodamaを認識させ、PCを使ってウェイクアップワードを録音しました。

#Google Assistant SDKをRaspberry Piにインストールし、使えるように設定する。
AIYキットのおかげで、Raspberry Piで動かすための手順が公式に細かく書かれています。
この手順に沿ってRaspberry Piの設定、デバイスの認証設定等を行なってください。
ちなみに、スマートスピーカーのように話しかけたら、返事をしてほしかったので、Google Assistant Serviceの項目の手順に沿って設定を行いました。
https://developers.google.com/assistant/sdk/guides/service/python/

設定が完了すると、Raspberry Piが自分のGoogle Assistantデバイスとして認識されるようになります。
またこの時codamaがRaspberryPiと接続しているマイクやスピーカーデバイスとして認識されているはずです。

#codamaとGoogle Assistantを連携
codamaもGoogle Assistantの設定も終わったら、いよいよ連携です。
GoogleAssistantSDKをインストールしたディレクトリに、```pushtotalk.py```というpythonファイルがあるので、これを起動します。
私の場合は、素直にディレクトリを変えずにインストールしたので、以下の位置にファイルが存在します。

/home/pi/env/lib/python3.5/site-packages/googlesamples/assistant/grpc/pushtotalk.py

実際にコードを以下のように変更追加を加えます。

```python:pushtotalk.py

import RPi.GPIO as GPIO #32行目あたりにRPi.GPIOを追加します。

#################################
###########　　省略　　 ###########
#################################

##454行目からこのコードがあります
with SampleAssistant(lang, device_model_id, device_id,
                         conversation_stream, display,
                         grpc_channel, grpc_deadline,
                         device_handler) as assistant:
        # If file arguments are supplied:
        # exit after the first turn of the conversation.
        if input_audio_file or output_audio_file:
            assistant.assist()
            return

        # If no file arguments supplied:
        # keep recording voice requests using the microphone
        # and playing back assistant response using the speaker.
        # When the once flag is set, don't wait for a trigger. Otherwise, wait.
        wait_for_user_trigger = not once
        logging.info('Please ask me start with "Hi,Jarvis" ')

        while True:
            ##GPIO27をチェックして、トリガーワードがくる(HIGH)になるのを待つ
            if GPIO.input(27) == GPIO.HIGH:
                    continue_conversation = assistant.assist()
                    wait_for_user_trigger = not continue_conversation

                    # If we only want one conversation, break.
                    if once and (not continue_conversation):
                        break

            #元のコード↓
            # if wait_for_user_trigger:
            #     click.pause(info='Press Enter to send a new request...')
            # continue_conversation = assistant.assist()
            # # wait for user trigger if there is no follow-up turn in
            # # the conversation.
            # wait_for_user_trigger = not continue_conversation
            #
            # # If we only want one conversation, break.
            # if once and (not continue_conversation):
            #     break
```

サンプルコードはAIY用ではなく、普通にPCのEnterキーを叩くと、それがトリガーとなって動き出すというものでした。何にせよ、キーボードの代わりにGPIOを見て、判断するように書き換えれば問題ありません。

これで全ての変更は完了です。
あとはRaspberry Piのコンソールで``` googlesamples-assistant-pushtotalk```と入力して実行してみたら終わりです。

"オーケー、グーグル"ではなく”ハイ、ジャービス”で反応して、googleアシスタントが実際に動くようになりました！

#Tips
設定以外に、開発する中でいくつか発見がありましたのでTipsとして書かせていただきます。

1. Googleアシスタントは最初英語になっています。これを日本語にするにはスマホのGoogle アシスタントアプリで言語の設定を行う必要があります。またアプリを見るとgoogle assistant sdkをインストールしたラズパイが自分のデバイスとして認識されているのが確認できます。

2. codamaがちゃんとウェイクアップワードに反応しているのか、物理的に見たい場合、codamaの上むきに付いているピンヘッダにGPIO27が出ています。(マニュアルに記載ない)
写真で示す部分に3.3VのGPIO27とGNDがあるので、LEDと抵抗を接続すると、ウェイクアップワードに反応してLEDが点灯するようになっています。
![IMG_3233.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/324560/ee36b8fc-9434-e379-8534-4329f30dc398.jpeg)


#最後に
codamaを使うことで俺専用スマートスピーカーを作ることができました！
codamaはGPIOも出しているので、サーボモーターを動かしてみたり、センサーをつけてみたり、市販品ではできないオリジナルのスマートスピーカーの可能性が広がりますね。
みなさんもcodama試してみてください！