自动驾驶路径规划——A*(Astar)算法

自动驾驶路径规划——A*(Astar)算法1968 年发明的 A 算法就是把启发式方法 heuristicapp 如 BFS 和常规方法如 Dijsktra 算法结合在一起的算法

大家好,欢迎来到IT知识分享网。

1. 最佳优先搜索(Best-First Search)

    最佳优先搜索(BFS),又称A算法,是一种启发式搜索算法(Heuristic Algorithm)。[不是广度优先搜索算法( Breadth First Search , BFS )]
    BFS算法在广度优先搜索的基础上,用启发估价函数对将要被遍历到的点进行估价,然后选择代价小的进行遍历,直到找到目标节点或者遍历完所有点,算法结束。

    要实现最佳优先搜索我们必须使用一个优先队列(priority queue)来实现,通常采用一个open优先队列和一个closed集open优先队列用来储存还没有遍历将要遍历的节点,而closed集用来储存已经被遍历过的节点。

1.1 最佳优先搜索的过程

最佳优先搜索的过程可以被描述为:

  1. 将根节点放入优先队列open中。
  2. 从优先队列中取出优先级最高的节点X。
  3. 根据节点X生成子节点Y:
    3.1 X的子节点Y不在open队列或者closed中,由估价函数计算出估价值,放入open队列中。
    3.2 X的子节点Y在open队列中,且估价值优于open队列中的子节点Y,将open队列中的子节点Y的估价值替换成新的估价值并按优先值排序。
    3.3 X的子节点Y在closed集中,且估价值优于closed集中的子节点Y,将closed集中的子节点Y移除,并将子节点Y加入open优先队列。


  4. 将节点X放入closed集中。
  5. 重复过程2,3,4直到目标节点找到,或者open为空,程序结束。

在这里插入图片描述

    BFS不能保证找到一条最短路径。然而,它比Dijkstra算法快的多,因为它用了一个启发式函数(heuristic function)快速地导向目标结点。
    这篇博客对BFS进行了详细的介绍用的是罗马尼亚度假问题在这里插入图片描述

    这篇则是用C++实现了BFS

2. A-Star算法

  • 和Dijkstra一样,A*能用于搜索最短路径。
  • 和BFS一样,A*能用启发式函数引导它自己。

左图为Astar算法效果图,右图为Dijkstra算法效果图自动驾驶路径规划——A*(Astar)算法
    Astar算法与Dijkstra算法的效果差不多,但Astar算法访问的节点数明显比Dijkstra算法少得多,说明其速度更快,运行时间更短。

2.1 Astar算法所属分类

A*算法在最短路径搜索算法中分类为:

  • 直接搜索算法:直接在实际地图上进行搜索,不经过任何预处理;
  • 启发式算法:通过启发函数引导算法的搜索方向;
  • 静态图搜索算法:被搜索的图的权值不随时间变化(后被证明同样可以适用于动态图的搜索 )

2.2 Astar算法基本概念

A*算法启发函数表示为: f(n)=g(n)+h(n)

  • f(n) 是从初始状态经由状态n到目标状态的代价估计
  • g(n) 是在状态空间中从初始状态到状态n的实际代价
  • h(n) 是从状态n到目标状态的最佳路径的估计代价

2.3 启发函数单调性的推导

     单调性:单调性是Astar算法非常重要的一个性质,它决定了在用Astar算法进行路径搜索时,一定能找到一条最优路径。
     设父节点的坐标为(x0,y0),它的任意一个子节点的坐标为(xi,yi),所以对两者之间的h(x),就一定满足
h ( x 0 ) ≤ h ( x i ) + C o s t 0 , i h({x_{\rm{0}}}) \le h({x_i}) + {\mathop{\rm Cos}\nolimits} {t_{0,i}} h(x0)h(xi)+Cost0,iCost0,i——从父节点到下一个子节点的代价值,恒大于等于0,即要满足代价函数是单调递增的;
父节点到子节点的估价值为h(x0)-h(xi),它总是小于或等于其代价值.


     根据启发函数公式可知,对父节点和子节点的f(x),总有 f ( x 0 ) = g ( x 0 ) + h ( x 0 ) f({x_{\rm{0}}}) = g({x_{\rm{0}}}) + h({x_{\rm{0}}}) f(x0)=g(x0)+h(x0) f ( x i ) = g ( x i ) + h ( x i ) f({x_i}) = g({x_i}) + h({x_i}) f(xi)=g(xi)+h(xi)      在Astar算法的搜索过程当中,实际代价g(x)是在不断增加的,可以由下式推出: g ( x i ) = g ( x 0 ) + C o s t 0 , i g({x_i}) = g({x_0}) + {\mathop{\rm Cos}\nolimits} {t_{0,i}} g(xi)=g(x0)+Cost0,i     子节点的代价值等于父节点的代价值加上从父节点到下一个子节点的代价值。代入第二条公式,得到下式: f ( x i ) = g ( x 0 ) + h ( x i ) + C o s t 0 , i f({x_i}) = g({x_0}) + h({x_i}) + {\mathop{\rm Cos}\nolimits} {t_{0,i}} f(xi)=g(x0)+h(xi)+Cost0,i     从而有 g ( x 0 ) + h ( x 0 ) ≤ g ( x 0 ) + h ( x i ) + C o s t 0 , i g({x_{\rm{0}}}) + h({x_{\rm{0}}}) \le g({x_{\rm{0}}}) + h({x_i}) + {\mathop{\rm Cos}\nolimits} {t_{0,i}} g(x0)+h(x0)g(x0)+h(xi)+Cost0,i     即 f ( x 0 ) ≤ f ( x i ) f({x_{\rm{0}}}) \le f({x_i}) f(x0)f(xi)    在Astar算法的运行过程中,后继的f(x)值时大于当前f(x)的值,即f(x)在之后对子节点的搜索扩展是单调递增的,不会像人工势场法一样出现局部极小值,因此使用Astar算法规划出的路径一定是最优路径.

2.4 设计代价函数时所需注意的点

  • 在使用A*算法的过程中,启发代价的值必须尽量接近于真实值(尽量选取能取到的最大值,这样可以提升搜索效率),以保证规划出的路径尽可能地与实际地图环境相符合。
  • 根据所需的模型选择不同的启发代价的计算方法时,同样必须保证启发代价所得的估计值小于真实值。

2.5 代价函数的选择

2.5.1 曼哈顿距离

    曼哈顿距离函数在标准坐标系中,表示起始和目标两节点的绝对值总和,其估计值就是从当前点做水平和垂直运动,到达目标点的成本的估计,因此,曼哈顿距离函数中,两点的距离如下 h ( x ) = K ∗ ( ∣ x 1 − x 2 ∣ + ∣ y 1 − y 2 ∣ ) h(x) = K*(\left| {
{x_1} – {x_2}} \right| + \left| {
{y_1} – {y_2}} \right|)
h(x)=K(x1x2+y1y2)
K——相邻两节点之间的距离,即单位距离;
(x1,y1)——起始节点的坐标;
(x2,y2)——目标节点的坐标;
在这里插入图片描述


2.5.2 欧几里得距离

    欧几里得距离又称为欧式距离,它是衡量两点之间距离远近的最常用的方法之一。欧几里得距离函数的值可以直接看作起始节点和目标节点,在欧式空间中的直线距离,其表达式如下所示 h ( n ) = K × ( x i − x k ) 2 + ( y i − y k ) 2 h(n) = K \times \sqrt {
{
{({x_i} – {x_k})}^2} + {
{({y_i} – {y_k})}^2}}
h(n)=K×(xixk)2+(yiyk)2
K——相邻两节点之间的距离,即单位距离;
(xi,yi)——当前节点的坐标;
(xk,yk)——目标节点的坐标;
在这里插入图片描述
    欧几里德距离函数作为启发代价的计算方法时,虽然寻径时搜索空间增加从而导致搜索效率的降低,但其所得的估计值最小;
    而在使用曼哈顿距离函数时,虽然寻径需要遍历的栅格空间少于欧几里得距离函数,搜索效率较高,但这种方法得到的估计值与欧几里得距离函数相比,距离真实值更远。




2.6 确定最终路径

2.7 路径平滑

2.8 Astar算法的优缺点

参考一篇博文的总结:

  • 如果 h(n) <= n到终点的实际距离,A*算法可以找到最短路径,但是搜索的点数多,搜索范围大,效率低。
  • 如果 h(n) > n到终点的实际距离,搜索的点数少,搜索范围小,效率高,但是得到的路径并不一定是最短的。
  • h(n) 越接近n到终点的实际距离,那么A*算法越完美。(个人理解是如果用曼哈顿距离,那么只需要找到一条长度小于等于该距离的路径就算完成任务了。而使用对角线距离就要找到一条长度大于等于对角线距离且最短的路径才行。)
  • 若 h(n)=0,即 f(n)=g(n),A*算法就变为了Dijkstra算法(Dijstra算法会毫无方向的向四周搜索)。
  • 若 h(n) 远远大于 g(n) ,那么 f(n) 的值就主要取决于 h(n),A*算法就演变成了BFS算法

    距离估计与实际值越接近,估价函数取得就越好。估价函数f(n)在g(n)一定的情况下,会或多或少的受距离估计值h(n)的制约,节点距目标点近,h值小,f值相对就小,能保证最短路的搜索向终点的方向进行,明显优于Dijkstra算法的毫无方向的向四周搜索。

2.9 Astar算法流程

在这里插入图片描述
具体流程可以参考这篇
以及古月居的这篇

  1. 用方格(三角形、五角形)划分空间,简化搜索区域。空间被划分为二维数组,数组中每个元素代表空间中的一个方格,可被标记为可行或不可行。未来的路径就是一系列可行方块的集合。Nodes的概念涵盖了一系列可行方块(或其它方块)
  2. 将起点A放到Openlist中,Openlist存放着一系列需要检查的节点(方块)
  3. 给Openlist中每个节点赋值F=G+H (起点为0,横向和纵向的移动代价为 10 ,对角线的移动代价为 14)
  4. 检查Openlist,选取F值最小的节点(此处为A点)。
  5. 将A点从Openlist中删除,放入Closelist中(Closelist中存放不可寻点,即已被访问过的点),把A点临近节点放入Openlist中,并将A点设为临近节点的父节点。
    在这里插入图片描述
  6. 给Openlist中每个节点赋值,选取F值最小的节点设为当前节点Node,(若当前节点Node为终点,则寻路结束,若Openlist中没有可寻节点,则寻路失败)
    List item
  7. 检查当前节点Node周围临近节点。忽略Closelist中的节点和不可行节点(障碍),如果临近节点在Openlist中,则对比一下是否从当前节点到临近节点的G值比原G值(直接到临近节点的实际代价值)小,若是,把当前节点作为父节点。否,不做改动。如果临近节点不在Openlist中,将其加入到Openlist中,将当前节点设为它的父节点。
  8. 若上步骤中新节点未造成任何改动,将新节点作为当前节点,重复6,7)中的步骤,直到找到目标节点。在这里插入图片描述寻找到目标节点
    在这里插入图片描述
  9. 从目标节点回溯可以找到初始点,从而确定路径在这里插入图片描述
        上述描述路径的图片有些错误,具体步骤如下图所示。在这里插入图片描述

A*算法寻路过程步骤总结

  1. 将起点A添加到open列表中
  2. 检查open列表,选取花费F最小的节点M(检查M如果为终点是则结束寻路,如果open列表没有则寻路失败,直接结束)。
  3. 对于与M相邻的每一节点N
    如果N是阻挡障碍,那么不管它。
    如果N在closed列表中,那么不管它
    如果N不在open列表中:添加它然后计算出它的花费F(n)=G+H。
    如果N已在open列表中:当我们使用当前生成的路径时,检查F花费是否更小。如果是,更新它的花费F和它的父节点。



  4. 重复2,3步。
  5. 停止,当你把终点加入到了 openlist 中,此时路径已经找到了或者 查找终点失败,并且 openlist 是空的,此时没有路径。
  6. 保存路径。从终点开始,每个方格沿着父节点移动直至起点,这就是你的路径。

3. 其他Astar算法

3.1 Astar——三维地图规划

3.1.1 3D-Astar原理

3.1.2 基于MATLAB实现3D-Astar

3.2 距离与能量复合Astar算法

    经典Astar算法路径规划是取两节点间曼哈顿距离作为距离估计为最优原则搜索路径,从而得到最短路径。搜索路径的过程中并没有考虑实际道路坡度道路滚动阻力系数对行驶车辆最短路径搜索的影响,也没有考虑在道路上行驶的能量损耗问题,即经典Astar算法搜索的最短路径并非符合实际车辆行驶的最优路径。

3.2.1 最短路径启发函数

最短路径启发函数: L f ( n ) = L g ( n ) + L h ( n ) {L_{\rm{f}}}\left( n \right) = {L_{\rm{g}}}\left( n \right) + {L_{\rm{h}}}\left( n \right) Lf(n)=Lg(n)+Lh(n)n——当前节点栅格;
Lg(n)——起点栅格与当前节点栅格之间的间隔距离代价(m);
Lh(n)——当前节点栅格与目标点栅格之间的间隔距离代价(m)。
L h ( n ) = ∥ n , t a r g e t ∥ {L_{\rm{h}}}\left( n \right) = \left\| {n,target} \right\| Lh(n)=n,target当前节点与目标点之间的欧几里得距离(m). L g ( n ) = L g ( n − 1 ) + c o s t ( n − 1 , n ) L {L_{\rm{g}}}\left( n \right) = {L_{\rm{g}}}\left( {n – 1} \right) + cost{\left( {n – 1,n} \right)_{\rm{L}}} Lg(n)=Lg(n1)+cost(n1,n)L上一节点栅格到当前节点栅格之间的间隔距离代价(m)


    对以下两种情况做分析,求解出 c o s t ( n − 1 , n ) L cost{\left( {n – 1,n} \right)_{\rm{L}}} cost(n1,n)L

在这里插入图片描述
最终得到的最短路径启发函数如下式:
L f ( n ) = L g ( n − 1 ) + 1 2 ∥ n − 1 , n ∥ ( 1 cos ⁡ ( a r c t a n ( i n − 1 ) ) + 1 cos ⁡ ( a r c t a n ( i n ) ) ) + ∥ n , t a r g e t ∥ {L_{\rm{f}}}\left( n \right) = {L_{\rm{g}}}\left( {n – 1} \right) + \frac{1}{2}\left\| {n – 1,n} \right\|\left( {\frac{1}{
{\cos \left( {
{\rm{arctan}}({i_{n – 1}})} \right)}} + \frac{1}{
{\cos \left( {
{\rm{arctan(}}{i_n})} \right)}}} \right) + \left\| {n,target} \right\|
Lf(n)=Lg(n1)+21n1,n(cos(arctan(in1))1+cos(arctan(in))1)+n,target


3.2.2 最短道路损耗功启发函数

道路损耗功启发函数:
W f ( n ) = W g ( n ) + W h ( n ) {W_{\rm{f}}}\left( n \right) = {W_{\rm{g}}}\left( n \right) + {W_{\rm{h}}}\left( n \right) Wf(n)=Wg(n)+Wh(n)n——当前节点栅格;
Wg(n)——起点栅格与当前节点栅格的道路损耗功价值(J);
Wh(n)——当前节点栅格与目标点栅格的道路损耗功价值(J)。
W h ( n ) = G δ ∥ n , t a r g e t ∥ {W_{\rm{h}}}\left( n \right) = G\delta \left\| {n,target} \right\| Wh(n)=Gδn,target当前节点与目标点之间的欧几里得距离(m).
W g ( n ) = W g ( n − 1 ) + c o s t ( n − 1 , n ) W {W_{\rm{g}}}\left( n \right) = {W_{\rm{g}}}\left( {n – 1} \right) + cost{\left( {n – 1,n} \right)_{\rm{W}}} Wg(n)=Wg(n1)+cost(n1,n)W上一节点栅格到当前节点栅格之间的的道路损耗功代价(J)




    对以下几种情况做分析,求解出 c o s t ( n − 1 , n ) W {cost{
{\left( {n – 1,n} \right)}_{\rm{W}}}}
cost(n1,n)W

在这里插入图片描述
最终得到的最短道路损耗功启发函数如下式:
W f ( n ) = W g ( n − 1 ) + { G cos ⁡ ( a r c t a n ( i n − 1 ) ) δ n − 1 + G sin ⁡ ( a r c t a n ( i n − 1 ) ) } ∥ n − 1 , n ∥ 2 cos ⁡ ( a r c t a n ( i n − 1 ) ) + { G cos ⁡ ( a r c t a n ( i n ) ) δ n + G sin ⁡ ( a r c t a n ( i n ) ) } ∥ n − 1 , n ∥ 2 cos ⁡ ( a r c t a n ( i n ) ) + G δ ∥ n , t a r g e t ∥ \begin{array}{ccccccccccccccc}{
{W_{\rm{f}}}\left( n \right) = {W_{\rm{g}}}\left( {n – 1} \right) + \left\{ {G\cos \left( {
{\rm{arctan}}({i_{n – 1}})} \right){\delta _{n – 1}} + G\sin \left( {
{\rm{arctan}}({i_{n – 1}})} \right)} \right\}\frac{
{\left\| {n – 1,n} \right\|}}{
{2\cos \left( {
{\rm{arctan}}({i_{n – 1}})} \right)}}}\\{\begin{array}{ccccccccccccccc}{}&{}\end{array} + \left\{ {G\cos \left( {
{\rm{arctan}}({i_n})} \right){\delta _n} + G\sin \left( {
{\rm{arctan}}({i_n})} \right)} \right\}\frac{
{\left\| {n – 1,n} \right\|}}{
{2\cos \left( {
{\rm{arctan}}({i_n})} \right)}} + G\delta \left\| {n,target} \right\|}\end{array}
Wf(n)=Wg(n1)+{
Gcos(arctan(in1))δn1+Gsin(arctan(in1))}
2cos(arctan(in1))n1,n
+{
Gcos(arctan(in))δn+Gsin(arctan(in))}
2cos(arctan(in))n1,n+Gδn,target



3.2.3 综合启发函数

    综合式启发函数统一最短路径启发函数和最小道路额外功函数,不同的权重大小决定最短路径启发函数和最小道路额外功函数在综合式启发函数中所占不同的比重。

3.3 双向Astar算法

    传统A算法在大环境中搜索,存在着搜索效率低的问题。
    传统A
算法是从起点开始向终点搜索,直到寻到可行路径停止搜索,在搜索路径的前期阶段远g(n)小于h(n),搜索时横向搜索范围窄,纵向搜索范围宽,搜索速度快,在搜索的后期阶段g(n)远大于h(n),搜索时纵向搜索范围窄,横向搜索范围宽,搜索速度慢;而改进后的双向A搜索算法分别从起点和终点开始搜索,当搜索到相同的当前节点时,搜索结束。相比于传统A算法,双向A*搜索算法都处于g(n)远小于h(n)阶段,一定程度上提高了算法的搜索效率,缩短搜索时间。在这里插入图片描述

4. MATLAB实现Astar算法

4.1 defColorMap.m

用于初始化地图参数

function [field,cmap] = defColorMap(rows, cols) cmap = [1 1 1; ... % 1-白色-空地 0 0 0; ... % 2-黑色-静态障碍 1 0 0; ... % 3-红色-动态障碍 1 1 0;... % 4-黄色-起始点 1 0 1;... % 5-品红-目标点 0 1 0; ... % 6-绿色-到目标点的规划路径 0 1 1]; % 7-青色-动态规划的路径 % 构建颜色MAPcolormap(cmap); % 定义栅格地图全域,并初始化空白区域 field = ones(rows, cols); % 障碍物区域 obsRate = 0.3; obsNum = floor(rows*cols*obsRate); obsIndex = randi([1,rows*cols],obsNum,1); field(obsIndex) = 2; 

4.2 getChildNode.m

用于获取子节点信息

function childNodes = getChildNode(field,closeList, parentNode) % 选取父节点周边8个节点作为备选子节点,线性化坐标 % 排除超过边界之外的、位于障碍区的、位于closeList中的 [rows, cols] = size(field); [row_parentNode, col_parentNode] = ind2sub([rows, cols], parentNode); childNodes = []; closeList = closeList(:,1); % 第1个子节点(右节点) childNode = [row_parentNode, col_parentNode+1]; if ~(childNode(1) < 1 || childNode(1) > rows ||... childNode(2) < 1 || childNode(2) > cols) if field(childNode(1), childNode(2)) ~= 2 childNode_LineIdx = sub2ind([rows, cols], childNode(1), childNode(2)); if ~ismember(childNode_LineIdx, closeList) childNodes(end+1) = childNode_LineIdx; end end end %2个子节点(右上节点) childNode = [row_parentNode-1, col_parentNode+1]; child_brother_node_sub1 = [row_parentNode-1, col_parentNode]; child_brother_node_sub2 = [row_parentNode, col_parentNode+1]; if ~(childNode(1) < 1 || childNode(1) > rows ||... childNode(2) < 1 || childNode(2) > cols) if field(childNode(1), childNode(2)) ~= 2 if ~(field(child_brother_node_sub1(1), child_brother_node_sub1(2)) == 2 & field(child_brother_node_sub2(1), child_brother_node_sub2(2)) == 2) childNode_LineIdx = sub2ind([rows, cols], childNode(1), childNode(2)); if ~ismember(childNode_LineIdx, closeList) childNodes(end+1) = childNode_LineIdx; end end end end %3个子节点(上节点) childNode = [row_parentNode-1, col_parentNode]; if ~(childNode(1) < 1 || childNode(1) > rows ||... childNode(2) < 1 || childNode(2) > cols) if field(childNode(1), childNode(2)) ~= 2 childNode_LineIdx = sub2ind([rows, cols], childNode(1), childNode(2)); if ~ismember(childNode_LineIdx, closeList) childNodes(end+1) = childNode_LineIdx; end end end %4个子节点(左上) childNode = [row_parentNode-1, col_parentNode-1]; child_brother_node_sub1 = [row_parentNode-1, col_parentNode]; child_brother_node_sub2 = [row_parentNode, col_parentNode-1]; if ~(childNode(1) < 1 || childNode(1) > rows ||... childNode(2) < 1 || childNode(2) > cols) if field(childNode(1), childNode(2)) ~= 2 if ~(field(child_brother_node_sub1(1), child_brother_node_sub1(2)) == 2 & field(child_brother_node_sub2(1), child_brother_node_sub2(2)) == 2) childNode_LineIdx = sub2ind([rows, cols], childNode(1), childNode(2)); if ~ismember(childNode_LineIdx, closeList) childNodes(end+1) = childNode_LineIdx; end end end end % 第5个子节点(左节点) childNode = [row_parentNode, col_parentNode-1]; if ~(childNode(1) < 1 || childNode(1) > rows ||... childNode(2) < 1 || childNode(2) > cols) if field(childNode(1), childNode(2)) ~= 2 childNode_LineIdx = sub2ind([rows, cols], childNode(1), childNode(2)); if ~ismember(childNode_LineIdx, closeList) childNodes(end+1) = childNode_LineIdx; end end end %6个子节点(左下) childNode = [row_parentNode+1, col_parentNode-1]; child_brother_node_sub1 = [row_parentNode, col_parentNode-1]; child_brother_node_sub2 = [row_parentNode+1, col_parentNode]; if ~(childNode(1) < 1 || childNode(1) > rows ||... childNode(2) < 1 || childNode(2) > cols) if field(childNode(1), childNode(2)) ~= 2 if ~(field(child_brother_node_sub1(1), child_brother_node_sub1(2)) == 2 & field(child_brother_node_sub2(1), child_brother_node_sub2(2)) == 2) childNode_LineIdx = sub2ind([rows, cols], childNode(1), childNode(2)); if ~ismember(childNode_LineIdx, closeList) childNodes(end+1) = childNode_LineIdx; end end end end %7个子节点(下) childNode = [row_parentNode+1, col_parentNode]; if ~(childNode(1) < 1 || childNode(1) > rows ||... childNode(2) < 1 || childNode(2) > cols) if field(childNode(1), childNode(2)) ~= 2 childNode_LineIdx = sub2ind([rows, cols], childNode(1), childNode(2)); if ~ismember(childNode_LineIdx, closeList) childNodes(end+1) = childNode_LineIdx; end end end %8个子节点(右下) childNode = [row_parentNode+1, col_parentNode+1]; child_brother_node_sub1 = [row_parentNode, col_parentNode+1]; child_brother_node_sub2 = [row_parentNode+1, col_parentNode]; if ~(childNode(1) < 1 || childNode(1) > rows ||... childNode(2) < 1 || childNode(2) > cols) if field(childNode(1), childNode(2)) ~= 2 if ~(field(child_brother_node_sub1(1), child_brother_node_sub1(2)) == 2 & field(child_brother_node_sub2(1), child_brother_node_sub2(2)) == 2) childNode_LineIdx = sub2ind([rows, cols], childNode(1), childNode(2)); if ~ismember(childNode_LineIdx, closeList) childNodes(end+1) = childNode_LineIdx; end end end end 

4.3 Astar.m

主程序

% 基于栅格地图的机器人路径规划算法 % A*算法 clc clear close all %% 栅格界面、场景定义 % 行数和列数 rows = 20; cols = 20; [field,cmap] = defColorMap(rows, cols); % 起点、终点、障碍物区域 startPos = 2; goalPos = rows*cols-2; field(startPos) = 4; field(goalPos) = 5; %% 预处理 % 初始化closeList parentNode = startPos; closeList = [startPos,0]; % 初始化openList openList = struct; childNodes = getChildNode(field,closeList,parentNode); for i = 1:length(childNodes) [row_startPos,col_startPos] = ind2sub([rows, cols],startPos); [row_goalPos,col_goalPos] = ind2sub([rows, cols],goalPos); [row,col] = ind2sub([rows, cols],childNodes(i)); % 存入openList结构体 openList(i).node = childNodes(i); openList(i).g = norm([row_startPos,col_startPos] - [row,col]); % 实际代价采用欧式距离 openList(i).h = abs(row_goalPos - row) + abs(col_goalPos - col); % 估计代价采用曼哈顿距离 openList(i).f = openList(i).g + openList(i).h; end % 初始化path for i = 1:rows*cols path{ 
   i,1} = i; % 线性索引值 end for i = 1:length(openList) node = openList(i).node; path{ 
   node,2} = [startPos,node]; end %% 开始搜索 % 从openList开始搜索移动代价最小的节点 [~, idx_min] = min([openList.f]); parentNode = openList(idx_min).node; % 进入循环 while true % 找出父节点的8个子节点,障碍物节点用inf, childNodes = getChildNode(field, closeList,parentNode); % 判断这些子节点是否在openList中,若在,则比较更新;没在则追加到openList中 for i = 1:length(childNodes) % 需要判断的子节点 childNode = childNodes(i); [in_flag,idx] = ismember(childNode, [openList.node]); % 计算代价函数 [row_parentNode,col_parentNode] = ind2sub([rows, cols], parentNode); [row_childNode,col_childNode] = ind2sub([rows, cols], childNode); [row_goalPos,col_goalPos] = ind2sub([rows, cols],goalPos); g = openList(idx_min).g + norm( [row_parentNode,col_parentNode] -... [row_childNode,col_childNode]); h = abs(row_goalPos - row_childNode) + abs(col_goalPos - col_childNode); % 采用曼哈顿距离进行代价估计 f = g + h; if in_flag % 若在,比较更新g和f if f < openList(idx).f openList(idx).g = g; openList(idx).h = h; openList(idx).f = f; path{ 
   childNode,2} = [path{ 
   parentNode,2}, childNode]; end else % 若不在,追加到openList openList(end+1).node = childNode; openList(end).g = g; openList(end).h = h; openList(end).f = f; path{ 
   childNode,2} = [path{ 
   parentNode,2}, childNode]; end end % 从openList移出移动代价最小的节点到closeList closeList(end+1,: ) = [openList(idx_min).node, openList(idx_min).f]; openList(idx_min)= []; % 重新搜索:从openList搜索移动代价最小的节点 [~, idx_min] = min([openList.f]); parentNode = openList(idx_min).node; % 判断是否搜索到终点 if parentNode == goalPos closeList(end+1,: ) = [openList(idx_min).node, openList(idx_min).f]; break end end %% 画路径 % 找出目标最优路径 path_target = path{ 
   goalPos,2}; for i = 1:rows*cols if ~isempty(path{ 
   i,2}) field((path{ 
   i,1})) = 7; end end field(startPos) = 4; field(goalPos) = 5; field(path_target(2:end-1)) = 6; % 画栅格图 image(1.5,1.5,field); grid on; set(gca,'gridline','-','gridcolor','k','linewidth',2,'GridAlpha',0.5); set(gca,'xtick',1:cols+1,'ytick',1:rows+1); axis image; hold on; [y0,x0] = ind2sub([rows,cols], path_target); y = y0 + 0.5; x = x0 + 0.5; plot(x,y,'-','Color','r','LineWidth',2.5); hold on; points = [x',y']; M = 10; [x1,y1] = bezir_n(points, M); plot(x1,y1,'-','Color','y','LineWidth',2.5); hold on; values = spcrv([[x(1) x x(end)];[y(1) y y(end)]],3); plot(values(1,:),values(2,:), 'b','LineWidth',2.5); 

可以先参考古月居的这篇文章

4.4 算法效果

在这里插入图片描述
运行总时间
在这里插入图片描述
栅格地图大小(20×20)
在这里插入图片描述栅格地图大小(30×30)
在这里插入图片描述
栅格地图大小(40×40)
    可以看到Astar算法对于栅格地图越大的情况,搜索时间越长,其速度相比Dijkstra有优势(尤其是在地图比较大的时候,优势更明显)。但其总耗时较长,不适用于实时的路径规划,不适用于局部路径规划,适用于全局路径规划。






5. python实现Astar算法

python 版本的伪代码(来源:https://brilliant.org/wiki/a-star-search/)如下:

make an openlist containing only the starting node make an empty closed list while (the destination node has not been reached): consider the node with the lowest f score in the open list if (this node is our destination node) : we are finished if not: put the current node in the closed list and look at all of its neighbors for (each neighbor of the current node): if (neighbor has lower g value than current and is in the closed list) : replace the neighbor with the new, lower, g value current node is now the neighbor's parent else if (current g value is lower and this neighbor is in the open list ) : replace the neighbor with the new, lower, g value change the neighbor's parent to our current node else if this neighbor is not in both lists: add it to the open list and set its g 

6. Java实现Astar算法

可以参考这篇文章

7. 实践案例——基于ROS实现Astar与DWA算法

    本项目以Astar算法作为全局路径规划算法,DWA作为局部路径规划算法,实现效果如下。(具体原理与算法代码解释与说明会在之后的文章附上)

ROS_导航_Astar+DWA

声明

本人所有文章仅作为自己的学习记录,若有侵权,联系立删。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/130390.html

(0)
上一篇 2025-08-15 18:45
下一篇 2025-08-15 19:00

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信