見出し画像

ROS2 × Docker で Fast DDS を UDPv4 のみにする理由

「ROS2 × Docker」で「Fast DDS」を「UDPv4 のみ」にする理由をまとめました。


1. はじめに

「ROS2」を「Docker」内で動かしていると、「ノードが見えない」「Topic が届かない」といった通信トラブルに遭遇することがあります。その対策としてよく紹介されるのが Fast DDS を UDPv4 のみにする設定です。

この記事では、その理由を DDS の通信トランスポートの仕組みから整理します。

2. DDS の通信トランスポート

「Fast DDS」(ROS2 の RMW 実装の一つ)は、通信手段を「Transport」という単位で扱います。

代表的なものは次の 3 種類です。

3. Fast DDS のデフォルト動作

Fast DDS は通常、次のように通信方法を自動選択します。

つまりデフォルトでは「SHM + UDP」が有効になっています。

これはパフォーマンス面では理想的で、

・同一マシン → SHM(高速)
・別マシン → UDP(ネットワーク通信)

という最適な経路が自動的に選ばれます。

4. Docker で問題が起きる理由

4-1. 実際に起きていること

Dockerでは、この自動選択の仕組みがうまく機能しない場合があります。ポイントは 「SHM」(Shared Memory)の扱いです。

Dockerの標準設定では「/dev/shm」が コンテナごとに分離されています。つまり、「Container A」と「Container B」が同じホスト上に存在していても 共有メモリを直接共有できません

「Fast DDS」は、同一ホスト内のノードを検出すると、「共有メモリが使えるはず」と判断して SHM 通信を優先しようとします

しかし Dockerコンテナ間で「/dev/shm」が共有されていない場合、

・共有メモリセグメントの作成
・共有メモリのオープン

などが正常に行えず、メッセージの受け渡しに失敗することがあります。

結果として次のような現象が発生します。

・node が見えない
・topic が表示されない
・message が届かない

4-2. SHM が使えない環境との不一致

ここで重要なのは、問題の本質が、「SHMが使えない環境なのに、Fast DDSがSHMを使おうとする不一致」にあるという点です。

補足として、「Fast DDS」は SHM が利用できないと判断した場合に UDP へフォールバック(切り替え)する仕組みを持っています。

しかし Docker のネットワーク構成によっては

・SHM が使えると誤認する
・判定に時間がかかる
・中途半端に接続される

といった状況が起き、通信がブラックホール化する場合があります。

そのため 最初から UDP のみを使うように固定することで、通信の安定性を高めることができます。

4-3. もう一つの理由 - マルチキャスト問題

Dockerでは「UDP マルチキャスト」の扱いも問題になることがあります。

「ROS2」のノード発見(Discovery)は UDP マルチキャストを利用しています。
しかし Dockerでは

・bridge ネットワーク
・docker0 インターフェース
・カスタムネットワーク

などが存在するため、

意図しないインターフェースでマルチキャストが流れることがあります。

これにより

・discovery が不安定になる
・別コンテナの通信が混線する

といった問題が発生する場合があります。

「UDPv4」を明示的に指定することで、通信経路をシンプルにし、不要なインターフェースを避ける効果も期待できます。

5. 対策

5-1. UDP のみにする

この問題を避けるために、「SHM」を無効化して「UDP」のみを使用する設定にします。

「Fast DDS」の XML 設定例です。

<?xml version="1.0" encoding="UTF-8" ?>
<profiles xmlns="http://www.eprosima.com/XMLSchemas/fastRTPS_Profiles">

    <transport_descriptors>
        <transport_descriptor>
            <transport_id>UdpTransport</transport_id>
            <type>UDPv4</type>
        </transport_descriptor>
    </transport_descriptors>

    <participant profile_name="udp_transport_profile" is_default_profile="true">
        <rtps>
            <userTransports>
                <transport_id>UdpTransport</transport_id>
            </userTransports>
            <useBuiltinTransports>false</useBuiltinTransports>
        </rtps>
    </participant>

</profiles>

この設定のポイントは次の 2 つです。

・builtin transport を無効化
これにより「Fast DDS」のデフォルトのTransport(SHM など)が無効化されます。

<useBuiltinTransports>false</useBuiltinTransports>

・UDPv4 を明示的に指定
userTransports に登録することで「UDPv4のみ」を利用する構成になります。

<type>UDPv4</type>

この XML を「ROS2」で利用するには、「Fast DDS」に設定ファイルの場所を教える必要があります。

環境変数を設定します。

export FASTRTPS_DEFAULT_PROFILES_FILE=/path/to/fastdds.xml

これにより、「ROS2」起動時に「Fast DDS」がこの設定を読み込みます。

※ ROS2 のディストリビューションや Fast DDS のバージョンによっては、
他の環境変数設定の影響を受ける場合があるため注意が必要です。

5-2. 別の解決方法(参考)

「UDP」のみにする以外にも、Docker 側の設定で SHM を共有する方法もあります。

例えば次のオプションです。

--ipc=host

これを付けるとコンテナが ホストの SHMを利用するようになります。

また

--shm-size

で共有メモリサイズを拡張する方法もあります。

ただしこの方法は

・セキュリティ分離が弱くなる
・コンテナ設計に依存する

ため、実運用ではUDPのみに固定する方法がシンプルで採用されることが多いです。

6. まとめ

Docker環境では

・Fast DDS が SHM を使おうとする
・Docker は SHM をコンテナごとに分離する

という 環境とミドルウェアの不一致が起きます。その結果、ROS2 の通信が失敗することがあります。

そのためトラブル回避として、Fast DDS を UDPv4 のみに固定する設定がよく利用されます。

【おまけ】 ROS2 × Docker を安定させるコツ

「ROS2」を「Docker」環境で安定させるために、次の組み合わせがよく使われます。

・Fast DDS の UDPのみ
・--network=host
・通信 NIC の固定

--network=host は、Docker コンテナがホストのネットワークをそのまま使う設定で、ROS2 の DDS discovery(UDP multicast)が Docker の bridge/NAT に邪魔されないようにするために使われます。

通信 NIC の固定とは、ROS2 / DDS が通信に使うネットワークインターフェース(例:eth0 や wlan0)を1つに指定することです。これにより、Wi-Fi・有線LAN・VPN・docker0 など複数のNICがある環境で 誤ったインターフェースに discovery や通信が流れるのを防げます。

これらを組み合わせることで、ROS2の通信トラブルを大幅に減らすことができます。



いいなと思ったら応援しよう!