from cereal import car
from collections import defaultdict
from common . numpy_fast import interp
from opendbc . can . can_define import CANDefine
from opendbc . can . parser import CANParser
from selfdrive . config import Conversions as CV
from selfdrive . car . interfaces import CarStateBase
from selfdrive . car . honda . values import CAR , DBC , STEER_THRESHOLD , SPEED_FACTOR , HONDA_BOSCH
def calc_cruise_offset ( offset , speed ) :
# euristic formula so that speed is controlled to ~ 0.3m/s below pid_speed
# constraints to solve for _K0, _K1, _K2 are:
# - speed = 0m/s, out = -0.3
# - speed = 34m/s, offset = 20, out = -0.25
# - speed = 34m/s, offset = -2.5, out = -1.8
_K0 = - 0.3
_K1 = - 0.01879
_K2 = 0.01013
return min ( _K0 + _K1 * speed + _K2 * speed * offset , 0. )
def get_can_signals ( CP ) :
# this function generates lists for signal, messages and initial values
signals = [
( " XMISSION_SPEED " , " ENGINE_DATA " , 0 ) ,
( " WHEEL_SPEED_FL " , " WHEEL_SPEEDS " , 0 ) ,
( " WHEEL_SPEED_FR " , " WHEEL_SPEEDS " , 0 ) ,
( " WHEEL_SPEED_RL " , " WHEEL_SPEEDS " , 0 ) ,
( " WHEEL_SPEED_RR " , " WHEEL_SPEEDS " , 0 ) ,
( " STEER_ANGLE " , " STEERING_SENSORS " , 0 ) ,
( " STEER_ANGLE_RATE " , " STEERING_SENSORS " , 0 ) ,
( " MOTOR_TORQUE " , " STEER_MOTOR_TORQUE " , 0 ) ,
( " STEER_TORQUE_SENSOR " , " STEER_STATUS " , 0 ) ,
( " LEFT_BLINKER " , " SCM_FEEDBACK " , 0 ) ,
( " RIGHT_BLINKER " , " SCM_FEEDBACK " , 0 ) ,
( " GEAR " , " GEARBOX " , 0 ) ,
( " SEATBELT_DRIVER_LAMP " , " SEATBELT_STATUS " , 1 ) ,
( " SEATBELT_DRIVER_LATCHED " , " SEATBELT_STATUS " , 0 ) ,
( " BRAKE_PRESSED " , " POWERTRAIN_DATA " , 0 ) ,
( " BRAKE_SWITCH " , " POWERTRAIN_DATA " , 0 ) ,
( " CRUISE_BUTTONS " , " SCM_BUTTONS " , 0 ) ,
( " ESP_DISABLED " , " VSA_STATUS " , 1 ) ,
( " USER_BRAKE " , " VSA_STATUS " , 0 ) ,
( " BRAKE_HOLD_ACTIVE " , " VSA_STATUS " , 0 ) ,
( " STEER_STATUS " , " STEER_STATUS " , 5 ) ,
( " GEAR_SHIFTER " , " GEARBOX " , 0 ) ,
( " PEDAL_GAS " , " POWERTRAIN_DATA " , 0 ) ,
( " CRUISE_SETTING " , " SCM_BUTTONS " , 0 ) ,
( " ACC_STATUS " , " POWERTRAIN_DATA " , 0 ) ,
]
checks = [
( " ENGINE_DATA " , 100 ) ,
( " WHEEL_SPEEDS " , 50 ) ,
( " STEERING_SENSORS " , 100 ) ,
( " SEATBELT_STATUS " , 10 ) ,
( " CRUISE " , 10 ) ,
( " POWERTRAIN_DATA " , 100 ) ,
( " VSA_STATUS " , 50 ) ,
]
if CP . carFingerprint == CAR . ODYSSEY_CHN :
checks + = [
( " SCM_FEEDBACK " , 25 ) ,
( " SCM_BUTTONS " , 50 ) ,
]
else :
checks + = [
( " SCM_FEEDBACK " , 10 ) ,
( " SCM_BUTTONS " , 25 ) ,
]
if CP . carFingerprint in ( CAR . CRV_HYBRID , CAR . CIVIC_BOSCH_DIESEL ) :
checks + = [
( " GEARBOX " , 50 ) ,
]
else :
checks + = [
( " GEARBOX " , 100 ) ,
]
if CP . radarOffCan :
# Civic is only bosch to use the same brake message as other hondas.
if CP . carFingerprint not in ( CAR . ACCORDH , CAR . CIVIC_BOSCH , CAR . CIVIC_BOSCH_DIESEL , CAR . CRV_HYBRID , CAR . INSIGHT ) :
signals + = [ ( " BRAKE_PRESSED " , " BRAKE_MODULE " , 0 ) ]
checks + = [ ( " BRAKE_MODULE " , 50 ) ]
signals + = [ ( " CAR_GAS " , " GAS_PEDAL_2 " , 0 ) ,
( " MAIN_ON " , " SCM_FEEDBACK " , 0 ) ,
( " CRUISE_CONTROL_LABEL " , " ACC_HUD " , 0 ) ,
( " EPB_STATE " , " EPB_STATUS " , 0 ) ,
( " CRUISE_SPEED " , " ACC_HUD " , 0 ) ]
checks + = [ ( " GAS_PEDAL_2 " , 100 ) ]
else :
# Nidec signals.
signals + = [ ( " BRAKE_ERROR_1 " , " STANDSTILL " , 1 ) ,
( " BRAKE_ERROR_2 " , " STANDSTILL " , 1 ) ,
( " CRUISE_SPEED_PCM " , " CRUISE " , 0 ) ,
( " CRUISE_SPEED_OFFSET " , " CRUISE_PARAMS " , 0 ) ]
checks + = [ ( " STANDSTILL " , 50 ) ]
if CP . carFingerprint == CAR . ODYSSEY_CHN :
checks + = [ ( " CRUISE_PARAMS " , 10 ) ]
else :
checks + = [ ( " CRUISE_PARAMS " , 50 ) ]
if CP . carFingerprint in ( CAR . ACCORD , CAR . ACCORD_15 , CAR . ACCORDH , CAR . CIVIC_BOSCH , CAR . CIVIC_BOSCH_DIESEL , CAR . CRV_HYBRID , CAR . INSIGHT ) :
signals + = [ ( " DRIVERS_DOOR_OPEN " , " SCM_FEEDBACK " , 1 ) ]
elif CP . carFingerprint == CAR . ODYSSEY_CHN :
signals + = [ ( " DRIVERS_DOOR_OPEN " , " SCM_BUTTONS " , 1 ) ]
elif CP . carFingerprint == CAR . HRV :
signals + = [ ( " DRIVERS_DOOR_OPEN " , " SCM_BUTTONS " , 1 ) ,
( " WHEELS_MOVING " , " STANDSTILL " , 1 ) ]
else :
signals + = [ ( " DOOR_OPEN_FL " , " DOORS_STATUS " , 1 ) ,
( " DOOR_OPEN_FR " , " DOORS_STATUS " , 1 ) ,
( " DOOR_OPEN_RL " , " DOORS_STATUS " , 1 ) ,
( " DOOR_OPEN_RR " , " DOORS_STATUS " , 1 ) ,
( " WHEELS_MOVING " , " STANDSTILL " , 1 ) ]
checks + = [ ( " DOORS_STATUS " , 3 ) ]
if CP . carFingerprint == CAR . CIVIC :
signals + = [ ( " CAR_GAS " , " GAS_PEDAL_2 " , 0 ) ,
( " MAIN_ON " , " SCM_FEEDBACK " , 0 ) ,
( " IMPERIAL_UNIT " , " HUD_SETTING " , 0 ) ,
( " EPB_STATE " , " EPB_STATUS " , 0 ) ]
elif CP . carFingerprint == CAR . ACURA_ILX :
signals + = [ ( " CAR_GAS " , " GAS_PEDAL_2 " , 0 ) ,
( " MAIN_ON " , " SCM_BUTTONS " , 0 ) ]
elif CP . carFingerprint in ( CAR . CRV , CAR . CRV_EU , CAR . ACURA_RDX , CAR . PILOT_2019 , CAR . RIDGELINE ) :
signals + = [ ( " MAIN_ON " , " SCM_BUTTONS " , 0 ) ]
elif CP . carFingerprint in ( CAR . FIT , CAR . HRV ) :
signals + = [ ( " CAR_GAS " , " GAS_PEDAL_2 " , 0 ) ,
( " MAIN_ON " , " SCM_BUTTONS " , 0 ) ,
( " BRAKE_HOLD_ACTIVE " , " VSA_STATUS " , 0 ) ]
elif CP . carFingerprint == CAR . ODYSSEY :
signals + = [ ( " MAIN_ON " , " SCM_FEEDBACK " , 0 ) ,
( " EPB_STATE " , " EPB_STATUS " , 0 ) ]
checks + = [ ( " EPB_STATUS " , 50 ) ]
elif CP . carFingerprint == CAR . PILOT :
signals + = [ ( " MAIN_ON " , " SCM_BUTTONS " , 0 ) ,
( " CAR_GAS " , " GAS_PEDAL_2 " , 0 ) ]
elif CP . carFingerprint == CAR . ODYSSEY_CHN :
signals + = [ ( " MAIN_ON " , " SCM_BUTTONS " , 0 ) ,
( " EPB_STATE " , " EPB_STATUS " , 0 ) ]
checks + = [ ( " EPB_STATUS " , 50 ) ]
# add gas interceptor reading if we are using it
if CP . enableGasInterceptor :
signals . append ( ( " INTERCEPTOR_GAS " , " GAS_SENSOR " , 0 ) )
signals . append ( ( " INTERCEPTOR_GAS2 " , " GAS_SENSOR " , 0 ) )
checks . append ( ( " GAS_SENSOR " , 50 ) )
return signals , checks
class CarState ( CarStateBase ) :
def __init__ ( self , CP ) :
super ( ) . __init__ ( CP )
can_define = CANDefine ( DBC [ CP . carFingerprint ] [ ' pt ' ] )
self . shifter_values = can_define . dv [ " GEARBOX " ] [ " GEAR_SHIFTER " ]
self . steer_status_values = defaultdict ( lambda : " UNKNOWN " , can_define . dv [ " STEER_STATUS " ] [ " STEER_STATUS " ] )
self . user_gas , self . user_gas_pressed = 0. , 0
self . brake_switch_prev = 0
self . brake_switch_ts = 0
self . cruise_setting = 0
self . v_cruise_pcm_prev = 0
self . cruise_mode = 0
def update ( self , cp , cp_cam ) :
ret = car . CarState . new_message ( )
# car params
v_weight_v = [ 0. , 1. ] # don't trust smooth speed at low values to avoid premature zero snapping
v_weight_bp = [ 1. , 6. ] # smooth blending, below ~0.6m/s the smooth speed snaps to zero
# update prevs, update must run once per loop
self . prev_cruise_buttons = self . cruise_buttons
self . prev_cruise_setting = self . cruise_setting
# ******************* parse out can *******************
if self . CP . carFingerprint in ( CAR . ACCORD , CAR . ACCORD_15 , CAR . ACCORDH , CAR . CIVIC_BOSCH , CAR . CIVIC_BOSCH_DIESEL , CAR . CRV_HYBRID , CAR . INSIGHT ) : # TODO: find wheels moving bit in dbc
ret . standstill = cp . vl [ " ENGINE_DATA " ] [ ' XMISSION_SPEED ' ] < 0.1
ret . doorOpen = bool ( cp . vl [ " SCM_FEEDBACK " ] [ ' DRIVERS_DOOR_OPEN ' ] )
elif self . CP . carFingerprint == CAR . ODYSSEY_CHN :
ret . standstill = cp . vl [ " ENGINE_DATA " ] [ ' XMISSION_SPEED ' ] < 0.1
ret . doorOpen = bool ( cp . vl [ " SCM_BUTTONS " ] [ ' DRIVERS_DOOR_OPEN ' ] )
elif self . CP . carFingerprint == CAR . HRV :
ret . doorOpen = bool ( cp . vl [ " SCM_BUTTONS " ] [ ' DRIVERS_DOOR_OPEN ' ] )
else :
ret . standstill = not cp . vl [ " STANDSTILL " ] [ ' WHEELS_MOVING ' ]
ret . doorOpen = any ( [ cp . vl [ " DOORS_STATUS " ] [ ' DOOR_OPEN_FL ' ] , cp . vl [ " DOORS_STATUS " ] [ ' DOOR_OPEN_FR ' ] ,
cp . vl [ " DOORS_STATUS " ] [ ' DOOR_OPEN_RL ' ] , cp . vl [ " DOORS_STATUS " ] [ ' DOOR_OPEN_RR ' ] ] )
ret . seatbeltUnlatched = bool ( cp . vl [ " SEATBELT_STATUS " ] [ ' SEATBELT_DRIVER_LAMP ' ] or not cp . vl [ " SEATBELT_STATUS " ] [ ' SEATBELT_DRIVER_LATCHED ' ] )
steer_status = self . steer_status_values [ cp . vl [ " STEER_STATUS " ] [ ' STEER_STATUS ' ] ]
ret . steerError = steer_status not in [ ' NORMAL ' , ' NO_TORQUE_ALERT_1 ' , ' NO_TORQUE_ALERT_2 ' , ' LOW_SPEED_LOCKOUT ' , ' TMP_FAULT ' ]
# NO_TORQUE_ALERT_2 can be caused by bump OR steering nudge from driver
self . steer_not_allowed = steer_status not in [ ' NORMAL ' , ' NO_TORQUE_ALERT_2 ' ]
# LOW_SPEED_LOCKOUT is not worth a warning
ret . steerWarning = steer_status not in [ ' NORMAL ' , ' LOW_SPEED_LOCKOUT ' , ' NO_TORQUE_ALERT_2 ' ]
if self . CP . radarOffCan :
self . brake_error = 0
else :
self . brake_error = cp . vl [ " STANDSTILL " ] [ ' BRAKE_ERROR_1 ' ] or cp . vl [ " STANDSTILL " ] [ ' BRAKE_ERROR_2 ' ]
ret . espDisabled = cp . vl [ " VSA_STATUS " ] [ ' ESP_DISABLED ' ] != 0
speed_factor = SPEED_FACTOR [ self . CP . carFingerprint ]
ret . wheelSpeeds . fl = cp . vl [ " WHEEL_SPEEDS " ] [ ' WHEEL_SPEED_FL ' ] * CV . KPH_TO_MS * speed_factor
ret . wheelSpeeds . fr = cp . vl [ " WHEEL_SPEEDS " ] [ ' WHEEL_SPEED_FR ' ] * CV . KPH_TO_MS * speed_factor
ret . wheelSpeeds . rl = cp . vl [ " WHEEL_SPEEDS " ] [ ' WHEEL_SPEED_RL ' ] * CV . KPH_TO_MS * speed_factor
ret . wheelSpeeds . rr = cp . vl [ " WHEEL_SPEEDS " ] [ ' WHEEL_SPEED_RR ' ] * CV . KPH_TO_MS * speed_factor
v_wheel = ( ret . wheelSpeeds . fl + ret . wheelSpeeds . fr + ret . wheelSpeeds . rl + ret . wheelSpeeds . rr ) / 4.
# blend in transmission speed at low speed, since it has more low speed accuracy
v_weight = interp ( v_wheel , v_weight_bp , v_weight_v )
ret . vEgoRaw = ( 1. - v_weight ) * cp . vl [ " ENGINE_DATA " ] [ ' XMISSION_SPEED ' ] * CV . KPH_TO_MS * speed_factor + v_weight * v_wheel
ret . vEgo , ret . aEgo = self . update_speed_kf ( ret . vEgoRaw )
ret . steeringAngle = cp . vl [ " STEERING_SENSORS " ] [ ' STEER_ANGLE ' ]
ret . steeringRate = cp . vl [ " STEERING_SENSORS " ] [ ' STEER_ANGLE_RATE ' ]
self . cruise_setting = cp . vl [ " SCM_BUTTONS " ] [ ' CRUISE_SETTING ' ]
self . cruise_buttons = cp . vl [ " SCM_BUTTONS " ] [ ' CRUISE_BUTTONS ' ]
ret . leftBlinker = cp . vl [ " SCM_FEEDBACK " ] [ ' LEFT_BLINKER ' ] != 0
ret . rightBlinker = cp . vl [ " SCM_FEEDBACK " ] [ ' RIGHT_BLINKER ' ] != 0
self . brake_hold = cp . vl [ " VSA_STATUS " ] [ ' BRAKE_HOLD_ACTIVE ' ]
if self . CP . carFingerprint in ( CAR . CIVIC , CAR . ODYSSEY , CAR . CRV_5G , CAR . ACCORD , CAR . ACCORD_15 , CAR . ACCORDH , CAR . CIVIC_BOSCH , CAR . CIVIC_BOSCH_DIESEL , CAR . CRV_HYBRID , CAR . INSIGHT ) :
self . park_brake = cp . vl [ " EPB_STATUS " ] [ ' EPB_STATE ' ] != 0
main_on = cp . vl [ " SCM_FEEDBACK " ] [ ' MAIN_ON ' ]
elif self . CP . carFingerprint == CAR . ODYSSEY_CHN :
self . park_brake = cp . vl [ " EPB_STATUS " ] [ ' EPB_STATE ' ] != 0
main_on = cp . vl [ " SCM_BUTTONS " ] [ ' MAIN_ON ' ]
else :
self . park_brake = 0 # TODO
main_on = cp . vl [ " SCM_BUTTONS " ] [ ' MAIN_ON ' ]
gear = int ( cp . vl [ " GEARBOX " ] [ ' GEAR_SHIFTER ' ] )
ret . gearShifter = self . parse_gear_shifter ( self . shifter_values . get ( gear , None ) )
self . pedal_gas = cp . vl [ " POWERTRAIN_DATA " ] [ ' PEDAL_GAS ' ]
# crv doesn't include cruise control
if self . CP . carFingerprint in ( CAR . CRV , CAR . CRV_EU , CAR . ODYSSEY , CAR . ACURA_RDX , CAR . RIDGELINE , CAR . PILOT_2019 , CAR . ODYSSEY_CHN ) :
ret . gas = self . pedal_gas / 256.
else :
ret . gas = cp . vl [ " GAS_PEDAL_2 " ] [ ' CAR_GAS ' ] / 256.
# this is a hack for the interceptor. This is now only used in the simulation
# TODO: Replace tests by toyota so this can go away
if self . CP . enableGasInterceptor :
self . user_gas = ( cp . vl [ " GAS_SENSOR " ] [ ' INTERCEPTOR_GAS ' ] + cp . vl [ " GAS_SENSOR " ] [ ' INTERCEPTOR_GAS2 ' ] ) / 2.
self . user_gas_pressed = self . user_gas > 1e-5 # this works because interceptor read < 0 when pedal position is 0. Once calibrated, this will change
ret . gasPressed = self . user_gas_pressed
else :
ret . gasPressed = self . pedal_gas > 1e-5
ret . steeringTorque = cp . vl [ " STEER_STATUS " ] [ ' STEER_TORQUE_SENSOR ' ]
ret . steeringTorqueEps = cp . vl [ " STEER_MOTOR_TORQUE " ] [ ' MOTOR_TORQUE ' ]
ret . steeringPressed = abs ( ret . steeringTorque ) > STEER_THRESHOLD [ self . CP . carFingerprint ]
self . brake_switch = cp . vl [ " POWERTRAIN_DATA " ] [ ' BRAKE_SWITCH ' ] != 0
if self . CP . radarOffCan :
self . cruise_mode = cp . vl [ " ACC_HUD " ] [ ' CRUISE_CONTROL_LABEL ' ]
ret . cruiseState . standstill = cp . vl [ " ACC_HUD " ] [ ' CRUISE_SPEED ' ] == 252.
ret . cruiseState . speedOffset = calc_cruise_offset ( 0 , ret . vEgo )
if self . CP . carFingerprint in ( CAR . CIVIC_BOSCH , CAR . CIVIC_BOSCH_DIESEL , CAR . ACCORDH , CAR . CRV_HYBRID , CAR . INSIGHT ) :
ret . brakePressed = cp . vl [ " POWERTRAIN_DATA " ] [ ' BRAKE_PRESSED ' ] != 0 or \
( self . brake_switch and self . brake_switch_prev and \
cp . ts [ " POWERTRAIN_DATA " ] [ ' BRAKE_SWITCH ' ] != self . brake_switch_ts )
self . brake_switch_prev = self . brake_switch
self . brake_switch_ts = cp . ts [ " POWERTRAIN_DATA " ] [ ' BRAKE_SWITCH ' ]
else :
ret . brakePressed = cp . vl [ " BRAKE_MODULE " ] [ ' BRAKE_PRESSED ' ] != 0
# On set, cruise set speed pulses between 254~255 and the set speed prev is set to avoid this.
ret . cruiseState . speed = self . v_cruise_pcm_prev if cp . vl [ " ACC_HUD " ] [ ' CRUISE_SPEED ' ] > 160.0 else cp . vl [ " ACC_HUD " ] [ ' CRUISE_SPEED ' ] * CV . KPH_TO_MS
self . v_cruise_pcm_prev = ret . cruiseState . speed
else :
ret . cruiseState . speedOffset = calc_cruise_offset ( cp . vl [ " CRUISE_PARAMS " ] [ ' CRUISE_SPEED_OFFSET ' ] , ret . vEgo )
ret . cruiseState . speed = cp . vl [ " CRUISE " ] [ ' CRUISE_SPEED_PCM ' ] * CV . KPH_TO_MS
# brake switch has shown some single time step noise, so only considered when
# switch is on for at least 2 consecutive CAN samples
ret . brakePressed = bool ( cp . vl [ " POWERTRAIN_DATA " ] [ ' BRAKE_PRESSED ' ] or
( self . brake_switch and self . brake_switch_prev and
cp . ts [ " POWERTRAIN_DATA " ] [ ' BRAKE_SWITCH ' ] != self . brake_switch_ts ) )
self . brake_switch_prev = self . brake_switch
self . brake_switch_ts = cp . ts [ " POWERTRAIN_DATA " ] [ ' BRAKE_SWITCH ' ]
ret . brake = cp . vl [ " VSA_STATUS " ] [ ' USER_BRAKE ' ]
ret . cruiseState . enabled = cp . vl [ " POWERTRAIN_DATA " ] [ ' ACC_STATUS ' ] != 0
ret . cruiseState . available = bool ( main_on ) and self . cruise_mode == 0
# Gets rid of Pedal Grinding noise when brake is pressed at slow speeds for some models
if self . CP . carFingerprint in ( CAR . PILOT , CAR . PILOT_2019 , CAR . RIDGELINE ) :
if ret . brake > 0.05 :
ret . brakePressed = True
# TODO: discover the CAN msg that has the imperial unit bit for all other cars
self . is_metric = not cp . vl [ " HUD_SETTING " ] [ ' IMPERIAL_UNIT ' ] if self . CP . carFingerprint in ( CAR . CIVIC ) else False
if self . CP . carFingerprint in HONDA_BOSCH :
ret . stockAeb = bool ( cp_cam . vl [ " ACC_CONTROL " ] [ " AEB_STATUS " ] and cp_cam . vl [ " ACC_CONTROL " ] [ " ACCEL_COMMAND " ] < - 1e-5 )
else :
ret . stockAeb = bool ( cp_cam . vl [ " BRAKE_COMMAND " ] [ " AEB_REQ_1 " ] and cp_cam . vl [ " BRAKE_COMMAND " ] [ " COMPUTER_BRAKE " ] > 1e-5 )
if self . CP . carFingerprint in HONDA_BOSCH :
self . stock_hud = False
ret . stockFcw = False
else :
ret . stockFcw = cp_cam . vl [ " BRAKE_COMMAND " ] [ " FCW " ] != 0
self . stock_hud = cp_cam . vl [ " ACC_HUD " ]
self . stock_brake = cp_cam . vl [ " BRAKE_COMMAND " ]
return ret
@staticmethod
def get_can_parser ( CP ) :
signals , checks = get_can_signals ( CP )
bus_pt = 1 if CP . isPandaBlack and CP . carFingerprint in HONDA_BOSCH else 0
return CANParser ( DBC [ CP . carFingerprint ] [ ' pt ' ] , signals , checks , bus_pt )
@staticmethod
def get_cam_can_parser ( CP ) :
signals = [ ]
if CP . carFingerprint in HONDA_BOSCH :
signals + = [ ( " ACCEL_COMMAND " , " ACC_CONTROL " , 0 ) ,
( " AEB_STATUS " , " ACC_CONTROL " , 0 ) ]
else :
signals + = [ ( " COMPUTER_BRAKE " , " BRAKE_COMMAND " , 0 ) ,
( " AEB_REQ_1 " , " BRAKE_COMMAND " , 0 ) ,
( " FCW " , " BRAKE_COMMAND " , 0 ) ,
( " CHIME " , " BRAKE_COMMAND " , 0 ) ,
( " FCM_OFF " , " ACC_HUD " , 0 ) ,
( " FCM_OFF_2 " , " ACC_HUD " , 0 ) ,
( " FCM_PROBLEM " , " ACC_HUD " , 0 ) ,
( " ICONS " , " ACC_HUD " , 0 ) ]
# all hondas except CRV, RDX and 2019 Odyssey@China use 0xe4 for steering
checks = [ ( 0xe4 , 100 ) ]
if CP . carFingerprint in [ CAR . CRV , CAR . CRV_EU , CAR . ACURA_RDX , CAR . ODYSSEY_CHN ] :
checks = [ ( 0x194 , 100 ) ]
bus_cam = 1 if CP . carFingerprint in HONDA_BOSCH and not CP . isPandaBlack else 2
return CANParser ( DBC [ CP . carFingerprint ] [ ' pt ' ] , signals , checks , bus_cam )