@@ -71,6 +71,7 @@ def __init__(
7171 self .current_traj_parameter = 0.0
7272 self .t_last = None
7373 self .reverse = None
74+ self .sharp_turn = False
7475
7576 def set_path (self , path : Path ):
7677 if path == self .path_arg :
@@ -145,6 +146,62 @@ def is_target_behind_vehicle(self, vehicle_pose, target_point_coords):
145146 dot_product = vec_x * heading_x + vec_y * heading_y
146147 return (dot_product < 0 )
147148
149+ def _check_sharp_turn_ahead (self , lookahead_s = 3.0 , threshold_angle = np .pi / 2.0 , num_steps = 4 ):
150+ if not self .path :
151+ return False
152+
153+ path = self .path
154+ current_s = self .current_path_parameter
155+ domain_start , domain_end = path .domain ()
156+
157+ if current_s >= domain_end - 1e-3 :
158+ return False
159+
160+ step_s = lookahead_s / num_steps
161+ s_prev = current_s
162+
163+ try :
164+ tangent_prev = path .eval_tangent (s_prev )
165+ if np .linalg .norm (tangent_prev ) < 1e-6 :
166+ s_prev_adjusted = min (s_prev + step_s / 2 , domain_end )
167+ if s_prev_adjusted <= s_prev :
168+ return False
169+ tangent_prev = path .eval_tangent (s_prev_adjusted )
170+ if np .linalg .norm (tangent_prev ) < 1e-6 :
171+ return False
172+ s_prev = s_prev_adjusted
173+
174+ angle_prev = atan2 (tangent_prev [1 ], tangent_prev [0 ])
175+
176+ except Exception as e :
177+ return False
178+
179+ for i in range (num_steps ):
180+ s_next = s_prev + step_s
181+ s_next = min (s_next , domain_end )
182+
183+ if s_next <= s_prev + 1e-6 :
184+ break
185+
186+ try :
187+ tangent_next = path .eval_tangent (s_next )
188+ if np .linalg .norm (tangent_next ) < 1e-6 :
189+ s_prev = s_next
190+ continue
191+
192+ angle_next = atan2 (tangent_next [1 ], tangent_next [0 ])
193+ except Exception as e :
194+ break
195+
196+ angle_change = abs (normalise_angle (angle_next - angle_prev ))
197+
198+ if angle_change > threshold_angle :
199+ return True
200+
201+ angle_prev = angle_next
202+ s_prev = s_next
203+ return False
204+
148205 def compute (self , state : VehicleState , component : Component = None ):
149206 t = state .pose .t
150207 if self .t_last is None :
@@ -183,7 +240,7 @@ def compute(self, state: VehicleState, component: Component = None):
183240 fx , fy = self ._find_rear_axle_position (curr_x , curr_y , curr_yaw )
184241 else :
185242 fx , fy = self ._find_front_axle_position (curr_x , curr_y , curr_yaw )
186- search_start = self .current_path_parameter - 0.0
243+ search_start = self .current_path_parameter
187244 search_end = self .current_path_parameter + 5.0
188245 closest_dist , closest_parameter = self .path .closest_point_local ((fx , fy ), [search_start , search_end ])
189246 self .current_path_parameter = closest_parameter
@@ -195,12 +252,17 @@ def compute(self, state: VehicleState, component: Component = None):
195252 dx = fx - target_x
196253 dy = fy - target_y
197254
255+ is_sharp_turn_ahead = self ._check_sharp_turn_ahead (
256+ lookahead_s = 2.0 ,
257+ threshold_angle = np .pi / 2.0
258+ )
259+ if is_sharp_turn_ahead and not self .sharp_turn :
260+ self .sharp_turn = True
198261 use_reverse = self .is_target_behind_vehicle (state .pose , (target_x , target_y ))
199- if use_reverse :
262+ if use_reverse and self . sharp_turn and not self . reverse :
200263 self .reverse = True
201- else :
202- self .reverse = False
203-
264+ self .sharp_turn = False
265+
204266 if self .reverse :
205267 cross_track_error = dx * (- tangent [1 ]) + dy * tangent [0 ]
206268 self .k += self .k
0 commit comments