はじめに
この記事は、ROBOTIS公式のTurtleBot3 Quick Startチュートリアルに沿って遠隔操作環境を構築する際に、ROS 2の通信で詰まった点と、その解決策をまとめたものです。同じような問題に直面している方の助けになれば幸いです。
対象読者
- TurtleBot3とROS 2を使い始めたばかりの方
- ROS 2のマルチキャスト通信がうまくいかず、ノード間の通信に問題を抱えている方
- Dockerコンテナ内でROS 2環境を構築し、外部デバイスとの通信で詰まっている方
tldr
-
問題: Wi-Fiルーターがマルチキャスト通信をブロックするため、ROS 2ノードが互いを認識できない。
- 解決策: Remote PCでFast DDS Discovery Serverを起動し、全ノードをユニキャストで接続させる。
-
Docker利用時: コンテナは
--network=hostオプション付きで起動し、ホストのネットワークを直接利用する。 - 前提: 全デバイス(Remote PC, TurtleBot3)は、あらかじめ同じWi-Fiネットワークに接続しておく。
- 推奨: 通信を安定させるため、各デバイスのIPアドレスを固定する。
目次
- 詰まった所: ルーターによるマルチキャスト通信のブロック
- 解決策: Fast DDS Discovery Serverの導入
- 補足1: なぜルーターはマルチキャストをブロックするのか?
- 補足2: Docker利用時の注意点 --network=host
- 補足3: IPアドレスの固定化
詰まった所: ルーターによるマルチキャスト通信のブロック
両方のデバイスを同じWi-Fiネットワークに接続しても、依然としてROS 2の通信は確立しませんでした。ros2 topic listを実行しても、お互いのトピックが見えない状態です。
tcpdumpでパケットを監視したところ、Remote PCはマルチキャストアドレス (239.255.0.1) に向けてパケットを送信しているものの、TurtleBot3側ではそのパケットを受信できていませんでした。これは、Wi-Fiルーターがクライアント間のマルチキャスト通信を意図的にブロックしていることが原因でした。
本来であれば、ルーターの管理画面から「APアイソレーション」や「IGMPスヌーピング」などの設定を変更すればマルチキャスト通信が可能になるはずですが、Fast DDS Discovery Server を使用して通信を行いました。
解決策: Fast DDS Discovery Serverの導入
この問題を回避するため、ROS 2の標準機能であるFast DDS Discovery Serverを利用しました。これは、ノード発見の仕組みをマルチキャストから、特定のサーバーを介したユニキャスト通信に切り替えるものです。
-
サーバーをRemote PCで起動する
- Discovery Serverを1台のPC(今回はRemote PC)で起動します。このサーバーが、ネットワーク内の全ノードの情報を集約する中央ハブとなります。
-
クライアント(全ノード)がサーバーに接続する
- 他のすべてのノード(Remote PC上の他のターミナル、TurtleBot3上のノード)は、クライアントとしてこのサーバーに接続しにいきます。
これにより、ルーターに依存しない安定した通信環境を構築できます。
Fast DDS Discovery Serverの導入手順
1. サーバーの起動 (Remote PC)
まず、サーバー役となるPCで以下のコマンドを実行し、Discovery Serverを起動します。
--server-id 0 はサーバーのIDを指定するもので、0番のサーバーとして起動します。
fastdds discovery --server-id 0
サーバーが 127.0.0.1:11811 で待機状態になります。
2. クライアントの設定 (すべてのノード)
次に、サーバーに接続させたいすべてのターミナル(Remote PC、TurtleBot3の両方)で、以下の環境変数を設定します。192.168.68.49 の部分は、サーバーを起動しているPCのIPアドレスに置き換えてください。
export ROS_DISCOVERY_SERVER="192.168.68.49:11811"
この設定により、ROS 2ノードはマルチキャストを使わず、指定されたIPアドレスのサーバーに直接自身の情報を登録しにいきます。
この状態で ros2 launch turtlebot3_bringup robot.launch.py や ros2 run turtlebot3_teleop teleop_keyboard を実行することで、無事に通信が確立し、遠隔操作が可能になりました。
補足1: なぜルーターはマルチキャストをブロックするのか?
ルーターがデフォルトでマルチキャスト通信をブロック(転送しない)する主な理由は、ネットワークの安定性と効率性を保つためです。主に2つの技術的な背景があります。
-
不必要なフラッディングの防止
ルーターは、ブロードキャストがネットワーク全体に広がるのを防ぐのと同様に、マルチキャストも無制御に転送しません。もし転送してしまうと、その通信を必要としないセグメントにまで不要なトラフィックが溢れ(フラッディング)、帯域の浪費や無関係なデバイスへの負荷につながるためです。 -
マルチキャスト特有の転送処理が必要
ユニキャスト(1対1)通信とは異なり、マルチキャストを正しく転送するには、「どの先に受信者がいるか」をルーターが知る必要があります。これにはIGMP(ホストがグループ参加を宣言するプロトコル)やPIM(ルーター間で経路を作るプロトコル)といった特別な設定が必要です。これらの設定はデフォルトで無効になっているため、ルーターは「転送先が不明なパケット」としてマルチキャストを破棄します。
補足2: Docker利用時の注意点 --network=host
docker runでコンテナを通常起動すると、コンテナはホストOSとは別の**仮想ネットワークスタック**を持ち、独自のIPアドレス(例:172.17.0.2)が割り当てられます。このため、コンテナ内のプロセスはホストのIPアドレスを直接使用できません。ポートマッピング (-p`) をしても、DDSのような複雑な通信ではうまくいかないことが多々あります。
解決策:
Dockerコンテナを --network=host オプション付きで起動します。
# コンテナをホストネットワークモードで起動
sudo docker run -it -d --name my_ros_container --network=host my_ros_image:latest
このオプションを付けると、コンテナは独立したネットワークスタックを持たず、ホストOSのネットワーク名前空間を共有します。つまり、コンテナはホストと全く同じIPアドレス (192.168.68.49) を持ち、ポートも共有するため、ネットワークに関する問題の大部分を回避できます。
補足3: IPアドレスの固定化
DHCP環境では、デバイスを再起動した際にIPアドレスが変わってしまう可能性があります。ROS_DISCOVERY_SERVERで指定するIPアドレスや、各種設定ファイルに記述したIPアドレスが変わると、その都度設定を修正する必要があるため、ルーターのDHCP設定や各デバイスのネットワーク設定で、Remote PCとTurtleBot3のIPアドレスを固定しておくことを推奨します。
補足4: 前提としてネットワークセグメントを合わせる
ROS 2のノード発見は、デフォルトでマルチキャストに依存しています。異なるネットワークセグメントにデバイスが存在すると、マルチキャストパケットが届かず通信できません。基本的な前提として、すべてのデバイスを同じWi-Fiに接続するなど、同一のネットワークセグメント上で通信させることが重要です。
参考