1717L = 2.9 # [m] wheel base of vehicle
1818
1919
20- old_nearest_point_index = None
2120show_animation = True
2221
2322
@@ -31,89 +30,106 @@ def __init__(self, x=0.0, y=0.0, yaw=0.0, v=0.0):
3130 self .rear_x = self .x - ((L / 2 ) * math .cos (self .yaw ))
3231 self .rear_y = self .y - ((L / 2 ) * math .sin (self .yaw ))
3332
33+ def update (self , a , delta ):
3434
35- def update (state , a , delta ):
35+ self .x += self .v * math .cos (self .yaw ) * dt
36+ self .y += self .v * math .sin (self .yaw ) * dt
37+ self .yaw += self .v / L * math .tan (delta ) * dt
38+ self .v += a * dt
39+ self .rear_x = self .x - ((L / 2 ) * math .cos (self .yaw ))
40+ self .rear_y = self .y - ((L / 2 ) * math .sin (self .yaw ))
3641
37- state .x = state .x + state .v * math .cos (state .yaw ) * dt
38- state .y = state .y + state .v * math .sin (state .yaw ) * dt
39- state .yaw = state .yaw + state .v / L * math .tan (delta ) * dt
40- state .v = state .v + a * dt
41- state .rear_x = state .x - ((L / 2 ) * math .cos (state .yaw ))
42- state .rear_y = state .y - ((L / 2 ) * math .sin (state .yaw ))
42+ def calc_distance (self , point_x , point_y ):
4343
44- return state
44+ dx = self .rear_x - point_x
45+ dy = self .rear_y - point_y
46+ return math .hypot (dx , dy )
4547
4648
47- def PIDControl (target , current ):
48- a = Kp * (target - current )
49+ class States :
4950
50- return a
51+ def __init__ (self ):
52+ self .x = []
53+ self .y = []
54+ self .yaw = []
55+ self .v = []
56+ self .t = []
5157
58+ def append (self , t , state ):
59+ self .x .append (state .x )
60+ self .y .append (state .y )
61+ self .yaw .append (state .yaw )
62+ self .v .append (state .v )
63+ self .t .append (t )
5264
53- def pure_pursuit_control (state , cx , cy , pind ):
5465
55- ind = calc_target_index (state , cx , cy )
66+ def PIDControl (target , current ):
67+ a = Kp * (target - current )
5668
57- if pind >= ind :
58- ind = pind
69+ return a
5970
60- if ind < len (cx ):
61- tx = cx [ind ]
62- ty = cy [ind ]
63- else :
64- tx = cx [- 1 ]
65- ty = cy [- 1 ]
66- ind = len (cx ) - 1
6771
68- alpha = math .atan2 (ty - state .rear_y , tx - state .rear_x ) - state .yaw
72+ class Trajectory :
73+ def __init__ (self , cx , cy ):
74+ self .cx = cx
75+ self .cy = cy
76+ self .old_nearest_point_index = None
6977
70- Lf = k * state .v + Lfc
78+ def __call__ (self , state ):
79+ if self .old_nearest_point_index is None :
80+ # search nearest point index
81+ dx = [state .rear_x - icx for icx in self .cx ]
82+ dy = [state .rear_y - icy for icy in self .cy ]
83+ d = [idx ** 2 + idy ** 2 for (idx , idy ) in zip (dx , dy )]
84+ ind = d .index (min (d ))
85+ self .old_nearest_point_index = ind
86+ else :
87+ ind = self .old_nearest_point_index
88+ distance_this_index = state .calc_distance (self .cx [ind ], self .cy [ind ])
89+ while True :
90+ ind = ind + 1 if (ind + 1 ) < len (self .cx ) else ind
91+ distance_next_index = state .calc_distance (self .cx [ind ], self .cy [ind ])
92+ if distance_this_index < distance_next_index :
93+ break
94+ distance_this_index = distance_next_index
95+ self .old_nearest_point_index = ind
7196
72- delta = math . atan2 ( 2.0 * L * math . sin ( alpha ) / Lf , 1.0 )
97+ L = 0.0
7398
74- return delta , ind
99+ Lf = k * state . v + Lfc
75100
76- def calc_distance (state , point_x , point_y ):
101+ # search look ahead target point index
102+ while Lf > L and (ind + 1 ) < len (self .cx ):
103+ dx = self .cx [ind ] - state .rear_x
104+ dy = self .cy [ind ] - state .rear_y
105+ L = math .hypot (dx , dy )
106+ ind += 1
77107
78- dx = state .rear_x - point_x
79- dy = state .rear_y - point_y
80- return math .hypot (dx , dy )
108+ return ind
81109
82110
83- def calc_target_index (state , cx , cy ):
111+ def pure_pursuit_control (state , trajectory , pind ):
84112
85- global old_nearest_point_index
113+ ind = trajectory (state )
114+
115+ if pind >= ind :
116+ ind = pind
86117
87- if old_nearest_point_index is None :
88- # search nearest point index
89- dx = [state .rear_x - icx for icx in cx ]
90- dy = [state .rear_y - icy for icy in cy ]
91- d = [idx ** 2 + idy ** 2 for (idx , idy ) in zip (dx , dy )]
92- ind = d .index (min (d ))
93- old_nearest_point_index = ind
118+ if ind < len (trajectory .cx ):
119+ tx = trajectory .cx [ind ]
120+ ty = trajectory .cy [ind ]
94121 else :
95- ind = old_nearest_point_index
96- distance_this_index = calc_distance (state , cx [ind ], cy [ind ])
97- while True :
98- ind = ind + 1 if (ind + 1 ) < len (cx ) else ind
99- distance_next_index = calc_distance (state , cx [ind ], cy [ind ])
100- if distance_this_index < distance_next_index :
101- break
102- distance_this_index = distance_next_index
103- old_nearest_point_index = ind
104-
105- L = 0.0
122+ tx = trajectory .cx [- 1 ]
123+ ty = trajectory .cy [- 1 ]
124+ ind = len (trajectory .cx ) - 1
125+
126+ alpha = math .atan2 (ty - state .rear_y , tx - state .rear_x ) - state .yaw
106127
107128 Lf = k * state .v + Lfc
108129
109- # search look ahead target point index
110- while Lf > L and (ind + 1 ) < len (cx ):
111- dx = cx [ind ] - state .rear_x
112- dy = cy [ind ] - state .rear_y
113- L = math .hypot (dx , dy )
114- ind += 1
130+ delta = math .atan2 (2.0 * L * math .sin (alpha ) / Lf , 1.0 )
115131
116- return ind
132+ return delta , ind
117133
118134
119135def plot_arrow (x , y , yaw , length = 1.0 , width = 0.5 , fc = "r" , ec = "k" ):
@@ -144,25 +160,18 @@ def main():
144160
145161 lastIndex = len (cx ) - 1
146162 time = 0.0
147- x = [state .x ]
148- y = [state .y ]
149- yaw = [state .yaw ]
150- v = [state .v ]
151- t = [0.0 ]
152- target_ind = calc_target_index (state , cx , cy )
163+ states = States ()
164+ states .append (time , state )
165+ trajectory = Trajectory (cx , cy )
166+ target_ind = trajectory (state )
153167
154168 while T >= time and lastIndex > target_ind :
155169 ai = PIDControl (target_speed , state .v )
156- di , target_ind = pure_pursuit_control (state , cx , cy , target_ind )
157- state = update (state , ai , di )
158-
159- time = time + dt
170+ di , target_ind = pure_pursuit_control (state , trajectory , target_ind )
171+ state .update (ai , di )
160172
161- x .append (state .x )
162- y .append (state .y )
163- yaw .append (state .yaw )
164- v .append (state .v )
165- t .append (time )
173+ time += dt
174+ states .append (time , state )
166175
167176 if show_animation : # pragma: no cover
168177 plt .cla ()
@@ -171,7 +180,7 @@ def main():
171180 lambda event : [exit (0 ) if event .key == 'escape' else None ])
172181 plot_arrow (state .x , state .y , state .yaw )
173182 plt .plot (cx , cy , "-r" , label = "course" )
174- plt .plot (x , y , "-b" , label = "trajectory" )
183+ plt .plot (states . x , states . y , "-b" , label = "trajectory" )
175184 plt .plot (cx [target_ind ], cy [target_ind ], "xg" , label = "target" )
176185 plt .axis ("equal" )
177186 plt .grid (True )
@@ -184,15 +193,15 @@ def main():
184193 if show_animation : # pragma: no cover
185194 plt .cla ()
186195 plt .plot (cx , cy , ".r" , label = "course" )
187- plt .plot (x , y , "-b" , label = "trajectory" )
196+ plt .plot (states . x , states . y , "-b" , label = "trajectory" )
188197 plt .legend ()
189198 plt .xlabel ("x[m]" )
190199 plt .ylabel ("y[m]" )
191200 plt .axis ("equal" )
192201 plt .grid (True )
193202
194203 plt .subplots (1 )
195- plt .plot (t , [iv * 3.6 for iv in v ], "-r" )
204+ plt .plot (states . t , [iv * 3.6 for iv in states . v ], "-r" )
196205 plt .xlabel ("Time[s]" )
197206 plt .ylabel ("Speed[km/h]" )
198207 plt .grid (True )
0 commit comments