环境感知基础:栅格地图构建、代价地图概念、障碍物膨胀处理、传感器融合策略
各位同学,欢迎来到《四旋翼无人机避障路径设计实战》的第一章。
说实话,做无人机避障这么多年,我最大的感触就是:没有好的环境感知,再牛的路径规划算法都是空中楼阁。你想想看,飞机连周围有什么都不知道,怎么规划路径?所以这一章,咱们先把地基打牢。
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亿个格子,嵌入式芯片根本扛不住。
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; // 标记为占据
}
}
}
}
}
}
}
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米处。后来我改成“取最小值+置信度校验”,才解决了这个问题。
本章知识体系总览
下面这张图,是我画的本章节知识结构。你可以把它当作一张“地图”,随时回来对照。
好了,第一章的内容就到这里。记住:环境感知是避障的“眼睛”,眼睛不好使,腿脚再利索也没用。下一章我们会把这些基础应用到实际的路径规划中,到时候你就知道今天打的地基有多重要了。