99import math
1010import numpy as np
1111import sys
12- sys .path .append ("../../PathPlanning/CubicSpline/" )
1312
14- try :
15- import cubic_spline_planner
16- except :
17- raise
13+ from scipy import interpolate
14+ from scipy import optimize
1815
1916Kp = 1.0 # speed propotional gain
2017# steering control parameter
@@ -39,6 +36,61 @@ def update(self, a, delta, dt):
3936 self .yaw = self .yaw + self .v / L * math .tan (delta ) * dt
4037 self .v = self .v + a * dt
4138
39+ class TrackSpline :
40+ def __init__ (self , x , y ):
41+ x , y = map (np .asarray , (x , y ))
42+ s = np .append ([0 ],(np .cumsum (np .diff (x )** 2 ) + np .cumsum (np .diff (y )** 2 ))** 0.5 )
43+
44+ self .X = interpolate .CubicSpline (s , x )
45+ self .Y = interpolate .CubicSpline (s , y )
46+
47+ self .dX = self .X .derivative (1 )
48+ self .ddX = self .X .derivative (2 )
49+
50+ self .dY = self .Y .derivative (1 )
51+ self .ddY = self .Y .derivative (2 )
52+
53+ self .length = s [- 1 ]
54+
55+ def yaw (self , s ):
56+ dx , dy = self .dX (s ), self .dY (s )
57+ return np .arctan2 (dy , dx )
58+
59+ def curvature (self , s ):
60+ dx , dy = self .dX (s ), self .dY (s )
61+ ddx , ddy = self .ddX (s ), self .ddY (s )
62+ return (ddy * dx - ddx * dy ) / ((dx ** 2 + dy ** 2 )** (3 / 2 ))
63+
64+ def __findClosestPoint (self , s0 , x , y ):
65+ def f (_s , * args ):
66+ _x , _y = self .X (_s ), self .Y (_s )
67+ return (_x - args [0 ])** 2 + (_y - args [1 ])** 2
68+
69+ def jac (_s , * args ):
70+ _x , _y = self .X (_s ), self .Y (_s )
71+ _dx , _dy = self .dX (_s ), self .dY (_s )
72+ return 2 * _dx * (_x - args [0 ])+ 2 * _dy * (_y - args [1 ])
73+
74+ minimum = optimize .fmin_cg (f , s0 , jac , args = (x , y ), full_output = True , disp = False )
75+ return minimum
76+
77+ def TrackError (self , x , y , s0 ):
78+ ret = self .__findClosestPoint (s0 , x , y )
79+
80+ s = ret [0 ][0 ]
81+ e = ret [1 ]
82+
83+ k = self .curvature (s )
84+ yaw = self .yaw (s )
85+
86+ dxl = self .X (s ) - x
87+ dyl = self .Y (s ) - y
88+ angle = pi_2_pi (yaw - math .atan2 (dyl , dxl ))
89+ if angle < 0 :
90+ e *= - 1
91+
92+ return e , k , yaw , s
93+
4294def PIDControl (target , current ):
4395 a = Kp * (target - current )
4496 return a
@@ -52,46 +104,22 @@ def pi_2_pi(angle):
52104
53105 return angle
54106
55- def rear_wheel_feedback_control (state , cx , cy , cyaw , ck , preind ):
56- ind , e = calc_nearest_index (state , cx , cy , cyaw )
57-
58- k = ck [ind ]
107+ def rear_wheel_feedback_control (state , e , k , yaw_r ):
59108 v = state .v
60- th_e = pi_2_pi (state .yaw - cyaw [ ind ] )
109+ th_e = pi_2_pi (state .yaw - yaw_r )
61110
62111 omega = v * k * math .cos (th_e ) / (1.0 - k * e ) - \
63112 KTH * abs (v ) * th_e - KE * v * math .sin (th_e ) * e / th_e
64113
65114 if th_e == 0.0 or omega == 0.0 :
66- return 0.0 , ind
115+ return 0.0
67116
68117 delta = math .atan2 (L * omega / v , 1.0 )
69118
70- return delta , ind
71-
72-
73- def calc_nearest_index (state , cx , cy , cyaw ):
74- dx = [state .x - icx for icx in cx ]
75- dy = [state .y - icy for icy in cy ]
76-
77- d = [idx ** 2 + idy ** 2 for (idx , idy ) in zip (dx , dy )]
78-
79- mind = min (d )
80-
81- ind = d .index (mind )
119+ return delta
82120
83- mind = math .sqrt (mind )
84121
85- dxl = cx [ind ] - state .x
86- dyl = cy [ind ] - state .y
87-
88- angle = pi_2_pi (cyaw [ind ] - math .atan2 (dyl , dxl ))
89- if angle < 0 :
90- mind *= - 1
91-
92- return ind , mind
93-
94- def closed_loop_prediction (cx , cy , cyaw , ck , speed_profile , goal ):
122+ def closed_loop_prediction (track , speed_profile , goal ):
95123 T = 500.0 # max simulation time
96124 goal_dis = 0.3
97125 stop_speed = 0.05
@@ -105,17 +133,17 @@ def closed_loop_prediction(cx, cy, cyaw, ck, speed_profile, goal):
105133 v = [state .v ]
106134 t = [0.0 ]
107135 goal_flag = False
108- target_ind = calc_nearest_index (state , cx , cy , cyaw )
136+
137+ s = np .arange (0 , track .length , 0.1 )
138+ e , k , yaw_r , s0 = track .TrackError (state .x , state .y , 0.0 )
109139
110140 while T >= time :
111- di , target_ind = rear_wheel_feedback_control (
112- state , cx , cy , cyaw , ck , target_ind )
113- ai = PIDControl (speed_profile [target_ind ], state .v )
141+ e , k , yaw_r , s0 = track .TrackError (state .x , state .y , s0 )
142+ di = rear_wheel_feedback_control (state , e , k , yaw_r )
143+ #ai = PIDControl(speed_profile[target_ind], state.v)
144+ ai = PIDControl (speed_profile , state .v )
114145 state .update (ai , di , dt )
115146
116- if abs (state .v ) <= stop_speed :
117- target_ind += 1
118-
119147 time = time + dt
120148
121149 # check goal
@@ -132,23 +160,22 @@ def closed_loop_prediction(cx, cy, cyaw, ck, speed_profile, goal):
132160 v .append (state .v )
133161 t .append (time )
134162
135- if target_ind % 1 == 0 and show_animation :
163+ if show_animation :
136164 plt .cla ()
137165 # for stopping simulation with the esc key.
138166 plt .gcf ().canvas .mpl_connect ('key_release_event' ,
139167 lambda event : [exit (0 ) if event .key == 'escape' else None ])
140- plt .plot (cx , cy , "-r" , label = "course" )
168+ plt .plot (track . X ( s ), track . Y ( s ) , "-r" , label = "course" )
141169 plt .plot (x , y , "ob" , label = "trajectory" )
142- plt .plot (cx [ target_ind ], cy [ target_ind ] , "xg" , label = "target" )
170+ plt .plot (track . X ( s0 ), track . Y ( s0 ) , "xg" , label = "target" )
143171 plt .axis ("equal" )
144172 plt .grid (True )
145- plt .title ("speed[km/h]:" + str (round (state .v * 3.6 , 2 )) +
146- ",target index:" + str (target_ind ))
173+ plt .title ("speed[km/h]:{:.2f}, target s-param:{:.2f}" .format (round (state .v * 3.6 , 2 ), s0 ))
147174 plt .pause (0.0001 )
148175
149176 return t , x , y , yaw , v , goal_flag
150177
151- def calc_speed_profile (cx , cy , cyaw , target_speed ):
178+ def calc_speed_profile (track , target_speed , s ):
152179 speed_profile = [target_speed ] * len (cx )
153180 direction = 1.0
154181
@@ -178,14 +205,16 @@ def main():
178205 ay = [0.0 , 0.0 , 5.0 , 6.5 , 3.0 , 5.0 , - 2.0 ]
179206 goal = [ax [- 1 ], ay [- 1 ]]
180207
181- cx , cy , cyaw , ck , s = cubic_spline_planner .calc_spline_course (
182- ax , ay , ds = 0.1 )
208+ track = TrackSpline (ax , ay )
209+ s = np .arange (0 , track .length , 0.1 )
210+
183211 target_speed = 10.0 / 3.6
184212
185- sp = calc_speed_profile (cx , cy , cyaw , target_speed )
213+ # Note: disable backward direction temporary
214+ #sp = calc_speed_profile(track, target_speed, s)
215+ sp = target_speed
186216
187- t , x , y , yaw , v , goal_flag = closed_loop_prediction (
188- cx , cy , cyaw , ck , sp , goal )
217+ t , x , y , yaw , v , goal_flag = closed_loop_prediction (track , sp , goal )
189218
190219 # Test
191220 assert goal_flag , "Cannot goal"
@@ -194,7 +223,7 @@ def main():
194223 plt .close ()
195224 plt .subplots (1 )
196225 plt .plot (ax , ay , "xb" , label = "input" )
197- plt .plot (cx , cy , "-r" , label = "spline" )
226+ plt .plot (track . X ( s ), track . Y ( s ) , "-r" , label = "spline" )
198227 plt .plot (x , y , "-g" , label = "tracking" )
199228 plt .grid (True )
200229 plt .axis ("equal" )
@@ -203,14 +232,14 @@ def main():
203232 plt .legend ()
204233
205234 plt .subplots (1 )
206- plt .plot (s , [ np .rad2deg (iyaw ) for iyaw in cyaw ] , "-r" , label = "yaw" )
235+ plt .plot (s , np .rad2deg (track . yaw ( s )) , "-r" , label = "yaw" )
207236 plt .grid (True )
208237 plt .legend ()
209238 plt .xlabel ("line length[m]" )
210239 plt .ylabel ("yaw angle[deg]" )
211240
212241 plt .subplots (1 )
213- plt .plot (s , ck , "-r" , label = "curvature" )
242+ plt .plot (s , track . curvature ( s ) , "-r" , label = "curvature" )
214243 plt .grid (True )
215244 plt .legend ()
216245 plt .xlabel ("line length[m]" )
0 commit comments