第二章 仿真环境搭建:ROS + Gazebo 环境安装、创建简单障碍物场景、配置机器人模型与传感器插件

好,咱们正式开始动手了。这一章要解决一个很实际的问题——怎么把仿真环境搭起来。说实话,我见过太多人算法写得飞起,结果一跑仿真就崩,最后发现是环境没配好。所以这一章,咱们稳扎稳打,把地基打牢。

2.1 ROS + Gazebo 环境安装

ROS 和 Gazebo 的关系,说白了就是「大脑」和「身体」。ROS 负责通信、决策,Gazebo 负责物理模拟、传感器数据生成。我个人习惯用 ROS Noetic + Gazebo 11 的组合,稳定,坑少。

推荐版本组合:

  • Ubuntu 20.04 LTS
  • ROS Noetic Ninjemys
  • Gazebo 11(与 ROS Noetic 官方兼容)

安装其实就几条命令,但我建议你一步步来,别复制粘贴一整段。我在项目中遇到过有人因为源没换,装了一整天没装上的情况。

# 1. 设置 sources.list
sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu $(lsb_release -sc) main" > /etc/apt/sources.list.d/ros-latest.list'

# 2. 设置密钥
sudo apt-key adv --keyserver 'hkp://keyserver.ubuntu.com:80' --recv-key C1CF6E31E6BADE8868B172B4F42ED6FBAB17C654

# 3. 更新并安装完整桌面版
sudo apt update
sudo apt install ros-noetic-desktop-full

# 4. 初始化 rosdep
sudo rosdep init
rosdep update

# 5. 设置环境变量
echo "source /opt/ros/noetic/setup.bash" >> ~/.bashrc
source ~/.bashrc

# 6. 安装 Gazebo 11(通常已包含在 desktop-full 中)
sudo apt install gazebo11 gazebo11-plugin-base

小技巧:安装完成后,先跑一下 roscore 和 gazebo 两个命令,看看能不能正常启动。如果 Gazebo 启动后一片漆黑,别慌,可能是显卡驱动问题,装个 nvidia-driver-470 一般能解决。

2.2 创建简单障碍物场景

环境搭好了,接下来咱们得有个「试验场」。你想想看,避障算法总得有东西可避吧?我一般不会一上来就用复杂地图,而是先搭一个简单的障碍物场景,方便调试。

Gazebo 里建场景有两种方式:一是用 GUI 手动拖拽,二是写 .world 文件。我个人更推荐后者,因为可复现、可版本控制。

下面是一个最简单的障碍物场景,包含地面、一面墙和几个柱子:

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

    <!-- 一面墙 -->
    <model name="wall">
      <pose>2.0 0.0 0.5 0 0 0</pose>
      <link name="body">
        <collision name="collision">
          <geometry>
            <box>
              <size>0.2 3.0 1.0</size>
            </box>
          </geometry>
        </collision>
        <visual name="visual">
          <geometry>
            <box>
              <size>0.2 3.0 1.0</size>
            </box>
          </geometry>
          <material>
            <ambient>0.8 0.2 0.2 1</ambient>
          </material>
        </visual>
      </link>
    </model>

    <!-- 两个柱子 -->
    <model name="pillar1">
      <pose>1.0 1.5 0.5 0 0 0</pose>
      <link name="body">
        <collision name="collision">
          <geometry>
            <cylinder>
              <radius>0.2</radius>
              <length>1.0</length>
            </cylinder>
          </geometry>
        </collision>
        <visual name="visual">
          <geometry>
            <cylinder>
              <radius>0.2</radius>
              <length>1.0</length>
            </cylinder>
          </geometry>
        </visual>
      </link>
    </model>

    <model name="pillar2">
      <pose>1.0 -1.5 0.5 0 0 0</pose>
      <link name="body">
        <collision name="collision">
          <geometry>
            <cylinder>
              <radius>0.2</radius>
              <length>1.0</length>
            </cylinder>
          </geometry>
        </collision>
        <visual name="visual">
          <geometry>
            <cylinder>
              <radius>0.2</radius>
              <length>1.0</length>
            </cylinder>
          </geometry>
        </visual>
      </link>
    </model>
  </world>
</sdf>

注意:我曾经在写 .world 文件时,把 <pose> 的坐标写反了,结果墙直接插到了地里。建议你每次修改后,先用 gazebo --verbose my_world.world 检查一下,看看有没有报错。

2.3 配置机器人模型(差速轮 / 全向轮)

场景有了,该让主角登场了。机器人模型用 URDF 或 SDF 描述。我习惯用 URDF,因为 ROS 生态对 URDF 支持更好。

先说说差速轮模型。差速轮说白了就是两个主动轮 + 一个万向轮,靠左右轮的速度差实现转向。下面是一个极简的差速轮 URDF:

<robot name="diff_drive_robot">
  <link name="base_link">
    <visual>
      <geometry>
        <box size="0.4 0.3 0.1"/>
      </geometry>
    </visual>
  </link>

  <!-- 左轮 -->
  <link name="left_wheel">
    <visual>
      <geometry>
        <cylinder radius="0.05" length="0.04"/>
      </geometry>
    </visual>
  </link>

  <!-- 右轮 -->
  <link name="right_wheel">
    <visual>
      <geometry>
        <cylinder radius="0.05" length="0.04"/>
      </geometry>
    </visual>
  </link>

  <joint name="left_wheel_joint" type="continuous">
    <parent link="base_link"/>
    <child link="left_wheel"/>
    <origin xyz="-0.15 0.2 0" rpy="0 0 0"/>
    <axis xyz="0 0 1"/>
  </joint>

  <joint name="right_wheel_joint" type="continuous">
    <parent link="base_link"/>
    <child link="right_wheel"/>
    <origin xyz="-0.15 -0.2 0" rpy="0 0 0"/>
    <axis xyz="0 0 1"/>
  </joint>
</robot>

全向轮稍微复杂一点。它通常用三个或四个麦克纳姆轮,每个轮子可以独立控制。我建议初学者先从差速轮入手,因为控制逻辑更直观。全向轮虽然运动灵活,但调参时容易让人抓狂——我在项目里就吃过这个亏,全向轮在瓷砖地面上打滑,定位直接飘了。

2.4 传感器仿真插件配置

机器人要感知环境,离不开传感器。Gazebo 里传感器是通过插件实现的。最常用的两个:激光雷达(Lidar)和深度相机。

下面是一个激光雷达插件的配置示例,直接加到 URDF 里就行:

<gazebo reference="laser_link">
  <sensor type="ray" name="head_laser">
    <pose>0 0 0.1 0 0 0</pose>
    <visualize>true</visualize>
    <update_rate>10</update_rate>
    <ray>
      <scan>
        <horizontal>
          <samples>360</samples>
          <resolution>1</resolution>
          <min_angle>-3.14159</min_angle>
          <max_angle>3.14159</max_angle>
        </horizontal>
      </scan>
      <range>
        <min>0.1</min>
        <max>10.0</max>
        <resolution>0.01</resolution>
      </range>
    </ray>
    <plugin name="laser_controller" filename="libgazebo_ros_ray_sensor.so">
      <topicName>/scan</topicName>
      <frameName>laser_link</frameName>
    </plugin>
  </sensor>
</gazebo>

经验之谈:update_rate 别设太高,10Hz 就够用。我见过有人设到 100Hz,结果 CPU 直接拉满,仿真跑得比乌龟还慢。另外,visualize 设为 true 可以在 Gazebo 里看到激光射线,调试时很有用。

深度相机的配置类似,用 depth_camera 插件。这里不展开,后面章节会专门讲传感器融合。

2.5 本章知识体系总览

为了让你对整个流程有个全局认识,我画了一张图。这张图展示了从环境安装到传感器配置的完整链路:

仿真环境搭建核心流程 ROS + Gazebo 安装 Ubuntu 20.04 + Noetic 创建障碍物场景 .world 文件 / GUI 拖拽 配置机器人模型 差速轮 / 全向轮 URDF 传感器仿真插件 激光雷达 / 深度相机 启动仿真 & 验证 roslaunch + rviz 可视化 ← 从安装到验证,一步都不能跳

嗯,这张图基本概括了咱们这一章要做的事。从安装环境开始,到创建场景、配置机器人、挂载传感器,最后启动仿真验证。每一步都有坑,但只要你按顺序来,就不会出大问题。

好了,这一章的内容就到这儿。下一章咱们会正式进入避障算法的核心——如何让机器人「看到」障碍物并做出反应。到时候见。

本章要点回顾:

  • ROS Noetic + Gazebo 11 是当前最稳定的组合
  • 障碍物场景推荐用 .world 文件编写,方便复用
  • 差速轮模型适合初学者,全向轮运动灵活但调参复杂
  • 传感器插件配置时注意 update_rate 不要过高
  • 每次修改后先跑 gazebo --verbose 检查错误
可可精品资料库