@@ -21,7 +21,7 @@ def pi_2_pi(angle):
2121 return (angle + math .pi ) % (2 * math .pi ) - math .pi
2222
2323
24- def LSL (alpha , beta , d ):
24+ def left_straight_left (alpha , beta , d ):
2525 sa = math .sin (alpha )
2626 sb = math .sin (beta )
2727 ca = math .cos (alpha )
@@ -38,12 +38,11 @@ def LSL(alpha, beta, d):
3838 t = mod2pi (- alpha + tmp1 )
3939 p = math .sqrt (p_squared )
4040 q = mod2pi (beta - tmp1 )
41- # print(np.rad2deg(t), p, np.rad2deg(q))
4241
4342 return t , p , q , mode
4443
4544
46- def RSR (alpha , beta , d ):
45+ def right_straight_right (alpha , beta , d ):
4746 sa = math .sin (alpha )
4847 sb = math .sin (beta )
4948 ca = math .cos (alpha )
@@ -63,7 +62,7 @@ def RSR(alpha, beta, d):
6362 return t , p , q , mode
6463
6564
66- def LSR (alpha , beta , d ):
65+ def left_straight_right (alpha , beta , d ):
6766 sa = math .sin (alpha )
6867 sb = math .sin (beta )
6968 ca = math .cos (alpha )
@@ -82,7 +81,7 @@ def LSR(alpha, beta, d):
8281 return t , p , q , mode
8382
8483
85- def RSL (alpha , beta , d ):
84+ def right_straight_left (alpha , beta , d ):
8685 sa = math .sin (alpha )
8786 sb = math .sin (beta )
8887 ca = math .cos (alpha )
@@ -101,7 +100,7 @@ def RSL(alpha, beta, d):
101100 return t , p , q , mode
102101
103102
104- def RLR (alpha , beta , d ):
103+ def right_left_right (alpha , beta , d ):
105104 sa = math .sin (alpha )
106105 sb = math .sin (beta )
107106 ca = math .cos (alpha )
@@ -119,7 +118,7 @@ def RLR(alpha, beta, d):
119118 return t , p , q , mode
120119
121120
122- def LRL (alpha , beta , d ):
121+ def left_right_left (alpha , beta , d ):
123122 sa = math .sin (alpha )
124123 sb = math .sin (beta )
125124 ca = math .cos (alpha )
@@ -137,41 +136,70 @@ def LRL(alpha, beta, d):
137136 return t , p , q , mode
138137
139138
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
144142 D = math .hypot (dx , dy )
145- d = D * c
146- # print(dx, dy, D, d)
143+ d = D * curvature
147144
148145 theta = mod2pi (math .atan2 (dy , dx ))
149146 alpha = mod2pi (- theta )
150- beta = mod2pi (eyaw - theta )
151- # print(theta, alpha, beta, d)
147+ beta = mod2pi (end_yaw - theta )
152148
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 ]
154151
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
157154
158155 for planner in planners :
159156 t , p , q , mode = planner (alpha , beta , d )
160157 if t is None :
161158 continue
162159
163160 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
170198
171- return px , py , pyaw , bmode , bcost
199+ return path_x , path_y , path_yaw , directions
172200
173201
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 ):
175203 """
176204 Dubins path plannner
177205
@@ -200,7 +228,7 @@ def dubins_path_planning(sx, sy, syaw, ex, ey, eyaw, c, D_ANGLE=np.deg2rad(10.0)
200228 leyaw = eyaw - syaw
201229
202230 lpx , lpy , lpyaw , mode , clen = dubins_path_planning_from_origin (
203- lex , ley , leyaw , c , D_ANGLE )
231+ lex , ley , leyaw , c , step_size )
204232
205233 px = [math .cos (- syaw ) * x + math .sin (- syaw )
206234 * y + sx for x , y in zip (lpx , lpy )]
@@ -211,45 +239,60 @@ def dubins_path_planning(sx, sy, syaw, ex, ey, eyaw, c, D_ANGLE=np.deg2rad(10.0)
211239 return px , py , pyaw , mode , clen
212240
213241
214- def generate_course (length , mode , c , D_ANGLE ):
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
215257
216- px = [0.0 ]
217- py = [0.0 ]
218- pyaw = [0.0 ]
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
219263
220- for m , l in zip (mode , length ):
221- pd = 0.0
222- if m == "S" :
223- d = 1.0 * c
224- else : # turning couse
225- d = D_ANGLE
264+ # set origin state
265+ origin_x , origin_y , origin_yaw = path_x [ind ], path_y [ind ], path_yaw [ind ]
226266
227- while pd < abs (l - d ):
228- # print(pd, l)
229- px .append (px [- 1 ] + d / c * math .cos (pyaw [- 1 ]))
230- py .append (py [- 1 ] + d / c * math .sin (pyaw [- 1 ]))
267+ ind -= 1
268+ if i >= 1 and (lengths [i - 1 ] * lengths [i ]) > 0 :
269+ pd = - d - ll
270+ else :
271+ pd = d - ll
231272
232- if m == "L" : # left turn
233- pyaw .append (pyaw [- 1 ] + d )
234- elif m == "S" : # Straight
235- pyaw .append (pyaw [- 1 ])
236- elif m == "R" : # right turn
237- pyaw .append (pyaw [- 1 ] - d )
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 )
238277 pd += d
239278
240- d = l - pd
241- px .append (px [- 1 ] + d / c * math .cos (pyaw [- 1 ]))
242- 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 [], [], [], []
243287
244- if m == "L" : # left turn
245- pyaw .append (pyaw [- 1 ] + d )
246- elif m == "S" : # Straight
247- pyaw .append (pyaw [- 1 ])
248- elif m == "R" : # right turn
249- pyaw .append (pyaw [- 1 ] - d )
250- 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 ()
251294
252- return px , py , pyaw
295+ return path_x , path_y , path_yaw , directions
253296
254297
255298def plot_arrow (x , y , yaw , length = 1.0 , width = 0.5 , fc = "r" , ec = "k" ): # pragma: no cover
@@ -289,54 +332,11 @@ def main():
289332 plot_arrow (start_x , start_y , start_yaw )
290333 plot_arrow (end_x , end_y , end_yaw )
291334
292- # for (ix, iy, iyaw) in zip(px, py, pyaw):
293- # plot_arrow(ix, iy, iyaw, fc="b")
294-
295335 plt .legend ()
296336 plt .grid (True )
297337 plt .axis ("equal" )
298338 plt .show ()
299339
300340
301- def test ():
302-
303- NTEST = 5
304-
305- for i in range (NTEST ):
306- start_x = (np .random .rand () - 0.5 ) * 10.0 # [m]
307- start_y = (np .random .rand () - 0.5 ) * 10.0 # [m]
308- start_yaw = np .deg2rad ((np .random .rand () - 0.5 ) * 180.0 ) # [rad]
309-
310- end_x = (np .random .rand () - 0.5 ) * 10.0 # [m]
311- end_y = (np .random .rand () - 0.5 ) * 10.0 # [m]
312- end_yaw = np .deg2rad ((np .random .rand () - 0.5 ) * 180.0 ) # [rad]
313-
314- curvature = 1.0 / (np .random .rand () * 5.0 )
315-
316- px , py , pyaw , mode , clen = dubins_path_planning (
317- start_x , start_y , start_yaw , end_x , end_y , end_yaw , curvature )
318-
319- if show_animation :
320- plt .cla ()
321- # for stopping simulation with the esc key.
322- plt .gcf ().canvas .mpl_connect ('key_release_event' ,
323- lambda event : [exit (0 ) if event .key == 'escape' else None ])
324- plt .plot (px , py , label = "final course " + str (mode ))
325-
326- # plotting
327- plot_arrow (start_x , start_y , start_yaw )
328- plot_arrow (end_x , end_y , end_yaw )
329-
330- plt .legend ()
331- plt .grid (True )
332- plt .axis ("equal" )
333- plt .xlim (- 10 , 10 )
334- plt .ylim (- 10 , 10 )
335- plt .pause (1.0 )
336-
337- print ("Test done" )
338-
339-
340341if __name__ == '__main__' :
341- test ()
342342 main ()
0 commit comments