Arduino Nano 33 BLE Senseを使って機械学習

# はじめに
TensorFlow Liteをマイコン上で動かしてみたいな～と思って調べてみたところ,Arduinoの公式が,Arduino Nano 33 BLE SenseでTensorFLow Liteのモデルを動かすチュートリアル的（[ページのリンク](https://docs-content.arduino.cc/tutorials/nano-33-ble-sense/get-started-with-machine-learning/)）なものを出していたので、実践してみました。進めてみるとそのままのコードでは動かない部分があったので、備忘録として書くので雑です。

# 使用デバイス
**Arduino Nano 33 BLE Sense**
[スイッチサイエンスのリンク](https://www.switch-science.com/products/7670?srsltid=AfmBOooNPSyWZCeAAsAf1Ik29X8c28lYCCL6Kv1CY9DM9B1SORWWy6aK)
マイコン : nRF52840
フラッシュメモリ : 1MB
SRAM : 256kB
- 通信機能 
-- BLE
 --   NFC
- センサ
-- IMU
-- マイク
-- 環境センサ
-- 光センサ
-- 近接センサ

このように小型で多数のセンサが搭載されているマイコンボードになっています。

# 環境構築
公式サイトではArduinoを使っていますが、今回はPlatformIOを使っていこうと思います。
まずは下の画像のようにプロジェクトを作成します。
![スクリーンショット 2024-12-09 045200.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654052/aef4d448-1ff2-2013-e073-dbf363669922.png)


次に**Arduino_LSM9DS1**というライブラリをインストールします。
Arduino_LSM9DS1で調べて最初に出てきたライブラリを先ほど作ったプロジェクトに追加します。
![スクリーンショット 2024-12-09 045803.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654052/47d689a8-d673-afd6-95de-02b6c552e51d.png)

次にArduino用のTensorFlow liteのライブラリをインストールするのですが、こちらは検索しても出てこないのでGitHubからダウンロードします。
https://github.com/tensorflow/tflite-micro-arduino-examples
上記のリポジトリをクローンします。
クローンしたものをlibディレクトリに入れてください。
これで環境構築は完了です。

# センサデータの収集
```
#include <Arduino_LSM9DS1.h>

const float accelerationThreshold = 2.5; // threshold of significant in G's
const int numSamples = 119;

int samplesRead = numSamples;

void setup() {
  Serial.begin(9600);
  while (!Serial);

  if (!IMU.begin()) {
    Serial.println("Failed to initialize IMU!");
    while (1);
  }

  Serial.println("aX,aY,aZ,gX,gY,gZ");
}

void loop() {
  float aX, aY, aZ, gX, gY, gZ;

  while (samplesRead == numSamples) {
    if (IMU.accelerationAvailable()) {
      IMU.readAcceleration(aX, aY, aZ);

      float aSum = fabs(aX) + fabs(aY) + fabs(aZ);

      if (aSum >= accelerationThreshold) {
        samplesRead = 0;
        break;
      }
    }
  }


  while (samplesRead < numSamples) {
    if (IMU.accelerationAvailable() && IMU.gyroscopeAvailable()) {
      IMU.readAcceleration(aX, aY, aZ);
      IMU.readGyroscope(gX, gY, gZ);

      samplesRead++;

      Serial.print(aX, 3);
      Serial.print(',');
      Serial.print(aY, 3);
      Serial.print(',');
      Serial.print(aZ, 3);
      Serial.print(',');
      Serial.print(gX, 3);
      Serial.print(',');
      Serial.print(gY, 3);
      Serial.print(',');
      Serial.print(gZ, 3);
      Serial.println();

      if (samplesRead == numSamples) {
        Serial.println();
      }
    }
  }
}
```
ここではジェスチャごとの加速度データを取得します。
簡単にコードの説明をすると
```
float aSum = fabs(aX) + fabs(aY) + fabs(aZ);
```
ここでX,Y,Zそれぞれの加速度の絶対値を足してそれがaccelerationThresholdを超えたら、データの記録を開始するというものになります。
ここで、各ジェスチャを10回ほど行い、それぞれのデータをcsvファイルとして保存します。

# モデルの作成
ここではモデルの作成を行います。
ここは[こちらのGoogle Colab](https://colab.research.google.com/github/arduino/ArduinoTensorFlowLiteTutorials/blob/master/GestureToEmoji/arduino_tinyml_workshop.ipynb)のコードをそのまま実行すれば大丈夫です。
最後まで実行すると**model.h**というファイルが生成されるのでそれをローカルに保存してください。

# 実際に加速度を計測して分類する
ここでは実際に分類していきます。
こちらも基本的には[こちらのコード](https://github.com/arduino/ArduinoTensorFlowLiteTutorials/tree/master/GestureToEmoji/ArduinoSketches/IMU_Classifier)を使えばいいのですが、ここで注意が必要です。
このコードをそのまま実行するとエラーが発生します。

まず
```
#include <tensorflow/lite/micro/micro_error_reporter.h>
```
でエラーが発生すると思います。
実際にtensorflow/lite/micro/の中を見てみると、micro_error_reporter.hというファイルは存在しないので、探してみるとmicro/tflite_bridgeという場所にあったので、
```
<tensorflow/lite/micro/tflite_bridge/micro_error_reporter.h>
```
に変更します。
また

```
#include <tensorflow/lite/version.h>
```
でもエラーが発生します。
こちらはリポジトリ内のどこにも見つからず途方に暮れていると、version.hをコメントアウトしているサイトを発見して、コメントアウトしたら動作しました。ディレクトリ構造が古いままなんですかね....

最後に
```
tflInterpreter = new tflite::MicroInterpreter(tflModel, tflOpsResolver, tensorArena, tensorArenaSize, &tflErrorReporter);
```
こちらでもエラーが発生すると思います。
こちらのエラーも原因を調べていると同じエラーが発生している人が[issuesを上げていた](https://github.com/arduino/ArduinoTensorFlowLiteTutorials/issues/36)ので確認して以下のように修正したらエラーが解消されました。
```
tflInterpreter = new tflite::MicroInterpreter(tflModel, tflOpsResolver, tensorArena, (size_t)tensorArenaSize,nullptr, nullptr);
```
このコードを書き込んで動かしてシリアルモニタを見てみると
```
punch: 0.000102
flex: 0.999898

punch: 0.986821
flex: 0.013179
```
上記のような値が出てきてしっかりと推論ができていることがわかります。

# 最後に
今回はArduino Nano 33 BLE Senseの機械学習の公式チュートリアルで詰まったところを備忘録として残しておきました。エラーを解消しようと思って調べてみても古い記事が多かったので、同じようなエラーが発生している人の役に立てればと思います。また今回はあくまで動くようにしただけで、コードの詳しい内容、特にC++のコードは理解できていない部分が多いので、エラーが解消できた理由などわかる方がいればコメントいただければ嬉しいです。
今後はほかのマイコンや、音声認識など別のモデルも実装していきたいと思います。
備忘録なのでだいぶ雑な感じになってしまいましたが、最後まで読んでいただきありがとうございます。