Skip to content

refactor(ros2): decouple DDS middleware and add CycloneDDS backend#9589

Draft
JesusAnaya wants to merge 1 commit intocarla-simulator:ue4-devfrom
JesusAnaya:new-feature/adding-ros2-cyclone-dds
Draft

refactor(ros2): decouple DDS middleware and add CycloneDDS backend#9589
JesusAnaya wants to merge 1 commit intocarla-simulator:ue4-devfrom
JesusAnaya:new-feature/adding-ros2-cyclone-dds

Conversation

@JesusAnaya
Copy link

@JesusAnaya JesusAnaya commented Mar 16, 2026

Description

🚧 This is a Draft PR: not ready to merge yet. I'm opening it early to share the proposal, gather feedback, and invite the community to test it. See the Status & Call for Testing section below.


I'd like to start by saying that I genuinely hope the team sees value in this proposal. This refactoring was born out of a real need I have myself, and one I've seen shared by others in the community, particularly teams working with Autoware and similar ROS2-based projects that rely on CycloneDDS rather than FastDDS. Right now, CARLA's ROS2 integration is tightly coupled to FastDDS, which blocks those workflows entirely.

This PR introduces a clean abstraction layer that solves that problem today with CycloneDDS support, and opens the door for additional DDS backends in the future, without touching publisher/subscriber logic. I think this is a net positive for the project's ecosystem, and I'd love to hear the team's thoughts.


561529104-0c0541d3-2ec3-42b7-98d6-6bfa85802a13

Refactors the ROS2 native integration in LibCarla to decouple the transport layer from FastDDS, introducing a strategy-pattern abstraction that supports multiple DDS backends simultaneously. CycloneDDS is added as a second supported backend alongside FastDDS.

The backend is selected at build time via --included-dds=fastdds,cyclonedds and resolved at runtime through DDSBackendFactory. The abstraction is designed to be open to additional backends (e.g. OpenDDS) without modifying the publisher/subscriber logic.

This refactoring was driven by the need of multiple CARLA community teams to work with CycloneDDS instead of FastDDS in their ROS2 workflows.

Key changes:

  • New DDS abstraction layer: DDSBackend enum, DDSBackendFactory, IDDSPublisherBackend and IDDSSubscriberBackend interfaces
  • FastDDS extracted into FastDDSPublisherBackend / FastDDSSubscriberBackend
  • CycloneDDS backend added: IDL-generated C type bindings, native serialization via dds_topic_descriptor_t, CycloneDDSConversions.h
  • PublisherImpl<T> and SubscriberImpl<S> delegate to backends via factory
  • 30 ROS2 type headers guarded with CARLA_ROS2_DDS_FASTDDS; POD msg structs and per-backend type maps added for independent serialization
  • Build system updated: Setup.sh, BuildLibCarla.sh, Vars.mk, CMake files
  • UE4 integration: CarlaSettings parses --dds-backend arg, CarlaEngine passes it to ROS2::Enable(), Carla.Build.cs reads included_dds_backends.txt
  • 61 unit tests in test_dds_backend.cpp covering factory, interfaces, backend resolution, enum/string conversion, and available-backends query
  • Windows build scripts left unchanged; Windows supports FastDDS only for now (see below)

Fixes #9294


How to Build & Test

The following steps build CARLA with both FastDDS and CycloneDDS backends enabled. --included-dds=fastdds,cyclonedds compiles both into separate static libraries (libcarla_fastdds.a and libcarla_cyclonedds.a). At runtime, the active backend is selected via --dds-backend=<fastdds|cyclonedds>.

To build with a single backend only, replace the value with --included-dds=fastdds or --included-dds=cyclonedds.

DDS_BACKENDS="fastdds,cyclonedds"
COMMON_ARGS="--python-version=3.12 --ros2 --included-dds=${DDS_BACKENDS} --target-wheel-platform=manylinux_2_31_x86_64"

# 1. Setup all dependencies (FastDDS, CycloneDDS, Chrono, etc.)
make setup ARGS="${COMMON_ARGS}" 2>&1 | tee output_1.log

# 2. Build LibCarla (server + client, debug + release, both DDS backends)
make LibCarla ARGS="${COMMON_ARGS}" 2>&1 | tee output_2.log

# 3. Build PythonAPI
make PythonAPI ARGS="${COMMON_ARGS}" 2>&1 | tee output_3.log

# 4. Build CarlaUE4Editor
make CarlaUE4Editor ARGS="${COMMON_ARGS}" 2>&1 | tee output_4.log

# 5. Build the final package
make package ARGS="${COMMON_ARGS} --no-zip" 2>&1 | tee output_5.log

Each step pipes output to a numbered log file for easier debugging if something goes wrong.


Status & Call for Testing

This PR is currently a draft. Linux testing has been completed, but Windows support still needs to be validated. I plan to test the Windows build myself this week to confirm that FastDDS remains stable under the new abstraction.

In the meantime, I'd love for others to try this out. If you run into any issues, have suggestions, or want to propose changes, please feel free to:

  • Comment directly on this PR
  • Push suggestions to this branch

The goal is to iterate together until we have a version that's solid enough to merge. I'm very open to feedback on both the architecture and the implementation details.


Where has this been tested?

  • Platform(s): Linux ✅ — Windows 🔄 (in progress this week)
  • Python version(s): 3.10, 3.11, 3.12
  • Unreal Engine version(s): UE4

Possible Drawbacks

  • Windows support remains FastDDS only until Windows testing is completed and validated
  • Projects relying on FastDDS-specific internals may need to migrate to the new backend interfaces
  • Build time may increase slightly when both backends are included

This change is Reviewable

Refactors the ROS2 native integration in LibCarla to decouple the
transport layer from FastDDS, introducing a strategy-pattern abstraction
that supports multiple DDS backends simultaneously. CycloneDDS is added
as a second supported backend alongside FastDDS.

The backend is selected at build time via --included-dds=fastdds,cyclonedds
and resolved at runtime through DDSBackendFactory. The abstraction is
designed to be open to additional backends (e.g. OpenDDS) without
modifying the publisher/subscriber logic.

This refactoring was driven by the need of multiple CARLA community teams
to work with CycloneDDS instead of FastDDS in their ROS2 workflows.
See: carla-simulator#9294

Key changes:
- New DDS abstraction layer: DDSBackend enum, DDSBackendFactory,
  IDDSPublisherBackend and IDDSSubscriberBackend interfaces
- FastDDS extracted into FastDDSPublisherBackend / FastDDSSubscriberBackend
- CycloneDDS backend added: IDL-generated C type bindings, native
  serialization via dds_topic_descriptor_t, CycloneDDSConversions.h
- PublisherImpl<T> and SubscriberImpl<S> delegate to backends via factory
- 30 ROS2 type headers guarded with CARLA_ROS2_DDS_FASTDDS; POD msg
  structs and per-backend type maps added for independent serialization
- Build system updated: Setup.sh, BuildLibCarla.sh, Vars.mk, CMake files
- UE4 integration: CarlaSettings parses --dds-backend arg, CarlaEngine
  passes it to ROS2::Enable(), Carla.Build.cs reads included_dds_backends.txt
- 61 unit tests in test_dds_backend.cpp covering factory, interfaces,
  backend resolution, enum/string conversion, and available-backends query
- Fixed ROS2.cpp: restore ESensors enum values in GetOrCreateSensor()
  calls (sensor_type is a stream ID, not an enum value)
- Windows build scripts left unchanged; Windows supports FastDDS only
@update-docs
Copy link

update-docs bot commented Mar 16, 2026

Thanks for opening this pull request! The maintainers of this repository would appreciate it if you would update our CHANGELOG.md based on your changes.

@habby1012
Copy link

Hi, thanks for sharing this PR — the DDS abstraction looks like a clean way to support CycloneDDS while keeping the current architecture.

I'm curious about one design choice: did you consider moving the abstraction to the ROS2 layer (e.g., using rclcpp + rmw) instead of directly at the DDS layer?

I've been experimenting with that approach on our side (based on the ue5-dev branch), and it seems feasible to integrate with CARLA as well. It could potentially allow switching middleware through RMW implementations.

I'm wondering what trade-offs led you to stay at the DDS layer — for example, dependency concerns or integration complexity.

Would love to hear your thoughts — thanks!

@Blyron
Copy link
Contributor

Blyron commented Mar 17, 2026

Hi @JesusAnaya

First of all, thank you so much for your interest in contributing to CARLA! We really appreciate the time and effort you’ve put into this.

However, we’ve noticed this PR is quite large (40+ files/changes), which makes it very difficult for us to perform a thorough and high-quality review. To ensure we don't miss anything and to speed up the merging process, could you please break this down into smaller, more focused PRs?

Small, incremental changes are much easier for the maintainers to digest and get merged quickly.

Best,

@JesusAnaya
Copy link
Author

@habby1012 Hi, thank you very much for your comment. The proposal you mentioned sounds interesting. I'm personally working on this refactoring because I'm interested in making Carla compatible with other DDS middleware for personal projects, without having to propose such a large architecture change. I don't know if the Carla Core team plans to make changes of this kind in the future, but I think that for now, given the way the server is designed, keeping DDS as an internal library might be the easiest way to integrate ROS. I imagine that maintaining the current integrity and supporting ROS in the simplest way possible for project maintenance is one of the priorities, but it's something that can be discussed, I suppose, although it would have to be discussed with more people within the core team to see if there are plans to achieve this or something similar to what you mentioned in the long term.

@JesusAnaya
Copy link
Author

Hi @JesusAnaya

First of all, thank you so much for your interest in contributing to CARLA! We really appreciate the time and effort you’ve put into this.

However, we’ve noticed this PR is quite large (40+ files/changes), which makes it very difficult for us to perform a thorough and high-quality review. To ensure we don't miss anything and to speed up the merging process, could you please break this down into smaller, more focused PRs?

Small, incremental changes are much easier for the maintainers to digest and get merged quickly.

Best,

Thank you so much for your comment. What you're saying makes perfect sense. It's just that when I was making the changes, I realized that to achieve my goal, I had to make all those modifications. Let me take a step back and go back to a previous version where I made the fewest changes and see how we can start from there. I'll try to make the fewest possible changes for this first iteration, and then I'll submit iterations of my proposed changes in subsequent pull requests, as you mentioned.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants