3. URDF核心元素:<robot>、<link>、<joint>

写URDF模型,说白了就是搭积木。你得先定义有哪些零件(link),再说明它们之间怎么连(joint),最后用<robot>这个大盒子把所有东西装起来。我刚开始接触URDF时,总以为把几何画好就行,结果模型死活动不了——后来才发现,关节的方向搞反了。嗯,今天咱们就把这三个核心元素彻底聊透。

URDF 核心三元素 <robot> 根标签 <link> 刚体部件 视觉/碰撞/惯性 <joint> 运动副 类型/父子/坐标 一个 robot 包含多个 link,通过 joint 连接成运动链

3.1 <robot> —— 模型的根

每个URDF文件有且只有一个<robot>标签。它就像集装箱,所有link和joint都放在里面。我个人习惯给<robot>加上name属性,比如name="my_robot"。这名字后面在ROS里会作为命名空间的一部分,挺关键的。

基本结构:
<robot name="my_robot">
    <link name="base_link"> ... </link>
    <joint name="joint1" type="revolute"> ... </joint>
</robot>

你可能会问:能不能在robot标签里加别的?官方允许加version之类的属性,但我建议别画蛇添足。保持干净,后面用xacro扩展时也方便。

3.2 <link> —— 机器人的骨头

link代表刚体部件。一个机器人底盘、一个连杆、一个摄像头外壳,都是link。每个link必须有唯一的名字。我记得第一次做六轴机械臂,给所有link起名arm1, arm2……结果调试时根本分不清哪个是哪个。后来我改用shoulder_link、upper_arm_link这种语义名,舒服多了。

link内部主要包含三个子模块:

  • visual —— 长得什么样(网格、颜色)
  • collision —— 碰撞检测用的简化形状
  • inertial —— 质量、惯性矩阵(动力学仿真必需)
避坑指南: 我曾经偷懒不写collision,直接拿visual当碰撞用,结果Gazebo里两个连杆互相穿透,物理仿真直接崩了。记住:visual管“看起来”,collision管“碰起来”,两者可以不一样。
<link name="base_link">
    <visual>
        <geometry>
            <box size="0.4 0.3 0.1"/>
        </geometry>
        <material name="blue">
            <color rgba="0 0.4 0.8 1"/>
        </material>
    </visual>
    <collision>
        <geometry>
            <box size="0.4 0.3 0.1"/>
        </geometry>
    </collision>
    <inertial>
        <mass value="2.0"/>
        <inertia ixx="0.01" ixy="0" ixz="0" iyy="0.01" iyz="0" izz="0.02"/>
    </inertial>
</link>

3.3 <joint> —— 让零件动起来

joint把两个link连在一起,并定义它们的相对运动。没有joint,你的机器人就是一坨死零件。joint有几种常用类型:

类型说明自由度
revolute旋转关节,有角度限制(像人胳膊肘)1
continuous无限旋转(像车轮)1
prismatic平移关节(像伸缩杆)1
fixed刚性连接,不能动(比如把传感器焊在底盘上)0
floating6自由度浮动(常用于移动基座)6

每个joint必须指定parent和child。说白了,就是告诉机器人:谁是谁的爹。坐标系原点默认在joint的位置,xyz和rpy定义子link相对于父link的偏移。

⚠️ 常见翻车现场: 我见过有人把parent和child填反,结果模型在RViz里拧成麻花。还有,revolute关节忘了设limit,仿真器直接报错。下面是一个标准旋转关节的例子:
<joint name="shoulder_joint" type="revolute">
    <parent link="base_link"/>
    <child link="upper_arm_link"/>
    <origin xyz="0 0 0.2" rpy="0 0 0"/>
    <axis xyz="0 0 1"/>
    <limit lower="-1.57" upper="1.57" effort="10" velocity="1.0"/>
</joint>

3.4 三者的协作关系

你想想看,一个机器人模型就是一棵树。<robot>是根,link是节点,joint是树枝。从base_link开始,通过joint挂上新的link,一层层搭出整个运动链。我个人习惯先画一个拓扑图,再写URDF,这样不容易乱。

核心原则:
  • 每个link只能有一个parent joint(但可以有多个child joint)
  • joint的坐标系原点就是运动副的旋转/平移中心
  • fixed joint虽然不动,但能帮你整理模型层级

嗯,这里要注意:URDF里没有“闭环”的概念。如果你要做并联机构或者闭环运动链,得用其他方法(比如sdf或xacro加约束)。但绝大多数串联机器人、移动底盘,这三个元素完全够用。

我的小习惯: 写joint时,我会在注释里标出关节的极限角度对应机器人什么姿态。比如<!-- 0度时手臂竖直向上 -->。半年后回头看,这些注释能救你命。