• 使用 Python 的自主机器人算法 Dijkstra 路径规划


    迪杰斯特拉算法

    • Dijkstra 算法是一种广泛使用的算法,用于查找图中的最短路径。
    • 它通过从起始节点迭代选择成本最小的节点来探索搜索空间。
    • Dijkstra 算法计算到达每个节点的成本,并在找到更短路径时更新成本。
    • 它会持续下去,直到到达目标节点或探索完所有可到达的节点。

    公式

    • math.hypot()

    • math.sqrt()

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

    Djikstra算法结果

    Dijkstra算法优点

    • 最佳解决方案:Dijkstra 算法保证找到起始节点和图中所有其他节点之间的最短路径,前提是该图具有非负边权重。这种最优性确保机器人采用最有效的路线到达目的地。
    • 完整性:Dijkstra 算法是完整的,这意味着如果存在解决方案,它总是会找到解决方案如果从起始节点到目标节点存在有效路径,Dijkstra 算法就会发现它。
    • 可扩展性:Dijkstra 算法在具有适度数量的节点和边的图上表现良好。其时间复杂度为O((V + E) log V),其中V是节点数,E是边数。这使得它适用于许多现实世界的路径规划场景。
    • 灵活性:Dijkstra 算法可以应用于各种图表示,包括有向图和无向图。它还可以处理加权图,其中不同的边具有不同的成本或距离
    • 增量更新:Dijkstra 算法允许对图进行增量更新。如果环境发生变化或出现新的障碍物,算法可以重新运行以找到更新的最短路径,而无需从头开始。
    • 广泛的适用性:Dijkstra 的算法广泛应用于各种应用,包括机器人、导航系统、网络路由和物流。其多功能性和经过验证的有效性使其成为自主机器人路径规划的热门选择
  • 相关阅读:
    vulnhub Photographer: 1
    基于Apache Hudi 构建Serverless实时分析平台
    【Vue】params和query的区别?实战两种路由传参方式
    【IC设计】ZC706板卡点灯入门(含Verilog代码,xdc约束,实验截图)
    Git 标签(Tag)实战:打标签和删除标签的步骤指南
    微服务组件之Feign
    【软考】-- 操作系统(上)
    Spring 中BeanFactory和FactoryBean有什么不同之处呢?
    远程仓库地址改变后更换url
    el form 表单validate成功后没有执行逻辑
  • 原文地址:https://blog.csdn.net/qq_41929396/article/details/133378006