
1. 多节点抢同一 child,tf2 不仲裁
谁广播、频率多少、stamp 用什么,决定查找侧是否稳定。两个节点同时发 base_link→laser,tf2 不替你做仲裁——后到的样本污染 buffer,表现为间歇跳变。应用层「检测到跳变就手动修 TF」是毒:掩盖双源,直到频率略变就全线外推失败。
职责表进仓库:frame → 唯一发布者 → 静态/动态 → 源 stamp 策略。MR 改广播必须改这张表;代码审查里看到第二个 TransformBroadcaster 指向已有 child,应直接打回。
2. StaticTransformBroadcaster:外参一次到位
标定完成的外参、固定安装关系——启动时发一次,走 /tf_static:
static_broadcaster_ = std::make_shared<tf2_ros::StaticTransformBroadcaster>(node);
static_broadcaster_->sendTransform(static_transforms);不要在运行中反复 send 同一 static 边「刷新」——除非标定热更新流程明确允许。与 URDF fixed joint + RSP 重叠的边,删应用侧广播,而不是「两边都发更保险」。
3. TransformBroadcaster:动态边跟源走
高频里程计、定位输出、关节链——专用节点发布,stamp 来自轮速/IMU/估计器:
geometry_msgs::msg::TransformStamped odom_tf;
odom_tf.header.stamp = wheel_odom_msg->header.stamp; // 不是 this->now()
odom_tf.header.frame_id = "odom";
odom_tf.child_frame_id = "base_link";
// fill transform from integration
tf_broadcaster_->sendTransform(odom_tf);禁止随手打未来时间,除非模块明确做预测且下游知道那是预测边。未来 stamp 让查询「偶然成功」,几何却指向尚未发生的运动。
4. 与 robot_state_publisher 的边界
RSP 吃 URDF + joint_states,发布模型运动学 TF。应用节点不要再广播 RSP 已有边「以防万一」——重复广播是 TF 问题里最难查的一类:看起来都对,偶尔跳一下,录包却很难抓到双源瞬间。
map→odom / odom→base 归定位栈;模型关节归 RSP;传感器外参归 static 或 URDF。画一张边归属表贴在 bringup 文档里,比事后 grep 全仓库高效。
5. 查找侧:消息时间,不是墙钟
订阅者查 TF 用 msg.header.stamp,与广播侧 stamp 策略成对设计。广播用源时间、查找用 now(),是现场一半 TF 问题的来源。
timeout 设合理值(如 50 ms),失败分类打点而不是无限重试。查找失败率应进监控,与广播频率联动评估——只加 timeout 不查发布者,是在拖延爆炸。
6. 频率与多机负载
广播频率匹配源更新,不是越高越好。10 个节点各 100 Hz 刷 TF,在多机 discovery 下会挤占带宽;过低则放大外推。改频率前后对比:查找失败率、CPU、ros2 topic bw /tf。
多机器人同域时,frame 命名空间隔离(prefix)比提高频率有用——抢 frame 名和抢 child 一样致命。
7. 测试与验收
- 集成测试:故意启动两个发布者抢同一 child,应被检测脚本或
view_frames抓到多父。 view_frames无环、无多父;职责表与ros2 node info一致。- 断掉唯一发布者后,依赖方应分类报错,而不是继续输出控制。
- bringup 检查项:静态边在、动态边持续、无重复 child。
- MR 改广播附带职责表 diff,评审可机械核对。
8. 录包与离线调试
录包应包含 /tf、/tf_static 与相关传感话题,回放时用 --clock 且查询侧仍用消息 stamp:
ros2 bag record -o tf_debug /tf /tf_static /joint_states /odom
ros2 bag play tf_debug --clock离线脚本若用 now() 查 TF,会系统性 past extrapolation——复盘结论变成「当时 TF 全断」,实际是查询方式错了。职责表应标注每条边的预期发布频率,便于对比 bag 里 /tf 的 hz 是否达标。
9. 案例:「更保险」的双广播
bringup 里 RSP 已发 base→lidar,驱动节点又发同名边「以防 RSP 晚起」。大部分时刻两路数值接近,偶发时间戳交错导致 buffer 跳变;costmap 表现为障碍物栅格闪一下。删掉驱动侧重复广播,闪变消失——不是驱动 bug,是架构双源。
一帧一主、stamp 随源——听起来像纪律口号,却是 TF 稳定性的最小充分条件。双源是架构债,不是调参能还的。
相关
也可以看看
johan's blog