3、创建第一个仿真世界:添加地面、添加光源、添加静态物体、保存世界文件。

好,咱们继续往下走。上一章我们把空荡荡的 Gazebo 界面跑起来了,但说实话,一个黑漆漆、啥也没有的仿真环境,看着就像个没装修的毛坯房。你想想看,机器人连个参照物都没有,怎么测试传感器?怎么验证算法?

所以这一章,我们就来亲手「装修」这个毛坯房。我会带你一步步添加地面、打上灯光、摆几个静态物体,最后把这个世界保存下来。嗯,做完这些,你的仿真世界才算真正有了「家」的样子。

核心目标:掌握 Gazebo 世界文件的构建逻辑,理解 .world 文件的 XML 结构。

3.1 世界文件的结构:.world 到底是个啥?

Gazebo 里的世界,说白了就是一个 .world 文件。它本质上是一个 SDF(Simulation Description Format)格式的 XML 文件。我个人习惯把它比作「仿真世界的剧本」——里面定义了场景里有什么、光线怎么打、物理引擎怎么跑。

一个最简的 .world 文件骨架长这样:

<?xml version="1.0" ?>
<sdf version="1.6">
  <world name="my_first_world">
    <!-- 这里放各种元素 -->
  </world>
</sdf>

注意看,最外层是 <sdf> 标签,里面包着一个 <world>。所有地面、光源、模型,都放在 <world> 里面。这个结构其实很直观,对吧?

3.2 添加地面:让机器人有个落脚的地方

没有地面的世界,机器人一出生就会「自由落体」。我在项目中遇到过这种情况,第一次加载模型时直接掉到虚空里去了,找了半天才发现是忘了加地面。

Gazebo 提供了一个内置的地面模型,叫 ground_plane。添加方式很简单,在 <world> 里加上这段:

<include>
  <uri>model://ground_plane</uri>
</include>

就这么两行?对,就这么两行。Gazebo 会自动从模型数据库中加载一个标准地面。不过,如果你想自定义地面的颜色或纹理,可以再加一个 <pose> 标签调整位置,或者用 <material> 改材质。但刚开始,咱们先用默认的。

小提示:model:// 是 Gazebo 内置模型的引用方式。如果你自己下载了模型,也可以用 file:// 指定本地路径。

3.3 添加光源:别让世界一片漆黑

地面有了,但黑乎乎的也看不见。Gazebo 默认会带一个环境光,但很微弱。我建议你手动添加一个太阳光,让场景更真实。

光源的类型主要有三种:

光源类型 说明 适用场景
directional 平行光,模拟太阳 室外场景,全局照明
point 点光源,向四周发光 室内灯泡、手电筒
spot 聚光灯,有方向锥角 舞台灯光、车灯

咱们先加一个平行光,模拟太阳。代码是这样的:

<light name="sun" type="directional">
  <pose>0 0 10 0 0 0</pose>
  <diffuse>0.8 0.8 0.8 1</diffuse>
  <specular>0.2 0.2 0.2 1</specular>
  <direction>-0.5 0.1 -1</direction>
  <attenuation>
    <range>1000</range>
    <constant>0.9</constant>
    <linear>0.01</linear>
    <quadratic>0.001</quadratic>
  </attenuation>
  <cast_shadows>true</cast_shadows>
</light>

这里我解释几个关键参数:

  • diffuse:漫反射颜色,RGB 值,最后一个 1 是透明度。0.8 0.8 0.8 是偏白的暖光。
  • direction:光线方向向量。我习惯让光从左上角打下来,这样阴影比较自然。
  • cast_shadows:是否投射阴影。建议打开,否则物体看起来像飘着的。

为什么会把 pose 设成 0 0 10?因为平行光的位置其实不影响光照效果,但放在高处更符合直觉。你想想看,太阳不就在天上嘛。

3.4 添加静态物体:摆几个家具

光有地面和光源,世界还是太单调。我们来放几个静态物体——比如一个桌子、一个箱子。静态物体意味着它不会动,但机器人可以撞上去、传感器可以检测到它。

Gazebo 内置了一些基础模型,比如 cinder_block(煤渣砖块)、table(桌子)。我们用 cinder_block 来演示:

<include>
  <uri>model://cinder_block</uri>
  <pose>1.0 0.5 0.0 0 0 0</pose>
  <static>true</static>
</include>

注意 <static>true</static> 这一行。它的意思是:这个物体是静态的,物理引擎不会对它施加重力或碰撞力。说白了,它就像钉在地上的柱子,雷打不动。

如果你想让物体可以被推动,就把 static 设为 false 或者直接删掉这行。不过,咱们这一章先做静态的,后面章节再讲动态物体。

避坑指南:我曾经犯过一个错误——给地面也加了 <static>true</static>,结果机器人掉到地面以下去了。因为地面本身默认就是静态的,你再加一层静态约束反而会出 bug。所以,地面模型不要手动加 static 标签。

3.5 保存世界文件:把你的劳动成果存下来

好了,地面、光源、物体都加完了。现在我们要把这个世界保存成一个 .world 文件。这样下次启动 Gazebo 时,直接加载这个文件,就能看到一模一样的场景。

完整的 my_first_world.world 文件内容如下:

<?xml version="1.0" ?>
<sdf version="1.6">
  <world name="my_first_world">
    
    <!-- 地面 -->
    <include>
      <uri>model://ground_plane</uri>
    </include>

    <!-- 太阳光 -->
    <light name="sun" type="directional">
      <pose>0 0 10 0 0 0</pose>
      <diffuse>0.8 0.8 0.8 1</diffuse>
      <specular>0.2 0.2 0.2 1</specular>
      <direction>-0.5 0.1 -1</direction>
      <attenuation>
        <range>1000</range>
        <constant>0.9</constant>
        <linear>0.01</linear>
        <quadratic>0.001</quadratic>
      </attenuation>
      <cast_shadows>true</cast_shadows>
    </light>

    <!-- 静态物体:煤渣砖块 -->
    <include>
      <uri>model://cinder_block</uri>
      <pose>1.0 0.5 0.0 0 0 0</pose>
      <static>true</static>
    </include>

    <!-- 静态物体:再来一个,换个位置 -->
    <include>
      <uri>model://cinder_block</uri>
      <pose>-1.0 -0.5 0.0 0 0 0.5</pose>
      <static>true</static>
    </include>

  </world>
</sdf>

保存文件时,我建议你放在一个专门的目录里,比如 ~/gazebo_worlds/。命名要清晰,别用 test.world 这种名字,以后项目多了根本找不到。我个人习惯用 项目名_场景名.world 的格式。

启动这个世界的命令是:

gazebo ~/gazebo_worlds/my_first_world.world

看到没?Gazebo 加载后,地面、阳光、两个砖块,整整齐齐。你可以用鼠标拖拽视角,从各个角度观察。嗯,这才像个仿真世界的样子。

3.6 本章知识体系

为了让你更直观地理解这一章的内容结构,我画了一张图:

第3章:创建第一个仿真世界 .world 文件 地面 ground_plane 光源 light 静态物体 include directional / point / spot pose / static / uri 保存为 .world 文件

这张图把本章的核心逻辑串起来了:.world 文件是容器,里面装地面、光源、静态物体,最后保存成文件。你以后每次新建世界,都可以按这个模板来。

3.7 小结

这一章我们做了四件事:加了地面让机器人有落脚点,打了灯光让世界亮起来,摆了静态物体让场景有内容,最后保存了世界文件。每一步都不复杂,但组合起来,你就拥有了一个可复用的仿真环境。

嗯,这里要注意一点:.world 文件是纯文本,你可以用任何编辑器修改。我习惯用 VS Code,语法高亮看着舒服。如果你发现加载后物体位置不对,检查一下 <pose> 的坐标值,x、y、z 的顺序别搞反了。

好了,去动手试试吧。把代码敲进去,看看你的第一个仿真世界长什么样。

核心要点回顾:

  • 世界文件以 <sdf> 包裹 <world> 为骨架
  • 地面用 model://ground_plane 引入
  • 光源分三种类型,平行光最常用
  • 静态物体加 <static>true</static> 防止物理干扰
  • 保存文件后通过 gazebo 文件名.world 启动

可可精品资料库