机器人定位结果看起来有系统性偏差时,直觉会先去怀疑标定。但相当一部分“标定不准”的现象,实际来自 TF 树本身错了:某个坐标系根本不存在、父子关系接反了、或者关节值没有真正驱动对应的变换。
这篇文章按“先确认树结构,再确认数值来源”的顺序展开,因为在一个结构错误的 TF 树上做标定,只会把结构问题掩盖得更深。
先确认树本身是否连通
第一个检查不该是标定参数,而是坐标系能不能查到、链路是否完整:
1 | ros2 run tf2_tools view_frames |
view_frames 会输出一张包含全部坐标系和连接关系的图。如果相机坐标系根本不在这张图上,那么后面的定位误差都无从谈起。如果它在图上但和基座不在同一条链路上,说明中间缺了一个关节或一棵子树。
常见问题包括:关节的 parent 和 child 写反,导致变换方向相反;模型里有两个 base_link 导致树出现分叉;以及固定关节被误写成可动关节,使静态部分被当作运行时数值。
数值来源必须和模型对齐
URDF 描述的是结构,/joint_states 提供的是数值。两者必须按关节名对齐。名字对不上的关节不会报错,只是保持默认位置,表现为某个部件在 RViz 里静止不动。
1 | ros2 topic echo /joint_states --once |
比对时要关注三件事:关节名是否完全一致(包括命名空间前缀)、关节值单位是否为弧度、以及 joint_states 的时间戳是否在推进。时间戳停住的关节值会被 TF 按过期数据处理,查询时得到外推失败或旧值。
固定关节与静态变换
不做运动的坐标系不需要 robot_state_publisher 参与,可以用静态变换发布:
1 | ros2 run tf2_ros static_transform_publisher \ |
这里容易出现重复发布:同一个变换既有 URDF 里的固定关节,又有额外的静态发布者。两个来源的数值不一致时,下游查询到的结果取决于时序,故障表现为偶发跳变。
选择原则很简单:属于机器人模型的固定关节放在 URDF 里,传感器安装外参要么全部放 URDF,要么全部用静态发布,不要混用。
和标定的边界
TF 树正确是标定有意义的前提。如果 base_link 到 camera_link 的变换本身就错了,那么手眼标定求出的结果会把这个结构错误吸收进去,表现为“标定参数看起来怪但误差不大”,一旦结构修正就需要重新标定。
因此排查顺序建议是先验证树结构和数值来源,确认静态部分符合设计,再进入标定环节。这两类问题的证据不同:结构问题看树和关节名,标定问题看残差和任务误差。
参考资料
证据边界
本文讨论 TF 树结构与关节值来源的排查顺序,不包含任何具体机器人的模型文件或标定结果。文中命令用于检查结构一致性;“树正确”只能说明坐标系关系符合模型描述,不能证明标定精度或传感器数据正确。