4. 占据栅格地图原理:栅格地图定义、概率更新模型、贝叶斯估计在栅格地图中的应用

好,咱们今天聊聊占据栅格地图。这玩意儿,说白了就是扫地机器人脑子里那张“世界地图”。你想想看,机器人又没长眼睛,它怎么知道前面是墙还是空地?靠的就是这张图。

我记得刚入行那会儿,有个项目用的是激光雷达,但地图建出来总是歪歪扭扭的。后来才发现,问题就出在栅格地图的概率更新上。嗯,这里面的门道,咱们一点点掰开揉碎了讲。

4.1 栅格地图的定义

什么叫栅格地图?很简单,就是把环境切成一个个小格子。每个格子代表一小块区域,比如 5cm × 5cm。每个格子存一个值,表示这个格子被障碍物占据的概率。

我个人习惯用 0 到 1 之间的数来表示:

  • 0:绝对空闲(比如开阔地)
  • 1:绝对占据(比如一堵墙)
  • 0.5:完全未知(还没探测过)

你可能会问:“为啥不直接用 0 和 1 两个值?多简单。” 嗯,这里有个坑。传感器是有噪声的,你测一次说这里有障碍,测两次又说没有,那到底信谁?用概率就能把这种不确定性给量化出来。

核心思想:栅格地图不是一张“死图”,而是一个不断更新的概率模型。每个格子都在“学习”自己到底是不是障碍物。

4.2 概率更新模型

好,现在每个格子都有个初始概率,比如 0.5(未知)。机器人走一圈,传感器扫到某个格子,我们就要更新它的概率。

这里有个关键点:更新不是简单的加减法。你不能说“测到一次障碍就加 0.1,测到空闲就减 0.1”。为什么?因为概率论告诉我们,这样会出问题——概率会跑到 [0,1] 范围外面去。

实际工程中,我们用的是 对数几率(log-odds) 模型。公式长这样:

l_t = l_{t-1} + log( p(z|x) / (1 - p(z|x)) )

其中:

  • l_t 是当前格子的对数几率值
  • l_{t-1} 是上一次的值
  • p(z|x) 是传感器模型——给定格子状态 x 时,测到观测值 z 的概率

最后,把对数几率转回概率:

p = 1 - 1 / (1 + exp(l))

我在项目中遇到过一个问题:传感器模型 p(z|x) 设得太乐观,导致地图上全是“鬼影”。后来我学乖了,给传感器模型加了个饱和值,比如最大对数几率不超过 10,最小不低于 -10。这样地图就干净多了。

小技巧:实际代码里,别直接算 exp 和 log,太慢。可以预计算一个查找表,把传感器模型的值存成整数,用查表法更新。我在嵌入式平台上这么干过,速度能快 3 倍。

4.3 贝叶斯估计在栅格地图中的应用

说到概率更新,就绕不开贝叶斯估计。说白了,贝叶斯就是“用新证据更新旧信念”的一套数学框架。

在栅格地图里,公式是这样的:

p(m_i | z_{1:t}, x_{1:t}) = 
  [ p(z_t | m_i) * p(m_i | z_{1:t-1}, x_{1:t-1}) ] / p(z_t | z_{1:t-1}, x_{1:t})

看着复杂?其实意思很简单:

  • 先验:之前认为格子 m_i 是障碍的概率
  • 似然:当前传感器观测 z_t 在格子 m_i 下的可能性
  • 后验:更新后,格子 m_i 是障碍的概率

你想想看,这就像你判断一个人是不是程序员。先验概率可能是 50%(随便猜的)。然后你看到他穿格子衫(观测),似然很高——程序员穿格子衫的概率大。于是后验概率就提高了。再看到他秃头(又一个观测),后验概率继续涨。这就是贝叶斯更新。

我曾经踩过一个坑:在嵌入式平台上直接算浮点数的贝叶斯公式,结果 CPU 跑满了,电池掉电飞快。后来我把所有概率都转成 整数对数几率,用定点数运算,才把性能拉回来。

注意:贝叶斯更新假设每个观测是独立的。但实际中,连续两次激光扫描很可能相关(比如扫到同一面墙)。如果直接套公式,地图会过度自信。我一般会在更新时加一个衰减因子,比如每次只取 0.8 倍的新信息,留 0.2 给旧信息压压惊。

4.4 实际工程中的取舍

理论讲完了,咱们聊聊落地。在真正的扫地机器人上,栅格地图有几个现实问题:

  1. 内存:一个 100m² 的房子,5cm 分辨率,就是 40,000 个格子。每个格子存一个 float(4 字节),就是 160KB。听起来不多?但你还得存好几层地图(比如障碍物、地毯、悬崖),再加上路径规划用的数据结构,内存很快就吃紧了。
  2. 更新速度:激光雷达每秒转 10 圈,每圈 360 个点。每来一个点,就要更新对应的格子。如果算法写得不好,CPU 就炸了。
  3. 动态障碍:家里有宠物、小孩、拖鞋。这些是移动的,不能永久写进地图里。

我个人的做法是:

  • 8 位整数 存对数几率,而不是 float。这样每个格子只占 1 字节,内存省 4 倍。
  • 对动态障碍,单独开一层“临时地图”,每 5 秒清空一次。只有连续出现 3 次以上的障碍,才写入永久地图。
  • 更新时,只更新传感器射线穿过的格子,别全图遍历。这个优化能省 90% 的计算量。

一句话总结:栅格地图的核心就是“用贝叶斯公式,把传感器噪声过滤掉,留下干净的环境信息”。但工程实现时,内存和速度才是真正的老大难。

好,这一章就到这儿。下一章咱们聊聊如何用这些格子做路径规划——让机器人知道“往哪儿走才能扫干净”。