DonkeyCarのディープラーニングモデルをMATLAB/Simulinkを使ってRaspberry Piに実装する

# はじめに

[「DonkeyCarのデータセットをMATLAB/Simulinkでリプレイしてみる」](https://qiita.com/covao/items/16f96b17db87eb45c1f6)では、DonkeyCarのデータセットを使ってディープラーニングモデルのリプレイを行いました。今回、MATLAB/Simulinkで作成したDonkeyCarのディープラーニングモデルをRaspberry Piに実装してみます。

# ソフトウエア
- MATLAB 2021B ([MATLAB Home](https://jp.mathworks.com/products/matlab-home.html))
- [Deep Learning Toolbox](https://jp.mathworks.com/products/deep-learning.html) 
- [Simulink Support Package for Raspberry Pi Add-On](https://jp.matのhworks.com/help/supportpkg/raspberrypi/)
- [MATLAB Coder Interface for Deep Learning Libraries Add-on](https://jp.mathworks.com/matlabcentral/fileexchange/68612-matlab-coder-interface-for-deep-learning-libraries)

# ハードウエア
- Raspberry Pi 4B
- Raspberry Piカメラモジュール
 
# PythonベースのDonkeyCar環境とMATLAB/Simulinkの比較
DonkeyCarは、PythonとTenserFlow/KerasライブラリをベースにつくられたAIカーソフトウエアで、走行用プログラムやユーティリティがオープンソースとして公開されており、無償で利用できます。
Pythonのクラスで記述されたパーツライブラリーが用意されていて、センサー、コントローラ、アクチュエータのコードを組み合わせてコーディングができます。
しかしながら、ソースコードの規模が大きく、AIカーをシンプルに理解するには、難しいと感じるところもあります。
一方、Simulinkは、AIカーのコントローラをブロック図で記述でき、構造を理解しやすく、シミュレーションや計測、制御に向いています。

# Raspbian上でのDonkeyCarとMATLAB/Simulink実行環境の共存
Simulink Support Package for Raspberry PiのRaspbian OSにDonkeyCarのソフトをインストールしたところ、両方の環境を共存させて使うことができました。:sunglasses:

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329764/8b2b4076-db2d-25b3-fefe-833b6fa02dd8.png)

# Simulinkを使ったDonkeyCarのディープラーニングモデル

Raspberry Piのカメラ画像をDonkeyCarのCNNモデルに入力し、ステアリング角、スロットル値を出力します。
PWM値に変換し、I/Oブロックを接続することで、サーボモーターや駆動モータを動作させることができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329764/ed7f4a03-838f-bd7a-befd-68c04fa0e196.png)

[SimulinkモデルのGitHubリンク](https://github.com/covao/DonkeyCar_Raspi_Simulink/blob/main/README.md)

DonkeyCarのディープラーニングモデルは、以下の学習済み *.h5ファイル(Kerasモデル)をインポートして、matファイルに変換したものを使用しています。
https://github.com/autorope/donkey_datasets/tree/master/circuit_launch_20210716/models
# MATLAB Functionを使った実行サイクル時間の表示
MATLAB Functionブロックに下記の関数を記述し、１サイクルの演算周期に要した時間を出力します。
```matlab
function y = exec_time()
    persistent t0
    if isempty(t0)
        t0 = 0;
        tic;
    end
    t = toc;
    y = t - t0;
    t0 = t;
end
```

# ターゲットハードウエア実行モード
下記のような実行モードがあります。
Simulinkのシミュレーションで確認してから、ターゲットハードウエアのExternalモードでビルドを行い、Raspberry Piへ実装してみます。


| 実行モード | モデル演算 | I/O |特徴|
|:------------:|:------------:|:------------:|:------------:
| Simulink       |ホストPC        |  なし       |シミュレーションをすぐに実行可能|
| Connected I/O (Input/Output mode)   | ホストPC      | ターゲットボード|ビルド時間が短く、モデル演算は速いが、通信によるI/Oの遅延あり|
| Run on board (External mode)  | ターゲットボード | ターゲットボード|ボード上で実行するため、リアルタイム制御に適している|
| Deploy         | ターゲットボード          | ターゲットボード  |ホストPC接続なしでボード上の実行が可能|


# ARMターゲットでのディープラーニング高速化
試行錯誤の末、MATLAB Homeでは、以下のようなSimulinkモデルのHWオプションを設定すると、ARM ターゲットのコード生成を行うことができ、演算が高速化しました。:sweat_smile:

```matlab
set_param(bdroot,'HardwareBoard','None');
set_param(bdroot,'HardwareBoard','Raspberry Pi');

set_param(bdroot,'TargetLang','C++');
set_param(bdroot,'SimTargetLang','C++');
set_param(bdroot,'CodeInterfacePackaging','Nonreusable function');

set_param(bdroot,'DLTargetLibrary','arm-compute');
set_param(bdroot,'ProdHWDeviceType', 'ARM Compatible->ARM Cortex');
set_param(bdroot,'DLArmComputeVersion','19.05');
set_param(bdroot,'DLArmComputeArch','armv8');
set_param(bdroot,'UseSimulinkCoderFeatures','off');

```
- Simulinkモデルの新規作成より、Simulink Support Package for Raspberry Pi HardwareのBasic Modelのテンプレートを使ってベースモデルを作成し、コマンドでオプションを設定しています。
- 最初の２行は、HardwareBoardをNoneから、Raspberry Piに切り替えて、Raspberry Pi向けのオプションを自動設定しています。
# 実行時間の確認
汎用C/C++コードでは、モデルサンプリング周期 0.05 secをオーバーし、0.2-0.5 sec程度かかっていましたが、ARMターゲットのオプション適用後、モデルサンプリング周期 0.05 sec前後で演算されています。

- 汎用C/C++による実行サイクル時間 
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329764/ced5f929-61b9-051b-fd62-fbfbe3bec724.png)
- ARMターゲットによる実行サイクル時間
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/329764/4c34eb94-9b05-cbc6-7778-63211a9ce27a.png)


# まとめ
Simulinkで作成したDonkeyCarのディープラーニングモデルをRaspberry Piに実装してみました。ARMターゲットのコード生成を行うことで、Raspberry Pi上でのディープラーニング演算が高速化しました。
# 参考
- [Mathworks Documentation: Simulink Support Package for Raspberry Pi Hardware](https://jp.mathworks.com/help/supportpkg/raspberrypi/)
- [Mathworks社ドキュメント ARM ターゲットでの深層学習用のコード生成](https://jp.mathworks.com/help/coder/ug/code-generation-using-arm-compute-library-without-a-hardware-support-package.html)
- [Donkey Car Datasets (サンプル)](https://github.com/autorope/donkey_datasets)