ROSConJP 2021で発表したUnreal Engine4(UE4)用のROS2 client libraryであるrclUEについて、ご紹介します。rclUEを使うことで、UE4をROS2のシミュレータとして使用することができるようになります。
発表スライドはこちら
はじめに
ラピュタロボティクスではCloud robotics platform rapyuta.ioを提供しています。ロボットシミュレータとしてはGazeboを使用していて、Gazeboをクラウド上にdeployすることで、ROS1を用いたクラウド上のマルチロボットシミュレータを実現しています。
Gazeboを使ってクラウド上で複数ロボットのシミュレータを構築する際にいくつか課題がありました。
- ROS1は一台のロボット用に設計されているので、複数台でシミュレーションを行なう際にいくつかのハック(hack)が必要
- 複数のロボットをシミュレーションするためのGazeboのパフォーマンス/スケーラビリティの問題
- シミュレーションをスケールアップするためには、クラウド上に分散環境を構築する必要がありました。/clock topicをインターネット上でブロードキャストして同期をする方法は、最適とは言えない
- URDF/SDFを編集することは、ROSエンジニア以外には簡単ではないことも多い
より多くのロボットでのシミュレーションを実行し、また、ロボットの専門家以外でも構成を簡単に編集可能なシミュレーションを実現するため、Unreal Engine4(UE4)を利用することとし、UE4をROS2のシミュレータとして使うためのrclUEの開発をはじめました。
UE4はOSSのゲームエンジンであり、高品質な描画やリアルタイム物理シミュレーションなどの機能を有しています。rclUEはC++とUE4のビジュアルスクリプティングから使用でき、ROS開発者以外でも簡単に使用することができます。
Turtlebot3 を利用したデモは turtlebot examples to UE4 から利用できます。
Turtlebot3のデモレポジトリはrclUE plugin とRapyutaSimulationPluginsをサブモジュールとして内部に含んでいます。rclUE はROS2ノードなどをUE4から利用するための機能を含んでおり、RapyutaSimulationPluginsはlidarや差動二輪ロボットをシミュレートするための機能が含まれています。
Unreal Engineをロボットシミュレータとして使用する動機
Unreal Engine は Epic Gamesが開発しているオープンソースのゲームエンジンで、高機能なフォトリアリスティックなレンダリング機能などを有しています。UE4は多くの機能がありますが、ロボットのシミュレータとして使うと以下のようなことがメリットとして考えられます。
- 高機能なレンダリング機能をつかうことで、機械学習などに利用できる
- Blueprint visual scripting(BP) によって、比較的容易にシミュレーション環境やロボットを編集できる
- behaviour tree (BT) を使うことで、人間などのロボット以外の要素をシミュレーションに組み込める
- ネットワーク対戦ゲームなどで実績のある、インターネットを介した通信システムを複数ロボットのシミュレーションへの適用できる
- PhysX や Chaos physics engines を利用することで実時間より高速なシミュレーションの実行
rclUE の設計
Unreal Architecture
Unreal Engine のコア機能の 1 つに、C++で新しいオブジェクトを作成し、そのプロパティや関数をエディタに公開する機能です。これによりエディタのGUIからプロパティの変更、BPのビジュアルスクリプティングから関数呼び出しなどを行なうことができます。
Unreal のタイプ システムは、クラス内に他のクラスをメンバーとしてもたせることよりも、継承することで他クラスの機能を使うことと相性がいいように設計されっており、すべてのクラスが (最終的に) ベースの UObject クラスから派生することを必要とします。UObject は、Java オブジェクトと同様に管理されたメモリであり、Unreal にはこれらを処理するためのガベージ コレクターが組み込まれています。
配列やマップなどのデータ構造や、C++ の STL 内に存在する多くの機能の代わりに、Unreal で内蔵された同等の機能を使用することで、上記の機能をデータ構造にも適用できるようになります。
先行事例
ROSIntegration は、ROS1 と UE4 の間の通信を rosbridge で可能にする UE4 のプラグインです。CARLA は、自律走行研究用のシミュレータで、UE4 のフォークされたリポジトリをベースにしており、ROS(ROS2 を含む)と自身との間の通信を可能にする独自の ROS ブリッジを備えています。
AirSimは、ドローンや車輪付き車両向けに設計されたシミュレーションソフトウェアで、C++マルチロータークライアントライブラリとPDポジションコントローラの2つのノードで構成されるラッパーを介してROSと統合されています。
CARLA SimとAirSimは、Unreal Engineのレンダリング機能を利用して、自律走行に関連する機械学習タスクを実行します。
AirSimやCARLAで行われている統合とは対照的に、rclUEはシンプルでポータブルな設計になっています。このため、必要な ROS2 の機能を UE4 プラグイン (ROSIntegration と同様) に実装しています。これにより、さまざまな UE4 プロジェクトに簡単に組み込むことができ、コミュニティがより利用しやすくなります。
さらに、rclUEでは、ROS2要素をUE4のタイプにマッピングした(例:ROS2 NodeをUE4 Actor、ROS2 PublisherをUE4 Actor Component)。これにより、UE4のGUIやBlueprintによる拡張機能からパラメータの編集や関数呼び出しをすることができるよう構成した。
ラピュタロボティクスではrclUEによりROS 以外の開発者もROS2 ソフトウェアを活用できるようになることを目指しています。
rclUE Architecture
Unreal Engineの特殊なアーキテクチャを活かすためには、Unreal Engineの慣習に従う必要があります。そのため、C++ (rclcpp) ではなく、C (rcl, rclc) で書かれた ROS2 クライアントライブラリを選択することとしました。特に、rclcpp のクラスはシリアル化とガベージコレクションの動作に必要な UE4 のバージョンのベースクラスを継承したクラスを作るのに適していません。
以下の図は、rclUE レイヤーが全体のアーキテクチャにどのように適合するかを示しています。
以下では、ROS2 Node、Publisher、Subscriberの実装の詳細について説明します。他のコンポーネント(Service, Action)も同様に実装されています。
ROS2 Node
ROS2Node は、レベル(=UE4でのシミュレーションの環境のこと)に配置できるオブジェクトのベースクラスである UE4 Actor として実装されています。ROS2Nodeは、Publisher、Subscriber、Service client、Service server を内部で管理するように実装されています(そのため、rclcppのエクゼキュータに相当する機能が簡略化されています)。
ROS2 Publisher
ROS2PulisherはActorComponentとして実装されています。ActorComponentは、様々なタイプのActorに追加できる再利用可能な動作を定義するコンポーネントの基本クラスです。ActorComponentとして、Publisherを必要とするあらゆるActorに追加することができます。
ROS2 Subscriber
トピックの購読は、ROS2Node のメソッドとして実装され、UE4 のデリゲートを介してコールバック メソッドにバインドされます。トピックを購読したいアクターは、コールバック関数をROS2Nodeに登録します。
Examples
以下では実際にrclUEを利用した、publisehrとsubscriberのサンプルについて説明します。ROS2の機能はC++とBlueprintの両方から使用できるため、それぞれについて紹介します。
PubSub Example (Unreal C++)
上図のROS2NodeのActorでは、Actorそのものを初期化した後(Init())、ActorComponentのStringPublisherをNewObjectで初期化し、パラメータを設定、デリゲートのバインドを行っています。その後、ノードにパブリッシャーを追加し、初期化しています。
パブリッシャーの設定は、アクターがシーンに追加されたときや、実行ファイルがコンパイルされたときにのみ呼び出されるコンストラクタではなく、シミュレーションを開始するときに呼び出されるアクター用のメソッドである BeginPlay で行っていることに注意してください。BeginPlayで初期化することで、変数(発行頻度など)をエディタで設定でき、その変更がシミュレーションの実行時に反映されることです。一方、コンストラクタで初期化した場合は、エディタで変更した変数は、エディタを再起動しない限り、シミュレーションに反映されません。
サブスクリプションを追加するには、ノードが初期化された後、FSubscriptionCallback型のオブジェクトにコールバック関数をバインドし、AddSubscriptionを呼び出します。
この例では、シンプルにするためにパブリッシャーとサブスクライバーのノードを使用しましたが、実際の使用例では、これらの機能性を必要とするアクター(ロボットのアクターなど)に統合されるべきです。
PubSub Example (Blueprint)
ROS2 Publisher Nodeのセットアップ:ROS2Nodeアクタを初期化してから、ActorComponent Publisherを追加し、メッセージをパブリッシュするノードで初期化します。NodeとPublisherのパラメータ(ノード名、メッセージタイプ、トピック名、Publishする周期など)はDetailsパネルで設定することができます。上図の下側に表示されているのが、周期的に実行される関数です。
ROS2 Subscriber Nodeのセットアップ: ROS2Nodeアクターを初期化し、Callback関数をbindしています。上図の下側に表示されているのが、msgをsubsccribeした時に実行される関数です。
上記の方法以外でも同様の機能は実装可能です。
おわりに
rclUEについて紹介しました。今回紹介した内容を応用することで、ROS2からUE4内のロボットを制御することができます。
turtlebot3をつかった例についてはこちらのレポジトリのREADMEに従うことで試すことができます。
rclUEはまだ初期段階であり、いくつかのバグや不足している機能があります。バグレポートやフィードバックをお待ちしています。ラピュタロボティクスではコミュニティと協力してrclUEをより便利なものにしていきたいと考えています。
このプロジェクトは東京都の未来を拓くイノベーションTOKYOプロジェクトの補助金を受けて行われました。