ROS2 Topic 传输机制:板内 vs 跨板
ROS2 Topic 传输机制板内 vs 跨板1. 两种传输方式2. 传输决策逻辑场景传输方式是否反序列化同进程同节点Intra-Process (Zero-Copy)❌ 不需要同进程不同节点Intra-Process❌ 不需要不同进程DDS (UDP/TCP/Shared Memory)✅ 需要不同板块DDS (网络)✅ 需要3. Intra-Process (板内) 传输原理核心特性使用IntraProcessBuffer直接传递消息指针无需反序列化消息以 ROS 消息对象形式传递Zero-Copy发布者直接将消息存入订阅者的缓冲区源码分析// intra_process_buffer.hpp// 板内传输直接传递 shared_ptr不经过序列化/反序列化// 添加消息到缓冲区共享方式virtualvoidadd_shared(MessageSharedPtr msg){buffer_-enqueue(std::move(shared_msg));// 直接存入指针}// 从缓冲区消费消息virtualMessageSharedPtrconsume_shared(){returnbuffer_-dequeue();// 直接取出指针无拷贝}传输流程Publisher::publish() ↓ IntraProcessManager::match_publishers_to_subscriptions() ↓ IntraProcessBuffer::add_shared(msg) // 直接存入订阅者缓冲区 ↓ 订阅者通过 wait() 收到通知直接取用消息对象关键代码位置rclcpp/experimental/intra_process_manager.hpp- 进程内通信管理器rclcpp/experimental/buffers/intra_process_buffer.hpp- 进程内缓冲区rclcpp/intra_process_setting.hpp- 进程内通信配置4. DDS 传输 (跨板) 原理需要反序列化的原因DDS 层使用 CDR (Common Data Representation) 序列化数据在网络上以字节流传输订阅端必须反序列化为 ROS 消息对象传输流程Publisher::publish() ↓ rmw_publish() // 序列化: ROS Msg → CDR bytes ↓ RMW (FastDDS/CycloneDDS) ↓ 网络传输 (UDP/TCP/Shmem) ↓ Subscription::take() // 反序列化: CDR bytes → ROS Msg ↓ 回调函数收到消息对象5. use_intra_process_comms 配置场景场景1: use_intra_process_comms true问题: 既有板内订阅又有跨板订阅Topic 默认用什么方式传输┌─────────────────────────────────────────────────────────────────────┐ │ use_intra_process_comms true │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ Publisher │ │ │ │ │ ├──► 板内订阅A ──► Intra-Process (Zero-Copy, 无序列化) │ │ │ │ │ └──► 跨板订阅B ──► DDS (需序列化) │ │ │ └─────────────────────────────────────────────────────────────────────┘答案: 同时使用两种方式板内订阅→Intra-Process(Zero-Copy无序列化)跨板订阅→DDS(需要序列化)Publisher 会双重发布一份通过IntraProcessManager发给板内订阅者一份通过 DDS/RMW 发给跨板订阅者源码逻辑sub// IntraProcessManager 会检查匹配的订阅者// 如果存在跨进程的订阅者仍然会走 DDS 路径if(can_communicate(publisher,subscription)){// 板内通信IntraProcessBuffer}else{// 跨进程通信DDS}pubpublish(std::unique_ptrT,ROSMessageTypeDeletermsg){if(!intra_process_is_enabled_){this-do_inter_process_publish(*msg);return;}// If an interprocess subscription exist, then the unique_ptr is promoted// to a shared_ptr and published.// This allows doing the intraprocess publish first and then doing the// interprocess publish, resulting in lower publish-to-subscribe latency.// Its not possible to do that with an unique_ptr,// as do_intra_process_publish takes the ownership of the message.// When durability is set to TransientLocal (i.e. there is a buffer),// inter process publish should always take place to ensure// late joiners receive past data.boolinter_process_publish_neededget_subscription_count()get_intra_process_subscription_count()||buffer_;if(inter_process_publish_needed){autoshared_msgthis-do_intra_process_ros_message_publish_and_return_shared(std::move(msg));if(buffer_){buffer_-add_shared(shared_msg);}this-do_inter_process_publish(*shared_msg);}else{if(buffer_){autoshared_msgthis-do_intra_process_ros_message_publish_and_return_shared(std::move(msg));buffer_-add_shared(shared_msg);}else{this-do_intra_process_ros_message_publish(std::move(msg));}}}场景2: use_intra_process_comms false问题: 关闭后板内和板间都有订阅板内需要反序列化吗┌─────────────────────────────────────────────────────────────────────┐ │ use_intra_process_comms false │ ├─────────────────────────────────────────────────────────────────────┤ │ │ │ Publisher │ │ │ │ │ ├──► 板内订阅A ──► DDS (需序列化) ◄── 需要反序列化! │ │ │ │ │ └──► 跨板订阅B ──► DDS (需序列化) ◄── 需要反序列化 │ │ │ └─────────────────────────────────────────────────────────────────────┘答案: 需要反序列化关闭 Intra-Process 后所有订阅都走 DDS序列化ROS Msg → CDR bytes本地回环或网络传输反序列化CDR bytes → ROS Msg即使是同一个板内的订阅也需要完整的序列化/反序列化过程。6. 对比总结配置板内订阅跨板订阅序列化/反序列化use_intra_process_commstrueIntra-Process ✅DDS跨板需要use_intra_process_commsfalseDDSDDS都需要7. 性能影响场景延迟备注true 板内~1μsZero-Copy最优true 跨板~100μsDDS 序列化false 板内~100μs吃大亏!绕道 DDSfalse 跨板~100μs正常 DDS8. 如何启用 Intra-Process方式1: Node 级别默认启用rclcpp::NodeOptions options;options.use_intra_process_comms(true);// 默认 trueautonodestd::make_sharedrclcpp::Node(my_node,options);方式2: Publisher/Subscriber 级别控制// 显式启用autopubnode-create_publisherstd_msgs::msg::String(topic,rclcpp::QoS(10),rclcpp::IntraProcessSetting::Enable// 显式启用);// 显式禁用强制走 DDSautopub2node-create_publisherstd_msgs::msg::String(topic,rclcpp::QoS(10),rclcpp::IntraProcessSetting::Disable// 强制 DDS);IntraProcessSetting 枚举enumclassIntraProcessSetting{Enable,// 显式启用进程内通信Disable,// 显式禁用进程内通信NodeDefault// 跟随 Node 的默认设置};9. Zero-Copy 优化我们生成的优化文件optimized_message_pool.hpp进一步优化了消息传递// Zero-Copy 消息池classOptimizedMessagePool{public:// 预分配消息缓冲区// 指针直接复用// 减少内存分配/释放开销MessageT*allocate();// 从池中获取voiddeallocate(MessageT*msg);// 归还到池};10. 配置建议推荐配置// ✅ 推荐保持默认启用 intra-processrclcpp::NodeOptions options;options.use_intra_process_comms(true);// 默认就是 true何时禁用只有在下述情况才考虑禁用// 场景1明确知道只需要跨板通信不需要板内通信rclcpp::NodeOptions options;options.use_intra_process_comms(false);// 场景2调试时需要抓包分析 DDS 流量// 禁用后所有流量都走 DDS可以用 Wireshark 观察⚠️ 注意事项禁用use_intra_process_comms不会让板内订阅变快反而会强制走 DDS 路径增加不必要的序列化开销如果可能存在跨板订阅禁用会损失性能11. 总结板内订阅 (Intra-Process)Zero-Copy无需序列化/反序列化延迟极低 (~1μs)消息以shared_ptr形式直接传递跨板订阅 (DDS)需要 CDR 序列化/反序列化延迟较高 (~100μs)支持跨进程、跨机器通信use_intra_process_comms true:板内Zero-Copy无序列化跨板DDS 序列化同时支持两种路径use_intra_process_comms false:全部走 DDS板内也需要反序列化性能最差默认行为ROS2 默认启用 Intra-Process系统自动选择最优传输路径
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2412507.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!