Sipeed M1n (Maix Nano)とAquesTalkを組み合わせて、Tiny YOLOの物体検出結果を声でしゃべるカメラを作ってみた

# 概要
[Seeedで売られ始めたSipeed M1n](https://www.seeedstudio.com/Sipeed-M1n-Module-AI-Development-Kit-based-on-K210-p-4491.html)を買ってみた。[Maix Nanoとも呼ばれている](https://twitter.com/SipeedIO/status/1191709953846722560)らしい。
K210ボードは色々あるけど、M1nなんといっても小さい。小さいは正義。そして相変わらず安い。
ただ、他の多くのK210ボードと違ってLCDが付属しないので、物体検出結果を表示できない。
というわけで、極小の音声合成エンジンのAquesTalkシリーズと組み合わせ、声で喋らせてみた。

# 開発環境
ノートPCを新調したので、以下のツール類をダウンロードしてインストール。今回の開発機はUbuntuだが、以前Windowsで開発したときと同じ環境で済んだ。(むしろUSBシリアルのドライバ入れる手間が無かった。)
- [KFlush](https://github.com/sipeed/kflash_gui/releases)
    - MaixPyの実行環境やモデルをFlashに焼くのに使う。
- [uPyLoader](https://github.com/sipeed/uPyLoader/releases)
    - Flash上のファイルを、Uart経由で管理できるファイラーアプリ。
- [Maix IDE](https://dl.sipeed.com/MAIX/MaixPy/ide/_/v0.2.4)
    - 簡単なIDE。シリアルログを見ながらコード書ける。無くても開発は可能。

# Sipeed M1n 動作確認
早速、以前Maix Dockで動かしたことのある、Tiny YOLO v2のモデルを動かしてみる。
https://blog.sipeed.com/p/677.html

maixpy_20class.zipをダウンロードして、接続したボードにKFlashでアドレス`0x500000`にモデルを焼く。
![Screenshot from 2020-04-01 22-28-46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235770/8e810b98-759e-76ef-bd16-c7d992e31c30.png)
MaixPy環境はもとから焼いてあったらしく、モデルのみ焼けば動作した。
コードの実行は20class.pyをMaixIDEで開いて実行するか、uPyLoaderでアップロードしてExecuteボタンで実行。MaixIDEでログ見ながらやるのがおすすめ。
lcd表示部分を削除しなくてもM1nで動いた。

# AquesTalk基板作成
[AquesTalk pico LSI](https://www.a-quest.com/products/aquestalkpicolsi.html)はリアルタイム音声合成エンジンを8bitマイコンに詰め込んだもので、UARTやI2Cで発音データを送信するだけで簡単に喋ってくれるデバイス。
今回は秋月で売っていたATP3012R5-PU/AUを使用した。回路はほぼデータシートのリファレンスデザイン通り。
ATP3012シリーズとATP3011シリーズがあり、重要なピン配置と外部クロックの有無が異なるので注意。外部クロックを使いたくない場合や消費電力的にはATP3011の方がお手軽だが、ATP3012の方が音質は良いらしい。今回はいちおうジャンパピンで両方のピン配に対応するようにしてみた。
![aquestalk基板](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235770/68125a2a-2135-6eb5-19f4-473a45b24933.jpeg)
通信はとりあえずデフォルトのUART(Baudrate=9600Hz)で固定ということにして、VIN,GND,TXD,RXDの4ピンだけだしておいた。
音はとりあえず出ればいいので、秋月で買った小型スピーカーモジュールを基板上に貼っておき、AquesTalkと同じ電源で鳴るようにしておいた。

# Sipeed M1nとAquesTalk基板の接続
## Sipeed M1nブレイクアウトボードのピン配置について
Sipeed M1nには一般的な2.54mmピッチのピンヘッダや、UARTをUSB TypeCコネクタに引き出したブレイクアウトボードが付属していたが、シルクには何やら書いてあるものの、ピン配置のドキュメントがない。(2020/04/04時点)
[こちらの記事](https://qiita.com/uzuki_aoba/items/c82e0d72a738a1098b32)でピン配を推定してくれていたので、これを信じて試してみたらうまくいった。ありがたや。

## K210のUART通信
K210では、FPIOAというモジュールによって、GPIOやI2C,UARTなどの通信ペリフェラルをある程度自由にピンにアサインすることができる。
[FPIOA · MaixPy DOC](https://maixpy.sipeed.com/en/libs/Maix/fpioa.html)
今回はUARTを使いたいので、ブレイクアウトボードに出ていたPIN10,PIN17をそれぞれUART1のRXD,TXDに割り当てた。

```python
from fpioa_manager import fm

fm.register (board_info.PIN10, fm.fpioa.UART1_RX)
fm.register (board_info.PIN17, fm.fpioa.UART1_TX)
uart = UART (UART.UART1, 9600, 8, None, 1, timeout = 1000, read_buf_len = 256)
```
これだけでUARTピンが出せる。便利。
文字列を出力しつつオシロでPIN17をあたってみると、正常なUART波形が見れた。

## 接続基板の作成と組み立て
AquesTalk基板の4ピンと、対応するM1nボードのピンを接続する基板を作成した。AquesTalk基板はスピーカまで載せたこともあり大きいので、上にスタックする感じにしてみた。
![m1n_talk.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235770/f5c0cfcd-82ec-4987-cddc-ffbc8ae5d9fb.jpeg)

# コーディングとデプロイ
## MaixPyでの記述
先述のK210のTiny YOLOのサンプルをもとに、認識した物体をUARTでAquesTalkに送るようにスクリプトを書いた。
日本語的な都合で、取り急ぎ生物以外は無視！(「居るよ」「有るよ」の区別が面倒だっただけ)
生物無視してもいいんだけど、個人的には猫が必須なので生物側で。

本来はAquesTalkからの応答を待ってから、次の発音命令を送信するべきだが、そのへんも今のところ無視。なのでたまに変なことを言う。（「猫が居るよが居るよ」みたいな）
AquesTalkはイントネーションを自然にするための色々な発音記号も使えるが、それも今回は使っていない。いつか調教したい。

最初はただ毎回検出したものを喋ってみたが、流石に安定しなかったため、移動平均的な処理(5フレーム中半分以上のフレームで検出されたクラスについて喋る)を入れたら安定した。この辺も最適化の余地がありそう。

最終的なコードは下記リポジトリ。
https://github.com/k2kdisk/M1nTalk

## デプロイ
USB電源で動かしたかったので、uPyLoaderでM1nTalk.pyをmain.pyとしてアップロードした。
起動時にはmain.pyが自動的に実行されるので、main.pyを置き換えることでPCレスで実行できた。
![Screenshot from 2020-04-05 11-55-48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/235770/2005a53e-be22-c7da-3ea5-2ac421a09bac.png)

## 動画
我が家のネコさんに協力していただいてテストした。馬とかは飼っていないので、ネコと撮影している自分(人)のクラスしか認識していないけど、いい感じで喋っている。
[![Sipeed M1n (Maix Nano)の検出結果をAquesTalk Picoで音声合成して喋らせる](http://img.youtube.com/vi/yNkhttV8sAw/0.jpg)](https://youtu.be/yNkhttV8sAw)

# まとめ
- Sipeed M1nでUART通信できた。
    - FPIOAでピン配置をいじれるのがとても便利。
- UARTでAquesTalk pico LSIを簡単に喋らせることができた。
    - イントネーションや音質など、まだまだ改善の余地あり。
- USB電源と単純な基板でスマートカメラっぽいことができた。
    - せっかくYOLOなので、位置の情報とかも含めて喋ってみたい。

以上