44
55from cereal import log
66from opendbc .car .lateral import FRICTION_THRESHOLD , get_friction
7- from opendbc .car .tests .test_lateral_limits import MAX_LAT_JERK_UP
87from openpilot .common .constants import ACCELERATION_DUE_TO_GRAVITY
98from openpilot .common .filter_simple import FirstOrderFilter
10- from openpilot .selfdrive .controls .lib .drive_helpers import MIN_SPEED
119from openpilot .selfdrive .controls .lib .latcontrol import LatControl
1210from openpilot .common .pid import PIDController
1311
1715# wheel slip, or to speed.
1816
1917# This controller applies torque to achieve desired lateral
20- # accelerations. To compensate for the low speed effects we
21- # use a LOW_SPEED_FACTOR in the error. Additionally, there is
22- # friction in the steering wheel that needs to be overcome to
23- # move it at all, this is compensated for too.
18+ # accelerations. To compensate for the low speed effects the
19+ # proportional gain is increased at low speeds by the PID controller.
20+ # Additionally, there is friction in the steering wheel that needs
21+ # to be overcome to move it at all, this is compensated for too.
2422
25- LOW_SPEED_X = [0 , 10 , 20 , 30 ]
26- LOW_SPEED_Y = [15 , 13 , 10 , 5 ]
2723KP = 1.0
2824KI = 0.3
2925KD = 0.0
26+ INTERP_SPEEDS = [1 , 1.5 , 2.0 , 3.0 , 5 , 7.5 , 10 , 15 , 30 ]
27+ KP_INTERP = [250 , 120 , 65 , 30 , 11.5 , 5.5 , 3.5 , 2.0 , KP ]
3028
29+ LP_FILTER_CUTOFF_HZ = 1.2
30+ LAT_ACCEL_REQUEST_BUFFER_SECONDS = 1.0
31+ VERSION = 0
3132
3233class LatControlTorque (LatControl ):
3334 def __init__ (self , CP , CI , dt ):
3435 super ().__init__ (CP , CI , dt )
3536 self .torque_params = CP .lateralTuning .torque .as_builder ()
3637 self .torque_from_lateral_accel = CI .torque_from_lateral_accel ()
3738 self .lateral_accel_from_torque = CI .lateral_accel_from_torque ()
38- self .pid = PIDController (KP , KI , k_d = KD , rate = 1 / self .dt )
39+ self .pid = PIDController ([ INTERP_SPEEDS , KP_INTERP ], KI , KD , rate = 1 / self .dt )
3940 self .update_limits ()
4041 self .steering_angle_deadzone_deg = self .torque_params .steeringAngleDeadzoneDeg
41- self .LATACCEL_REQUEST_BUFFER_NUM_FRAMES = int (1 / self .dt )
42- self .requested_lateral_accel_buffer = deque ([0. ] * self .LATACCEL_REQUEST_BUFFER_NUM_FRAMES , maxlen = self .LATACCEL_REQUEST_BUFFER_NUM_FRAMES )
42+ self .lat_accel_request_buffer_len = int (LAT_ACCEL_REQUEST_BUFFER_SECONDS / self .dt )
43+ self .lat_accel_request_buffer = deque ([0. ] * self .lat_accel_request_buffer_len , maxlen = self .lat_accel_request_buffer_len )
4344 self .previous_measurement = 0.0
44- self .measurement_rate_filter = FirstOrderFilter (0.0 , 1 / (2 * np .pi * ( MAX_LAT_JERK_UP - 0.5 ) ), self .dt )
45+ self .measurement_rate_filter = FirstOrderFilter (0.0 , 1 / (2 * np .pi * LP_FILTER_CUTOFF_HZ ), self .dt )
4546
4647 def update_live_torque_params (self , latAccelFactor , latAccelOffset , friction ):
4748 self .torque_params .latAccelFactor = latAccelFactor
@@ -55,6 +56,7 @@ def update_limits(self):
5556
5657 def update (self , active , CS , VM , params , steer_limited_by_safety , desired_curvature , curvature_limited , lat_delay ):
5758 pid_log = log .ControlsState .LateralTorqueState .new_message ()
59+ pid_log .version = VERSION
5860 if not active :
5961 output_torque = 0.0
6062 pid_log .active = False
@@ -64,25 +66,23 @@ def update(self, active, CS, VM, params, steer_limited_by_safety, desired_curvat
6466 curvature_deadzone = abs (VM .calc_curvature (math .radians (self .steering_angle_deadzone_deg ), CS .vEgo , 0.0 ))
6567 lateral_accel_deadzone = curvature_deadzone * CS .vEgo ** 2
6668
67- delay_frames = int (np .clip (lat_delay / self .dt , 1 , self .LATACCEL_REQUEST_BUFFER_NUM_FRAMES ))
68- expected_lateral_accel = self .requested_lateral_accel_buffer [- delay_frames ]
69+ delay_frames = int (np .clip (lat_delay / self .dt , 1 , self .lat_accel_request_buffer_len ))
70+ expected_lateral_accel = self .lat_accel_request_buffer [- delay_frames ]
6971 # TODO factor out lateral jerk from error to later replace it with delay independent alternative
7072 future_desired_lateral_accel = desired_curvature * CS .vEgo ** 2
71- self .requested_lateral_accel_buffer .append (future_desired_lateral_accel )
73+ self .lat_accel_request_buffer .append (future_desired_lateral_accel )
7274 gravity_adjusted_future_lateral_accel = future_desired_lateral_accel - roll_compensation
7375 desired_lateral_jerk = (future_desired_lateral_accel - expected_lateral_accel ) / lat_delay
7476
7577 measurement = measured_curvature * CS .vEgo ** 2
7678 measurement_rate = self .measurement_rate_filter .update ((measurement - self .previous_measurement ) / self .dt )
7779 self .previous_measurement = measurement
7880
79- low_speed_factor = (np .interp (CS .vEgo , LOW_SPEED_X , LOW_SPEED_Y ) / max (CS .vEgo , MIN_SPEED )) ** 2
8081 setpoint = lat_delay * desired_lateral_jerk + expected_lateral_accel
8182 error = setpoint - measurement
82- error_lsf = error + low_speed_factor / KP * error
8383
8484 # do error correction in lateral acceleration space, convert at end to handle non-linear torque responses correctly
85- pid_log .error = float (error_lsf )
85+ pid_log .error = float (error )
8686 ff = gravity_adjusted_future_lateral_accel
8787 # latAccelOffset corrects roll compensation bias from device roll misalignment relative to car roll
8888 ff -= self .torque_params .latAccelOffset
@@ -102,9 +102,10 @@ def update(self, active, CS, VM, params, steer_limited_by_safety, desired_curvat
102102 pid_log .i = float (self .pid .i )
103103 pid_log .d = float (self .pid .d )
104104 pid_log .f = float (self .pid .f )
105- pid_log .output = float (- output_torque ) # TODO: log lat accel?
105+ pid_log .output = float (- output_torque ) # TODO: log lat accel?
106106 pid_log .actualLateralAccel = float (measurement )
107107 pid_log .desiredLateralAccel = float (setpoint )
108+ pid_log .desiredLateralJerk = float (desired_lateral_jerk )
108109 pid_log .saturated = bool (self ._check_saturation (self .steer_max - abs (output_torque ) < 1e-3 , CS , steer_limited_by_safety , curvature_limited ))
109110
110111 # TODO left is positive in this convention
0 commit comments