5
5
author Atsushi Sakai(@Atsushi_twi)
6
6
7
7
"""
8
- import math
8
+ import sys
9
+ import os
10
+ sys .path .append (os .path .dirname (os .path .abspath (__file__ )) + "/../utils/" )
9
11
10
- import matplotlib . pyplot as plt
12
+ import math
11
13
import numpy as np
12
- from scipy . spatial . transform import Rotation as Rot
14
+ from utils . angle import angle_mod , create_2d_rotation_matrix
13
15
14
16
show_animation = True
15
17
16
18
17
- def dubins_path_planning (s_x , s_y , s_yaw , g_x , g_y , g_yaw , curvature ,
18
- step_size = 0.1 ):
19
+ def plan_dubins_path (s_x , s_y , s_yaw ,
20
+ g_x , g_y , g_yaw ,
21
+ curvature ,
22
+ step_size = 0.1 ):
19
23
"""
20
- Dubins path planner
21
-
22
- :param s_x: x position of start point [m]
23
- :param s_y: y position of start point [m]
24
- :param s_yaw: yaw angle of start point [rad]
25
- :param g_x: x position of end point [m]
26
- :param g_y: y position of end point [m]
27
- :param g_yaw: yaw angle of end point [rad]
28
- :param curvature: curvature for curve [1/m]
29
- :param step_size: (optional) step size between two path points [m]
30
- :return:
31
- x_list: x positions of a path
32
- y_list: y positions of a path
33
- yaw_list: yaw angles of a path
34
- modes: mode list of a path
35
- lengths: length of path segments.
36
- """
37
-
38
- g_x -= s_x
39
- g_y -= s_y
24
+ Path dubins path
25
+
26
+ Parameters
27
+ ----------
28
+ s_x : float
29
+ x position of the start point [m]
30
+ s_y : float
31
+ y position of the start point [m]
32
+ s_yaw : float
33
+ yaw angle of the start point [rad]
34
+ g_x : float
35
+ x position of the goal point [m]
36
+ g_y : float
37
+ y position of the end point [m]
38
+ g_yaw : float
39
+ yaw angle of the end point [rad]
40
+ curvature : float
41
+ curvature for curve [1/m]
42
+ step_size : float (optional)
43
+ step size between two path points [m]. Default is 0.1
44
+
45
+ Returns
46
+ -------
47
+ x_list: array
48
+ x positions of the path
49
+ y_list: array
50
+ y positions of the path
51
+ yaw_list: array
52
+ yaw angles of the path
53
+ modes: array
54
+ mode list of the path
55
+ lengths: array
56
+ length list of the path segments.
40
57
41
- l_rot = Rot .from_euler ('z' , s_yaw ).as_matrix ()[0 :2 , 0 :2 ]
42
- le_xy = np .stack ([g_x , g_y ]).T @ l_rot
43
- le_yaw = g_yaw - s_yaw
58
+ """
59
+ # calculate local goal x, y, yaw
60
+ l_rot = create_2d_rotation_matrix (s_yaw )
61
+ le_xy = np .stack ([g_x - s_x , g_y - s_y ]).T @ l_rot
62
+ local_goal_x = le_xy [0 ]
63
+ local_goal_y = le_xy [1 ]
64
+ local_goal_yaw = g_yaw - s_yaw
44
65
45
66
lp_x , lp_y , lp_yaw , modes , lengths = dubins_path_planning_from_origin (
46
- le_xy [ 0 ], le_xy [ 1 ], le_yaw , curvature , step_size )
67
+ local_goal_x , local_goal_y , local_goal_yaw , curvature , step_size )
47
68
48
- rot = Rot .from_euler ('z' , - s_yaw ).as_matrix ()[0 :2 , 0 :2 ]
69
+ # Convert a local coordinate path to the global coordinate
70
+ rot = create_2d_rotation_matrix (- s_yaw )
49
71
converted_xy = np .stack ([lp_x , lp_y ]).T @ rot
50
72
x_list = converted_xy [:, 0 ] + s_x
51
73
y_list = converted_xy [:, 1 ] + s_y
52
- yaw_list = [ pi_2_pi ( i_yaw + s_yaw ) for i_yaw in lp_yaw ]
74
+ yaw_list = angle_mod ( np . array ( lp_yaw ) + s_yaw )
53
75
54
76
return x_list , y_list , yaw_list , modes , lengths
55
77
56
78
57
- def mod2pi (theta ):
58
- return theta - 2.0 * math .pi * math .floor (theta / 2.0 / math .pi )
59
-
60
-
61
- def pi_2_pi (angle ):
62
- return (angle + math .pi ) % (2 * math .pi ) - math .pi
79
+ def _mod2pi (theta ):
80
+ return angle_mod (theta , zero_2_2pi = True )
63
81
64
82
65
- def left_straight_left (alpha , beta , d ):
83
+ def _LSL (alpha , beta , d ):
66
84
sa = math .sin (alpha )
67
85
sb = math .sin (beta )
68
86
ca = math .cos (alpha )
@@ -76,9 +94,9 @@ def left_straight_left(alpha, beta, d):
76
94
if p_squared < 0 :
77
95
return None , None , None , mode
78
96
tmp1 = math .atan2 ((cb - ca ), tmp0 )
79
- t = mod2pi (- alpha + tmp1 )
97
+ t = _mod2pi (- alpha + tmp1 )
80
98
p = math .sqrt (p_squared )
81
- q = mod2pi (beta - tmp1 )
99
+ q = _mod2pi (beta - tmp1 )
82
100
83
101
return t , p , q , mode
84
102
@@ -96,9 +114,9 @@ def right_straight_right(alpha, beta, d):
96
114
if p_squared < 0 :
97
115
return None , None , None , mode
98
116
tmp1 = math .atan2 ((ca - cb ), tmp0 )
99
- t = mod2pi (alpha - tmp1 )
117
+ t = angle_mod (alpha - tmp1 , zero_2_2pi = True )
100
118
p = math .sqrt (p_squared )
101
- q = mod2pi (- beta + tmp1 )
119
+ q = _mod2pi (- beta + tmp1 )
102
120
103
121
return t , p , q , mode
104
122
@@ -116,8 +134,8 @@ def left_straight_right(alpha, beta, d):
116
134
return None , None , None , mode
117
135
p = math .sqrt (p_squared )
118
136
tmp2 = math .atan2 ((- ca - cb ), (d + sa + sb )) - math .atan2 (- 2.0 , p )
119
- t = mod2pi (- alpha + tmp2 )
120
- q = mod2pi ( - mod2pi (beta ) + tmp2 )
137
+ t = _mod2pi (- alpha + tmp2 )
138
+ q = _mod2pi ( - _mod2pi (beta ) + tmp2 )
121
139
122
140
return t , p , q , mode
123
141
@@ -135,8 +153,8 @@ def right_straight_left(alpha, beta, d):
135
153
return None , None , None , mode
136
154
p = math .sqrt (p_squared )
137
155
tmp2 = math .atan2 ((ca + cb ), (d - sa - sb )) - math .atan2 (2.0 , p )
138
- t = mod2pi (alpha - tmp2 )
139
- q = mod2pi (beta - tmp2 )
156
+ t = _mod2pi (alpha - tmp2 )
157
+ q = _mod2pi (beta - tmp2 )
140
158
141
159
return t , p , q , mode
142
160
@@ -153,13 +171,13 @@ def right_left_right(alpha, beta, d):
153
171
if abs (tmp_rlr ) > 1.0 :
154
172
return None , None , None , mode
155
173
156
- p = mod2pi (2 * math .pi - math .acos (tmp_rlr ))
157
- t = mod2pi (alpha - math .atan2 (ca - cb , d - sa + sb ) + mod2pi (p / 2.0 ))
158
- q = mod2pi (alpha - beta - t + mod2pi (p ))
174
+ p = _mod2pi (2 * math .pi - math .acos (tmp_rlr ))
175
+ t = _mod2pi (alpha - math .atan2 (ca - cb , d - sa + sb ) + _mod2pi (p / 2.0 ))
176
+ q = _mod2pi (alpha - beta - t + _mod2pi (p ))
159
177
return t , p , q , mode
160
178
161
179
162
- def left_right_left (alpha , beta , d ):
180
+ def _LRL (alpha , beta , d ):
163
181
sa = math .sin (alpha )
164
182
sb = math .sin (beta )
165
183
ca = math .cos (alpha )
@@ -170,9 +188,9 @@ def left_right_left(alpha, beta, d):
170
188
tmp_lrl = (6.0 - d * d + 2.0 * c_ab + 2.0 * d * (- sa + sb )) / 8.0
171
189
if abs (tmp_lrl ) > 1 :
172
190
return None , None , None , mode
173
- p = mod2pi (2 * math .pi - math .acos (tmp_lrl ))
174
- t = mod2pi (- alpha - math .atan2 (ca - cb , d + sa - sb ) + p / 2.0 )
175
- q = mod2pi ( mod2pi (beta ) - alpha - t + mod2pi (p ))
191
+ p = _mod2pi (2 * math .pi - math .acos (tmp_lrl ))
192
+ t = _mod2pi (- alpha - math .atan2 (ca - cb , d + sa - sb ) + p / 2.0 )
193
+ q = _mod2pi ( _mod2pi (beta ) - alpha - t + _mod2pi (p ))
176
194
177
195
return t , p , q , mode
178
196
@@ -184,13 +202,13 @@ def dubins_path_planning_from_origin(end_x, end_y, end_yaw, curvature,
184
202
D = math .hypot (dx , dy )
185
203
d = D * curvature
186
204
187
- theta = mod2pi (math .atan2 (dy , dx ))
188
- alpha = mod2pi (- theta )
189
- beta = mod2pi (end_yaw - theta )
205
+ theta = _mod2pi (math .atan2 (dy , dx ))
206
+ alpha = _mod2pi (- theta )
207
+ beta = _mod2pi (end_yaw - theta )
190
208
191
- planning_funcs = [left_straight_left , right_straight_right ,
209
+ planning_funcs = [_LSL , right_straight_right ,
192
210
left_straight_right , right_straight_left ,
193
- right_left_right , left_right_left ]
211
+ right_left_right , _LRL ]
194
212
195
213
best_cost = float ("inf" )
196
214
bt , bp , bq , best_mode = None , None , None , None
@@ -319,6 +337,7 @@ def generate_local_course(total_length, lengths, modes, max_curvature,
319
337
320
338
def plot_arrow (x , y , yaw , length = 1.0 , width = 0.5 , fc = "r" ,
321
339
ec = "k" ): # pragma: no cover
340
+ import matplotlib .pyplot as plt
322
341
if not isinstance (x , float ):
323
342
for (i_x , i_y , i_yaw ) in zip (x , y , yaw ):
324
343
plot_arrow (i_x , i_y , i_yaw )
@@ -330,6 +349,7 @@ def plot_arrow(x, y, yaw, length=1.0, width=0.5, fc="r",
330
349
331
350
def main ():
332
351
print ("Dubins path planner sample start!!" )
352
+ import matplotlib .pyplot as plt
333
353
334
354
start_x = 1.0 # [m]
335
355
start_y = 1.0 # [m]
@@ -341,13 +361,13 @@ def main():
341
361
342
362
curvature = 1.0
343
363
344
- path_x , path_y , path_yaw , mode , lengths = dubins_path_planning (start_x ,
345
- start_y ,
346
- start_yaw ,
347
- end_x ,
348
- end_y ,
349
- end_yaw ,
350
- curvature )
364
+ path_x , path_y , path_yaw , mode , lengths = plan_dubins_path (start_x ,
365
+ start_y ,
366
+ start_yaw ,
367
+ end_x ,
368
+ end_y ,
369
+ end_yaw ,
370
+ curvature )
351
371
352
372
if show_animation :
353
373
plt .plot (path_x , path_y , label = "final course " + "" .join (mode ))
0 commit comments