混合A* 中基于 Voronoi 势场的路径代价和 Voronoi 势场的实现测试

参考

Practical Search Techniques in Path Planning for Autonomous Driving 混合 A* 论文

Sensor-Based Exploration: The Hierarchical Generalized Voronoi Graph Voronoi 图论文

认识 Voronoi ,泰森多边形 voronoi 介绍和应用

Voronoi Field 和 Voronoi Diagram

沃罗诺伊图 Voronoi Diagram 又称作狄利克雷镶嵌或者泰森多边形。是一种离散区域分割方法。

  • 离散性:将空间划分为离散的区域,每个区域与一个生成点相关联。

  • 连续性:Voronoi边界是由相邻的生成点之间的距离确定的连续线段。

  • 局部性:每个点的Voronoi区域仅由其最近的邻近点决定,与其他点的位置无关。

fig.1 voronoi diagram 离散图

沃罗诺伊场 Voronoi Field 是一个连续的函数场,用于描述空间中的距离信息。

  • 连续性:Voronoi field 是一个连续的函数场,而不是离散的区域划分。

  • 定义:它基于一组特定点,为每个点定义一个场值,表示该点到最近的邻近点的距离。

  • 插值:Voronoi field 可以通过插值方法(如线性插值或高斯过程)计算出在整个空间中的值。

fig.2 voronoi field 连续的势场

混合 A* 中的 Voronoi 势场代价

用 voronoi 势场中路径点的势场值来描述路径与障碍物接近程度之间。

voronoi 势场定义如下:

\begin{cases} \rho_V(x,y)=(\frac{\alpha}{\alpha+d_{O}(x,y)})(\frac{d_{V}(x,y)}{d_{O}(x,y)+d_V(x,y)}) \frac{(d_O-d_O^{max})^2}{(d_O^{max})^2}, \quad &d_O\le d^{max}_O \\ \rho_V(x,y)=0, &otherwise \end{cases}

d_O(x,y) 是 (x,y) 到最近障碍物的距离,d_V(x,y) 是 (x,y) 到所在 Generalized Voronoi Diagram (GVD) 区域的边的最近距离。

\alpha>0 是控制势场衰减率常数,d_O>0 是控制势场最大有效范围常数,d_O^{max}>0 是地图中距离障碍物最远的距离。

Voronoi 场性质

  1. \rho_V(x,y)=0,\quad d_O\ge d^{max}_O

  2. \rho_V(x,y)\in[0,1] 在 (x,y) 上连续,因为 d_O(x,y) 和 d_V(x,y) 不会同时为 0;

  3. \rho_V(x,y) 只有在障碍物内才会达到最大值;

  4. \rho_V(x,y) 只有在 GVD 边上才为 0;

Voronoi 场优势

Voronoi 场的主要优势在于,场值与可导航空间(自由空间)成比例关系,即使是狭窄的开口,由于比例缩放,依然存在低势场区域(GVD 的边)

fig.3 混合 A* 论文中停车场的 voronoi 势场

图 fig.3 中,(a) 显示 Voronoi 势场,红色是障碍物,灰色部分是表示势场强度,颜色越黑,说明此处势场越强,距离障碍物越近。(b) 显示对应的 Voronoi 图,其中色块的边界就是势场为 0 的空间,在 (b) 中可以看到永远存在一条势场值为 0 的通道!(c) 表示在标准势场中,即使是狭窄通道仍具有高势能区域。

!!!注意!!!

图 3(c) 在原文中称为 standard potential field 标准势场,什么是标准势场?没有找到好的解释。在标准势场中,狭窄通道中仍有高势能区域。这说明在“标准势场”中,自由区间是高势能区域,障碍物是低势能区域。而在 costmap 中,自由空间是低数值区域,障碍物是高数值区域。

图 3(c) 中高势能区域是浅色,低势能区域是深色,这与 rgd 图一致,说明原文的标准势场图是用 rgb 图画的。

Voronoi 势场反映地图障碍物的相对距离,即使在狭窄区域也不会完全封闭。也就是说 Voronoi 势场图中,在非完全封闭区域,始终存在一条高势能通道。Voronoi 势场图可以用来找地图中离障碍物最远的通道。

Voronoi 图可以导出自由空间骨架,但对于运动学非完整性车辆或机器而言,这样的路径是不可直接使用。

Voronoi 势场的 costmap2d 插件实现,测试

Voronoi 势场用 costmap 显示,cost 值 254u 和 255u 作为障碍物显示。灰图是 costmap 的 map 显示。
绿色网络是 gridcells 数据格式,显示 gvd 网络。

fig.4 voronoi 势场的 costmap 显示
fig.5 voronoi 势场的 map 显示

更多的测试发现,对于不规则的地图 gvd 网络混乱,对于“凹”区域总会有 gdv 网络连接,其实观察原论文的图片也有这种问题

fig.6 混乱地图的 voronoi 势场的 costmap 显示
fig.7 凹地图的 voronoi 势场的 costmap 显示

凹地图的 gvd 分支剪枝效果不佳,需要自己另外实现效果。

我的做法是从提取的 gvd 图中计算交点和端点,从端点处开始沿着分支消除,遇到交点停止。

fig.8 凹地图中多余的 gvd 分支
fig.9 消除 gvd 凹处的分支

图 fig.9 中橙色 girdcells 数据就是消除多余分支后的 gvd,同时可以观察到障碍物凹处的势场值变连续了。虽然实现了效果,但是这种粗暴简单的做法计算量比较大,实际应用还需要改进数据结构算法。

对于不规则,混乱的障碍物地图,可以通过“膨胀-腐蚀”操作平滑障碍物边缘,过滤噪点。这里就不测试了。

  • 24
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 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、付费专栏及课程。

余额充值