Skip to content

Commit 81ddb1f

Browse files
authored
Merge pull request AtsushiSakai#279 from AtsushiSakai/fix_dubins
code clean up reeds shepp path
2 parents dc06c18 + 29c02fa commit 81ddb1f

File tree

2 files changed

+99
-117
lines changed

2 files changed

+99
-117
lines changed

PathPlanning/ReedsSheppPath/reeds_shepp_path_planning.py

Lines changed: 66 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,15 @@ def mod2pi(x):
4949
return v
5050

5151

52-
def SLS(x, y, phi):
52+
def straight_left_straight(x, y, phi):
5353
phi = mod2pi(phi)
54-
if y > 0.0 and phi > 0.0 and phi < math.pi * 0.99:
54+
if y > 0.0 and 0.0 < phi < math.pi * 0.99:
5555
xd = - y / math.tan(phi) + x
5656
t = xd - math.tan(phi / 2.0)
5757
u = phi
5858
v = math.sqrt((x - xd) ** 2 + y ** 2) - math.tan(phi / 2.0)
5959
return True, t, u, v
60-
elif y < 0.0 and phi > 0.0 and phi < math.pi * 0.99:
60+
elif y < 0.0 < phi < math.pi * 0.99:
6161
xd = - y / math.tan(phi) + x
6262
t = xd - math.tan(phi / 2.0)
6363
u = phi
@@ -68,7 +68,6 @@ def SLS(x, y, phi):
6868

6969

7070
def set_path(paths, lengths, ctypes):
71-
7271
path = Path()
7372
path.ctypes = ctypes
7473
path.lengths = lengths
@@ -89,12 +88,12 @@ def set_path(paths, lengths, ctypes):
8988
return paths
9089

9190

92-
def SCS(x, y, phi, paths):
93-
flag, t, u, v = SLS(x, y, phi)
91+
def straight_curve_straight(x, y, phi, paths):
92+
flag, t, u, v = straight_left_straight(x, y, phi)
9493
if flag:
9594
paths = set_path(paths, [t, u, v], ["S", "L", "S"])
9695

97-
flag, t, u, v = SLS(x, -y, -phi)
96+
flag, t, u, v = straight_left_straight(x, -y, -phi)
9897
if flag:
9998
paths = set_path(paths, [t, u, v], ["S", "R", "S"])
10099

@@ -107,7 +106,7 @@ def polar(x, y):
107106
return r, theta
108107

109108

110-
def LSL(x, y, phi):
109+
def left_straight_left(x, y, phi):
111110
u, t = polar(x - math.sin(phi), y - 1.0 + math.cos(phi))
112111
if t >= 0.0:
113112
v = mod2pi(phi - t)
@@ -117,99 +116,97 @@ def LSL(x, y, phi):
117116
return False, 0.0, 0.0, 0.0
118117

119118

120-
def LRL(x, y, phi):
119+
def left_right_left(x, y, phi):
121120
u1, t1 = polar(x - math.sin(phi), y - 1.0 + math.cos(phi))
122121

123122
if u1 <= 4.0:
124123
u = -2.0 * math.asin(0.25 * u1)
125124
t = mod2pi(t1 + 0.5 * u + math.pi)
126125
v = mod2pi(phi - t + u)
127126

128-
if t >= 0.0 and u <= 0.0:
127+
if t >= 0.0 >= u:
129128
return True, t, u, v
130129

131130
return False, 0.0, 0.0, 0.0
132131

133132

134-
def CCC(x, y, phi, paths):
135-
136-
flag, t, u, v = LRL(x, y, phi)
133+
def curve_curve_curve(x, y, phi, paths):
134+
flag, t, u, v = left_right_left(x, y, phi)
137135
if flag:
138136
paths = set_path(paths, [t, u, v], ["L", "R", "L"])
139137

140-
flag, t, u, v = LRL(-x, y, -phi)
138+
flag, t, u, v = left_right_left(-x, y, -phi)
141139
if flag:
142140
paths = set_path(paths, [-t, -u, -v], ["L", "R", "L"])
143141

144-
flag, t, u, v = LRL(x, -y, -phi)
142+
flag, t, u, v = left_right_left(x, -y, -phi)
145143
if flag:
146144
paths = set_path(paths, [t, u, v], ["R", "L", "R"])
147145

148-
flag, t, u, v = LRL(-x, -y, phi)
146+
flag, t, u, v = left_right_left(-x, -y, phi)
149147
if flag:
150148
paths = set_path(paths, [-t, -u, -v], ["R", "L", "R"])
151149

152150
# backwards
153151
xb = x * math.cos(phi) + y * math.sin(phi)
154152
yb = x * math.sin(phi) - y * math.cos(phi)
155-
# println(xb, ",", yb,",",x,",",y)
156153

157-
flag, t, u, v = LRL(xb, yb, phi)
154+
flag, t, u, v = left_right_left(xb, yb, phi)
158155
if flag:
159156
paths = set_path(paths, [v, u, t], ["L", "R", "L"])
160157

161-
flag, t, u, v = LRL(-xb, yb, -phi)
158+
flag, t, u, v = left_right_left(-xb, yb, -phi)
162159
if flag:
163160
paths = set_path(paths, [-v, -u, -t], ["L", "R", "L"])
164161

165-
flag, t, u, v = LRL(xb, -yb, -phi)
162+
flag, t, u, v = left_right_left(xb, -yb, -phi)
166163
if flag:
167164
paths = set_path(paths, [v, u, t], ["R", "L", "R"])
168165

169-
flag, t, u, v = LRL(-xb, -yb, phi)
166+
flag, t, u, v = left_right_left(-xb, -yb, phi)
170167
if flag:
171168
paths = set_path(paths, [-v, -u, -t], ["R", "L", "R"])
172169

173170
return paths
174171

175172

176-
def CSC(x, y, phi, paths):
177-
flag, t, u, v = LSL(x, y, phi)
173+
def curve_straight_curve(x, y, phi, paths):
174+
flag, t, u, v = left_straight_left(x, y, phi)
178175
if flag:
179176
paths = set_path(paths, [t, u, v], ["L", "S", "L"])
180177

181-
flag, t, u, v = LSL(-x, y, -phi)
178+
flag, t, u, v = left_straight_left(-x, y, -phi)
182179
if flag:
183180
paths = set_path(paths, [-t, -u, -v], ["L", "S", "L"])
184181

185-
flag, t, u, v = LSL(x, -y, -phi)
182+
flag, t, u, v = left_straight_left(x, -y, -phi)
186183
if flag:
187184
paths = set_path(paths, [t, u, v], ["R", "S", "R"])
188185

189-
flag, t, u, v = LSL(-x, -y, phi)
186+
flag, t, u, v = left_straight_left(-x, -y, phi)
190187
if flag:
191188
paths = set_path(paths, [-t, -u, -v], ["R", "S", "R"])
192189

193-
flag, t, u, v = LSR(x, y, phi)
190+
flag, t, u, v = left_straight_right(x, y, phi)
194191
if flag:
195192
paths = set_path(paths, [t, u, v], ["L", "S", "R"])
196193

197-
flag, t, u, v = LSR(-x, y, -phi)
194+
flag, t, u, v = left_straight_right(-x, y, -phi)
198195
if flag:
199196
paths = set_path(paths, [-t, -u, -v], ["L", "S", "R"])
200197

201-
flag, t, u, v = LSR(x, -y, -phi)
198+
flag, t, u, v = left_straight_right(x, -y, -phi)
202199
if flag:
203200
paths = set_path(paths, [t, u, v], ["R", "S", "L"])
204201

205-
flag, t, u, v = LSR(-x, -y, phi)
202+
flag, t, u, v = left_straight_right(-x, -y, phi)
206203
if flag:
207204
paths = set_path(paths, [-t, -u, -v], ["R", "S", "L"])
208205

209206
return paths
210207

211208

212-
def LSR(x, y, phi):
209+
def left_straight_right(x, y, phi):
213210
u1, t1 = polar(x + math.sin(phi), y - 1.0 - math.cos(phi))
214211
u1 = u1 ** 2
215212
if u1 >= 4.0:
@@ -224,60 +221,60 @@ def LSR(x, y, phi):
224221
return False, 0.0, 0.0, 0.0
225222

226223

227-
def generate_path(q0, q1, maxc):
224+
def generate_path(q0, q1, max_curvature):
228225
dx = q1[0] - q0[0]
229226
dy = q1[1] - q0[1]
230227
dth = q1[2] - q0[2]
231228
c = math.cos(q0[2])
232229
s = math.sin(q0[2])
233-
x = (c * dx + s * dy) * maxc
234-
y = (-s * dx + c * dy) * maxc
230+
x = (c * dx + s * dy) * max_curvature
231+
y = (-s * dx + c * dy) * max_curvature
235232

236233
paths = []
237-
paths = SCS(x, y, dth, paths)
238-
paths = CSC(x, y, dth, paths)
239-
paths = CCC(x, y, dth, paths)
234+
paths = straight_curve_straight(x, y, dth, paths)
235+
paths = curve_straight_curve(x, y, dth, paths)
236+
paths = curve_curve_curve(x, y, dth, paths)
240237

241238
return paths
242239

243240

244-
def interpolate(ind, l, m, maxc, ox, oy, oyaw, px, py, pyaw, directions):
245-
246-
if m == "S":
247-
px[ind] = ox + l / maxc * math.cos(oyaw)
248-
py[ind] = oy + l / maxc * math.sin(oyaw)
249-
pyaw[ind] = oyaw
241+
def interpolate(ind, length, mode, max_curvature, origin_x, origin_y, origin_yaw, path_x, path_y, path_yaw, directions):
242+
if mode == "S":
243+
path_x[ind] = origin_x + length / max_curvature * math.cos(origin_yaw)
244+
path_y[ind] = origin_y + length / max_curvature * math.sin(origin_yaw)
245+
path_yaw[ind] = origin_yaw
250246
else: # curve
251-
ldx = math.sin(l) / maxc
252-
if m == "L": # left turn
253-
ldy = (1.0 - math.cos(l)) / maxc
254-
elif m == "R": # right turn
255-
ldy = (1.0 - math.cos(l)) / -maxc
256-
gdx = math.cos(-oyaw) * ldx + math.sin(-oyaw) * ldy
257-
gdy = -math.sin(-oyaw) * ldx + math.cos(-oyaw) * ldy
258-
px[ind] = ox + gdx
259-
py[ind] = oy + gdy
260-
261-
if m == "L": # left turn
262-
pyaw[ind] = oyaw + l
263-
elif m == "R": # right turn
264-
pyaw[ind] = oyaw - l
265-
266-
if l > 0.0:
247+
ldx = math.sin(length) / max_curvature
248+
ldy = 0.0
249+
if mode == "L": # left turn
250+
ldy = (1.0 - math.cos(length)) / max_curvature
251+
elif mode == "R": # right turn
252+
ldy = (1.0 - math.cos(length)) / -max_curvature
253+
gdx = math.cos(-origin_yaw) * ldx + math.sin(-origin_yaw) * ldy
254+
gdy = -math.sin(-origin_yaw) * ldx + math.cos(-origin_yaw) * ldy
255+
path_x[ind] = origin_x + gdx
256+
path_y[ind] = origin_y + gdy
257+
258+
if mode == "L": # left turn
259+
path_yaw[ind] = origin_yaw + length
260+
elif mode == "R": # right turn
261+
path_yaw[ind] = origin_yaw - length
262+
263+
if length > 0.0:
267264
directions[ind] = 1
268265
else:
269266
directions[ind] = -1
270267

271-
return px, py, pyaw, directions
268+
return path_x, path_y, path_yaw, directions
272269

273270

274-
def generate_local_course(L, lengths, mode, maxc, step_size):
275-
npoint = math.trunc(L / step_size) + len(lengths) + 4
271+
def generate_local_course(total_length, lengths, mode, max_curvature, step_size):
272+
n_point = math.trunc(total_length / step_size) + len(lengths) + 4
276273

277-
px = [0.0 for i in range(npoint)]
278-
py = [0.0 for i in range(npoint)]
279-
pyaw = [0.0 for i in range(npoint)]
280-
directions = [0.0 for i in range(npoint)]
274+
px = [0.0 for _ in range(n_point)]
275+
py = [0.0 for _ in range(n_point)]
276+
pyaw = [0.0 for _ in range(n_point)]
277+
directions = [0.0 for _ in range(n_point)]
281278
ind = 1
282279

283280
if lengths[0] > 0.0:
@@ -305,14 +302,14 @@ def generate_local_course(L, lengths, mode, maxc, step_size):
305302
while abs(pd) <= abs(l):
306303
ind += 1
307304
px, py, pyaw, directions = interpolate(
308-
ind, pd, m, maxc, ox, oy, oyaw, px, py, pyaw, directions)
305+
ind, pd, m, max_curvature, ox, oy, oyaw, px, py, pyaw, directions)
309306
pd += d
310307

311308
ll = l - pd - d # calc remain length
312309

313310
ind += 1
314311
px, py, pyaw, directions = interpolate(
315-
ind, l, m, maxc, ox, oy, oyaw, px, py, pyaw, directions)
312+
ind, l, m, max_curvature, ox, oy, oyaw, px, py, pyaw, directions)
316313

317314
# remove unused data
318315
while px[-1] == 0.0:
@@ -344,22 +341,17 @@ def calc_paths(sx, sy, syaw, gx, gy, gyaw, maxc, step_size):
344341
* iy + q0[1] for (ix, iy) in zip(x, y)]
345342
path.yaw = [pi_2_pi(iyaw + q0[2]) for iyaw in yaw]
346343
path.directions = directions
347-
path.lengths = [l / maxc for l in path.lengths]
344+
path.lengths = [length / maxc for length in path.lengths]
348345
path.L = path.L / maxc
349346

350-
# print(paths)
351-
352347
return paths
353348

354349

355350
def reeds_shepp_path_planning(sx, sy, syaw,
356351
gx, gy, gyaw, maxc, step_size=0.2):
357-
358352
paths = calc_paths(sx, sy, syaw, gx, gy, gyaw, maxc, step_size)
359353

360354
if not paths:
361-
# print("No path")
362-
# print(sx, sy, syaw, gx, gy, gyaw)
363355
return None, None, None, None, None
364356

365357
minL = float("Inf")
@@ -374,48 +366,6 @@ def reeds_shepp_path_planning(sx, sy, syaw,
374366
return bpath.x, bpath.y, bpath.yaw, bpath.ctypes, bpath.lengths
375367

376368

377-
def test():
378-
379-
NTEST = 5
380-
381-
for i in range(NTEST):
382-
start_x = (np.random.rand() - 0.5) * 10.0 # [m]
383-
start_y = (np.random.rand() - 0.5) * 10.0 # [m]
384-
start_yaw = np.deg2rad((np.random.rand() - 0.5) * 180.0) # [rad]
385-
386-
end_x = (np.random.rand() - 0.5) * 10.0 # [m]
387-
end_y = (np.random.rand() - 0.5) * 10.0 # [m]
388-
end_yaw = np.deg2rad((np.random.rand() - 0.5) * 180.0) # [rad]
389-
390-
curvature = 1.0 / (np.random.rand() * 20.0)
391-
step_size = 0.1
392-
393-
px, py, pyaw, mode, clen = reeds_shepp_path_planning(
394-
start_x, start_y, start_yaw, end_x, end_y, end_yaw, curvature, step_size)
395-
396-
if show_animation: # pragma: no cover
397-
plt.cla()
398-
# for stopping simulation with the esc key.
399-
plt.gcf().canvas.mpl_connect('key_release_event',
400-
lambda event: [exit(0) if event.key == 'escape' else None])
401-
plt.plot(px, py, label="final course " + str(mode))
402-
403-
# plotting
404-
plot_arrow(start_x, start_y, start_yaw)
405-
plot_arrow(end_x, end_y, end_yaw)
406-
407-
plt.legend()
408-
plt.grid(True)
409-
plt.axis("equal")
410-
plt.xlim(-10, 10)
411-
plt.ylim(-10, 10)
412-
plt.pause(1.0)
413-
414-
# plt.show()
415-
416-
print("Test done")
417-
418-
419369
def main():
420370
print("Reeds Shepp path planner sample start!!")
421371

@@ -451,5 +401,4 @@ def main():
451401

452402

453403
if __name__ == '__main__':
454-
test()
455404
main()

0 commit comments

Comments
 (0)