4. 实战:搭建一个两轮差速底盘
好,咱们直接动手。这一章我会带你从零开始,搭一个两轮差速底盘的 URDF 模型。底盘 link 怎么设计?轮子的 joint 怎么配?最后怎么在 RViz 里检查?一条龙走完。
我个人习惯先把整体结构想清楚,再写代码。差速底盘说白了就是两个主动轮 + 一个万向轮(或者从动轮),靠左右轮的速度差来转向。你想想看,扫地机器人、AGV 小车,基本都是这个套路。
4.1 底盘 link 设计
底盘是机器人的身体,所有轮子、传感器都挂在它上面。我一般用 base_link 作为根 link。形状嘛,简单点就用 box,尺寸根据实际小车来。
下面是一个典型的底盘 link 定义。注意,我习惯把原点放在底盘几何中心,这样轮子坐标算起来方便。
<link name="base_link">
<visual>
<geometry>
<box size="0.4 0.3 0.08"/>
</geometry>
<origin xyz="0 0 0" 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.08"/>
</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>
这里我用了 box 几何,长 0.4m,宽 0.3m,高 0.08m。碰撞和视觉保持一致,省得后面仿真出幺蛾子。惯性参数我给了个粗略值,真要做实物你得用 CAD 算一下。
4.2 车轮 joint 配置
差速底盘的两个主动轮,一般用 continuous 类型的 joint,可以绕 Y 轴无限旋转。万向轮用 fixed 或者 continuous 都行,这里我用 fixed 简化。
先看左轮 joint。我记得第一次配轮子时,坐标算反了,小车原地转圈……后来学乖了,画个草图再写。
<joint name="left_wheel_joint" type="continuous">
<parent link="base_link"/>
<child link="left_wheel"/>
<origin xyz="-0.15 0.2 -0.04" rpy="0 0 0"/>
<axis xyz="0 1 0"/>
</joint>
解释一下:xyz 里 -0.15 是沿 X 向后(我习惯把车头朝 X 正方向),0.2 是向左偏移(Y 正方向),-0.04 是让轮子中心比底盘底面低一点,刚好露出半个轮子。轴是 Y 轴,这样轮子才能转起来。
右轮对称,把 Y 改成负的:
<joint name="right_wheel_joint" type="continuous">
<parent link="base_link"/>
<child link="right_wheel"/>
<origin xyz="-0.15 -0.2 -0.04" rpy="0 0 0"/>
<axis xyz="0 1 0"/>
</joint>
万向轮我放在底盘后方中间:
<joint name="caster_wheel_joint" type="fixed">
<parent link="base_link"/>
<child link="caster_wheel"/>
<origin xyz="0.15 0.0 -0.06" rpy="0 0 0"/>
</joint>
注意,万向轮一般比主动轮小一点,所以 z 方向更低,保证它着地。
4.3 轮子 link 定义
轮子用圆柱体。左轮和右轮除了名字和颜色,其他一样。我直接贴左轮:
<link name="left_wheel">
<visual>
<geometry>
<cylinder radius="0.05" length="0.04"/>
</geometry>
<origin xyz="0 0 0" rpy="0 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.0001" ixy="0" ixz="0" iyy="0.0001" iyz="0" izz="0.0002"/>
</inertial>
</link>
右轮复制一份,把 link name 改成 right_wheel,颜色可以换成灰色以示区分。万向轮我用小球代替:
<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>
<collision>
<geometry>
<sphere radius="0.03"/>
</geometry>
</collision>
<inertial>
<mass value="0.05"/>
<inertia ixx="0.00001" ixy="0" ixz="0" iyy="0.00001" iyz="0" izz="0.00001"/>
</inertial>
</link>
4.4 可视化检查
写完了别急着高兴,一定要用 RViz 看一眼。我每次都会踩到一些低级错误,比如 joint 轴方向反了、轮子悬空。
启动检查三步走:
- 保存 URDF 文件,比如
diff_drive.urdf。 - 终端运行
check_urdf diff_drive.urdf,看有没有语法错误。 - 用
urdf_to_graphiz diff_drive.urdf生成结构图,确认父子关系。
然后在 RViz 里加载:
ros2 launch urdf_tutorial display.launch.py model:=diff_drive.urdf
或者用 robot_state_publisher 自己发布。我个人偏好直接 launch,省事。
- 轮子是否与底盘有重叠?调整 origin 的 z 值。
- 左右轮是否对称?量一下 Y 方向距离。
- 万向轮是否刚好触地?别让它悬空或陷进底盘。
revolute,结果轮子只能转 ±90°,小车直接趴窝。差速轮一定要用 continuous。
4.5 完整模型一览
把上面所有片段拼起来,就是一个能用的差速底盘 URDF。下面我整理了一个简化的结构表格:
| 组件 | link 名称 | joint 名称 | 类型 | 父 link |
|---|---|---|---|---|
| 底盘 | base_link | — | 根 link | — |
| 左轮 | left_wheel | left_wheel_joint | continuous | base_link |
| 右轮 | right_wheel | right_wheel_joint | continuous | base_link |
| 万向轮 | caster_wheel | caster_wheel_joint | fixed | base_link |
你想想看,这个结构其实很干净。底盘是中心,轮子挂在两边。后面加传感器、加外壳,都往 base_link 上堆就行。
嗯,到这里你已经亲手搭了一个差速底盘。虽然简单,但它是所有移动机器人的基础。下一章我们会在这个底盘上加更多轮子,变成四轮小车。不过那是后话了,先把今天的模型跑起来再说。