ROS2×KV260でリアルタイム解析してみた

ROS2×KV260でリアルタイム解析してみた

ISPは長らく組み込みやロボット分野で技術的なノウハウを蓄積してきました。今回はデモ用のロボットを開発したのでご紹介します。

テーマとしては,FPGAを使ってエッジAIを備えるロボットをつくり,CARETというROS2の計測ツールを使ってリアルタイム性を検証しよう!といった感じです。

どのようなロボット?

製作したロボットのハードウェア構成です。

カメラなどを搭載したエッジ端末(KV260)と,マイコン(Arduino)や距離センサを搭載したロボットを合体させて,AI処理が出来るロボットを製作しました。KV260については後述します。

制作したロボットのハードウェア構成

ちなみに,モバイルバッテリーとWIFIアダプタも取り付けているので,完全ワイヤレス化が実現されています。

技術概要

ROS2

ROS 2(Robot Operating System 2)は,ロボットプログラミングのためのオープンソースのソフトウェアフレームワークです。 ROS 2は,ROSの前バージョンであるROS 1を発展させ,改善したもので,「リアルタイム対応」や「複数台ロボットの制御」など新しい要件に対応し,ロボットシステムの設計と開発をサポートするために設計されました。

今回のノード構成はこちらです。

ノードの構成

カメラノードで画像を取得し,AI処理ノードで画像認識を行います。 その際,FPGAに処理をオフロードすることで高速でAIの推論が出来るようになります。 この推論結果と距離情報を元に,動作決定ノードでロボットの動作を決定し,シリアル通信ノードを介してArduinoに命令を送りロボットが動作します。

KV260/Vitis-AI

KV260はAMD(Xilinx)が開発したFPGAを備えたAIソリューション用評価ボードです。 FPGAはソフトウェア的に書き換え可能な論理回路で,高速に並列処理が可能となっており,GPUを使った並列処理と比べて消費電力などの面で優れています。また,FPGA自体はただの論理回路なので処理時間に揺れなどはありません。

KV260のOSはpetalinux推奨ですが,今回,ROS2を使う関係上Ubuntuを使っています。 以下に開発環境をまとめます。

  • Ubuntu-22.04 LTS
  • ROS2-humble
  • Vitis-AI v2.5

AI処理は物体検出モデルであるYOLOv3を使用しました。 カメラで取得した画像情報をKV260上でFPGAに処理をオフロードし,検出された物体のバウンディングボックス情報を取得することが出来ます。

YOLOv3(物体検出モデル)

本来であれば,画像認識アプリケーションの実装,FPGAにオフロードするための特別な処理やディープラーニング用の回路(DPU)を作成する必要があるのですが,今回はそれらが予め用意されているVitis-AIというライブラリを使用して実装しました。

Vitis-AIはXilinxが提供するFPGAボード用のライブラリで,様々なAI処理を実現することが出来ます。AIモデルのラインナップはかなり豊富で最新版(v3.5)だとYOLOはv8までありました。

また,Model-zooという学習済みモデルも提供しているので,自前で学習を行う必要なくAIアプリケーションを使用することが出来ます。

バウンディングボックス検出例

YOLOv3ではこのように,物体を検出してバウンディングボックスを返却してくれます。 今回使ったKV260では約14FPSで動作しました。KV260自体が250ドルという値段を考えると,十分早いのではないでしょうか?

CARET

ROS2はROSと比べてリアルタイム性を謳ってはいるが,本当にリアルタイムなのか? 

そんなときに,エンドツーエンドでノード間やノード内の処理速度を計測できるツールが,CARETというオープンソースのソフトウェアです。 CARETはROS2専用の計測ツールで,2019年から株式会社ティアフォー、埼玉大学 安積研究室、東京大学 加藤研究室(敬称略)と協業し開発を行っています。
ROSCon2022に登壇

CARET イメージ

CARETはコールバックなどを起点として,パッケージのビルド時にトレースポイントを埋め込むことで計測することを可能にしますが,凄いのは元のコードを一切変更することなくそれが行える点です。 具体的にはワークスペースのビルド前にCARETの環境変数をsourceして環境変数を設定してあげることで計測を行うことが出来るようになります。計測後はjupyter-labからpythonのコードを走らせることで上記の画像のようにリアルタイム性の可視化画像を取得できます。

動かしてみた

完成したロボットはこんな感じです。足りないパーツは3Dプリンタで自作しています。

ロボット

追従動作

ロボットの動作内容としては「追従動作」で,「りんご」のラベルの物体を検出したら追いかける仕様になっています。ロボットからは下画像のように周りが見えており,バウンディングボックスを追跡しながら,距離によってモータ速度をPID制御により変更し,常に同じ距離を保つように動作します。

追従動作イメージ

協調動作

さらにロボットをもう1台作り,このように先頭のロボットに追従しながら進むロボットになりました。両ロボットにROS2を搭載することにより,ロボット同士は同じネットワーク上であれば互いに通信することが出来ます。

協調動作例

ROSでも設定次第ではホスト間の通信が出来ますが,ROS2ではROSマスタの存在がなくなったことで単一障害点がなくなり,正式に複数ホスト対応となりました。

リアルタイム性解析

最後にCARETを使って,追従動作ロボットのリアルタイム性の検証を行いました。 リアルタイム性とは,時間的制約を守れること・予測できることを指していて,今回使用しているOSはリアルタイム OS でないのでリアルタイム保証は難しいのですが、可能な限り計測して検証したいと考えています。ついでに性能を改善する余地があれば改善していきたいと思っていました。

測定1回目

測定1回目

CARETでは,このようにビジュアライゼーションすることで,一目でどのような性能なのかを知ることができます。横軸は時間(s)で縦軸はノードやトピックを表していて,上から順番にカメラノード,AI処理ノード,動作決定ノード,シリアル通信ノードへ情報が流れています。

見るとカメラノードが5~6FPSでした。 カメラ自体はスペック上30FPSで動作するはずなのでおかしいことが分かります。

原因を調べたところ,取得する画像のサイズが1980×1080になっていたことが分かりました。 どうせ画像処理のところで400×400くらいにリサイズされるので,640×480に変更して再計測しました。

測定2回目

測定2回目

上のたくさん線が出ているところがカメラノードで,無事30FPSで動作するようになりました。 しかし318.46msと,とても時間がかかっている箇所があります。これはカメラノードからAI処理ノードへの画像データの受け渡しの部分に当たります。

結論から言うと,画像の受け渡しに300ms以上時間がかかっているのはQOSの設定でした。QOSとはノード同士が通信するときにデータを保持するためのキューのようなものです。このキューのサイズを大きくし過ぎていたため,300ms前のデータが呼ばれているといった実装になっていました。

これを修正したのが次のようになります。

測定3回目

測定3回目
  • latency : 125ms
  • FPS : 13~14FPS

最終的な結果は,このようになりました。 カメラノードは30fpsで動作しつつ,画像情報の受け渡しにも17.7msまで抑えています。AI処理ノードの処理時間は75msで一番時間がかかっていますが,これは期待通りの速度です。全体として処理遅延は125msほどでFPSは13~14FPSとなっています。

本来,ロボットが期待通りの動作をしていない場合,問題の切り分けが難しく,デバッグには労力がかかります。今回エンドツーエンドでデータの流れを可視化することで,問題箇所がハッキリとわかり,短時間で性能改善をすることが出来ました。

また,処理時間の揺れについては以下のようになりました。 minが処理遅延の最小値,maxが最大値でavgが平均です。

CARET測定結果
  • /camera_sender_pub_node:カメラノード
  • /yolov3_img:AI処理ノード
  • /following:動作決定ノード
  • /subscribe_transmitter:シリアル通信ノード

まとめ

このように,本来子供の学習用だったロボットキットはAIやFPGAを積んだ高性能ロボットに魔改造されました。 一番の詰まりどころはKV260/FPGA関連ではないでしょうか。 まだ世に出てから日が浅いのでドキュメントも少なく,ChatGPT3.5も答えてくれませんでした。 自分としてもガンガン開発したというよりは,できるかどうかの試行錯誤を繰り返していった感じです。組み込みは根気が大事だと実感しました。以上。