空间建模基础:栅格地图、代价地图、配置空间(C-Space)概念

做路径规划,第一步不是写算法,而是想清楚一个问题:机器人眼中的世界长什么样?

你想想看,我们人类看路,一眼就知道哪里能走、哪里是墙。但机器人不行。它看到的只是一堆传感器数据——激光点云、超声波读数、摄像头画面。这些原始数据,必须转换成一种它能理解的空间模型,才能做规划。

我个人习惯把空间建模比作「给机器人画地图」。但这张地图不是普通地图,它要回答三个核心问题:
1. 哪里是空地?
2. 哪里不好走?
3. 机器人本身占多大地方?

对应的,就是今天要讲的三个概念:栅格地图、代价地图、配置空间(C-Space)。

1. 栅格地图:把世界切成小方块

栅格地图是最直观的建模方式。说白了,就是把环境划分成一个个小格子,每个格子标记为「可通过」或「不可通过」。

我在项目中遇到过这样一个场景:用2D激光雷达做室内导航。雷达扫一圈,得到一堆点云。把这些点投影到栅格上,有障碍物的格子标1,空地标0。就这么简单。

但这里有个坑——栅格分辨率怎么选?

分辨率太高,地图太大,计算慢;分辨率太低,障碍物细节丢失,机器人容易撞墙。我一般遵循一个经验法则:栅格边长 = 机器人宽度的 1/3 到 1/5。

核心要点:

  • 栅格地图本质是离散化表示
  • 每个格子存储占用状态(0/1)或概率值
  • 分辨率是精度与效率的平衡点

来看一个简单的栅格地图构建代码片段:

import numpy as np

class GridMap:
    def __init__(self, width, height, resolution):
        self.width = width          # 地图宽度(米)
        self.height = height        # 地图高度(米)
        self.resolution = resolution # 每个格子的边长(米)
        self.grid = np.zeros((int(height/resolution), 
                              int(width/resolution)))
    
    def set_obstacle(self, x, y):
        # 将世界坐标转换为栅格坐标
        gx = int(x / self.resolution)
        gy = int(y / self.resolution)
        self.grid[gy, gx] = 1
    
    def is_free(self, x, y):
        gx = int(x / self.resolution)
        gy = int(y / self.resolution)
        return self.grid[gy, gx] == 0

2. 代价地图:不是所有空地都一样好走

栅格地图只有「能走」和「不能走」两种状态。但实际场景中,有些地方虽然能走,却不好走。

举个例子:
- 地毯区域,机器人轮子打滑,走起来费劲
- 靠近桌腿的地方,虽然能过,但容易刮蹭
- 斜坡路面,耗电量更大

这时候就需要代价地图。每个格子不再只是0或1,而是一个代价值。代价越高,路径规划算法越倾向于避开它。

我的经验:代价地图通常分两层——静态代价和动态代价。静态代价来自地图本身(比如路面材质),动态代价来自实时传感器(比如临时出现的行人)。两层叠加,才是最终规划用的代价图。

代价地图的更新频率很关键。我记得有一次做仓储机器人,代价地图更新太慢,机器人总是撞到突然出现的叉车。后来把更新频率从1Hz提到10Hz,问题就解决了。

代价类型 来源 更新频率 示例
静态代价 预建地图 低频(一次加载) 墙壁、固定货架
动态代价 实时传感器 高频(5-20Hz) 行人、移动障碍物
膨胀代价 算法生成 随静态代价更新 障碍物周边安全区域

3. 配置空间(C-Space):把机器人缩成一个点

这是空间建模里最巧妙的思想。你想想看,路径规划时,如果机器人是个不规则形状,判断它能不能通过某个狭窄通道,计算量会非常大。

C-Space的思路是:把机器人缩成一个点,同时把障碍物按照机器人的尺寸「膨胀」开。

具体怎么做?
- 对于圆形机器人,直接把所有障碍物向外扩展一个半径
- 对于矩形机器人,需要做Minkowski和运算,稍微复杂一些

注意:C-Space的维度取决于机器人的自由度。对于差速轮式机器人,C-Space是2D的(x, y)。但对于机械臂,C-Space可能是6维甚至更高。高维C-Space的建模和规划,是另一个层面的难题。

我曾经在一个项目中踩过坑:用C-Space做AGV的路径规划,障碍物膨胀半径设得太小。结果规划出来的路径,机器人虽然理论上能过,但实际走起来总是擦到货架。后来把膨胀半径从0.1米加到0.15米,问题就解决了。

嗯,这里要注意:膨胀半径不是越大越好。太大,会导致可行区域消失,规划失败。太小,又不够安全。我一般取机器人半径的1.2倍作为安全裕量。

4. 三者的关系:一张图说清楚

这三个概念不是孤立的。它们之间的关系,我用一张SVG图来展示:

栅格地图 离散化环境 0/1 占用状态 静态基础层 代价地图 连续代价值 静态+动态叠加 规划决策层 C-Space 机器人缩为点 障碍物膨胀 规划空间层 空间建模流程 ① 传感器数据 → 栅格地图(原始占用信息) ② 栅格地图 + 代价信息 → 代价地图(可通行性评估) ③ 代价地图 + 机器人尺寸 → C-Space(规划就绪空间) 最终:路径规划算法在C-Space中搜索最优路径

5. 实际项目中的选择建议

讲完理论,说说实际中怎么选。

  • 简单场景(空旷仓库、走廊):只用栅格地图就够了。代价地图和C-Space反而增加计算量。
  • 复杂场景(家庭环境、办公室):栅格地图+代价地图是标配。C-Space看机器人形状是否规则。
  • 高精度场景(手术机器人、精密装配):三者全上,而且分辨率要很高。

避坑指南:我曾经在一个项目中,为了追求精度,把栅格分辨率设到了1厘米。结果地图文件几百兆,规划一次要好几秒。后来改成5厘米,规划时间降到0.2秒,路径质量几乎没有下降。记住:够用就好,别过度设计。

好了,空间建模这块就讲到这里。这三个概念是路径规划的基石,理解透了,后面的算法学起来会轻松很多。

可可精品资料库