from common . numpy_fast import clip , interp
from opendbc . can . packer import CANPacker
from selfdrive . car . tesla . teslacan import TeslaCAN
from selfdrive . car . tesla . values import DBC , CANBUS , CarControllerParams
class CarController ( ) :
def __init__ ( self , dbc_name , CP , VM ) :
self . CP = CP
self . last_angle = 0
self . long_control_counter = 0
self . packer = CANPacker ( dbc_name )
self . pt_packer = CANPacker ( DBC [ CP . carFingerprint ] [ ' pt ' ] )
self . tesla_can = TeslaCAN ( self . packer , self . pt_packer )
def update ( self , enabled , CS , frame , actuators , cruise_cancel ) :
can_sends = [ ]
# Temp disable steering on a hands_on_fault, and allow for user override
hands_on_fault = ( CS . steer_warning == " EAC_ERROR_HANDS_ON " and CS . hands_on_level > = 3 )
lkas_enabled = enabled and ( not hands_on_fault )
if lkas_enabled :
apply_angle = actuators . steeringAngleDeg
# Angular rate limit based on speed
steer_up = ( self . last_angle * apply_angle > 0. and abs ( apply_angle ) > abs ( self . last_angle ) )
rate_limit = CarControllerParams . RATE_LIMIT_UP if steer_up else CarControllerParams . RATE_LIMIT_DOWN
max_angle_diff = interp ( CS . out . vEgo , rate_limit . speed_points , rate_limit . max_angle_diff_points )
apply_angle = clip ( apply_angle , ( self . last_angle - max_angle_diff ) , ( self . last_angle + max_angle_diff ) )
# To not fault the EPS
apply_angle = clip ( apply_angle , ( CS . out . steeringAngleDeg - 20 ) , ( CS . out . steeringAngleDeg + 20 ) )
else :
apply_angle = CS . out . steeringAngleDeg
self . last_angle = apply_angle
can_sends . append ( self . tesla_can . create_steering_control ( apply_angle , lkas_enabled , frame ) )
# Longitudinal control (40Hz)
if self . CP . openpilotLongitudinalControl and ( ( frame % 5 ) in [ 0 , 2 ] ) :
target_accel = actuators . accel
target_speed = max ( CS . out . vEgo + ( target_accel * CarControllerParams . ACCEL_TO_SPEED_MULTIPLIER ) , 0 )
max_accel = 0 if target_accel < 0 else target_accel
min_accel = 0 if target_accel > 0 else target_accel
can_sends . extend ( self . tesla_can . create_longitudinal_commands ( CS . acc_state , target_speed , min_accel , max_accel , self . long_control_counter ) )
self . long_control_counter + = 1
# Cancel on user steering override, since there is no steering torque blending
if hands_on_fault :
cruise_cancel = True
# Cancel when openpilot is not enabled anymore
if not enabled and bool ( CS . out . cruiseState . enabled ) :
cruise_cancel = True
if ( ( frame % 10 ) == 0 and cruise_cancel ) :
# Spam every possible counter value, otherwise it might not be accepted
for counter in range ( 16 ) :
can_sends . append ( self . tesla_can . create_action_request ( CS . msg_stw_actn_req , cruise_cancel , CANBUS . chassis , counter ) )
can_sends . append ( self . tesla_can . create_action_request ( CS . msg_stw_actn_req , cruise_cancel , CANBUS . autopilot_chassis , counter ) )
# TODO: HUD control
return can_sends