Skip to content

Commit 29da707

Browse files
committed
clean rrt codes
1 parent 14271dd commit 29da707

File tree

6 files changed

+323
-440
lines changed

6 files changed

+323
-440
lines changed

PathPlanning/RRT/rrt.py

Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
1+
"""
2+
3+
Path planning Sample Code with Randomized Rapidly-Exploring Random Trees (RRT)
4+
5+
author: AtsushiSakai(@Atsushi_twi)
6+
7+
"""
8+
9+
import math
10+
import random
11+
12+
import matplotlib.pyplot as plt
13+
14+
show_animation = True
15+
16+
17+
class RRT:
18+
"""
19+
Class for RRT planning
20+
"""
21+
22+
class Node():
23+
"""
24+
RRT Node
25+
"""
26+
27+
def __init__(self, x, y):
28+
self.x = x
29+
self.y = y
30+
self.parent = None
31+
32+
def __init__(self, start, goal, obstacle_list,
33+
rand_area, expand_dis=1.0, goal_sample_rate=5, max_iter=500):
34+
"""
35+
Setting Parameter
36+
37+
start:Start Position [x,y]
38+
goal:Goal Position [x,y]
39+
obstacleList:obstacle Positions [[x,y,size],...]
40+
randArea:Ramdom Samping Area [min,max]
41+
42+
"""
43+
self.start = self.Node(start[0], start[1])
44+
self.end = self.Node(goal[0], goal[1])
45+
self.min_rand = rand_area[0]
46+
self.max_rand = rand_area[1]
47+
self.expand_dis = expand_dis
48+
self.goal_sample_rate = goal_sample_rate
49+
self.max_iter = max_iter
50+
self.obstacleList = obstacle_list
51+
self.node_list = []
52+
53+
def planning(self, animation=True):
54+
"""
55+
rrt path planning
56+
57+
animation: flag for animation on or off
58+
"""
59+
60+
self.node_list = [self.start]
61+
for i in range(self.max_iter):
62+
rnd = self.get_random_point()
63+
nearest_ind = self.get_nearest_list_index(self.node_list, rnd)
64+
nearest_node = self.node_list[nearest_ind]
65+
66+
new_node = self.steer(rnd, nearest_node)
67+
new_node.parent = nearest_node
68+
69+
if not self.check_collision(new_node, self.obstacleList):
70+
continue
71+
72+
self.node_list.append(new_node)
73+
print("nNodelist:", len(self.node_list))
74+
75+
# check goal
76+
if self.calc_dist_to_goal(new_node.x, new_node.y) <= self.expand_dis:
77+
print("Goal!!")
78+
return self.generate_final_course(len(self.node_list) - 1)
79+
80+
if animation and i % 5:
81+
self.draw_graph(rnd)
82+
83+
return None # cannot find path
84+
85+
def steer(self, rnd, nearest_node):
86+
new_node = self.Node(rnd[0], rnd[1])
87+
d, theta = self.calc_distance_and_angle(nearest_node, new_node)
88+
if d > self.expand_dis:
89+
new_node.x = nearest_node.x + self.expand_dis * math.cos(theta)
90+
new_node.y = nearest_node.y + self.expand_dis * math.sin(theta)
91+
92+
return new_node
93+
94+
def generate_final_course(self, goal_ind):
95+
path = [[self.end.x, self.end.y]]
96+
node = self.node_list[goal_ind]
97+
while node.parent is not None:
98+
path.append([node.x, node.y])
99+
node = node.parent
100+
path.append([node.x, node.y])
101+
102+
return path
103+
104+
def calc_dist_to_goal(self, x, y):
105+
dx = x - self.end.x
106+
dy = y - self.end.y
107+
return math.sqrt(dx ** 2 + dy ** 2)
108+
109+
def get_random_point(self):
110+
if random.randint(0, 100) > self.goal_sample_rate:
111+
rnd = [random.uniform(self.min_rand, self.max_rand),
112+
random.uniform(self.min_rand, self.max_rand)]
113+
else: # goal point sampling
114+
rnd = [self.end.x, self.end.y]
115+
return rnd
116+
117+
def draw_graph(self, rnd=None):
118+
plt.clf()
119+
if rnd is not None:
120+
plt.plot(rnd[0], rnd[1], "^k")
121+
for node in self.node_list:
122+
if node.parent:
123+
plt.plot([node.x, node.parent.x],
124+
[node.y, node.parent.y],
125+
"-g")
126+
127+
for (ox, oy, size) in self.obstacleList:
128+
plt.plot(ox, oy, "ok", ms=30 * size)
129+
130+
plt.plot(self.start.x, self.start.y, "xr")
131+
plt.plot(self.end.x, self.end.y, "xr")
132+
plt.axis([-2, 15, -2, 15])
133+
plt.grid(True)
134+
plt.pause(0.01)
135+
136+
@staticmethod
137+
def get_nearest_list_index(node_list, rnd):
138+
dlist = [(node.x - rnd[0]) ** 2 + (node.y - rnd[1])
139+
** 2 for node in node_list]
140+
minind = dlist.index(min(dlist))
141+
142+
return minind
143+
144+
@staticmethod
145+
def check_collision(node, obstacleList):
146+
for (ox, oy, size) in obstacleList:
147+
dx = ox - node.x
148+
dy = oy - node.y
149+
d = dx * dx + dy * dy
150+
if d <= size ** 2:
151+
return False # collision
152+
153+
return True # safe
154+
155+
@staticmethod
156+
def calc_distance_and_angle(from_node, to_node):
157+
dx = to_node.x - from_node.x
158+
dy = to_node.y - from_node.y
159+
d = math.sqrt(dx ** 2 + dy ** 2)
160+
theta = math.atan2(dy, dx)
161+
return d, theta
162+
163+
164+
def main(gx=5.0, gy=10.0):
165+
print("start " + __file__)
166+
167+
# ====Search Path with RRT====
168+
obstacleList = [
169+
(5, 5, 1),
170+
(3, 6, 2),
171+
(3, 8, 2),
172+
(3, 10, 2),
173+
(7, 5, 2),
174+
(9, 5, 2)
175+
] # [x,y,size]
176+
# Set Initial parameters
177+
rrt = RRT(start=[0, 0],
178+
goal=[gx, gy],
179+
rand_area=[-2, 15],
180+
obstacle_list=obstacleList)
181+
path = rrt.planning(animation=show_animation)
182+
183+
if path is None:
184+
print("Cannot find path")
185+
else:
186+
print("found path!!")
187+
188+
# Draw final path
189+
if show_animation:
190+
rrt.draw_graph()
191+
plt.plot([x for (x, y) in path], [y for (x, y) in path], '-r')
192+
plt.grid(True)
193+
plt.pause(0.01) # Need for Mac
194+
plt.show()
195+
196+
197+
if __name__ == '__main__':
198+
main()

0 commit comments

Comments
 (0)