4
4
5
5
author Atsushi Sakai(@Atsushi_twi)
6
6
co-author Videh Patel(@videh25) : Added the missing RS paths
7
+ co-author fishyy119(@fishyy119) : Improved runtime efficiency
7
8
8
9
"""
9
- import sys
10
10
import pathlib
11
+ import sys
12
+
11
13
sys .path .append (str (pathlib .Path (__file__ ).parent .parent .parent ))
12
14
13
15
import math
16
+ from typing import List , Tuple
14
17
15
18
import matplotlib .pyplot as plt
16
19
import numpy as np
20
+ from numpy .typing import NDArray
21
+
17
22
from utils .angle import angle_mod
18
23
19
24
show_animation = True
@@ -342,63 +347,88 @@ def generate_path(q0, q1, max_curvature, step_size):
342
347
return paths
343
348
344
349
345
- def calc_interpolate_dists_list (lengths , step_size ) :
346
- interpolate_dists_list = []
350
+ def calc_interpolate_dists_list (lengths : List [ float ] , step_size : float ) -> List [ NDArray [ np . floating ]] :
351
+ interpolate_dists_list : List [ NDArray [ np . floating ]] = []
347
352
for length in lengths :
348
353
d_dist = step_size if length >= 0.0 else - step_size
349
- interp_dists = np .arange (0.0 , length , d_dist )
350
- interp_dists = np .append (interp_dists , length )
354
+
355
+ interp_core = np .arange (0.0 , length , d_dist , dtype = np .float64 )
356
+ interp_dists = np .empty (len (interp_core ) + 1 , dtype = np .float64 )
357
+ interp_dists [:- 1 ] = interp_core
358
+ interp_dists [- 1 ] = length
359
+
351
360
interpolate_dists_list .append (interp_dists )
352
361
353
362
return interpolate_dists_list
354
363
355
364
356
- def generate_local_course (lengths , modes , max_curvature , step_size ):
365
+ def generate_local_course (
366
+ lengths : List [float ],
367
+ modes : List [str ],
368
+ max_curvature : float ,
369
+ step_size : float ,
370
+ ) -> Tuple [NDArray [np .floating ], NDArray [np .floating ], NDArray [np .floating ], NDArray [np .signedinteger ]]:
357
371
interpolate_dists_list = calc_interpolate_dists_list (lengths , step_size * max_curvature )
372
+ total_len = sum (len (arr ) for arr in interpolate_dists_list )
373
+ xs = np .empty (total_len , dtype = np .float64 )
374
+ ys = np .empty_like (xs )
375
+ yaws = np .empty_like (xs )
376
+ directions = np .empty_like (xs , dtype = np .int32 )
358
377
359
378
origin_x , origin_y , origin_yaw = 0.0 , 0.0 , 0.0
360
-
361
- xs , ys , yaws , directions = [], [], [], []
362
- for ( interp_dists , mode , length ) in zip (interpolate_dists_list , modes ,
363
- lengths ):
364
-
365
- for dist in interp_dists :
366
- x , y , yaw , direction = interpolate ( dist , length , mode ,
367
- max_curvature , origin_x ,
368
- origin_y , origin_yaw )
369
- xs . append ( x )
370
- ys . append ( y )
371
- yaws . append ( yaw )
372
- directions . append ( direction )
373
- origin_x = xs [- 1 ]
374
- origin_y = ys [- 1 ]
375
- origin_yaw = yaws [ - 1 ]
379
+ idx = 0
380
+
381
+ for interp_dists , mode , length in zip (interpolate_dists_list , modes , lengths ):
382
+ n = len ( interp_dists )
383
+ x_arr , y_arr , yaw_arr , dir_arr = interpolate_vectorized (
384
+ interp_dists , length , mode , max_curvature , origin_x , origin_y , origin_yaw
385
+ )
386
+ xs [ idx : idx + n ] = x_arr
387
+ ys [ idx : idx + n ] = y_arr
388
+ yaws [ idx : idx + n ] = yaw_arr
389
+ directions [ idx : idx + n ] = dir_arr
390
+
391
+ origin_x = x_arr [ - 1 ]
392
+ origin_y = y_arr [- 1 ]
393
+ origin_yaw = yaw_arr [- 1 ]
394
+ idx += n
376
395
377
396
return xs , ys , yaws , directions
378
397
379
398
380
- def interpolate (dist , length , mode , max_curvature , origin_x , origin_y ,
381
- origin_yaw ):
399
+ def interpolate_vectorized (
400
+ dists : NDArray [np .floating ],
401
+ length : float ,
402
+ mode : str ,
403
+ max_curvature : float ,
404
+ origin_x : float ,
405
+ origin_y : float ,
406
+ origin_yaw : float ,
407
+ ) -> Tuple [NDArray [np .floating ], NDArray [np .floating ], NDArray [np .floating ], NDArray [np .signedinteger ]]:
382
408
if mode == "S" :
383
- x = origin_x + dist / max_curvature * math .cos (origin_yaw )
384
- y = origin_y + dist / max_curvature * math .sin (origin_yaw )
385
- yaw = origin_yaw
409
+ x = origin_x + dists / max_curvature * math .cos (origin_yaw )
410
+ y = origin_y + dists / max_curvature * math .sin (origin_yaw )
411
+ yaw = np . full_like ( dists , origin_yaw )
386
412
else : # curve
387
- ldx = math .sin (dist ) / max_curvature
388
- ldy = 0.0
389
- yaw = None
413
+ ldx = np .sin (dists ) / max_curvature
414
+ ldy = np . zeros_like ( dists )
415
+ yaw = np . zeros_like ( dists )
390
416
if mode == "L" : # left turn
391
- ldy = (1.0 - math .cos (dist )) / max_curvature
392
- yaw = origin_yaw + dist
393
- elif mode == "R" : # right turn
394
- ldy = (1.0 - math .cos (dist )) / - max_curvature
395
- yaw = origin_yaw - dist
396
- gdx = math .cos (- origin_yaw ) * ldx + math .sin (- origin_yaw ) * ldy
397
- gdy = - math .sin (- origin_yaw ) * ldx + math .cos (- origin_yaw ) * ldy
417
+ ldy = (1.0 - np .cos (dists )) / max_curvature
418
+ yaw = origin_yaw + dists
419
+ else : # elif mode == "R": # right turn
420
+ ldy = (1.0 - np .cos (dists )) / (- max_curvature )
421
+ yaw = origin_yaw - dists
422
+
423
+ cos_oy = math .cos (- origin_yaw )
424
+ sin_oy = math .sin (- origin_yaw )
425
+ gdx = cos_oy * ldx + sin_oy * ldy
426
+ gdy = - sin_oy * ldx + cos_oy * ldy
398
427
x = origin_x + gdx
399
428
y = origin_y + gdy
400
429
401
- return x , y , yaw , 1 if length > 0.0 else - 1
430
+ direction = 1 if length > 0 else - 1
431
+ return x , y , yaw , np .full_like (dists , direction , dtype = np .int32 )
402
432
403
433
404
434
def calc_paths (sx , sy , syaw , gx , gy , gyaw , maxc , step_size ):
@@ -407,19 +437,23 @@ def calc_paths(sx, sy, syaw, gx, gy, gyaw, maxc, step_size):
407
437
408
438
paths = generate_path (q0 , q1 , maxc , step_size )
409
439
for path in paths :
410
- xs , ys , yaws , directions = generate_local_course (path .lengths ,
411
- path .ctypes , maxc ,
412
- step_size )
440
+ xs , ys , yaws , directions = generate_local_course (path .lengths , path .ctypes , maxc , step_size )
413
441
414
442
# convert global coordinate
415
- path .x = [math .cos (- q0 [2 ]) * ix + math .sin (- q0 [2 ]) * iy + q0 [0 ] for
416
- (ix , iy ) in zip (xs , ys )]
417
- path .y = [- math .sin (- q0 [2 ]) * ix + math .cos (- q0 [2 ]) * iy + q0 [1 ] for
418
- (ix , iy ) in zip (xs , ys )]
419
- path .yaw = [pi_2_pi (yaw + q0 [2 ]) for yaw in yaws ]
420
- path .directions = directions
421
- path .lengths = [length / maxc for length in path .lengths ]
422
- path .L = path .L / maxc
443
+ local_pts = np .vstack ([xs , ys , np .ones_like (xs )]) # shape: [3, N]
444
+ cos_y = np .cos (syaw )
445
+ sin_y = np .sin (syaw )
446
+ se2 = np .array ([[cos_y , - sin_y , sx ],[sin_y , cos_y , sy ],[0 , 0 , 1 ]])
447
+ global_pts = se2 @ local_pts # shape: [3, N]
448
+
449
+ path .x = global_pts [0 , :].tolist ()
450
+ path .y = global_pts [1 , :].tolist ()
451
+
452
+ path .yaw = ((yaws + syaw + np .pi ) % (2 * np .pi ) - np .pi ).tolist ()
453
+
454
+ path .directions = directions .tolist ()
455
+ path .lengths = [l / maxc for l in path .lengths ]
456
+ path .L /= maxc
423
457
424
458
return paths
425
459
0 commit comments