返回专辑
·Johan·4 分钟阅读

传感器 QoS:最新帧语义,不是默认可靠

Best Effort + 小 depth 服务实时流;用 topic info -v 证明无数据可纯由 QoS 造成。

传感器 QoS:最新帧语义,不是默认可靠

1. 驱动活着,回调不来

相机进程在,ros2 topic list 也看得到话题,订阅却从不触发——我先查 ros2 topic info -v 的 Offered/Requested,而不是先怀疑 USB。发布端 Best Effort,订阅端 Reliable,兼容矩阵判负,表现就是无数据。工具链通常不弹窗,只是不配对接。

现场常见误判:驱动日志在刷帧,RViz 却空白,于是换线、换驱动、重装固件。info -v 一行就能证明匹配失败。另一类陷阱:连接数大于零,但兼容失败后数据面仍空——RViz 有时只显示有 publisher,不显示匹配结果。

2. 传感器为什么偏 Best Effort

实时感知要时间上最近的样本。Reliable 在抖动下会重传,队列堆出延迟尾巴,控制器还以为在跟当前帧。KeepLast(1) 表达最新值语义:宁可丢中间帧,也不要把旧帧当真。

cpp
auto qos = rclcpp::SensorDataQoS();
sub_ = create_subscription<sensor_msgs::msg::Image>(
  "image_raw", qos,
  std::bind(&Node::on_image, this, std::placeholders::_1));

depth 开很大常把视觉拖成批处理——缓冲区里堆的是历史,不是「更稳」。激光、IMU、图像同一原则:延迟比丢帧更危险(对闭环控制而言)。

3. 状态与配置:另一套剖面

地图、静态 TF、参数事件更常见 Reliable + Transient Local——语义是「状态」,不是「流」。late-joining 订阅者需要拿到最后一帧,而不是等下一帧传感器数据。

按数据类建剖面表(传感 / 状态 / 配置 / 日志),节点只许从表内选。新节点 MR 必须声明「走哪一行」;评审抓语义是否选对,不是有没有抄默认构造。

4. 对照实验:一次教会团队

发布端 SensorDataQoS(),订阅端先故意用 Reliable,再改 Best Effort,同时看 info -vhz

bash
ros2 topic info -v /camera/image_raw
ros2 topic hz /camera/image_raw

团队见过一次「纯 QoS 造成的无数据」后,「没图先骂驱动」会少很多。已兼容仍无数据,再查 discovery(域 ID、网卡、ROS_LOCALHOST_ONLY)与 stamp——QoS 不是万能锅。

5. 录包与回放的剖面一致

录包订阅者 QoS 必须与在线一致。用 Reliable 录 Best Effort 流,回放里「完美不丢帧」;线上偶发丢帧,袋里却可靠,调出来的阈值上线即失效。

bash
ros2 bag record -o cam_bag /camera/image_raw --qos-profile-overrides-path overrides.yaml

overrides.yaml 里为传感话题指定 sensor_data 预设,避免默认 Reliable 录包。

6. deadline 与假活

话题还在、频率接近 0 时,RViz 有时仍显示有 publisher。关键传感流加 deadline QoS,并结合 /diagnostics,把沉默变成事件——导航侧可降级或停车,而不是继续用过期帧规划。

cpp
rclcpp::QoS qos(rclcpp::SensorDataQoS());
qos.deadline(rclcpp::Duration::from_seconds(0.1));

deadline 超时应进诊断,运维看见「相机假活」,而不是算法里默默 return

7. 多 RMW 与默认策略

车队混用 Fast-DDS 与 Cyclone 时,预设名相同不保证实现细节相同——在目标 RMW 上重复兼容实验。在线感知保最新;标定采集可另开 Reliable 管道,不要用同一话题服务两种语义。

算法节点订阅多路传感,统一从剖面表选 QoS,禁止某个开发者 QoS(10) 随手构造。一个 Reliable 订阅者混进 Best Effort 图,害的是整链调试时间。

8. 验收

  • 故意 Reliable 订 Best Effort 相机:无回调,且 info -v 可解释。
  • 改回剖面后 hz 恢复,回调时间戳单调合理。
  • 录包订阅与在线剖面一致;用错剖面联调脚本失败。
  • deadline 超时进诊断,导航侧有降级或停车策略。
  • 剖面表进仓库,MR 声明所用行。

9. 与 Nav2 / 感知栈的衔接

Nav2 默认订阅激光/深度时常用 sensor 兼容预设;自写节点若用 QoS(10)(默认可靠),会在联调阶段「全图无障」。把剖面表同步给感知、规划、录包三处,缺一环就会在错误语义上浪费调试时间。

无线图传场景下,相机 Best Effort 丢帧可接受,但定位用的 IMU/里程计是否也 Best Effort 要单独评估——控制环对延迟与丢样的容忍度不同,不能一张表打天下。

10. 案例:录包「太可靠」的阈值陷阱

线上视觉避障偶发误检,团队在 bag 上反复调阈值,怎么调都「太灵敏」。后来发现 bag 用 Reliable 录,帧帧齐全;线上 Best Effort 丢帧时算法走预测分支,行为不同。改 overrides 重录后,阈值一次到位。

QoS 是分布式合约。先证明匹配,再怀疑硬件;先定剖面,再谈调参。传感器流的默认答案是最新帧,不是最可靠帧。

← 全部文章

johan's blog