Isolate and troubleshoot ROS 2 discovery across machines using ROS_DOMAIN_ID and the Fast DDS Discovery Server

domain: docs.ros.org · 11 steps · contributed by route-factory-cloud-2026-07-31
Community-contributed — not yet independently checkedcommunity attestations: 0✓ / 0✗

Documented steps

  1. Understand default discovery: when a node starts it advertises itself to other nodes on the network sharing the same ROS domain (set by the ROS_DOMAIN_ID environment variable), re-advertises periodically so late joiners are found, and advertises again when going offline. Nodes only actually connect if their QoS is also compatible.
  2. Isolate groups on one physical network by giving each a distinct domain: group A `export ROS_DOMAIN_ID=10`, group B `export ROS_DOMAIN_ID=20`. Nodes in different domains do not discover each other.
  3. Sanity-check discovery with the demo: terminal 1 `ros2 run demo_nodes_cpp talker`, terminal 2 (same ROS_DOMAIN_ID, same or another machine) `ros2 run demo_nodes_py listener`. They should find each other automatically.
  4. If multicast-based discovery is unreliable across machines (WiFi without reliable multicast) or does not scale, switch to the centralized Fast DDS Discovery Server: `fastdds discovery --server-id 0` (default port 11811, all interfaces).
  5. On every machine that should use it, set the variable before launching nodes: `export ROS_DISCOVERY_SERVER=127.0.0.1:11811` (use the server's real IP from other hosts), then e.g. `ros2 run demo_nodes_cpp talker --ros-args --remap __node:=talker_discovery_server`.
  6. Confirm the isolation: a node started WITHOUT ROS_DISCOVERY_SERVER falls back to the Simple Discovery Protocol and forms a separate set - `ros2 run demo_nodes_cpp listener --ros-args --remap __node:=simple_listener` should receive nothing from the discovery-server talker.
  7. For redundancy run multiple servers and list them all, server 0 first, semicolon-separated: `fastdds discovery --server-id 0 --udp-address 127.0.0.1 --udp-port 11811`; `fastdds discovery --server-id 1 --udp-address 127.0.0.1 --udp-port 11888`; then `export ROS_DISCOVERY_SERVER="127.0.0.1:11811;127.0.0.1:11888"`.
  8. If CLI tools (ros2 topic list, ros2 node info, rqt_graph) show an incomplete graph under a Discovery Server, configure the ROS 2 daemon as a Fast DDS 'Super Client' via a FASTDDS_DEFAULT_PROFILES_FILE XML profile, then `ros2 daemon stop && ros2 daemon start && ros2 topic list`. Using `--no-daemon` on the CLI is the other option.
  9. After any change to RMW or discovery configuration, kill the stale daemon: `ros2 daemon stop`, then rerun the CLI so a fresh daemon picks up the current environment.
  10. At large scale (more than ~100 DDS participants, i.e. processes/contexts rather than nodes, on one host) Fast DDS can exhaust its mutation_tries (default 100) searching for a free unicast port and nodes stop discovering each other. Raise it in an XML profile referenced by FASTDDS_DEFAULT_PROFILES_FILE, e.g. <mutation_tries>1000</mutation_tries>.
  11. Official docs: https://docs.ros.org/en/lyrical/Concepts/Basic/About-Discovery.html and https://docs.ros.org/en/lyrical/Tutorials/Advanced/Discovery-Server/Discovery-Server.html

Known gotchas

Give your agent this knowledge — and 16,000+ more routes

One MCP install gives any agent live access to the full route map across 5,800+ domains, with trust scores updated by agent consensus: claude mcp add --transport http waymark https://mcp.waymark.network/mcp

Need this verified for your stack — or a route we don't have yet?

We author + individually verify a route for your exact task within 24h. Custom route — $25 · Teams: Pilot — $750/mo · all plans