@@ -151,6 +151,111 @@ def _find_front_axle_position(self, x, y, yaw):
151151 fy = y + self .wheelbase * sin (yaw )
152152 return fx , fy
153153
154+ def _find_rear_axle_position (self , x , y , yaw ):
155+ """Compute rear-axle world position from the vehicle's reference point and yaw."""
156+ rx = x - self .wheelbase * cos (yaw )
157+ ry = y - self .wheelbase * sin (yaw )
158+ return rx , ry
159+
160+ def initialize_state_and_direction (self , state : VehicleState ):
161+ # Initializes the controller's state and determines initial driving direction (forward/reverse).
162+ if self .path is None :
163+ raise ValueError ("Stanley: Path must be set before initializing state and direction." )
164+ curr_x = state .pose .x
165+ curr_y = state .pose .y
166+ curr_yaw = state .pose .yaw if state .pose .yaw is not None else 0.0
167+ fx , fy = self ._find_front_axle_position (curr_x , curr_y , curr_yaw )
168+ path_domain_start , path_domain_end = self .path .domain ()
169+ search_end = min (path_domain_end , path_domain_start + 5.0 )
170+ search_domain_start = [path_domain_start , search_end ]
171+ _ , closest_param_at_start = self .path .closest_point_local ((fx , fy ), search_domain_start )
172+ tangent_at_start = self .path .eval_tangent (closest_param_at_start )
173+ initial_reverse = False
174+ if np .linalg .norm (tangent_at_start ) > 1e-6 :
175+ path_yaw_at_start = atan2 (tangent_at_start [1 ], tangent_at_start [0 ])
176+ heading_diff = normalise_angle (path_yaw_at_start - curr_yaw )
177+ initial_reverse = abs (heading_diff ) > (np .pi / 2.0 )
178+ self .pid_speed .reset ()
179+ self .current_path_parameter = closest_param_at_start
180+ if self .trajectory :
181+ self .current_traj_parameter = self .trajectory .domain ()[0 ]
182+ return initial_reverse
183+
184+ def is_target_behind_vehicle (self , vehicle_pose , target_point_coords ):
185+ """Checks if a target point is behind the vehicle."""
186+ curr_x = vehicle_pose .x
187+ curr_y = vehicle_pose .y
188+ curr_yaw = vehicle_pose .yaw
189+ if curr_yaw is None :
190+ return False
191+ target_x = target_point_coords [0 ]
192+ target_y = target_point_coords [1 ]
193+ vec_x = target_x - curr_x
194+ vec_y = target_y - curr_y
195+ if abs (vec_x ) < 1e-6 and abs (vec_y ) < 1e-6 :
196+ return False
197+ heading_x = cos (curr_yaw )
198+ heading_y = sin (curr_yaw )
199+ dot_product = vec_x * heading_x + vec_y * heading_y
200+ return (dot_product < 0 )
201+
202+ def _check_sharp_turn_ahead (self , lookahead_s = 3.0 , threshold_angle = np .pi / 2.0 , num_steps = 4 ):
203+ """Checks for sharp turns within a lookahead distance on the path."""
204+ if not self .path :
205+ return False
206+
207+ path = self .path
208+ current_s = self .current_path_parameter
209+ domain_start , domain_end = path .domain ()
210+
211+ if current_s >= domain_end - 1e-3 :
212+ return False
213+
214+ step_s = lookahead_s / num_steps
215+ s_prev = current_s
216+
217+ try :
218+ tangent_prev = path .eval_tangent (s_prev )
219+ if np .linalg .norm (tangent_prev ) < 1e-6 :
220+ s_prev_adjusted = min (s_prev + step_s / 2 , domain_end )
221+ if s_prev_adjusted <= s_prev :
222+ return False
223+ tangent_prev = path .eval_tangent (s_prev_adjusted )
224+ if np .linalg .norm (tangent_prev ) < 1e-6 :
225+ return False
226+ s_prev = s_prev_adjusted
227+
228+ angle_prev = atan2 (tangent_prev [1 ], tangent_prev [0 ])
229+
230+ except Exception as e :
231+ return False
232+
233+ for i in range (num_steps ):
234+ s_next = s_prev + step_s
235+ s_next = min (s_next , domain_end )
236+
237+ if s_next <= s_prev + 1e-6 :
238+ break
239+
240+ try :
241+ tangent_next = path .eval_tangent (s_next )
242+ if np .linalg .norm (tangent_next ) < 1e-6 :
243+ s_prev = s_next
244+ continue
245+
246+ angle_next = atan2 (tangent_next [1 ], tangent_next [0 ])
247+ except Exception as e :
248+ break
249+
250+ angle_change = abs (normalise_angle (angle_next - angle_prev ))
251+
252+ if angle_change > threshold_angle :
253+ return True
254+
255+ angle_prev = angle_next
256+ s_prev = s_next
257+ return False
258+
154259 def compute (self , state : VehicleState , component : Component = None ):
155260 """Compute the control outputs: (longitudinal acceleration, front wheel angle)."""
156261 t = state .pose .t
0 commit comments