Context
Sensor data (TF-Luna 100 Hz, VL53L0X array 25-30 Hz) plus control commands (MAVROS setpoint 10 Hz) all flow through ROS 2 DDS. The latency budget:
- Sensor → policy: < 50 ms (for real-time obstacle avoidance).
- Policy → ArduPilot: < 100 ms (one setpoint cycle).
If you exceed those, the obstacle avoidance reacts to stale geometry and the policy is fighting yesterday’s news.
DDS RMW implementations
| RMW | Latency (ms) | Throughput (MB/s) | Maintenance |
|---|---|---|---|
| rmw_fastrtps_cpp | 0.3–0.5 (loopback) | ~600 | Default ROS 2, actively maintained |
| rmw_cyclonedds_cpp | 0.2–0.4 | ~800 | Eclipse, excellent for latency-critical |
| rmw_connextdds | proprietary | proprietary | RTI commercial |
| rmw_gurumdds_cpp | n/a | n/a | Less widely deployed |
Recommendation: leave rmw_fastrtps_cpp as the default for compatibility. If benchmarks show > 5 ms transport latency on critical topics, switch to CycloneDDS:
export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
sudo apt install ros-jazzy-rmw-cyclonedds-cpp
QoS profiles — sensor data vs control
| Topic | Reliability | Durability | Depth | Reasoning |
|---|---|---|---|---|
/drone/tf_luna_down (sensor) |
BestEffort | Volatile | 1 | losses tolerable — sensor publishes continuously |
/drone/sweep/result (LaserScan) |
Reliable | Volatile | 5 | single scan matters — process it |
/drone/scan/status |
Reliable | TransientLocal | 1 | latched — state machine reads after connect |
/mavros/setpoint_position/local |
BestEffort | Volatile | 1 | stale setpoints irrelevant, only the latest matters |
/mavros/state |
Reliable | Volatile | 10 | every state change matters |
/map (OccupancyGrid) |
Reliable | TransientLocal | 1 | latched — Nav2 / frontier_picker read on subscribe |
/navigate_to_pose/_action/* |
Reliable | Volatile | service-default | action infrastructure |
from rclpy.qos import QoSProfile, ReliabilityPolicy, DurabilityPolicy, HistoryPolicy
sensor_qos = QoSProfile(
reliability=ReliabilityPolicy.BEST_EFFORT,
durability=DurabilityPolicy.VOLATILE,
history=HistoryPolicy.KEEP_LAST,
depth=1)
Transport overhead
| Operation | Single-process | Multi-process (DDS) | Network |
|---|---|---|---|
| Topic publish | ~0.05 ms | ~0.3 ms loopback | ~1-5 ms LAN |
| Service call | ~0.1 ms | ~0.5 ms loopback | ~2-10 ms LAN |
| Action call (init) | ~1 ms | ~2 ms loopback | ~5-20 ms LAN |
| TF lookup (cached) | < 0.01 ms | n/a | n/a |
ROS_DOMAIN_ID isolation
Parallel stacks (TASK-033 simulation + researchbest in parallel) are isolated via:
export ROS_DOMAIN_ID=42 # researchbest
export ROS_LOCALHOST_ONLY=1 # restrict to loopback
ROS_LOCALHOST_ONLY=1 reduces discovery overhead — no network traffic.
Component composition vs separate processes
Composition = multiple nodes in one process via rclcpp::ComponentManager (C++) or Composable Node (Python). Latency between nodes in the same process: ~0.05 ms (intra-process). Downside: one crash takes down all nodes.
We use composition for the tight loop: frontier_picker + mission_fsm + state_publisher in a single process. SLAM and MAVROS run as separate processes (crash isolation).
Profiling tools
| Tool | What it measures |
|---|---|
ros2 topic hz |
Publication rate |
ros2 topic bw |
Bandwidth |
ros2 topic delay |
End-to-end latency |
ros2 wtf |
Diagnostics dump |
ros2 trace (via ros2_tracing) |
LTTng tracing — full call graph |
.env_researchbest configuration for D2
# Minimum-latency setup for the researchbest stack
export ROS_DOMAIN_ID=42
export ROS_LOCALHOST_ONLY=1
export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp # optional
# DDS XML profile — disable discovery announcements on non-local IP
export CYCLONEDDS_URI='<CycloneDDS><Domain><General><DontRoute>true</DontRoute></General></Domain></CycloneDDS>'
Smoke
# Latency baseline
ros2 topic hz /drone/tf_luna_down # expect 100 Hz
ros2 topic delay /drone/tf_luna_down # expect < 5 ms
ros2 topic hz /drone/sweep/result # expect ~0.05 Hz (1 every 22 s)
ros2 topic delay /drone/sweep/result # expect < 10 ms
Sources
- DDS implementations benchmark (community Discourse threads)
- ROS 2 QoS docs — https://docs.ros.org/en/jazzy/Concepts/Intermediate/About-Quality-of-Service-Settings.html
- Eclipse Cyclone DDS — https://cyclonedds.io
- ros2_tracing — https://github.com/ros2/ros2_tracing