3、机器人建模基础:URDF与SDF格式详解,从零搭建一个差速轮底盘模型
说到机器人建模,很多新手第一反应就是「画个3D模型」。其实不然。在仿真和真机部署之间,我们需要一种机器能读懂的语言来描述机器人长什么样、关节怎么动、传感器装在哪。这就是URDF和SDF干的事。
我个人习惯把URDF比作机器人的「身份证」——它告诉仿真器:我有几个轮子、底盘多大、重心在哪。而SDF更像「户口本」,能描述更复杂的环境和物理属性。今天咱们就从零搭一个差速轮底盘,把这两个格式都走一遍。
核心知识点速览
- URDF vs SDF:什么时候用哪个?
- 差速轮底盘的几何与运动学模型
- 从零手写URDF文件
- 用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 传感器),咱们后面章节再聊。记住一点:模型是机器人的「骨架」,骨架搭正了,后面的算法才能跑得稳。