ROS2 自作 Turtlebot3 による 草刈りロボット開発。#8 Transformer で経路計画をする。

ROS2 自作 Turtlebot3 による 草刈りロボット開発。#8 Transformer で経路計画をする。

--- ROS2 ロボット自律走行の経路計画の補助に、機械学習(Transformer、LSTM)を使う。 ----

ROS2 自作 Turtlebot3 による 草刈りロボット開発。#6 Nav2 Planner を替えてみる で、ThetaStarPlanner を使って、Auto Mower 時の走行の直進性の改善がみられた。

しかし、まだおんちゃんが望む直進性能には、足りない。
そこで、ThetaStarPlanner の経路プランの一部補正として、機械学習が使えないか、無い知恵を絞って、考えてみた。

1. 概要
結論を先に言ってしまえば、経路プランに、Transformer、Lstm による、Speech To Text モデルのロジックを使えないだろうか? と言う話じゃ。

下の画像だと、赤線の経路を、青線の様にしたい。
障害物の手前まで真っ直ぐ進んで、障害物をなぞるように進んで、再度、スタートとストップの直線上に戻る、走行が欲しい。


2024-09-30 14-25-56-1.jpg

前の画像を、下記のように抜粋する。
これって、Transformers、LSTM Speech to Text の音声入力を、高速フーリエ変換したスペクトグラムの画像に似ていないじゃろか?

2024-09-30 14-25-56-1b.jpg


y: tf-map で示される、y軸の距離とする。
x: tf-map で示される、x軸の距離とする。
画像サイズ:
-1.5[M] <= y < =1.5[M] だとして、 分解能を、0.05[M] とすると、
height: 60+1 [dot]

ただし、端は通らないから、ロボットradius: 0.3[M] より内側を使って、端は、通行不可とする。
-1.2[M] <= ry <= 1.2[M] だとして、 分解能を、0.05[M] とすると、
height: 48+1 [dot]
model の出力値 rY:
0 <= rY <= 47+1
注) 後で、center line の 1[dot] が必要だと判ったので、+1 する。

障害物(走行不可)、といずれでもない class_id も必要。
modelの出力は、整数のみだから、変換テーブル(Vocab) を用意する。
ロボットは、障害物がない、通常は、ry=0.0 [M] を取ると、model には、教える。

注) predict 結果に、いずれでもない class があると、間が、詰まってくるのかな?
いや、多分、いずれでもない class 以外の、accuracy の低いclass をすべて使えば問題ないと思う。
注2) predict の出力イメージは、x 等間隔による、y軸 のプロット値のみが出てくる。
もしかしたら、x軸に関して、リニアでは無いのかもしれない。そうしたら、この計画は、破綻する、無理かも。

以上の条件で、学習データを用意して、スクラッチ学習すれば、model ができそうなきがする。

モデルへの入力データと、学習データは、global cost map(static layer+obstacle layer+inflatuion layer) の中から、
ロボット位置 -> 目的位置 をx 軸とする矩形を抽出して使う。
ここで、悩むのが、global cost map を cv::Mat に変換した時点で、上下が逆転している事。
これへの対応をどうするか、まだ、整理がついておりましぇん。

これは、やはり再度、上下を逆転させて、見た目を同じにする。
画像サイズも大きなものが必要か?
Keras V3 Automatic Speech Recognition with Transformer with Mltu で、
input_shape:
1392
193
なので、上記、再逆転した cv::Mat を 拡大して使用する。
分解能: 0.025[M]
x: 1000 [dot] -> 25 [M] (距離)
y: 120+2 [dot] -> 3.05 [M] (幅)
ry: 96+2 [dot] -> 2.45 [M] (幅)
class num: 48+1+2

注1) x(距離) は、実際は、もっと短い場合があるので、このときは、足りない残りを、 padding する。
注2) 上の画像で、620x135 [pixle] ぞね。

以上の手順を整理すると、
i) Global cost map (解像度: 0.05) のデータの上下逆にしたものを、cv::Mat(生 cv::Mat とする) に変換。
ii) 上記、生 cv::Mat 上で、ロボットの現在位置 -> 目的位置 の幅 3[m] の矩形を抽出して、 それを x2 倍した画像を用いる。
学習用として、画像を保存するばあいは、このまま保存する。
実行用として、model に入力するときは、距離が、25[M] に足りないときは、足りない部分を padding する。
predict 結果は、実際の距離に応じた部分だけを使う。

2. このモデルの運用イメージ
Auto Mower で、ロボットの草刈りコース位置上の start - stop 間のコースに関して、
最初に、今行っている、start - stop 間の障害物チェックを行う。
障害物が検出されなければ、cmd_vel で直線的に走行する。

障害物が検出されたなら、次に、このモデルで予測する。
predict 結果に、障害物(走行不可)ありが報告されたなら、通常の navigation2 による走行を行う。
障害物(走行不可)がなければ、cmd_vel による走行を行う。
この場合、predict 結果の、yのプロットを使って、cmd_vel でなぞる必要がある。

3. モデル学習
1) 使うモデルは、とりあえず改造がかんたんそうな、
TensorFlow 2.10.0 RNN - LSTM による、Speech Recognition
を、試してみるか?

2) Keras ASR with CTC を試す。
Automatic Speech Recognition using CTC

3) Keras V3 Automatic Speech Recognition with Transformer を試す。
Automatic Speech Recognition with Transformer
やっぱり、こちらが良いのか?

4) Keras V2 Automatic Speech Recognition with Transformer をベースにして、DataProvider : mltu の改造版を使った、
asr_with_transformer_mltu にする。
こちらは、Keras V3 で動くようにしています。
model も、Keras V3 Automatic Speech Recognition with Transformer と同じです。

DataProvider : mltu の改造版 で散々いじったので、改造ができそう。

実際の学習用を、github に上げました。
opp_with_transformer_mltu

i) 学習。
$ python train_transformer_opp_mltu.py

ii) model の Freeze.
$ python test-model-freeze.py

iii) Convert a.model_frozen.pb to ONNX
$ python -m tf2onnx.convert --input ./Models/test_opp/a.model_frozen.pb --output a.model.onnx --outputs Identity:0 --inputs source:0

a.model.onnx ができる。

iv) Predict.
$ python inferencModel.py
a.model.onnx を使う。

train loss > 0.7 ですが、一応、画像を取り込んで、コースをプロットできます。
注) 最初の1件目が、めちゃくちゃ時間がかかるぞね。気長にまっとうせ。2件目からは、スムーズにPredictできます。
注2) ONNX にしたら、早くなった。

4. 学習画像(コース画像)の作成。
学習画像は、Auto Mower でロボットを実際に走行させながら、今回の、ML Planner が必要とされるタイミングで、保存させる。

i) global costmap(static_layer + obostacle_layer + inflation_layer) を再度、上下逆にした cv::Mat を用いて、
注) inflation layer が入っているので、その部分を少しのこして障害物部分を削る。
目安は、保存された画像に、gimp で、ロボットの走行コースの線引きをする際に、障害物のすぐ隣に線を引いても、ロボットがぶつからない程度。
ii) ロボットのStart 位置を中心として、Start - End の直線が、+x軸と平行になるように、cv::Mat を回転させる。
iii) 回転させた cv::Mat 上で、
width: Start -> +x軸上の、End 直線距離( y=0)
height: コース幅
の矩形を抽出する。
iii) 必要なサイズに、拡大して、 jpg ファイルで保存する。
例) コース画像 のファイル名
n.jpg
n: 1 - 999

注) この部分は、もう作ったぞね。 by nishi 2024.10.8

5. 教師 class データ(コースライン画像)の作成。
i) 4. で作った画像を、gimp で読み込んで、元画像の上に layer を追加して、そのレイヤー上に、ロボットの走行ラインを、gimp の鉛筆かなにかで、線引きする(コースライン)。
注) 障害物がなにも無い場所は、 Y軸の真ん中に線を引く。障害物で通れないところは、線を引かない。
Y軸の端も、ロボット radius より内側を使う。障害物で、ロボット radiusより外側しか空いていないところは、障害物で通れない所になるので、引かない。

元画像のレイヤーを非表示にして、course line 画像として、別名で保存する。
例) コースライン画像のファイル名
n-l.jpg
n: 1 - 999

ii) c++ または、 python で、course line 画像上の line を x軸の一定間隔でスライスして、y軸の値を、text ファイル(コース クラス テキスト)に保存する。
注) course line が無いところは、none または、 -1 などにする。
注2) Y軸で、端から、 ロボット radius より内側のみ使う。ロボット radius より外側は、 none または、 -1 などにする。

class ファイル (コース クラス テキスト) は、コースライン画像毎につくる。
ファイル名: n-l.yaml

レコードのフォーマット例。
コース画像ファイル名 , yの個数 , x のスライス間隔[dot] , y0[dot], y1[dot], y2[dot], ...
注) y0 .. yn は、
0 <= rY <= 47+1 となる。
注) +1 は、 center line 分のクラス。

変換は、cpp プログラムを用意する。
cource_class_gen.cpp

6. model 学習でのデータ入力。
学習時のデータは、4. の画像ファイル と 5. の text ファイルを用いて行う。
4. の画像ファイルの長さ(col)が、model の input の length に足りないときは、後ろに、padding を行う。
4. の画像ファイルの高さ(row)が、model の input の width に足りないときは、上下に padding を行う。
注) 変換テーブル(Vocab) は、前もって用意する。
3段階になるか?
class id -> image-y[dot] -> tf-y[M]

まは、めんどくさい。

とりあえず、Auto Mower を、 Gazebo で走らせて、コース画像ファイルが、39 個できたので、
コース画像ファイル から、 gimp で、コースライン画像を作って、
それを使って、コース クラス テキスト に変換する、cpp を使って、 n-l.yaml も作ったので
Traininng させてみた。
transformer_opp_mltu.py

200 epoch 学習させて、
loss: 0.7154
val_loss: 0.8575
になったので、一応学習できているのだろうか?学習データを一気に増やさないといかん。
しかし、これが一番難儀じゃ。

ある程度、できたら、github にでもアップロードしますぞね。
学習させる、Python Scripts は、できているが、データつくりがまだまだじゃ。
さらには、これを使って、実際のコース計画は、まだじゃ。

7. モデルの問題点。
このモデルの問題点は、1 つの x点上で、y は、1 個しか出てこないこと。1つの x 上の y軸上を移動するコースは、プロットすることができない。
ここを、プロットしたければ、この 地点を、 start - stop とする矩形画像を使って、model を実行すれば、
y軸上の移動コースが、 x軸として算出できる。

実際の運用としては、最初のコース予測で出てきた、y のプロット点の値が、急に離れた場合は、Y軸上のコースを走行していると判断できるので、
上記の処理する。で、なんとか解決できそう。

ただし、このモデルは、ThetaStarPlanner の経路プランの一部補正用として使用する事がよさそうだ。

今は、ただひたすら画像を増やしながら、学習させているが、この分だと、いつ終わるのか?
気が遠くなりそうじゃ。

loss=0.7 を切る事ができないでいる。
もしかしたら、これが限界かもしれない。
測定距離 20[M] -> 15[M]
15/0.025 = 600[dot] に小さくして学習させてみる。

学習データ、1097 個用意して、学習させたけれども、一向に val=0.7 を切らない。
1000個くらいは、必要か?
業を煮やしたので、Speech to Text LSTM のモデルで試してみる。
ROS2 自作 Turtlebot3 による 草刈りロボット開発。#9 LSTM で経路計画をする。

8. ONNX に変換。
Frozen Graph TensorFlow 2.x に、ONNX への変換方法があったので、変換してみた。


一応、変換はできたぞね。実行もできました。ONNX 版だと軽いみたい。
これなら、OrangePi 5 でも実行できそう。
もっと、学習データを増やして、精度が上がれば、つかえるかもしれんぞね。

参考ページ。

1) 機械学習を活用した経路計画技術

2) 機械学習に基づくロボットの経路計画
注) これの例題だと、僕の方の手法でもできそうだが。
ただし、model の実行速度によると思うが?

3) Achieving SoTA In Path Prediction With Transformer! MmTransformer For Multimodal And Diverse Path Prediction.
いかん、こちらに、すでにおなじようなものがあったぞね。残念。

4) ロボットを根本から変えるLLM技術「Transformer」の威力

5) Hugging Face Transformers

6) 経路計画基礎の基礎〜ダイクストラ法

7) 指定経路を追従する移動ロボットのための障害物回避走行アルゴリズム

8) MultiHeadAttention
Transformer で使う、Self-Attemtion用の layer みたい。

このブログ記事について

このページは、おんちゃんが2024年9月30日 13:17に書いたブログ記事です。

ひとつ前のブログ記事は「ROS2 自作 Turtlebot3 による 草刈りロボット開発。#7 障害物からの脱出に機械学習を使う。」です。

次のブログ記事は「ROS2 自作 Turtlebot3 による 草刈りロボット開発。#9 LSTM で経路計画をする。」です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。

カテゴリ

ウェブページ

サイトナビ