| 通信机制 | 典型端到端延迟(μs) | 最大吞吐量(msg/s) | 抖动(σ,μs) |
|---|---|---|---|
| 话题(默认QoS) | 80~150 | 4500 | ±35 |
| 话题(Best Effort) | 60~110 | 6700 | ±50 |
| 服务(同步请求) | 220~400 | 800 | ±80 |
| 动作(目标-反馈-结果) | 350~700 | 300 | ±120 |
以上数据来自Raspberry Pi 4B(4核Cortex-A72,1.8GHz)运行Ubuntu Server 22.04 + ROS2 Humble,通信载荷为sensor_msgs/msg/Image(640×480灰度图)。实测发现,Best Effort模式能让话题吞吐量提升约50%,但代价是丢包率在WiFi环境下可能超过2%。如果项目需要保证每帧都送达(如激光雷达数据),必须使用Reliable模式。
publish()到接收节点回调函数开始执行的时间差,包含序列化、DDS传输、反序列化、调度等待四个环节。实测需要一套组合工具。我习惯用ros2 topic delay做快速摸底,但它只能测话题延迟且精度有限。深入分析必须上专业工具:
ddsperf工具能直接输出DDS层的延迟和丢包统计,排除应用层干扰。一次典型测试的步骤:先让系统预热30秒(发布1000条消息),然后正式采集60秒数据,同时用perf stat -p 监控接收节点的CPU事件。输出CSV格式为timestamp_send,timestamp_recv,msg_seq,后续用np.diff计算延迟。
实际开发中,大部分团队会选择先抓CPU热点再决定优化方向。在一次激光雷达SLAM节点的分析中,我遇到过接收回调中做了大量图像处理导致DDS内存堆积——问题不在通信层。用perf report看top函数,如果前三位都是rmw_*或dds_*开头的符号,说明瓶颈在中间件;如果spin()调用占比超过40%,说明空闲等待太多,可以调高执行器的优先级。
RCLCPP_INFO在循环中产生大量写操作)rclcpp::executors::MultiThreadedExecutor并设置合理线程数FlatBuffers替代自定义序列化ROS2不是硬实时系统,但可以通过合理配置让软实时场景(100ms以内截止时间)稳定运行。关键指标是调度延迟:从DDS收到消息到应用层回调开始执行的时间。这个延迟受Linux调度器影响很大,我在NXP i.MX8M上实测过,非实时内核下中位调度延迟30μs,最大可达1.2ms。
降低调度延迟的手段:
isolcpus内核参数,配合pthread_setaffinity_np()。chrt -f 90)。/sys/devices/system/cpu/cpu*/cpufreq/scaling_governor里统一设为performance,并在测试报告中标记CPU频率锁定值。
嵌入式设备内存通常有限。DDS内部队列(history_depth)设置过大,在吞吐量高峰时会吃光RAM。实测一个sensor_msgs/msg/Image(1920×1080彩色)在深度为10时占用约60MB堆内存。建议——
ros2 topic bw /topic_name观察实时流量。depth为1~3,除非需要历史记录。valgrind --tool=massif分析堆分配,找出意外增长的元数据。目标:在自己的ROS2节点上测量话题延迟并画出分布直方图。
std_msgs/msg/String。delay.csv。matplotlib画出直方图。