Sipeed M1 Dock(MAiX Dock)でTinyYoloを動かして、人を認識したらSDカードに保存する

# はじめに

*こんにちは、のんびりエンジニアのたっつーです。*
*[ブログ](https://www.fast-system.jp/)を運営しているのでよろしければ見てください。*

今回はこのM1 Dock（MAiX Dock）ボードを使って、超小型なボードを使ってTinyYoloを動作させながら、人間を認識したらSDカードに画像を保存するような動作を実装してみました。

想定される使い道としては***監視カメラ***などで***人をトリガーとして何かを動作させる場合***などに使えるのかなと思います。

# M1 Dock（MAiX Dock）とは？

[Sipeed M1 dock suit ( M1 dock + 2.4 inch LCD + OV2640 ) K210 Dev. Board 1st RV64 AI board for Edge Computing](https://www.seeedstudio.com/Sipeed-M1-dock-suit-M1-dock-2-4-inch-LCD-OV2640-K210-Dev-Board-1st-RV64-AI-board-for-Edge-Computing.html)

購入すると以下のセットが届きます。
***ボード、ディスプレイ、カメラ付き***のオールインワンのセットになっています。これで***19ドルほどで購入***できるのはすごい安いですね。

[ケース（@ksasao）](https://twitter.com/ksasao/status/1127934765074485250) さんのを使わしていただいており、３Dプリンターで出力した物になります。

![D6w0jBUUYAAWlLz-768x576.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227880/33f3eb97-32da-de61-4c4a-ab693f504d06.jpeg)

RISC-Vと言うオープンCPUアーキテクチャを採用している安価なチップを採用しています、それに加えてこのボードでは ***KPU(Knowldge Processing Unit) を搭載しており、機械学習で必要な演算を高速に実行***する事が可能です。

K210のチップベンダーkendryte社のサイトに掲げられている特徴を引用します。

- Performance
   - CPU: RISC-V Dual Core 64bit, with FPU
   - Image Recognition:QVGA@60fps/VGA@30fps
   - Audio: Microphone array (8 mics)
- Security
   - Advanced encryption standard (AES) hardware accelerator
   - One time programmable (OTP) ROM
   - SHA256
- Power Consumption
   - Power consumption of typical application scenarios < 1W
   - Power consumption of chip < 300mW
- Expansibility
   - OS: FreeRTOS
   - NN Model: TinyYOLOv2 (after pruned)
   - DNN Framework: TensorFlow/Keras/Darknet
   - PeripheralsFPIOA/UART/GPIO/SPI/I²C/I²S/WDT/TIMER/RTC, etc.

# ダウンロード

今回使うツールをダウンロードしますが、それぞれの以下のような物になります。
　***K-Flash*** ： ROMを書き換えるツール　
　***maixpy_20class*** ： TinyYoloのROM・ソースーコード
　***uPyLoader*** ： ファイル転送ツール

実際にダウンロードして、ローカルのフォルダに保存しておきましょう。

1. https://kendryte.com/downloads/ から「K-Flash V0.3.2」をダウンロード
1. https://bbs.sipeed.com/t/topic/683 から「maixpy_20class.zip」をダウンロード
1. https://github.com/BetaRavener/uPyLoader/releases から最新版の「uPyLoader-win.exe」をダウンロード

以下のように配置した状態で開始します。
![image-88-768x373.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227880/24c7ccfe-d935-c895-4ef5-a13b394faf5a.png)

「uPyLoader-win.exe」「K-Flush」についてはプロパティから***セキュリティの「許可する」をオン***にしておきましょう。
![image-89.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227880/60bc3552-20af-66a2-b892-4d916f6e3f31.png)
![image-91.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227880/070c2c0b-bdef-4294-4bcb-ffd3a7d6c87a.png)

上記で必要な物のダウンロードが行えましたので、次からは実際にYoloを動かす手順になります。

# TinyYoloを動かす

## M1 Dock(MAiX Dock)をPCと接続

M1 Docke(MAiX Dock)をPCと接続すると、自動でドライバー（CH340）が認識されます。
認識されたらここの***ポート番号（今回はCOM3）を覚えておきましょう***。
![image-92.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227880/7b048fee-7ea9-183a-4af1-126551e17917.png)

## K-FlashでROMの書き換え

まず最初のステップでは、TinyYoloを動かすためにM1 Dock（MAiX Dock）のROMを直接書き換えます。

### maixpy_20class.bin の書き込み

***「COM3」***が選択されている事を確認したら、***「maixpy_20class.bin」を選択***して、***「Flush」ボタンでROM書き込み***を行いましょう。
![image-93-768x374.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227880/71299403-1895-2bd3-0a5f-6bddcff3281d.png)

### 20class.kfpkg の書き込み

次も同じ手順で***「20class.kfpkg」を書き込み***ましょう。
![image-94-768x374.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227880/b08c4a1d-edb6-33b4-ee0c-681ee2575659.png)

## TinyYoloのPythonコードを転送

### boot.pyの作成

次に「20class.py」をコピーして「boot.py」を作成しておきましょう。
![image-95-768x726.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227880/8376e49b-aceb-2acc-3723-f58e2a81a2a6.png)

### boot.pyの転送

「uPyLoader.exe」を起動してください。

***「COM3」を選択***して、***「Connect」ボタン***を押下してデバイスに接続します。
![image-96-768x120.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227880/11a05db9-cf81-ae0e-e4a0-937f9f7ab662.png)

接続に成功すると以下のようにファイル一覧が表示されます。
![image-97-500x250.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227880/ab901b17-e526-0b48-232c-383bb9633b00.png)

先ほど作成した***「boot.py」をデバイスに転送***しましょう。
![image-98-768x463.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227880/2c6f69fc-2773-0b1f-1ab5-25a31bf27715.png)

## 動作確認

***USBケーブルを指しなおして***みましょう。
boot.pyのソースコードが実行され、実際に以下のように***人・車などの２０分類のTinyYoloが実行***できると思います。

> ※カメラの画像が反転している場合は、sensor.set_vflip(0)の次の行に sensor.set_hmirror(0)を追加する。 
> https://twitter.com/ksasao/status/1129035637129129985

<blockquote class="twitter-tweet" data-lang="ja"><p dir="ltr" lang="ja">MAiX Dock で TinyYolo2 を動かした結果。20ドルくらいの値段でこの性能はコスパ良すぎ！<br><br>車、人が認識されています。 <a href="https://t.co/CIJdjQAWvG">pic.twitter.com/CIJdjQAWvG</a></p>— たっつー@Unity情報発信 (@kingyo222) <a href="https://twitter.com/kingyo222/status/1129328433824010240?ref_src=twsrc%5Etfw">2019年5月17日</a></blockquote>
<script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

すごいですね！

# SDカードにデータを保存する

次に本記事のメインになります。
実際にTinyYoloを使う場合には、何かを検知して何かアクションを行う必要がありますよね。
ここのでは***”人を検知して”、”SDカードに画像として保存”***の手順をやってみます。

## SDカードのフォーマット

まず、***SDカードをWindowsに読み込ませてフォーマット***を行いましょう。（ここで***小さい容量の物を使うと、FAT16でフォーマット***されてしまうため動作しないので気を付けてください。）
![image-99.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227880/f4a4aba8-b805-e8e3-2e55-31c8393c3bde.png)

## boot.pyの書き換え

さきほど、作成した***boot.pyを以下のように変更***してください。

```python:boot.py
import sensor,image,lcd,time
import KPU as kpu

lcd.init(freq=15000000)
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.set_hmirror(0)
sensor.run(1)
clock = time.clock()
classes = ['aeroplane', 'bicycle', 'bird', 'boat', 'bottle', 'bus', 'car', 'cat', 'chair', 'cow', 'diningtable', 'dog', 'horse', 'motorbike', 'person', 'pottedplant', 'sheep', 'sofa', 'train', 'tvmonitor']
task = kpu.load(0x500000) 
anchor = (1.08, 1.19, 3.42, 4.41, 6.63, 11.38, 9.42, 5.11, 16.62, 10.52)
a = kpu.init_yolo2(task, 0.5, 0.3, 5, anchor)
cnt = 1
while(True):
    clock.tick()
    img = sensor.snapshot()
    code = kpu.run_yolo2(task, img)
    print(clock.fps())
    if code:
        person = False
        for i in code:
            a=img.draw_rectangle(i.rect())
            a = lcd.display(img)
            for i in code:
                lcd.draw_string(i.x(), i.y(), classes[i.classid()], lcd.RED, lcd.WHITE)
                lcd.draw_string(i.x(), i.y()+12, '%f1.3'%i.value(), lcd.RED, lcd.WHITE)
                if classes[i.classid()] == 'person':
                    person = True
        if person == True:
            name = 'person_' + str(cnt) + '.jpg'
            img.save(name)
            lcd.draw_string(1, 1, 'saved ' + name, lcd.RED, lcd.WHITE)
            cnt = cnt + 1
    else:
        a = lcd.display(img)
a = kpu.deinit(task)
```

## boot.pyの転送

***SDカードを M1 Dock(MAiX Dock)にセット、USBケーブルを再接続***してください。

※ここで、***内部メモリからブートする事があるので、SDカードからブートするまで何度か再接続してください。***

「uPyLoader.exe」を起動して再度「COM3」に接続します。
![image-96-768x120.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227880/982af638-7aa5-363c-74f1-959bfc38fae4.png)

そうすると以下の警告が表示されます。
これはSDカードからブートしようとしたけど、ファイル転送のPythonコードが存在しないから「uPyLoader.exe」が正常に動かないよ！って意味の内容です。
![image-100-768x464.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227880/2b68a684-b04b-4e34-5d02-3f15a5a98ce9.png)

なので、「uPyLoader」のメニューから「File > Init Transfer files」を選択して、転送用のPythonコードを初期化しましょう。
![image-101-768x463.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227880/72709891-ac0b-ef21-7ec7-37029c5229c6.png)

正常に初期化が終わると、「__upload.py」/「__donwload.py」の２つが転送されています。
![image-102-768x463.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227880/a0ad8847-4da4-5925-dec3-430fafb67efc.png)

次に作成作成した、「boot.py」をデバイスに転送します。
![image-103-768x463.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227880/39d85356-d06d-569b-1c1d-df9fc16666b3.png)

お疲れ様です、以上で手順が終わりました。

## 動作確認

実際にUSBを指しなおして、動作確認してみましょう。

画面の左上に「saved person_128.jpg」などの表示が追加されたと思います、これは SDカード にデータ保存したよ！って意味で画面上にメッセージを追加したのでわかりやすいと思います。

![IMG_1841-768x1024.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227880/de8f6aea-be33-4ea9-5f8c-de7b726d158b.jpeg)

uPyLoaderで実際に確認してみましたが、保存されている事が確認できますね。

![m1-dock-kekka-768x607.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/227880/08b36012-62ca-ae1e-0dd9-c78cac03d7c4.png)

# 終わりに

どうでしたか簡単でしたね。

色々とWebの手順などを見ていると、Pythonを使ったやり方がありますが環境構築が手間なのでこの手順のように単体の実行ファイルで関係すると楽だと思いますので、ぜひ皆さんも試してみてください。

*よければ ブログ「[Unity+AssetStoreおすすめ情報](https://www.fast-system.jp/)」の方にも色々記載しているのでぜひご参照いただければと思います。*