Best_First.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. """
  2. Best-First Searching
  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 queue
  11. from Search_2D import plotting
  12. from Search_2D import env
  13. class BestFirst:
  14. def __init__(self, s_start, s_goal):
  15. self.s_start, self.s_goal = s_start, s_goal
  16. self.Env = env.Env()
  17. self.plotting = plotting.Plotting(self.s_start, self.s_goal)
  18. self.u_set = self.Env.motions # feasible input set
  19. self.obs = self.Env.obs # position of obstacles
  20. self.OPEN = queue.QueuePrior() # OPEN set
  21. self.OPEN.put(self.s_start, self.Heuristic(self.s_start))
  22. self.CLOSED = [] # CLOSED set / visited order
  23. self.PARENT = {self.s_start: self.s_start}
  24. def searching(self):
  25. """
  26. Best-first Searching
  27. :return: planning path, visited order
  28. """
  29. while self.OPEN:
  30. s = self.OPEN.get()
  31. if s == self.s_goal:
  32. break
  33. self.CLOSED.append(s)
  34. for s_n in self.get_neighbor(s):
  35. if s_n not in self.PARENT: # node not explored
  36. self.OPEN.put(s_n, self.Heuristic(s_n))
  37. self.PARENT[s_n] = s
  38. return self.extract_path(), self.CLOSED
  39. def Heuristic(self, s):
  40. """
  41. estimated distance between current state and goal state.
  42. :param s: current state
  43. :return: estimated distance
  44. """
  45. h = math.hypot(s[0] - self.s_goal[0], s[1] - self.s_goal[1])
  46. return h
  47. def get_neighbor(self, s):
  48. """
  49. find neighbors of state s that not in obstacles.
  50. :param s: state
  51. :return: neighbors
  52. """
  53. s_list = []
  54. for u in self.u_set:
  55. s_next = tuple([s[i] + u[i] for i in range(2)])
  56. if not self.is_collision(s, s_next):
  57. s_list.append(s_next)
  58. return s_list
  59. def is_collision(self, s_start, s_end):
  60. if s_start in self.obs or s_end in self.obs:
  61. return True
  62. if s_start[0] != s_end[0] and s_start[1] != s_end[1]:
  63. if s_end[0] - s_start[0] == s_start[1] - s_end[1]:
  64. s1 = (min(s_start[0], s_end[0]), min(s_start[1], s_end[1]))
  65. s2 = (max(s_start[0], s_end[0]), max(s_start[1], s_end[1]))
  66. else:
  67. s1 = (min(s_start[0], s_end[0]), max(s_start[1], s_end[1]))
  68. s2 = (max(s_start[0], s_end[0]), min(s_start[1], s_end[1]))
  69. if s1 in self.obs or s2 in self.obs:
  70. return True
  71. return False
  72. def extract_path(self):
  73. """
  74. Extract the path based on the relationship of nodes.
  75. :return: The planning path
  76. """
  77. path = [self.s_goal]
  78. s = self.s_goal
  79. while True:
  80. s = self.PARENT[s]
  81. path.append(s)
  82. if s == self.s_start:
  83. break
  84. return list(path)
  85. def main():
  86. s_start = (5, 5)
  87. s_goal = (45, 25)
  88. BF = BestFirst(s_start, s_goal)
  89. plot = plotting.Plotting(s_start, s_goal)
  90. path, visited = BF.searching()
  91. plot.animation(path, visited, "Best-first Searching") # animation
  92. if __name__ == '__main__':
  93. main()