Google AIY Voice Kitを改造してIoT部屋を作ってみた(1)

#はじめに
 Google AIY Voice Kitとは、Googleが一般向けにリリースした、Raspberry Piを用いた音声認識技術とAI技術を融合させたスマートスピーカの開発キットです。
本ページではこのキットをハード・ソフトともに改造してみた際の備忘録(?)的な感じにまとめてみました。
ハード的には筐体を設計・加工して頑丈にしてみました。
また、ソフト的には普通の受け答えはもちろん、赤外線LEDを使って自宅の照明やエアコンを話しかけてつけたり消したり、webラジオを流してみたり、音量をレベルメータで表示したりするなどしました。
(Qiitaで記事を書くのは初めてです。)

システム全体の構成は以下のようになっています。
![IoT部屋.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399916/db713d93-52fc-c3ab-f8cb-a02633e8a3b5.png)

そして、実際に製作したものがこちらになります。
斜め前から見た図↓
![DSC_0009.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399916/e465f3a2-f2b4-f49d-70f3-8b50f59725e8.jpeg)
後ろから見た図↓
![DSC_0010.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399916/05f01f64-b140-2ca5-d798-4d695aad2bd6.jpeg)
#使用した機材・ソフトウェアなど
####＜音声認識＆しゃべらせる部分＞
・Google AIY Voice Kit(初期のやつ)
・Raspberry Pi 3
・16GBのSDカード
・USB(Micro B)に変換できるACアダプタ(5V/3A)
・Amazonで買った7インチ液晶
・HDMIケーブル
####＜筐体の設計・加工＞
Autodesk Inventor Professional 2017で筐体を設計して汎用フライス盤・CNCで加工を行いました。(大げさかもですが(;^_^A
####＜制御部分＞
OSイメージにデフォルトで入っているプログラム(assistant_library_with_local_commands_demo.py)をもとに機能を追加しました。(家電との赤外線通信・webラジオ再生・ゆっくりボイスの再生など)

#1. とりあえずキットのまま組み立てる
まずはキットのまま組み立ててみて、動作を確認します。
組み立て方・セットアップ方法などはこちら(https://aiyprojects.withgoogle.com/voice/)
を参考にしました。
この辺りにおいては、既存の事例が豊富に紹介されているので改めて説明することは控えさせていただきます。
#2. こんなの見たらやるしかないじゃん！！
Google AIY Voice Kit(以下AIスピーカ)、クッソ便利…!!
だって「OK,Google(0.3秒くらいの間)今日の天気は？」と話しかけたらセットアップ時に紐づけられたGoogleアカウントの現在地情報から、その場の天気を教えてくれます。しかもきれいな日本語の発音で…
他には「Ok,Google(い　つ　も　の　間)おはよう」と話してみれば、名前を呼んでくれて挨拶から今日の日時・天気・予定などなど…ここまでできるのかと思うくらいたくさん教えてくれます。

そこで1つ、スイッチサイエンスさんのサイト(https://www.switch-science.com/catalog/3955/)
を読んでて気づいたことがありました。それは・・・
**「ユーザーとの会話の中からシステムがユーザーの意志を読み取り、スマート スピーカーを制御します。「暑いなぁ」と語りかければ、Raspberry Piに接続された赤外線送信機から、エアコンを操作し、設定温度などを下げます。Raspberry Piを使用しているからこそ、アイデア次第で、家庭内の様々な物が音声で操作できるようになります」**
という商品説明の部分なんですが、こんなの見たらやるしかないですよね、はい。
ということでまずは赤外線でライトを操作するところまでをご紹介します。
#3. 赤外線でライトをつける準備
AIスピーカに付属している拡張基板(AIY Voice HAT)には赤外線を送信するためのモジュールが見当たりませんでした。なので、そのための基板を自作してみました。
回路設計にはkiCad4.0.1を用いています。
回路図↓
![SnapCrab_NoName_2019-4-16_22-22-0_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399916/dbe700a5-29ea-2737-8280-0496adceb6a8.png)配線図↓![SnapCrab_Pcbnew 401-stable CUserskodani_kzDocumentsPCBsAI_IRconnection_2AI_IRconnectionkicad_pcb_2019-4-16_22-29-45_No-00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399916/4129420d-14ca-9c0b-f69f-aa4900541380.png)
そしてこの基板の2,3ピンをそれぞれRaspberry Pi3のGPIO3,2に接続します。(GPIOのピンと基板のピン、順番をそろえればよかったと作ってから気づきましたorz)
※拡張基板の左上付近にあるI2Cと書かれているピンヘッダがあるので、
+5V→基板1ピン SDA→基板2ピン SCL→基板3ピン GND→基板4ピン
と接続していきます。こんな感じです↓![DSC_0012.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/399916/b19cd6c0-4142-a16d-e14d-2566fdd37a4e.jpeg)
接続が完了したら、いよいよ赤外線通信を行うための環境を導入します。
今回使用したのはlirc(Linux Infrared Remote Control)です。これについてはweb上で赤外線を覚えさせたり、送信したりするための多くの方法が議論されているのでそちらを参照してください。このデバイスを製作した際Make.様のサイトが非常に参考になりました。
(http://make.bcde.jp/raspberry-pi/%E8%B5%A4%E5%A4%96%E7%B7%9A%E3%83%AA%E3%83%A2%E3%82%B3%E3%83%B3%E3%82%92%E4%BD%BF%E3%81%86/#LIRC)
ターミナルで「irsend LIST (ファイル名).conf ""」と打って記録したリモコンのボタン一覧が出てきたらもうすぐです。
#4. assistant_library_with_local_commands_demo.pyの編集
早速ですが、「/home/(ユーザ名)/AIY-voice-kit-python/src/examples/voice」の中にある「assistant_library_with_local_commands_demo.py」に追記します。このプログラムは、OK,Googleと呼びかけた後に任意の言葉をしゃべると、それに対してGoogleアシスタント(Raspberry Piの中の人)が返事をしてくれる、といった内容です。
音声を文字列として認識する部分はあらかじめ用意されているので、それを利用していきます。今回は、「OK,Google(少し間をおいて)電気つけて」と話しかけると、部屋のライトをONにする動きを行います。

```python:assistant_library_with_local_commands_demo.py
#!/usr/bin/env python3
"""Run a recognizer using the Google Assistant Library.

The Google Assistant Library has direct access to the audio API, so this Python
code doesn't need to record audio. Hot word detection "OK, Google" is supported.

It is available for Raspberry Pi 2/3 only; Pi Zero is not supported.
"""
import logging
import platform
import subprocess
import sys
import os
import threading
import time
import datetime
import concurrent.futures

from google.assistant.library.event import EventType

from aiy.assistant import auth_helpers
from aiy.assistant.library import Assistant
from aiy.board import Board, Led
from aiy.voice import tts
    
cmd_lightOn = "irsend SEND_ONCE myIoT_Home light_on"  # <-- 電気をつけるコマンド

#以下、追加コマンド(すべて打つ必要はない)
cmd_lightOff = "irsend SEND_ONCE myIoT_Home light_off"
cmd_lightUp = "irsend SEND_ONCE myIoT_Home light_up"
cmd_lightDown = "irsend SEND_ONCE myIoT_Home light_down"
cmd_lightBrown = "irsend SEND_ONCE myIoT_Home light_brown"
cmd_lightWhtie = "irsend SEND_ONCE myIoT_Home light_white"
cmd_mame = "irsend SEND_ONCE myIoT_Home light_sleep"
cmd_airOn = "irsend SEND_ONCE myIoT_Home air_on"
cmd_airOff = "irsend SEND_ONCE myIoT_Home air_off"
cmd_airUp = "irsend SEND_ONCE myIoT_Home air_up"
cmd_airDown = "irsend SEND_ONCE myIoT_Home air_down"
#ここまで(追加コマンド)

logging.basicConfig(
    level=logging.INFO,
    format="[%(asctime)s] %(levelname)s:%(name)s:%(message)s"
)

def power_off_pi():
    aiy.audio.say('Good bye!')
    subprocess.call('sudo shutdown now', shell=True)
# ~略~

elif event.type == EventType.ON_RECOGNIZING_SPEECH_FINISHED and event.args:
        print('You said:', event.args['text'])
        text = event.args['text'].lower()

        if text == 'power off':
            assistant.stop_conversation()
            power_off_pi()
        elif text == 'reboot':
            assistant.stop_conversation()
            reboot_pi()
        elif text == 'ip address':
            assistant.stop_conversation()
            say_ip()

#!!!ここから追加!!!
        elif text == '電気つけて':  #変数textに自分のしゃべった言葉が格納される
            assistant.stop_conversation()
            os.system(cmd_lightOn)
#!!!ここまで追加!!!

elif event.type == EventType.ON_END_OF_UTTERANCE:
        status_ui.status('thinking')

# ...(続く)
```

プログラムに追加した部分で重要なのは、「OK,Google」の後に自分の話した言葉は変数textの中に文字列として入ることです。
その文字列が「電気つけて」という言葉なら、先ほど接続した赤外線の基板から赤外線信号が送信されます。
送信の役割を担っているのが"os.system(cmd_lightOn)"という部分です。

os.system("実行したいコマンド")で、ターミナル上で動作するコマンドを呼び出すことができます。(subprocess.callのほうがいいかも？)今回はlircを利用して赤外線を送信するコマンドである、"irsend SEND_ONCE myIoT_Home light_on"というコマンドを実行しています。(私の環境の場合。登録時に設定する名前などで記述が変わる可能性あり。)
しかしながら、今後ほかの機能(電気を消す、エアコンをつけるなど)を追加することを考えた場合、コマンドをos.systemのカッコの中に入れているのでは面倒なので、変数として複数用意することを考えました。（きっとほかにいい方法があるはずですが…）

コメントで囲まれた部分を既存のコードに追加したら、Raspberry Piを再起動させてファイルを実行してみましょう。また、電源を入れた後の自動起動したくなると思います。その方法としてautostartに追記する方法があります。「/home/(ユーザ名)/.config/lxsession/LXDE-pi」の中にあるautostartという名のファイルにこのように追記することで、次回の起動時から自動的にこのプログラムを走らせることができます。

```text:autostart
@lxpanel --profile LXDE-pi
@pcmanfm --desktop --profile LXDE-pi
@xscreensaver -no-splash
@point-rpi
@/home/(ユーザ名)/AIY-voice-kit-python/src/examples/voice/assistant_library_with_local_commands_demo.py
```

とりあえず今日はここまで。。。
次回は筐体の設計を行っていきます。
#5. 参考文献
・赤外線リモコンを使う | Make. - RaspberryPi http://make.bcde.jp/raspberry-pi/%E8%B5%A4%E5%A4%96%E7%B7%9A%E3%83%AA%E3%83%A2%E3%82%B3%E3%83%B3%E3%82%92%E4%BD%BF%E3%81%86/#LIRC
・Voice - AIY Projects - https://aiyprojects.withgoogle.com/voice/