3. 环境感知基础:障碍物检测与分割、点云处理基础、栅格地图构建

各位同学,欢迎来到《动态避障控制核心技巧》的第三讲。今天咱们聊点实在的——机器人怎么“看”世界。

你想想看,一个机器人要避开障碍物,第一步是什么?不是算路径,不是调PID,而是得先知道周围有什么。说白了,就是环境感知。我做了这么多年机器人控制,见过太多算法写得漂亮、但传感器数据一塌糊涂的项目。嗯,这里要强调一下:感知是决策的基石,地基没打好,楼盖得再高也得塌。

3.1 障碍物检测与分割:让机器人学会“认东西”

障碍物检测,听起来高大上,其实核心就两件事:“这玩意儿是不是障碍物?”“它到底在哪儿?”

我个人习惯把障碍物分成两类:

  • 静态障碍物:墙、柱子、桌子腿。这些玩意儿不会动,建图时一次性搞定。
  • 动态障碍物:人、其他机器人、滚过来的球。这些才是避障算法的真正挑战。

分割技术就是用来区分这些的。我在项目中遇到过最头疼的问题,就是激光雷达扫到一个人,结果算法把人家的一条腿当成了一根柱子,另一条腿当成另一根柱子——这要是直接避障,机器人就得从人胯下钻过去,多尴尬。

核心思路:使用欧几里得聚类(Euclidean Clustering)或区域生长(Region Growing)算法,将点云中距离相近的点归为一类。每个聚类就是一个候选障碍物。

为什么会这样?因为激光雷达的点云是稀疏的,人的两条腿之间有空隙,如果聚类半径设得太大,两条腿就分开了;设得太小,又容易把人和旁边的桌子腿粘在一起。嗯,这里有个经验值:对于室内场景,聚类半径通常设在 0.1m ~ 0.3m 之间。

// 伪代码:欧几里得聚类
1. 构建KD-Tree加速近邻搜索
2. 初始化一个空队列Q
3. 对于点云中每个未访问的点P:
   a. 将P加入Q
   b. 对于Q中的每个点Pi:
      - 搜索半径r内的所有近邻点
      - 将未访问的近邻点加入Q
   c. 当Q处理完毕,Q中的所有点构成一个聚类
4. 过滤掉点数太少(噪声)或太多(地面)的聚类
避坑指南:我曾经在工厂项目里,因为地面有点坡度,聚类算法把地面上的反光点也当成了障碍物。后来加了高度过滤——只保留高于地面 5cm 以上的点云,问题就解决了。

3.2 点云处理基础:从原始数据到有用信息

点云是什么?说白了就是一堆三维坐标点。激光雷达每秒能扫出几十万个点,但原始数据是不能直接用的——里面有噪声、有离群点、还有大量冗余信息。

我建议你记住三个核心操作:

  1. 体素滤波(Voxel Filter):把空间划分成小立方体,每个立方体只保留一个代表点。这样能大幅降低数据量,同时保留几何结构。我一般设体素大小为 0.05m,效果不错。
  2. 统计滤波(Statistical Outlier Removal):计算每个点与近邻的平均距离,如果距离过大,就判定为离群点扔掉。这招对付传感器噪声特别管用。
  3. 地面去除(Ground Removal):用RANSAC算法拟合一个平面,把地面点去掉。不然机器人会把地面也当成障碍物,那就没法走了。
注意:体素滤波的尺寸不是越小越好。设得太小,数据量降不下来;设得太大,会丢失细节,比如细的桌腿可能直接被滤没了。我一般根据机器人尺寸来定——对于直径 0.5m 的机器人,体素 0.1m 是个不错的起点。

你想想看,处理完的点云,就像一张干净的地图。接下来,我们要把它变成机器人能理解的形式——栅格地图。

3.3 栅格地图构建(Occupancy Grid Map)

栅格地图,就是把环境划分成一个个小格子,每个格子标记为“占用”、“空闲”或“未知”。这是最经典、最实用的环境表示方法之一。

我记得刚入行时,总觉得栅格地图太简单,不如直接用点云。后来做实际项目才发现,栅格地图有两大好处:

  • 计算效率高:路径规划直接在二维栅格上跑A*,比在三维点云里快得多。
  • 不确定性建模:每个格子可以存一个概率值,表示被占用的可能性。传感器有噪声?没关系,用贝叶斯更新慢慢修正。

构建栅格地图的核心公式其实就一个——对数几率更新(Log-Odds Update)

// 对数几率更新公式
L(m_i | z_{1:t}) = L(m_i | z_{1:t-1}) + L(m_i | z_t) - L(m_i)

其中:
- L(m_i) 是格子 i 的先验对数几率(通常设为0,表示50%概率)
- L(m_i | z_t) 是当前观测的逆传感器模型
- 最终概率通过 P = 1 / (1 + exp(-L)) 转换回来

这个公式的好处是,你每次扫到同一个格子,都可以更新它的概率。扫到一次是障碍物,概率变成 0.7;扫到十次都是障碍物,概率就接近 0.99。反过来,如果第一次扫到是障碍物,第二次扫到是空闲,概率会慢慢回调——这就是贝叶斯滤波的魅力。

实践建议:栅格分辨率通常设为 0.05m ~ 0.1m。对于室内导航,0.05m 足够精细;对于室外大场景,0.2m 也可以接受。分辨率越高,内存占用越大——一个 100m x 100m 的区域,0.05m 分辨率需要 400 万个格子,每个格子存一个 float,就是 16MB。嗯,这点内存现在不算什么,但在嵌入式系统上还是要掂量一下。

3.4 知识体系总览

为了让你更直观地理解这三块内容的关系,我画了一张流程图:

环境感知基础:知识体系流程图 激光雷达原始点云 点云预处理(滤波+地面去除) 障碍物检测与分割 栅格地图构建 障碍物列表(位置+尺寸) 占用栅格地图

从这张图你可以看到,整个流程是串行的:原始点云进来,先做预处理,然后兵分两路——一路做障碍物检测与分割,输出障碍物列表;另一路做栅格地图构建,输出占用地图。这两条路最终都会喂给后面的路径规划模块。

我的经验:在实际项目中,我通常会把障碍物检测和栅格地图结合起来用。栅格地图负责全局导航,障碍物列表负责局部避障。比如,栅格地图告诉你前面有一堵墙,障碍物检测告诉你墙前面还站着一个人——这时候机器人就得同时考虑墙的不可穿越性和人的动态性。

好了,这一章的内容就到这里。环境感知是避障的第一步,也是最容易被忽视的一步。很多新手一上来就调路径规划算法,结果发现机器人老是撞墙——其实不是算法不行,是感知没做好。嗯,希望你能把今天讲的内容吃透,下一章我们就要开始聊路径规划了。


公众号:蓝海资料掘金营,微信deep3321