当前位置:   article > 正文

Dijistra和A star算法

dijistra

Dijistra和A star算法在自动驾驶领域可用于路径的搜索,甚至在一定的场景下能用作轨迹的规划。

A star算法相当于是Dijistra算法的改进,在其基础上加上了绝对距离等判断条件,从而大大降低了路径搜索的范围,节约了算力。理解两个算法,我们要先从Dijistra算法开始。

1.Dijistra算法的思路

Dijistra算法的思路很简单,采用的是一种贪心的策略,声明一个数组dis来保存源点到各个顶点的最短距离和一个保存已经找到了最短路径的顶点的集合:T,初始时,原点 s 的路径权重被赋为 0 (dis[s] = 0)。若对于顶点 s 存在能直接到达的边(s,m),则把dis[m]设为w(s, m),同时把所有其他(s不能直接到达的)顶点的路径长度设为无穷大。初始时,集合T只有顶点s。
然后,从dis数组选择最小值,则该值就是源点s到该值对应的顶点的最短路径,并且把该点加入到T中,OK,此时完成一个顶点,然后,我们需要看看新加入的顶点是否可以到达其他顶点并且看看通过该顶点到达其他点的路径长度是否比源点直接到达短,如果是,那么就替换这些顶点在dis中的值。然后,又从dis中找出最小值,重复上述动作,直到T中包含了图的所有顶点。

算法的伪代码如下:

 其中:

最小堆open:存储所有需要处理的节点

变量closed: 表示已经处理完的节点集

变量predecessors: 回溯最短路径上的已经访问过的节点

uCost:源节点到该点的距离

从下图可以大致理解一下Djistra的搜索过程:

假设一个从s到t的场景:

首先s可以到b和a,这是我们将其作为存储起来,这个时候从s到a的距离是大于从s到b的;因此再搜索b的下一步路径,将a保留存储。s到b再到c的距离是1.5还是小于s到a,因此继续从c向后搜索这时从s到b再到c再到d的距离大于从s到a的距离,因此从a再开始搜索,搜索一步后就到了目的地,整个算法的进程结束。

能力有限可能讲的不是很到位,大伙可以自行查阅资料,Dijistra算法还是比较好理解的。

2.A star算法的改进

 A*算法其实就是在Dijistra算法加了一个欧氏距离或者曼哈顿距离的判断。

欧式距离:

欧式距离计算公式_Panpan Wei的博客-CSDN博客_欧式距离计算公式

曼哈顿距离:

 

 其实现伪代码如图:

可以看出A*算法相对于Dijistra主要加上了绝对距离h,这个h代表的是当前点到终点的欧式距离或者曼哈顿距离。可以理解为如果我在搜索时,这个距离过大,那么这个点之后的路径将不在进行搜索。我们可以对这个欧式距离设定一定的权重,来使得A*算法探索路径的能力和得到最优路径的能力有一个很好的平衡。

3.两种算法的实现和结果对比

Dijistra算法:

  1. """
  2. Grid based Dijkstra planning
  3. """
  4. import matplotlib.pyplot as plt
  5. import math
  6. show_animation = True
  7. class Dijkstra:
  8. def __init__(self, ox, oy, resolution, robot_radius):
  9. """
  10. Initialize map for a star planning
  11. ox: x position list of Obstacles [m]
  12. oy: y position list of Obstacles [m]
  13. resolution: grid resolution [m]
  14. rr: robot radius[m]
  15. """
  16. self.min_x = None
  17. self.min_y = None
  18. self.max_x = None
  19. self.max_y = None
  20. self.x_width = None
  21. self.y_width = None
  22. self.obstacle_map = None
  23. self.resolution = resolution
  24. self.robot_radius = robot_radius
  25. self.calc_obstacle_map(ox, oy)
  26. self.motion = self.get_motion_model()
  27. class Node:
  28. def __init__(self, x, y, cost, parent_index):
  29. self.x = x # index of grid
  30. self.y = y # index of grid
  31. self.cost = cost
  32. self.parent_index = parent_index # index of previous Node
  33. def __str__(self):
  34. return str(self.x) + "," + str(self.y) + "," + str(
  35. self.cost) + "," + str(self.parent_index)
  36. def planning(self, sx, sy, gx, gy):
  37. """
  38. dijkstra path search
  39. input:
  40. s_x: start x position [m]
  41. s_y: start y position [m]
  42. gx: goal x position [m]
  43. gx: goal x position [m]
  44. output:
  45. rx: x position list of the final path
  46. ry: y position list of the final path
  47. """
  48. #设置起点
  49. start_node = self.Node(self.calc_xy_index(sx, self.min_x),
  50. self.calc_xy_index(sy, self.min_y), 0.0, -1)
  51. #设置目标终点
  52. goal_node = self.Node(self.calc_xy_index(gx, self.min_x),
  53. self.calc_xy_index(gy, self.min_y), 0.0, -1)
  54. #初始化两个字典
  55. open_set, closed_set = dict(), dict()
  56. #给字典放元素,先放进去起始点
  57. open_set[self.calc_index(start_node)] = start_node
  58. while 1:
  59. #搜索最小的键值对
  60. c_id = min(open_set, key=lambda o: open_set[o].cost)
  61. #得到当前可以保存的路径
  62. current = open_set[c_id]
  63. #在图像中得到展示
  64. # show graph
  65. if show_animation: # pragma: no cover
  66. plt.plot(self.calc_position(current.x, self.min_x),
  67. self.calc_position(current.y, self.min_y), "xc")
  68. # for stopping simulation with the esc key.
  69. plt.gcf().canvas.mpl_connect(
  70. 'key_release_event',
  71. lambda event: [exit(0) if event.key == 'escape' else None])
  72. if len(closed_set.keys()) % 10 == 0:
  73. plt.pause(0.001)
  74. #如果x,y已经等于目标点
  75. if current.x == goal_node.x and current.y == goal_node.y:
  76. print("Find goal")
  77. goal_node.parent_index = current.parent_index
  78. goal_node.cost = current.cost
  79. break
  80. # Remove the item from the open set
  81. del open_set[c_id]
  82. # Add it to the closed set
  83. closed_set[c_id] = current
  84. # expand search grid based on motion model
  85. for move_x, move_y, move_cost in self.motion:
  86. node = self.Node(current.x + move_x,
  87. current.y + move_y,
  88. current.cost + move_cost, c_id)
  89. n_id = self.calc_index(node)
  90. if n_id in closed_set:
  91. continue
  92. if not self.verify_node(node):
  93. continue
  94. if n_id not in open_set:
  95. open_set[n_id] = node # Discover a new node
  96. else:
  97. if open_set[n_id].cost >= node.cost:
  98. # This path is the best until now. record it!
  99. open_set[n_id] = node
  100. rx, ry = self.calc_final_path(goal_node, closed_set)
  101. return rx, ry
  102. def calc_final_path(self, goal_node, closed_set):
  103. # generate final path
  104. rx, ry = [self.calc_position(goal_node.x, self.min_x)], [
  105. self.calc_position(goal_node.y, self.min_y)]
  106. parent_index = goal_node.parent_index
  107. while parent_index != -1:
  108. n = closed_set[parent_index]
  109. rx.append(self.calc_position(n.x, self.min_x))
  110. ry.append(self.calc_position(n.y, self.min_y))
  111. parent_index = n.parent_index
  112. return rx, ry
  113. def calc_position(self, index, minp):
  114. pos = index * self.resolution + minp
  115. return pos
  116. def calc_xy_index(self, position, minp):
  117. return round((position - minp) / self.resolution)
  118. def calc_index(self, node):
  119. return (node.y - self.min_y) * self.x_width + (node.x - self.min_x)
  120. def verify_node(self, node):
  121. px = self.calc_position(node.x, self.min_x)
  122. py = self.calc_position(node.y, self.min_y)
  123. if px < self.min_x:
  124. return False
  125. if py < self.min_y:
  126. return False
  127. if px >= self.max_x:
  128. return False
  129. if py >= self.max_y:
  130. return False
  131. if self.obstacle_map[node.x][node.y]:
  132. return False
  133. return True
  134. def calc_obstacle_map(self, ox, oy):
  135. self.min_x = round(min(ox))
  136. self.min_y = round(min(oy))
  137. self.max_x = round(max(ox))
  138. self.max_y = round(max(oy))
  139. print("min_x:", self.min_x)
  140. print("min_y:", self.min_y)
  141. print("max_x:", self.max_x)
  142. print("max_y:", self.max_y)
  143. self.x_width = round((self.max_x - self.min_x) / self.resolution)
  144. self.y_width = round((self.max_y - self.min_y) / self.resolution)
  145. print("x_width:", self.x_width)
  146. print("y_width:", self.y_width)
  147. # obstacle map generation
  148. self.obstacle_map = [[False for _ in range(self.y_width)]
  149. for _ in range(self.x_width)]
  150. for ix in range(self.x_width):
  151. x = self.calc_position(ix, self.min_x)
  152. for iy in range(self.y_width):
  153. y = self.calc_position(iy, self.min_y)
  154. for iox, ioy in zip(ox, oy):
  155. d = math.hypot(iox - x, ioy - y)
  156. if d <= self.robot_radius:
  157. self.obstacle_map[ix][iy] = True
  158. break
  159. @staticmethod
  160. def get_motion_model():
  161. # dx, dy, cost
  162. motion = [[1, 0, 1],
  163. [0, 1, 1],
  164. [-1, 0, 1],
  165. [0, -1, 1],
  166. [-1, -1, math.sqrt(2)],
  167. [-1, 1, math.sqrt(2)],
  168. [1, -1, math.sqrt(2)],
  169. [1, 1, math.sqrt(2)]]
  170. return motion
  171. def main():
  172. print(__file__ + " start!!")
  173. # start and goal position
  174. sx =10.0 # [m]
  175. sy = 10.0 # [m]
  176. gx = 50.0 # [m]
  177. gy = 50.0 # [m]
  178. grid_size = 2.0 # [m]
  179. robot_radius = 1.0 # [m]
  180. # set obstacle positions
  181. ox, oy = [], []
  182. for i in range(-10, 60):
  183. ox.append(i)
  184. oy.append(-10.0)
  185. for i in range(-10, 60):
  186. ox.append(60.0)
  187. oy.append(i)
  188. for i in range(-10, 61):
  189. ox.append(i)
  190. oy.append(60.0)
  191. for i in range(-10, 61):
  192. ox.append(-10.0)
  193. oy.append(i)
  194. for i in range(-10, 40):
  195. ox.append(20.0)
  196. oy.append(i)
  197. for i in range(0, 40):
  198. ox.append(40.0)
  199. oy.append(60.0 - i)
  200. for i in range(40, 55):
  201. ox.append(i)
  202. oy.append(30)
  203. if show_animation: # pragma: no cover
  204. plt.plot(ox, oy, ".k")
  205. plt.plot(sx, sy, "og")
  206. plt.plot(gx, gy, "xb")
  207. plt.grid(True)
  208. plt.axis("equal")
  209. dijkstra = Dijkstra(ox, oy, grid_size, robot_radius)
  210. rx, ry = dijkstra.planning(sx, sy, gx, gy)
  211. if show_animation: # pragma: no cover
  212. plt.plot(rx, ry, "-r")
  213. plt.pause(0.01)
  214. plt.show()
  215. if __name__ == '__main__':
  216. main()

A*算法实现(定义一个欧式距离或曼哈顿距离函数)

  1. """
  2. A* grid planning
  3. """
  4. import numpy as np
  5. import math
  6. import matplotlib.pyplot as plt
  7. show_animation = True
  8. class AStarPlanner:
  9. def __init__(self, ox, oy, resolution, rr):
  10. """
  11. Initialize grid map for a star planning
  12. ox: x position list of Obstacles [m]
  13. oy: y position list of Obstacles [m]
  14. resolution: grid resolution [m]
  15. rr: robot radius[m]
  16. """
  17. self.resolution = resolution
  18. self.rr = rr
  19. self.min_x, self.min_y = 0, 0
  20. self.max_x, self.max_y = 0, 0
  21. self.obstacle_map = None
  22. self.x_width, self.y_width = 0, 0
  23. self.motion = self.get_motion_model()
  24. self.calc_obstacle_map(ox, oy)
  25. class Node:
  26. def __init__(self, x, y, cost, parent_index):
  27. self.x = x # index of grid
  28. self.y = y # index of grid
  29. self.cost = cost
  30. self.parent_index = parent_index
  31. def __str__(self):
  32. return str(self.x) + "," + str(self.y) + "," + str(
  33. self.cost) + "," + str(self.parent_index)
  34. def planning(self, sx, sy, gx, gy):
  35. """
  36. A star path search
  37. input:
  38. s_x: start x position [m]
  39. s_y: start y position [m]
  40. gx: goal x position [m]
  41. gy: goal y position [m]
  42. output:
  43. rx: x position list of the final path
  44. ry: y position list of the final path
  45. """
  46. # 设置起点
  47. start_node = self.Node(self.calc_xy_index(sx, self.min_x),
  48. self.calc_xy_index(sy, self.min_y), 0.0, -1)
  49. # 设置目标终点
  50. goal_node = self.Node(self.calc_xy_index(gx, self.min_x),
  51. self.calc_xy_index(gy, self.min_y), 0.0, -1)
  52. # 初始化两个字典
  53. open_set, closed_set = dict(), dict()
  54. # 给字典放元素,先放进去起始点
  55. open_set[self.calc_grid_index(start_node)] = start_node
  56. #添加欧式距离或者曼哈顿距离
  57. while 1:
  58. # 搜索最小的键值对,前一项和Dijstra一样,后面一项是添加的距离
  59. #c_id = min(open_set, key=lambda o: open_set[o].cost)
  60. #c_id = min(open_set, key=lambda o: open_set[o].cost + self.calc_heuristic(open_set[o], goal_node))
  61. #c_id = min(open_set, key=lambda o: open_set[o].cost + self.calc_euclidean(open_set[o], goal_node))
  62. c_id = min(open_set, key=lambda o: open_set[o].cost + self.calc_manhattan(open_set[o], goal_node))
  63. # 得到当前可以保存的路径
  64. current = open_set[c_id]
  65. # 在图像中得到展示
  66. # show graph
  67. if show_animation: # pragma: no cover
  68. plt.plot(self.calc_grid_position(current.x, self.min_x),
  69. self.calc_grid_position(current.y, self.min_y), "xc")
  70. # for stopping simulation with the esc key.
  71. plt.gcf().canvas.mpl_connect(
  72. 'key_release_event',
  73. lambda event: [exit(0) if event.key == 'escape' else None])
  74. if len(closed_set.keys()) % 10 == 0:
  75. plt.pause(0.001)
  76. # 如果x,y已经等于目标点
  77. if current.x == goal_node.x and current.y == goal_node.y:
  78. print("Find goal")
  79. goal_node.parent_index = current.parent_index
  80. goal_node.cost = current.cost
  81. break
  82. # Remove the item from the open set
  83. del open_set[c_id]
  84. # Add it to the closed set
  85. closed_set[c_id] = current
  86. # expand search grid based on motion model
  87. for move_x, move_y, move_cost in self.motion:
  88. node = self.Node(current.x + move_x,
  89. current.y + move_y,
  90. current.cost + move_cost, c_id)
  91. n_id = self.calc_grid_index(node)
  92. if n_id in closed_set:
  93. continue
  94. if not self.verify_node(node):
  95. continue
  96. if n_id not in open_set:
  97. open_set[n_id] = node # Discover a new node
  98. else:
  99. if open_set[n_id].cost >= node.cost:
  100. # This path is the best until now. record it!
  101. open_set[n_id] = node
  102. rx, ry = self.calc_final_path(goal_node, closed_set)
  103. return rx, ry
  104. def calc_final_path(self, goal_node, closed_set):
  105. # generate final path,用于更新最后的环境
  106. rx, ry = [self.calc_grid_position(goal_node.x, self.min_x)], [
  107. self.calc_grid_position(goal_node.y, self.min_y)]
  108. parent_index = goal_node.parent_index
  109. while parent_index != -1:
  110. n = closed_set[parent_index]
  111. rx.append(self.calc_grid_position(n.x, self.min_x))
  112. ry.append(self.calc_grid_position(n.y, self.min_y))
  113. parent_index = n.parent_index
  114. return rx, ry
  115. @staticmethod
  116. #三角形距离计算
  117. # def calc_heuristic(n1, n2):
  118. # w = 5.0 # weight of heuristic
  119. # d = w * math.hypot(n1.x - n2.x, n1.y - n2.y)
  120. # return d
  121. #欧氏距离计算
  122. # def calc_euclidean(n1,n2):
  123. # w=1.0
  124. # d=w*pow(pow(n1.x-n2.x,2)+pow(n1.y-n2.y,2),0.5)
  125. # return d
  126. #曼哈顿距离计算
  127. def calc_manhattan(n1,n2):
  128. """
  129. 添加曼哈顿距离
  130. w:权重系数
  131. n1:x方向node
  132. n2:y方向node
  133. d:距离
  134. """
  135. w = 5.0
  136. d = w*(abs(n1.x-n2.x)+abs(n1.y - n2.y))
  137. return d
  138. def calc_grid_position(self, index, min_position):
  139. """
  140. calc grid position
  141. :param index:
  142. :param min_position:
  143. :return:
  144. """
  145. pos = index * self.resolution + min_position
  146. return pos
  147. #获取下标的函数
  148. def calc_xy_index(self, position, min_pos):
  149. return round((position - min_pos) / self.resolution)
  150. #获取网格下标
  151. def calc_grid_index(self, node):
  152. return (node.y - self.min_y) * self.x_width + (node.x - self.min_x)
  153. #判断存入节点选择
  154. def verify_node(self, node):
  155. px = self.calc_grid_position(node.x, self.min_x)
  156. py = self.calc_grid_position(node.y, self.min_y)
  157. if px < self.min_x:
  158. return False
  159. elif py < self.min_y:
  160. return False
  161. elif px >= self.max_x:
  162. return False
  163. elif py >= self.max_y:
  164. return False
  165. # collision check
  166. if self.obstacle_map[node.x][node.y]:
  167. return False
  168. return True
  169. #生成地图
  170. def calc_obstacle_map(self, ox, oy):
  171. self.min_x = round(min(ox))
  172. self.min_y = round(min(oy))
  173. self.max_x = round(max(ox))
  174. self.max_y = round(max(oy))
  175. print("min_x:", self.min_x)
  176. print("min_y:", self.min_y)
  177. print("max_x:", self.max_x)
  178. print("max_y:", self.max_y)
  179. self.x_width = round((self.max_x - self.min_x) / self.resolution)
  180. self.y_width = round((self.max_y - self.min_y) / self.resolution)
  181. print("x_width:", self.x_width)
  182. print("y_width:", self.y_width)
  183. # obstacle map generation
  184. self.obstacle_map = [[False for _ in range(self.y_width)]
  185. for _ in range(self.x_width)]
  186. for ix in range(self.x_width):
  187. x = self.calc_grid_position(ix, self.min_x)
  188. for iy in range(self.y_width):
  189. y = self.calc_grid_position(iy, self.min_y)
  190. for iox, ioy in zip(ox, oy):
  191. d = math.hypot(iox - x, ioy - y)
  192. if d <= self.rr:
  193. self.obstacle_map[ix][iy] = True
  194. break
  195. #规定可执行动作行为
  196. @staticmethod
  197. def get_motion_model():
  198. # dx, dy, cost
  199. motion = [[1, 0, 1],
  200. [0, 1, 1],
  201. [-1, 0, 1],
  202. [0, -1, 1],
  203. [-1, -1, math.sqrt(2)],
  204. [-1, 1, math.sqrt(2)],
  205. [1, -1, math.sqrt(2)],
  206. [1, 1, math.sqrt(2)]]
  207. return motion
  208. def main():
  209. print(__file__ + " start!!")
  210. # start and goal position
  211. sx = 10.0 # [m]
  212. sy = 10.0 # [m]
  213. gx = 50.0 # [m]
  214. gy = 50.0 # [m]
  215. grid_size = 2.0 # [m]
  216. robot_radius = 1.0 # [m]
  217. # set obstacle positions
  218. ox, oy = [], []
  219. for i in range(-10, 60):
  220. ox.append(i)
  221. oy.append(-10.0)
  222. for i in range(-10, 60):
  223. ox.append(60.0)
  224. oy.append(i)
  225. for i in range(-10, 61):
  226. ox.append(i)
  227. oy.append(60.0)
  228. for i in range(-10, 61):
  229. ox.append(-10.0)
  230. oy.append(i)
  231. for i in range(-10, 40):
  232. ox.append(20.0)
  233. oy.append(i)
  234. for i in range(0, 40):
  235. ox.append(40.0)
  236. oy.append(60.0 - i)
  237. # #添加一个障碍
  238. for i in range(40, 55):
  239. ox.append(i)
  240. oy.append(30)
  241. if show_animation: # pragma: no cover
  242. #显示中文标题
  243. plt.rcParams['font.sans-serif'] = ['SimHei'] # 显示中文标签
  244. plt.rcParams['axes.unicode_minus'] = False
  245. plt.title("路径规划实验结果")
  246. #设置坐标轴字体字号
  247. plt.yticks(fontproperties='Times New Roman', size=16)
  248. plt.xticks(fontproperties='Times New Roman', size=16)
  249. #更改作图颜色
  250. plt.plot(ox, oy, ".r")
  251. plt.plot(sx, sy, "og")
  252. plt.plot(gx, gy, "xb")
  253. plt.grid(True)
  254. plt.axis("equal")
  255. a_star = AStarPlanner(ox, oy, grid_size, robot_radius)
  256. rx, ry = a_star.planning(sx, sy, gx, gy)
  257. if show_animation: # pragma: no cover
  258. plt.plot(rx, ry, "-b")
  259. plt.pause(0.001)
  260. plt.show()
  261. plt.show()
  262. if __name__ == '__main__':
  263. main()

4.实现效果

Dijistra算法:

 A*算法:

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/683089
推荐阅读
相关标签
  

闽ICP备14008679号