Skip to main content

CycloneDDS Setup

Configure CycloneDDS to communicate with HDDS participants.

Installation

Ubuntu/Debian

sudo apt install cyclonedds-dev cyclonedds-tools

From Source

git clone https://github.com/eclipse-cyclonedds/cyclonedds.git
cd cyclonedds
mkdir build && cd build
cmake -DCMAKE_INSTALL_PREFIX=/usr/local ..
make -j$(nproc)
sudo make install

ROS2 (Already Installed)

# CycloneDDS is bundled with ROS2
source /opt/ros/$ROS_DISTRO/setup.bash

Basic Configuration

Minimal Interop Configuration

Create cyclonedds.xml:

<?xml version="1.0" encoding="UTF-8"?>
<CycloneDDS xmlns="https://cdds.io/config">
<Domain id="any">
<General>
<AllowMulticast>true</AllowMulticast>
</General>
</Domain>
</CycloneDDS>

Apply configuration:

export CYCLONEDDS_URI=file:///path/to/cyclonedds.xml

Network Interface Selection

<CycloneDDS xmlns="https://cdds.io/config">
<Domain id="any">
<General>
<NetworkInterfaceAddress>eth0</NetworkInterfaceAddress>
<!-- Or by IP -->
<!-- <NetworkInterfaceAddress>192.168.1.100</NetworkInterfaceAddress> -->
</General>
</Domain>
</CycloneDDS>

Discovery Configuration

Multicast Discovery (Default)

<CycloneDDS xmlns="https://cdds.io/config">
<Domain id="any">
<General>
<AllowMulticast>spdp</AllowMulticast>
</General>
</Domain>
</CycloneDDS>

Unicast Discovery (No Multicast)

<CycloneDDS xmlns="https://cdds.io/config">
<Domain id="any">
<General>
<AllowMulticast>false</AllowMulticast>
</General>
<Discovery>
<Peers>
<Peer address="192.168.1.100"/> <!-- HDDS participant -->
<Peer address="192.168.1.101"/>
</Peers>
</Discovery>
</Domain>
</CycloneDDS>

Domain ID

<CycloneDDS xmlns="https://cdds.io/config">
<Domain id="42">
<!-- Configuration for domain 42 -->
</Domain>
</CycloneDDS>

Or via environment:

export ROS_DOMAIN_ID=42

Transport Configuration

Socket Buffers

<CycloneDDS xmlns="https://cdds.io/config">
<Domain id="any">
<Internal>
<SocketReceiveBufferSize min="4MB"/>
<SocketSendBufferSize min="4MB"/>
</Internal>
</Domain>
</CycloneDDS>

Shared Memory (Iceoryx)

<CycloneDDS xmlns="https://cdds.io/config">
<Domain id="any">
<SharedMemory>
<Enable>true</Enable>
<SubId>0</SubId>
<LogLevel>warning</LogLevel>
</SharedMemory>
</Domain>
</CycloneDDS>

Note: CycloneDDS shared memory uses Iceoryx and is not directly compatible with HDDS built-in shared memory. For same-host interop, use UDP loopback.

Debugging

Enable Tracing

<CycloneDDS xmlns="https://cdds.io/config">
<Domain id="any">
<Tracing>
<Verbosity>finest</Verbosity>
<OutputFile>cyclone.log</OutputFile>
<Category>discovery</Category>
</Tracing>
</Domain>
</CycloneDDS>

Check Discovery

# List discovered participants
ddsperf -D0 ping

# Monitor topic traffic
ddsperf sub MySensorTopic

Type Definition

CycloneDDS and HDDS must use identical type definitions.

IDL File

// sensor_data.idl
module sensors {
struct SensorData {
unsigned long sensor_id; // @key
float value;
unsigned long long timestamp;
};
};

Generate CycloneDDS Types

idlc -l c sensor_data.idl
# Generates: sensor_data.c, sensor_data.h

Generate HDDS Types

hdds-gen -l rust sensor_data.idl
# Generates: sensor_data.rs

Verification

Test Connectivity

CycloneDDS Publisher:

#include <dds/dds.h>
#include "sensor_data.h"

int main() {
dds_entity_t participant = dds_create_participant(0, NULL, NULL);
dds_entity_t topic = dds_create_topic(
participant, &sensors_SensorData_desc, "SensorTopic", NULL, NULL);
dds_entity_t writer = dds_create_writer(participant, topic, NULL, NULL);

sensors_SensorData sample = { .sensor_id = 1, .value = 25.5, .timestamp = 0 };
dds_write(writer, &sample);

dds_delete(participant);
return 0;
}

HDDS Subscriber:

use hdds::*;

fn main() -> Result<(), HddsError> {
let participant = DomainParticipant::new(0)?;
let topic = participant.create_topic::<SensorData>("SensorTopic")?;
let subscriber = participant.create_subscriber()?;
let reader = subscriber.create_datareader(&topic)?;

loop {
if let Ok(samples) = reader.take() {
for (sample, _) in samples {
println!("Received from CycloneDDS: {:?}", sample);
}
}
}
}

Common Issues

IssueSolution
No discoveryCheck domain ID matches, check network interface
Type mismatchUse same IDL, regenerate types
No dataCheck QoS compatibility

Full Example Configuration

<?xml version="1.0" encoding="UTF-8"?>
<CycloneDDS xmlns="https://cdds.io/config">
<Domain id="0">
<General>
<NetworkInterfaceAddress>auto</NetworkInterfaceAddress>
<AllowMulticast>spdp</AllowMulticast>
<MaxMessageSize>65500B</MaxMessageSize>
</General>

<Discovery>
<ParticipantIndex>auto</ParticipantIndex>
<MaxAutoParticipantIndex>100</MaxAutoParticipantIndex>
</Discovery>

<Internal>
<SocketReceiveBufferSize min="4MB"/>
<SocketSendBufferSize min="4MB"/>
</Internal>

<Tracing>
<Verbosity>warning</Verbosity>
</Tracing>
</Domain>
</CycloneDDS>

Next Steps