第3章 机器人建模实战:构建两轮差速底盘
这一章咱们直接动手。不绕弯子,从零开始搭一个两轮差速底盘机器人。你想想看,差速底盘几乎是移动机器人的"Hello World",但真正把它在URDF里建好、轮子转起来、支撑轮不卡地,还是有不少门道的。我个人习惯先把整体结构想清楚再写代码,不然容易改来改去。
3.1 整体设计思路
差速底盘的核心就三个部分:一个车身、两个主动轮、一个或多个支撑轮。主动轮负责驱动和转向——说白了,两边轮子转速不一样就能转弯。支撑轮呢,就是防止底盘前后翘起来。我在项目里见过有人把支撑轮做成固定球,结果转弯时摩擦力太大,直接把底盘拽偏了。所以这里我建议用万向轮模型,或者至少给个浮动关节。
3.2 编写底盘 URDF
我们直接上代码。先定义底盘本体,再挂轮子。注意坐标系:base_link 是底盘中心,轮子关节的 origin 要算好偏移量。
<robot name="diff_drive_base">
<!-- 底盘本体 -->
<link name="base_link">
<visual>
<geometry>
<box size="0.4 0.3 0.12"/>
</geometry>
<origin xyz="0 0 0.06" rpy="0 0 0"/>
<material name="blue">
<color rgba="0.2 0.4 0.9 1.0"/>
</material>
</visual>
<collision>
<geometry>
<box size="0.4 0.3 0.12"/>
</geometry>
</collision>
<inertial>
<mass value="2.0"/>
<inertia ixx="0.01" ixy="0" ixz="0" iyy="0.015" iyz="0" izz="0.01"/>
</inertial>
</link>
<!-- 左驱动轮 -->
<link name="left_wheel">
<visual>
<geometry>
<cylinder radius="0.05" length="0.04"/>
</geometry>
<origin xyz="0 0 0" rpy="1.5708 0 0"/>
<material name="black">
<color rgba="0.1 0.1 0.1 1.0"/>
</material>
</visual>
<collision>
<geometry>
<cylinder radius="0.05" length="0.04"/>
</geometry>
</collision>
<inertial>
<mass value="0.2"/>
<inertia ixx="0.0002" ixy="0" ixz="0" iyy="0.0002" iyz="0" izz="0.0003"/>
</inertial>
</link>
<joint name="left_wheel_joint" type="continuous">
<parent link="base_link"/>
<child link="left_wheel"/>
<origin xyz="-0.15 0.2 -0.06" rpy="0 0 0"/>
<axis xyz="0 1 0"/>
</joint>
<!-- 右驱动轮 (对称) -->
<link name="right_wheel">
<!-- 与左轮相同,略 -->
</link>
<joint name="right_wheel_joint" type="continuous">
<parent link="base_link"/>
<child link="right_wheel"/>
<origin xyz="-0.15 -0.2 -0.06" rpy="0 0 0"/>
<axis xyz="0 1 0"/>
</joint>
<!-- 支撑轮 (万向球) -->
<link name="caster_wheel">
<visual>
<geometry>
<sphere radius="0.03"/>
</geometry>
<material name="silver">
<color rgba="0.7 0.7 0.7 1.0"/>
</material>
</visual>
</link>
<joint name="caster_joint" type="fixed">
<parent link="base_link"/>
<child link="caster_wheel"/>
<origin xyz="0.15 0 -0.09" rpy="0 0 0"/>
</joint>
</robot>
3.3 轮子关节的细节
注意看左轮 joint 的 origin:xyz="-0.15 0.2 -0.06"。为什么 z 是负的?因为 base_link 的原点在底盘几何中心,轮子要往下偏移到底盘下表面。你想想看,如果 z 设成 0,轮子就嵌在车身里了。另外 axis xyz="0 1 0" 表示绕 Y 轴旋转——这样轮子才能向前滚动。
| 关节名称 | 类型 | 位置 (xyz) | 旋转轴 | 说明 |
|---|---|---|---|---|
| left_wheel_joint | continuous | -0.15, 0.2, -0.06 | 0 1 0 | 左驱动轮,绕Y轴 |
| right_wheel_joint | continuous | -0.15, -0.2, -0.06 | 0 1 0 | 右驱动轮,对称 |
| caster_joint | fixed | 0.15, 0, -0.09 | — | 后部支撑球 |
3.4 模型可视化检查
写完了别急着高兴。先跑两个命令,确保模型没毛病。
# 1. 语法与结构检查
check_urdf diff_drive.urdf
# 2. 在 rviz 里看三维效果
ros2 launch urdf_tutorial display.launch.py model:=`pwd`/diff_drive.urdf
# 或者用 ROS1:
roslaunch urdf_tutorial display.launch model:=`pwd`/diff_drive.urdf
check_urdf 会输出关节树,确保每个关节都有 parent 和 child,没有悬空的连杆。我曾经有一次忘了给支撑轮加 link,结果 check_urdf 直接报错,找了好半天才发现。
3.5 在 rviz 里看什么?
- 颜色和材质: 底盘是不是蓝色?轮子是不是黑色?支撑轮是不是银色?
- 关节原点: 轮子是否在正确的位置?左右对称吗?
- 碰撞体: 打开 "RobotModel" 的 "Show Collision" 选项,看看碰撞体是否包裹住了视觉体。
- TF 树: 打开 "TF" 插件,看看坐标系之间的变换是否连续。
我个人习惯在 rviz 里把轮子关节的 continuous 类型手动拖动一下,看看轮子能不能顺畅旋转。如果卡顿或者扭曲,说明惯性参数或者几何原点有问题。
- check_urdf 无报错
- rviz 中模型显示完整,颜色正确
- 轮子位置对称,支撑轮触地
- TF 树无断链
- 关节可正常旋转(continuous类型)
3.6 支撑轮的两种设计思路
支撑轮其实有两种常见做法。一种像我上面写的——固定关节 + 球体,简单可靠。另一种是用浮动关节(floating),让支撑轮可以自由倾斜,更接近真实万向轮。但浮动关节在 URDF 里需要额外指定 type="floating",而且仿真里容易抖动。我个人更推荐固定球体,除非你做的项目对地面适应性要求极高。
3.7 本章小结
我们完成了一个完整的差速底盘 URDF 模型。从底盘本体到两个驱动轮,再到支撑轮,每一步都经过了检查和可视化。你想想看,这个模型虽然简单,但已经包含了 URDF 最核心的要素:link、joint、geometry、inertial、collision。下一章我们会往上面加传感器,但那是后话了。
嗯,到这里,你的第一个移动机器人模型就跑起来了。去 rviz 里转一转,成就感还是有的吧?