ROS 系统中,话题通信是最常见的数据传递方式。相机、雷达、IMU、里程计、控制指令都会通过 topic 发布和订阅。系统调试时,经常会遇到消息频率不稳定、延迟变大、订阅不到数据或控制响应慢等问题。

本文以 ROS1 为例,整理排查话题频率和延迟的常用命令、代码注意点和系统层面原因。

查看 topic 列表

先确认当前系统中有哪些话题:

1
rostopic list

查看某个话题的类型:

1
rostopic type /camera/image_raw

查看消息结构:

1
rosmsg show sensor_msgs/Image

如果话题不存在,先检查节点是否启动、命名空间是否正确、launch 文件参数是否覆盖了 topic 名称。

查看发布频率

使用 rostopic hz

1
rostopic hz /odom

输出会显示平均频率、最小间隔、最大间隔和标准差。对于稳定发布的传感器,频率应该接近配置值。例如 IMU 100Hz,里程计 50Hz。

如果频率明显低于预期,可能原因包括:

  • 发布节点计算耗时太长。
  • 传感器驱动本身输出频率低。
  • CPU 占用过高。
  • 网络传输瓶颈。
  • 消息体太大,例如原始图像。

查看消息带宽

使用 rostopic bw

1
rostopic bw /camera/image_raw

图像和点云消息带宽通常很高。如果在无线网络或跨机器通信中传输原始图像,很容易造成延迟。

可以考虑:

  • 降低分辨率。
  • 降低发布频率。
  • 使用压缩图像话题。
  • 将计算节点部署到传感器所在机器。
  • 避免多个节点重复订阅大数据话题。

查看消息内容

少量消息可以用:

1
rostopic echo /cmd_vel

如果话题频率很高,可以只看一条:

1
rostopic echo -n 1 /odom

对于包含 header 的消息,要关注 header.stamp

1
rostopic echo -n 1 /camera/image_raw/header

stamp 代表消息产生时间,和当前时间差距过大时,可能存在处理延迟、时间同步问题或仿真时间配置问题。

计算消息延迟

如果消息包含 std_msgs/Header,可以在订阅端计算当前时间和消息时间戳差值:

1
2
3
4
5
6
7
8
9
10
11
import rospy
from nav_msgs.msg import Odometry

def callback(msg):
now = rospy.Time.now()
delay = (now - msg.header.stamp).to_sec()
rospy.loginfo("odom delay %.3f s", delay)

rospy.init_node("delay_checker")
rospy.Subscriber("/odom", Odometry, callback, queue_size=10)
rospy.spin()

如果使用仿真时间,确保设置了:

1
rosparam get /use_sim_time

并且 /clock 正常发布。仿真时间和系统时间混用会导致延迟计算失真。

queue_size 的影响

发布和订阅时都要设置合理的 queue_size。以 Python 为例:

1
2
pub = rospy.Publisher("/cmd_vel", Twist, queue_size=10)
sub = rospy.Subscriber("/odom", Odometry, callback, queue_size=10)

队列太小可能丢消息,队列太大可能积压旧消息导致延迟变大。对于控制指令和实时感知,通常宁愿丢旧消息,也不要处理过期消息。

如果回调处理速度低于消息发布速度,队列会持续积压。此时应该优化回调逻辑,或者在回调中只缓存最新数据,把耗时计算放到独立线程或定时器中。

回调函数不要做重活

一个常见错误是在订阅回调中做耗时计算、文件写入、网络请求或复杂规划。这样会阻塞后续消息处理。

更稳的方式是回调只保存最新消息:

1
2
3
4
5
6
7
8
9
10
11
12
latest_odom = None

def odom_callback(msg):
global latest_odom
latest_odom = msg

def timer_callback(event):
if latest_odom is None:
return
process(latest_odom)

rospy.Timer(rospy.Duration(0.02), timer_callback)

这样处理频率由 timer 控制,不会被消息频率完全牵着走。

跨机器通信排查

跨机器 ROS 通信还要检查网络配置:

1
2
3
echo $ROS_MASTER_URI
echo $ROS_IP
echo $ROS_HOSTNAME

常见要求:

  • 所有机器能访问同一个 ROS master。
  • 节点公布的 IP 或 hostname 能被其他机器访问。
  • 防火墙没有阻断 ROS 通信端口。
  • 多网卡机器设置了正确的 ROS_IP

可以使用 pingrostopic listrostopic echo 分层验证。

使用 rqt_graph

图形化查看节点和话题关系:

1
rqt_graph

它可以快速发现:

  • 节点没有连接到预期话题。
  • 话题命名空间不一致。
  • 存在多个发布者。
  • 数据流向和设计不一致。

对于复杂 launch 文件,rqt_graph 比肉眼查 XML 更直观。

小结

ROS 话题频率和延迟排查可以按顺序进行:确认 topic 存在,查看类型和内容,使用 rostopic hz 看频率,使用 rostopic bw 看带宽,基于 header 时间戳计算延迟,再检查 queue_size、回调耗时和跨机器网络。实时系统中要特别注意旧消息积压,很多“控制慢”的问题本质上是处理了过期数据。