第3章:URDF机器人建模

URDF,全称是Unified Robot Description Format。说白了,它就是ROS世界里描述机器人长什么样的标准语言。你想想看,要让机器人在Gazebo里动起来,总得先告诉它:你长什么样?胳膊多长?轮子多大?传感器装在哪?这些信息,都得靠URDF来定义。

我个人习惯把URDF理解成机器人的「身份证」加「骨架图」。它用XML格式,把机器人的每个部件、每个关节都描述得清清楚楚。刚开始接触时可能会觉得标签有点多,但别急,咱们一个一个来拆解。

3.1 URDF语法基础

URDF文件本质上就是个XML文件。所以它的基本规则很简单:有根标签、有子标签、有属性。根标签是<robot>,所有内容都包在里面。

来看个最简单的例子:

<?xml version="1.0"?>
<robot name="my_robot">
    <link name="base_link">
        <visual>
            <geometry>
                <box size="0.5 0.3 0.1"/>
            </geometry>
        </visual>
    </link>
</robot>

这段代码定义了一个叫my_robot的机器人,它只有一个部件base_link,形状是个长方体。嗯,这里要注意:size属性的三个值分别对应长、宽、高,单位是米。

小技巧:我刚开始写URDF时,经常搞混坐标轴方向。后来养成习惯:先在纸上画个草图,标清楚每个部件的朝向,再动手写代码。这样能省不少调试时间。

3.2 link与joint定义

一个完整的机器人,不可能只有一个部件。多个部件之间怎么连接?这就用到<joint>标签了。

<link>定义的是「刚体」——也就是不会变形的部件。每个link可以包含:

  • visual:视觉外观,用于显示
  • collision:碰撞模型,用于物理仿真
  • inertial:惯性参数,用于动力学计算

<joint>定义的是「连接关系」——两个link之间的约束。常见的joint类型有:

类型 说明 自由度
fixed 固定连接,不能动 0
revolute 旋转关节,像门轴 1
prismatic 滑动关节,像抽屉 1
continuous 无限旋转,像车轮 1

我在项目中遇到过最坑的事:把轮子关节设成了revolute,结果机器人转了几圈就卡住了。后来才意识到,车轮应该用continuous。这种细节,文档里不会特意提醒你。

来看一个带joint的完整例子:

<robot name="two_wheel_robot">
    <link name="base_link">
        <visual>
            <geometry>
                <cylinder radius="0.1" length="0.3"/>
            </geometry>
        </visual>
    </link>

    <link name="left_wheel">
        <visual>
            <geometry>
                <cylinder radius="0.05" length="0.02"/>
            </geometry>
        </visual>
    </link>

    <joint name="left_wheel_joint" type="continuous">
        <parent link="base_link"/>
        <child link="left_wheel"/>
        <origin xyz="0 -0.15 0" rpy="0 1.57 0"/>
        <axis xyz="0 0 1"/>
    </joint>
</robot>

这里<origin>定义了子link相对于父link的位置偏移,rpy是旋转角度(滚转、俯仰、偏航)。<axis>指定了关节的旋转轴方向。

避坑指南:我曾经把rpy的单位搞错了,以为是角度,结果写了个90度进去。实际上URDF里用的是弧度!1.57才是90度。这个错误让我排查了整整一个下午。

3.3 传感器模型添加

光有机械结构还不够,机器人得感知环境吧?URDF里可以添加各种传感器模型。最常见的是激光雷达和摄像头。

添加传感器其实就是在机器人上再加一个link,然后挂上对应的传感器插件。不过URDF本身只负责「外观」,传感器的「功能」要靠Gazebo插件来实现。

来看一个添加激光雷达的例子:

<link name="laser_link">
    <visual>
        <geometry>
            <cylinder radius="0.03" length="0.05"/>
        </geometry>
        <material name="red">
            <color rgba="1 0 0 1"/>
        </material>
    </visual>
</link>

<joint name="laser_joint" type="fixed">
    <parent link="base_link"/>
    <child link="laser_link"/>
    <origin xyz="0.2 0 0.1" rpy="0 0 0"/>
</joint>

这样就在机器人前方0.2米、高度0.1米的位置装了个红色的小圆柱体,代表激光雷达。至于它能不能真的扫描到障碍物,那得在Gazebo里配置传感器插件才行。

核心要点:URDF只负责「长什么样」和「装在哪」。传感器「怎么工作」是Gazebo插件的事。这两个层次要分清楚,不然容易混淆。

3.4 可视化检查

写完了URDF,怎么知道对不对?别急着跑Gazebo,先用ROS自带的可视化工具检查一下。

我最常用的方法是:

  1. 用check_urdf命令检查语法
  2. 用urdf_to_graphiz生成结构图
  3. 在RViz里加载模型看效果

具体操作:

# 检查URDF文件语法
check_urdf my_robot.urdf

# 生成结构图(需要安装graphviz)
urdf_to_graphiz my_robot.urdf

# 在RViz中查看
roslaunch urdf_tutorial display.launch model:=my_robot.urdf

check_urdf会告诉你有没有语法错误、关节定义是否完整。urdf_to_graphiz会生成一张PDF图,清晰地展示所有link和joint的层级关系。

我个人习惯在RViz里做最终检查。因为有些问题,比如link位置不对、关节方向反了,光看代码是看不出来的。在3D视图里转一圈,问题一目了然。

经验之谈:我建议每写完一个部件,就立刻在RViz里看一眼。别等全部写完了再检查。这样能及时发现问题,避免后面改得头疼。

下面这张图展示了URDF建模的核心流程:

URDF建模核心流程 定义link 几何形状、颜色、惯性 定义joint 连接关系、类型、位置 添加传感器 激光雷达、摄像头 可视化检查 check_urdf → RViz Gazebo仿真 加载模型、配置插件、开始仿真 发现问题,返回修改

URDF建模其实就是一个「搭积木」的过程。先定义一个个独立的link,然后用joint把它们连接起来,最后加上传感器。每一步都可以在RViz里实时看到效果,非常直观。

嗯,说到这我想起一个细节:很多新手会把所有link都写在一个文件里。我个人建议按功能模块拆分,比如chassis.urdf、arm.urdf、sensors.urdf,然后用<xacro:include>引入。这样后期维护起来方便得多。

本章核心:URDF是机器人的「骨架」描述文件。掌握link和joint的定义,就能搭建任意结构的机器人模型。可视化检查是必不可少的环节,千万别跳过。