4. Joint详解:类型与父子关系
关节——说白了就是机器人身上“会动的地方”。你想想看,一个机械臂如果没有关节,那就是一根铁棍。URDF 里的 <joint> 标签,就是用来描述两个连杆之间怎么相对运动的。我做了这么多年机器人,每次拿到一个新模型,第一件事就是检查关节定义,因为这里出错了,后面 TF 全乱套。
这一章咱们就把 <joint> 的六种类型掰开揉碎讲清楚,顺便聊聊父子关系这个核心概念。嗯,内容有点干,但都是硬货。
4.1 六种关节类型,一个都不能少
URDF 一共定义了六种关节类型。我刚开始学的时候也觉得多,但用久了就会发现——每种类型都对应着真实的机械结构。咱们一个一个过。
| 类型 | 运动方式 | 典型应用 | 自由度 |
|---|---|---|---|
continuous | 连续旋转,无角度限制 | 车轮、转台 | 1 (旋转) |
revolute | 旋转,有角度限制 | 关节臂、肘关节 | 1 (旋转) |
prismatic | 直线滑动,有行程限制 | 伸缩臂、滑台 | 1 (平移) |
fixed | 完全固定,无运动 | 传感器支架、结构件 | 0 |
floating | 6自由度自由运动 | 无人机、水下机器人 | 6 |
planar | 平面内运动 (x,y + 偏航) | AGV 全向轮底盘 | 3 |
continuous;如果机械限位在 ±180° 以内,用 revolute 并老老实实填 <limit>。曾经有个项目,我把连续旋转的转台写成了 revolute,结果仿真时老是撞限位,排查了半天……
4.2 父子关系——关节的“上下级”
每个 <joint> 必须指定 parent 和 child。这可不是随便写的。父连杆固定,子连杆相对父连杆运动。说白了,关节就是“子连杆在父连杆坐标系下的运动描述”。
举个例子:
<joint name="shoulder_pan" type="revolute">
<parent link="base_link"/>
<child link="shoulder_link"/>
<origin xyz="0 0 0.2" rpy="0 0 0"/>
<axis xyz="0 0 1"/>
<limit lower="-3.14" upper="3.14" effort="100" velocity="1.0"/>
</joint>
这里 base_link 是父,shoulder_link 是子。关节旋转轴是 Z 轴。你想想看,如果我把父子写反了,整个 TF 树就倒挂了——我遇到过不止一次,新手经常在这里翻车。
tf_echo 一查,才发现坐标系方向全反了。所以我的建议是:画一个树形图,标清楚每个 joint 的 parent 和 child,再写 URDF。
4.3 每个类型的细节与避坑
continuous —— 没有 <limit> 的上下界,但必须给 effort 和 velocity。嗯,ROS 里有些控制器会检查这两个字段,别漏了。
revolute —— 必须设置 lower 和 upper。我习惯把单位统一成弧度,避免角度/弧度混用。曾经有个同事用了角度值,结果仿真时关节直接飞出去了……
prismatic —— 平移关节,axis 指定移动方向。注意 xyz 是单位向量。如果你想让滑台沿 X 轴滑动,就写 axis xyz="1 0 0"。
fixed —— 最简单,但最容易忽略。比如相机支架、激光雷达底座,都用 fixed。别小看它,TF 树里 fixed joint 能帮你把坐标系整理得清清楚楚。
floating —— 6自由度,一般用在移动机器人或者无人机上。但说实话,我很少在 URDF 里直接用 floating,因为大多数时候我们用 base_link 配合 odom 来做。不过如果你在做水下机器人仿真,floating 就很有用了。
planar —— 平面三自由度 (x, y, yaw)。适合全向轮底盘。注意,planar 关节在 Gazebo 里需要额外的插件支持,否则可能动不了。
fixed 占位,等运动学模型确定后再改。我经常在项目初期用 fixed 搭骨架,后面再替换成运动关节。
4.4 关节的坐标轴与原点
每个 joint 都有一个 <origin>,它定义了子连杆坐标系相对于父连杆坐标系的偏移和旋转。这个 xyz 和 rpy 非常关键——它直接决定了关节的位置和朝向。
举个例子:如果 origin xyz="0 0 0.5" rpy="0 0 0",表示子连杆的原点位于父连杆上方 0.5 米处,且姿态相同。而 axis 则是在子连杆坐标系下定义的旋转轴或平移轴。
<!-- 一个典型的轮式关节 -->
<joint name="left_wheel_joint" type="continuous">
<parent link="base_link"/>
<child link="left_wheel"/>
<origin xyz="0.2 0.3 0" rpy="0 0 0"/>
<axis xyz="0 1 0"/> <!-- 绕 Y 轴旋转 -->
</joint>
这里车轮绕 Y 轴旋转,意味着车轮向前滚动。如果你把 axis 写成 0 0 1,那车轮就会像陀螺一样原地打转——嗯,我见过有人这么干过,结果车子在仿真里横着走。
4.5 关节与 TF 树的关系
URDF 里的每个 joint 都会在 TF 树中生成一个坐标变换。父连杆坐标系到子连杆坐标系的变换,就是由 joint 的 origin 加上当前关节变量(角度/位移)决定的。所以,joint 定义得越准确,TF 树就越清晰。
我个人习惯在写完 URDF 后,立刻用 urdf_to_graphviz 生成一张图,检查父子关系是否合理。你也可以用 check_urdf 工具做语法检查,但它查不出逻辑错误——比如父子颠倒。
- 关节类型决定了运动自由度与约束
- 父子关系定义了 TF 树的流向(父→子)
origin是子坐标系在父坐标系中的位姿axis在子坐标系下定义,注意单位向量- fixed 关节虽然不动,但能帮你整理坐标系结构
好了,这一章的内容就是这些。关节是 URDF 的灵魂,把 joint 搞明白了,你的机器人模型就成功了一半。下一章我们会深入坐标变换,看看 TF 到底是怎么把关节串起来的。