3. 第一个URDF模型:创建简单的连杆与关节

说实话,URDF 这玩意儿刚接触时挺唬人的。一堆 XML 标签,什么 link、joint、geometry,看着像天书。但你别怕,拆开来看,其实就两样东西:连杆(link)和关节(joint)。

我当年第一次写 URDF,花了整整一下午才让一个方块出现在 Rviz 里。后来发现,核心逻辑就三句话:
- 连杆是「零件」
- 关节是「连接方式」
- Rviz 是「照妖镜」,能让你看到模型长啥样

好,咱们直接动手。

3.1 连杆(link)—— 机器人的「骨头」

连杆就是机器人的每一个刚体部件。底座、手臂、轮子、摄像头支架……全是 link。每个 link 在 URDF 里就是一个 <link> 标签。

一个最简单的 link 长这样:

<link name="base_link">
    <visual>
        <geometry>
            <box size="0.2 0.1 0.05"/>
        </geometry>
        <origin xyz="0 0 0" rpy="0 0 0"/>
        <material name="blue">
            <color rgba="0 0 1 1"/>
        </material>
    </visual>
</link>

这里我解释一下每个字段:

字段 含义 我的经验
name 连杆的唯一标识 建议用英文小写+下划线,别用中文
visual 可视化属性,决定你在 Rviz 里看到什么 可以没有,但你就看不见它了
geometry 形状:box、cylinder、sphere、mesh 调试阶段用 box 最方便
origin 相对于 link 坐标系的偏移和旋转 默认是 (0,0,0),别乱改
material 颜色和材质 颜色用 RGBA,A=1 不透明
小技巧:调试时把颜色设亮一点,比如红色或亮蓝。我之前用深灰色,在 Rviz 里找了半天没找到模型……后来才发现颜色太暗,跟背景融为一体了。

3.2 关节(joint)—— 连接「骨头」的「韧带」

关节把两个 link 连在一起,并定义它们之间的相对运动。没有关节,你的机器人就是一盘散沙。

关节有几种常见类型:

类型 自由度 典型用途
fixed 0 螺丝固定、焊接、底座
revolute 1(旋转) 关节电机、轮子
prismatic 1(平移) 伸缩臂、滑轨
continuous 1(无限旋转) 车轮、转台
floating 6 无人机、自由漂浮物

一个最简单的 fixed 关节:

<joint name="base_to_wheel" type="fixed">
    <parent link="base_link"/>
    <child link="wheel_link"/>
    <origin xyz="0.1 0 0" rpy="0 0 0"/>
</joint>

注意三个关键点:

  • parent:父连杆,通常是靠近基座的部件
  • child:子连杆,相对于父连杆运动
  • origin:子连杆在父连杆坐标系中的位置
我曾经踩过的坑:把 parent 和 child 搞反了。结果模型在 Rviz 里乱飞,子部件跑到天上去。检查了半天才发现是父子关系颠倒了。记住:父连杆是「不动」的那个参考系。

3.3 完整示例:一个两连杆的简单模型

咱们把上面两个概念合起来,写一个完整的 URDF 文件。这个模型包含一个底座和一个轮子,用 fixed 关节连接。

<?xml version="1.0"?>
<robot name="simple_robot">

    <!-- 底座 -->
    <link name="base_link">
        <visual>
            <geometry>
                <box size="0.3 0.2 0.1"/>
            </geometry>
            <origin xyz="0 0 0" rpy="0 0 0"/>
            <material name="blue">
                <color rgba="0.2 0.4 0.8 1"/>
            </material>
        </visual>
    </link>

    <!-- 轮子 -->
    <link name="wheel_link">
        <visual>
            <geometry>
                <cylinder radius="0.05" length="0.04"/>
            </geometry>
            <origin xyz="0 0 0" rpy="1.57 0 0"/>
            <material name="gray">
                <color rgba="0.5 0.5 0.5 1"/>
            </material>
        </visual>
    </link>

    <!-- 连接底座和轮子 -->
    <joint name="base_to_wheel" type="fixed">
        <parent link="base_link"/>
        <child link="wheel_link"/>
        <origin xyz="0.15 0 -0.05" rpy="0 0 0"/>
    </joint>

</robot>

你发现没有?轮子用了 cylinder,并且 rpy="1.57 0 0" 把它旋转了 90 度,让圆柱的轴线朝 Y 轴方向——这样看起来才像个轮子。1.57 弧度就是 90 度,我习惯用弧度,因为 URDF 只认弧度。

3.4 在 Rviz 中可视化你的第一个模型

模型写好了,怎么看?Rviz 就是你的「3D 预览窗口」。

步骤很简单:

  1. 把上面的 URDF 保存为 simple_robot.urdf
  2. 启动 Rviz:rviz2(ROS2)或 rviz(ROS1)
  3. 在 Rviz 中,添加一个 RobotModel 显示插件
  4. 在 RobotModel 的属性中,把 Robot Description 设为 robot_description
  5. 发布 URDF 到参数服务器:ros2 run robot_state_publisher robot_state_publisher simple_robot.urdf

嗯,这里要注意:Rviz 本身不直接读 URDF 文件。它从 ROS 参数服务器获取模型。所以你需要先启动 robot_state_publisher 节点,它会自动把 URDF 加载到参数里。

核心逻辑:URDF → robot_state_publisher → 参数服务器 → Rviz 显示。缺一环都看不到模型。

3.5 本章知识结构图

下面这张图帮你理清 URDF 模型的核心组成和可视化流程:

URDF 模型核心结构 URDF 文件 连杆 (link) 关节 (joint) visual collision inertial parent child origin robot_state_publisher 加载 Rviz 可视化显示 link 定义零件外观 joint 定义连接关系

3.6 常见问题与避坑

我整理了几个新手最容易踩的坑,你写 URDF 时多留个心眼:

  • 忘记加 <robot> 根标签——URDF 文件必须有一个 <robot name="xxx"> 包裹所有内容
  • link 名称重复——每个 link 的 name 必须唯一,重复会导致加载失败
  • joint 的 parent 和 child 写反——父连杆靠近基座,子连杆远离基座
  • origin 坐标乱写——子连杆的位置是相对于父连杆的,不是世界坐标系
  • 忘记启动 robot_state_publisher——Rviz 不会自动加载 URDF,必须通过这个节点发布
我曾经犯过的错:写了一个 10 个 link 的模型,结果 Rviz 里只显示了 9 个。找了半天发现有一个 link 的 geometry 标签写成了 <geometr>,少了个 y。URDF 解析器不会报错,只会默默跳过。所以,写完一定要用 check_urdf 工具验证一下。

验证命令:

check_urdf simple_robot.urdf

如果输出类似下面这样,说明语法正确:

robot name is: simple_robot
---------- Successfully Parsed XML ---------------
root link: base_link has 1 child(ren)
    child(1):  wheel_link

看到这个输出,你就可以放心去 Rviz 里欣赏你的第一个 URDF 模型了。