Configuration Complexity

RC7 preparation: this page retains historical investigations and measurements, not approval of the current candidate. Runtime file contracts were checked against current source; historical interoperability, performance and platform claims were not remeasured by that review.

← Back to overview

The pain

Getting DDS to work well in ROS 2 routinely means becoming a part-time DDS network engineer (21 reports): hundreds of XML knobs, per-vendor dialects (Fast DDS profiles vs Cyclone XML vs Connext QoS), kernel tuning (rmem_max, ipfrag_*), and hidden prerequisites that are nearly impossible to find. The shipped defaults are not the robotics-/WiFi-appropriate ones, so “good enough” takes days of trial and error.

  • Localhost-only mode silently requires multicast enabled on the loopback interface (ip link set lo multicast on) — undocumented in practice.
  • Selecting the right network interface, or making a Discovery Server introspectable, needs expert XML.
  • A binary install can even go looking for a paid vendor by default.

Most recent example

ROS Discourse — “I’m done manually tuning DDS parameters!” (2026-04-30). A long, well-received thread: hundreds of knobs, days of trial-and-error, and still suboptimal results — a representative statement of the configuration-complexity tax.

Reference list (most recent)

Date Source Problem
2026-04-30 ROS Discourse “Done tuning DDS”: hundreds of knobs, days lost
2025-12-09 ROS Discourse OSRF “Consolidated User Insights” on DDS pain
2025-08-15 ros2#1716 Jazzy on Windows searches for paid RTI Connext
2025-04-04 rmw_cyclonedds#537 failed to create domain, error Error
2025-04-02 cyclonedds#2201 Network-interface selection requires config spelunking

How ZeroDDS solves it

Robotics-appropriate defaults with explicit layered runtime files.

  • ros_defaults() works out of the box. A single RuntimeConfig::ros_defaults() sets the representation offers (XCDR1 + XCDR2) and the 16 MiB reassembly cap ROS actually needs — rmw_zerodds interops with a real ROS 2 talker 20/20 with no XML and no environment tuning.
  • Runtime configuration is a typed base and ordered drop-ins. Discovery uses discovery.peers/discovery.no_multicast/transport.user_multicast, interface pinning transport.interface. Later fragments override earlier values without copying the entire base.
  • Interface selection is one file setting. The “network-interface selection” pain (cyclonedds#2201) is transport.interface: <ip>, used for IP interface selection and advertised locators. SHM and Unix-domain sockets do not acquire an IP interface from this setting.
  • No hidden loopback prerequisite. Unicast localhost discovery does not depend on multicast being enabled on lo.
  • No paid-vendor fallback. The whole stack is open source (Apache-2.0 / MIT); there is no proprietary tier a default install can drift toward.

Why it no longer has to be a pain

Keep the project base under version control and add site-specific fragments. Explicit includes make shared settings visible. Invalid known runtime values fail before startup instead of silently falling back.

RC7 runtime files

The runtime standard path reads /etc/zerodds/zerodds.yaml, then YAML fragments sorted by filename in /etc/zerodds/zerodds.d, then /run/zerodds/zerodds.d. Missing implicit paths are allowed. Unreadable or malformed files fail. Legacy runtime environment overrides no longer select these values.

# /etc/zerodds/zerodds.yaml
discovery:
  no_multicast: true
  peers:
    - 192.0.2.10
transport:
  user_multicast: false
  recv_batch: 32
# /etc/zerodds/zerodds.d/20-site.yaml
discovery:
  +peers:
    - 192.0.2.11

Replace the example addresses with reachable IPv4 addresses or IPv4:port. include: shared.d includes another directory relative to the including file. Nested directories require explicit includes. Includes load before a file's own values. Maps merge, lists replace, +peers appends. Use block lists, not inline lists. Cycles and invalid includes fail.

Rust projects select a required base through ConfigSource::from_path(path), including its sibling <stem>.d, then the fallible RuntimeConfig::from_source. Explicit caller configuration stays authoritative. RuntimeConfig::default() alone reads neither files nor environment. ConfigSource::origins() reports surviving scalar origins, including list elements.

This is the runtime schema, not every bridge schema. Bridge --config, ROS selectors, explicit security APIs and vendor settings retain their own contracts. Explicit variable interpolation remains supported. Unknown application keys are not a fully validated application schema.

Executable source: runtime_config_layering.rs. Loader contract: zerodds-config README.

Reproduce it yourself

# Out-of-the-box ROS interop with no XML / no env tuning:
crates/ros2-rmw/interop/run_interop.sh   # uses ros_defaults()

→ Back to overview · Next: Scaling

Konfigurations-Komplexität

RC7-Vorbereitung: Diese Seite enthält historische Untersuchungen und Messwerte, keine Freigabe des aktuellen Kandidaten. Die Runtime-Dateiverträge wurden mit dem aktuellen Quellstand abgeglichen; historische Interop-, Performance- und Plattformbehauptungen dadurch nicht erneut vermessen.

← Zurück zur Übersicht

Der Schmerz

DDS in ROS 2 gut zum Laufen zu bringen heißt routinemäßig, ein Teilzeit-DDS-Netzwerk-Ingenieur zu werden (21 Reports): hunderte XML-Knöpfe, Per-Vendor-Dialekte (Fast-DDS-Profile vs Cyclone-XML vs Connext-QoS), Kernel-Tuning (rmem_max, ipfrag_*) und versteckte Voraussetzungen, die nahezu unmöglich zu finden sind. Die ausgelieferten Defaults sind nicht die robotik-/WiFi-passenden, sodass „gut genug” Tage von Trial-and-Error kostet.

  • Localhost-Only-Modus erfordert still, dass Multicast auf dem Loopback-Interface aktiviert ist (ip link set lo multicast on) — in der Praxis undokumentiert.
  • Das richtige Netzwerk-Interface zu wählen oder einen Discovery-Server introspizierbar zu machen, braucht Experten-XML.
  • Ein Binary-Install kann sogar per Default nach einem bezahlten Vendor suchen.

Jüngstes Beispiel

ROS Discourse — „I’m done manually tuning DDS parameters!” (2026-04-30). Ein langer, gut aufgenommener Thread: hunderte Knöpfe, Tage von Trial-and-Error und immer noch suboptimale Ergebnisse — eine repräsentative Aussage über die Konfigurations-Komplexitäts-Steuer.

Referenzliste (jüngste zuerst)

Datum Quelle Problem
2026-04-30 ROS Discourse „Done tuning DDS”: hunderte Knöpfe, Tage verloren
2025-12-09 ROS Discourse OSRF „Consolidated User Insights” zum DDS-Schmerz
2025-08-15 ros2#1716 Jazzy auf Windows sucht nach bezahltem RTI Connext
2025-04-04 rmw_cyclonedds#537 failed to create domain, error Error
2025-04-02 cyclonedds#2201 Netzwerk-Interface-Auswahl erfordert Config-Spelunking

Wie ZeroDDS es löst

Robotik-passende Defaults mit expliziten, geschichteten Runtime-Dateien.

  • ros_defaults() funktioniert out of the box. Ein einziges RuntimeConfig::ros_defaults() setzt die Representation-Offers (XCDR1 + XCDR2) und den 16-MiB-Reassembly-Cap, die ROS tatsächlich braucht — rmw_zerodds interopt mit einem echten ROS-2-Talker 20/20 ohne XML und ohne Umgebungs-Tuning.
  • Runtime-Konfiguration besteht aus einer typisierten Basis und sortierten Ergänzungen. Discovery nutzt discovery.peers/discovery.no_multicast/transport.user_multicast, Interface-Pinning transport.interface. Spätere Fragmente überschreiben frühere Werte, ohne die gesamte Basis zu kopieren.
  • Interface-Auswahl ist ein Dateiwert. Der „Netzwerk-Interface-Auswahl”-Schmerz (cyclonedds#2201) ist transport.interface: <ip>, für IP-Interface-Auswahl und angekündigte Locators. SHM und Unix-Domain-Sockets erhalten dadurch kein IP-Interface.
  • Keine versteckte Loopback-Voraussetzung. Unicast-Localhost-Discovery hängt nicht davon ab, dass Multicast auf lo aktiviert ist.
  • Kein Paid-Vendor-Fallback. Der ganze Stack ist Open Source (Apache-2.0 / MIT); es gibt keinen proprietären Tier, zu dem ein Default-Install driften könnte.

Warum es kein Schmerz mehr sein muss

Die Projektbasis kann versioniert werden, standortspezifische Fragmente ergänzen sie. Explizite Includes machen gemeinsame Einstellungen sichtbar. Ungültige bekannte Runtime-Werte verhindern den Start, statt still durch Defaults ersetzt zu werden.

RC7-Runtime-Dateien

Der Standardpfad liest /etc/zerodds/zerodds.yaml, danach die nach Dateinamen sortierten YAML-Fragmente in /etc/zerodds/zerodds.d, dann /run/zerodds/zerodds.d. Fehlende implizite Pfade sind erlaubt; fehlerhafte oder unlesbare Dateien verhindern den Start. Alte Runtime-Umgebungsvariablen überschreiben diese Werte nicht.

# /etc/zerodds/zerodds.yaml
discovery:
  no_multicast: true
  peers:
    - 192.0.2.10
transport:
  user_multicast: false
  recv_batch: 32

Beispieladressen durch erreichbare IPv4-Adressen oder IPv4:Port ersetzen. Ein späteres Fragment kann mit discovery: und darunter +peers: eine Liste ergänzen. include: shared.d bindet ein weiteres Verzeichnis relativ zur Datei ein. Verschachtelte Verzeichnisse benötigen explizite Includes. Includes werden vor den eigenen Werten gelesen. Maps werden zusammengeführt, Listen ersetzt, +peers ergänzt sie. Blocklisten verwenden. Zyklen und ungültige Includes werden abgelehnt.

ConfigSource::from_path(path) verlangt eine Projektbasis und liest ihr benachbartes <stem>.d; danach folgt RuntimeConfig::from_source. Explizite Runtime-Konfiguration bleibt maßgeblich. RuntimeConfig::default() liest weder Dateien noch Umgebung. ConfigSource::origins() zeigt die Herkunft einzelner Werte. Bridge---config, ROS-Selektoren, explizite Security-APIs und Vendor-Konfiguration behalten eigene Verträge. Explizite Variableninterpolation bleibt unterstützt; unbekannte Anwendungsschlüssel sind kein vollständig validiertes Anwendungsschema.

Ausführbare Quelle: runtime_config_layering.rs. Loader-Vertrag: zerodds-config README.

Selbst reproduzieren

# Out-of-the-box-ROS-Interop ohne XML / ohne Env-Tuning:
crates/ros2-rmw/interop/run_interop.sh   # nutzt ros_defaults()

→ Zurück zur Übersicht · Weiter: Scaling