Migrate from CycloneDDS
Guide to switching from CycloneDDS (rmw_cyclonedds) to HDDS (rmw_hdds) in ROS2 applications.
Quick Migration
Step 1: Install rmw_hdds
sudo apt install ros-$ROS_DISTRO-rmw-hdds
Step 2: Update Environment
# Remove CycloneDDS setting
unset CYCLONEDDS_URI
# Set HDDS
export RMW_IMPLEMENTATION=rmw_hdds_cpp
Step 3: Verify
ros2 doctor --report | grep rmw
# Output: middleware name : rmw_hdds_cpp
Configuration Migration
Environment Variables
| CycloneDDS | HDDS | Description |
|---|---|---|
ROS_DOMAIN_ID | ROS_DOMAIN_ID | Same (compatible) |
CYCLONEDDS_URI | HDDS_CONFIG_FILE | Config file path |
CYCLONEDDS_PID_FILE | N/A | Not applicable |
XML Configuration
CycloneDDS configuration:
<?xml version="1.0" encoding="UTF-8"?>
<CycloneDDS xmlns="https://cdds.io/config">
<Domain id="any">
<General>
<NetworkInterfaceAddress>eth0</NetworkInterfaceAddress>
<AllowMulticast>true</AllowMulticast>
</General>
<Discovery>
<ParticipantIndex>auto</ParticipantIndex>
<MaxAutoParticipantIndex>100</MaxAutoParticipantIndex>
</Discovery>
<Tracing>
<Verbosity>warning</Verbosity>
</Tracing>
</Domain>
</CycloneDDS>
Equivalent HDDS configuration:
<?xml version="1.0" encoding="UTF-8"?>
<hdds>
<domain id="0">
<transport>
<udp enabled="true">
<interface>eth0</interface>
<multicast enabled="true"/>
</udp>
</transport>
<logging level="warn"/>
</domain>
</hdds>
QoS Configuration Mapping
Reliability
CycloneDDS (XML):
<Reliability>
<Kind>reliable</Kind>
<MaxBlockingTime>1s</MaxBlockingTime>
</Reliability>
HDDS:
<reliability kind="RELIABLE" max_blocking_ms="1000"/>
History
CycloneDDS:
<History>
<Kind>keep_last</Kind>
<Depth>10</Depth>
</History>
HDDS:
<history kind="KEEP_LAST" depth="10"/>
Durability
| CycloneDDS | HDDS |
|---|---|
volatile | VOLATILE |
transient_local | TRANSIENT_LOCAL |
transient | TRANSIENT |
persistent | PERSISTENT |
Transport Configuration
Network Interface
CycloneDDS:
<General>
<NetworkInterfaceAddress>192.168.1.0/24</NetworkInterfaceAddress>
</General>
HDDS:
<transport>
<udp>
<interface>192.168.1.0/24</interface>
</udp>
</transport>
Multicast Settings
CycloneDDS:
<General>
<AllowMulticast>spdp</AllowMulticast>
<MulticastTimeToLive>1</MulticastTimeToLive>
</General>
HDDS:
<transport>
<udp>
<multicast enabled="true">
<spdp>true</spdp>
<sedp>false</sedp>
<ttl>1</ttl>
</multicast>
</udp>
</transport>
Socket Buffers
CycloneDDS:
<Internal>
<SocketReceiveBufferSize min="1MB"/>
<SocketSendBufferSize min="1MB"/>
</Internal>
HDDS:
<transport>
<udp>
<receive_buffer_size>1048576</receive_buffer_size>
<send_buffer_size>1048576</send_buffer_size>
</udp>
</transport>
Discovery Configuration
Peers/Initial Locators
CycloneDDS:
<Discovery>
<Peers>
<Peer address="192.168.1.100"/>
<Peer address="192.168.1.101"/>
</Peers>
</Discovery>
HDDS:
<discovery>
<initial_peers>
<peer>192.168.1.100:7400</peer>
<peer>192.168.1.101:7400</peer>
</initial_peers>
</discovery>
Lease Duration
CycloneDDS:
<Discovery>
<LeaseDuration>10s</LeaseDuration>
</Discovery>
HDDS:
<discovery>
<lease_duration_sec>10</lease_duration_sec>
</discovery>
Shared Memory (Iceoryx)
CycloneDDS with Iceoryx
CycloneDDS:
<Domain id="any">
<SharedMemory>
<Enable>true</Enable>
<LogLevel>warning</LogLevel>
</SharedMemory>
</Domain>
HDDS Shared Memory
HDDS (built-in, no Iceoryx needed):
<transport>
<shared_memory enabled="true">
<segment_size_mb>64</segment_size_mb>
<prefer>true</prefer>
</shared_memory>
</transport>
Or via environment variable:
# HDDS shared memory is enabled by default
# To disable:
export HDDS_SHM_DISABLE=1
Logging Configuration
CycloneDDS Tracing
CycloneDDS:
<Tracing>
<Verbosity>config</Verbosity>
<OutputFile>cyclone.log</OutputFile>
<Category>discovery</Category>
</Tracing>
HDDS Logging
HDDS:
export HDDS_LOG_LEVEL=debug
export HDDS_LOG_FILE=/var/log/hdds.log
export HDDS_LOG_DISCOVERY=1
Or in XML:
<logging>
<level>debug</level>
<file>/var/log/hdds.log</file>
<categories>
<discovery>true</discovery>
</categories>
</logging>
Code Changes
No Code Changes Required
rmw_hdds is API-compatible with standard ROS2:
# Works unchanged with HDDS
import rclpy
from std_msgs.msg import String
def main():
rclpy.init()
node = rclpy.create_node('my_node')
pub = node.create_publisher(String, 'topic', 10)
sub = node.create_subscription(
String, 'topic', lambda msg: print(msg.data), 10)
rclpy.spin(node)
if __name__ == '__main__':
main()
Remove CycloneDDS-Specific Code
If you used CycloneDDS C API directly:
Before (CycloneDDS-specific):
#include <dds/dds.h>
dds_entity_t participant = dds_create_participant(0, NULL, NULL);
After (RMW-agnostic):
// Use only ROS2 APIs
auto node = rclcpp::Node::make_shared("my_node");
Performance Comparison
| Metric | CycloneDDS | HDDS | Notes |
|---|---|---|---|
| Latency (64B) | 35 us | 8 us | Same host, SHM |
| Latency (UDP) | 50 us | 45 us | Same LAN |
| Throughput | 2.2 M/s | 2.5 M/s | 64B messages |
| Memory (idle) | 3 MB | 2 MB | Per participant |
Common Migration Issues
Issue: CYCLONEDDS_URI Not Recognized
Symptom: Configuration ignored after migration
Solution: Use HDDS configuration:
# Replace
export CYCLONEDDS_URI=file:///path/to/cyclone.xml
# With
export HDDS_CONFIG_FILE=/path/to/hdds.xml
Issue: Different Multicast Behavior
Symptom: Discovery works differently
Solution: Match multicast settings:
<transport>
<udp>
<multicast enabled="true">
<address>239.255.0.1</address>
</multicast>
</udp>
</transport>
Issue: Shared Memory Performance Different
CycloneDDS uses Iceoryx, HDDS has built-in SHM.
Solution: Configure HDDS SHM:
# Increase segment size if needed
export HDDS_SHM_SEGMENT_SIZE=268435456 # 256 MB
Issue: Security Configuration
Solution: Both use standard ROS2 SROS2:
export ROS_SECURITY_ENABLE=true
export ROS_SECURITY_STRATEGY=Enforce
Feature Comparison
| Feature | CycloneDDS | HDDS |
|---|---|---|
| RTPS 2.4 | Yes | Yes |
| DDS Security | Yes | Yes |
| Shared Memory | Iceoryx | Built-in |
| XTypes | Partial | Full |
| Zero-copy | Iceoryx | Built-in |
| Content Filter | Yes | Yes |
Mixed RMW Testing
CycloneDDS and HDDS interoperate via RTPS:
# Terminal 1: CycloneDDS
export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
ros2 run demo_nodes_cpp talker
# Terminal 2: HDDS
export RMW_IMPLEMENTATION=rmw_hdds_cpp
ros2 run demo_nodes_cpp listener
# Both communicate successfully
Rollback
To revert to CycloneDDS:
unset HDDS_CONFIG_FILE
export RMW_IMPLEMENTATION=rmw_cyclonedds_cpp
export CYCLONEDDS_URI=file:///path/to/cyclone.xml
Migration Checklist
- Install rmw_hdds package
- Remove
CYCLONEDDS_URIenvironment variable - Set
RMW_IMPLEMENTATION=rmw_hdds_cpp - Convert XML configuration to HDDS format
- Test with
ros2 doctor - Verify topic communication
- Check shared memory operation
- Performance test
- Update launch files and scripts
- Remove CycloneDDS packages (optional)
Automated Conversion
Convert CycloneDDS XML to HDDS format:
# Using hdds-tools
hdds-convert cyclone-to-hdds \
--input /path/to/cyclonedds.xml \
--output /path/to/hdds.xml
Next Steps
- rmw_hdds Configuration - Detailed settings
- Performance Tuning - Optimization guide
- Migration from FastDDS - Alternative path