@@ -21,7 +21,7 @@ def pi_2_pi(angle):
21
21
return (angle + math .pi ) % (2 * math .pi ) - math .pi
22
22
23
23
24
- def LSL (alpha , beta , d ):
24
+ def left_straight_left (alpha , beta , d ):
25
25
sa = math .sin (alpha )
26
26
sb = math .sin (beta )
27
27
ca = math .cos (alpha )
@@ -38,12 +38,11 @@ def LSL(alpha, beta, d):
38
38
t = mod2pi (- alpha + tmp1 )
39
39
p = math .sqrt (p_squared )
40
40
q = mod2pi (beta - tmp1 )
41
- # print(np.rad2deg(t), p, np.rad2deg(q))
42
41
43
42
return t , p , q , mode
44
43
45
44
46
- def RSR (alpha , beta , d ):
45
+ def right_straight_right (alpha , beta , d ):
47
46
sa = math .sin (alpha )
48
47
sb = math .sin (beta )
49
48
ca = math .cos (alpha )
@@ -63,7 +62,7 @@ def RSR(alpha, beta, d):
63
62
return t , p , q , mode
64
63
65
64
66
- def LSR (alpha , beta , d ):
65
+ def left_straight_right (alpha , beta , d ):
67
66
sa = math .sin (alpha )
68
67
sb = math .sin (beta )
69
68
ca = math .cos (alpha )
@@ -82,7 +81,7 @@ def LSR(alpha, beta, d):
82
81
return t , p , q , mode
83
82
84
83
85
- def RSL (alpha , beta , d ):
84
+ def right_straight_left (alpha , beta , d ):
86
85
sa = math .sin (alpha )
87
86
sb = math .sin (beta )
88
87
ca = math .cos (alpha )
@@ -101,7 +100,7 @@ def RSL(alpha, beta, d):
101
100
return t , p , q , mode
102
101
103
102
104
- def RLR (alpha , beta , d ):
103
+ def right_left_right (alpha , beta , d ):
105
104
sa = math .sin (alpha )
106
105
sb = math .sin (beta )
107
106
ca = math .cos (alpha )
@@ -119,7 +118,7 @@ def RLR(alpha, beta, d):
119
118
return t , p , q , mode
120
119
121
120
122
- def LRL (alpha , beta , d ):
121
+ def left_right_left (alpha , beta , d ):
123
122
sa = math .sin (alpha )
124
123
sb = math .sin (beta )
125
124
ca = math .cos (alpha )
@@ -137,41 +136,70 @@ def LRL(alpha, beta, d):
137
136
return t , p , q , mode
138
137
139
138
140
- def dubins_path_planning_from_origin (ex , ey , eyaw , c , D_ANGLE ):
141
- # normalize
142
- dx = ex
143
- dy = ey
139
+ def dubins_path_planning_from_origin (end_x , end_y , end_yaw , curvature , step_size ):
140
+ dx = end_x
141
+ dy = end_y
144
142
D = math .hypot (dx , dy )
145
- d = D * c
146
- # print(dx, dy, D, d)
143
+ d = D * curvature
147
144
148
145
theta = mod2pi (math .atan2 (dy , dx ))
149
146
alpha = mod2pi (- theta )
150
- beta = mod2pi (eyaw - theta )
151
- # print(theta, alpha, beta, d)
147
+ beta = mod2pi (end_yaw - theta )
152
148
153
- planners = [LSL , RSR , LSR , RSL , RLR , LRL ]
149
+ planners = [left_straight_left , right_straight_right , left_straight_right , right_straight_left , right_left_right ,
150
+ left_right_left ]
154
151
155
- bcost = float ("inf" )
156
- bt , bp , bq , bmode = None , None , None , None
152
+ best_cost = float ("inf" )
153
+ bt , bp , bq , best_mode = None , None , None , None
157
154
158
155
for planner in planners :
159
156
t , p , q , mode = planner (alpha , beta , d )
160
157
if t is None :
161
158
continue
162
159
163
160
cost = (abs (t ) + abs (p ) + abs (q ))
164
- if bcost > cost :
165
- bt , bp , bq , bmode = t , p , q , mode
166
- bcost = cost
167
-
168
- # print(bmode)
169
- px , py , pyaw = generate_course ([bt , bp , bq ], bmode , c , D_ANGLE )
161
+ if best_cost > cost :
162
+ bt , bp , bq , best_mode = t , p , q , mode
163
+ best_cost = cost
164
+ lengths = [bt , bp , bq ]
165
+
166
+ px , py , pyaw , directions = generate_local_course (
167
+ sum (lengths ), lengths , best_mode , curvature , step_size )
168
+
169
+ return px , py , pyaw , best_mode , best_cost
170
+
171
+
172
+ def interpolate (ind , length , mode , max_curvature , origin_x , origin_y , origin_yaw , path_x , path_y , path_yaw , directions ):
173
+ if mode == "S" :
174
+ path_x [ind ] = origin_x + length / max_curvature * math .cos (origin_yaw )
175
+ path_y [ind ] = origin_y + length / max_curvature * math .sin (origin_yaw )
176
+ path_yaw [ind ] = origin_yaw
177
+ else : # curve
178
+ ldx = math .sin (length ) / max_curvature
179
+ ldy = 0.0
180
+ if mode == "L" : # left turn
181
+ ldy = (1.0 - math .cos (length )) / max_curvature
182
+ elif mode == "R" : # right turn
183
+ ldy = (1.0 - math .cos (length )) / - max_curvature
184
+ gdx = math .cos (- origin_yaw ) * ldx + math .sin (- origin_yaw ) * ldy
185
+ gdy = - math .sin (- origin_yaw ) * ldx + math .cos (- origin_yaw ) * ldy
186
+ path_x [ind ] = origin_x + gdx
187
+ path_y [ind ] = origin_y + gdy
188
+
189
+ if mode == "L" : # left turn
190
+ path_yaw [ind ] = origin_yaw + length
191
+ elif mode == "R" : # right turn
192
+ path_yaw [ind ] = origin_yaw - length
193
+
194
+ if length > 0.0 :
195
+ directions [ind ] = 1
196
+ else :
197
+ directions [ind ] = - 1
170
198
171
- return px , py , pyaw , bmode , bcost
199
+ return path_x , path_y , path_yaw , directions
172
200
173
201
174
- def dubins_path_planning (sx , sy , syaw , ex , ey , eyaw , c , D_ANGLE = np . deg2rad ( 10.0 ) ):
202
+ def dubins_path_planning (sx , sy , syaw , ex , ey , eyaw , c , step_size = 0.1 ):
175
203
"""
176
204
Dubins path plannner
177
205
@@ -200,7 +228,7 @@ def dubins_path_planning(sx, sy, syaw, ex, ey, eyaw, c, D_ANGLE=np.deg2rad(10.0)
200
228
leyaw = eyaw - syaw
201
229
202
230
lpx , lpy , lpyaw , mode , clen = dubins_path_planning_from_origin (
203
- lex , ley , leyaw , c , D_ANGLE )
231
+ lex , ley , leyaw , c , step_size )
204
232
205
233
px = [math .cos (- syaw ) * x + math .sin (- syaw )
206
234
* y + sx for x , y in zip (lpx , lpy )]
@@ -211,44 +239,60 @@ def dubins_path_planning(sx, sy, syaw, ex, ey, eyaw, c, D_ANGLE=np.deg2rad(10.0)
211
239
return px , py , pyaw , mode , clen
212
240
213
241
214
- def generate_course (length , mode , c , D_ANGLE ):
215
- px = [0.0 ]
216
- py = [0.0 ]
217
- pyaw = [0.0 ]
218
-
219
- for m , l in zip (mode , length ):
220
- pd = 0.0
221
- if m == "S" :
222
- d = 1.0 * c
223
- else : # turning couse
224
- d = D_ANGLE
225
-
226
- while pd < abs (l - d ):
227
- # print(pd, l)
228
- px .append (px [- 1 ] + d / c * math .cos (pyaw [- 1 ]))
229
- py .append (py [- 1 ] + d / c * math .sin (pyaw [- 1 ]))
230
-
231
- if m == "L" : # left turn
232
- pyaw .append (pyaw [- 1 ] + d )
233
- elif m == "S" : # Straight
234
- pyaw .append (pyaw [- 1 ])
235
- elif m == "R" : # right turn
236
- pyaw .append (pyaw [- 1 ] - d )
242
+ def generate_local_course (total_length , lengths , mode , max_curvature , step_size ):
243
+ n_point = math .trunc (total_length / step_size ) + len (lengths ) + 4
244
+
245
+ path_x = [0.0 for _ in range (n_point )]
246
+ path_y = [0.0 for _ in range (n_point )]
247
+ path_yaw = [0.0 for _ in range (n_point )]
248
+ directions = [0.0 for _ in range (n_point )]
249
+ ind = 1
250
+
251
+ if lengths [0 ] > 0.0 :
252
+ directions [0 ] = 1
253
+ else :
254
+ directions [0 ] = - 1
255
+
256
+ ll = 0.0
257
+
258
+ for (m , l , i ) in zip (mode , lengths , range (len (mode ))):
259
+ if l > 0.0 :
260
+ d = step_size
261
+ else :
262
+ d = - step_size
263
+
264
+ # set origin state
265
+ origin_x , origin_y , origin_yaw = path_x [ind ], path_y [ind ], path_yaw [ind ]
266
+
267
+ ind -= 1
268
+ if i >= 1 and (lengths [i - 1 ] * lengths [i ]) > 0 :
269
+ pd = - d - ll
270
+ else :
271
+ pd = d - ll
272
+
273
+ while abs (pd ) <= abs (l ):
274
+ ind += 1
275
+ path_x , path_y , path_yaw , directions = interpolate (
276
+ ind , pd , m , max_curvature , origin_x , origin_y , origin_yaw , path_x , path_y , path_yaw , directions )
237
277
pd += d
238
278
239
- d = l - pd
240
- px .append (px [- 1 ] + d / c * math .cos (pyaw [- 1 ]))
241
- py .append (py [- 1 ] + d / c * math .sin (pyaw [- 1 ]))
279
+ ll = l - pd - d # calc remain length
280
+
281
+ ind += 1
282
+ path_x , path_y , path_yaw , directions = interpolate (
283
+ ind , l , m , max_curvature , origin_x , origin_y , origin_yaw , path_x , path_y , path_yaw , directions )
284
+
285
+ if len (path_x ) <= 1 :
286
+ return [], [], [], []
242
287
243
- if m == "L" : # left turn
244
- pyaw .append (pyaw [- 1 ] + d )
245
- elif m == "S" : # Straight
246
- pyaw .append (pyaw [- 1 ])
247
- elif m == "R" : # right turn
248
- pyaw .append (pyaw [- 1 ] - d )
249
- pd += d
288
+ # remove unused data
289
+ while len (path_x ) >= 1 and path_x [- 1 ] == 0.0 :
290
+ path_x .pop ()
291
+ path_y .pop ()
292
+ path_yaw .pop ()
293
+ directions .pop ()
250
294
251
- return px , py , pyaw
295
+ return path_x , path_y , path_yaw , directions
252
296
253
297
254
298
def plot_arrow (x , y , yaw , length = 1.0 , width = 0.5 , fc = "r" , ec = "k" ): # pragma: no cover
@@ -288,53 +332,11 @@ def main():
288
332
plot_arrow (start_x , start_y , start_yaw )
289
333
plot_arrow (end_x , end_y , end_yaw )
290
334
291
- # for (ix, iy, iyaw) in zip(px, py, pyaw):
292
- # plot_arrow(ix, iy, iyaw, fc="b")
293
-
294
335
plt .legend ()
295
336
plt .grid (True )
296
337
plt .axis ("equal" )
297
338
plt .show ()
298
339
299
340
300
- def test ():
301
- NTEST = 5
302
-
303
- for i in range (NTEST ):
304
- start_x = (np .random .rand () - 0.5 ) * 10.0 # [m]
305
- start_y = (np .random .rand () - 0.5 ) * 10.0 # [m]
306
- start_yaw = np .deg2rad ((np .random .rand () - 0.5 ) * 180.0 ) # [rad]
307
-
308
- end_x = (np .random .rand () - 0.5 ) * 10.0 # [m]
309
- end_y = (np .random .rand () - 0.5 ) * 10.0 # [m]
310
- end_yaw = np .deg2rad ((np .random .rand () - 0.5 ) * 180.0 ) # [rad]
311
-
312
- curvature = 1.0 / (np .random .rand () * 5.0 )
313
-
314
- px , py , pyaw , mode , clen = dubins_path_planning (
315
- start_x , start_y , start_yaw , end_x , end_y , end_yaw , curvature )
316
-
317
- if show_animation :
318
- plt .cla ()
319
- # for stopping simulation with the esc key.
320
- plt .gcf ().canvas .mpl_connect ('key_release_event' ,
321
- lambda event : [exit (0 ) if event .key == 'escape' else None ])
322
- plt .plot (px , py , label = "final course " + str (mode ))
323
-
324
- # plotting
325
- plot_arrow (start_x , start_y , start_yaw )
326
- plot_arrow (end_x , end_y , end_yaw )
327
-
328
- plt .legend ()
329
- plt .grid (True )
330
- plt .axis ("equal" )
331
- plt .xlim (- 10 , 10 )
332
- plt .ylim (- 10 , 10 )
333
- plt .pause (1.0 )
334
-
335
- print ("Test done" )
336
-
337
-
338
341
if __name__ == '__main__' :
339
- test ()
340
342
main ()
0 commit comments