第 3.5 节

添加地图

作者:董佳辉

添加地图

这里以添加 rmuc_2026 为例,说明如何把一个新场地接入咱们的仿真和导航工程。换成 rmuc_2027、rmul_2027 或自己的场地名,流程一样,但模型尺寸、坐标和出生点要重新确认。

先分清三种文件:Gazebo 的三维场地、Nav2 的二维栅格地图、small_gicp 定位用的三维点云。 它们分别由不同程序读取,只添加其中一种,其他文件不会自动生成。

文件谁读取具体作用
STL/DAE + 模型 SDF + 世界 SDFGazebo搭建三维环境,决定机器人看到什么、撞到什么、雷达能扫到什么
PGM/PNG + 地图 YAMLmap_server、Nav2提供二维静态地图,表示空闲、障碍和未知区域
PCDsmall_gicp_relocalization;Point-LIO 是否读取取决于先验开关提供保存的三维环境点云,用于定位或先验地图相关功能

当前常规导航的关系为:

三维场地 → Gazebo → 仿真雷达、IMU和机器人运动

二维图片 + 地图YAML → map_server → Nav2静态地图
实时点云 + 先验PCD → small_gicp → map与odom之间的定位变换
实时地形点云 → 代价地图 → 更新当前障碍

如果只是给实车添加已经建好的地图,可以直接看后面的“实车添加地图”,不需要制作 Gazebo 场地。

地图放在哪些文件夹

下面路径都相对于导航工作空间,也就是包含 src/、build/、install/ 的目录。

src/
├── rmu_gazebo_simulator/rmu_gazebo_simulator/
│   ├── config/gz_world.yaml                 # 选择仿真场地、设置机器人出生点
│   └── resource/
│       ├── models/
│       │   └── rmuc_2026/
│       │       ├── model.config             # 模型说明,指定入口model.sdf
│       │       ├── model.sdf                # 模型的显示、碰撞、缩放和位姿
│       │       └── meshes/
│       │           └── rmuc_2026.stl         # 三维场地网格
│       └── worlds/
│           └── rmuc_2026_world.sdf           # 加载场地、物理、传感器和光照
└── pb2025_sentry_nav/pb2025_nav_bringup/
    ├── map/
    │   ├── simulation/                      # 仿真二维地图:图片 + YAML
    │   ├── reality/                         # 实车二维地图:图片 + YAML
    │   └── staging/                         # 临时保存、尚未归档的二维地图
    └── pcd/
        ├── simulation/                      # 仿真定位点云
        ├── reality/                         # 实车定位点云
        └── staging/                         # 临时保存、尚未归档的点云
文件夹或文件具体作用
models/<场地名>/一套三维场地模型;目录名对应 model://<场地名>
meshes/存放 STL、DAE 等真正的三维形状文件
model.config告诉 Gazebo 模型叫什么、从哪个 SDF 文件加载
model.sdf引用网格,定义外观、碰撞、尺寸和位置;只有外观没有碰撞,机器人可能穿过场地
worlds/<场地名>_world.sdf把模型放进完整仿真世界,并配置物理和传感器等系统
gz_world.yaml选择加载哪个世界文件,以及机器人在哪里出生、朝向哪里
map/ 下的图片二维栅格地图的图像数据
map/ 下的 YAML指定图片路径、分辨率、原点和占用判断方式,和图片配套使用
pcd/ 下的 PCD三维环境点云,用于定位;不能拿 STL 改后缀代替

staging/ 只是临时存放目录,导航不会自动读取里面最新的文件。确认可用后,放到对应的 simulation/ 或 reality/。

仿真添加地图

以下以已有新场地 STL、二维图片及配套 YAML、定位 PCD 为前提。建图和保存方法见环境配置与运行。

添加三维模型

在 resource/models/ 下新建 rmuc_2026/meshes/,把新场地 STL 放进去:

resource/models/rmuc_2026/meshes/rmuc_2026.stl

再从原有 rmuc_2025/ 复制 model.config 和 model.sdf 到 rmuc_2026/,按下面修改。

model.config 中把模型名称改成:

<name>rmuc_2026</name>

model.sdf 中把模型名称改成:

<model name="rmuc_2026">

然后把 <visual> 和 <collision> 中的网格路径两处都改成:

<uri>model://rmuc_2026/meshes/rmuc_2026.stl</uri>

同时确认这两项:

配置怎么填
<scale>1 1 1</scale>模型尺寸已经以米表示时使用;毫米转米通常改成 0.001 0.001 0.001,显示和碰撞两处一致
<pose>x y z roll pitch yaw</pose>根据导出模型的原点和方向设置;前三项单位米,后三项单位弧度,不要直接照搬旧场地的偏移

保留 <static>true</static>,让场地固定不动。

添加世界文件

复制:

resource/worlds/rmuc_2025_world.sdf

命名为:

resource/worlds/rmuc_2026_world.sdf

保留原有插件、光照和外层结构,把文件末尾引用场地的部分改成:

<model name="rmuc_2026">
  <include>
    <uri>model://rmuc_2026</uri>
  </include>
  <pose>0 0 0 0 0 0</pose>
  <static>true</static>
</model>

这里的 pose 是场地模型在世界中的位置和姿态,也要根据实际模型调整。模型 SDF 和世界文件里的变换会叠加,不要重复补偿同一个偏移。

外层 <world name="default"> 保持原样,当前工程的桥接和相关服务使用这个世界名。

设置场地和出生点

修改仿真包的 src/rmu_gazebo_simulator/rmu_gazebo_simulator/config/gz_world.yaml,在已有 robots: 下面增加新场地配置,并把顶部的 world 切换过去:

world: "rmuc_2026"

robots:
  # 原有场地配置继续保留

  rmuc_2026:
    - name: "red_standard_robot1"
      color: "red"
      x_pose: "3.4"
      y_pose: "9.5"
      z_pose: "0.7"
      yaw: "0.0"

x_pose、y_pose、z_pose 是机器人在 Gazebo 世界坐标系中的出生位置,单位米;yaw 是朝向,单位弧度。上面的数值只是示例,要按实际地面高度和机器人模型原点调整。

文件里只保留一个顶部 world 和一个 robots,新场地加入已有列表。 当前启动文件会按名称加载 rmuc_2026_world.sdf,再读取 robots 下的 rmuc_2026 出生配置。

放入二维地图和PCD

把准备好的文件放到:

src/pb2025_sentry_nav/pb2025_nav_bringup/
├── map/simulation/
│   ├── rmuc_2026.yaml
│   └── rmuc_2026.pgm
└── pcd/simulation/
    └── rmuc_2026.pcd

地图 YAML 例如:

image: rmuc_2026.pgm
mode: trinary
resolution: 0.05
origin: [-3.4, -9.5, 0]
negate: 0
occupied_thresh: 0.65
free_thresh: 0.196
参数含义
image图片路径;相对路径以这份 YAML 所在目录为基准
mode栅格解释方式;trinary 表示占用、空闲、未知三态
resolution每像素代表多少米;0.05 即 5 cm
origin地图原点在 map 系中的 [x, y, yaw],第三项是转角,不是高度
negate本例 0 表示黑色倾向占用、白色倾向空闲
occupied_thresh、free_thresh像素换算后的占用判断门槛

优先保留建图工具生成的分辨率和原点,不能把出生点简单取负数当作 origin。图片与 PCD 要对应同一个场地,并具有正确的尺度和坐标关系。

本例的 free_thresh: 0.196 用于保留当前三态保存方式写出的未知灰色,具体见map_saver。已有地图应检查自己的图片和元数据,不必直接照抄这组值。

编译并启动

在工作空间根目录执行,已有依赖按前面的环境教程准备:

colcon build --symlink-install --packages-select rmu_gazebo_simulator pb2025_nav_bringup
source install/setup.bash
ros2 launch rmu_gazebo_simulator bringup_sim.launch.py

另开终端,进入同一工作空间,启动导航:

source install/setup.bash
ros2 launch pb2025_nav_bringup rm_navigation_simulation_launch.py \
  world:=rmuc_2026 \
  use_sim_time:=True \
  use_joy:=False \
  slam:=False

gz_world.yaml 里的 world 选择仿真场地,导航命令里的 world:=rmuc_2026 选择同名二维地图和 PCD,两边需要对应。 当前导航入口会读取安装包中的 map/simulation/rmuc_2026.yaml 和 pcd/simulation/rmuc_2026.pcd。

在 Gazebo 中确认场地和机器人位置正确,再在 RViz 中确认地图、点云与机器人位置对应。

实车添加地图

实车只需把已经建好的地图放到 reality/,不需要添加 Gazebo 模型和世界文件:

src/pb2025_sentry_nav/pb2025_nav_bringup/
├── map/reality/
│   ├── site_01.yaml
│   └── site_01.pgm
└── pcd/reality/
    └── site_01.pcd

确认 YAML 中的 image 指向配套图片,重新构建 pb2025_nav_bringup 并 source。 按前面的教程启动硬件和传感器节点后,运行:

source install/setup.bash
ros2 launch pb2025_nav_bringup rm_navigation_reality_launch.py \
  use_sim_time:=False \
  use_joy:=False \
  use_robot_state_pub:=True \
  slam:=False \
  world:=site_01

这里的 world:=site_01 只是选择 map/reality/site_01.yaml 和 pcd/reality/site_01.pcd,不会启动 Gazebo。