Discovery
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:
- 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.
- 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_CLIENTconfiguration to even introspect. - 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_PEERSto the peer IPs (orip:port) andZERODDS_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_KEYto emit the correct entity kind, which is exactly what made ZeroDDS ↔︎rmw_cycloneddsinterop 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
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:
- 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.
- 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. - 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_PEERSauf die Peer-IPs (oderip:port) undZERODDS_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