55author Atsushi Sakai(@Atsushi_twi)
66
77"""
8- import math
8+ import sys
9+ import os
10+ sys .path .append (os .path .dirname (os .path .abspath (__file__ )) + "/../utils/" )
911
10- import matplotlib . pyplot as plt
12+ import math
1113import numpy as np
12- from scipy . spatial . transform import Rotation as Rot
14+ from utils . angle import angle_mod , create_2d_rotation_matrix
1315
1416show_animation = True
1517
1618
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 ):
1923 """
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.
4057
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
4465
4566 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 )
4768
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 )
4971 converted_xy = np .stack ([lp_x , lp_y ]).T @ rot
5072 x_list = converted_xy [:, 0 ] + s_x
5173 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 )
5375
5476 return x_list , y_list , yaw_list , modes , lengths
5577
5678
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 )
6381
6482
65- def left_straight_left (alpha , beta , d ):
83+ def _LSL (alpha , beta , d ):
6684 sa = math .sin (alpha )
6785 sb = math .sin (beta )
6886 ca = math .cos (alpha )
@@ -76,9 +94,9 @@ def left_straight_left(alpha, beta, d):
7694 if p_squared < 0 :
7795 return None , None , None , mode
7896 tmp1 = math .atan2 ((cb - ca ), tmp0 )
79- t = mod2pi (- alpha + tmp1 )
97+ t = _mod2pi (- alpha + tmp1 )
8098 p = math .sqrt (p_squared )
81- q = mod2pi (beta - tmp1 )
99+ q = _mod2pi (beta - tmp1 )
82100
83101 return t , p , q , mode
84102
@@ -96,9 +114,9 @@ def right_straight_right(alpha, beta, d):
96114 if p_squared < 0 :
97115 return None , None , None , mode
98116 tmp1 = math .atan2 ((ca - cb ), tmp0 )
99- t = mod2pi (alpha - tmp1 )
117+ t = angle_mod (alpha - tmp1 , zero_2_2pi = True )
100118 p = math .sqrt (p_squared )
101- q = mod2pi (- beta + tmp1 )
119+ q = _mod2pi (- beta + tmp1 )
102120
103121 return t , p , q , mode
104122
@@ -116,8 +134,8 @@ def left_straight_right(alpha, beta, d):
116134 return None , None , None , mode
117135 p = math .sqrt (p_squared )
118136 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 )
121139
122140 return t , p , q , mode
123141
@@ -135,8 +153,8 @@ def right_straight_left(alpha, beta, d):
135153 return None , None , None , mode
136154 p = math .sqrt (p_squared )
137155 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 )
140158
141159 return t , p , q , mode
142160
@@ -153,13 +171,13 @@ def right_left_right(alpha, beta, d):
153171 if abs (tmp_rlr ) > 1.0 :
154172 return None , None , None , mode
155173
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 ))
159177 return t , p , q , mode
160178
161179
162- def left_right_left (alpha , beta , d ):
180+ def _LRL (alpha , beta , d ):
163181 sa = math .sin (alpha )
164182 sb = math .sin (beta )
165183 ca = math .cos (alpha )
@@ -170,9 +188,9 @@ def left_right_left(alpha, beta, d):
170188 tmp_lrl = (6.0 - d * d + 2.0 * c_ab + 2.0 * d * (- sa + sb )) / 8.0
171189 if abs (tmp_lrl ) > 1 :
172190 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 ))
176194
177195 return t , p , q , mode
178196
@@ -184,13 +202,13 @@ def dubins_path_planning_from_origin(end_x, end_y, end_yaw, curvature,
184202 D = math .hypot (dx , dy )
185203 d = D * curvature
186204
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 )
190208
191- planning_funcs = [left_straight_left , right_straight_right ,
209+ planning_funcs = [_LSL , right_straight_right ,
192210 left_straight_right , right_straight_left ,
193- right_left_right , left_right_left ]
211+ right_left_right , _LRL ]
194212
195213 best_cost = float ("inf" )
196214 bt , bp , bq , best_mode = None , None , None , None
@@ -319,6 +337,7 @@ def generate_local_course(total_length, lengths, modes, max_curvature,
319337
320338def plot_arrow (x , y , yaw , length = 1.0 , width = 0.5 , fc = "r" ,
321339 ec = "k" ): # pragma: no cover
340+ import matplotlib .pyplot as plt
322341 if not isinstance (x , float ):
323342 for (i_x , i_y , i_yaw ) in zip (x , y , yaw ):
324343 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",
330349
331350def main ():
332351 print ("Dubins path planner sample start!!" )
352+ import matplotlib .pyplot as plt
333353
334354 start_x = 1.0 # [m]
335355 start_y = 1.0 # [m]
@@ -341,13 +361,13 @@ def main():
341361
342362 curvature = 1.0
343363
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 )
351371
352372 if show_animation :
353373 plt .plot (path_x , path_y , label = "final course " + "" .join (mode ))
0 commit comments