地图构建:占据栅格地图原理、SLAM基本概念、Gmapping与Cartographer简介

地图构建这事儿,说白了就是让机器人回答三个问题:我在哪?周围有什么?怎么过去? 我刚开始做机器人那会儿,以为地图就是一张照片,后来才发现完全不是那么回事。机器人看到的世界,跟我们人眼看到的完全不一样。

今天咱们就聊聊地图构建的核心——占据栅格地图,以及两个非常主流的SLAM方案:Gmapping和Cartographer。嗯,这里面的坑我踩过不少,慢慢跟你讲。

占据栅格地图:机器人的"格子本"

你想想看,机器人怎么表示一个房间?它没有"沙发"、"茶几"这种概念。最朴素的办法,就是把空间切成一个个小格子,每个格子记录"这里有东西吗"的概率。

这就是占据栅格地图(Occupancy Grid Map)的核心思想。

核心公式(贝叶斯更新)

l(m_i | z_{1:t}, x_{1:t}) = l(m_i | z_{1:t-1}, x_{1:t-1}) + l(m_i | z_t, x_t) - l(m_i)

其中 l 表示对数几率(log-odds),m_i 是第 i 个栅格,z 是观测,x 是位姿。

每个格子存一个值,范围从0到1:

  • 0:空闲(比如走廊中间)
  • 1:占据(比如墙)
  • 0.5:未知(还没探测到)

我在项目里遇到过一个问题:直接用概率值做加法会溢出。后来改用对数几率(log-odds)就好多了。说白了就是把概率映射到(-∞, +∞)的实数域,加减法随便做,最后再映射回0~1。

工程小技巧

实际代码里,栅格值通常用整数表示,比如0~100。0代表空闲,100代表占据,50代表未知。这样省内存,计算也快。

SLAM基本概念:鸡生蛋还是蛋生鸡?

SLAM(Simultaneous Localization and Mapping)——同时定位与地图构建。这名字听着高大上,其实核心矛盾就一个:

要定位,得先有地图;要建图,得先知道位置。

这不就是鸡生蛋蛋生鸡吗?

解决办法是:一边猜一边修正。机器人先假设一个初始位置,然后根据传感器数据一点点修正地图,再用新地图反过来修正位置。循环往复,直到收敛。

我个人习惯把SLAM拆成三个子问题:

  1. 前端(Front-end):数据关联。把当前观测跟已有地图对上号。
  2. 后端(Back-end):优化。根据约束条件调整所有位姿和地图点。
  3. 回环检测(Loop Closure):认出"我来过这里",然后修正累积误差。

我曾经在一个大厂房里跑SLAM,跑了半小时,地图越偏越离谱。后来发现是回环检测没开——机器人转了一圈回来,不认得自己走过的路,误差就这么一点点攒起来了。

注意

回环检测不是万能的。如果环境对称性太强(比如全是白墙的走廊),回环检测很容易误匹配。我建议在特征明显的区域手动触发回环,或者加一些人工标记。

Gmapping:经典中的经典

Gmapping是基于粒子滤波(Particle Filter)的2D SLAM方案。它用一堆粒子来猜测机器人的可能位置,每个粒子带一张小地图。

核心思路:

  • 每个粒子代表一个可能的机器人轨迹
  • 根据激光雷达数据更新粒子权重
  • 权重低的粒子被淘汰,权重高的粒子被复制
  • 最后所有粒子加权平均,得到最终位姿

我当年第一次跑Gmapping,觉得它像个"笨办法"——用大量粒子暴力求解。但后来发现,在室内小场景里,它又快又稳。

特性 Gmapping
算法类型 粒子滤波(RBPF)
适用场景 室内小场景(< 1000m²)
传感器要求 激光雷达 + 里程计
优点 轻量、实时性好、调参简单
缺点 大场景粒子数爆炸、无回环检测

Gmapping有个致命伤:没有显式的回环检测。一旦走远,误差就收不回来了。所以它只适合小范围、闭环路径的场景。

Cartographer:Google的"大杀器"

Cartographer是Google开源的一套SLAM方案,支持2D和3D。它用图优化(Graph Optimization)代替了粒子滤波,解决了Gmapping在大场景下的痛点。

核心思路:

  • 把每一帧激光数据建成一个"子图(Submap)"
  • 子图之间通过约束连接成一个大图
  • 定期做全局优化,把所有子图对齐
  • 回环检测自动修正累积误差

Cartographer的"扫描匹配"核心

// 使用Ceres Solver做非线性优化
problem.AddResidualBlock(
    new AutoDiffCostFunction<ScanMatcherCost, 2, 3>(...),
    nullptr,
    pose_estimate);
problem.Solve(&options, &summary);

这段代码把当前激光帧跟子图做匹配,找到最优位姿。

我去年在一个2000m²的仓库里跑Cartographer,效果出奇的好。跑了半小时,回环一检测,地图几乎没漂移。但代价是计算量大——普通工控机跑起来CPU直接拉满。

特性 Cartographer
算法类型 图优化(Graph SLAM)
适用场景 大场景(> 1000m²)、复杂环境
传感器要求 激光雷达 + IMU + 里程计
优点 回环检测强、大场景稳定
缺点 计算量大、调参复杂

Gmapping vs Cartographer:怎么选?

我个人的经验是:

  • 小房间、走廊、家庭环境 → 用Gmapping。省资源,调参快,够用。
  • 大仓库、商场、工厂 → 用Cartographer。虽然重,但稳。
  • 预算有限、硬件差 → 优先Gmapping。Cartographer对CPU和内存要求高。
  • 需要3D建图 → 只能上Cartographer。Gmapping只支持2D。

避坑指南

我曾经在一个全是玻璃墙的展厅里跑SLAM,激光雷达直接穿透玻璃,地图上全是"幽灵点"。后来加了IMU做辅助,才勉强稳住。记住:激光雷达不是万能的,多传感器融合才是王道。

知识体系总览

下面这张图,把本章的核心逻辑串起来了。你可以把它当个"地图"——嗯,建图的地图。

地图构建知识体系 地图构建知识体系 地图构建 占据栅格地图 SLAM基本概念 主流SLAM方案 概率表示 贝叶斯更新 前端匹配 后端优化 Gmapping Cartographer 核心逻辑 1. 占据栅格地图是SLAM的"输出格式" 2. SLAM解决"定位与建图互相依赖"的问题 3. Gmapping适合小场景(粒子滤波),Cartographer适合大场景(图优化) 4. 实际工程中,多传感器融合 + 回环检测 = 稳定建图

嗯,地图构建这块内容不少,但核心就三件事:格子怎么表示、位置怎么猜、误差怎么消。Gmapping和Cartographer只是两种实现思路,理解了底层逻辑,换什么方案都不怕。

我建议你动手跑一跑。先拿Gmapping跑个室内小房间,再拿Cartographer跑个大走廊。对比一下地图质量和CPU占用,感受会深很多。