feat(LibCarla/ros2): [1/3] add publisher durability QoS and latched OpenDRIVE map topic#9786
Conversation
|
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. |
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR adds ROS 2 “latched” map publication (OpenDRIVE) via configurable publisher QoS, and introduces a Docker-based ROS 2 demo that visualizes the map lane network and live sensors in RViz.
Changes:
- Publish the current map’s OpenDRIVE on
rt/carla/mapwith transient-local durability (re-published on episode start / map load). - Add publisher QoS plumbing across ROS 2 middlewares (FastDDS, CycloneDDS, Zenoh) plus tests for the new default QoS behavior.
- Add a one-command “map and lidar” ROS 2 demo stack (Docker, RViz preset, marker conversion + TF helper) and documentation.
Reviewed changes
Copilot reviewed 24 out of 24 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| Unreal/CarlaUE4/Plugins/Carla/Source/Carla/Game/CarlaEngine.cpp | Triggers ROS 2 map publish with OpenDRIVE string on episode start. |
| PythonAPI/test/smoke/test_ros2.py | Adds smoke coverage for world reload + map re-publish stability. |
| PythonAPI/examples/ros2/rviz/ros2_native.rviz | Adds map marker display and switches fixed frame to map. |
| PythonAPI/examples/ros2/run_map_and_lidar_demo.sh | New entry script to build/run the Docker demo stack. |
| PythonAPI/examples/ros2/ros2_native.py | Ensures SIGTERM in containers triggers cleanup via KeyboardInterrupt. |
| PythonAPI/examples/ros2/map_and_lidar_demo/map_to_markers.py | New node converting /carla/map OpenDRIVE into RViz MarkerArray. |
| PythonAPI/examples/ros2/map_and_lidar_demo/launcher.sh | New container entrypoint orchestrating helper processes and shutdown. |
| PythonAPI/examples/ros2/map_and_lidar_demo/ego_tf_broadcaster.py | New helper broadcasting map->hero TF using simulation time. |
| PythonAPI/examples/ros2/map_and_lidar_demo/cleanup.py | New helper to remove leftover demo actors and restore async mode. |
| PythonAPI/examples/ros2/map_and_lidar_demo/build.sh | New script to build the demo Docker image (wheel + helpers). |
| PythonAPI/examples/ros2/map_and_lidar_demo/Dockerfile | New Docker image extending RViz image with CARLA wheel + helpers. |
| PythonAPI/examples/ros2/README.md | Documents the demo, files, and usage flow. |
| LibCarla/source/test/server/test_ros2_middleware.cpp | Extends tests to validate default QoS + QoS propagation. |
| LibCarla/source/carla/ros2/publishers/PublisherImpl.h | Adds optional PublisherQos parameter to publisher initialization. |
| LibCarla/source/carla/ros2/publishers/CarlaMapPublisher.h | New publisher for latched OpenDRIVE map topic. |
| LibCarla/source/carla/ros2/publishers/CarlaMapPublisher.cpp | Implements CarlaMapPublisher::Write. |
| LibCarla/source/carla/ros2/middleware/zenoh/ZenohWireFormat.h | Adds QoS serialization for rmw_zenoh liveliness keyexprs. |
| LibCarla/source/carla/ros2/middleware/zenoh/ZenohPublisherMiddleware.h | Adds transient-local support via advanced publisher cache + fallback. |
| LibCarla/source/carla/ros2/middleware/fastdds/FastDDSPublisherMiddleware.h | Applies transient-local durability/history settings based on QoS. |
| LibCarla/source/carla/ros2/middleware/cyclonedds/CycloneDDSPublisherMiddleware.h | Applies transient-local durability/history settings based on QoS. |
| LibCarla/source/carla/ros2/middleware/PublisherQos.h | Introduces PublisherQos and DurabilityKind. |
| LibCarla/source/carla/ros2/middleware/IPublisherMiddleware.h | Updates publisher middleware interface to accept PublisherQos. |
| LibCarla/source/carla/ros2/ROS2.h | Adds map publisher member + ProcessDataFromMap API. |
| LibCarla/source/carla/ros2/ROS2.cpp | Implements OpenDRIVE map publishing and resets publisher on shutdown. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
|
Hello @youtalk. I added more PRs related to ROS2 and a plan in #9784. This time, the goal is to add missing topics and functions that already exist in the carla-ros-bridge project, which would add value if we move them into the internal carla ROS2 implementation. I want to know your opinion about them. I know @LuisPovedaCano will review these PRs later when he has time, but I'd value your opinion as a ROS2 expert. |
|
@JArmandoAnaya Thank you for your great works! I'll review them. |
|
Hi @JArmandoAnaya, thanks for your hard work! |
|
Hello @Blyron, don't worry, I understand. I hope that all is good on your side. I was working faster over the last few weeks because I'd just finished other projects and had time to work on Carla in my free time. I'm taking on more projects now, so I'll also be slower to send more PRs. I will be happy to keep helping with this porting. Thank you for your time. |
9bec6be to
6168f0a
Compare
youtalk
left a comment
There was a problem hiding this comment.
Clean, minimal way to add latched topics: the PublisherQos defaults reproduce the old behavior, and all three RMWs implement transient_local correctly — the Zenoh fallback even rewrites the advertised liveliness QoS so a transient_local subscriber won't falsely match. A few asks below to keep the QoS surface and the map topic robust for arbitrary ROS 2 consumers. One cross-cutting request for the series: please add Jazzy to the interop validation (the PR reports Humble only) — RIHS type hashes and CycloneDDS exist precisely so modern distros can discover and decode these topics, and Jazzy gates matching on the type hash.
|
@youtalk Thank you for your review. I will take a look today. Please excuse the delay; I was out the last week. |
|
@JArmandoAnaya Totally no problem. I really appreciate your usual fast-paced development. |
…map topic Publishers in the native ROS 2 layer can now request transient local durability, and each middleware (FastDDS, CycloneDDS, Zenoh) maps it to its own QoS so late-joining subscribers still receive the last sample. The first user is a new /carla/map topic that publishes the OpenDRIVE description of the current map on every map load, letting any ROS 2 node read the map at any time without connecting to the simulator.
…e markers in RViz A single command now runs a demo stack in Docker against a CARLA server started with --ros2. It spawns the hero vehicle on autopilot, converts the latched /carla/map OpenDRIVE into lane markers and broadcasts the map to hero transform, so RViz shows the camera, the lidar point cloud and the town lane network together in one world-fixed view. The stack cleans up after itself: stopping the container destroys the vehicle and its sensors, and a new run removes anything a previous unclean exit left behind.
Review feedback: history_depth was only honored for transient local publishers, while volatile ones silently kept a hardcoded depth of 1. The writer history is now set from the requested depth in every case, and the invalid depth 0 is clamped to 1 through a single helper used by all three middlewares. The defaults still produce the exact QoS every publisher had before.
Review feedback: python is not guaranteed to exist on modern systems, so the helpers now declare python3 directly. The waypoint cap in map_to_markers.py becomes a named constant and logs a warning when a lane is truncated by it.
…ensor streams Extend PublisherQos with a ReliabilityKind and a SensorData() profile. The default stays reliable, keeping the exact writer QoS every existing publisher had, while camera image/camera_info and point cloud topics (lidar, semantic lidar, radar, DVS) switch to best-effort delivery so a slow or vanished subscriber can never stall the publishing thread, the ROS 2 sensor-data idiom for high-rate streams. All three middlewares honor the new field: FastDDS and CycloneDDS set the writer reliability, Zenoh advertises it in the liveliness QoS segment (rmw enum value 2) that rmw_zenoh matches endpoints on. The bundled RViz preset switches its image and point cloud displays to best-effort so they keep matching.
std_msgs/String carries no Header and that is deliberate: it keeps rt/carla/map wire-compatible with the carla-ros-bridge /carla/map topic. Document the identity contract a late joiner can rely on instead of a stamp: the writer cache holds exactly one sample and the map is re-published on every episode start / map load, so the latched payload always describes the currently loaded map.
… config The zenoh-ext advanced-publisher cache backing transient_local latching only works on a session with timestamping enabled. The bundled session config already turns it on, but when that file cannot be loaded the zenoh default config does not, silently degrading latched topics such as rt/carla/map to volatile. Patch the fallback config so latching stays on by default.
6168f0a to
356d1f6
Compare
|
The last comments and recommendations from @youtalk were applied. The PR is ready for code review. |
Description
The native ROS 2 interface streams sensor data well, but everything it publishes is volatile: a node that joins after the simulation has started has no way to learn anything about the world it is observing. The most basic piece of that picture is the map itself.
This PR teaches the publisher layer about durability. A publisher can now request transient local delivery, and each middleware (FastDDS, CycloneDDS and Zenoh) translates that into its own QoS, so the last sample is retained and delivered to late-joining subscribers. The default behavior of every existing topic is unchanged.
The first topic built on top of it is
/carla/map, which carries the full OpenDRIVE description of the current map and is refreshed on every map load. Any ROS 2 node can read it at any time, with no connection to the simulator:ros2 topic echo --qos-durability transient_local --once /carla/mapTo show what that enables, the PR also adds a small example. A single command runs a demo stack in Docker against a server started with
--ros2: it spawns the hero vehicle on autopilot, converts the latched map into lane markers and broadcasts the map to hero transform, so RViz displays the camera, the lidar point cloud and the town lane network together in one world-fixed view.The demo stack cleans up after itself: stopping the container destroys the vehicle and its sensors, and a new run removes anything left behind by a previous unclean exit.
Related to #9784 (first part of the series; ego vehicle topics and traffic lights follow in separate PRs, the last of which updates the CHANGELOG).
Preview
Where has this been tested?
Validation:
make check.LibCarla ARGS="--ros2"passes (140 server + 66 client tests, debug and release),make CarlaUE4Editorbuilds, full package build with--ros2passes the ROS 2 smoke tests, and a late-joiningros2 topic echoreceives the latched map on all three--rmw=middlewares. The demo was run end-to-end against the packaged server and verified in RViz on ROS 2 Humble.Possible Drawbacks
The latched map sample is kept in the middleware history, which holds the OpenDRIVE string (around 2 MB for the stock towns) in memory for the lifetime of the episode. On Zenoh, if the advanced publisher cache cannot be created, the publisher falls back to volatile delivery and logs a warning, so late joiners would not receive the map.
This change is