はじめに
本記事では、ROS2を使用するうえで通信を効率化するためのFast DDS Discovery Serverの機能を使う方法とその所感について紹介します。
なお、Fast DDS Discovery Server自体の詳細な実装や説明を知りたい方については、公式Docsを参照してみてください。
Fast DDS Discovery Serverとは
ROS2では、分散して駆動しているクライアントシステム(ノード)がそれぞれ非同期で情報を探索しています。これにより、ROS1のようなマスター・スレーブ方式から脱却し、高速な通信を実現しているとされています。
ところが、ROS2において、システム全体で取り扱う情報量が増加すると、それぞれのクライアントシステムの探索効率が悪化しまいます。例えば、ロボットAとロボットBの複数台のロボットを使う際に、ロボットAに必要な自己位置推定の情報を収集しようとしたときに、ノード探索の対象にロボットBも含まれてしまうような状況が挙げられます。このような事態はロボットシステムとして非常にクリティカルで、全体の速度やパフォーマンスの低下につながりかねません。
そこで、Fast DDS Discovery Serverは、システム全体の情報を一括集約するサーバを構築することで、探索効率を向上させるシステムです。つまり、データ通信の方式としてはマスター・スレーブ的な形式をとりつつ、TCPのような厳密な情報の授受に関するプロトコルを持たない従来のROS2の良さを維持したような形式を実現しています。
公式のDocsによれば、このDiscovery Serverを用いることで、ネットワークのトラフィックを大幅に削減し、最新リリースのv2では、Discovery Serverを用いない場合に比べて、トラフィックを20分の1程度に押さえ込めているとのことです(逆に元の標準システム大丈夫?ってなります(笑))。
使い方
使い方は非常にシンプルです。
ROS2 Foxy以降であれば恐らくROS2本体をOSへ導入する際にFast DDSが入っているはずです。
試しに、ターミナルでfastdds
と打ってみましょう。
$ fastdds
usage: fastdds <command> [<command-args>]
Commands:
discovery Server-Client discovery auxiliary generator
shm Shared-memory commands
fastdds <command> [-h] shows command usage
positional arguments:
command Command to run
options:
-h, --help show this help message and exit
このような応答があれば、fast DDSがきちんと準備されていることになります。
Discovery Serverでは、サーバ側とクライアント側でそれぞれおまじないが必要になります。
サーバの準備
簡単です。必要なのは、サーバIDと自身のIPアドレスと使われていない適当なポート番号です。サーバIDは、サーバを識別するための番号で、筆者らはあまり気にしませんが、仕組み上同じIPで複数のサーバをバックアップ的に立てられることが関連しているのかと...。
ここでは、具体例として、サーバのIDが0番、IPアドレスが192.168.10.50
で、ポート番号が8000番の時のDiscovery Serverの立ち上げは以下のようになります。
$ fastdds discovery -i 0 -l 192.168.10.50 -p 8000
### Server is running ###
Participant Type: SERVER
Security: NO
Server ID: 0
Server GUID prefix: XX.XX.XX.XX.XX.XX.XX.XX.XX.XX.XX.XX
Server Addresses: UDPv4:[192.168.10.50]:8000
手続きは以上です。ROSを扱っておきながら、ros2 run
とかros2 launch
とかやらないことに対して不安になるかもしれませんが、DDS自体がROSのミドルウェアだということを思い出せば納得なはずです。
クライアントの準備
Discovery Serverが立ち上がっているターミナルとは別に新しくターミナルを立ち上げます。
そのうえで、以下のコマンドで環境変数を設定します。
$ export ROS_DISCOVERY_SERVER=192.168.10.50:8000
export
コマンドなので特に応答はありません。ただ、一行これをターミナルに入れるだけで準備完了です。
試しに、サーバが立ち上がっている状態から、2つのノード間できちんとトピック通信ができているか確認してみましょう。
クライアント用のターミナルを2つ用意したうえで、まず、一方のターミナルに対して以下のコマンドを打ちましょう。
$ export ROS_DISCOVERY_SERVER=192.168.10.50:8000
$ ros2 run demo_nodes_cpp talker
そして、もう一方のターミナルに対しては、以下のコマンドを打ちましょう。
$ export ROS_DISCOVERY_SERVER=192.168.10.50:8000
$ ros2 run demo_nodes_cpp listener
すると、うまく値のやりとりができていることが確認できるはずです。
このターミナルらは、そのままに次のステップで仕様や用途を確認していきます。
やりとりの確認
Fast DDS Discovery Serverでは、情報のやり取りの確認ができない(しづらい)という欠点(仕方のない仕様)があります。
先ほどの2つのターミナルのノードを実行した状態で、さらにもう一つのターミナルを立ち上げてros2 topic list
を実行してみます。
$ export ROS_DISCOVERY_SERVER=192.168.10.50:8000
$ ros2 topic list
/parameter_events
/rosout
本来流れているはずのトピックが表示されません。
これは、バグでもノードの不調でもなく、そういう仕様によるものです。おそらく、topic list
やtopic echo
はノードを全探索するような仕組みになっているのに対して、Discovery Serverを使うとそこで一括管理されており、要求しない限り、そのターミナルには情報が入り込まないようになっているのだと思います。
同じように、rqt_graph
も従来のようには機能しません、が、使用されているノードだけ表示することができます。
$ export ROS_DISCOVERY_SERVER=192.168.10.50:8000
$ rqt_graph
QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-ubuntu'
所感・注意事項
注意する点として、特定のターミナルでexport ROS_DISCOVERY_SERVER=(以下略)
をしてしまうと、永続的にDiscovery Serverへ繋がってしまいます。例えば、通常方式でデバッグが完了→Discovery Server方式で実装→なにかバグを発見→通常方式でトピックの流れを確認(topic list
,topic echo
,rqt_graph
)という事態が生じた場合、Discovery Serverを使用したターミナルプロセスはExitして別のターミナルで実行する必要があります。
この点に留意すると、各ノードの機能を単体でテストしたり、1台のロボットでのナビゲーションを確認したりしたうえで、システムの規模を大きくする際にやっと初めて使用する、あるいは、きちんと応答があるかどうかのフィードバックをログに表示するような実装を含めるのが効果的なのではないか、と筆者らは考えています。
また、Discovery Serverの効き目は非常に大きいものだと筆者は感じています。とくに、Navigation2で複数台のロボットを取り扱う際に、実行速度がわかりやすく速くなっている実感がありました。ぜひ、有効的に使ってみてください。
参考