第四节:配置机器人仿真环境——创建仿真世界、添加静态障碍物、设置光照与物理参数

各位同学,欢迎来到第四节。今天我们要亲手搭建一个完整的仿真世界。

说实话,很多初学者一上来就急着跑导航算法,结果发现机器人要么撞墙、要么飘在空中。为什么?因为仿真环境没配好。我刚开始做项目时也吃过这个亏——在Gazebo里随便拉了个地面就开始调参数,折腾了两天,最后发现是物理引擎的摩擦系数设错了。

所以这一节,我们稳扎稳打,把仿真世界的底子打好。

4.1 创建仿真世界(World)

Gazebo里的世界文件,说白了就是一个描述环境的XML文件。它告诉仿真器:地面长什么样、墙在哪、光照从哪来、重力有多大。

我个人习惯用.world后缀来命名。先看一个最基础的例子:

<?xml version="1.0" ?>
<sdf version="1.6">
  <world name="my_robot_world">
    <include>
      <uri>model://sun</uri>
    </include>
    <include>
      <uri>model://ground_plane</uri>
    </include>
  </world>
</sdf>

这个文件做了两件事:加了一个太阳光源,加了一个地面。保存为empty.world,然后用gazebo empty.world启动,你就能看到一个空荡荡的世界。

小技巧: 我建议把世界文件放在你的机器人功能包里的worlds/目录下,方便管理。比如my_robot_bringup/worlds/。

4.2 添加静态障碍物

空世界没什么好玩的。我们要加一些障碍物,让机器人有东西可以绕。

静态障碍物,就是不会动、不会碎的物体。Gazebo里用<model>标签来定义。下面是一个长方体障碍物的例子:

<model name="obstacle_01">
  <static>true</static>
  <link name="link">
    <collision name="collision">
      <geometry>
        <box>
          <size>0.5 0.5 1.0</size>
        </box>
      </geometry>
    </collision>
    <visual name="visual">
      <geometry>
        <box>
          <size>0.5 0.5 1.0</size>
        </box>
      </geometry>
      <material>
        <ambient>0.8 0.2 0.2 1</ambient>
      </material>
    </visual>
  </link>
  <pose>2.0 1.5 0.5 0 0 0</pose>
</model>

注意看,<static>true</static>表示这个物体是固定的,不会被撞飞。<pose>定义了它的位置和朝向。这里我把它放在(2.0, 1.5)处,高度0.5米。

避坑指南: 我曾经犯过一个低级错误——只设置了<visual>忘了加<collision>。结果机器人直接穿模过去了,因为Gazebo根本检测不到碰撞。记住:视觉和碰撞是两个独立的部分,都得配。

如果你想加多个障碍物,复制粘贴这个模型块,改个名字和位置就行。比如:

<model name="obstacle_02">
  <static>true</static>
  <link name="link">
    <collision name="collision">
      <geometry>
        <cylinder>
          <radius>0.3</radius>
          <length>0.8</length>
        </cylinder>
      </geometry>
    </collision>
    <visual name="visual">
      <geometry>
        <cylinder>
          <radius>0.3</radius>
          <length>0.8</length>
        </cylinder>
      </geometry>
      <material>
        <ambient>0.2 0.8 0.2 1</ambient>
      </material>
    </visual>
  </link>
  <pose>-1.0 2.0 0.4 0 0 0</pose>
</model>

这是一个绿色圆柱体,放在(-1.0, 2.0)处。你想想看,如果场景里只有方盒子,导航算法跑起来其实没什么挑战。加一些圆柱、球体,效果会真实很多。

4.3 设置光照参数

光照影响什么?影响传感器的仿真效果,尤其是摄像头和激光雷达。光线太暗,摄像头拍出来全是噪点;光线太强,激光雷达可能被干扰。

Gazebo默认的太阳光其实够用,但如果你想精细控制,可以手动定义光源:

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

这里我设置了一个方向光,从斜上方打下来。注意<diffuse>控制光的颜色和强度,<cast_shadows>开启阴影。阴影对视觉SLAM影响很大,建议开启。

经验之谈: 我在做室内机器人项目时,发现默认光照下摄像头图像偏暗。后来把<diffuse>的RGB值从0.8调到了1.0,效果好了很多。但别调太高,否则画面过曝。

4.4 设置物理参数

物理参数决定了机器人怎么动、怎么停、会不会打滑。Gazebo的物理引擎基于ODE(Open Dynamics Engine),我们可以调整以下关键参数:

参数 默认值 说明
gravity 0 0 -9.8 重力加速度,Z轴负方向
max_step_size 0.001 物理仿真步长,越小越精确
real_time_factor 1.0 实时因子,1.0表示实时仿真
friction 1.0 摩擦系数,影响打滑程度

配置方法如下:

<physics type="ode">
  <max_step_size>0.002</max_step_size>
  <real_time_factor>1.0</real_time_factor>
  <real_time_update_rate>500</real_time_update_rate>
  <gravity>0 0 -9.81</gravity>
</physics>

这里我把步长设为0.002秒,更新率500Hz。为什么这么设?因为我的机器人运动速度较快,步长太小计算量太大,步长太大又容易穿透障碍物。0.002是个折中值。

注意: 如果你发现机器人在地面上抖动或者漂移,多半是摩擦系数没调好。我曾经遇到过机器人原地打转的问题,排查了半天,最后发现是<friction>设成了0.1。改成1.0后立刻稳了。

4.5 完整的世界文件示例

把上面所有内容整合起来,就是一个完整的世界文件:

<?xml version="1.0" ?>
<sdf version="1.6">
  <world name="nav2_test_world">
    <physics type="ode">
      <max_step_size>0.002</max_step_size>
      <real_time_factor>1.0</real_time_factor>
      <real_time_update_rate>500</real_time_update_rate>
      <gravity>0 0 -9.81</gravity>
    </physics>

    <light name="sun" type="directional">
      <cast_shadows>true</cast_shadows>
      <pose>0 0 10 0 0 0</pose>
      <diffuse>1.0 1.0 1.0 1</diffuse>
      <specular>0.2 0.2 0.2 1</specular>
      <direction>-0.5 0.1 -0.9</direction>
    </light>

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

    <model name="obstacle_01">
      <static>true</static>
      <link name="link">
        <collision name="collision">
          <geometry>
            <box>
              <size>0.5 0.5 1.0</size>
            </box>
          </geometry>
        </collision>
        <visual name="visual">
          <geometry>
            <box>
              <size>0.5 0.5 1.0</size>
            </box>
          </geometry>
          <material>
            <ambient>0.8 0.2 0.2 1</ambient>
          </material>
        </visual>
      </link>
      <pose>2.0 1.5 0.5 0 0 0</pose>
    </model>

    <model name="obstacle_02">
      <static>true</static>
      <link name="link">
        <collision name="collision">
          <geometry>
            <cylinder>
              <radius>0.3</radius>
              <length>0.8</length>
            </cylinder>
          </geometry>
        </collision>
        <visual name="visual">
          <geometry>
            <cylinder>
              <radius>0.3</radius>
              <length>0.8</length>
            </cylinder>
          </geometry>
          <material>
            <ambient>0.2 0.8 0.2 1</ambient>
          </material>
        </visual>
      </link>
      <pose>-1.0 2.0 0.4 0 0 0</pose>
    </model>
  </world>
</sdf>

保存为nav2_test.world,启动Gazebo加载它:

gazebo nav2_test.world

你应该能看到一个带阴影的明亮场景,地面上有一个红色方柱和一个绿色圆柱。

4.6 本章知识体系

下面这张图帮你理清今天的内容结构:

仿真环境配置核心要素 创建世界 .world文件 静态障碍物 碰撞+视觉 光照设置 方向光/点光源 物理参数 重力/摩擦/步长 关键原则 碰撞与视觉必须成对出现 | 光照影响传感器仿真 | 物理参数决定运动真实性 常见问题与解决 • 机器人穿模 → 检查是否缺少<collision>标签 • 机器人抖动 → 调整摩擦系数或减小步长 • 传感器数据异常 → 检查光照强度和阴影设置

嗯,到这里,你的仿真世界已经初具雏形了。下一节我们会把机器人模型放进去,让它在这些障碍物之间跑起来。不过在那之前,我建议你多试试不同的障碍物形状和位置,熟悉一下XML的写法。

课后练习: 试着在场景中添加一个球体障碍物,位置在(0, -2, 0.3),颜色为蓝色。然后启动Gazebo验证效果。

可可精品资料库