
1. 看起来都是 Transform,生命周期完全不同
外参当动态 50 Hz 狂刷、里程计当 static 发一次——演示能跑,产品期重启某个节点后就「永远查不到」或「几何静默错误」。Static Transform 走 /tf_static,语义是 Transient Local:晚加入的订阅者仍能拿到;动态 TF 进 tf2_ros::Buffer,受时间与缓存约束,晚加入只能看到「还在缓存窗口里的历史」。
把「发一次就够」和「必须持续更新」搞反,症状往往出现在 bringup 顺序变化或容器扩缩之后。多一个生命周期节点,踩雷概率就上去一档。
2. 静态边:标定产物,不是运行时状态
相机–IMU 外参、雷达安装角、固定支架——标定完成后应冻结为 static,进 URDF 固定关节或 StaticTransformBroadcaster。不必动态刷:浪费带宽,还制造虚假「在动」感,查找侧却一直命中同一数值。
geometry_msgs::msg::TransformStamped t;
t.header.stamp = node->now();
t.header.frame_id = "base_link";
t.child_frame_id = "camera_link";
// ... translation & rotation from calibration yaml ...
static_broadcaster_->sendTransform(t);静态边改了必须重启依赖方,或走明确的热更新流程(删旧 static、发新 static、通知下游)。 silently 改 yaml 不重发,晚启动节点读到的仍是旧外参。
3. 动态边:随运动或估计变化
odom→base_link、活动关节、map→odom——必须持续更新,stamp 来自源传感器或估计器,不是回调到达墙钟。轮速积分位姿不要 static 发一次:机器人一动几何就错,且不会有 obvious 报错。
动态边频率应匹配源更新率,不是「越高越好」。过高挤占带宽与 CPU;过低放大外推失败。改频率前后对比查找失败率,两头都看。
4. 标定结束的硬门槛
写入 yaml/URDF → 发布 static → 删除动态广播路径 → view_frames 通过。缺「删除动态路径」会出现双源:有时 static 赢,有时动态赢,现场表现为间歇跳变,极难用「再标定一次」解决。
ros2 run tf2_tools view_frames
# 检查 pdf/yaml:无环、无多父、外参边只在 static 侧迁移机型时 diff 静态树(frame 名与外参),不要只换 mesh。动态树(odom→base 等)跟定位方案绑定,换定位栈时同步改广播职责表。
5. 与 URDF / robot_state_publisher 的分工
模型运动学关节由 joint_states + RSP 发布,属于动态 TF。传感器固定安装若已在 URDF 里用 fixed joint 表达,RSP 会发,不要再 duplicate 一个 static broadcaster——双源同样难查。
仿真里 Gazebo 插件有时也发 TF;bringup 里写清「仿真谁发、真机谁发」,避免 Gazebo 与 RSP 抢同一 child。
6. 晚加入与缓存行为
新启动的感知节点应能立即查到全部 static 外参;查不到先查 static broadcaster 是否在、frame 名是否 typo。动态边查 past extrapolation:可能是上游定位停更,不是感知节点坏了。
cache 长度与动态发布频率相关;static 不受 cache 窗口限制。不要把 static 问题用加大 cache 来「修」——那是掩盖动态停更。
7. 版本管理与验收
静态树是机型资产,进配置包版本管理,与标定日期/序列号关联。动态树是定位方案资产,随栈切换而变。
- 晚启动节点仍能查到全部 static 外参。
- 切断动态广播后,依赖动态边的查询应按分类失败,而不是静默用旧值。
view_frames无环、无多父;标定后无动态路径残留。- 双源检测:同一 child 同时有 static 与动态发布,联调脚本应失败。
8. 案例:双源外参的间歇跳变
某臂载相机标定后,应用节点仍按 10 Hz 动态发 base→camera,同时 static broadcaster 也在。RViz 图像大多正常,偶发重投影偏一像素级——融合组以为是标定噪声。view_frames 显示同一 child 双父;删掉动态路径后跳变消失。标定结束 checklist 缺「删动态路径」这一项,会让团队反复重标定。
Static 回答「安装关系是什么」;Dynamic 回答「现在在哪」。混用语义,TF 树再满也是定时炸弹。
相关
也可以看看
johan's blog