3、Gazebo仿真环境搭建:创建仿真世界与物理引擎配置
Gazebo仿真环境,说白了就是给我们的激光雷达和机器人搭一个「虚拟试验场」。你想想看,真机调试一次成本多高?撞坏了还得修。所以仿真这一步,我个人觉得是整个联调流程里最值得花时间打磨的环节。
我在项目里遇到过好几次,仿真环境搭得太糙,结果算法在仿真里跑得飞起,一上真车就翻车。嗯,后来我学乖了——仿真世界必须尽可能贴近真实场景。今天我们就来一步步搭好这个虚拟世界。
核心要点:一个合格的仿真世界 = 合理的物理参数 + 有意义的障碍物布局 + 稳定的地面与墙壁结构。
3.1 世界文件的结构与创建
Gazebo的世界文件是 .world 格式,本质上就是一个SDF(Simulation Description Format)文件。我习惯把它放在 my_robot_gazebo/worlds/ 目录下。
先看一个最简世界文件长什么样:
<?xml version="1.0" ?>
<sdf version="1.6">
<world name="lidar_test_world">
<!-- 全局物理属性 -->
<physics type="ode">
<real_time_update_rate>1000</real_time_update_rate>
<max_step_size>0.001</max_step_size>
</physics>
<!-- 光照 -->
<include>
<uri>model://sun</uri>
</include>
<!-- 地面 -->
<include>
<uri>model://ground_plane</uri>
</include>
</world>
</sdf>
这个文件定义了三个基本要素:物理引擎、光照和地面。你直接保存成 empty.world,用 gazebo empty.world 就能打开一个带地板的空白世界。
我的习惯:每次新建世界文件,我都会先跑一遍这个最小模板,确认Gazebo能正常加载,再逐步添加内容。这样可以快速定位是模型问题还是世界配置问题。
3.2 添加障碍物与墙壁
空荡荡的世界没法测试激光雷达。我们需要加一些障碍物。Gazebo支持两种方式:用SDF内联定义,或者引用外部模型。
3.2.1 内联定义障碍物
我个人更推荐内联定义——所有东西写在一个文件里,方便版本管理。下面是一个带墙壁和柱子的世界:
<?xml version="1.0" ?>
<sdf version="1.6">
<world name="lidar_test_world">
<physics type="ode">
<real_time_update_rate>1000</real_time_update_rate>
<max_step_size>0.001</max_step_size>
</physics>
<include>
<uri>model://sun</uri>
</include>
<include>
<uri>model://ground_plane</uri>
</include>
<!-- 北侧墙壁 -->
<model name="wall_north">
<static>true</static>
<link name="link">
<collision name="collision">
<geometry>
<box>
<size>10.0 0.2 2.0</size>
</box>
</geometry>
</collision>
<visual name="visual">
<geometry>
<box>
<size>10.0 0.2 2.0</size>
</box>
</geometry>
<material>
<ambient>0.8 0.8 0.8 1.0</ambient>
</material>
</visual>
</link>
<pose>0.0 5.0 1.0 0 0 0</pose>
</model>
<!-- 圆柱障碍物 -->
<model name="cylinder_obstacle">
<static>true</static>
<link name="link">
<collision name="collision">
<geometry>
<cylinder>
<radius>0.3</radius>
<length>1.0</length>
</cylinder>
</geometry>
</collision>
<visual name="visual">
<geometry>
<cylinder>
<radius>0.3</radius>
<length>1.0</length>
</cylinder>
</geometry>
<material>
<ambient>0.2 0.5 0.8 1.0</ambient>
</material>
</visual>
</link>
<pose>2.0 0.0 0.5 0 0 0</pose>
</model>
</world>
</sdf>
这里有几个关键点:
- <static>true</static>:墙壁和障碍物设为静态,不会被撞飞。我曾经忘了加这个,机器人一碰墙壁,墙壁直接飞出去了……
- pose:位置和姿态,格式是
x y z roll pitch yaw。 - collision 和 visual:必须成对出现。collision 管物理碰撞,visual 管显示。两者几何体可以不同,但我建议保持一致,否则会出现「看着没撞上,实际撞上了」的诡异情况。
3.2.2 障碍物布局建议
为了测试激光雷达的SLAM和导航效果,我一般会摆这几类障碍物:
| 障碍物类型 | 尺寸示例 | 测试目的 |
|---|---|---|
| 长直墙壁 | 10m × 0.2m × 2m | 测试激光雷达的直线检测精度 |
| 圆柱体 | 半径0.3m,高1m | 测试圆形物体的点云拟合效果 |
| L型墙角 | 两段墙壁垂直拼接 | 测试拐角处的反射与遮挡处理 |
| 窄通道 | 宽度0.8m,两侧墙壁 | 测试导航的通过性判断 |
避坑提醒:障碍物不要摆得太密集。激光雷达在狭窄空间里会产生大量反射和多次回波,仿真里可能没问题,但真实场景下数据质量会急剧下降。我一般保持障碍物间距至少1米以上。
3.3 配置物理引擎参数
物理引擎决定了仿真世界的「手感」。Gazebo默认使用ODE(Open Dynamics Engine),也支持Bullet、Simbody等。我个人一直用ODE,稳定且文档齐全。
3.3.1 关键参数详解
下面这张表是我反复调试后总结的核心参数:
| 参数名 | 推荐值 | 作用 |
|---|---|---|
| real_time_update_rate | 1000 | 每秒物理更新次数,越高越精确,但CPU负载也高 |
| max_step_size | 0.001 | 单步最大时间步长(秒),与更新率配合 |
| gravity | 0 0 -9.8 | 重力加速度,默认就是地球标准值 |
| max_contacts | 20 | 每个物体最大接触点数量,太多会拖慢仿真 |
| cfm | 0.01 | 约束力混合参数,控制物体「软硬」程度 |
| erp | 0.2 | 误差修正参数,值越大物体回弹越明显 |
完整的物理引擎配置块长这样:
<physics type="ode">
<real_time_update_rate>1000</real_time_update_rate>
<max_step_size>0.001</max_step_size>
<gravity>0 0 -9.8</gravity>
<max_contacts>20</max_contacts>
<ode>
<solver>
<type>quick</type>
<iters>50</iters>
<sor>1.3</sor>
</solver>
<constraints>
<cfm>0.01</cfm>
<erp>0.2</erp>
<contact_max_correcting_vel>100.0</contact_max_correcting_vel>
<contact_surface_layer>0.001</contact_surface_layer>
</constraints>
</ode>
</physics>
经验之谈:如果你发现机器人在地面上「漂移」或者抖动,多半是 cfm 和 erp 没调好。cfm 太大物体会变「软」,erp 太大物体会「弹」。我一般从 cfm=0.01, erp=0.2 开始,再根据实际表现微调。
3.4 本章知识体系总览
下面这张图帮你理清整个仿真环境搭建的逻辑脉络:
3.5 验证你的世界文件
写完了世界文件,怎么确认它没问题?我一般做三步检查:
- 语法检查:用
gazebo --verbose your_world.world启动,看终端有没有报错。Gazebo的报错信息还算友好,会告诉你哪一行出了问题。 - 物理表现检查:把一个物体放到高处,看它会不会正常下落。如果物体穿模或者飘在空中,说明碰撞体配置有问题。
- 激光雷达模拟测试:在机器人模型上挂一个激光雷达传感器(后面章节会讲),看扫描到的点云是否与障碍物位置吻合。
曾经踩过的坑:有一次我忘了给墙壁加 <static>true</static>,结果Gazebo启动后墙壁直接「躺」在了地上。更坑的是,激光雷达扫描到的点云位置还是对的,但导航算法死活规划不出路径——因为墙壁一直在「滑动」。排查了整整一下午才发现是静态属性没设。
好了,到这里你已经掌握了Gazebo仿真环境搭建的核心技能。世界文件的结构、障碍物的添加方式、物理引擎的参数调优——这三块搞定了,后面往里面放机器人、挂激光雷达就水到渠成了。