rmw_connextdds 源码详细分析
工作区路径:/home/cp/work2/ros2Learn/ros2_humble/src/ros2/rmw_connextdds
版本:0.11.6(Humble),子包 4 个,构建类型 ament_cmake,语言 C/C++,许可证 Apache 2.0。
rmw_connextdds 是 RTI 提供的 ROS 2 RMW 实现,将标准 rmw_* C API 映射到 RTI Connext DDS Professional(rmw_connextdds)或 RTI Connext DDS Micro(rmw_connextddsmicro)。它替代旧版 rmw_connext_cpp,在性能与跨厂商互操作方面做了大量改进。
外部依赖:本仓库 不包含 Connext DDS 本体。构建与运行需安装 RTI Connext,并通过
CONNEXTDDS_DIR/NDDSHOME(Professional)或RTIMEHOME(Micro)指向安装路径;未检测到安装时对应包会被 跳过编译。
上游 README:rmw_connextdds
1. 总体认识
1.1 核心职责
| 能力 | 说明 |
|---|---|
| RMW 符号实现 | 导出全部 rmw_* 函数(经薄封装层) |
| DDS 实体管理 | DomainParticipant、Publisher/Subscriber、DataWriter/DataReader |
| 类型系统 | 基于 Fast-CDR + rosidl typesupport 注册 DDS 类型(Pro 用 TypePlugin/TypeCode) |
| Graph 发现 | 集成 rmw_dds_common,维护 ROS 2 图缓存 |
| Service/Client | DDS-RPC basic/extended 映射,可配置跨厂商互操作 |
| QoS 策略 | ROS QoS ↔ Connext QoS,支持 XML profile 与运行时环境变量 |
| 双后端共享 | rmw_connextdds_common 承载 ~16K 行公共 C++ 逻辑 |
1.2 在 ROS 2 栈中的位置
| 对比项 | rmw_connextdds | rmw_cyclonedds_cpp | rmw_fastrtps_cpp |
|---|---|---|---|
| DDS 产品 | RTI Connext Pro/Micro | Eclipse CycloneDDS | eProsima Fast-DDS |
| 实现语言 | C++ | C++ | C++ |
| Graph 共享 | rmw_dds_common |
rmw_dds_common |
自有 + 部分 common |
| 序列化 | Fast-CDR typesupport | 自有 CDR | Fast-CDR |
| 默认 Humble RMW | 否(需显式选择) | 可选 | 是 |
1.3 分层设计(读源码入口)
1 | rmw.h 符号 |
Micro 版将第一层替换为 rmw_connextddsmicro/src/rmw_api_impl_rtime.cpp,链接 rmw_connextdds_common_micro 而非 _pro。
2. 子包结构
1 | rmw_connextdds/ |
| 包 | 版本 | 产出 | 职责 |
|---|---|---|---|
rti_connext_dds_cmake_module |
— | CMake 模块 | rti_find_connextpro()、rti_find_connextmicro() |
rmw_connextdds_common |
0.11.6 | librmw_connextdds_common_pro / _micro |
全部 RMW 逻辑(编译宏区分后端) |
rmw_connextdds |
0.11.6 | librmw_connextdds.so |
导出 rmw_*,identifier="rmw_connextdds" |
rmw_connextddsmicro |
0.11.6 | librmw_connextddsmicro.so |
同上,identifier="rmw_connextddsmicro" |
2.1 依赖关系(rmw_connextdds_common/package.xml)
1 | rmw_connextdds_common |
Typesupport 注册(rmw_connextdds/CMakeLists.txt):
1 | register_rmw_implementation( |
与 Cyclone/FastRTPS 后端一样,同时支持 fastrtps 与 introspection 两套 typesupport。
3. 构建系统
3.1 条件编译与跳过
rmw_connextdds_common/CMakeLists.txt 通过 rti_find_connextpro() / rti_find_connextmicro() 探测安装:
- 找到 Pro → 构建
rmw_connextdds_common_pro(链RTIConnextDDS::c_api) - 找到 Micro → 构建
rmw_connextdds_common_micro+ 辅助库rti_connextdds_micro_ext - 两者皆无 → 仅
ament_package(),不产出 RMW 库
rmw_connextdds 包额外检查 TARGET rmw_connextdds_common::rmw_connextdds_common_pro,不存在则跳过。
3.2 编译宏区分后端
| 宏 | Pro | Micro |
|---|---|---|
RMW_CONNEXT_DDS_API |
RMW_CONNEXT_DDS_API_PRO |
RMW_CONNEXT_DDS_API_MICRO |
RMW_CONNEXTDDS_ID |
"rmw_connextdds" |
"rmw_connextddsmicro" |
| 默认 RPC 映射 | Extended | Basic |
| Security | 默认启用编译选项 | 可选 RMW_CONNEXT_ENABLE_SECURITY |
| 大对象优化 | 默认开 | 同 common 逻辑 |
dds_api.hpp 根据宏 include 不同头文件:
1 |
3.3 Connext 路径变量
| 变量 | 用途 |
|---|---|
CONNEXTDDS_DIR |
Pro 安装路径(优先于 NDDSHOME) |
NDDSHOME |
Pro 传统变量;apt 版 rmw_connext_cpp 可能硬编码 |
RTIMEHOME |
Micro 安装路径;Pro 6.x 可自动猜测 bundled Micro |
rti_connext_dds_cmake_module 还提供 env_hook/rti_connext_dds.sh.in 等脚本,在 source install/setup.bash 时注入库路径。
4. 核心数据结构
4.1 rmw_context_impl_t
在 context.hpp 中定义(对应 rmw/init.h 中的不透明 rmw_context_impl_t):
1 | struct rmw_context_impl_s { |
设计要点:
- 延迟创建 Participant:第一个
rmw_create_node时才真正创建并 enable DomainParticipant(node_count从 0→1)。 - 同一 context 内所有 node 必须 localhost_only 一致,否则
initialize_node失败。 rmw_dds_common::Context嵌入 graph 状态,与 Cyclone/FastRTPS 新实现路径一致。
4.2 实体实现类(rmw_impl.hpp)
| C++ 类 | 对应 rmw 句柄 | DDS 实体 |
|---|---|---|
RMW_Connext_Node |
rmw_node_t |
逻辑节点(无独立 Participant) |
RMW_Connext_Publisher |
rmw_publisher_t |
Topic + DataWriter |
RMW_Connext_Subscriber |
rmw_subscription_t |
Topic + DataReader |
RMW_Connext_Service |
rmw_service_t |
请求 Subscription + 响应 Publisher |
RMW_Connext_Client |
rmw_client_t |
请求 Publisher + 响应 Subscription |
RMW_Connext_GuardCondition |
rmw_guard_condition_t |
DDS GuardCondition |
RMW_Connext_StdWaitSet |
rmw_wait_set_t |
DDS WaitSet + 条件 attach 管理 |
每个 rmw_*_t->data 指向对应 C++ 对象;implementation_identifier 为 RMW_CONNEXTDDS_ID。
4.3 全局工厂引用
1 | DDS_DomainParticipantFactory * RMW_Connext_gv_DomainParticipantFactory = nullptr; |
首个 context init 时设置工厂 QoS(autoenable_created_entities = false);最后一个 context fini 且所有 node 销毁后重置。注释指出 context 创建非线程安全(与 rcl 层假设一致)。
5. 生命周期
5.1 rmw_init 流程(rmw_context.cpp)
1 | rmw_api_connextdds_init() |
rmw_shutdown / rmw_context_fini 逆序:停止 discovery 线程 → 销毁 graph 实体 → finalize participant → 递减全局计数。
5.2 Node 与 Participant 关系
与 CycloneDDS RMW 类似,多个 ROS node 共享一个 DomainParticipant(同一 rmw_context_t):
RMW_Connext_Node::create仅增加node_count并注册 graph- Participant 在首个 node 创建时
initialize_participant+enable_participant - 最后一个 node destroy 且 count 归零时 tear down participant
6. Topic 命名与 Demangle
6.1 ROS → DDS Topic 映射
前缀常量(demangle.cpp / rmw_impl.cpp):
| ROS 语义 | 前缀 | 示例 |
|---|---|---|
| Topic | rt |
/foo → rt/foo |
| Service 请求 | rq + Request 后缀 |
/add → rq/addRequest |
| Service 响应 | rr + Response 后缀 |
/add → rr/addResponse |
RMW_Connext_Publisher::create 中:
- 若 topic 已含
rq/或rr/前缀,直接使用(service 内部 topic) - 否则调用
rmw_connextdds_create_topic_name(ROS_TOPIC_PREFIX, topic_name, ...)
avoid_ros_namespace_conventions=true 时跳过 rt 前缀,用于直连原生 DDS topic。
6.2 Demangle(demangle.cpp)
_demangle_if_ros_topic:去掉rt/、rq/、rr/恢复 ROS 图名_demangle_if_ros_type:将pkg::msg::dds_::Type_还原为 ROS 类型名- 供 graph introspection、
ros2 topic list等使用
6.3 内部 Discovery Topic
rmw_graph.cpp 创建内部 publisher/subscription:
- Topic 名:
ros_discovery_info(avoid_ros_namespace_conventions=true) - 消息类型:
rmw_dds_common::msg::ParticipantEntitiesInfo - QoS:TRANSIENT_LOCAL + RELIABLE(pub depth=1,sub KEEP_ALL)
7. 类型支持与序列化
7.1 RMW_Connext_MessageTypeSupport
核心类(type_support.hpp),不使用 Connext 代码生成器,而是:
- 从
rosidl_message_type_support_t取 fastrtps typesupport 的message_type_support_callbacks_t - 用 introspection 计算
_serialized_size_max、是否 unbounded - Pro 版:构建 PRESTypePlugin + DDS TypeCode(
rmw_type_support_ndds.cpp) - Micro 版:简化类型注册(
rmw_type_support_rtime.cpp)
消息类别枚举:
1 | enum RMW_Connext_MessageType { |
Service 的 request/reply 在 CDR 前附加 RequestReply 头(RMW_Connext_RequestReplyMessage:gid + sequence number),映射方式由 request_reply_mapping 控制。
7.2 序列化格式
1 | // ndds/dds_api_ndds.cpp |
rmw_serialize / rmw_deserialize(rmw_serde.cpp)临时构造 RMW_Connext_MessageTypeSupport,调用 Fast-CDR 回调写入 rmw_serialized_message_t。
rmw_get_serialized_message_size 当前返回 RMW_RET_UNSUPPORTED。
7.3 Professional 特有:Content Filter Topic
custom_sql_filter.cpp + rmw_connextdds_create_contentfilteredtopic 实现 Content Filtered Topic(订阅端内容过滤),对应 rmw_subscription_set_content_filter。Micro 版部分 CFT API 返回 unsupported。
7.4 大消息优化
当 _serialized_size_max >= 1MB(RMW_CONNEXT_LARGE_DATA_MIN_SERIALIZED_SIZE)且未禁用优化时:
- 调整 RTPS reliability 协议参数(heartbeat 周期、send window)
- Pro 版默认
DDS_ASYNCHRONOUS_PUBLISH_MODE_QOS(可用RMW_CONNEXT_USE_DEFAULT_PUBLISH_MODE关闭)
8. 发布与订阅数据路径
8.1 发布
1 | rmw_api_connextdds_publish() |
rmw_publish_serialized_message 传入已序列化 buffer,跳过 ros 消息序列化步骤。
8.2 订阅
1 | rmw_api_connextdds_take() / take_with_info() |
还支持 take_serialized_message、take_sequence;loaned message 系列 API 返回 RMW_RET_UNSUPPORTED。
8.3 Graph 钩子
创建/销毁 pub/sub/service/client 时调用 graph_cache.hpp 中:
rmw_connextdds_graph_on_publisher_created/deleted- 更新
rmw_dds_common::GraphCache并rmw_connextdds_graph_publish_update广播
9. Service / Client 与 RPC 映射
9.1 DDS-RPC 两种 Profile
| Profile | 机制 | 默认 |
|---|---|---|
| Basic | 请求头(GUID+SN)inline 序列化在 payload 前 | Micro |
| Extended | 使用 DDS SampleIdentity 等元数据 | Pro |
环境变量 RMW_CONNEXT_REQUEST_REPLY_MAPPING=basic|extended 覆盖默认。
9.2 跨 RMW 互操作
| 目标 | 配置 |
|---|---|
rmw_fastrtps_cpp |
Pro + extended(默认) |
rmw_connextddsmicro |
两侧 basic |
rmw_cyclonedds_cpp |
RMW_CONNEXT_CYCLONE_COMPATIBILITY_MODE=y(非标准 basic 变体) |
Cyclone 默认 pub/sub 可互通,但 service/client 不互通(除非开兼容模式)。
9.3 实现类方法
RMW_Connext_Client::send_request/take_responseRMW_Connext_Service::take_request/send_responseclient_service_id在 context 内递增,用于构造唯一 GUID 后缀
10. Graph 与 Discovery
10.1 双通道发现
- ParticipantEntitiesInfo(与 Cyclone/FastRTPS 共用设计):节点/endpoint 增删时发布更新。
- Builtin topic readers(
dr_participants等):监听远端 DDS 参与者与 endpoint,填充 graph。
10.2 Discovery 线程(rmw_discovery.cpp)
独立线程 rmw_connextdds_discovery_thread:
- 创建 DDS_WaitSet,attach DCPS reader 的 DATA_AVAILABLE 条件
- attach
ros_discovery_infosubscriber 与退出 GuardCondition - 循环
DDS_WaitSet_wait,分发到graph_cache更新函数 - context shutdown 时 trigger exit guard,join 线程
10.3 Graph API
rmw_info.cpp、rmw_graph.cpp 实现:
rmw_get_node_names/with_enclavesrmw_get_topic_names_and_typesrmw_get_publishers_info_by_topic等
底层读取 ctx->common.graph_cache(rmw_dds_common),demangle topic/type 名后返回。
11. Wait Set 实现
11.1 RMW_Connext_StdWaitSet(rmw_waitset_std.hpp + rmw_impl_waitset_std.cpp)
rmw_wait 流程:
- 遍历
rmw_subscriptions_t等数组,将每个有效RMW_Connext_Subscriber的 StatusCondition 或 ReadCondition attach 到 WaitSet - Service/Client 的 request/response reader 同理
- GuardCondition、Event 条件一并 attach
DDS_WaitSet_wait(wait_timeout)- 未触发的条目在数组中置 NULL(符合 rmw 契约)
11.2 事件与 Listener
QoS 事件(rmw_event.cpp)通过 RMW_Connext_SubscriberStatusCondition / PublisherStatusCondition 映射 DDS status:
| rmw_event_type | DDS Status |
|---|---|
RMW_EVENT_REQUESTED_QOS_INCOMPATIBLE |
REQUESTED_INCOMPATIBLE_QOS_STATUS |
RMW_EVENT_LIVELINESS_CHANGED |
LIVELINESS_CHANGED_STATUS |
RMW_EVENT_MESSAGE_LOST |
SAMPLE_LOST_STATUS(若支持) |
DataReader listener 回调更新 condition 计数,供 rmw_take_event 读取。
12. QoS 处理
12.1 默认 XML Profile
编译期默认 QoS 库名:RMW_CONNEXT_DEFAULT_QOS_LIBRARY = "ros2"(static_config.hpp)。
rmw_connextdds_get_datawriter_qos / get_datareader_qos(dds_api_*.cpp):
- 从 Connext QoS Profile 加载 topic 默认值(支持 topic filter)
- 根据
endpoint_qos_override_policy决定是否叠加 ROSrmw_qos_profile_t - 应用大消息优化、异步 publish 等 RMW 策略
12.2 Override 策略
| 环境变量 | 值 | 行为 |
|---|---|---|
RMW_CONNEXT_PARTICIPANT_QOS_OVERRIDE_POLICY |
all / basic / never |
控制 Participant QoS 修改幅度 |
RMW_CONNEXT_ENDPOINT_QOS_OVERRIDE_POLICY |
always / never / dds_topics: <regex> |
控制 DataWriter/Reader QoS |
rmw_api_connextdds_qos_profile_check_compatible 直接委托 rmw_dds_common::qos_profile_check_compatible(rmw_qos.cpp)。
13. 运行时环境变量
(详见仓库 README.md,此处汇总与源码对应关系)
| 环境变量 | 作用 |
|---|---|
RMW_IMPLEMENTATION |
选择 rmw_connextdds 或 rmw_connextddsmicro |
RMW_CONNEXT_CYCLONE_COMPATIBILITY_MODE |
Service 与 Cyclone 互操作 |
RMW_CONNEXT_REQUEST_REPLY_MAPPING |
basic / extended |
RMW_CONNEXT_LEGACY_RMW_COMPATIBILITY_MODE |
与旧 rmw_connext_cpp 类型名兼容(_ 后缀) |
RMW_CONNEXT_DISABLE_LARGE_DATA_OPTIMIZATIONS |
关闭 ≥1MB 类型自动调优 |
RMW_CONNEXT_DISABLE_FAST_ENDPOINT_DISCOVERY |
关闭 Fast endpoint discovery snippet |
RMW_CONNEXT_USE_DEFAULT_PUBLISH_MODE |
不强制异步 publish(Pro) |
RMW_CONNEXT_INITIAL_PEERS |
覆盖 discovery initial_peers(Micro 常用) |
RMW_CONNEXT_UDP_INTERFACE |
Micro UDP 网卡(默认 lo) |
RMW_CONNEXT_ENDPOINT_QOS_OVERRIDE_POLICY |
Endpoint QoS 覆盖策略 |
RMW_CONNEXT_PARTICIPANT_QOS_OVERRIDE_POLICY |
Participant QoS 覆盖策略 |
14. 模块与源文件对照
14.1 src/common/(双后端共享)
| 文件 | 职责 |
|---|---|
rmw_context.cpp |
init/shutdown、Participant 生命周期、环境变量解析 |
rmw_impl.cpp |
Publisher/Subscriber/Client/Service 类实现、topic 创建 |
rmw_publication.cpp |
rmw_publish* API 层 |
rmw_subscription.cpp |
rmw_create_subscription、rmw_take* |
rmw_service.cpp |
Service/Client CRUD 与 request/response |
rmw_waitset.cpp |
guard condition、waitset CRUD API |
rmw_impl_waitset_std.cpp |
WaitSet attach/wait 核心逻辑 |
rmw_graph.cpp |
Graph 初始化、DCPS 回调、entity 增删 |
rmw_discovery.cpp |
Discovery 后台线程 |
rmw_info.cpp |
Graph introspection API |
rmw_event.cpp |
QoS 事件 init/take/callback |
rmw_listener.cpp |
DataReader/DataWriter listener 桥接 |
rmw_qos.cpp |
QoS 兼容性检查(委托 dds_common) |
rmw_serde.cpp |
serialize/deserialize |
rmw_type_support.cpp |
类型注册公共逻辑 |
demangle.cpp |
Topic/类型 demangle |
rmw_security_log.cpp |
SROS2 安全日志转发 |
rmw_network_flow_endpoints.cpp |
未实现(返回 UNSUPPORTED) |
14.2 src/ndds/(Professional)
| 文件 | 职责 |
|---|---|
dds_api_ndds.cpp |
Pro 专用 QoS、Participant 配置、CFT |
rmw_type_support_ndds.cpp |
PRESTypePlugin、TypeCode、样本池 |
rmw_typecode.cpp |
TypeCode 构建与缓存 |
custom_sql_filter.cpp |
Content Filter SQL 表达式 |
14.3 src/rtime/(Micro)
| 文件 | 职责 |
|---|---|
dds_api_rtime.cpp |
Micro Participant/Transport 配置 |
rmw_type_support_rtime.cpp |
简化类型注册 |
rtime_ext.c |
Micro API 扩展 shim |
15. 尚未实现或受限的功能
通过 RMW_CONNEXT_LOG_NOT_IMPLEMENTED / RMW_RET_UNSUPPORTED 标记:
| API / 能力 | 状态 |
|---|---|
rmw_borrow_loaned_message / rmw_take_loaned_message* |
不支持 |
rmw_publish_loaned_message |
不支持 |
rmw_*_allocation(pub/sub 预分配) |
不支持 |
rmw_get_serialized_message_size |
不支持 |
rmw_publisher_wait_for_all_acked |
需查具体版本(部分 stub) |
rmw_publisher_get_network_flow_endpoints |
不支持 |
| Strict unique network flow endpoints | 创建 subscription 时拒绝 |
| Micro 部分 Security / Extended RPC | 受限 |
查阅具体 API 时可在 rmw_connextdds_common/src/common/ 内 grep NOT_IMPLEMENTED。
16. Pro vs Micro 差异摘要
| 维度 | rmw_connextdds (Pro) | rmw_connextddsmicro |
|---|---|---|
| RTI 产品 | Connext DDS Professional 5.3.1+ / 6.x | Connext DDS Micro 3.x+ |
| 类型插件 | 完整 PRESTypePlugin + TypeObject | 轻量注册 |
| 默认 RPC | Extended(SampleIdentity) | Basic(inline header) |
| Publish 模式 | 默认异步 | 不强制覆盖 |
| UDP 接口 | 自动 | 默认 lo,需 RMW_CONNEXT_UDP_INTERFACE |
| Content Filter | 支持(SQL) | 有限/不支持 |
| 互操作 | Fast-DDS extended RPC | 与 Pro basic 模式互通 |
17. 与 rmw_dds_common 的协作
本实现 重度依赖 rmw_dds_common(参见 rmw_dds_common 源码详细分析):
| rmw_dds_common 组件 | 在 Connext RMW 中的用法 |
|---|---|
rmw_dds_common::Context |
嵌入 rmw_context_impl_t::common |
GraphCache |
存储节点/endpoint 图 |
ParticipantEntitiesInfo |
discovery topic 消息类型 |
qos_profile_check_compatible |
QoS 兼容性 API |
security.hpp |
init 时安全配置 |
Connext 特有逻辑主要在 DDS API 层(QoS snippet、TypePlugin)和 discovery 线程,graph 语义与 Cyclone 后端对齐。
18. 调试建议
- 确认 RMW 已加载:
rmw_get_implementation_identifier()→"rmw_connextdds"或"rmw_connextddsmicro"。 - Connext 日志:
rmw_set_log_severity→ 内部rmw_connextdds_set_log_verbosity;Debug 构建定义RMW_CONNEXT_DEBUG=1。 - Graph 问题:检查
ros_discovery_info是否有数据;对比 DCPS built-in reader 是否触发。 - QoS 不匹配:开
RMW_CONNEXT_ENDPOINT_QOS_OVERRIDE_POLICY=never排查是否 RMW 覆盖导致。 - 跨机通信(Micro):必设
RMW_CONNEXT_UDP_INTERFACE与RMW_CONNEXT_INITIAL_PEERS。 - Service 不通:核对 RPC mapping 与对端 RMW 是否匹配(见第 9.2 节)。
19. 推荐阅读顺序
rmw_connextdds/src/rmw_api_impl_ndds.cpp— 全部 RMW 入口一览include/rmw_connextdds/context.hpp— context 状态机src/common/rmw_context.cpp— init/participant 流程include/rmw_connextdds/rmw_impl.hpp— 实体类接口src/common/rmw_impl.cpp— Publisher/Subscriber 创建与 topic 映射src/common/rmw_graph.cpp+rmw_discovery.cpp— Graph 双通道include/rmw_connextdds/type_support.hpp+src/ndds/rmw_type_support_ndds.cpp— 类型与 CDRsrc/common/rmw_impl_waitset_std.cpp—rmw_wait行为include/rmw_connextdds/static_config.hpp— 编译期常量与环境变量名rti_connext_dds_cmake_module/cmake/rti_build_helper.cmake— 构建探测逻辑
20. 小结
rmw_connextdds 仓库采用 「薄 RMW 注册层 + 厚 common 库 + 双 DDS 后端适配」 架构:
- 对上:完整实现 Humble
rmw.h契约(除 loaned message 等可选特性); - 对下:封装 RTI Connext Pro/Micro C API,Pro 版使用 TypePlugin 深度集成;
- 横向:通过
rmw_dds_common与 Cyclone/FastRTPS 共享 ROS Graph 协议; - 互操作:Pub/Sub 默认可跨厂商;Service 需按 RPC profile 与环境变量配置。
替换旧 rmw_connext_cpp 时需注意 类型 discovery 后缀 与 RPC 映射 差异;生产环境应显式固定 RMW_IMPLEMENTATION 与相关 RMW_CONNEXT_* 环境变量。
正在加载留言…