Skip to main content

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

CycloneDDSHDDSDescription
ROS_DOMAIN_IDROS_DOMAIN_IDSame (compatible)
CYCLONEDDS_URIHDDS_CONFIG_FILEConfig file path
CYCLONEDDS_PID_FILEN/ANot 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

CycloneDDSHDDS
volatileVOLATILE
transient_localTRANSIENT_LOCAL
transientTRANSIENT
persistentPERSISTENT

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

MetricCycloneDDSHDDSNotes
Latency (64B)35 us8 usSame host, SHM
Latency (UDP)50 us45 usSame LAN
Throughput2.2 M/s2.5 M/s64B messages
Memory (idle)3 MB2 MBPer 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

FeatureCycloneDDSHDDS
RTPS 2.4YesYes
DDS SecurityYesYes
Shared MemoryIceoryxBuilt-in
XTypesPartialFull
Zero-copyIceoryxBuilt-in
Content FilterYesYes

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_URI environment 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