astar.py 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. import heapq
  2. import math
  3. import numpy as np
  4. import matplotlib.pyplot as plt
  5. class Node:
  6. def __init__(self, x, y, cost, pind):
  7. self.x = x # x position of node
  8. self.y = y # y position of node
  9. self.cost = cost # g cost of node
  10. self.pind = pind # parent index of node
  11. class Para:
  12. def __init__(self, minx, miny, maxx, maxy, xw, yw, reso, motion):
  13. self.minx = minx
  14. self.miny = miny
  15. self.maxx = maxx
  16. self.maxy = maxy
  17. self.xw = xw
  18. self.yw = yw
  19. self.reso = reso # resolution of grid world
  20. self.motion = motion # motion set
  21. def astar_planning(sx, sy, gx, gy, ox, oy, reso, rr):
  22. """
  23. return path of A*.
  24. :param sx: starting node x [m]
  25. :param sy: starting node y [m]
  26. :param gx: goal node x [m]
  27. :param gy: goal node y [m]
  28. :param ox: obstacles x positions [m]
  29. :param oy: obstacles y positions [m]
  30. :param reso: xy grid resolution
  31. :param rr: robot radius
  32. :return: path
  33. """
  34. n_start = Node(round(sx / reso), round(sy / reso), 0.0, -1)
  35. n_goal = Node(round(gx / reso), round(gy / reso), 0.0, -1)
  36. ox = [x / reso for x in ox]
  37. oy = [y / reso for y in oy]
  38. P, obsmap = calc_parameters(ox, oy, rr, reso)
  39. open_set, closed_set = dict(), dict()
  40. open_set[calc_index(n_start, P)] = n_start
  41. q_priority = []
  42. heapq.heappush(q_priority,
  43. (fvalue(n_start, n_goal), calc_index(n_start, P)))
  44. while True:
  45. if not open_set:
  46. break
  47. _, ind = heapq.heappop(q_priority)
  48. n_curr = open_set[ind]
  49. closed_set[ind] = n_curr
  50. open_set.pop(ind)
  51. for i in range(len(P.motion)):
  52. node = Node(n_curr.x + P.motion[i][0],
  53. n_curr.y + P.motion[i][1],
  54. n_curr.cost + u_cost(P.motion[i]), ind)
  55. if not check_node(node, P, obsmap):
  56. continue
  57. n_ind = calc_index(node, P)
  58. if n_ind not in closed_set:
  59. if n_ind in open_set:
  60. if open_set[n_ind].cost > node.cost:
  61. open_set[n_ind].cost = node.cost
  62. open_set[n_ind].pind = ind
  63. else:
  64. open_set[n_ind] = node
  65. heapq.heappush(q_priority,
  66. (fvalue(node, n_goal), calc_index(node, P)))
  67. pathx, pathy = extract_path(closed_set, n_start, n_goal, P)
  68. return pathx, pathy
  69. def calc_holonomic_heuristic_with_obstacle(node, ox, oy, reso, rr):
  70. n_goal = Node(round(node.x[-1] / reso), round(node.y[-1] / reso), 0.0, -1)
  71. ox = [x / reso for x in ox]
  72. oy = [y / reso for y in oy]
  73. P, obsmap = calc_parameters(ox, oy, reso, rr)
  74. open_set, closed_set = dict(), dict()
  75. open_set[calc_index(n_goal, P)] = n_goal
  76. q_priority = []
  77. heapq.heappush(q_priority, (n_goal.cost, calc_index(n_goal, P)))
  78. while True:
  79. if not open_set:
  80. break
  81. _, ind = heapq.heappop(q_priority)
  82. n_curr = open_set[ind]
  83. closed_set[ind] = n_curr
  84. open_set.pop(ind)
  85. for i in range(len(P.motion)):
  86. node = Node(n_curr.x + P.motion[i][0],
  87. n_curr.y + P.motion[i][1],
  88. n_curr.cost + u_cost(P.motion[i]), ind)
  89. if not check_node(node, P, obsmap):
  90. continue
  91. n_ind = calc_index(node, P)
  92. if n_ind not in closed_set:
  93. if n_ind in open_set:
  94. if open_set[n_ind].cost > node.cost:
  95. open_set[n_ind].cost = node.cost
  96. open_set[n_ind].pind = ind
  97. else:
  98. open_set[n_ind] = node
  99. heapq.heappush(q_priority, (node.cost, calc_index(node, P)))
  100. hmap = [[np.inf for _ in range(P.yw)] for _ in range(P.xw)]
  101. for n in closed_set.values():
  102. hmap[n.x - P.minx][n.y - P.miny] = n.cost
  103. return hmap
  104. def check_node(node, P, obsmap):
  105. if node.x <= P.minx or node.x >= P.maxx or \
  106. node.y <= P.miny or node.y >= P.maxy:
  107. return False
  108. if obsmap[node.x - P.minx][node.y - P.miny]:
  109. return False
  110. return True
  111. def u_cost(u):
  112. return math.hypot(u[0], u[1])
  113. def fvalue(node, n_goal):
  114. return node.cost + h(node, n_goal)
  115. def h(node, n_goal):
  116. return math.hypot(node.x - n_goal.x, node.y - n_goal.y)
  117. def calc_index(node, P):
  118. return (node.y - P.miny) * P.xw + (node.x - P.minx)
  119. def calc_parameters(ox, oy, rr, reso):
  120. minx, miny = round(min(ox)), round(min(oy))
  121. maxx, maxy = round(max(ox)), round(max(oy))
  122. xw, yw = maxx - minx, maxy - miny
  123. motion = get_motion()
  124. P = Para(minx, miny, maxx, maxy, xw, yw, reso, motion)
  125. obsmap = calc_obsmap(ox, oy, rr, P)
  126. return P, obsmap
  127. def calc_obsmap(ox, oy, rr, P):
  128. obsmap = [[False for _ in range(P.yw)] for _ in range(P.xw)]
  129. for x in range(P.xw):
  130. xx = x + P.minx
  131. for y in range(P.yw):
  132. yy = y + P.miny
  133. for oxx, oyy in zip(ox, oy):
  134. if math.hypot(oxx - xx, oyy - yy) <= rr / P.reso:
  135. obsmap[x][y] = True
  136. break
  137. return obsmap
  138. def extract_path(closed_set, n_start, n_goal, P):
  139. pathx, pathy = [n_goal.x], [n_goal.y]
  140. n_ind = calc_index(n_goal, P)
  141. while True:
  142. node = closed_set[n_ind]
  143. pathx.append(node.x)
  144. pathy.append(node.y)
  145. n_ind = node.pind
  146. if node == n_start:
  147. break
  148. pathx = [x * P.reso for x in reversed(pathx)]
  149. pathy = [y * P.reso for y in reversed(pathy)]
  150. return pathx, pathy
  151. def get_motion():
  152. motion = [[-1, 0], [-1, 1], [0, 1], [1, 1],
  153. [1, 0], [1, -1], [0, -1], [-1, -1]]
  154. return motion
  155. def get_env():
  156. ox, oy = [], []
  157. for i in range(60):
  158. ox.append(i)
  159. oy.append(0.0)
  160. for i in range(60):
  161. ox.append(60.0)
  162. oy.append(i)
  163. for i in range(61):
  164. ox.append(i)
  165. oy.append(60.0)
  166. for i in range(61):
  167. ox.append(0.0)
  168. oy.append(i)
  169. for i in range(40):
  170. ox.append(20.0)
  171. oy.append(i)
  172. for i in range(40):
  173. ox.append(40.0)
  174. oy.append(60.0 - i)
  175. return ox, oy
  176. def main():
  177. sx = 10.0 # [m]
  178. sy = 10.0 # [m]
  179. gx = 50.0 # [m]
  180. gy = 50.0 # [m]
  181. robot_radius = 2.0
  182. grid_resolution = 1.0
  183. ox, oy = get_env()
  184. pathx, pathy = astar_planning(sx, sy, gx, gy, ox, oy, grid_resolution, robot_radius)
  185. plt.plot(ox, oy, 'sk')
  186. plt.plot(pathx, pathy, '-r')
  187. plt.plot(sx, sy, 'sg')
  188. plt.plot(gx, gy, 'sb')
  189. plt.axis("equal")
  190. plt.show()
  191. if __name__ == '__main__':
  192. main()