14
14
15
15
from collections import defaultdict
16
16
from enum import Enum
17
+ from typing import Any , Dict , List , Tuple , TypedDict
17
18
18
19
from helper import angle_difference , interpolate_yaws
19
20
import numpy as np
20
21
from rtree import index
21
- from trajectory import Path , Trajectory , TrajectoryParameters
22
+
23
+ from trajectory import AnyFloat , FloatNDArray , Path , Trajectory , TrajectoryParameters
24
+
22
25
from trajectory_generator import TrajectoryGenerator
23
26
24
27
28
+ class ConfigDict (TypedDict ):
29
+ grid_resolution : float
30
+ turning_radius : float
31
+ stopping_threshold : int
32
+ num_of_headings : int
33
+ motion_model : str
34
+
35
+
25
36
class LatticeGenerator :
26
37
"""
27
38
Handles all the logic for computing the minimal control set.
@@ -46,7 +57,7 @@ class Flip(Enum):
46
57
Y = 2
47
58
BOTH = 3
48
59
49
- def __init__ (self , config : dict ):
60
+ def __init__ (self , config : ConfigDict ):
50
61
"""Init the lattice generator from the user supplied config."""
51
62
self .trajectory_generator = TrajectoryGenerator (config )
52
63
self .grid_resolution = config ['grid_resolution' ]
@@ -60,7 +71,7 @@ def __init__(self, config: dict):
60
71
self .DISTANCE_THRESHOLD = 0.5 * self .grid_resolution
61
72
self .ROTATION_THRESHOLD = 0.5 * (2 * np .pi / self .num_of_headings )
62
73
63
- def _get_wave_front_points (self , pos : int ) -> np . array :
74
+ def _get_wave_front_points (self , pos : int ) -> FloatNDArray :
64
75
"""
65
76
Calculate the end points that lie on the wave front.
66
77
@@ -97,7 +108,7 @@ def _get_wave_front_points(self, pos: int) -> np.array:
97
108
98
109
return np .array (positions )
99
110
100
- def _get_heading_discretization (self , number_of_headings : int ) -> list :
111
+ def _get_heading_discretization (self , number_of_headings : int ) -> List [ int ] :
101
112
"""
102
113
Calculate the heading discretization based on the number of headings.
103
114
@@ -131,7 +142,8 @@ def _get_heading_discretization(self, number_of_headings: int) -> list:
131
142
132
143
return sorted ([np .arctan2 (j , i ) for i , j in zip (outer_edge_x , outer_edge_y )])
133
144
134
- def _point_to_line_distance (self , p1 : np .array , p2 : np .array , q : np .array ) -> float :
145
+ def _point_to_line_distance (self , p1 : FloatNDArray , p2 : FloatNDArray ,
146
+ q : FloatNDArray ) -> AnyFloat :
135
147
"""
136
148
Return the shortest distance from a point to a line segment.
137
149
@@ -241,7 +253,7 @@ def _compute_min_trajectory_length(self) -> float:
241
253
242
254
return self .turning_radius * min (heading_diff )
243
255
244
- def _generate_minimal_spanning_set (self ) -> dict :
256
+ def _generate_minimal_spanning_set (self ) -> Dict [ float , List [ Trajectory ]] :
245
257
"""
246
258
Generate the minimal spanning set.
247
259
@@ -255,7 +267,7 @@ def _generate_minimal_spanning_set(self) -> dict:
255
267
a list of trajectories that begin at that angle
256
268
257
269
"""
258
- quadrant1_end_poses = defaultdict (list )
270
+ quadrant1_end_poses : Dict [ int , List [ Tuple [ Any , int ]]] = defaultdict (list )
259
271
260
272
# Since we only compute for quadrant 1 we only need headings between
261
273
# 0 and 90 degrees
@@ -338,7 +350,7 @@ def _generate_minimal_spanning_set(self) -> dict:
338
350
# we can leverage symmetry to create the complete minimal set
339
351
return self ._create_complete_minimal_spanning_set (quadrant1_end_poses )
340
352
341
- def _flip_angle (self , angle : float , flip_type : Flip ) -> float :
353
+ def _flip_angle (self , angle : int , flip_type : Flip ) -> float :
342
354
"""
343
355
Return the the appropriate flip of the angle in self.headings.
344
356
@@ -370,8 +382,8 @@ def _flip_angle(self, angle: float, flip_type: Flip) -> float:
370
382
return self .headings [int (heading_idx )]
371
383
372
384
def _create_complete_minimal_spanning_set (
373
- self , single_quadrant_minimal_set : dict
374
- ) -> dict :
385
+ self , single_quadrant_minimal_set : Dict [ int , List [ Tuple [ Any , int ]]]
386
+ ) -> Dict [ float , List [ Trajectory ]] :
375
387
"""
376
388
Create the full minimal spanning set from a single quadrant set.
377
389
@@ -390,7 +402,7 @@ def _create_complete_minimal_spanning_set(
390
402
in all quadrants
391
403
392
404
"""
393
- all_trajectories = defaultdict (list )
405
+ all_trajectories : Dict [ float , List [ Trajectory ]] = defaultdict (list )
394
406
395
407
for start_angle in single_quadrant_minimal_set .keys ():
396
408
@@ -425,6 +437,9 @@ def _create_complete_minimal_spanning_set(
425
437
)
426
438
)
427
439
440
+ if unflipped_trajectory is None or flipped_x_trajectory is None :
441
+ raise ValueError ('No trajectory was found' )
442
+
428
443
all_trajectories [
429
444
unflipped_trajectory .parameters .start_angle
430
445
].append (unflipped_trajectory )
@@ -459,6 +474,9 @@ def _create_complete_minimal_spanning_set(
459
474
)
460
475
)
461
476
477
+ if unflipped_trajectory is None or flipped_y_trajectory is None :
478
+ raise ValueError ('No trajectory was found' )
479
+
462
480
all_trajectories [
463
481
unflipped_trajectory .parameters .start_angle
464
482
].append (unflipped_trajectory )
@@ -513,6 +531,10 @@ def _create_complete_minimal_spanning_set(
513
531
)
514
532
)
515
533
534
+ if (unflipped_trajectory is None or flipped_y_trajectory is None or
535
+ flipped_x_trajectory is None or flipped_xy_trajectory is None ):
536
+ raise ValueError ('No trajectory was found' )
537
+
516
538
all_trajectories [
517
539
unflipped_trajectory .parameters .start_angle
518
540
].append (unflipped_trajectory )
@@ -528,7 +550,8 @@ def _create_complete_minimal_spanning_set(
528
550
529
551
return all_trajectories
530
552
531
- def _handle_motion_model (self , spanning_set : dict ) -> dict :
553
+ def _handle_motion_model (self , spanning_set : Dict [float , List [Trajectory ]]
554
+ ) -> Dict [float , List [Trajectory ]]:
532
555
"""
533
556
Add the appropriate motions for the user supplied motion model.
534
557
@@ -565,7 +588,8 @@ def _handle_motion_model(self, spanning_set: dict) -> dict:
565
588
print ('No handling implemented for Motion Model: ' + f'{ self .motion_model } ' )
566
589
raise NotImplementedError
567
590
568
- def _add_in_place_turns (self , spanning_set : dict ) -> dict :
591
+ def _add_in_place_turns (self , spanning_set : Dict [float , List [Trajectory ]]
592
+ ) -> Dict [float , List [Trajectory ]]:
569
593
"""
570
594
Add in place turns to the spanning set.
571
595
@@ -623,7 +647,8 @@ def _add_in_place_turns(self, spanning_set: dict) -> dict:
623
647
624
648
return spanning_set
625
649
626
- def _add_horizontal_motions (self , spanning_set : dict ) -> dict :
650
+ def _add_horizontal_motions (self , spanning_set : Dict [float , List [Trajectory ]]
651
+ ) -> Dict [float , List [Trajectory ]]:
627
652
"""
628
653
Add horizontal sliding motions to the spanning set.
629
654
@@ -723,7 +748,7 @@ def _add_horizontal_motions(self, spanning_set: dict) -> dict:
723
748
724
749
return spanning_set
725
750
726
- def run (self ):
751
+ def run (self ) -> Dict [ float , List [ Trajectory ]] :
727
752
"""
728
753
Run the lattice generator.
729
754
0 commit comments