ROS 占据栅格地图(Occupancy Grid Map)原理、存储文件、数据结构

Gmapping、Cartographer 输出的 2D 激光 SLAM 地图,就是占据栅格地图,是移动机器人导航、巡逻、AMCL 定位的基础数据。

一、栅格地图原理

把现实二维平面切分成大量大小一致正方形小格子(cell 栅格)。 每个格子保存该位置被障碍物占据的概率,三种状态:

  1. 空闲 free:可以通行;
  2. 占用 occupied:墙、柜子、障碍物,禁止通行;
  3. 未知 unknown:雷达没有扫描到,不清楚环境情况。

SLAM 建图更新逻辑(传感器模型)

激光雷达一束激光发射出去:

  • 激光打到障碍物的格子 → 提高该格子 “占用” 概率;
  • 激光发射点到障碍物中间穿过的所有格子 → 提高 “空闲” 概率;
  • 没有被激光照射到的格子保持未知。

内部算法不直接存 0‑1 概率,使用对数几率 log‑odds做累加更新,避免乘法带来的数值溢出;保存文件 / ROS 消息时,再换算为 0‑100 的整数概率值。

关键假设:各个栅格互相独立;环境是静态,不考虑动态行人。

二、内存中的数据结构(ROS 消息 nav_msgs/OccupancyGrid)

SLAM 运行时,内存通过 ROS 话题/map发布,消息结构:

plaintext

Header header        // frame_id一般为map坐标系,带时间戳
MapMetaData info
  resolution: float32      // 分辨率:米/每个栅格,例0.05代表5cm一格
  width: uint32            // 地图横向栅格数量
  height: uint32           // 地图纵向栅格数量
  origin: Pose             // 地图左下角在map世界坐标系的位姿(x,y,yaw)
int8[] data                // 一维数组,行优先存储,长度 = width × height

data 数组取值定义

表格

数值 含义
0 完全空闲,可以通行
100 完全被障碍物占用
‑1 未知区域
1~99 中间概率置信度

存储顺序:行优先 row‑major;先存第一行全部格子,再第二行。 栅格索引计算:index = y * width + x

世界坐标 ↔ 栅格像素坐标转换

重要坑:PGM 图片原点在左上角;ROS 物理世界原点对应图片左下角,Y 轴翻转。

plaintext

// 栅格(x_cell,y_cell)格子中心 → 现实世界map坐标
world_x = origin.x + (x_cell + 0.5) * resolution
world_y = origin.y + (y_cell + 0.5) * resolution

三、磁盘存储文件格式:.pgm + .yaml

执行map_server map_saver -f mymap,保存两个配套文件,必须成对使用。

1)mymap.pgm 便携式灰度图(Portable Gray Map)

  • 单通道无损灰度图片,无压缩,没有 jpeg 的压缩伪影,适合存储地图;
  • ROS 输出二进制 P5 格式 pgm; 像素灰度约定: | 像素灰度 | 含义 | |---|---| |0(黑色)| 障碍物占用 | |255(白色)| 空闲可通行 | |205(灰色)| 未知区域 |

注意:pgm 只是可视化存储载体;真正导航逻辑由 yaml 阈值完成翻译。

2)mymap.yaml元数据配置文件完整示例

yaml

image: mymap.pgm
resolution: 0.05
origin: [-8.0, -7.5, 0.0]
occupied_thresh: 0.65
free_thresh: 0.196
negate: 0

字段详解:

  1. image:pgm 图片相对路径;
  2. resolution:分辨率,每像素代表多少米;
  3. origin: [x,y,yaw]:pgm 图片左下角对应 ROS map 坐标系的坐标与旋转角;
  4. occupied_thresh:占用阈值,灰度换算成概率,大于该值判定障碍物;
  5. free_thresh:空闲阈值,小于该值判定空闲;
  6. negate:0 = 不反转;1 反转黑白,极少使用。

加载流程:map_server读取 yaml → 读取 pgm 灰度像素 → 根据两个阈值把灰度转换成‑1/0/100的 int8 数组,生成 OccupancyGrid 消息对外发布。

四、三种地图表达对比

表格

形式 存在位置 数据结构 用途
OccupancyGrid 消息 内存,ROS 话题/map int8 一维数组 + 元数据 给 RVIZ、move_base 导航、AMCL 定位实时使用
pgm+yaml 磁盘文件 灰度图片 + 文本配置 离线保存,重启系统加载地图
SLAM 算法内部地图 算法内存 log‑odds 二维浮点矩阵 建图迭代更新,不对外输出

五、工程高频坑点

  1. PGM 图片左上角≠ROS 世界原点;origin 对应的是图片左下角,Y 轴方向翻转,坐标转换极易算错;
  2. pgm 图片只是可视化导航不是直接读图片黑白,依靠 yaml 里面两个阈值做翻译;修改图片后要同步考虑阈值;
  3. 分辨率调小(0.025)地图更精细,但 width、height 变大,内存占用成倍上涨;
  4. data 数组是一维数组,不要当成二维数组直接访问,公式index=y*width+x不能写错;
  5. 栅格地图只记录障碍物占用概率不存储物体类别,机器人不知道是墙、箱子还是人,只知道能不能通行
Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐