路径规划算法:Voronoi Planner讲解

路径规划算法:Voronoi Planner讲解

image

附赠自动驾驶学习资料和量产经验:链接

Voronoi Diagram(也称作Dirichlet tessellation)是由俄国数学家Georgy Voronoy提出的一种空间分割算法。它通过一系列的种子节点(Seed Points)将空间切分为许多子区域,每个子区域被称为一个Cell,每个Cell中的所有点到当前Cell中的种子节点(Seed Points)的距离小于到其它所有种子节点(Seed Points)的距离。

image

图片来源: https://www.youtube.com/watch?v=7eCrHAv6sYY

image

每个Cell中包含的都是距离当前Cell距离最近的所有点,因此Cell的边界就是距离种子点(Seed Points)最远的点的集合。利用Voronoi Diagram的这个特性,将障碍物的边界当做种子点(Seed Points),那么Cell的边界就是远离所有障碍物的可行驶路径。

Voronoi Planner最大化的利用了障碍物之间的空隙,确保生成的路径是最大程度远离所有障碍物的安全行驶路径。

image

图片来源:https://natanaso.github.io/ece276b2018/ref/ECE276B_5_ConfigurationSpace.pdf

1、使用Voronoi Diagram进行路径规划

下图是一所大学校园的地图,图中包含各种多变形的障碍物,我们可以使用使用Voronoi Planner实现在地图中查找一条安全路径,最大程度的避开障碍物。

image

the northern half of Columbia's Morningside Campus.图片来源:https://www.cs.columbia.edu/~pblaer/projects/path_planner/

为了实现Voronoi路径规划,首先用一系列的离散点集序列组成的小线段模拟逼近多边形障碍物的每个边。

image

The points that approximate thepolygonal obstacles. 图片来源:https://www.cs.columbia.edu/~pblaer/projects/path_planner/

然后使用这些近似的离散点作为输入,使用Voronoi构造算法构造Voronoi Diagram。

image

The points that approximate thepolygonal obstacles. 图片来源:https://www.cs.columbia.edu/~pblaer/projects/path_planner/

Voronoi diagram构造完成之后,消除顶点包含在障碍物或者与障碍物相交的Voronoi Edge,剩下的Voronoi Edge就构成了避开所有障碍物的可行驶路径集合。

image

The points that approximate thepolygonal obstacles. 图片来源:https://www.cs.columbia.edu/~pblaer/projects/path_planner/

最后,将Voronoi Edge转化为Grahp结构,将机器人的起点位置和终点位置关联到最近的Voronoi Edge,然后通过图搜索算法(Dijkstra等)就可以生成一条从起点到终点的安全行驶路线。

2、Voronio Planner VS Sample Planner

从下图的对比可以看出,Voronoi Planner规划的路径的特点是尽量的远离障碍物。

image

图片来源:Local and Global Motion Planning for Unmanned Surface Vehicle

image

图片来源:Local and Global Motion Planning for Unmanned Surface Vehicle

3、梯度下降的路径平滑算法

同基于采样的运动规划生成的曲线一样,Voronio Planner生成的曲线都是不平滑的折线,所以需要对路径进行平滑操作,平滑的方法也比较多,今天先介绍其中一种。

3.1 问题定义

如下图所示,s表示运动规划的起点,e表示运动规划终点,斜线填充的网格表示障碍物位置,蓝色的线为运动规划算法(RRT、Voronoi etc.)规划出的路线,曲折不平;红色为平滑后的运动曲线,对车辆的实际行驶比较友好。

image

image

image

3.2 算法实现

上图代码一个5x5的网格地图,红色圆圈代表一条从(0,0)到(4,4)的规划路线,下Python面代码演示了如何由这条路线生成一条平滑路线。

image

from math import *

path = [[0, 0],
        [0, 1],
        [0, 2],
        [1, 2],
        [2, 2],
        [3, 2],
        [4, 2],
        [4, 3],
        [4, 4]]

def smooth(path, weight_data = 0.5, weight_smooth = 0.1, tolerance = 0.000001):
    # Make a deep copy of path into newpath
    newpath = [[0 for col in range(len(path[0]))] for row in range(len(path))]
    for i in range(len(path)):
        for j in range(len(path[0])):
            newpath[i][j] = path[i][j]
            
    change = tolerance
    while change >= tolerance:
        change = 0
        for i in range(1,len(path) - 1):
            for j in range(len(path[0])):
                d1 = weight_data * (path[i][j] - newpath[i][j])
                d2 = weight_smooth * (newpath[i-1][j] + newpath[i+1][j] - 2 * newpath[i][j])
                change += abs(d1 + d2)
                newpath[i][j] += d1 + d2
    return newpath 

newpath = smooth(path)

for i in range(len(path)):
    print('['+ ', '.join('%.3f'%x for x in path[i]) +']> ['+', '.join('%.3f'%x for x in newpath[i]) +']')

平滑后的路径输出结果如下:

[0.000, 0.000]> [0.000, 0.000]
[0.000, 1.000]> [0.021, 0.979]
[0.000, 2.000]> [0.149, 1.851]
[1.000, 2.000]> [1.021, 1.979]
[2.000, 2.000]> [2.000, 2.000]
[3.000, 2.000]> [2.979, 2.021]
[4.000, 2.000]> [3.851, 2.149]
[4.000, 3.000]> [3.979, 3.021]
[4.000, 4.000]> [4.000, 4.000]

平滑算法的实际应用效果如下:

image

图片来源:Local and Global Motion Planning for Unmanned Surface Vehicle

相关代码

1、Boost Voronio Diagram。(https://www.boost.org/doc/libs/1_60_0/libs/polygon/doc/voronoi_diagram.htm)

2、Scipy Spatial Voronoi(https://docs.scipy.org/doc/scipy-0.18.1/reference/generated/scipy.spatial.Voronoi.html)

3、Voronoi Planner的代码实现可以参考:

https://github.com/AtsushiSakai/PythonRobotics/blob/master/PathPlanning/VoronoiRoadMap/voronoi_road_map.py

参考链接

1、Boost Voronio Diagram。(https://www.boost.org/doc/libs/1_60_0/libs/polygon/doc/voronoi_diagram.htm)

2、Robot Path Planning Using Generalized Voronoi Diagrams(https://www.cs.columbia.edu/~pblaer/projects/path_planner/)

3、Local and Global Motion Planning for Unmanned Surface Vehicle,Roman Fedorenko, Boris Gurenko

  • 29
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
首先,我们需要了解什么是A*算法Voronoi图。 A*算法是一种启发式搜索算法,用于寻找最短路径。它利用启发式函数来估计从当前节点到目标节点的最短距离,并通过优先级队列来选择下一个要探索的节点。 Voronoi图是由一组离散点形成的图,其中每个点都是以该点为中心的最近邻点之间的垂直平分线。Voronoi图可用于路径规划,因为它可以将空间分割成区域,使得每个区域内的点都更接近于该区域内的离散点。 现在,我们可以开始编写基于A*算法Voronoi路径规划。 1. 首先,我们需要确定起始点和目标点。这些点可以是随机选择的,也可以是根据特定的规划问题选择的。 2. 接下来,我们需要生成Voronoi图。我们可以使用Python的scipy库来实现这一点。具体来说,我们可以使用scipy.spatial.Voronoi函数来生成Voronoi图。该函数将返回一个包含Voronoi图中的顶点、边和面的对象。 3. 接下来,我们需要计算起始点和目标点在Voronoi图上的位置。这可以通过找到最接近的Voronoi图顶点来实现。 4. 然后,我们可以使用A*算法来查找起始点到目标点的最短路径。我们可以使用Python的heapq模块来实现优先级队列。具体来说,我们可以将所有未探索的节点添加到队列中,并按其到目标点的估计距离排序。然后,我们可以选择距离目标点最近的节点,并从队列中删除它。接下来,我们可以将该节点标记为已探索,并检查其相邻节点。对于每个相邻节点,我们可以计算从起始点到该节点的实际距离,并通过计算从该节点到目标点的估计距离来计算该节点的总成本。如果该节点尚未被探索过或者其总成本比之前找到的路径更短,则将其添加到优先级队列中。 5. 最后,我们可以通过连接所有经过的Voronoi图顶点来生成路径。 下面是一个基于A*算法Voronoi路径规划的Python代码示例: ```python import heapq import numpy as np from scipy.spatial import Voronoi def generate_voronoi(points): vor = Voronoi(points) return vor def get_closest_voronoi_vertex(vor, point): distances = np.linalg.norm(vor.vertices - point, axis=1) closest_vertex_index = np.argmin(distances) return vor.vertices[closest_vertex_index] def a_star_search(start, goal, vor): frontier = [] heapq.heappush(frontier, (0, start)) came_from = {} cost_so_far = {} came_from[start] = None cost_so_far[start] = 0 while frontier: current = heapq.heappop(frontier)[1] if current == goal: break for neighbor in get_neighbors(vor, current): new_cost = cost_so_far[current] + distance(current, neighbor) if neighbor not in cost_so_far or new_cost < cost_so_far[neighbor]: cost_so_far[neighbor] = new_cost priority = new_cost + heuristic(goal, neighbor) heapq.heappush(frontier, (priority, neighbor)) came_from[neighbor] = current path = [goal] current = goal while current != start: current = came_from[current] path.append(current) path.reverse() return path def get_neighbors(vor, point): for simplex in vor.ridge_vertices: if -1 not in simplex and point in simplex: yield vor.vertices[simplex[simplex.index(point) ^ 1]] def distance(p1, p2): return np.linalg.norm(np.array(p1) - np.array(p2)) def heuristic(p1, p2): return distance(p1, p2) if __name__ == '__main__': points = np.random.rand(50, 2) start = (0.1, 0.1) goal = (0.9, 0.9) vor = generate_voronoi(points) start_vor = get_closest_voronoi_vertex(vor, start) goal_vor = get_closest_voronoi_vertex(vor, goal) path = a_star_search(start_vor, goal_vor, vor) print(path) ``` 在此示例中,我们首先生成了50个随机点,并使用这些点来生成Voronoi图。然后,我们选择起始点和目标点,并找到它们在Voronoi图上的最接近的顶点。接下来,我们使用A*算法来查找起始点到目标点的最短路径。最后,我们通过连接路径上的顶点来构建路径。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值