3、机器人建模基础:URDF与SDF格式详解,从零搭建一个差速轮底盘模型

说到机器人建模,很多新手第一反应就是「画个3D模型」。其实不然。在仿真和真机部署之间,我们需要一种机器能读懂的语言来描述机器人长什么样、关节怎么动、传感器装在哪。这就是URDF和SDF干的事。

我个人习惯把URDF比作机器人的「身份证」——它告诉仿真器:我有几个轮子、底盘多大、重心在哪。而SDF更像「户口本」,能描述更复杂的环境和物理属性。今天咱们就从零搭一个差速轮底盘,把这两个格式都走一遍。

核心知识点速览

  • URDF vs SDF:什么时候用哪个?
  • 差速轮底盘的几何与运动学模型
  • 从零手写URDF文件
  • 用SDF增强物理仿真精度
  • 常见坑点与调试技巧
机器人建模 URDF 格式 link / joint 定义 坐标系与变换 SDF 格式 物理属性 / 摩擦 传感器 / 插件 差速轮底盘模型实战 几何尺寸定义 轮子与驱动 传感器配置 仿真验证

3.1 URDF 到底是个啥?

URDF 全称是 Unified Robot Description Format,说白了就是 XML 格式的机器人描述文件。它用 link 和 joint 两个核心标签,搭出一棵「树」来描述机器人。

举个例子。一个差速轮底盘,至少包含:

  • base_link:底盘本体,一个扁长方体
  • left_wheel_link 和 right_wheel_link:左右两个驱动轮
  • caster_wheel_link:万向轮(可选,但建议加上,不然仿真里容易翻车)

每个 link 之间用 joint 连接。joint 的类型决定了运动方式——差速轮用 continuous 类型,因为轮子要一直转。

我的经验:刚开始写 URDF 时,我总把 joint 的 xyz 和 rpy 搞反。后来养成习惯:先画个草图,标出每个 link 的原点位置,再写代码。这招帮我省了不少调试时间。

3.2 从零手写差速轮底盘 URDF

咱们直接上代码。下面是一个完整的差速轮底盘 URDF,我加了详细注释。

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

  <!-- 底盘 -->
  <link name="base_link">
    <visual>
      <geometry>
        <box size="0.4 0.3 0.1"/>  <!-- 长40cm,宽30cm,高10cm -->
      </geometry>
      <origin xyz="0 0 0" rpy="0 0 0"/>
      <material name="blue">
        <color rgba="0 0 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>

  <!-- 左轮 -->
  <link name="left_wheel_link">
    <visual>
      <geometry>
        <cylinder radius="0.05" length="0.04"/>
      </geometry>
      <origin xyz="0 0 0" rpy="0 1.5708 0"/>  <!-- 绕Y轴旋转90度,让圆柱变成轮子 -->
      <material name="black">
        <color rgba="0.1 0.1 0.1 1"/>
      </material>
    </visual>
    <collision>
      <geometry>
        <cylinder radius="0.05" length="0.04"/>
      </geometry>
    </collision>
    <inertial>
      <mass value="0.2"/>
      <inertia ixx="0.0001" ixy="0" ixz="0" iyy="0.0001" iyz="0" izz="0.0002"/>
    </inertial>
  </link>

  <!-- 左轮关节 -->
  <joint name="left_wheel_joint" type="continuous">
    <parent link="base_link"/>
    <child link="left_wheel_link"/>
    <origin xyz="-0.15 0.2 -0.05" rpy="0 0 0"/>
    <axis xyz="0 1 0"/>  <!-- 绕Y轴旋转 -->
  </joint>

  <!-- 右轮 -->
  <link name="right_wheel_link">
    <!-- 与左轮类似,略 -->
  </link>

  <joint name="right_wheel_joint" type="continuous">
    <parent link="base_link"/>
    <child link="right_wheel_link"/>
    <origin xyz="-0.15 -0.2 -0.05" rpy="0 0 0"/>
    <axis xyz="0 1 0"/>
  </joint>

  <!-- 万向轮 -->
  <link name="caster_wheel_link">
    <visual>
      <geometry>
        <sphere radius="0.03"/>
      </geometry>
    </visual>
  </link>

  <joint name="caster_wheel_joint" type="fixed">
    <parent link="base_link"/>
    <child link="caster_wheel_link"/>
    <origin xyz="0.15 0 -0.08" rpy="0 0 0"/>
  </joint>

</robot>

注意:惯性矩阵(inertia)的值不能随便填。我曾经偷懒全填了0.001,结果仿真里机器人像纸片一样飘。正确的做法是根据几何形状计算,或者用工具生成。

3.3 SDF 格式:URDF 的升级版

URDF 有个硬伤——它只能描述单个机器人,不能描述场景。而且物理属性支持有限。Gazebo 后来推出了 SDF 格式,说白了就是 URDF 的「Pro 版」。

SDF 最大的改进是:

  • 支持世界描述:地面、墙壁、灯光都能写进去
  • 物理参数更丰富:摩擦系数、恢复系数、阻尼等
  • 支持插件:比如差速轮驱动插件,直接配置就能用

下面是把上面的 URDF 转成 SDF 的核心部分:

<model name="diff_drive_robot">
  <link name="base_link">
    <collision name="collision">
      <geometry>
        <box>
          <size>0.4 0.3 0.1</size>
        </box>
      </geometry>
      <surface>
        <friction>
          <ode>
            <mu>1.0</mu>    <!-- 摩擦系数 -->
            <mu2>0.5</mu2>
          </ode>
        </friction>
      </surface>
    </collision>
  </link>

  <!-- 差速轮驱动插件 -->
  <plugin name="diff_drive" filename="libDiffDrivePlugin.so">
    <left_joint>left_wheel_joint</left_joint>
    <right_joint>right_wheel_joint</right_joint>
    <wheel_separation>0.4</wheel_separation>
    <wheel_diameter>0.1</wheel_diameter>
  </plugin>
</model>

我建议:如果你只是做运动学仿真,URDF 完全够用。但一旦涉及物理交互(比如轮子打滑、碰撞检测),果断上 SDF。我在做 AGV 项目时,URDF 仿真出来的轨迹和真机能差 20%,换成 SDF 后误差降到了 5% 以内。

3.4 差速轮的运动学模型

写完了模型,咱们得理解它怎么动。差速轮的运动学说白了就两个公式:

参数 含义 计算公式
v 线速度 (m/s) v = (v_left + v_right) / 2
ω 角速度 (rad/s) ω = (v_right - v_left) / d
d 轮距 (m) 左右轮中心距离

其中 v_left 和 v_right 是左右轮的线速度。如果你给左右轮不同的速度,机器人就会转弯。这就是「差速」这个名字的由来。

嗯,这里要注意:轮距 d 必须和 URDF 里 joint 的 y 方向偏移一致。比如左轮在 y=0.2,右轮在 y=-0.2,那么 d=0.4。这个值写错了,仿真里的转弯半径就会对不上。

3.5 验证模型:用 check_urdf 和 rviz

写完了别急着跑仿真。先用工具检查一下:

# 检查 URDF 语法
check_urdf my_robot.urdf

# 在 rviz 中可视化
roslaunch urdf_tutorial display.launch model:=my_robot.urdf

如果一切正常,你应该能看到一个蓝色底盘、两个黑色轮子、一个小灰球(万向轮)。试着拖动关节滑块,轮子应该能绕 Y 轴旋转。

常见问题排查:

  • 轮子位置不对?检查 joint 的 origin xyz 值
  • 轮子不转?检查 joint 的 axis 方向
  • 模型显示不全?检查 link 的 geometry 定义

3.6 从仿真到真机的关键一步

URDF 和 SDF 不只是给仿真用的。在真机部署时,ROS 的 robot_state_publisher 节点会读取 URDF,实时发布 tf 变换。这意味着:

  • 你的里程计(odometry)可以直接用 URDF 里的关节信息计算
  • 导航栈(navigation stack)需要 URDF 来知道机器人的轮廓
  • 传感器外参标定也依赖 URDF 里的坐标系定义

所以,花时间把 URDF 写准确,后面能省很多事。我曾经在一个项目里因为 URDF 的轮子半径写错了 1mm,导致里程计累计误差每小时漂了 10 米。查了三天才找到原因。

我的习惯:每次改完 URDF,都用 check_urdf 检查一遍,然后在 rviz 里手动旋转每个关节,确认运动方向正确。这步花不了 5 分钟,但能避免后面几小时的调试。

好了,差速轮底盘的建模基础就这些。URDF 和 SDF 的更多高级用法(比如添加激光雷达、IMU 传感器),咱们后面章节再聊。记住一点:模型是机器人的「骨架」,骨架搭正了,后面的算法才能跑得稳。

可可精品资料库