import math
from cereal import car , log
from selfdrive . controls . lib . latcontrol import LatControl , MIN_STEER_SPEED
from selfdrive . controls . lib . pid import PIDController
SteerControlType = car . CarParams . SteerControlType
STEER_ANGLE_SATURATION_THRESHOLD = 2.5 # Degrees
class LatControlPID ( LatControl ) :
def __init__ ( self , CP , CI ) :
super ( ) . __init__ ( CP , CI )
kargs = { }
if self . CP . steerControlType == SteerControlType . torque :
kargs . update ( { " pos_limit " : self . steer_max , " neg_limit " : - self . steer_max } )
self . pid = PIDController ( ( CP . lateralTuning . pid . kpBP , CP . lateralTuning . pid . kpV ) ,
( CP . lateralTuning . pid . kiBP , CP . lateralTuning . pid . kiV ) ,
k_f = CP . lateralTuning . pid . kf , * * kargs )
self . get_steer_feedforward = CI . get_steer_feedforward_function ( )
def reset ( self ) :
super ( ) . reset ( )
self . pid . reset ( )
def update ( self , active , CS , VM , params , last_actuators , steer_limited , desired_curvature , desired_curvature_rate , llk ) :
pid_log = log . ControlsState . LateralPIDState . new_message ( )
pid_log . steeringAngleDeg = float ( CS . steeringAngleDeg )
pid_log . steeringRateDeg = float ( CS . steeringRateDeg )
angle_steers_des_no_offset = math . degrees ( VM . get_steer_from_curvature ( - desired_curvature , CS . vEgo , params . roll ) )
angle_steers_des = angle_steers_des_no_offset #+ params.angleOffsetDeg
error = angle_steers_des - CS . steeringAngleDeg
pid_log . steeringAngleDesiredDeg = angle_steers_des
pid_log . angleError = error
if CS . vEgo < MIN_STEER_SPEED or not active :
output_steer = 0.0
pid_log . active = False
self . pid . reset ( )
else :
# offset does not contribute to resistive torque
steer_feedforward = self . get_steer_feedforward ( angle_steers_des_no_offset , CS . vEgo )
output_steer = self . pid . update ( error , override = CS . steeringPressed ,
feedforward = steer_feedforward , speed = CS . vEgo )
pid_log . active = True
pid_log . p = self . pid . p
pid_log . i = self . pid . i
pid_log . f = self . pid . f
pid_log . output = output_steer
if self . CP . steerControlType != SteerControlType . torque :
angle_control_saturated = abs ( angle_steers_des - CS . steeringAngleDeg ) > STEER_ANGLE_SATURATION_THRESHOLD
pid_log . saturated = self . _check_saturation ( angle_control_saturated , CS , steer_limited )
else :
pid_log . saturated = self . _check_saturation ( self . steer_max - abs ( output_steer ) < 1e-3 , CS , steer_limited )
if self . CP . steerControlType != SteerControlType . torque :
angle_steers_des = output_steer
output_steer = 0
return output_steer , angle_steers_des , pid_log