feat(LibCarla/ros2): [2/7] add POD message types, FastDDS conversions, and TypeMap specializations - #9612
Merged
LuisPovedaCano merged 3 commits intoApr 8, 2026
Conversation
…ackend support Introduce a strategy-pattern abstraction that decouples PublisherImpl and SubscriberImpl from the FastDDS API, enabling future integration of additional DDS middleware implementations (e.g. CycloneDDS). New abstraction layer (LibCarla/source/carla/ros2/dds/): - DDSMiddleware enum and string conversion utilities - IDDSPublisherMiddleware / IDDSSubscriberMiddleware pure virtual interfaces - DDSMiddlewareFactory with thread-safe middleware selection and creation - FastDDSPublisherMiddleware<T> / FastDDSSubscriberMiddleware<S> template implementations behind the new interfaces - FastDDSTypeMap<T> identity-mapping type traits (to be replaced with real conversions when POD message types are introduced) Modified files: - PublisherImpl.h: replaced direct FastDDS inheritance and members with delegation to IDDSPublisherMiddleware via the factory (public API unchanged) - SubscriberImpl.h: same pattern for subscriber side - cmake/fast_dds/CMakeLists.txt: added CARLA_ROS2_DDS_FASTDDS compile definition, new header globs, and fixed missing include directories in the debug build target No behavior change — FastDDS remains the only compiled middleware. Concrete publishers and subscribers are unaffected.
…real TypeMap specializations Introduce backend-neutral POD message structs and to_fastdds/from_fastdds conversion functions, completing the type abstraction layer started in PR carla-simulator#1 without touching any concrete publisher or subscriber. New files (LibCarla/source/carla/ros2/types/): - 31 plain C++ structs in types/msg/ - one per ROS2 message type, no DDS dependency, standard library headers only, all members value-initialized - FastDDSConversions.h: inline to_fastdds/from_fastdds overload pairs for all 31 type pairs, ordered bottom-up so composites call primitives; move overloads for msg::Image and msg::PointCloud2 to avoid copying large data vectors New test file (LibCarla/source/test/server/test_dds_middleware.cpp): - 45 unit tests across 10 groups covering the middleware enum, factory, interfaces, PublisherImpl, and SubscriberImpl using hand-written mocks; no DDS daemon required (CARLA_ROS2_DDS_TESTING suppresses real includes) Modified files: - FastDDSTypeMap.h: 28 real specializations mapping msg::X to FastDDS types, coexisting with the existing identity specializations (different key types, no ODR conflict) - DDSMiddleware.h: add ToROS2DDSTypeName() for use in PR carla-simulator#3 - DDSMiddlewareFactory.h: add CARLA_ROS2_DDS_TESTING guard to FastDDS include/create blocks so test binary compiles without real DDS headers - PublisherImpl.h / SubscriberImpl.h: LIBCARLA_WITH_GTEST test seams for middleware injection and message simulation - cmake/fast_dds/CMakeLists.txt: added glob for types/msg/*.h install No behavior change - identity TypeMap specializations remain active; all concrete publishers and subscribers compile and work unchanged.
|
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. |
This was referenced Mar 30, 2026
Merged
5 tasks
This was referenced Apr 6, 2026
Contributor
|
I've been looking the changes, this looks good to me. Please resolve the conflicts. |
JArmandoAnaya
marked this pull request as ready for review
April 7, 2026 17:04
Contributor
Author
|
@LuisPovedaCano, Done! |
germanros1987
pushed a commit
that referenced
this pull request
Aug 19, 2026
Introduce the middleware-neutral type layer of the ROS 2 middleware decoupling series, ported from ue4-dev: - types/msg/*.h: 31 plain C++ structs, one per ROS 2 message type, no DDS dependency, standard library headers only, all members value-initialized (upstream ue4-dev #9612). - types/CdrSerialization.h: serialize_to_cdr(), deserialize_from_cdr() and cdr_serialized_size() for all msg::* types using Fast-CDR (classic CDR, little-endian, DDS encapsulation header). The buffers are wire-compatible with every ROS 2 distribution and can be handed directly to FastDDS write() paths or CycloneDDS dds_writecdr(), removing the need for per-vendor generated type files. A kMaxCdrSequenceElements cap rejects hostile sequence lengths during deserialization (upstream ue4-dev #9643). - types/CdrTopicInfo.h: per-type type_name(), REP-2011 RIHS01 type hash and max_serialized_size(); the hashes let ROS 2 Iron and newer RMWs parse the type hash CARLA advertises via USER_DATA (upstream ue4-dev #9681). - types/UserDataFormat.h: build_user_data() / build_user_data_for<T>() helpers producing the REP-2016 "typehash=RIHS01_<hex>;" key-value payload (upstream ue4-dev #9681). UE5 adaptation: ue5-dev pins FastDDS 2.11.2 with bundled Fast-CDR 1.x, so CdrSerialization.h keeps the Fast-CDR 1.x spellings (eprosima::fastcdr::Cdr::DDS_CDR, getSerializedDataLength()) instead of the Fast-CDR 2.x forms the ue4-dev tip carries since its Fast-DDS 2.14.6 upgrade (ue4-dev #9789). Five lines differ; the wire format is identical either way and is pinned by the golden-bytes test added in the follow-up test commit. The FastDDSConversions.h / FastDDSTypeMap.h files from #9612 are deliberately not ported; they were superseded by unified CDR upstream. The new headers are not referenced by any build target yet; they start compiling when the middleware abstraction lands in the next PR of the series. (adapted from ue4-dev 542959a) (adapted from ue4-dev f53144c) (adapted from ue4-dev c64e8f4) (adapted from ue4-dev b865088) (cherry picked from commit 5d0d578)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Introduce backend-neutral POD message structs and
to_fastdds/from_fastddsconversion functions, completing the type abstraction layer started in PR # 1 - without touching any concrete publisher or subscriber.New files (
LibCarla/source/carla/ros2/types/):types/msg/- one per ROS2 message type, no DDS dependencyFastDDSConversions.h- inlineto_fastdds/from_fastddsoverloads for all 31 type pairs, with move overloads forImageandPointCloud2New test file:
LibCarla/source/test/server/test_dds_middleware.cpp- 45 unit tests across 10 groups covering the middleware enum, factory, interfaces,PublisherImpl, andSubscriberImplModified files:
FastDDSTypeMap.h: real specializations mappingmsg::Xto FastDDS types, alongside the existing identity specializationsDDSMiddleware.h: addToROS2DDSTypeName()utility for use in PR CARLA takes forever to start when run from a network folder #3DDSMiddlewareFactory.h: add&& !defined(CARLA_ROS2_DDS_TESTING)guard to FastDDS include/create blocks so tests compile without real DDS headersPublisherImpl.h/SubscriberImpl.h:#ifdef LIBCARLA_WITH_GTESTtest seams for middleware injectioncmake/fast_dds/CMakeLists.txt: added glob fortypes/msg/*.hinstallNo behavior change - identity TypeMap specializations remain active; all concrete publishers and subscribers compile and work unchanged. Real POD specializations exist but are unused until PR #2b.
Description
This PR introduces the type abstraction layer that decouples ROS2 message data from FastDDS-generated types. It is the second in the PR series that incrementally implements the decoupled DDS middleware architecture originally prototyped in draft PR #9589.
The key step here is replacing FastDDS-generated structs (with their getter/setter API) with plain C++ structs (
msg::X) that have no DDS dependency. The FastDDS middleware receives these POD values and converts them internally viato_fastdds/from_fastdds- a pattern that will work identically for CycloneDDS in PR #3.These changes do not affect current behavior. The identity
FastDDSTypeMapspecializations remain active, so all concrete publishers and subscribers continue to use FastDDS types directly until PR #2b switches them over.What's new
31 POD message structs (
LibCarla/source/carla/ros2/types/msg/):Plain C++ structs in
namespace carla::ros2::msg, one per ROS2 message type. Each struct has no dependency on FastDDS, CycloneDDS, or any DDS library - only standard library headers. All members are value-initialized.Time.hbuiltin_interfaces/Timeint32_t sec,uint32_t nanosecHeader.hstd_msgs/HeaderTime stamp,std::string frame_idVector3.hgeometry_msgs/Vector3double x, y, zQuaternion.hgeometry_msgs/Quaterniondouble x, y, z, wPoint.hgeometry_msgs/Pointdouble x, y, zPoint32.hgeometry_msgs/Point32float x, y, zFloat32.hstd_msgs/Float32float dataString.hstd_msgs/Stringstd::string dataPose.hgeometry_msgs/PosePoint position,Quaternion orientationPoseWithCovariance.hgeometry_msgs/PoseWithCovariancePose,std::array<double, 36>Twist.hgeometry_msgs/TwistVector3 linear, angularTwistWithCovariance.hgeometry_msgs/TwistWithCovarianceTwist,std::array<double, 36>Transform.hgeometry_msgs/TransformVector3 translation,Quaternion rotationTransformStamped.hgeometry_msgs/TransformStampedHeader,child_frame_id,TransformOdometry.hnav_msgs/OdometryHeader,PoseWithCovariance,TwistWithCovarianceRegionOfInterest.hsensor_msgs/RegionOfInterestbool do_rectifyPointField.hsensor_msgs/PointFieldstd::string name, offset, datatype, countNavSatStatus.hsensor_msgs/NavSatStatusint8_t status,uint16_t serviceNavSatFix.hsensor_msgs/NavSatFixHeader,NavSatStatus, lat/lon/alt, covarianceClock.hrosgraph_msgs/ClockTime clockImu.hsensor_msgs/ImuHeader, orientation + angular velocity + linear acceleration with covariancesImage.hsensor_msgs/ImageHeader, dimensions, encoding,std::vector<uint8_t> dataCameraInfo.hsensor_msgs/CameraInfoHeader, dimensions, distortion model, K/R/P matrices,RegionOfInterest roiPointCloud2.hsensor_msgs/PointCloud2Header,std::vector<PointField>,std::vector<uint8_t> dataTFMessage.htf2_msgs/TFMessagestd::vector<TransformStamped>TF2Error.htf2_msgs/TF2Erroruint8_t error,std::string error_stringAckermannDrive.hackermann_msgs/AckermannDriveAckermannDriveStamped.hackermann_msgs/AckermannDriveStampedHeader,AckermannDrive driveCarlaCollisionEvent.hcarla_msgs/CarlaCollisionEventHeader,uint32_t other_actor_id,Vector3 normal_impulseCarlaEgoVehicleControl.hcarla_msgs/CarlaEgoVehicleControlHeader, throttle/steer/brake/gear/boolsCarlaLineInvasion.hcarla_msgs/LaneInvasionEventHeader,int32_t crossed_lane_markingsConversion functions (
types/FastDDSConversions.h):Inline
to_fastdds()/from_fastdds()overload pairs for all 31 type pairs, ordered bottom-up so composites can call primitives. Move overloads are provided formsg::Imageandmsg::PointCloud2to avoid copying largestd::vector<uint8_t>data buffers when the source is mutable.Real
FastDDSTypeMapspecializations (dds/fastdds/FastDDSTypeMap.h):26 new template specializations alongside the existing identity specializations. Both sets coexist because they key on different types -
msg::Imagevssensor_msgs::msg::Image- so there is no ambiguity and no ODR violation.ToROS2DDSTypeName()utility (dds/DDSMiddleware.h):Mangles a C++ type name into the ROS2-compatible DDS format (
"sensor_msgs::msg::Image"→"sensor_msgs::msg::dds_::Image_"). Added for use in PR #3 when PubSubTypes are regenerated with unmangled names. Not applied inInit()methods in this PR - current auto-generated PubSubTypes already return mangled names fromgetName().Test seams (
publishers/PublisherImpl.h,subscribers/SubscriberImpl.h):#ifdef LIBCARLA_WITH_GTESTguards expose middleware injection for unit tests:SetMiddlewareForTesting(std::unique_ptr<IDDSPublisherMiddleware>)- inject a mock publisherSetMiddlewareForTesting(std::unique_ptr<IDDSSubscriberMiddleware>)- inject a mock subscriberSimulateMessageReceiptForTesting(const msg_type&)- write directly to internal message storageAdded early so PR #2b's publisher/subscriber changes can be validated in unit tests without a running DDS network.
Unit tests (
LibCarla/source/test/server/test_dds_middleware.cpp):45 tests across 10 groups using GoogleTest and hand-written mocks. The test file defines
CARLA_ROS2_DDS_TESTINGto suppress real DDS includes (no DDS daemon required), while keepingCARLA_ROS2_DDS_FASTDDSdefined so availability checks exercise their real compile-time logic.dds_middleware_enumdds_middleware_to_stringdds_middleware_from_stringdds_middleware_availabledds_middleware_type_nameToROS2DDSTypeName()manglingDDSMiddlewareFactoryFixturedds_publisher_interfacedds_subscriber_interfacepublisher_implPublisherImpldelegation and data flowsubscriber_implSubscriberImpldelegation and flag behaviorDesign decisions
FastDDSTypeMap<sensor_msgs::msg::Image>) and real POD specializations (FastDDSTypeMap<msg::Image>) key on different types, so both sets compile and coexist with no conflict until identity specializations are removed in PR #2bToROS2DDSTypeNamedeferred - current auto-generated PubSubTypes already callsetName()with the mangled format (e.g.,"sensor_msgs::msg::dds_::NavSatFix_"); applying the function now would double-mangle. It will be used in PR CARLA takes forever to start when run from a network folder #3 when PubSubTypes are regeneratedFastDDSConversions.huses the existing flattypes/Image.hpaths rather than a reorganizedtypes/fastdds/layout; reorganization is deferred to avoid scope creepCARLA_ROS2_DDS_TESTINGguard in factory -DDSMiddlewareFactory.hincludes/creates FastDDS middleware only whenCARLA_ROS2_DDS_TESTINGis not defined; availability checks (IsMiddlewareAvailable,GetAvailableMiddlewareString) are unaffected and reflect the real compile-time statePR series
This PR is part of the DDS middleware decoupling series (#9294). Each PR in the chain inherits the commits of all prior PRs. The Commits column lists only the commits introduced by that PR, and the Files column counts only the files changed by those new commits.
feature/dds-middleware-abstraction-layer0ab35ee6feature/ros2-pod-types-and-fastdds-conversionse665d2affeature/ros2-publishers-pod-types-migration98b6f7aafeature/ros2-cyclonedds-enum-factory2a4a8db3GenericCdrPubSubTypefeature/ros2-cdr-serialization5a9dd3b4,0a9ca585feature/ros2-cyclonedds-cdr-middlewared3f2a45b,2d80046bfeature/ros2-remove-fastdds-generated-typeseea4e0a4Related
Fixes #9294
Where has this been tested?
Possible Drawbacks
FastDDSTypeMapspecializations exist but are unused - the identity specializations remain active. This is a deliberate transitional state.Compilation steps
Test plan
make LibCarla ARGS="--ros2"compiles successfullymake check.LibCarlapasses (90/90 tests: 45 existing + 45 new DDS middleware tests)--gtest_filter='*dds_middleware*:*DDSMiddleware*:*publisher_impl*:*subscriber_impl*:*publisher_interface*:*subscriber_interface*'.cppfiles were modifiedThis change is