概述
本文详细介绍了D*算法原理,它是一种动态搜索路径的算法。D*算法主要解决位置地形条件下路径重新规划(replan)问题,当移动机器人碰到障碍时候通过局部修正快速得到最优的路径规划。相比于重新利用Dijkstra或者A*做为Replanner,D*对运行时间的优化随着随着搜索搜索空间增长有着显著的优化。
重要定义
-
G G G定义为目标节点
-
b ( X ) = Y b(X)=Y b(X)=Y:表示 Y Y Y为 X X X的 b a c k p o i n t e r backpointer backpointer,即 X X X为 Y Y Y的父节点,因此 G G G不存在父亲节点
-
t a g ( X ) tag(X) tag(X)表示节点 X X X的状态,目前区分 N e w , O p e n , C l o s e d New, Open, Closed New,Open,Closed
- t a g ( X ) = N e w tag(X)=New tag(X)=New:节点 X X X不在 o p e n l i s t openlist openlist中
- t a g ( X ) = O p e n tag(X)=Open tag(X)=Open:节点 X X X在当前 o p e n l i s t openlist openlist中
- t a g ( X ) = C l o s e d tag(X)=Closed tag(X)=Closed:节点 X X X不再在 o p e n l i s t openlist openlist中
-
H ( X ) H(X) H(X)表示节点 X X X到目标节点 G G G的启发式函数
-
c ( X , Y ) c(X, Y) c(X,Y)表示从 Y Y Y到 X X X边的权重,同时定义 X X X和 Y Y Y是邻居节点
-
k ( X ) k(X) k(X)定义为 X X X在 o p e n l i s t openlist openlist中最小的 h ( X ) h(X) h(X)数值
-
如果 k ( X ) < h ( X ) k(X) < h(X) k(X)<h(X),定义为 X X X为 R a i s e Raise Raise,D*使用 o p e n l i s t openlist openlist中 R a i s e Raise Raise状态传播路径损失增加的信息
-
如果 k ( X ) = h ( X ) k(X) = h(X) k(X)=h(X),定义为 X X X为 L o w e r Lower Lower,D*使用 o p e n l i s t openlist openlist中 L o w e r Lower Lower状态传播路径损失减少的信息
-
-
k m i n k_{min} kmin为 o p e n l i s t openlist openlist中所有节点 k ( X ) k(X) k(X)的最小值,即 min ( k ( X ) ) \min(k(X)) min(k(X)),最优路径损失小于等于 k m i n k_{min} kmin
-
k o l d k_{old} kold定义为上一轮 k m i n k_{min} kmin的数值
算法框架
- 将目标节点加入到 o p e n l i s t openlist openlist, h ( G ) = 0 h(G)=0 h(G)=0
- 循环执行
progress_state
函数直到满足下面三个条件之一- k m i n = − 1 k_{min}=-1 kmin=−1
- 初始节点从 o p e n l i s t openlist openlist中删除(与A*算法逻辑类似)
- o p e n l i s t openlist openlist为空 (与Dijkstra算法逻辑类似)
- 如果 k m i n = − 1 k_{min}=-1 kmin=−1,表示目标节点不可到达,结束程序
- 循环追踪最优路径
- 如果到达目标节点,结束程序
- 如果地图环境发生变化(遇到障碍物
Y
Y
Y)
- 调用
modify_cost(Y,X,c(X,Y))
函数修改边的cost,并将节点 Y Y Y加入 o p e n l i s t openlist openlist - 循环执行
progress_state
函数搜索绕开障碍物 Y Y Y的路径,直到 k m i n ≥ h ( X ) & & k m i n ! = − 1 k_{min}\ge h(X) \&\& k_{min} != -1 kmin≥h(X)&&kmin!=−1,其中 X X X为当前状态节点。(这个终止条件表明 o p e n l i s t openlist openlist中最小的 k k k值已经比 h ( X ) h(X) h(X)值大了,不能再找到更小的 k m i n 去优化路径 k_{min}去优化路径 kmin去优化路径。) - 如果 k m i n = − 1 k_{min}=-1 kmin=−1,表示目标节点不可到达,结束程序
- 调用
核心算法解释
progress_state
progress_state
主要功能是计算到目标节点的最优cost。该算法可以简单分为四个大模块。
模块1
该模块主要是从
o
p
e
n
l
i
s
t
openlist
openlist选择最小
k
k
k值得节点,保存最小
k
m
i
n
k_{min}
kmin到
k
o
l
d
k_{old}
kold,最后调用delete(X)
函数从
o
p
e
n
l
i
s
t
openlist
openlist中删除
X
X
X节点。这里delete(X)
函数核心功能是
t
a
g
(
X
)
=
C
l
o
s
e
d
tag(X)=Closed
tag(X)=Closed。
模块2
该模块判断节点 k o l d < h ( X ) k_{old} < h(X) kold<h(X)是否是 R a i s e Raise Raise状态,表明该节点已经受到障碍物得影响,那么搜索能够降低 h ( X ) h(X) h(X)邻居节点。如果找到满足条件,那么把 Y Y Y设置为 X X X的父亲节点,同时更新 h ( X ) h(X) h(X)的值。该过程只能够减小 h ( X ) h(X) h(X),但是与 h o l d h_{old} hold的关系尚未可知,需要下面的模块进一步判断。
模块3
该模块是判断了 X X X节点为 L o w e r Lower Lower状态,然后继续判断邻居节点 Y Y Y是否有必要 X X X作为父亲节点。如果 X X X和邻居节点 Y Y Y满足下面三个条件之一,需要把 Y Y Y节点加入到 o p e n l i s t openlist openlist,进一步考察
- 情况1: Y Y Y节点为 N e w New New,表示还未加入到 o p e n l i s t openlist openlist;
- 情况2: X X X为 Y Y Y的父亲节点,但是不满足 h ( Y ) ≠ h ( X ) + c ( X , Y ) h(Y)\ne h(X) + c(X, Y) h(Y)=h(X)+c(X,Y),说明 h ( x ) h(x) h(x)更新过,可能是由于障碍物引起的
- 情况3: X X X不是 Y Y Y的父亲节点,但是 h ( Y ) > h ( X ) + c ( X , Y ) h(Y) > h(X) + c(X, Y) h(Y)>h(X)+c(X,Y),说明 Y Y Y可以利用 X X X减小 h ( Y ) h(Y) h(Y)
模块4
主要处理 X X X为 R a i s e Raise Raise情况下扩展,该情况下受到障碍物的影响了。可以分为以下三个模块:
模块4.1
当满足下面条件之一,将 Y Y Y节点加入到 o p e n l i s t openlist openlist
- 情况1: Y Y Y节点状态为 N e w New New,表明还未被探索
- 情况2: X X X为 Y Y Y节点的父亲节点,但是 h ( Y ) ≠ h ( X ) + c ( X , Y ) h(Y)\ne h(X) + c(X,Y) h(Y)=h(X)+c(X,Y),表明 X X X节点受到障碍无影响
模块4.2
如果 X X X不是 Y Y Y节点的父亲节点,但是 h ( Y ) > h ( X ) + c ( X , Y ) h(Y)>h(X)+c(X,Y) h(Y)>h(X)+c(X,Y), 表明 Y Y Y节点可以通过 X X X减少 h ( Y ) h(Y) h(Y),但是因为 X X X是 R a i s e Raise Raise状态,需要 X X X加入到 o p e n l i s t openlist openlist中待下一次满足条件,将 X X X作为 Y Y Y节点的父亲节点(对应于模块3中的条件)。
模块4.3
如果 X X X不是 Y Y Y节点的父亲节点,且 h ( X ) > h ( Y ) + c ( X , Y ) h(X)>h(Y) + c(X, Y) h(X)>h(Y)+c(X,Y),且 t a g ( Y ) = C l o s e d tag(Y)=Closed tag(Y)=Closed,且 h ( Y ) > k o l d h(Y)>k_{old} h(Y)>kold,表明 Y Y Y节点能够通过 X X X节点减小 h ( Y ) h(Y) h(Y),但是 h ( Y ) h(Y) h(Y)居然比最小的 k o l d k_{old} kold故而需要重新把 Y Y Y大,故而需要加入到 o p e n l i s t openlist openlist中
modify_cost(X, Y, c)
modify_cost
函数主要是用修改边的cost函数,并将受影响的状态加入
o
p
e
n
l
i
s
t
openlist
openlist
- 更新所有的 c ( X , Y ) c(X, Y) c(X,Y)
- 如果 t a g ( X ) = C l o s e d tag(X)=Closed tag(X)=Closed,将 X X X加入到 o p e n l i s t openlist openlist
- 返回 o p e n l i s t openlist openlist中的 k m i n k_{min} kmin
insert
insert
函数主要的功能是将需要考虑的节点加入到
o
p
e
n
l
i
s
t
openlist
openlist,并更新状态。
- 如果 t a g ( X ) = N e w tag(X)=New tag(X)=New, k ( X ) = h n e w k(X)=h_{new} k(X)=hnew
- 如果 t a g ( X ) = O p e n tag(X)=Open tag(X)=Open, k ( X ) = min ( k ( X ) , h n e w ) k(X)=\min(k(X), h_{new}) k(X)=min(k(X),hnew)
- 如果 t a g ( X ) = C l o s e d tag(X)=Closed tag(X)=Closed, k ( X ) = min ( h ( X ) , h n e w ) k(X)=\min(h(X), h_{new}) k(X)=min(h(X),hnew)
- h ( X ) = h n e w h(X)=h_{new} h(X)=hnew
- t a g ( X ) = O p e n tag(X)=Open tag(X)=Open
例子
如上图所示,D*算法静态搜索能够得到从起点
(
2
,
1
)
(2,1)
(2,1)到
(
7
,
6
)
(7, 6)
(7,6)的最短路径,其中用蓝色标记。在该过程中,从目标节点反向搜索过程中主要调用progress_state
中模块3,此时根据问题求解方式可以等价于Dijkstra或者A*算法。假设移动机器人运动到
(
3
,
2
)
(3, 2)
(3,2)发现
(
4
,
3
)
(4, 3)
(4,3)是障碍物,此时需要执行replan的流程,这一部分也是D*的核心。
- Replan过程首先把 ( 4 , 3 ) (4,3) (4,3)加入到 o p e n l i s t openlist openlist中,然后对邻居节点进行扩展。此时 h ( 4 , 3 ) h(4,3) h(4,3)是一个极大的值,该节点状态也变成了 R a i s e Raise Raise状态。因为与 ( 4 , 3 ) (4, 3) (4,3)连接的其他邻居连接都是最大cost,所以模块2不被执行,此时只有模块4.1被执行了,也就是将 ( 3 , 2 ) (3,2) (3,2)加入到 o p e n l i s t openlist openlist中, h ( 3 , 2 ) h(3,2) h(3,2)设置为最大值
- 接下来会将 ( 3 , 2 ) (3,2) (3,2)弹出作为当前节点进行搜索,此时状态也是 R a i s e Raise Raise状态。此时 k o l d = 5.6 k_{old}=5.6 kold=5.6,模块2中搜索周围发现不存在邻居节点的 h ( Y ) ≤ k o l d h(Y)\le k_{old} h(Y)≤kold,因此不执行。通过模块4.1,将 R a i s e Raise Raise状态扩散给 ( 2 , 2 ) , ( 2 , 1 ) , ( 3 , 1 ) (2,2),(2,1),(3,1) (2,2),(2,1),(3,1),并将 h h h值设置为最大值。通过模块4.3将 ( 4 , 1 ) (4,1) (4,1)加入到 o p e n l i s t openlist openlist。此时, o p e n l i s t = { ( 2 , 2 ) , ( 2 , 1 ) , ( 3 , 1 ) , ( 4 , 1 ) } openlist=\{(2,2),(2,1),(3,1),(4,1)\} openlist={(2,2),(2,1),(3,1),(4,1)}
- 下一步弹出 ( 4 , 1 ) (4,1) (4,1), k o l d = 6.2 k_{old}=6.2 kold=6.2,该节点为 L o w e r Lower Lower状态,因此只需要执行模块3。对周围邻居进行探索, ( 3 , 2 ) (3,2) (3,2)满足情况3,将 ( 3 , 2 ) (3,2) (3,2)设置为 ( 4 , 1 ) (4,1) (4,1)的子节点,同时使 ( 3 , 2 ) (3,2) (3,2)变成 L o w e r Lower Lower状态加入到 o p e n l i s t openlist openlist中。此时 k ( 3 , 2 ) = 7.6 k(3,2)=7.6 k(3,2)=7.6。
- 其他的节点按照类似的关系一直更新,直到所有的返回的 k m i n ≥ h ( 3 , 2 ) k_{min}\ge h(3,2) kmin≥h(3,2),说明 o p e n l i s t openlist openlist中不存在节点能够优化 h ( 3 , 2 ) h(3,2) h(3,2)
Reference
- D*
- Robotic Motion Planning: A* and D* Search
- Optimal and Efficient Path Planning for Partially-Known Environments