2 · Link与Joint详解
这一章我们深入拆解 URDF 里最核心的两个零件——Link 和 Joint。说白了,机器人模型就是一堆 Link 通过 Joint 串起来的骨架。你想想看,没有 Joint 的 Link 就是一堆孤立的铁块,没有 Link 的 Joint 就是空气。我刚开始学 URDF 的时候,总把视觉和碰撞搞混,后来踩了几个坑才摸清楚门道。
Link 标签属性
每个 Link 就是一个刚体。URDF 里 Link 必须包含三个子模块:visual(长什么样)、collision(碰撞箱)、inertial(质量/惯量)。我个人习惯先把 visual 搭好,再复制一份改成 collision,省得手写两遍几何体。
<link name="base_link">
<visual>
<geometry>
<box size="0.4 0.3 0.1"/>
</geometry>
<origin xyz="0 0 0" rpy="0 0 0"/>
<material name="blue">
<color rgba="0 0 1 1"/>
</material>
</visual>
<collision>
<geometry>
<box size="0.4 0.3 0.1"/>
</geometry>
<origin xyz="0 0 0" rpy="0 0 0"/>
</collision>
<inertial>
<mass value="2.0"/>
<inertia ixx="0.01" ixy="0" ixz="0" iyy="0.01" iyz="0" izz="0.01"/>
</inertial>
</link>
visual / collision / inertial 细节
visual 只影响显示,不影响物理。你可以把模型做得花里胡哨,但 collision 一定要简单——用 box、cylinder、sphere 就够了。我在项目里见过有人把 collision 直接复制成带倒角的 mesh,结果仿真卡成 PPT……
inertial 是很多新手忽略的坑。如果你不写 inertial,ROS 会默认给一个极小的惯量,机械臂动力学直接崩掉。我曾经调试一个六轴臂,关节抖得像帕金森,最后发现是惯性张量少了个零。
ixx = 0.001 * mass 先顶着,但别用在真实机器人上。
Joint 类型与属性
Joint 决定了两个 Link 怎么动。URDF 支持六种类型,我按常用度排个序:
| 类型 | 自由度 | 典型用途 |
|---|---|---|
| revolute | 1 (旋转) | 关节电机、轮子转向 |
| continuous | 1 (无限旋转) | 车轮、转台 |
| prismatic | 1 (平移) | 伸缩臂、滑轨 |
| fixed | 0 | 焊接件、传感器支架 |
| floating | 6 | 自由物体(很少用) |
| planar | 3 (平面运动) | AGV 全向轮简化 |
每个 Joint 必须指定 parent 和 child,以及 origin(子坐标系相对于父坐标系的偏移)。你想想看,这个 origin 就是 TF 变换的源头。
limit 子标签,否则 MoveIt 会报错。我当年忘了加 limit,结果规划器一直说“joint out of range”,排查了半小时。
父子坐标系关系
这是整个 URDF 的命根子。每个 Joint 定义了一个坐标系变换:child Link 的坐标系原点在 parent Link 坐标系中的位置。说白了,你写 <origin xyz="0.2 0 0.1" rpy="0 0 1.57"/>,就是告诉 TF:子 Link 的原点相对于父 Link 移动了 (0.2,0,0.1) 米,再绕 Z 轴转 90°。
我习惯在纸上先画坐标系树,再写 URDF。举个例子:
<joint name="shoulder_pan" type="revolute">
<parent link="base_link"/>
<child link="shoulder_link"/>
<origin xyz="0 0 0.15" rpy="0 0 0"/>
<axis xyz="0 0 1"/>
<limit lower="-3.14" upper="3.14" effort="100" velocity="1.0"/>
</joint>
这里 shoulder_link 的原点就在 base_link 上方 0.15 米处,旋转轴朝 Z。嗯,要注意 axis 是在 父坐标系 下定义的,别搞反了。
origin 永远是相对于 parent link 的。
实战小贴士
- 用
check_urdf工具验证文件,它会告诉你哪个 joint 缺了 parent。 - visual 和 collision 的 origin 可以不同,但建议保持一致,否则显示和碰撞箱错位。
- inertial 的 origin 默认在 link 原点,如果你的重心不在几何中心,记得加
<origin/>偏移。
说实话,Link 和 Joint 的标签就那么几个,但组合起来能搭出任何机器人。你只要把父子关系理清楚,后面的 TF 和运动学就是水到渠成的事。