feat(LibCarla/ros2): add configurable ROS 2 domain id via --ros-domain-id - #9778
Conversation
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds support for selecting a ROS 2 domain id for CARLA’s native ROS 2 connector, wiring the value from CLI/settings into the middleware layer so FastDDS/CycloneDDS (and future middlewares) consistently honor it.
Changes:
- Introduces
--ros-domain-id=<N>end-to-end: build/launch script → UE settings parsing → ROS2 enable → middleware participants. - Adds a middleware-agnostic
MiddlewareConfigplus validation utilities and unit tests for domain-id handling. - Updates ROS2 RViz helper script and documentation (quickstart, example README, changelog) to describe and use the new option.
Reviewed changes
Copilot reviewed 16 out of 16 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| Util/BuildTools/BuildCarlaUE4.sh | Adds CLI option parsing and forwards --ros-domain-id into editor/server flags. |
| Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Settings/CarlaSettings.h | Adds a persisted UE setting for ROS 2 domain id with default sentinel. |
| Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Settings/CarlaSettings.cpp | Parses domain id from command line into settings at startup. |
| Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Game/CarlaEngine.cpp | Validates domain id and passes it into ROS2 enablement. |
| PythonAPI/examples/ros2/run_rviz.sh | Accepts --ros-domain-id, validates it, and forwards ROS_DOMAIN_ID into the container. |
| PythonAPI/examples/ros2/README.md | Documents how to use a custom ROS 2 domain id with CARLA and RViz. |
| LibCarla/source/test/server/test_ros2_middleware.cpp | Adds unit tests covering domain-id validity and MiddlewareConfig behavior. |
| LibCarla/source/carla/ros2/middleware/fastdds/FastDDSSharedParticipant.cpp | Creates FastDDS participant using configured domain id. |
| LibCarla/source/carla/ros2/middleware/cyclonedds/CycloneDDSSertype.cpp | Creates CycloneDDS participant using configured domain id (or defaults). |
| LibCarla/source/carla/ros2/middleware/MiddlewareConfig.h | New shared config header holding domain id + helper constants/functions. |
| LibCarla/source/carla/ros2/middleware/ISubscriberMiddleware.h | Documents requirement for middlewares to honor MiddlewareConfig domain id. |
| LibCarla/source/carla/ros2/middleware/IPublisherMiddleware.h | Documents requirement for middlewares to honor MiddlewareConfig domain id. |
| LibCarla/source/carla/ros2/ROS2.h | Extends ROS2::Enable API to accept domain_id. |
| LibCarla/source/carla/ros2/ROS2.cpp | Stores domain id into MiddlewareConfig and logs chosen domain. |
| Docs/ext_quickstart.md | Documents the new server CLI option and its constraints. |
| CHANGELOG.md | Notes the newly added --ros-domain-id option. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…n-id Add a --ros-domain-id=<N> server option to select the ROS 2 domain id at startup, mirroring the existing --rmw flow. The domain id (0 to 232) lives in the middleware abstraction layer (new MiddlewareConfig) and is read by every middleware when it creates its transport context, so FastDDS, CycloneDDS, and future middlewares all honor it. The interface contract is documented on the publisher/subscriber middleware interfaces. When the option is omitted, each middleware keeps its previous default domain, so existing behavior is unchanged. Out-of-range values log an error and fall back to the default. The flag is parsed by CarlaSettings, validated and forwarded by CarlaEngine, and forwarded into the editor command line by BuildCarlaUE4.sh so that "make launch ARGS=\"--ros2 --ros-domain-id=N\"" works. The rviz Docker example (run_rviz.sh) gains a matching --ros-domain-id option that sets ROS_DOMAIN_ID.
…play name Make the test group numbering in test_ros2_middleware.cpp contiguous after the middleware_config group was inserted (the new group kept number 5 and the rest were left unchanged, producing two Group 5 headers). The groups are now numbered 1 through 12 in order. Use "ID" instead of "Id" in the CarlaSettings ROS2 domain id display name so the editor label matches the wording used in the CLI option and documentation.
…n id Resolve the effective ROS 2 domain id in the middleware abstraction layer in priority order: the --ros-domain-id command line value, then the ROS_DOMAIN_ID environment variable, then the default domain 0. This lets the server pick up the standard ROS 2 environment variable when the option is not given, matching how other ROS 2 tools select a domain, while the option still takes precedence. MiddlewareConfig gains TryParseDomainId and ResolveDomainId (pure, unit-tested) plus GetEffectiveDomainId/ResolveEffective. FastDDS and CycloneDDS now use the resolved value, so both middlewares select the domain identically instead of CycloneDDS relying on DDS_DOMAIN_DEFAULT. The startup log reports the effective domain id and its source. Also rename the launch scripts' internal --ros-domain-id variable to ROS_DOMAIN_ID_ARG. The previous name shadowed the inherited ROS_DOMAIN_ID environment variable and reset it to empty for the launched editor, so an exported ROS_DOMAIN_ID was lost when starting CARLA through make launch. Add unit tests for parsing, precedence and the environment wrapper, and document the resolution order.
c592c67 to
ca0ab5c
Compare
…leware zenoh_ros_domain_id() now uses the effective domain id resolved by MiddlewareConfig (--ros-domain-id, then ROS_DOMAIN_ID, then 0) instead of reading the environment variable directly, so the Zenoh keyexprs honor the same resolution order as the FastDDS and CycloneDDS participants. Adds keyexpr and resolution-order unit tests.
|
This PR is now ready for review. @habby1012 I integrated the new ROS 2 domain ID management into your Zenoh implementation, The CARLA topics are visible on the configured domain and isolated from the other domains. |
|
@JArmandoAnaya, It looks good, thanks! |
|
Thank you for merging @Blyron. @habby1012, now it is possible to change the ROS Domain ID in CARLA UE4. If you have time to share your feedback on how Zenoh is working with this new feature, it would be great! Thank you. |
|
@JArmandoAnaya, Sorry for the late reply, I was off for the Dragon Boat Festival! |
|
@habby1012 nice to hear it! Thank you for your feedback. |
…ain-id Add a --ros-domain-id=<N> server option to select the ROS 2 domain id at startup, alongside the existing --rmw flow. The domain id (0 to 232) lives in the middleware abstraction layer (new MiddlewareConfig) and is read by FastDDS, CycloneDDS, and Zenoh when they create their transport context. Resolution order is --ros-domain-id, then the ROS_DOMAIN_ID environment variable, then the default domain 0. Out-of-range values are ignored and the next source is used; omitting the option keeps the previous behavior (domain 0). ue5 adaptation: ROS2.cpp compiles into carla-server while the middlewares compile into libcarla-ros2-native.so, so MiddlewareConfig's process-wide storage would not be shared across that boundary. The domain id therefore crosses it through a new DDS-free SetActiveDomainId export on the ActiveMiddleware bridge (it stores the value in the shared library's MiddlewareConfig and returns the resolved id for the startup log), replacing the direct MiddlewareConfig::SetDomainId call used on the monolithic ue4 build. The ue4 BuildCarlaUE4.sh editor-flag forwarding is not ported (ue5 reads FCommandLine directly), and the doc note goes into Docs/ros2_native.md (Docs/ext_quickstart.md does not exist on ue5). Upstream commit (ue4-dev e78db15): feat(LibCarla/ros2): add configurable ROS 2 domain id via --ros-domain-id (#9778) * feat(LibCarla/ros2): add configurable ROS 2 domain id via --ros-domain-id Add a --ros-domain-id=<N> server option to select the ROS 2 domain id at startup, mirroring the existing --rmw flow. The domain id (0 to 232) lives in the middleware abstraction layer (new MiddlewareConfig) and is read by every middleware when it creates its transport context, so FastDDS, CycloneDDS, and future middlewares all honor it. The interface contract is documented on the publisher/subscriber middleware interfaces. When the option is omitted, each middleware keeps its previous default domain, so existing behavior is unchanged. Out-of-range values log an error and fall back to the default. The flag is parsed by CarlaSettings, validated and forwarded by CarlaEngine, and forwarded into the editor command line by BuildCarlaUE4.sh so that "make launch ARGS=\"--ros2 --ros-domain-id=N\"" works. The rviz Docker example (run_rviz.sh) gains a matching --ros-domain-id option that sets ROS_DOMAIN_ID. * refactor(LibCarla/ros2): renumber test groups and align domain id display name Make the test group numbering in test_ros2_middleware.cpp contiguous after the middleware_config group was inserted (the new group kept number 5 and the rest were left unchanged, producing two Group 5 headers). The groups are now numbered 1 through 12 in order. Use "ID" instead of "Id" in the CarlaSettings ROS2 domain id display name so the editor label matches the wording used in the CLI option and documentation. * feat(LibCarla/ros2): fall back to ROS_DOMAIN_ID env var for the domain id Resolve the effective ROS 2 domain id in the middleware abstraction layer in priority order: the --ros-domain-id command line value, then the ROS_DOMAIN_ID environment variable, then the default domain 0. This lets the server pick up the standard ROS 2 environment variable when the option is not given, matching how other ROS 2 tools select a domain, while the option still takes precedence. MiddlewareConfig gains TryParseDomainId and ResolveDomainId (pure, unit-tested) plus GetEffectiveDomainId/ResolveEffective. FastDDS and CycloneDDS now use the resolved value, so both middlewares select the domain identically instead of CycloneDDS relying on DDS_DOMAIN_DEFAULT. The startup log reports the effective domain id and its source. Also rename the launch scripts' internal --ros-domain-id variable to ROS_DOMAIN_ID_ARG. The previous name shadowed the inherited ROS_DOMAIN_ID environment variable and reset it to empty for the launched editor, so an exported ROS_DOMAIN_ID was lost when starting CARLA through make launch. Add unit tests for parsing, precedence and the environment wrapper, and document the resolution order. * feat(LibCarla/ros2): apply the configured domain id to the Zenoh middleware zenoh_ros_domain_id() now uses the effective domain id resolved by MiddlewareConfig (--ros-domain-id, then ROS_DOMAIN_ID, then 0) instead of reading the environment variable directly, so the Zenoh keyexprs honor the same resolution order as the FastDDS and CycloneDDS participants. Adds keyexpr and resolution-order unit tests. (adapted from ue4-dev e78db15) (cherry picked from commit 0e6969a)
Description
CARLA's native ROS 2 integration always used a fixed ROS 2 domain. The domain participant was created with a hardcoded value (domain 0 for FastDDS, the DDS default for CycloneDDS), so there was no way to run CARLA on a custom domain or to keep several ROS 2 systems isolated on the same network.
This PR adds a new server option,
--ros-domain-id=<N>, that sets the ROS 2 domain id at startup. It follows the same pattern as the existing--rmwoption:The domain id is not tied to any specific DDS vendor. It is stored in the ROS 2 middleware abstraction layer (a small
MiddlewareConfighelper) and read by each middleware when it creates its transport context. FastDDS and CycloneDDS both honor it today, and any middleware added later (for example, a Zenoh backend) picks it up the same way. The requirement is documented on the publisher and subscriber middleware interfaces.When the option is not provided, the server falls back to the standard
ROS_DOMAIN_IDenvironment variable, and then to the default domain 0. The full resolution order is--ros-domain-id, thenROS_DOMAIN_ID, then 0. This matches how other ROS 2 tools select a domain and keeps the behavior backward-compatible, since domain 0 is still used when neither source is set. Values outside the valid range (0 to 232), from either source, are ignored and the next source is used.The rviz Docker example (
PythonAPI/examples/ros2/run_rviz.sh) now includes a matching--ros-domain-id=<N>option, allowing it to be run end-to-end on a custom domain. Both the example README and the command-line options documentation were updated.This addresses the request in #8853, which asks for a way to change the ROS_DOMAIN_ID in 0.10.0. The change is implemented here first against
ue4-dev(0.9.x), where the ROS 2 middleware abstraction layer already lives, and can be ported toue5-dev(0.10.0) afterward. The reference is kept as "Related to" rather than "Closes" so the issue stays open until the 0.10.0 port lands.Related to #8853
Where has this been tested?
Validation performed:
make check.LibCarla ARGS="--ros2"passes (debug and release), including new unit tests for the domain id configuration, string parsing, theROS_DOMAIN_IDfallback precedence, and range validation.--ros-domain-id=42: all CARLA topics and live data appear on domain 42 and nothing appears on domain 0.ROS_DOMAIN_ID=42with no option: topics appear on domain 42, confirming the environment-variable fallback.make launch ARGS="--ros2 --ros-domain-id=42": same result, confirming the flag is forwarded to the editor.Possible Drawbacks
A single domain id applies to the whole server process, which matches the current model of one shared transport context per middleware. There is no per-sensor or per-topic domain selection, and this is not expected to be needed.
This change is