Skip to content

Commit 8c7ab87

Browse files
committed
add clrrt sample
1 parent fe99a52 commit 8c7ab87

File tree

5 files changed

+965
-0
lines changed

5 files changed

+965
-0
lines changed
Lines changed: 393 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,393 @@
1+
#!/usr/bin/python
2+
# -*- coding: utf-8 -*-
3+
"""
4+
@brief: Path Planning Sample Code with RRT for car like robot.
5+
6+
@author: AtsushiSakai(@Atsushi_twi)
7+
8+
@license: MIT
9+
10+
"""
11+
12+
import random
13+
import math
14+
import copy
15+
import numpy as np
16+
import dubins_path_planning
17+
import pure_pursuit
18+
import unicycle_model
19+
20+
21+
class RRT():
22+
u"""
23+
Class for RRT Planning
24+
"""
25+
26+
def __init__(self, start, goal, obstacleList, randArea,
27+
goalSampleRate=10, maxIter=100):
28+
u"""
29+
Setting Parameter
30+
31+
start:Start Position [x,y]
32+
goal:Goal Position [x,y]
33+
obstacleList:obstacle Positions [[x,y,size],...]
34+
randArea:Ramdom Samping Area [min,max]
35+
36+
"""
37+
self.start = Node(start[0], start[1], start[2])
38+
self.end = Node(goal[0], goal[1], goal[2])
39+
self.minrand = randArea[0]
40+
self.maxrand = randArea[1]
41+
self.goalSampleRate = goalSampleRate
42+
self.obstacleList = obstacleList
43+
self.maxIter = maxIter
44+
45+
def Planning(self, animation=True):
46+
u"""
47+
Pathplanning
48+
49+
animation: flag for animation on or off
50+
"""
51+
52+
self.nodeList = [self.start]
53+
for i in range(self.maxIter):
54+
rnd = self.get_random_point()
55+
nind = self.GetNearestListIndex(self.nodeList, rnd)
56+
57+
newNode = self.steer(rnd, nind)
58+
# print(newNode.cost)
59+
60+
if self.CollisionCheck(newNode, obstacleList):
61+
nearinds = self.find_near_nodes(newNode)
62+
newNode = self.choose_parent(newNode, nearinds)
63+
self.nodeList.append(newNode)
64+
self.rewire(newNode, nearinds)
65+
66+
if animation and i % 5 == 0:
67+
self.DrawGraph(rnd=rnd)
68+
matplotrecorder.save_frame() # save each frame
69+
70+
# generate coruse
71+
path_indexs = self.get_best_last_indexs()
72+
73+
# pure pursuit tracking
74+
for ind in path_indexs:
75+
path = self.gen_final_course(ind)
76+
77+
flag, x, y, yaw, v, t = self.check_tracking_path_is_feasible(path)
78+
79+
if flag:
80+
print("feasible path is found")
81+
break
82+
83+
return x, y, yaw, v, t
84+
85+
def check_tracking_path_is_feasible(self, path):
86+
print("check_tracking_path_is_feasible")
87+
88+
init_speed = 0.0
89+
target_speed = 10.0 / 3.6
90+
91+
path = np.matrix(path[::-1])
92+
93+
state = unicycle_model.State(
94+
x=self.start.x, y=self.start.y, yaw=self.start.yaw, v=init_speed)
95+
96+
target_ind = pure_pursuit.calc_nearest_index(
97+
state, path[:, 0], path[:, 1])
98+
99+
lastIndex = len(path[:, 0]) - 2
100+
101+
x = [state.x]
102+
y = [state.y]
103+
yaw = [state.yaw]
104+
v = [state.v]
105+
t = [0.0]
106+
a = [0.0]
107+
d = [0.0]
108+
time = 0.0
109+
110+
while lastIndex > target_ind:
111+
print(lastIndex, target_ind)
112+
ai = pure_pursuit.PIDControl(target_speed, state.v)
113+
di, target_ind = pure_pursuit.pure_pursuit_control(
114+
state, path[:, 0], path[:, 1], target_ind)
115+
state = unicycle_model.update(state, ai, di)
116+
117+
time = time + unicycle_model.dt
118+
119+
x.append(state.x)
120+
y.append(state.y)
121+
yaw.append(state.yaw)
122+
v.append(state.v)
123+
t.append(time)
124+
a.append(ai)
125+
d.append(di)
126+
127+
if self.CollisionCheckWithXY(path[:, 0], path[:, 1], self.obstacleList):
128+
# print("OK")
129+
return True, x, y, yaw, v, t, a, d
130+
else:
131+
# print("NG")
132+
return False, x, y, yaw, v, t, a, d
133+
134+
# plt.plot(x, y, '-r')
135+
# plt.plot(path[:, 0], path[:, 1], '-g')
136+
# plt.show()
137+
138+
# return True
139+
140+
def choose_parent(self, newNode, nearinds):
141+
if len(nearinds) == 0:
142+
return newNode
143+
144+
dlist = []
145+
for i in nearinds:
146+
tNode = self.steer(newNode, i)
147+
if self.CollisionCheck(tNode, obstacleList):
148+
dlist.append(tNode.cost)
149+
else:
150+
dlist.append(float("inf"))
151+
152+
mincost = min(dlist)
153+
minind = nearinds[dlist.index(mincost)]
154+
155+
if mincost == float("inf"):
156+
print("mincost is inf")
157+
return newNode
158+
159+
newNode = self.steer(newNode, minind)
160+
161+
return newNode
162+
163+
def pi_2_pi(self, angle):
164+
while(angle >= math.pi):
165+
angle = angle - 2.0 * math.pi
166+
167+
while(angle <= -math.pi):
168+
angle = angle + 2.0 * math.pi
169+
170+
return angle
171+
172+
def steer(self, rnd, nind):
173+
# print(rnd)
174+
curvature = 1.0
175+
176+
nearestNode = self.nodeList[nind]
177+
178+
px, py, pyaw, mode, clen = dubins_path_planning.dubins_path_planning(
179+
nearestNode.x, nearestNode.y, nearestNode.yaw, rnd.x, rnd.y, rnd.yaw, curvature)
180+
181+
newNode = copy.deepcopy(nearestNode)
182+
newNode.x = px[-1]
183+
newNode.y = py[-1]
184+
newNode.yaw = pyaw[-1]
185+
186+
newNode.path_x = px
187+
newNode.path_y = py
188+
newNode.path_yaw = pyaw
189+
newNode.cost += clen
190+
newNode.parent = nind
191+
192+
return newNode
193+
194+
def get_random_point(self):
195+
196+
if random.randint(0, 100) > self.goalSampleRate:
197+
rnd = [random.uniform(self.minrand, self.maxrand),
198+
random.uniform(self.minrand, self.maxrand),
199+
random.uniform(-math.pi, math.pi)
200+
]
201+
else: # goal point sampling
202+
rnd = [self.end.x, self.end.y, self.end.yaw]
203+
204+
node = Node(rnd[0], rnd[1], rnd[2])
205+
206+
return node
207+
208+
def get_best_last_indexs(self):
209+
# print("get_best_last_index")
210+
211+
YAWTH = math.radians(1.0)
212+
XYTH = 0.5
213+
214+
goalinds = []
215+
for (i, node) in enumerate(self.nodeList):
216+
if self.calc_dist_to_goal(node.x, node.y) <= XYTH:
217+
goalinds.append(i)
218+
219+
# angle check
220+
fgoalinds = []
221+
for i in goalinds:
222+
if abs(self.nodeList[i].yaw - self.end.yaw) <= YAWTH:
223+
fgoalinds.append(i)
224+
225+
return fgoalinds
226+
227+
# mincost = min([self.nodeList[i].cost for i in fgoalinds])
228+
# for i in fgoalinds:
229+
# if self.nodeList[i].cost == mincost:
230+
# return i
231+
232+
# return None
233+
234+
def gen_final_course(self, goalind):
235+
path = [[self.end.x, self.end.y]]
236+
while self.nodeList[goalind].parent is not None:
237+
node = self.nodeList[goalind]
238+
for (ix, iy) in zip(reversed(node.path_x), reversed(node.path_y)):
239+
path.append([ix, iy])
240+
# path.append([node.x, node.y])
241+
goalind = node.parent
242+
path.append([self.start.x, self.start.y])
243+
return path
244+
245+
def calc_dist_to_goal(self, x, y):
246+
return np.linalg.norm([x - self.end.x, y - self.end.y])
247+
248+
def find_near_nodes(self, newNode):
249+
nnode = len(self.nodeList)
250+
r = 50.0 * math.sqrt((math.log(nnode) / nnode))
251+
# r = self.expandDis * 5.0
252+
dlist = [(node.x - newNode.x) ** 2 +
253+
(node.y - newNode.y) ** 2 +
254+
(node.yaw - newNode.yaw) ** 2
255+
for node in self.nodeList]
256+
nearinds = [dlist.index(i) for i in dlist if i <= r ** 2]
257+
return nearinds
258+
259+
def rewire(self, newNode, nearinds):
260+
261+
nnode = len(self.nodeList)
262+
263+
for i in nearinds:
264+
nearNode = self.nodeList[i]
265+
tNode = self.steer(nearNode, nnode - 1)
266+
267+
obstacleOK = self.CollisionCheck(tNode, obstacleList)
268+
imporveCost = nearNode.cost > tNode.cost
269+
270+
if obstacleOK and imporveCost:
271+
# print("rewire")
272+
self.nodeList[i] = tNode
273+
274+
def DrawGraph(self, rnd=None):
275+
u"""
276+
Draw Graph
277+
"""
278+
import matplotlib.pyplot as plt
279+
# plt.clf()
280+
if rnd is not None:
281+
plt.plot(rnd.x, rnd.y, "^k")
282+
for node in self.nodeList:
283+
if node.parent is not None:
284+
plt.plot(node.path_x, node.path_y, "-g")
285+
# plt.plot([node.x, self.nodeList[node.parent].x], [
286+
# node.y, self.nodeList[node.parent].y], "-g")
287+
288+
for (ox, oy, size) in obstacleList:
289+
plt.plot(ox, oy, "ok", ms=30 * size)
290+
291+
dubins_path_planning.plot_arrow(
292+
self.start.x, self.start.y, self.start.yaw)
293+
dubins_path_planning.plot_arrow(
294+
self.end.x, self.end.y, self.end.yaw)
295+
296+
plt.axis([-2, 15, -2, 15])
297+
plt.grid(True)
298+
plt.pause(0.01)
299+
300+
# plt.show()
301+
# input()
302+
303+
def GetNearestListIndex(self, nodeList, rnd):
304+
dlist = [(node.x - rnd.x) ** 2 +
305+
(node.y - rnd.y) ** 2 +
306+
(node.yaw - rnd.yaw) ** 2 for node in nodeList]
307+
minind = dlist.index(min(dlist))
308+
309+
return minind
310+
311+
def CollisionCheck(self, node, obstacleList):
312+
313+
for (ox, oy, size) in obstacleList:
314+
for (ix, iy) in zip(node.path_x, node.path_y):
315+
dx = ox - ix
316+
dy = oy - iy
317+
d = dx * dx + dy * dy
318+
if d <= size ** 2:
319+
return False # collision
320+
321+
return True # safe
322+
323+
def CollisionCheckWithXY(self, x, y, obstacleList):
324+
325+
for (ox, oy, size) in obstacleList:
326+
for (ix, iy) in zip(x, y):
327+
dx = ox - ix
328+
dy = oy - iy
329+
d = dx * dx + dy * dy
330+
if d <= size ** 2:
331+
return False # collision
332+
333+
return True # safe
334+
335+
336+
class Node():
337+
u"""
338+
RRT Node
339+
"""
340+
341+
def __init__(self, x, y, yaw):
342+
self.x = x
343+
self.y = y
344+
self.yaw = yaw
345+
self.path_x = []
346+
self.path_y = []
347+
self.path_yaw = []
348+
self.cost = 0.0
349+
self.parent = None
350+
351+
352+
if __name__ == '__main__':
353+
print("Start rrt start planning")
354+
import matplotlib.pyplot as plt
355+
import matplotrecorder
356+
matplotrecorder.donothing = True
357+
358+
# ====Search Path with RRT====
359+
obstacleList = [
360+
(5, 5, 1),
361+
(3, 6, 2),
362+
(3, 8, 2),
363+
(3, 10, 2),
364+
(7, 5, 2),
365+
(9, 5, 2)
366+
] # [x,y,size(radius)]
367+
368+
# Set Initial parameters
369+
start = [0.0, 0.0, math.radians(0.0)]
370+
goal = [10.0, 10.0, math.radians(0.0)]
371+
372+
rrt = RRT(start, goal, randArea=[-2.0, 15.0], obstacleList=obstacleList)
373+
x, y, yaw, v, t = rrt.Planning(animation=False)
374+
375+
flg, ax = plt.subplots(1)
376+
# Draw final path
377+
rrt.DrawGraph()
378+
plt.plot(x, y, '-r')
379+
plt.grid(True)
380+
plt.pause(0.001)
381+
382+
for i in range(10):
383+
matplotrecorder.save_frame() # save each frame
384+
385+
flg, ax = plt.subplots(1)
386+
plt.plot(t, yaw, '-r')
387+
388+
flg, ax = plt.subplots(1)
389+
plt.plot(t, v, '-r')
390+
391+
plt.show()
392+
393+
matplotrecorder.save_movie("animation.gif", 0.1)

0 commit comments

Comments
 (0)