ARAstar.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. """
  2. ARA_star 2D (Anytime Repairing A*)
  3. @author: huiming zhou
  4. """
  5. import os
  6. import sys
  7. import math
  8. sys.path.append(os.path.dirname(os.path.abspath(__file__)) +
  9. "/../../Search-based Planning/")
  10. from Search_2D import plotting
  11. from Search_2D import env
  12. class AraStar:
  13. def __init__(self, s_start, s_goal, e, heuristic_type):
  14. self.s_start, self.s_goal = s_start, s_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.e = e # initial weight
  20. self.g = {self.s_start: 0, self.s_goal: float("inf")} # cost to come
  21. self.OPEN = {self.s_start: self.fvalue(self.s_start)} # priority queue / OPEN set
  22. self.CLOSED = set() # CLOSED set
  23. self.INCONS = {} # INCONS set
  24. self.PARENT = {self.s_start: self.s_start} # relations
  25. self.path = [] # planning path
  26. self.visited = [] # order of visited nodes
  27. def searching(self):
  28. self.ImprovePath()
  29. self.path.append(self.extract_path())
  30. while self.update_e() > 1: # continue condition
  31. self.e -= 0.5 # increase weight
  32. self.OPEN.update(self.INCONS)
  33. for s in self.OPEN:
  34. self.OPEN[s] = self.fvalue(s)
  35. self.INCONS = {}
  36. self.CLOSED = set()
  37. self.ImprovePath() # improve path
  38. self.path.append(self.extract_path())
  39. return self.path, self.visited
  40. def ImprovePath(self):
  41. """
  42. :return: a e'-suboptimal path
  43. """
  44. visited_each = []
  45. while True:
  46. s, f_small = self.get_smallest_f()
  47. if self.fvalue(self.s_goal) <= f_small:
  48. break
  49. self.CLOSED.add(s)
  50. for s_n in self.get_neighbor(s):
  51. new_cost = self.g[s] + self.cost(s, s_n)
  52. if s_n not in self.g or new_cost < self.g[s_n]:
  53. self.g[s_n] = new_cost
  54. self.PARENT[s_n] = s
  55. visited_each.append(s_n)
  56. if s_n not in self.CLOSED:
  57. self.OPEN[s_n] = self.fvalue(s_n)
  58. else:
  59. self.INCONS[s_n] = 0
  60. self.visited.append(visited_each)
  61. def get_smallest_f(self):
  62. """
  63. :return: node with smallest f_value in OPEN set.
  64. """
  65. s_list = {}
  66. for s in self.OPEN:
  67. s_list[s] = self.fvalue(s)
  68. s_small = min(s_list, key=s_list.get)
  69. self.OPEN.pop(s_small)
  70. return s_small, s_list[s_small]
  71. def get_neighbor(self, s):
  72. """
  73. find neighbors of state s that not in obstacles.
  74. :param s: state
  75. :return: neighbors
  76. """
  77. s_list = set()
  78. for u in self.u_set:
  79. s_next = tuple([s[i] + u[i] for i in range(2)])
  80. if s_next not in self.obs:
  81. s_list.add(s_next)
  82. return s_list
  83. def update_e(self):
  84. v = float("inf")
  85. if self.OPEN:
  86. v = min(self.g[s] + self.h(s) for s in self.OPEN)
  87. if self.INCONS:
  88. v = min(v, min(self.g[s] + self.h(s) for s in self.INCONS))
  89. return min(self.e, self.g[self.s_goal] / v)
  90. def fvalue(self, x):
  91. return self.g[x] + self.e * self.h(x)
  92. def extract_path(self):
  93. """
  94. Extract the path based on the PARENT set.
  95. :return: The planning path
  96. """
  97. path = [self.s_goal]
  98. s = self.s_goal
  99. while True:
  100. s = self.PARENT[s]
  101. path.append(s)
  102. if s == self.s_start:
  103. break
  104. return list(path)
  105. def h(self, s):
  106. """
  107. Calculate heuristic.
  108. :param s: current node (state)
  109. :return: heuristic function value
  110. """
  111. heuristic_type = self.heuristic_type # heuristic type
  112. goal = self.s_goal # goal node
  113. if heuristic_type == "manhattan":
  114. return abs(goal[0] - s[0]) + abs(goal[1] - s[1])
  115. else:
  116. return math.hypot(goal[0] - s[0], goal[1] - s[1])
  117. @staticmethod
  118. def cost(s_start, s_goal):
  119. """
  120. Calculate cost for this motion
  121. :param s_start: starting node
  122. :param s_goal: end node
  123. :return: cost for this motion
  124. :note: cost function could be more complicate!
  125. """
  126. return 1
  127. def main():
  128. s_start = (5, 5)
  129. s_goal = (45, 25)
  130. arastar = AraStar(s_start, s_goal, 2.5, "euclidean")
  131. plot = plotting.Plotting(s_start, s_goal)
  132. path, visited = arastar.searching()
  133. plot.animation_ara_star(path, visited, "Anytime Repairing A* (ARA*)")
  134. if __name__ == '__main__':
  135. main()