4、连杆标签<link>(上):<link>标签的结构、name属性的重要性、惯性属性<inertial>的组成

好,我们正式开始拆解URDF里最核心的零件——<link>标签。

你可以把link想象成机器人的每一块骨头。没有骨头,肌肉(joint)往哪儿连?所以,link是URDF的基石。今天我们先讲上半部分:标签结构、name属性的坑,以及惯性属性怎么配。

4.1 <link>标签的基本结构

一个完整的link标签,长这样:

<link name="base_link">
    <inertial>
        <origin xyz="0 0 0" rpy="0 0 0"/>
        <mass value="10.0"/>
        <inertia ixx="0.1" ixy="0" ixz="0"
                 iyy="0.1" iyz="0"
                 izz="0.1"/>
    </inertial>
    <visual>
        <!-- 视觉模型 -->
    </visual>
    <collision>
        <!-- 碰撞模型 -->
    </collision>
</link>

嗯,这里要注意:inertial、visual、collision这三个子标签,顺序可以调换,但name属性必须写。我见过有人把name写成注释,结果Gazebo死活不认——那叫一个憋屈。

核心原则:每个link必须有且只有一个name,且在整个URDF文件中唯一。

4.2 name属性的重要性——别小看这个名字

name属性说白了就是link的身份证。你想想看,机器人可能有几十个link,如果没有唯一的名字,joint怎么知道它连的是哪块骨头?

我个人习惯用层级命名法:

  • base_link —— 底盘
  • arm_1_link —— 手臂第一节
  • arm_2_link —— 手臂第二节
  • gripper_left_finger —— 左夹爪

我曾经在一个项目里,把两个link都叫link_1,结果ROS启动时直接报错:Duplicate link name。排查了半小时才发现是复制粘贴忘了改名字。所以,命名规范一定要从一开始就定好。

避坑指南:name中不要使用空格、中文、特殊符号(如@、#、$)。ROS底层用的是XML解析器,这些字符会导致解析失败。我曾经见过一个团队用中文命名,结果在rviz里显示乱码,最后全部重写。

4.3 惯性属性<inertial>的组成

惯性属性是link里最容易出错的地方。很多初学者直接抄网上的例子,结果机器人仿真时要么飞上天,要么原地打转。为什么会这样?因为惯性参数不对。

<inertial>包含三个子元素:

子标签 作用 必填 常见错误
<origin> 惯性坐标系相对于link坐标系的偏移 是 忘记设置,默认在原点,导致质心偏移
<mass> 质量,单位kg 是 写0或负数,Gazebo直接崩溃
<inertia> 惯性张量矩阵的6个独立分量 是 ixx/iyy/izz太小或太大,仿真抖动

4.3.1 <origin>——质心位置

这个标签定义的是惯性坐标系的原点,也就是质心(Center of Mass, CoM)的位置。默认情况下,惯性坐标系和link坐标系重合。如果你的零件形状不对称,就必须手动调整。

<!-- 假设一个长杆,质心在杆的中心偏右一点 -->
<origin xyz="0.05 0 0" rpy="0 0 0"/>

我建议:尽量把link坐标系的原点设在质心位置,这样origin就可以写成xyz="0 0 0",省心不少。但如果你是从CAD导出的模型,质心位置通常已经算好了,直接填就行。

4.3.2 <mass>——质量

这个最简单,就是一个数字。但要注意:单位是千克,不是克,也不是磅。

<mass value="2.5"/>  <!-- 2.5kg -->

我曾经接手过一个项目,对方把所有质量都写成了克,结果仿真时机器人轻得像纸片,一碰就飞。所以,一定要确认单位。

4.3.3 <inertia>——惯性张量

这是最复杂、也最容易出错的部分。惯性张量是一个3x3的对称矩阵,URDF里只需要填写6个独立分量:

<inertia ixx="0.1" ixy="0" ixz="0"
         iyy="0.1" iyz="0"
         izz="0.1"/>

这6个分量的物理意义:

  • ixx、iyy、izz:绕X、Y、Z轴的转动惯量(主对角线)
  • ixy、ixz、iyz:惯性积(非对角线),表示质量分布的不对称性

对于简单几何体,可以用公式估算:

形状 ixx iyy izz
实心球(半径r,质量m) 0.4 * m * r² 0.4 * m * r² 0.4 * m * r²
实心圆柱(半径r,高h,质量m) 0.5 * m * r² m * (3r² + h²) / 12 m * (3r² + h²) / 12
长方体(长a,宽b,高c,质量m) m * (b² + c²) / 12 m * (a² + c²) / 12 m * (a² + b²) / 12

小技巧:如果你不确定惯性参数,可以用SolidWorks、Fusion 360等CAD软件导出。它们会自动计算准确的惯性张量。我个人的习惯是:复杂零件用CAD算,简单零件用手算。

4.4 知识结构图:<link>标签的惯性属性

下面这张图帮你理清inertial标签的内部结构:

连杆标签 <link> 的惯性属性结构 <link name="..."> <inertial> <origin> <mass> <inertia> 各子标签的作用 • <origin>:定义质心位置(xyz)和姿态(rpy),默认在link坐标系原点 • <mass>:定义质量,单位kg,必须大于0 • <inertia>:定义惯性张量的6个独立分量(ixx, ixy, ixz, iyy, iyz, izz) 这三个子标签缺一不可,否则Gazebo或ROS 2的robot_state_publisher会报错

4.5 实战案例:为一个简单的连杆配置惯性

假设我们有一个长0.5m、半径0.05m、质量2kg的实心圆柱,作为机器人的小臂。我们来手算惯性参数。

根据上面的表格,实心圆柱的公式:

  • ixx = 0.5 * m * r² = 0.5 * 2 * 0.05² = 0.0025
  • iyy = m * (3r² + h²) / 12 = 2 * (3*0.05² + 0.5²) / 12 = 2 * (0.0075 + 0.25) / 12 = 2 * 0.2575 / 12 ≈ 0.0429
  • izz = iyy ≈ 0.0429(因为圆柱绕Y和Z轴对称)
  • ixy = ixz = iyz = 0(对称形状,惯性积为0)

最终代码:

<link name="forearm_link">
    <inertial>
        <origin xyz="0 0 0" rpy="0 0 0"/>
        <mass value="2.0"/>
        <inertia ixx="0.0025" ixy="0" ixz="0"
                 iyy="0.0429" iyz="0"
                 izz="0.0429"/>
    </inertial>
    <visual>
        <geometry>
            <cylinder length="0.5" radius="0.05"/>
        </geometry>
    </visual>
    <collision>
        <geometry>
            <cylinder length="0.5" radius="0.05"/>
        </geometry>
    </collision>
</link>

重要提醒:ixx、iyy、izz的值不能为0,也不能太小。我曾经见过有人把ixx写成0.000001,结果仿真时这个link像果冻一样疯狂抖动。一般来说,ixx/iyy/izz至少大于1e-6,否则数值不稳定。

4.6 本章小结

今天我们拆解了<link>标签的上半部分:

  • name属性是link的唯一标识,必须唯一、规范、无特殊字符
  • <inertial>包含origin、mass、inertia三个子标签,缺一不可
  • 惯性张量的6个分量要合理计算,不能随意填写