本文将从四叉树的基本概念出发,系统阐述其在路径规划中的应用,并对比介绍另一种经典的拓扑路径规划方法——可视图法。这两种方法分别代表了基于空间分解基于几何图构造的不同规划思想。

一、可视图路径规划方法

1. 方法内容

可视图法是一种基于几何拓扑的全局路径规划方法。其核心思想是将机器人视为质点,将障碍物顶点、起点和终点作为图的节点,连接所有相互可见的节点形成边,从而构建一个完全连通的“可视图”。在该图中搜索最短路径即得规划结果。

关键特征:

  • 可见性定义:两点之间连线不穿过任何障碍物内部
  • 图结构:节点=障碍物顶点+起点+终点,边=可见线段
  • 最优性:在定义的可见性条件下,可找到精确的最短路径

2. 数学原理

(1) 几何基础
  • 障碍物表示:多边形集合 ( O = {O_1, O_2, …, O_m} )
  • 顶点集合:( V = {v_1, v_2, …, v_n} \cup {S, G} ),其中S为起点,G为终点
  • 可见性判断:对于任意两点 ( p, q ),若线段 ( \overline{pq} ) 与所有障碍物的内部无交点,则p、q相互可见
(2) 可见性判断算法

线段与多边形相交检测可通过射线法分离轴定理实现:

\text{Visible}(p,q) = \bigwedge_{i=1}^{m} (\overline{pq} \cap \text{int}(O_i) = \emptyset)
(3) 最短路径搜索

构建图 ( G = (V, E) ) 后,边权重为欧氏距离:

w(p,q) = \|p - q\|_2

使用Dijkstra算法A*算法求解最短路径。

3. 具体实现

伪代码示例:
function VisibilityGraphPathPlanning(S, G, obstacles):
    // 1. 提取所有障碍物顶点
    vertices = extractAllVertices(obstacles)
    vertices.add(S)
    vertices.add(G)
    
    // 2. 构建可视图
    graph = new Graph()
    for i from 0 to vertices.size()-1:
        for j from i+1 to vertices.size()-1:
            if isVisible(vertices[i], vertices[j], obstacles):
                distance = euclideanDistance(vertices[i], vertices[j])
                graph.addEdge(vertices[i], vertices[j], distance)
    
    // 3. 搜索最短路径
    path = dijkstra(graph, S, G)
    return path

function isVisible(p, q, obstacles):
    for each obstacle in obstacles:
        // 检查线段pq是否与障碍物边界相交
        if segmentIntersectsPolygon(p, q, obstacle):
            return false
        // 特殊处理:允许接触顶点但不得穿过内部
    return true
复杂度分析:
  • 可见性检查:( O(n^2 \cdot m \cdot k) )(n为顶点数,m为障碍物数,k为多边形边数)
  • 适用于障碍物数量少、形状简单的场景

二、四叉树路径规划方法

1. 方法内容

四叉树路径规划属于基于空间分解的方法,通过对环境进行多分辨率递归划分,构建层次化的环境表示。该方法特别适用于:

  • 大规模非均匀环境
  • 需要多分辨率规划的场合
  • 动态环境下的高效更新

2. 数学原理与数据结构

(1) 四叉树定义

四叉树是每个非叶子节点有四个子节点的树结构,对应空间划分的四个象限:

Q = \begin{cases}
\text{Leaf}(state) & \text{若为叶节点} \\
\text{Node}(NW, NE, SW, SE) & \text{否则}
\end{cases}

其中state ∈ {FREE, OCCUPIED, MIXED}

(2) 空间划分规则

给定区域 ( R = [x_{min}, x_{max}] \times [y_{min}, y_{max}] ):

  • 若区域完全自由或完全占据,停止划分
  • 若区域包含障碍物边界,则递归划分为四个子区域:
\begin{aligned}
Q_{NW} &= [x_{min}, \frac{x_{min}+x_{max}}{2}] \times [\frac{y_{min}+y_{max}}{2}, y_{max}] \\
Q_{NE} &= [\frac{x_{min}+x_{max}}{2}, x_{max}] \times [\frac{y_{min}+y_{max}}{2}, y_{max}] \\
&\text{...依此类推}
\end{aligned}
(3) 邻接关系与路径搜索

在四叉树中搜索路径需处理:

  • 同层邻接:相同分辨率下的相邻节点
  • 跨层邻接:不同分辨率节点间的连接(需特殊处理分辨率差异)

3. 具体实现

四叉树构建算法:
class QuadtreeNode:
    def __init__(self, bounds, depth=0):
        self.bounds = bounds  # [xmin, ymin, xmax, ymax]
        self.children = None
        self.state = UNKNOWN  # FREE, OCCUPIED, MIXED
        self.depth = depth

function buildQuadtree(environment, max_depth, min_size):
    root = QuadtreeNode(environment.bounds)
    splitNode(root, environment, max_depth, min_size)
    return root

function splitNode(node, environment, max_depth, min_size):
    if node.depth >= max_depth or area(node.bounds) <= min_size:
        node.state = classifyRegion(node.bounds, environment)
        return
    
    // 划分区域
    subregions = partition(node.bounds)
    node.children = []
    for sub in subregions:
        child = QuadtreeNode(sub, node.depth+1)
        node.children.append(child)
        
        // 递归构建
        if regionContainsObstacle(sub, environment):
            if needsFurtherSplit(sub, min_size):
                splitNode(child, environment, max_depth, min_size)
            else:
                child.state = OCCUPIED
        else:
            child.state = FREE
基于四叉树的路径规划:
function QuadtreePathPlanning(start, goal, quadtree):
    // 1. 构建层次化图结构
    graph = buildHierarchicalGraph(quadtree)
    
    // 2. 添加起点和终点到最近的安全节点
    start_node = findNearestFreeNode(quadtree, start)
    goal_node = findNearestFreeNode(quadtree, goal)
    graph.addNode(start_node)
    graph.addNode(goal_node)
    
    // 3. 多分辨率路径搜索
    path = hierarchicalAStar(graph, start_node, goal_node)
    
    // 4. 路径优化(可选)
    optimized_path = simplifyPath(path)
    return optimized_path

function buildHierarchicalGraph(quadtree):
    graph = Graph()
    traverse(quadtree.root, graph)
    return graph

function traverse(node, graph):
    if node.children is None:
        if node.state == FREE:
            graph.addNode(node)
            // 查找相邻的自由节点
            neighbors = findNeighbors(node)
            for neighbor in neighbors:
                if neighbor.state == FREE:
                    cost = distance(node.center, neighbor.center)
                    graph.addEdge(node, neighbor, cost)
    else:
        for child in node.children:
            traverse(child, graph)

三、两种方法的比较与应用场景

性能对比:

特性 可视图法 四叉树法
路径最优性 精确最短路径 近似最优路径
计算复杂度 (O(n^3))(最坏) (O(n \log n))
内存消耗 中等 较低(自适应)
环境适应性 适合简单多边形环境 适合复杂非均匀环境
动态更新 困难(需重建图) 较容易(局部更新)
实现难度 中等 较高

应用场景选择:

  1. 可视图法适用

    • 结构化室内环境
    • 障碍物数量有限且形状规则
    • 需要精确最短路径的场合
    • 离线规划为主
  2. 四叉树法适用

    • 大规模室外环境
    • 非均匀障碍物分布
    • 需要多分辨率规划的场合
    • 动态环境或实时规划需求

四、改进与融合方法

1. 可视图法的改进

  • 切线图法:减少不必要的边,提高效率
  • 广义Voronoi图:最大化路径与障碍物的距离
  • 分层规划:结合粗略与精细规划

2. 四叉树法的扩展

  • 八叉树:扩展到三维空间
  • 自适应深度控制:基于局部复杂度动态调整分辨率
  • 概率四叉树:处理不确定环境信息

3. 融合方法

将四叉树用于环境表示,在叶节点上构建局部可视图,实现:

  1. 四叉树提供层次化空间划分
  2. 在每个叶节点区域内使用可视图进行精确规划
  3. 层次间路径通过四叉树结构连接

结论

可视图法和四叉树法代表了路径规划中两种不同的哲学:前者追求在精确几何模型上的最优解,后者追求在层次化表示中的高效性。实际应用中,选择何种方法取决于环境特征、计算资源和规划需求。随着机器人应用场景的复杂化,融合多种方法的混合规划策略正成为主流趋势,既能保证规划质量,又能适应大规模动态环境的需求。

Logo

立足具身智能前沿赛道,致力于搭建全球化、开源化、全栈式技术交流与实践共创平台。

更多推荐