bidirectional_a_star.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. """
  2. Bidirectional_a_star 2D
  3. @author: huiming zhou
  4. """
  5. import os
  6. import sys
  7. sys.path.append(os.path.dirname(os.path.abspath(__file__)) +
  8. "/../../Search-based Planning/")
  9. from Search_2D import queue
  10. from Search_2D import plotting
  11. from Search_2D import env
  12. class BidirectionalAstar:
  13. def __init__(self, x_start, x_goal, heuristic_type):
  14. self.xI, self.xG = x_start, x_goal
  15. self.heuristic_type = heuristic_type
  16. self.Env = env.Env() # class Env
  17. self.u_set = self.Env.motions # feasible input set
  18. self.obs = self.Env.obs # position of obstacles
  19. self.g_fore = {self.xI: 0, self.xG: float("inf")}
  20. self.g_back = {self.xG: 0, self.xI: float("inf")}
  21. self.OPEN_fore = queue.QueuePrior()
  22. self.OPEN_fore.put(self.xI, self.g_fore[self.xI] + self.h(self.xI, self.xG))
  23. self.OPEN_back = queue.QueuePrior()
  24. self.OPEN_back.put(self.xG, self.g_back[self.xG] + self.h(self.xG, self.xI))
  25. self.CLOSED_fore = []
  26. self.CLOSED_back = []
  27. self.Parent_fore = {self.xI: self.xI}
  28. self.Parent_back = {self.xG: self.xG}
  29. def searching(self):
  30. visited_fore, visited_back = [], []
  31. s_meet = self.xI
  32. while not self.OPEN_fore.empty() and not self.OPEN_back.empty():
  33. # solve foreward-search
  34. s_fore = self.OPEN_fore.get()
  35. if s_fore in self.Parent_back:
  36. s_meet = s_fore
  37. break
  38. visited_fore.append(s_fore)
  39. for u in self.u_set:
  40. s_next = tuple([s_fore[i] + u[i] for i in range(len(s_fore))])
  41. if s_next not in self.obs:
  42. new_cost = self.g_fore[s_fore] + self.get_cost(s_fore, u)
  43. if s_next not in self.g_fore:
  44. self.g_fore[s_next] = float("inf")
  45. if new_cost < self.g_fore[s_next]:
  46. self.g_fore[s_next] = new_cost
  47. self.Parent_fore[s_next] = s_fore
  48. self.OPEN_fore.put(s_next, new_cost + self.h(s_next, self.xG))
  49. # solve backward-search
  50. s_back = self.OPEN_back.get()
  51. if s_back in self.Parent_fore:
  52. s_meet = s_back
  53. break
  54. visited_back.append(s_back)
  55. for u in self.u_set:
  56. s_next = tuple([s_back[i] + u[i] for i in range(len(s_back))])
  57. if s_next not in self.obs:
  58. new_cost = self.g_back[s_back] + self.get_cost(s_back, u)
  59. if s_next not in self.g_back:
  60. self.g_back[s_next] = float("inf")
  61. if new_cost < self.g_back[s_next]:
  62. self.g_back[s_next] = new_cost
  63. self.Parent_back[s_next] = s_back
  64. self.OPEN_back.put(s_next, new_cost + self.h(s_next, self.xI))
  65. return self.extract_path(s_meet), visited_fore, visited_back
  66. def extract_path(self, s):
  67. path_back_fore = [s]
  68. s_current = s
  69. while True:
  70. s_current = self.Parent_fore[s_current]
  71. path_back_fore.append(s_current)
  72. if s_current == self.xI:
  73. break
  74. path_back_back = []
  75. s_current = s
  76. while True:
  77. s_current = self.Parent_back[s_current]
  78. path_back_back.append(s_current)
  79. if s_current == self.xG:
  80. break
  81. return list(reversed(path_back_fore)) + list(path_back_back)
  82. def h(self, state, goal):
  83. """
  84. Calculate heuristic.
  85. :param state: current node (state)
  86. :param goal: goal node (state)
  87. :return: heuristic
  88. """
  89. heuristic_type = self.heuristic_type
  90. if heuristic_type == "manhattan":
  91. return abs(goal[0] - state[0]) + abs(goal[1] - state[1])
  92. elif heuristic_type == "euclidean":
  93. return ((goal[0] - state[0]) ** 2 + (goal[1] - state[1]) ** 2) ** (1 / 2)
  94. else:
  95. print("Please choose right heuristic type!")
  96. @staticmethod
  97. def get_cost(x, u):
  98. """
  99. Calculate cost for this motion
  100. :param x: current node
  101. :param u: input
  102. :return: cost for this motion
  103. :note: cost function could be more complicate!
  104. """
  105. return 1
  106. def main():
  107. x_start = (5, 5) # Starting node
  108. x_goal = (49, 25) # Goal node
  109. bastar = BidirectionalAstar(x_start, x_goal, "euclidean")
  110. plot = plotting.Plotting(x_start, x_goal) # class Plotting
  111. fig_name = "Bidirectional-A* Algorithm"
  112. path, v_fore, v_back = bastar.searching()
  113. plot.animation_bi_astar(path, v_fore, v_back, fig_name) # animation generate
  114. if __name__ == '__main__':
  115. main()