2. URDF核心元素:link、joint、几何与碰撞

各位好,我是你们的老朋友。今天咱们来啃URDF里最硬核的几块骨头——link、joint、几何原点、惯性参数和碰撞检测。说实话,这些概念刚接触时容易绕晕,但只要你理清了,后面MoveIt调参就跟玩一样。

URDF 核心元素结构 link • 视觉几何 (visual) • 碰撞几何 (collision) • 惯性参数 (inertial) • 原点 origin joint • 类型 (fixed, revolute…) • parent / child • 原点 origin • 轴 axis geometry & origin • 几何体:box, cylinder, sphere, mesh • xyz / rpy 偏移 • 碰撞 vs 视觉 引用

2.1 link 标签——机器人的骨骼

每个link代表机器人身上的一个刚体部件。你可以把它想象成一块骨头。我习惯把link分成三类:视觉link(长得什么样)、碰撞link(实际占多大空间)、惯性link(有多重、转动惯量多少)。

核心结构:

<link name="base_link">
    <visual>
        <geometry>
            <box size="0.4 0.3 0.1"/>
        </geometry>
        <origin xyz="0 0 0" rpy="0 0 0"/>
    </visual>
    <collision>
        <geometry>
            <cylinder radius="0.2" length="0.5"/>
        </geometry>
        <origin xyz="0 0 0.25" rpy="0 0 0"/>
    </collision>
    <inertial>
        <mass value="5.0"/>
        <inertia ixx="0.1" ixy="0" ixz="0" iyy="0.1" iyz="0" izz="0.1"/>
    </inertial>
</link>

嗯,这里要注意:origin 是相对于link自身坐标系的偏移。我见过很多新手把视觉和碰撞的origin搞混,结果仿真时机器人看着没撞,实际却卡住了。说白了,碰撞几何要尽量贴合真实外形,但可以简化——比如用圆柱代替复杂的爪子。

2.2 joint 标签——让骨头动起来

joint连接两个link,定义它们之间的相对运动。我个人最常用的类型是 revolute(旋转关节)和 prismatic(移动关节)。固定关节 fixed 也经常用来把传感器“粘”在机器人上。

关节类型自由度典型用途
fixed0固定连接,如相机支架
revolute1 (旋转)电机驱动关节,有角度限制
prismatic1 (平移)伸缩臂、滑台
continuous1 (无限旋转)轮子、转台
floating6移动基座(很少直接用在URDF)
避坑指南: 我曾经在定义revolute关节时忘了加 <limit>,结果MoveIt规划时直接报错。记住,effort 和 velocity 也要填,不然控制器会“软绵绵”。
<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="20" velocity="1.0"/>
</joint>

你想想看,axis 定义了旋转轴的方向。如果想让关节绕着X轴转,就把 xyz="1 0 0"。我刚开始总把轴方向搞反,后来养成了一个习惯:在Rviz里加一个坐标轴显示,一眼就能看出问题。

2.3 geometry 与 origin——形状与位置

URDF支持四种基本几何:box、cylinder、sphere 和 mesh。我个人偏爱用mesh导入STL文件,这样外观更真实。但碰撞检测时,我会用简化几何体——比如用几个球体包络机械臂,计算量小很多。

性能警告: 如果你在collision里用了高精度的mesh,MoveIt的碰撞检测会变得非常慢。我的经验是:视觉用精细mesh,碰撞用基本几何体或低面片mesh。

origin 的 xyz 和 rpy 控制几何体相对于link坐标系的偏移。举个例子:你想让圆柱体竖着放,但默认圆柱的轴线是Z轴,如果模型是横着的,就旋转 rpy="0 1.57 0"(绕Y轴转90度)。

2.4 惯性参数——仿真真实感的灵魂

没有惯性参数的机器人,就像在太空中飘着。MoveIt做轨迹规划时,如果惯性矩阵给得离谱,规划出来的轨迹加速度会特别奇怪。我踩过最大的坑:给了一个连杆质量0.001kg,结果仿真时轻轻一碰就飞出去了。

惯性矩阵 <inertia> 有6个独立分量:ixx, ixy, ixz, iyy, iyz, izz。对于简单几何,可以用公式估算。比如一个长方体,质量m,尺寸a×b×c:

  • ixx = m*(b² + c²)/12
  • iyy = m*(a² + c²)/12
  • izz = m*(a² + b²)/12
  • 其他交叉项设为0(如果坐标系在质心)

快速估算技巧: 我经常用SolidWorks或Fusion 360导出URDF,它们会自动计算惯性。但如果你手写URDF,可以用这个在线小工具:惯性计算器(其实就是一个Python脚本)。嗯,别偷懒,惯性参数不准,后面PID调死你。

2.5 碰撞检测——安全第一

碰撞检测分两层:自碰撞(机器人和自己打架)和环境碰撞(撞到桌子、墙壁)。URDF里通过 <collision> 标签定义碰撞形状。MoveIt默认使用FCL(Flexible Collision Library)进行检测。

我曾经在调试一个六轴机器人时,发现规划出来的路径总是莫名其妙地抖动。查了两天,最后发现是碰撞几何里有一个mesh的顶点数太多,导致距离计算不稳定。换成简化圆柱后,问题立刻消失。

我的习惯: 每个link都至少定义一个collision几何,哪怕和visual一模一样。否则MoveIt会认为这个link“不存在”,碰撞检测直接跳过,很危险。