WSL2 のネットワークモードを mirrored(ミラーモード)にして ROS 2(CycloneDDS)を動かすと、通信の切断やノードが見つからない接続不良が起きやすく、nat(NAT モード)に戻すと解消することがあります。
この挙動の理由と、ミラーモードのまま安定させる設定をまとめます。
前提: 以下の対策は すべての ROS 2 ノードが同一の WSL2 インスタンス内で完結している 構成を想定しています。Windows 側や LAN 上の別マシンと DDS 通信する場合は、
lo(ループバック)指定では通信できません。その場合は使用する実インタフェースを指定してください。
ミラーモードでは Windows と WSL2 がネットワークスタックを共有します。これが CycloneDDS の自動アドレス検出(ディスカバリ)と噛み合わず、接続不良につながります。主に次の 3 点が関係します。
ROS 2(DDS)のノード探索は主に UDP マルチキャストを使います。
- NAT モード: Windows と WSL2 は別の IP 空間に分離されており、パケットの境界が明確です。
- ミラーモード: Windows 側のインタフェースが WSL2 側からもそのまま見えます。このため、WSL2 内の CycloneDDS が送ったマルチキャストパケットを自分自身が再受信するループが起きやすくなります。これがディスカバリの輻輳やパケットドロップを招きます。
CycloneDDS は起動時に利用可能なインタフェースをスキャンし、通信に使う IP を自動で決めます。
- ミラーモードでは、Windows 側の仮想アダプタ(Wi-Fi、Bluetooth、VPN、他 VM の仮想スイッチなど)が WSL2 から見えます。
- その結果、通信が通らない不適切なインタフェースを優先バインドしてしまい、通信が成立しないことがあります。
ミラーモードでは、WSL2 内のプロセスがリスンするポートが Windows 側でも同じポートとして露出します。Windows ファイアウォールが DDS の使う UDP(7400 番台付近)のマルチキャスト通信を制限し、パケットのブロックや間引きの原因になることがあります。
Windows 側ツールとの兼ね合いで mirrored を維持したい場合は、CycloneDDS にどのインタフェースで通信するかを明示する設定ファイル(XML) を用意すると安定します。
WSL2 のホームディレクトリ直下などに、次の設定ファイルを作成します。
<?xml version="1.0" encoding="UTF-8" ?>
<CycloneDDS xmlns="https://cdds.io/config"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://cdds.io/config https://raw.githubusercontent.com/eclipse-cyclonedds/cyclonedds/master/src/core/config/src/cyclonedds.xsd">
<Domain id="any">
<General>
<Interfaces>
<NetworkInterface name="lo"/>
</Interfaces>
<AllowMulticast>spdp</AllowMulticast>
</General>
</Domain>
</CycloneDDS>補足:
- 上記は新しめの CycloneDDS(0.10 系以降)の
<Interfaces>形式です。古いバージョンでは<NetworkInterfaceAddress>lo</NetworkInterfaceAddress>を使います。利用バージョンに合わせてください。AllowMulticastをspdpにすると、ディスカバリ(SPDP)だけマルチキャストを使い、データはユニキャストになります。true(全部マルチキャスト)でも動きますが、loopback 運用ではspdpが無難です。loのみで運用する場合、<Peers>でユニキャストのピアを直接指定する手もあります。
ここが見落としやすい点です。Linux の lo は既定で MULTICAST フラグが立っていないことが多く、その状態だと SPDP(参加者発見)が流れず、lo を指定しても繋がりません。次で確認・有効化します。
ip link show lo # <LOOPBACK,...> に MULTICAST が含まれるか確認
sudo ip link set lo multicast on # 含まれていなければ有効化この設定は再起動で消えるため、恒久化するには systemd サービスなどで起動時に再実行してください。
作成した設定ファイルを CycloneDDS に読み込ませるため、~/.bashrc(または ~/.zshrc)の末尾に追記します。
export CYCLONEDDS_URI=file://$HOME/cyclonedds.xml
~/cyclonedds.xmlのような bare path も新しめのバージョンなら通りますが、~はクォートで展開されないなどの落とし穴があるため、file://形式が確実です。
追記後、ターミナルを再起動するか source ~/.bashrc を実行して反映させます。
この設定で、CycloneDDS はミラーモードで露出した余計なインタフェースやエコーループを避け、指定したインタフェース(上記例では lo)だけで通信します。全ノードが WSL2 内で完結する構成なら、NAT モード時と同等の安定性が得られます。
lo は同一 WSL2 インスタンス内の通信に限定されるため、Windows 上の ROS 2 ノードや LAN 上の別マシンとも DDS 通信したい場合は使えません。その場合は lo ではなく、外部と疎通する実インタフェース名を指定します。
インタフェース名は ip addr(または ip link)で確認できます。WSL2 では eth0 であることが多いですが、環境によって異なるので実際の名前を使ってください。
<?xml version="1.0" encoding="UTF-8" ?>
<CycloneDDS xmlns="https://cdds.io/config"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://cdds.io/config https://raw.githubusercontent.com/eclipse-cyclonedds/cyclonedds/master/src/core/config/src/cyclonedds.xsd">
<Domain id="any">
<General>
<Interfaces>
<NetworkInterface name="eth0"/>
</Interfaces>
<AllowMulticast>true</AllowMulticast>
</General>
</Domain>
</CycloneDDS>補足:
- 実インタフェースを指定してもマルチキャストが不安定なときは、
AllowMulticastを無効化し、通信相手の IP を<Peers>に直接列挙してユニキャストで疎通させる方が確実です。- 通信相手が Windows ホストの場合、Windows Defender ファイアウォールで DDS が使う UDP(7400 番台付近)を許可する必要があります。
<!-- マルチキャストを使わずユニキャストのピアを直接指定する例 -->
<Domain id="any">
<General>
<Interfaces>
<NetworkInterface name="eth0"/>
</Interfaces>
<AllowMulticast>false</AllowMulticast>
</General>
<Discovery>
<Peers>
<Peer Address="192.168.0.10"/> <!-- 通信相手の IP -->
</Peers>
</Discovery>
</Domain>上の例は
<Domain>からの断片です。単独のファイルとして使う場合は、ステップ 1 と同じく XML 宣言と<CycloneDDS>ルート要素で囲んでください。実インタフェース指定では loopback の MULTICAST フラグ(ステップ 2)は不要です。
ここまでは CycloneDDS の話でした。RMW 実装によって事情が変わります。結論を先に言うと、Fast DDS は Cyclone と同じ問題が起きるので同種の対策が要りますが、Zenoh はアーキテクチャ的にこの問題をほぼ踏みません。
| RMW | ミラーモードでの問題 | 対策 |
|---|---|---|
| CycloneDDS | 起きる(マルチキャスト依存) | cyclonedds.xml で <Interfaces> 指定、または <Peers> |
| Fast DDS | 起きる(同上) | XML の interfaceWhiteList 指定、または Discovery Server |
| Zenoh | ほぼ起きない(既定でマルチキャスト無効・TCP ルータ方式) | 既定のまま。外部通信は connect/endpoints を明示。マルチキャスト scouting はオンにしない |
Fast DDS も RTPS の UDP マルチキャストでディスカバリするため、エコーループや余計なインタフェースへのバインドという根は CycloneDDS と同じです。対策の考え方も同じで「使うインタフェースを明示する」ですが、設定は XML プロファイルの interfaceWhiteList で行います。
~/fastdds_profiles.xml(WSL2 内で完結するなら lo、外部通信するなら eth0 などに変更):
<?xml version="1.0" encoding="UTF-8" ?>
<profiles xmlns="http://www.eprosima.com">
<transport_descriptors>
<transport_descriptor>
<transport_id>custom_udp_lo</transport_id>
<type>UDPv4</type>
<interfaceWhiteList>
<interface>lo</interface> <!-- IP で指定するなら <address>127.0.0.1</address> -->
</interfaceWhiteList>
</transport_descriptor>
</transport_descriptors>
<participant profile_name="default_participant" is_default_profile="true">
<rtps>
<useBuiltinTransports>false</useBuiltinTransports>
<userTransports>
<transport_id>custom_udp_lo</transport_id>
</userTransports>
</rtps>
</participant>
</profiles>export RMW_IMPLEMENTATION=rmw_fastrtps_cpp
export FASTDDS_DEFAULT_PROFILES_FILE=~/fastdds_profiles.xml
# 古い Fast DDS では FASTRTPS_DEFAULT_PROFILES_FILE補足:
is_default_profile="true"を付けると全 ROS 2 参加者に自動適用され、プロファイル名の指定が要りません。- CycloneDDS と同じく、
lo限定で運用するなら loopback の MULTICAST フラグ有効化(sudo ip link set lo multicast on)が要ります。 useBuiltinTransportsをfalseにすると共有メモリ(SHM)転送も無効になり、同一ホスト内でも UDP 経由になります。localhost 用途で SHM の速度を活かしたい場合は、SHM 用のtransport_descriptorも併記して両方を有効にしてください。- それでもマルチキャストが不安定なら、マルチキャストを使わず Discovery Server(
ROS_DISCOVERY_SERVER環境変数)に切り替える手もあります。CycloneDDS の<Peers>ユニキャスト指定に相当する発想です。
Zenoh は仕組みが大きく違います。UDP マルチキャスト scouting が既定で無効で、各ノードは TCP で Zenoh ルータ(zenohd)に接続し、ルータ経由の gossip でディスカバリします。マルチキャストに依存しない設計だと公式にも明記されており、ミラーモードのエコーループ問題は素の状態ではまず起きません。
- WSL2 内で完結する場合: ホストごとにルータ(
ros2 run rmw_zenoh_cpp rmw_zenohd)を 1 つ立て、ノードを localhost のルータに繋ぐ標準構成のまま動きます。特別な設定は不要です。 - Windows 側や LAN の別マシンと通信する場合: マルチキャストに頼らず、セッション設定(JSON5)の
connect/endpointsに相手ルータのtcp/<IP>:7447を列挙します(ZENOH_SESSION_CONFIG_URI/ZENOH_ROUTER_CONFIG_URIで読み込み)。 - 注意: 同一ホスト内をルータ無しで動かそうとして
ZENOH_CONFIG_OVERRIDE='scouting/multicast/enabled=true'を入れると、わざわざマルチキャストを有効化することになり、ミラーモードの問題を自分から呼び戻します。ミラーモードではオンにしないのが無難です。
この問題で素直に楽なのは Zenoh、という整理になります。
この問題は ROS 2 側ではなく、WSL2 の OS / ネットワーク層に起因します。主な Issue とフォーラムスレッドを挙げます。
- ros2/ros2cli #934 ros2cli daemon check fails running on WSL2 ミラーモード使用時に ros2cli デーモンがハングアップ・クラッシュする問題の報告。
- microsoft/WSL #12399 With WSL2's Mirror Network Mode, Services on the Windows Host are Inaccessible... ミラーモードで Windows-WSL2 間の双方向通信がドロップするバグ。ROS 2 ユーザーからの報告もあり。
- microsoft/WSL #14063 WSL NetworkMode mirrored unable to connect to Windows host via TCP パケットルーティングの不整合により、DDS のディスカバリが崩壊する原因となっている OS 側のバグ。
- NVIDIA Developer Forums IsaacSim ROS2 connection issue when running WSL2 in mirrored mode Windows 上の Isaac Sim と WSL2 内の ROS 2 をミラーモードで通信させようとしてトピックが不通になる実例。
RMW 別の設定ドキュメント:
- Fast DDS: Interface Whitelist
interfaceWhiteListで使用インタフェースを限定する公式手順。 - Fast DDS: XML profiles
プロファイルの読み込み(
FASTDDS_DEFAULT_PROFILES_FILE)と既定プロファイル指定。 - ros2/rmw_zenoh README 既定でマルチキャスト scouting が無効・ルータ方式である旨と各環境変数の説明。