RRT.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. import env
  2. import plotting
  3. import node
  4. import numpy as np
  5. import math
  6. import matplotlib.pyplot as plt
  7. import matplotlib.patches as patches
  8. class Node:
  9. def __init__(self, x, y):
  10. self.x = x
  11. self.y = y
  12. self.path_x = []
  13. self.path_y = []
  14. self.parent = None
  15. class RRT:
  16. def __init__(self, xI, xG):
  17. self.xI = Node(xI[0], xI[1])
  18. self.xG = node.Node(xG[0], xG[1])
  19. self.env = env.Env()
  20. # self.plotting = plotting.Plotting(xI, xG)
  21. self.x_range = self.env.x_range
  22. self.y_range = self.env.y_range
  23. # self.obs_boundary = self.env.obs_boundary
  24. # self.obs_circle = self.env.obs_circle
  25. self.obstacleList = [
  26. (5, 5, 1),
  27. (3, 6, 2),
  28. (3, 8, 2),
  29. (3, 10, 2),
  30. (7, 5, 2),
  31. (9, 5, 2),
  32. (8, 10, 1)
  33. ] # [x, y, radius]
  34. self.expand_range = 0.8
  35. self.goal_sample_rate = 0.05
  36. self.iterations = 500
  37. self.node_list = []
  38. path = self.planning()
  39. if path is None:
  40. print("No path!")
  41. else:
  42. print("get it!")
  43. self.draw_graph()
  44. plt.plot([x[0] for x in path], [x[1] for x in path], '-r')
  45. plt.grid(True)
  46. plt.pause(0.01) # Need for Mac
  47. plt.show()
  48. def planning(self):
  49. self.node_list = [self.xI]
  50. for i in range(self.iterations):
  51. node_rand = self.generate_random_node()
  52. node_near = self.get_nearest_node(self.node_list, node_rand)
  53. node_new = self.new_node(node_near, node_rand, self.expand_range)
  54. if not self.check_collision(node_new, self.obstacleList):
  55. self.node_list.append(node_new)
  56. self.draw_graph(node_rand)
  57. if self.cal_dis_to_goal(self.node_list[-1]) <= self.expand_range:
  58. node_end = self.new_node(self.node_list[-1], node.Node(self.xG.x, self.xG.y), self.expand_range)
  59. if not self.check_collision(node_end, self.obstacleList):
  60. return self.extract_path(self.node_list)
  61. return None
  62. def draw_graph(self, rnd=None):
  63. plt.clf()
  64. # for stopping simulation with the esc key.
  65. plt.gcf().canvas.mpl_connect('key_release_event',
  66. lambda event: [exit(0) if event.key == 'escape' else None])
  67. if rnd is not None:
  68. plt.plot(rnd.x, rnd.y, "^k")
  69. for node_x in self.node_list:
  70. if node_x.parent:
  71. plt.plot(node_x.path_x, node_x.path_y, "-g")
  72. for (ox, oy, size) in self.obstacleList:
  73. self.plot_circle(ox, oy, size)
  74. plt.plot(self.xI.x, self.xI.y, "xr")
  75. plt.plot(self.xG.x, self.xG.y, "xr")
  76. plt.axis("equal")
  77. plt.axis([-2, 15, -2, 15])
  78. plt.grid(True)
  79. plt.pause(0.01)
  80. @staticmethod
  81. def plot_circle(x, y, size, color="-b"): # pragma: no cover
  82. deg = list(range(0, 360, 5))
  83. deg.append(0)
  84. xl = [x + size * math.cos(np.deg2rad(d)) for d in deg]
  85. yl = [y + size * math.sin(np.deg2rad(d)) for d in deg]
  86. plt.plot(xl, yl, color)
  87. def extract_path(self, nodelist):
  88. path = [(self.xG.x, self.xG.y)]
  89. node_now = nodelist[-1]
  90. while node_now.parent is not None:
  91. node_now = node_now.parent
  92. path.append((node_now.x, node_now.y))
  93. return path
  94. def cal_dis_to_goal(self, node_cal):
  95. return math.hypot((node_cal.x - self.xG.x), (node_cal.y - self.xG.y))
  96. def new_node(self, node_start, node_goal, expand_range):
  97. new_node = node.Node(node_start.x, node_start.y)
  98. d, theta = self.calc_distance_and_angle(new_node, node_goal)
  99. new_node.path_x = [new_node.x]
  100. new_node.path_y = [new_node.y]
  101. if d < expand_range:
  102. expand_range = d
  103. new_node.x += expand_range * math.cos(theta)
  104. new_node.y += expand_range * math.sin(theta)
  105. new_node.path_x.append(new_node.x)
  106. new_node.path_y.append(new_node.y)
  107. new_node.parent = node_start
  108. return new_node
  109. def generate_random_node(self):
  110. if np.random.random() > self.goal_sample_rate:
  111. return node.Node(np.random.uniform(self.x_range[0], self.x_range[1]),
  112. np.random.uniform(self.y_range[0], self.y_range[1]))
  113. else:
  114. return node.Node(self.xG.x, self.xG.y)
  115. def get_nearest_node(self, node_list, node_random):
  116. dlist = [(nod.x - node_random.x) ** 2 + (nod.y - node_random.y) ** 2
  117. for nod in node_list]
  118. minind = dlist.index(min(dlist))
  119. return self.node_list[minind]
  120. @staticmethod
  121. def calc_distance_and_angle(from_node, to_node):
  122. dx = to_node.x - from_node.x
  123. dy = to_node.y - from_node.y
  124. d = math.hypot(dx, dy)
  125. theta = math.atan2(dy, dx)
  126. return d, theta
  127. def check_collision(self, node_check, obstacleList):
  128. if node_check is None:
  129. return True
  130. for (ox, oy, size) in obstacleList:
  131. dx_list = [ox - x for x in node_check.path_x]
  132. dy_list = [oy - y for y in node_check.path_y]
  133. d_list = [dx * dx + dy * dy for (dx, dy) in zip(dx_list, dy_list)]
  134. if min(d_list) <= size ** 2:
  135. return True # collision
  136. return False # safe
  137. #
  138. # def check_collision(self, node_check):
  139. # for obs in self.obs_boundary:
  140. # dx = node_check.x - obs[0]
  141. # dy = node_check.y - obs[1]
  142. # if 0 <= dx <= obs[2] and 0 <= dy <= obs[2]:
  143. # return True
  144. #
  145. # for obs in self.obs_circle:
  146. # d = (node_check.x - obs[0]) ** 2 + (node_check.y - obs[1]) ** 2
  147. # if d <= obs[2] ** 2:
  148. # return True
  149. #
  150. # return False
  151. if __name__ == '__main__':
  152. x_Start = (0, 0) # Starting node
  153. x_Goal = (6, 10) # Goal node
  154. rrt = RRT(x_Start, x_Goal)