Discovery

Back to overview

The pain

DDS discovery is the single most-reported source of “my ROS 2 nodes don’t talk” (62 reports in the field scan). Three structural problems recur:

  1. Multicast-based Simple Discovery (SDP) is fragile and noisy. It depends on UDP multicast, which is dropped or rate-limited on WiFi, in Docker, and on managed corporate/academic networks. Where it works, its traffic grows with the number of endpoints — and ROS 2 creates many internal topics per node, so discovery traffic can drown out the actual data at fleet scale.
  2. The Discovery Server “fix” is itself fragile. Restarting the server, or a node, frequently leaves endpoints permanently unmatched until everything is restarted in the right order; it needs expert XML and CLI SUPER_CLIENT configuration to even introspect.
  3. Defaults discover too much. Unrelated robots on the same network discover each other and can trigger unintended motion.

Most recent example

Fast-DDS#6401 — “Unexpected piggyback HB to all matched readers breaks EDP recovery loop after sleep/wake cycle” (2026-05-18). After a sleep/wake cycle in a three-node Simple Discovery topology, one pair of nodes permanently fails to re-match because an async piggyback Heartbeat is broadcast to all matched readers, corrupting a third node’s re-match state machine.

Reference list (most recent)

Date Source Problem
2026-05-18 Fast-DDS#6401 EDP recovery breaks after sleep/wake (piggyback HB)
2026-05-11 Fast-DDS#6346 Remote reader/writer no longer discovered in 3.5.0+
2025-10-14 Fast-DDS#5872 DataReader gets no data after Discovery Server restart
2025-06-23 rmw_cyclonedds#541 Listener gets no message with one RMW but fine with another
2022-10-05 ROS Discourse OSRF: defaults discover too much and flood the network
2020-11-17 ROS Discourse SDP traffic 93 % higher; drowns out data at 50–200 nodes

How ZeroDDS solves it

Discovery is direct unicast peer addressing — no multicast, no server.

  • Multicast-free unicast discovery. Set ZERODDS_PEERS to the peer IPs (or ip:port) and ZERODDS_NO_MULTICAST=1. ZeroDDS sends SPDP to each peer’s well-known RTPS port (7400 + 250·domain + 10 + 2·pid). No multicast packet ever leaves the host, so WiFi/Docker/subnet multicast handling is irrelevant.
  • No Discovery Server to restart. Because peers address each other directly, there is no separate server process whose restart leaves the mesh in a half-matched state — the entire class of “DataReader gets no data after server restart” (Fast-DDS#5872) does not exist.
  • Deterministic re-match. ZeroDDS’s SEDP re-announces and re-matches on a defined schedule; the “permanently unmatched after sleep/wake” failure mode is driven by direct, idempotent peer state, not a fragile piggyback-HB side effect.
  • The “listener gets no message” class is a known, fixed bug for us. rmw_cyclonedds#541 is the keyed-vs-keyless entity-kind mismatch family — a keyless type announced with a WithKey entity id is silently rejected by the peer’s topic-kind match. ZeroDDS consults DdsType::HAS_KEY to emit the correct entity kind, which is exactly what made ZeroDDS ↔︎ rmw_cyclonedds interop go 20/20 bidirectional.
  • Scope is opt-in, not accidental. Peers are an explicit list, so unrelated robots on the same network do not discover each other by default.

Why it no longer has to be a pain

The root cause of the discovery cluster is indirection and broadcast: multicast you don’t control, plus a server (or piggyback side effects) whose state can desync. ZeroDDS replaces both with explicit, direct, unicast peer addressing — the same thing teams end up hand-building with Discovery Servers and XML, but as a first-class, out-of-the-box mode with no extra process.

Reproduce it yourself

# Multicast-free discovery across vendors (ZeroDDS sub ↔ Cyclone talker,
# multicast fully disabled on both): expect matched=1, 20/20 samples.
crates/ros2-rmw/interop/run_multicast_free_xvendor.sh

# rmw_zerodds against a real rmw_cyclonedds talker/listener on rt/chatter.
crates/ros2-rmw/interop/run_interop.sh

Back to overview · Next: Multicast / WiFi

Discovery

Zurück zur Übersicht

Der Schmerz

DDS-Discovery ist die meistgemeldete Einzelquelle für „meine ROS-2-Nodes reden nicht” (62 Reports im Field-Scan). Drei strukturelle Probleme kehren wieder:

  1. Multicast-basierte Simple Discovery (SDP) ist fragil und laut. Sie hängt an UDP-Multicast, das auf WiFi, in Docker und in verwalteten Firmen-/Uni-Netzen gedroppt oder rate-limitiert wird. Wo es funktioniert, wächst der Traffic mit der Zahl der Endpoints — und ROS 2 erzeugt viele interne Topics je Node, sodass Discovery-Traffic die eigentlichen Daten bei Flotten-Größe übertönen kann.
  2. Der Discovery-Server-„Fix” ist selbst fragil. Ein Neustart des Servers oder eines Nodes lässt Endpoints häufig dauerhaft un-gematcht, bis alles in der richtigen Reihenfolge neu gestartet wird; er braucht Experten-XML und CLI-SUPER_CLIENT-Konfiguration, um überhaupt introspizierbar zu sein.
  3. Defaults entdecken zu viel. Unverwandte Roboter im selben Netz finden sich gegenseitig und können ungewollte Bewegung auslösen.

Jüngstes Beispiel

Fast-DDS#6401 — „Unexpected piggyback HB to all matched readers breaks EDP recovery loop after sleep/wake cycle” (2026-05-18). Nach einem Sleep/Wake-Zyklus in einer Drei-Node-Simple-Discovery-Topologie schafft ein Node-Paar das Re-Match dauerhaft nicht, weil ein asynchroner Piggyback-Heartbeat an alle gematchten Reader gebroadcastet wird und die Re-Match-State-Machine eines dritten Nodes korrumpiert.

Referenzliste (jüngste zuerst)

Datum Quelle Problem
2026-05-18 Fast-DDS#6401 EDP-Recovery bricht nach Sleep/Wake (Piggyback-HB)
2026-05-11 Fast-DDS#6346 Remote-Reader/Writer in 3.5.0+ nicht mehr entdeckt
2025-10-14 Fast-DDS#5872 DataReader bekommt keine Daten nach Discovery-Server-Neustart
2025-06-23 rmw_cyclonedds#541 Listener bekommt mit einer RMW keine Nachricht, mit anderer schon
2022-10-05 ROS Discourse OSRF: Defaults entdecken zu viel und fluten das Netz
2020-11-17 ROS Discourse SDP-Traffic 93 % höher; übertönt Daten bei 50–200 Nodes

Wie ZeroDDS es löst

Discovery ist direkte Unicast-Peer-Adressierung — kein Multicast, kein Server.

  • Multicast-freie Unicast-Discovery. Setze ZERODDS_PEERS auf die Peer-IPs (oder ip:port) und ZERODDS_NO_MULTICAST=1. ZeroDDS sendet SPDP an den Well-known-RTPS-Port jedes Peers (7400 + 250·domain + 10 + 2·pid). Kein Multicast-Paket verlässt jemals den Host, sodass WiFi-/Docker-/Subnetz-Multicast-Handling irrelevant ist.
  • Kein Discovery-Server zum Neustarten. Weil Peers sich direkt adressieren, gibt es keinen separaten Server-Prozess, dessen Neustart das Mesh halb-gematcht zurücklässt — die ganze Klasse „DataReader bekommt keine Daten nach Server-Neustart” (Fast-DDS#5872) existiert nicht.
  • Deterministisches Re-Match. Das SEDP von ZeroDDS re-announct und re-matcht nach definiertem Schema; der Fehlermodus „dauerhaft un-gematcht nach Sleep/Wake” wird von direktem, idempotentem Peer-State getrieben, nicht von einem fragilen Piggyback-HB-Seiteneffekt.
  • Die „Listener bekommt keine Nachricht”-Klasse ist für uns ein bekannter, gefixter Bug. rmw_cyclonedds#541 ist die Keyed-vs-Keyless-EntityKind-Mismatch-Familie — ein Keyless-Typ, der mit einer WithKey-Entity-ID announct wird, wird vom Topic-Kind-Match des Peers still abgelehnt. ZeroDDS konsultiert DdsType::HAS_KEY, um den korrekten Entity-Kind zu emittieren — genau das ließ die ZeroDDS-↔︎-rmw_cyclonedds-Interop 20/20 bidirektional laufen.
  • Scope ist opt-in, nicht versehentlich. Peers sind eine explizite Liste, sodass unverwandte Roboter im selben Netz sich per Default nicht gegenseitig entdecken.

Warum es kein Schmerz mehr sein muss

Die Wurzel des Discovery-Clusters ist Indirektion und Broadcast: Multicast, das du nicht kontrollierst, plus ein Server (oder Piggyback-Seiteneffekte), dessen State desyncen kann. ZeroDDS ersetzt beides durch explizite, direkte Unicast-Peer-Adressierung — dasselbe, was Teams am Ende mit Discovery-Servern und XML von Hand zusammenbauen, aber als First-Class-Out-of-the-Box-Modus ohne Extra-Prozess.

Selbst reproduzieren

# Multicast-freie Discovery cross-vendor (ZeroDDS-Sub ↔ Cyclone-Talker,
# Multicast auf beiden voll deaktiviert): erwarte matched=1, 20/20 Samples.
crates/ros2-rmw/interop/run_multicast_free_xvendor.sh

# rmw_zerodds gegen einen echten rmw_cyclonedds-Talker/Listener auf rt/chatter.
crates/ros2-rmw/interop/run_interop.sh

Zurück zur Übersicht · Weiter: Multicast / WiFi