ROS机器人-从零开始每日日志记录day7
FastDDS 中 ASYNCHRONOUS 与 SYNCHRONOUS 的区别?
在 ROS 2 中,可以通过环境变量 RMW_FASTRTPS_PUBLICATION_MODE 来设置 FastDDS 的发布模式,有两个可选值:
| 模式 | 行为 | 特点 |
|---|---|---|
| SYNCHRONOUS(同步) | 调用 publish() / write() 时,数据在调用者线程中直接完成序列化并送入传输层发送 |
调用者线程会被阻塞,直到数据交给传输层;延迟更低,适合对实时性敏感的场景 |
| ASYNCHRONOUS(异步) | 调用 publish() / write() 时,数据仅被拷贝到内部发送队列,由一个独立的后台线程(Async Delivery Thread)负责实际发送 |
调用者线程立即返回,不阻塞;适合大数据量场景,但引入了额外的线程开销和微小延迟 |
同步 = 自己寄快递,异步 = 把快递放门口,等快递员来取。
为什么 ASYNCHRONOUS 可能会导致 CPU 使用率激增?
异步模式下,FastDDS 会为每个 DomainParticipant 创建一个专用的 Async Delivery Thread,负责从发送队列中取数据并通过传输层(UDP / Shared Memory)发出。
问题出在高频小数据的场景:
- 异步线程的工作机制是"等待队列 → 被唤醒 → 发送 → 再等待"的循环。
- 当节点以很高频率(如 200 Hz 的 IMU、编码器数据)持续发布小消息时,队列几乎永远不为空,线程刚处理完一条数据就立刻被下一条唤醒,根本没有机会真正休眠。
- 此时线程退化为近似忙等(busy-loop),CPU 占用随之飙升。
- 更糟的是,如果系统中有多个 Participant 都开启了 ASYNCHRONOUS 模式,每个都会各自持有一个这样的线程,CPU 开销会叠加放大。
异步线程是为"偶尔来一单大货"设计的,你让它"每秒送 200 个小包裹",它就累趴了。
如何正确使用 ASYNCHRONOUS 模式?
解决 Fast DDS 异步模式导致的 CPU 激增,不能靠单一手段,而需要一套分层治理策略。核心思路是:让发送线程从"无脑全速空转"变为"按需、限速、高效地工作"。
1.启用 Flow Controller
没有流控的异步发送线程就像一个没有油门的车——永远踩到底。
// 1. 创建流控描述符
auto flow_ctrl_desc = std::make_shared<eprosima::fastdds::rtps::FlowControllerDescriptor>();
flow_ctrl_desc->name = "sensor_flow_ctrl";
flow_ctrl_desc->max_bytes_per_period = 80 * 1024 * 1024; // 80 MB/s
flow_ctrl_desc->period_ms = 100; // 每100ms一个周期
flow_ctrl_desc->scheduler_policy = eprosima::fastdds::rtps::FlowControllerSchedulerPolicy::FIFO;
// 2. 注册到 Participant
participant_qos.transport().flow_controllers().push_back(flow_ctrl_desc);
// 3. 绑定到 DataWriter
writer_qos.reliable_writer_qos().flow_controller_name = "sensor_flow_ctrl";
Flow Controller 在发送线程内部实现了 Token Bucket / Leaky Bucket 算法。当达到速率上限时,发送线程会主动 sleep 直到下一个周期,而不是自旋等待。CPU 从 100% 降至 20-40% 是常见效果。
调参建议:
| 场景 | max_bytes_per_period | period_ms | 等效带宽 |
|---|---|---|---|
| 激光雷达 (1.5MB × 20Hz) | 35 MB | 100 | ~280 Mbps |
| 相机图像 (4MB × 10Hz) | 50 MB | 100 | ~400 Mbps |
| IMU (200B × 500Hz) | 1 MB | 100 | ~80 Mbps |
| 通用保守值 | 10 MB | 100 | ~800 Mbps |
2.优化发送线程配置
绑核 + 实时调度
publisher_qos.publish_mode().async_thread = {
.scheduling_policy = SCHED_FIFO,
.priority = 10,
.affinity = 0x08 // CPU3
};
- 减少上下文切换和 Cache Thrashing
- 避免与业务线程争抢导致双方都变慢
调整线程休眠策略(如果 Fast DDS 版本支持)
某些版本允许配置异步线程的等待策略:
// 优先使用条件变量阻塞等待,而非自旋
// 具体参数名取决于 Fast DDS 版本,查阅对应文档
3.减少无效工作量
合并小消息 / 增大批次
高频小消息是 CPU 杀手(每条消息 = 1次唤醒 + 1次序列化 + 1次系统调用)。
- 应用层打包:将多个 IMU 样本合并为一个数组再发布
- 增大 History Depth:允许发送线程一次取出多条样本批量处理
- 使用 SHM 传输:同机通信走共享内存,跳过序列化+Socket 开销
// 共享内存传输(同机零拷贝)
descriptor.transport_configurations().push_back(
std::make_shared<SharedMemTransportDescriptor>()
);
选择合适的 QoS
| 当前配置 | 问题 | 优化方向 |
|---|---|---|
| RELIABLE + KEEP_ALL + 大队列 | 发送线程永远有活干,永不休眠 | 改为 KEEP_LAST(N),N 取合理值 |
| BEST_EFFORT + 无流控 | 虽不重传但全速发送 | 加 Flow Controller |
| 大 History + 慢消费者 | 队列堆积,发送线程持续满载 | 减小 History 或加速消费者 |
4.评估是否真的需要异步
消息频率 < 100Hz 且 单包 < 2KB → 切回 SYNCHRONOUS
同步模式没有后台线程,CPU 开销天然更低。
分离关键与非关键数据流
- 控制指令 → 同步 Writer(低 CPU、确定性延迟)
- 传感器大数据 → 异步 Writer + Flow Controller
- 日志/诊断 → 异步 Writer + 更低优先级 + 更严流控
不同 Writer 可以有不同的发布模式和流控策略,不必一刀切。
5.系统与构建层面
| 措施 | 说明 |
|---|---|
| Release 构建 | Debug 版 Fast DDS 的发送线程 CPU 可能是 Release 的 5-10x |
| isolcpus | isolcpus=3 防止 OS 将其他任务调度到发送线程专用核 |
| IRQ 亲和性 | 将网卡中断迁离发送线程所在核心 |
| 关闭超线程 | HT 兄弟核共享执行单元,导致性能不可预测 |
| NUMA 对齐 | 确保发送线程、网卡、内存在同一 NUMA 节点 |
| 升级 Fast DDS | 新版本持续优化异步线程调度逻辑 |
遇到异步 CPU 激增时:
- 是否启用了 Flow Controller?
- 是否是 Debug 构建?
- 发送线程是否绑核?是否与业务线程隔离?
- History 深度是否过大导致队列永远不满?
- 是否存在高频小消息未合并?
- 是否所有 Writer 都开了异步?低频 Writer 能否切回同步?
- 网卡中断是否打到了发送线程所在核心?
- QoS策略是否值得调整?
异步模式的 CPU 代价本质上是用计算换取吞吐和解耦。Flow Controller 是你为这笔交易设定的"预算上限"。没有预算上限的异步发布,就是在用无限 CPU 购买你可能并不需要的额外性能。先加流控,再做优化,最后考虑架构调整。
踩坑记录:外部系统通过 UDP 向 ROS 导航发数据,Domain ID 必须一致!
当外部系统(如上位机、PLC、仿真器)通过 UDP 将目标点等数据发送给 ROS 2 导航栈时,双方的 DDS Domain ID 必须一致,否则节点之间根本无法互相发现,数据发了也白发。
- ROS 2 侧通过环境变量
ROS_DOMAIN_ID设置(默认值为 0,Linux 下可用范围 0–101、215–232)。 - 外部系统侧的 DDS 配置中也要设置相同的 Domain ID。
- 可以先用
ros2 node list/ros2 topic list确认当前域内是否能看到对方节点,看不到大概率就是 Domain ID 对不上。
同一物理网络上的多机通信还需要确保多播(multicast)可用,或者配置好 DDS 的 unicast discovery peers。
觉得有用的话,点个关注叭!
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)