TensorFlow Lite for MicrocontrollersとESP32を用いた安価なAI自動運転の検証
1. この記事について
DonkeyCarなど行動模倣(Behavior Cloning)を行うAI RC CARではカメラ画像を入力とした推論と走行が一般的だ。1。この場合、エッジ側にもそれなりの計算力が必要になり、実機ハードウェアの構成が高額になる。この記事ではカメラを使用せずに単純なセンサ情報のみで同様の仕組みを実現できることをシミュレーション環境と実機での検証を通して確認した。検証では3つの距離センサの値を入力とする3層のニューラルネットワークを用いて自動走行を実現した。さらに実機の検証ではTensorFlow Lite for Microcontrollers2とESP32を使い、安価な構成でニューラルネットワークによるラジコンカーの自動運転が実現できることを示した。
検証で作成したコードは以下のGithubリポジトリで公開している。
2. シミュレーションによる予備検証
まず初めに、実現の目論見を確認するため、シミュレーションによる予備検証を実施した。
2.1 シミュレーション環境
シミュレーション環境は詳解確率ロボティクス3に記載の差動2輪ロボットのシミュレーション環境を参考に実装した。別途、コースをあらわす壁と距離センサを実装している。Pytorch版のシミュレーション環境はGistで公開している。TensorFlow版は前述のリポジトリから参照できる。実装フレームワークが違うのみでそれぞれに違いはない。
ロボットには3つの距離センサを設置した。それぞれのセンサは前方方向に1つとそれを原点として左右に60度開いて設置している。
シミュレーションはデータ収集・学習・推論走行の3つのパートに別れている。「データ収集」では比例制御によりコースを自動走行する。比例制御は左右のセンサ値の差分を入力として操舵の制御値を決定する。また学習データとして観測されるセンサの値と対になる制御値の記録を行う。「学習」では学習データを元にニューラルネットワークを訓練を実行する。「推論走行」では学習したニューラルネットワークを使い自動走行を実行し、その評価を行う。
2.2 ニューラルネットワークモデル
シミュレーションで取得した学習データは以下の形でCSV形式で保存した。速度の値は学習データとして記録されるが固定値であるため意味を持たない。各センサの値入力として操舵角と速度を推定する回帰問題として学習させる。
左センサ値,中央センサ値,右センサ値,操舵角,速度
定義したニューラルネットワークモデルは3層の全結合層から構成される。アクティベーション関数は1層目と2層目にReluを使用し、最終段には設定しない。また、Loss関数はMSEを設定している。以下、TensorFlowでの実装例を示す。
import tensorflow as tf from tensorflow import keras from tensorflow.keras import layers model = keras.Sequential([ layers.Dense(8, activation='relu', input_shape=(3,)), layers.Dense(8, activation='relu'), layers.Dense(2), ]) optimizer = keras.optimizers.SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True) model.compile(loss='mse', optimizer = optimizer, metrics = ['mae']) model.summary()
2.3 シミュレーション検証の結果
シミュレーションでは実行の様子を動画で確認できる。ここでは結果の画像を掲載する。画像中の円が自動運転車を表している。自動運転車から3本出ている赤い線がセンサの計測方向となる。観測されるセンサの値は各線と壁の接触点と自動運転車との直線距離となる。3000ステップの試行を行い、3000レコードのデータを集めた。
収集したデータを使い訓練したニューラルネットワークを比例制御と置き換えて自動走行を実行した。初期位置をX軸方向にずらして実行している。以下の画像を確認すると比例制御の動きと同じ軌跡で自動運転が行われていることが確認できる。線形制御の出力データからニューラルネットワークがその関数を「近似’している。
いずれも人を介在しない自動走行だが、前者は人が走行できるようにルールをコードベースに落とし込んでいる。しかし、後者はデータから自動的にルールを発見させているという点で大きな違いがある。
3. 実機による評価
シミュレーションにおいて距離センサ3つの入力のみで行動模倣を実現できることがわかった。実機へも適用できるか検証を実施した。
3.1 検証車両の紹介
今回実機検証の車両としてRumiCarというオープンハードウェアの車両を用いて検証を行なった。RumiCarは安価なラジコンカーを改造し、ESP32と距離センサVL53L0Xを3つ搭載している。ベースとなるラジコンカーの制約としてスロットルは全身、後進、停止、ステアリングは直進、右、左という離散的な制御しかできない。
3.3 実機に合わせたニューラルネットワークの変更とESP32へのデプロイ
ニューラルネットワークの構成をシミュレーションから実機に合わせて変更した。センサの値から「直進」「左」「右」の3つのクラスを推論するよう分類問題として学習させる。
import tensorflow as tf from tensorflow import keras from tensorflow.keras import layers model = keras.Sequential([ layers.Dense(8, activation='relu', input_shape=(3,)), layers.Dense(8, activation='relu'), layers.Dense(3, activation="softmax"), ]) optimizer = keras.optimizers.SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True) model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy']) model.summary()
訓練後のモデルをTensorFlow Lite for microcontrollers向けに変換する。TensorFlow Lite形式で保存したモデルをxxdコマンドを使い、バイト配列として出力する。出力されたバイト配列をファームウェアの一部としてESP32といった低リソースのマイコンへデプロイする。TensorFlow Lite for microcontrollersの詳細な利用方法については公式を参照[^2]。
converter = tf.lite.TFLiteConverter.from_keras_model(model) converter.optimizations = [tf.lite.Optimize.DEFAULT] tflite_model = converter.convert() #量子化はせずFP32のまま処理していことに注意! open("converted_model.tflite", "wb").write(tflite_model) #TFLite形式で保存 !apt-get install xxd !xxd -i converted_model.tflite > airc_model.cpp #xxdコマンドでモデルをC言語で参照可能なバイト配列として出力する。
TensorFlow Lite microcontrollersはCPUやフレームワークといった利用する組み込み環境に合わせて自分でビルドする必要がある。Arduino フレームワークとESP32の組み合わせはビルド済みのライブラリがリリースされており、Arduino IDE, PlatoformIOのライブラリ管理から「TensorFlowLite_ESP32」でインストールできる。今回はこちらのライブラリを利用して実装を行なった。
詳細な実装コードついては冒頭のリポジトリを参照してほしい。
3.4 実機検証結果
実機の検証においても比例制御による自動走行で学習データを収集した。前述の制御の制約に合わせるため出力結果をルールベースで各命令に対応させている。ニューラルネットワークの訓練と形式の変換はGoogle Colaboraotryで行い、ESP32へプログラムとともに書き込む。
以下が実機検証の動画である。コースは紙を山折りにした物を円形に配置し作成した。実機でもニューラルネットワークがセンサのデータから制御値を推論して走行できていることがわかる。
4. まとめ
この記事では距離センサ3つのみという構成で、ニューラルネットワークによる自動走行が可能であることをシミュレーションを通して検証した。また、TensorFlow Lite for microcontrollersを利用することで、ESP32を搭載した実機のラジコンカーで自動走行が可能であることを検証した。今回は単純な制御則でも十分に制御できるが、コースを逸脱しないように走行するという抽象的表現を人がプログラミングでルールとして落とし込むのではなく、データから演繹的に自動的にルールを作り出せること、さらにそれを「マイコンレベルで実現できる」という点が非常に面白い。今後マイコンを利用したセンサデータと複雑なルールの組み合わせが単純だが高度なことができるデバイスの登場を予感させる。