基于网格编码的低空路径规划实践指南

1. 概述

无人机配送、设施巡检、应急运输等低空应用场景的快速发展,对三维空间路径规划提出了更高要求。飞行路径需要同时考虑建筑物避让、禁飞区域约束以及多机协同时的冲突检测,传统的二维路径规划难以满足低空场景下精细化的空间计算需求。

那么,有没有一种更简单的方法,让计算机也能高效地”看清”三维空间里的障碍,并快速找到安全的飞行路线呢?答案是:网格编码,它的核心思路是,把三维空间切分成无数个小方块,每个格子标记为”能飞”或”不能飞”。由此复杂的三维几何计算就简化成了”查格子”的问题,路径规划变成在棋盘上找路,碰撞检测变成看两架飞机是否占了同一个格子。

Yukon 空间数据库插件的 yukon_geogridcoder 扩展模块 提供了空间网格编码能力。它集成了多种网格编码标准,能够将三维建筑、二维禁飞区等各类空间对象统一转换为标准网格,并在网格空间中完成高效的路径搜索,从而保障低空飞行的安全。

本文以城市低空配送场景为例,介绍如何使用 Yukon 提供的网格函数,完成”障碍物底图构建 → 路径规划”的完整流程。


2. 为什么选择网格编码?

在深入了解具体操作之前,先花两分钟理解:为什么不用传统的几何计算,而要选择网格编码?

传统方法的痛点:

在三维空间里做路径规划,如果直接对建筑模型、禁飞区进行几何运算,计算机会面临很多难题:

  • 计算复杂:判断无人机是否会撞上一栋形状不规则的建筑,本质上是在做三维空间求交运算,数学上非常复杂,数据量大时速度很慢。

  • 异构数据难融合:低空飞行需要综合建筑、禁飞区、气象等多源数据,这些数据格式、坐标系和精度各异,需要大量的预处理工作。

  • 多机协同难:多架无人机同时飞行时,需要实时检测它们的路径是否会冲突,如果每两架飞行器之间都做几何碰撞检测,计算量会随着飞行器数量急剧增长。

网格编码的优势:

网格编码把复杂的三维几何世界转换成了一张”棋盘”,让路径规划、障碍避让、冲突检测都变成在棋盘上走格子的高效运算。

  • 将几何求交转为网格查询:传统方法需要做复杂的三维空间求交运算,网格编码只需判断目标网格是否被占用,计算逻辑大幅简化。

  • 空间索引原生支持:网格编码可直接创建 GIN 索引,利用网格的层级结构实现快速空间过滤,海量数据下依然高效。

  • 异构数据同源化:建筑模型、禁飞区、气象等多源数据,均可映射到同一套网格体系,无需为每种数据单独做格式转换和坐标对齐。

  • 多机冲突并行检测:多架无人机的路径冲突检测,简化为检查路径网格集合是否重叠,天然支持并行计算和自动避让。


3. 功能介绍

本文涉及的三个核心函数由 Yukon 的 yukon_geogridcoder 扩展模块提供:

函数

功能简介

ST_AsGeoGridCode

将空间几何对象(如建筑、禁飞区)转换为统一的网格编码,支持指定层级控制精度,用于构建网格化障碍物底图。

ST_GridCodeFindMultiDronePath

在网格空间中搜索三维安全路径,支持多组起终点、障碍避让、禁飞区绕行等,可自动检测并规避多机路径冲突。

ST_GeomFromGeoGridCode

将网格编码转换回空间几何对象,支持二维和三维网格,用于在地图或三维场景中可视化展示网格。

上述函数的完整语法与参数说明,请访问 接口参考


4. 最佳实践

4.1. 环境要求

数据库

  • PostgreSQL 16,如使用 GaussDB,需确保内核版本兼容 PostgreSQL 16。

  • Yukon 2.2,已创建 yukon_geogridcoder 扩展:

    CREATE EXTENSION yukon_geogridcoder;
    
  • 数据库 search_path 已包含 Yukon 插件所在的 schema:

    SHOW search_path;  -- 查看当前 search_path
    SET search_path TO public, yukon;  -- 设置 search_path
    
  • 数据库连接客户端,例如 DBeaver、pgAdmin 或命令行 psql。

硬件配置建议

  • 内存 16GB 及以上

  • CPU 4 核及以上

  • 磁盘 SSD,预留 50GB 以上

4.2. 数据概况

三维建筑数据,作为底图数据生成网格,空间数据类型为 GeoModel。

三维建筑原始数据

4.3. 数据入库和处理

  1. 将三维建筑数据导入 Yukon 数据库,确保数据包含几何字段(GeoModel 类型)。示例数据中建筑表名为 Building,空间字段为 smgeometry

  2. 为构建更精细的网格,建议使用工具对建筑数据进行预处理。这里使用 SuperMap iDesktopX 的骨架拆分功能将三维建筑数据 Building 拆分,得到更细粒度的数据集 building_split,作为下面构建网格的源数据。

骨架拆分

4.4. 构建建筑物网格

此步骤是低空飞行的环境建模阶段,构建的建筑物网格将作为低空飞行的底图。

这里构建 24 层级 GeoSOT 网格,网格尺度约 3.9m × 3.9m × 3.9m(1/8″ 网格)。之所以选择 24 层级,是因为这个精度(约 4 米)既能保证无人机与建筑物之间有足够的安全距离,又不会因网格过细而导致数据量爆炸。

GeoSOT 网格层级对照表
-- 创建网格编码表
CREATE TABLE building_grid24 (
    id SERIAL,
    grids geogridcode[]
);

-- 创建 GIN 索引,加速查询
CREATE INDEX building_grid24_gin
    ON building_grid24
    USING GIN (grids);

-- 插入网格数据
INSERT INTO building_grid24 (grids)
SELECT ST_AsGeoGridCode(
    ST_Translate(
        ST_SetSRID(ST_Boundary(smgeometry), 4490),
        0, 0, -6378137
    ),
    24, 'geosot'
)
FROM building_split; -- smgeometry 为表 building_split 的空间字段(GeoModel 类型)

函数说明:

  • ST_Boundary 获取建筑对象的边界;

  • ST_SetSRID 设置坐标系为 EPSG 4490,ST_AsGeoGridCode 当前仅支持 SRID=4490;

  • ST_Translate 将模型的高程原点从地心平移到地表,相当于把海拔基准面”拉”到地面上,便于后续以米为单位进行空间分析;

24 层级网格显示效果

建筑物网格化效果

4.5. 网格路径规划

构建好网格底图后,开始在网格空间中搜索安全路径。

4.5.1 基础路径规划

选择两个起止点,规划三维路径。

-- 创建路径结果表
CREATE TABLE result_path (
    id SERIAL,
    start_point geometry,
    end_point geometry,
    path geogridcode[]
);

-- 路径计算
WITH data AS (
    SELECT (
        ST_GridCodeFindMultiDronePath(
            ARRAY [
                ARRAY ['SRID=4490;POINTZ(116.374115 39.989219 34.615913)', 'SRID=4490;POINTZ(116.376302 39.990080 30.97979)']
            ]::geometry[],
            '[
                {
                    "schema_name": "public", -- 障碍物表所在的 schema
                    "table_name": "building_grid24",  -- 障碍物数据表名
                    "column_name": "grids", -- 障碍物数据表存储网格编码的字段名
                    "is_2d": false, -- false 表示该表存储的是三维网格编码,true 表示该表存储的是二维网格编码
                    "min_level": 24, -- 障碍物网格的最小编码层级
                    "max_level": 24  -- 障碍物网格的最大编码层级
                }
            ]'::JSONB,
            24
        )
    ).*
)

-- 将路径计算结果存入路径结果表
INSERT INTO result_path (start_point, end_point, path)
SELECT start_point, end_point, path FROM data;

关键参数设置说明:

本次路径规划场景的关键参数选择如下:

参数

取值

参数说明

geogrid_level

24

与建筑物网格层级一致(约 3.9m 精度),确保路径与障碍物在同一精度级别上计算,避免偏差

path_pairs

一组飞行起终点

POINTZ 表达三维坐标(经度、纬度、高程)

obstacle_configs

JSONB 格式字符串

配置障碍物数据源,以 JSONB 数组形式传入,每个元素描述一个障碍物表的空间字段、网格层级等信息。当前示例仅配置建筑物网格。

allow_diagonal_movement

false(默认)

低空飞行中不建议对角穿越网格,保持路径与网格方向一致,飞行更平稳

buffer_distance_meters

0(默认)

基础场景暂不设置缓冲区,后续章节单独演示

返回值: 一张包含多条路径的表,包含 start_point(起点)、end_point(终点)、path(起点到终点的最短路径网格编码数组,路径中的每个网格编码都是一个 geogridcode 类型的值,表示无人机飞行过程中经过的每个网格)。

路径可视化

-- 创建路径可视化结果表
CREATE TABLE result_path_vis (
    id SERIAL PRIMARY KEY,
    path_id INT,
    geom geometry(MULTIPOLYGONZ, 4490)
);

-- 将最短路径网格编码转为空间对象,存入路径可视化结果表
INSERT INTO result_path_vis (path_id, geom)
SELECT id,
    ST_GeomFromText(
        REGEXP_REPLACE(
            ST_AsText(ST_GeomFromGeoGridCode(UNNEST(path))),
            'POLYHEDRALSURFACE',
            'MULTIPOLYGON'
        )
    )
FROM result_path;

路径规划效果展示

仅建筑物障碍下的路径规划效果

在地图上,可以看到一条由小方块连成的飞行路线,路径会自动绕开建筑物网格,确保飞行安全。

4.5.2 增加禁飞区域

在上一步的基础上,只需向 obstacle_configs 中增加禁飞区配置,函数会自动将其识别为不可穿越区域并重新规划绕行路径,其余参数保持不变。

WITH data AS (
    SELECT (
        ST_GridCodeFindMultiDronePath(
            ARRAY [
                ARRAY ['SRID=4490;POINTZ(116.374115 39.989219 34.615913)', 'SRID=4490;POINTZ(116.376302 39.990080 30.97979)']
            ]::geometry[],
            '[
                {
                    "schema_name": "public",
                    "table_name": "building_grid24",
                    "column_name": "grids",
                    "is_2d": false,
                    "min_level": 24,
                    "max_level": 24
                },
                {
                    /* 新增:禁飞区配置 */
                    "schema_name": "public", -- 禁飞区表所在的 schema
                    "table_name": "no_fly_zone", -- 禁飞区数据表名
                    "column_name": "smgeometry", -- 禁飞区数据表存储空间对象的字段名
                    "is_2d": true -- 禁飞区数据表存储的是二维面数据
                }
            ]'::JSONB,
            24
        )
    ).*
)
INSERT INTO result_path (start_point, end_point, path)
SELECT start_point, end_point, path FROM data;

与上一步相比,obstacle_configs 中新增了一条禁飞区配置,其中 is_2d: true 表示该表存储的是二维面数据(如行政禁飞区、临时管制区等),路径规划引擎会自动将其扩展为对应层级的三维不可穿越网格,无需手动转换。

路径规划效果对比

场景

路径规划效果

仅建筑物障碍

仅建筑物障碍下的路径

建筑物障碍 + 禁飞区

增加禁飞区后的绕行路径

4.5.3 多机协同路径规划

设置多对起止点,当路径在网格层面发生重叠时,系统会自动调整,防止碰撞。只需修改 path_pairs 参数,障碍物配置可与上一步保持一致:

WITH data AS (
    SELECT (
        ST_GridCodeFindMultiDronePath(
            ARRAY [
                /* 第 1 组起终点 */
                ARRAY ['SRID=4490;POINTZ(116.374115 39.989219 34.615913)', 'SRID=4490;POINTZ(116.376302 39.990080 30.97979)'],
                /* 第 2 组起终点 */
                ARRAY ['SRID=4490;POINTZ(116.375608 39.988837 32.483978)', 'SRID=4490;POINTZ(116.374601 39.989809 26.852046)']
            ]::geometry[],
            '[
                {
                    "schema_name": "public",
                    "table_name": "building_grid24",
                    "column_name": "grids",
                    "is_2d": false,
                    "min_level": 24,
                    "max_level": 24
                },
                {
                    "schema_name": "public",
                    "table_name": "no_fly_zone",
                    "column_name": "smgeometry",
                    "is_2d": true
                }
            ]'::JSONB,
            24
        )
    ).*
)
INSERT INTO result_path (start_point, end_point, path)
SELECT start_point, end_point, path FROM data;
多机协同路径规划效果
  • ST_GridCodeFindMultiDronePath 函数接收多组起终点数组,在网格空间中同时计算所有路径。当多条路径存在重叠网格时,函数会自动调整其中一条或多条路径,避免碰撞。