第3章 · URDF基础语法

URDF 说白了就是机器人的“骨架描述语言”。你想想看,要让一个机器人动起来,总得先告诉系统它长什么样、有哪些零件、关节怎么转吧?URDF 就是干这个的。这一章我们就把它的语法拆开揉碎,从 XML 基础到每个标签的用法,一次性讲清楚。

URDF 基础语法 XML 基础 <robot> 标签 <link> & <joint> 文件格式规范 标签嵌套 · 属性 · 单位 · 命名规范

XML 基础 —— 别被尖括号吓到

URDF 本质上是 XML 的一种方言。如果你写过 HTML,那 XML 对你来说就是小菜一碟。每个标签都用 < > 包起来,成对出现,比如 <robot>...</robot>。属性写在标签名后面,值用双引号括起来。

💡 我的习惯: 写 URDF 时,我总把缩进对齐,父子标签一目了然。曾经有个同事没注意缩进,少写了一个闭合标签,Gazebo 直接崩溃……从那以后我每次写完都会用 xmllint 检查一遍。

<robot> 标签 —— 整个模型的根

每个 URDF 文件最外层必须是 <robot>。它有两个必填属性:name 和 xmlns(命名空间)。我个人习惯把 name 设成机器人的型号,比如 my_rover。

<robot name="my_rover" xmlns:xacro="http://www.ros.org/wiki/xacro">
    <!-- 所有 link 和 joint 都写在这里面 -->
</robot>

嗯,这里要注意:xmlns:xacro 不是必须的,但如果你后面要用 XACRO 宏(第19章会讲),最好提前加上。

<link> 标签 —— 机器人的“骨头”

每个刚体部件就是一个 <link>。比如底盘、轮子、机械臂的连杆。它必须有一个 name 属性,而且名字在整个文件里不能重复。我在项目里吃过亏:两个 link 都叫 base,结果 robot_state_publisher 直接罢工。

一个典型的 link 包含三部分:

  • 视觉(visual) —— 长什么样,用什么几何体,什么颜色。
  • 碰撞(collision) —— 物理引擎算碰撞时用的形状,通常比视觉简单。
  • 惯性(inertial) —— 质量、重心、惯性张量。没有它,仿真里的机器人会像纸片一样飘。
<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.01"/>
    </inertial>
</link>
⚠️ 我曾经踩过的坑: 惯性参数随便填了个 0,结果 Gazebo 里机器人疯狂自旋。后来才明白,惯性张量不能全零,至少对角项要有正值。你可以用 urdf_to_graphviz 检查模型,但惯性不对只能靠经验。

<joint> 标签 —— 让零件动起来

关节连接两个 link,定义它们的相对运动。每个 joint 必须有 name 和 type。type 有六种:revolute、continuous、prismatic、fixed、floating、planar。最常用的是 revolute(旋转关节)和 fixed(固定关节)。

关节内部需要指定:

  • parent 和 child —— 谁是谁的父级。父级通常是靠近基座的 link。
  • origin —— 关节原点在父级坐标系下的位置和姿态。
  • axis —— 旋转轴或移动轴的方向向量。
  • limit —— 对于可动关节,必须设置 lower、upper、effort、velocity。
<joint name="wheel_joint" type="revolute">
    <parent link="base_link"/>
    <child link="left_wheel"/>
    <origin xyz="0.2 0.15 0" rpy="0 0 0"/>
    <axis xyz="0 1 0"/>
    <limit lower="-3.14" upper="3.14" effort="10" velocity="1.0"/>
</joint>
🔧 实战建议: 我一般先把所有 link 的视觉和碰撞写完,再统一加关节。这样思路清晰,不会漏掉连接。另外,origin 的 rpy 用弧度制,别写成角度,否则关节会歪到离谱。

URDF 文件格式规范 —— 细节决定成败

写 URDF 就像写代码,有规有矩才能不出错。下面是我总结的几个硬性规范:

规范项要求反例 / 说明
文件后缀.urdf 或 .xacro不要用 .xml,ROS 工具可能不识别
编码UTF-8中文注释?可以,但最好全英文,避免跨平台乱码
标签闭合所有标签必须闭合<link>...</link> 或自闭合 <material/>
命名规则link/joint 名称只能用字母、数字、下划线不要用空格、连字符,否则解析报错
单位长度:米,角度:弧度,质量:千克我曾经把轮距写成厘米,结果模型缩成玩具车
根标签只能有一个 <robot>多根标签会导致解析失败

你想想看,如果单位搞错了,机器人要么变成巨人,要么变成蚂蚁。我刚开始学的时候,把 origin 的 z 写成 0.05 米,结果轮子陷进地里一半。后来养成习惯,所有尺寸都用米,角度用弧度,再也没出过这种低级错误。

📌 避坑指南: 我曾经在 joint 的 axis 里写了 xyz="0 0 0",Gazebo 直接报错“axis cannot be zero vector”。记住,旋转轴必须是非零向量。还有,limit 里的 effort 和 velocity 别设成 0,否则关节像焊死了一样。

好了,URDF 基础语法就这些。说白了就是 <robot> 包着 <link> 和 <joint>,再加上一堆属性。下一章我们亲手写一个完整的 URDF 模型,到时候你会觉得这东西其实挺简单的。