环境感知基础:栅格地图构建、代价地图概念、障碍物膨胀处理、传感器融合策略

各位同学,欢迎来到《四旋翼无人机避障路径设计实战》的第一章。

说实话,做无人机避障这么多年,我最大的感触就是:没有好的环境感知,再牛的路径规划算法都是空中楼阁。你想想看,飞机连周围有什么都不知道,怎么规划路径?所以这一章,咱们先把地基打牢。

1. 栅格地图构建——把世界变成格子

栅格地图,说白了就是把无人机飞行的空间,切成一堆小方格。每个格子要么是“空的”,要么是“有障碍物”。

我个人习惯用0表示空闲,1表示占据。简单粗暴,但有效。

// 栅格地图定义示例
#define MAP_WIDTH  100
#define MAP_HEIGHT 100

uint8_t grid_map[MAP_WIDTH][MAP_HEIGHT]; // 0:空闲, 1:占据

void init_grid_map(void) {
    for (int i = 0; i < MAP_WIDTH; i++) {
        for (int j = 0; j < MAP_HEIGHT; j++) {
            grid_map[i][j] = 0; // 默认全部空闲
        }
    }
}

这里有个坑——栅格分辨率怎么选?我在项目中遇到过,有人把格子设成1cm一个,结果内存直接爆了。你想想,100m×100m的区域,1cm分辨率就是1亿个格子,嵌入式芯片根本扛不住。

注意:栅格分辨率要根据实际场景来。室内飞行建议5-10cm,室外可以放宽到20-50cm。别贪心,够用就行。

2. 代价地图概念——不是所有格子都一样

栅格地图只告诉你“能不能走”,但代价地图告诉你“好不好走”。

举个例子:同样是空闲格子,靠近墙壁的格子,你愿意飞过去吗?万一有点风吹草动,飞机就可能撞墙。所以这些格子虽然空闲,但代价高。

代价地图的核心思想就是:给每个格子赋一个代价值。值越高,越不建议走。

代价值 含义 典型场景
0 完全安全 开阔空域
1-50 低风险 靠近障碍物边缘
51-99 高风险 狭窄通道
100 不可通行 障碍物本身

嗯,这里要注意:代价地图不是静态的。飞行过程中,传感器数据不断更新,代价地图也要实时刷新。我早期做项目时,就是吃了这个亏——地图更新太慢,飞机差点撞树。

3. 障碍物膨胀处理——给障碍物穿件“外套”

为什么要做膨胀处理?原因很简单:无人机不是质点

你想想看,路径规划算法算出来的路径,通常是一条线。但无人机有尺寸啊,机臂、螺旋桨都有物理大小。如果路径刚好贴着障碍物边缘,飞机一转弯,螺旋桨就可能打到墙。

所以,我们要把障碍物“膨胀”一圈。膨胀半径一般取无人机最大尺寸的一半,再加点安全余量。

// 障碍物膨胀处理示例
#define EXPAND_RADIUS 3 // 膨胀3个栅格

void expand_obstacles(uint8_t *map, int width, int height) {
    uint8_t temp[width * height];
    memcpy(temp, map, width * height);
    
    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            if (temp[y * width + x] == 1) {
                // 以障碍物为中心,膨胀周围格子
                for (int dy = -EXPAND_RADIUS; dy <= EXPAND_RADIUS; dy++) {
                    for (int dx = -EXPAND_RADIUS; dx <= EXPAND_RADIUS; dx++) {
                        int nx = x + dx;
                        int ny = y + dy;
                        if (nx >= 0 && nx < width && ny >= 0 && ny < height) {
                            map[ny * width + nx] = 1; // 标记为占据
                        }
                    }
                }
            }
        }
    }
}
小技巧:膨胀半径不是越大越好。我见过有人设了10个栅格的膨胀,结果整个地图全是障碍物,飞机根本没法飞。一般建议膨胀半径 = 无人机半径 / 栅格分辨率 + 1~2个安全栅格。

4. 传感器融合策略——多只眼睛看得更清楚

单传感器总有短板。激光雷达测距准,但看不到玻璃;超声波便宜,但受温度影响大;视觉传感器信息丰富,但光线不好就抓瞎。

所以,传感器融合是必经之路

我常用的融合策略是“加权平均+置信度判断”。每个传感器上报数据时,同时上报一个置信度。比如超声波在2米以内很准,置信度给0.9;超过5米,置信度降到0.3。最后根据置信度加权平均,得到最终的距离值。

// 传感器融合示例(简化版)
typedef struct {
    float distance;
    float confidence; // 0.0 ~ 1.0
} sensor_data_t;

float sensor_fusion(sensor_data_t sensors[], int count) {
    float weighted_sum = 0.0;
    float total_weight = 0.0;
    
    for (int i = 0; i < count; i++) {
        weighted_sum += sensors[i].distance * sensors[i].confidence;
        total_weight += sensors[i].confidence;
    }
    
    if (total_weight < 0.01) return -1; // 所有传感器都不可信
    return weighted_sum / total_weight;
}

我曾经踩过一个坑:超声波和激光雷达数据冲突时,直接取平均值。结果两个传感器一个测到1米,一个测到3米,平均出来2米——但实际障碍物就在1米处。后来我改成“取最小值+置信度校验”,才解决了这个问题。

核心原则:传感器融合不是简单平均,而是“取长补短”。哪个传感器在当前位置最可靠,就多信它一点。

本章知识体系总览

下面这张图,是我画的本章节知识结构。你可以把它当作一张“地图”,随时回来对照。

环境感知基础 — 知识体系 栅格地图构建 • 空间离散化为方格 • 0/1 表示空闲/占据 • 分辨率权衡:精度 vs 内存 • 典型值:室内5cm,室外20cm 代价地图概念 • 每个格子赋予代价值 • 0=安全,100=不可通行 • 靠近障碍物代价递增 • 需实时更新,动态调整 障碍物膨胀处理 • 补偿无人机物理尺寸 • 膨胀半径 = 无人机半径 + 余量 • 避免路径贴边飞行 • 过度膨胀会导致无路可走 传感器融合策略 • 多传感器取长补短 • 加权平均 + 置信度判断 • 冲突时取最小值更安全 • 避免简单平均导致误判 四者协同:构建 → 评估 → 安全处理 → 多源融合

好了,第一章的内容就到这里。记住:环境感知是避障的“眼睛”,眼睛不好使,腿脚再利索也没用。下一章我们会把这些基础应用到实际的路径规划中,到时候你就知道今天打的地基有多重要了。