3、Gazebo仿真基础:世界文件、模型文件、SDF格式、传感器仿真
各位同学,欢迎来到Gazebo仿真的核心环节。说实话,我刚开始接触Gazebo时,也被它那一堆文件格式搞得有点懵。但别担心,今天我们就把它拆开揉碎了讲清楚。
3.1 世界文件:仿真的“舞台”
世界文件,说白了就是告诉Gazebo:“嘿,咱们在哪儿仿真?环境长什么样?”它定义了光照、重力、地面、物理参数,还有你要加载的模型。
我个人习惯把世界文件命名为 my_world.world。它的本质是一个SDF文件,但专门用来描述整个仿真环境。
来看一个最简单的例子:
<?xml version="1.0" ?>
<sdf version="1.6">
<world name="default">
<include>
<uri>model://sun</uri>
</include>
<include>
<uri>model://ground_plane</uri>
</include>
<physics name="default_physics" type="ode">
<real_time_update_rate>1000</real_time_update_rate>
<max_step_size>0.001</max_step_size>
</physics>
</world>
</sdf>
这里我加载了太阳和地面。注意那个 physics 标签,它控制着仿真的物理精度。我曾经在项目里把 max_step_size 设成0.01,结果机器人跑起来像在月球上跳舞——太飘了。
max_step_size,但别超过0.005,否则物理碰撞会变得不准确。
3.2 模型文件:你的“演员”
模型文件定义了机器人或物体的外观、碰撞体积、惯性参数等。Gazebo支持两种格式:老牌的URDF和更现代的SDF。
我个人更推荐SDF,因为它能表达URDF做不到的东西,比如关节摩擦、流体阻力。嗯,这里要注意:如果你从ROS1转过来,可能习惯了URDF,但ROS2时代,SDF才是亲儿子。
一个简单的盒子模型长这样:
<?xml version="1.0" ?>
<sdf version="1.6">
<model name="my_box">
<pose>0 0 0.5 0 0 0</pose>
<link name="base_link">
<collision name="collision">
<geometry>
<box>
<size>1 1 1</size>
</box>
</geometry>
</collision>
<visual name="visual">
<geometry>
<box>
<size>1 1 1</size>
</box>
</geometry>
<material>
<ambient>0.8 0.2 0.2 1</ambient>
</material>
</visual>
<inertial>
<mass>1.0</mass>
<inertia>
<ixx>0.166</ixx>
<iyy>0.166</iyy>
<izz>0.166</izz>
</inertia>
</inertial>
</link>
</model>
</sdf>
你想想看,这里分了三个部分:collision 负责物理碰撞,visual 负责你看到的模样,inertial 负责质量分布。三者缺一不可。
inertial 标签,结果Gazebo直接报错崩溃。记住,每个link都必须有惯性参数,哪怕质量设成0.001都行。
3.3 SDF格式:Gazebo的“通用语言”
SDF(Simulation Description Format)是Gazebo的原生格式。它比URDF强大在哪?我列个表你就明白了:
| 特性 | URDF | SDF |
|---|---|---|
| 支持多个机器人 | ❌ 只能描述一个 | ✅ 可以描述多个 |
| 传感器仿真 | ❌ 不支持 | ✅ 原生支持 |
| 物理参数 | 有限 | 丰富(摩擦、阻尼、流体) |
| 世界环境 | ❌ 不能定义 | ✅ 可以定义 |
说白了,如果你要做复杂的仿真,SDF是唯一的选择。我刚开始用URDF做传感器仿真时,折腾了半天发现根本不行——因为URDF压根就没设计这个功能。
3.4 传感器仿真:让机器人“感知”世界
传感器仿真,是Gazebo最吸引人的地方。你可以给机器人装上激光雷达、摄像头、IMU、接触传感器等,然后看它如何与环境互动。
举个例子,给机器人加一个激光雷达:
<sensor name="laser" type="ray">
<pose>0 0 0.1 0 0 0</pose>
<ray>
<scan>
<horizontal>
<samples>360</samples>
<resolution>1</resolution>
<min_angle>-1.57</min_angle>
<max_angle>1.57</max_angle>
</horizontal>
</scan>
<range>
<min>0.1</min>
<max>10.0</max>
<resolution>0.01</resolution>
</range>
</ray>
<plugin name="laser_plugin" filename="libgazebo_ros_ray_sensor.so"/>
</sensor>
这里 samples 是扫描点数,min_angle 和 max_angle 决定了扫描范围。我做过一个项目,把 samples 设成720,结果仿真卡成PPT——因为每个点都要做射线碰撞检测,计算量太大了。
摄像头传感器也很常用:
<sensor name="camera" type="camera">
<camera>
<horizontal_fov>1.047</horizontal_fov>
<image>
<width>640</width>
<height>480</height>
<format>R8G8B8</format>
</image>
<clip>
<near>0.1</near>
<far>100</far>
</clip>
</camera>
</sensor>
注意那个 horizontal_fov,单位是弧度。1.047弧度约等于60度,这是常见的摄像头视角。如果你想要广角效果,可以调到1.57(90度)甚至更大。
为什么会这样设置?因为Gazebo的摄像头模拟的是真实相机的针孔模型,视野越宽,边缘畸变越明显。我在做视觉SLAM仿真时,就吃过这个亏——仿真里跑得好好的,换到真实相机上就崩了,因为真实相机的畸变参数没配好。
3.5 知识体系总览
下面这张图,是我自己总结的Gazebo仿真知识结构,你一看就明白各个模块的关系了:
从这张图你能看到,世界文件、模型文件、SDF格式、传感器仿真这四块是相互关联的。世界文件引用模型,模型用SDF描述,传感器是模型的一部分。搞懂了这四者的关系,Gazebo仿真你就入门了。
/usr/share/gazebo-11/worlds/ 目录下,你可以直接拿来改。
好了,这一章的内容就到这里。记住,仿真不是目的,验证算法才是。下一章我们会把这些知识串起来,做一个完整的机器人仿真案例。
可可精品资料库