You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
355 lines
14 KiB
355 lines
14 KiB
from collections import defaultdict
|
|
|
|
from cereal import car
|
|
from common.conversions import Conversions as CV
|
|
from common.numpy_fast import interp
|
|
from opendbc.can.can_define import CANDefine
|
|
from opendbc.can.parser import CANParser
|
|
from selfdrive.car.interfaces import CarStateBase
|
|
from selfdrive.car.honda.values import CAR, DBC, STEER_THRESHOLD, HONDA_BOSCH, HONDA_NIDEC_ALT_SCM_MESSAGES, HONDA_BOSCH_ALT_BRAKE_SIGNAL
|
|
|
|
TransmissionType = car.CarParams.TransmissionType
|
|
|
|
|
|
def get_can_signals(CP, gearbox_msg, main_on_sig_msg):
|
|
signals = [
|
|
("XMISSION_SPEED", "ENGINE_DATA"),
|
|
("WHEEL_SPEED_FL", "WHEEL_SPEEDS"),
|
|
("WHEEL_SPEED_FR", "WHEEL_SPEEDS"),
|
|
("WHEEL_SPEED_RL", "WHEEL_SPEEDS"),
|
|
("WHEEL_SPEED_RR", "WHEEL_SPEEDS"),
|
|
("STEER_ANGLE", "STEERING_SENSORS"),
|
|
("STEER_ANGLE_RATE", "STEERING_SENSORS"),
|
|
("MOTOR_TORQUE", "STEER_MOTOR_TORQUE"),
|
|
("STEER_TORQUE_SENSOR", "STEER_STATUS"),
|
|
("LEFT_BLINKER", "SCM_FEEDBACK"),
|
|
("RIGHT_BLINKER", "SCM_FEEDBACK"),
|
|
("GEAR", gearbox_msg),
|
|
("SEATBELT_DRIVER_LAMP", "SEATBELT_STATUS"),
|
|
("SEATBELT_DRIVER_LATCHED", "SEATBELT_STATUS"),
|
|
("BRAKE_PRESSED", "POWERTRAIN_DATA"),
|
|
("BRAKE_SWITCH", "POWERTRAIN_DATA"),
|
|
("CRUISE_BUTTONS", "SCM_BUTTONS"),
|
|
("ESP_DISABLED", "VSA_STATUS"),
|
|
("USER_BRAKE", "VSA_STATUS"),
|
|
("BRAKE_HOLD_ACTIVE", "VSA_STATUS"),
|
|
("STEER_STATUS", "STEER_STATUS"),
|
|
("GEAR_SHIFTER", gearbox_msg),
|
|
("PEDAL_GAS", "POWERTRAIN_DATA"),
|
|
("CRUISE_SETTING", "SCM_BUTTONS"),
|
|
("ACC_STATUS", "POWERTRAIN_DATA"),
|
|
("MAIN_ON", main_on_sig_msg),
|
|
]
|
|
|
|
checks = [
|
|
("ENGINE_DATA", 100),
|
|
("WHEEL_SPEEDS", 50),
|
|
("STEERING_SENSORS", 100),
|
|
("SEATBELT_STATUS", 10),
|
|
("CRUISE", 10),
|
|
("POWERTRAIN_DATA", 100),
|
|
("VSA_STATUS", 50),
|
|
("STEER_STATUS", 100),
|
|
("STEER_MOTOR_TORQUE", 0), # TODO: not on every car
|
|
]
|
|
|
|
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, CAR.ACURA_RDX_3G, CAR.HONDA_E):
|
|
checks.append((gearbox_msg, 50))
|
|
else:
|
|
checks.append((gearbox_msg, 100))
|
|
|
|
if CP.carFingerprint in HONDA_BOSCH_ALT_BRAKE_SIGNAL:
|
|
signals.append(("BRAKE_PRESSED", "BRAKE_MODULE"))
|
|
checks.append(("BRAKE_MODULE", 50))
|
|
|
|
if CP.carFingerprint in HONDA_BOSCH:
|
|
signals += [
|
|
("EPB_STATE", "EPB_STATUS"),
|
|
("IMPERIAL_UNIT", "CAR_SPEED"),
|
|
]
|
|
checks += [
|
|
("EPB_STATUS", 50),
|
|
("CAR_SPEED", 10),
|
|
]
|
|
|
|
if not CP.openpilotLongitudinalControl:
|
|
signals += [
|
|
("CRUISE_CONTROL_LABEL", "ACC_HUD"),
|
|
("CRUISE_SPEED", "ACC_HUD"),
|
|
("ACCEL_COMMAND", "ACC_CONTROL"),
|
|
("AEB_STATUS", "ACC_CONTROL"),
|
|
]
|
|
checks += [
|
|
("ACC_HUD", 10),
|
|
("ACC_CONTROL", 50),
|
|
]
|
|
else: # Nidec signals
|
|
signals += [("CRUISE_SPEED_PCM", "CRUISE"),
|
|
("CRUISE_SPEED_OFFSET", "CRUISE_PARAMS")]
|
|
|
|
if CP.carFingerprint == CAR.ODYSSEY_CHN:
|
|
checks.append(("CRUISE_PARAMS", 10))
|
|
else:
|
|
checks.append(("CRUISE_PARAMS", 50))
|
|
|
|
if CP.carFingerprint in (CAR.ACCORD, CAR.ACCORDH, CAR.CIVIC_BOSCH, CAR.CIVIC_BOSCH_DIESEL, CAR.CRV_HYBRID, CAR.INSIGHT, CAR.ACURA_RDX_3G, CAR.HONDA_E):
|
|
signals.append(("DRIVERS_DOOR_OPEN", "SCM_FEEDBACK"))
|
|
elif CP.carFingerprint == CAR.ODYSSEY_CHN:
|
|
signals.append(("DRIVERS_DOOR_OPEN", "SCM_BUTTONS"))
|
|
elif CP.carFingerprint in (CAR.FREED, CAR.HRV):
|
|
signals += [("DRIVERS_DOOR_OPEN", "SCM_BUTTONS"),
|
|
("WHEELS_MOVING", "STANDSTILL")]
|
|
else:
|
|
signals += [("DOOR_OPEN_FL", "DOORS_STATUS"),
|
|
("DOOR_OPEN_FR", "DOORS_STATUS"),
|
|
("DOOR_OPEN_RL", "DOORS_STATUS"),
|
|
("DOOR_OPEN_RR", "DOORS_STATUS"),
|
|
("WHEELS_MOVING", "STANDSTILL")]
|
|
checks += [
|
|
("DOORS_STATUS", 3),
|
|
("STANDSTILL", 50),
|
|
]
|
|
|
|
if CP.carFingerprint == CAR.CIVIC:
|
|
signals += [("IMPERIAL_UNIT", "HUD_SETTING"),
|
|
("EPB_STATE", "EPB_STATUS")]
|
|
checks += [
|
|
("HUD_SETTING", 50),
|
|
("EPB_STATUS", 50),
|
|
]
|
|
elif CP.carFingerprint in (CAR.ODYSSEY, CAR.ODYSSEY_CHN):
|
|
signals.append(("EPB_STATE", "EPB_STATUS"))
|
|
checks.append(("EPB_STATUS", 50))
|
|
|
|
# add gas interceptor reading if we are using it
|
|
if CP.enableGasInterceptor:
|
|
signals.append(("INTERCEPTOR_GAS", "GAS_SENSOR"))
|
|
signals.append(("INTERCEPTOR_GAS2", "GAS_SENSOR"))
|
|
checks.append(("GAS_SENSOR", 50))
|
|
|
|
if CP.openpilotLongitudinalControl:
|
|
signals += [
|
|
("BRAKE_ERROR_1", "STANDSTILL"),
|
|
("BRAKE_ERROR_2", "STANDSTILL")
|
|
]
|
|
checks.append(("STANDSTILL", 50))
|
|
|
|
return signals, checks
|
|
|
|
|
|
class CarState(CarStateBase):
|
|
def __init__(self, CP):
|
|
super().__init__(CP)
|
|
can_define = CANDefine(DBC[CP.carFingerprint]["pt"])
|
|
self.gearbox_msg = "GEARBOX"
|
|
if CP.carFingerprint == CAR.ACCORD and CP.transmissionType == TransmissionType.cvt:
|
|
self.gearbox_msg = "GEARBOX_15T"
|
|
|
|
self.main_on_sig_msg = "SCM_FEEDBACK"
|
|
if CP.carFingerprint in HONDA_NIDEC_ALT_SCM_MESSAGES:
|
|
self.main_on_sig_msg = "SCM_BUTTONS"
|
|
|
|
self.shifter_values = can_define.dv[self.gearbox_msg]["GEAR_SHIFTER"]
|
|
self.steer_status_values = defaultdict(lambda: "UNKNOWN", can_define.dv["STEER_STATUS"]["STEER_STATUS"])
|
|
|
|
self.brake_error = False
|
|
self.brake_switch_prev = False
|
|
self.brake_switch_active = False
|
|
self.cruise_setting = 0
|
|
self.v_cruise_pcm_prev = 0
|
|
|
|
def update(self, cp, cp_cam, cp_body):
|
|
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 *******************
|
|
# TODO: find wheels moving bit in dbc
|
|
if self.CP.carFingerprint in (CAR.ACCORD, CAR.ACCORDH, CAR.CIVIC_BOSCH, CAR.CIVIC_BOSCH_DIESEL, CAR.CRV_HYBRID, CAR.INSIGHT, CAR.ACURA_RDX_3G, CAR.HONDA_E):
|
|
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 in (CAR.FREED, CAR.HRV):
|
|
ret.standstill = not cp.vl["STANDSTILL"]["WHEELS_MOVING"]
|
|
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.steerFaultPermanent = steer_status not in ("NORMAL", "NO_TORQUE_ALERT_1", "NO_TORQUE_ALERT_2", "LOW_SPEED_LOCKOUT", "TMP_FAULT")
|
|
# LOW_SPEED_LOCKOUT is not worth a warning
|
|
# NO_TORQUE_ALERT_2 can be caused by bump or steering nudge from driver
|
|
ret.steerFaultTemporary = steer_status not in ("NORMAL", "LOW_SPEED_LOCKOUT", "NO_TORQUE_ALERT_2")
|
|
|
|
if self.CP.openpilotLongitudinalControl:
|
|
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
|
|
|
|
ret.wheelSpeeds = self.get_wheel_speeds(
|
|
cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_FL"],
|
|
cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_FR"],
|
|
cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_RL"],
|
|
cp.vl["WHEEL_SPEEDS"]["WHEEL_SPEED_RR"],
|
|
)
|
|
v_wheel = (ret.wheelSpeeds.fl + ret.wheelSpeeds.fr + ret.wheelSpeeds.rl + ret.wheelSpeeds.rr) / 4.0
|
|
|
|
# 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 * self.CP.wheelSpeedFactor + v_weight * v_wheel
|
|
ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw)
|
|
|
|
ret.steeringAngleDeg = cp.vl["STEERING_SENSORS"]["STEER_ANGLE"]
|
|
ret.steeringRateDeg = 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, ret.rightBlinker = self.update_blinker_from_stalk(
|
|
250, cp.vl["SCM_FEEDBACK"]["LEFT_BLINKER"], cp.vl["SCM_FEEDBACK"]["RIGHT_BLINKER"])
|
|
ret.brakeHoldActive = cp.vl["VSA_STATUS"]["BRAKE_HOLD_ACTIVE"] == 1
|
|
|
|
# TODO: set for all cars
|
|
if self.CP.carFingerprint in (CAR.CIVIC, CAR.ODYSSEY, CAR.ODYSSEY_CHN, CAR.CRV_5G, CAR.ACCORD, CAR.ACCORDH, CAR.CIVIC_BOSCH,
|
|
CAR.CIVIC_BOSCH_DIESEL, CAR.CRV_HYBRID, CAR.INSIGHT, CAR.ACURA_RDX_3G, CAR.HONDA_E):
|
|
ret.parkingBrake = cp.vl["EPB_STATUS"]["EPB_STATE"] != 0
|
|
|
|
gear = int(cp.vl[self.gearbox_msg]["GEAR_SHIFTER"])
|
|
ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(gear, None))
|
|
|
|
if self.CP.enableGasInterceptor:
|
|
ret.gas = (cp.vl["GAS_SENSOR"]["INTERCEPTOR_GAS"] + cp.vl["GAS_SENSOR"]["INTERCEPTOR_GAS2"]) / 2.
|
|
else:
|
|
ret.gas = cp.vl["POWERTRAIN_DATA"]["PEDAL_GAS"]
|
|
ret.gasPressed = ret.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.get(self.CP.carFingerprint, 1200)
|
|
|
|
if self.CP.carFingerprint in HONDA_BOSCH:
|
|
if not self.CP.openpilotLongitudinalControl:
|
|
ret.cruiseState.nonAdaptive = cp.vl["ACC_HUD"]["CRUISE_CONTROL_LABEL"] != 0
|
|
ret.cruiseState.standstill = cp.vl["ACC_HUD"]["CRUISE_SPEED"] == 252.
|
|
|
|
# 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.speed = cp.vl["CRUISE"]["CRUISE_SPEED_PCM"] * CV.KPH_TO_MS
|
|
|
|
if self.CP.carFingerprint in HONDA_BOSCH_ALT_BRAKE_SIGNAL:
|
|
ret.brakePressed = cp.vl["BRAKE_MODULE"]["BRAKE_PRESSED"] != 0
|
|
else:
|
|
# brake switch has shown some single time step noise, so only considered when
|
|
# switch is on for at least 2 consecutive CAN samples
|
|
# brake switch rises earlier than brake pressed but is never 1 when in park
|
|
brake_switch_vals = cp.vl_all["POWERTRAIN_DATA"]["BRAKE_SWITCH"]
|
|
if len(brake_switch_vals):
|
|
brake_switch = cp.vl["POWERTRAIN_DATA"]["BRAKE_SWITCH"] != 0
|
|
if len(brake_switch_vals) > 1:
|
|
self.brake_switch_prev = brake_switch_vals[-2] != 0
|
|
self.brake_switch_active = brake_switch and self.brake_switch_prev
|
|
self.brake_switch_prev = brake_switch
|
|
ret.brakePressed = (cp.vl["POWERTRAIN_DATA"]["BRAKE_PRESSED"] != 0) or self.brake_switch_active
|
|
|
|
ret.brake = cp.vl["VSA_STATUS"]["USER_BRAKE"]
|
|
ret.cruiseState.enabled = cp.vl["POWERTRAIN_DATA"]["ACC_STATUS"] != 0
|
|
ret.cruiseState.available = bool(cp.vl[self.main_on_sig_msg]["MAIN_ON"])
|
|
|
|
# Gets rid of Pedal Grinding noise when brake is pressed at slow speeds for some models
|
|
if self.CP.carFingerprint in (CAR.PILOT, CAR.PASSPORT, CAR.RIDGELINE):
|
|
if ret.brake > 0.1:
|
|
ret.brakePressed = True
|
|
|
|
# TODO: discover the CAN msg that has the imperial unit bit for all other cars
|
|
if self.CP.carFingerprint in (CAR.CIVIC, ):
|
|
self.is_metric = not cp.vl["HUD_SETTING"]["IMPERIAL_UNIT"]
|
|
elif self.CP.carFingerprint in HONDA_BOSCH:
|
|
self.is_metric = not cp.vl["CAR_SPEED"]["IMPERIAL_UNIT"]
|
|
else:
|
|
self.is_metric = False
|
|
|
|
if self.CP.carFingerprint in HONDA_BOSCH:
|
|
ret.stockAeb = (not self.CP.openpilotLongitudinalControl) and bool(cp.vl["ACC_CONTROL"]["AEB_STATUS"] and cp.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"]
|
|
|
|
if self.CP.enableBsm and self.CP.carFingerprint in (CAR.CRV_5G, ):
|
|
# BSM messages are on B-CAN, requires a panda forwarding B-CAN messages to CAN 0
|
|
# more info here: https://github.com/commaai/openpilot/pull/1867
|
|
ret.leftBlindspot = cp_body.vl["BSM_STATUS_LEFT"]["BSM_ALERT"] == 1
|
|
ret.rightBlindspot = cp_body.vl["BSM_STATUS_RIGHT"]["BSM_ALERT"] == 1
|
|
|
|
return ret
|
|
|
|
def get_can_parser(self, CP):
|
|
signals, checks = get_can_signals(CP, self.gearbox_msg, self.main_on_sig_msg)
|
|
bus_pt = 1 if 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 = []
|
|
checks = [
|
|
("STEERING_CONTROL", 100),
|
|
]
|
|
|
|
if CP.carFingerprint not in HONDA_BOSCH:
|
|
signals += [("COMPUTER_BRAKE", "BRAKE_COMMAND"),
|
|
("AEB_REQ_1", "BRAKE_COMMAND"),
|
|
("FCW", "BRAKE_COMMAND"),
|
|
("CHIME", "BRAKE_COMMAND"),
|
|
("FCM_OFF", "ACC_HUD"),
|
|
("FCM_OFF_2", "ACC_HUD"),
|
|
("FCM_PROBLEM", "ACC_HUD"),
|
|
("ICONS", "ACC_HUD")]
|
|
checks += [
|
|
("ACC_HUD", 10),
|
|
("BRAKE_COMMAND", 50),
|
|
]
|
|
|
|
return CANParser(DBC[CP.carFingerprint]["pt"], signals, checks, 2)
|
|
|
|
@staticmethod
|
|
def get_body_can_parser(CP):
|
|
if CP.enableBsm and CP.carFingerprint == CAR.CRV_5G:
|
|
signals = [("BSM_ALERT", "BSM_STATUS_RIGHT"),
|
|
("BSM_ALERT", "BSM_STATUS_LEFT")]
|
|
|
|
checks = [
|
|
("BSM_STATUS_LEFT", 3),
|
|
("BSM_STATUS_RIGHT", 3),
|
|
]
|
|
bus_body = 0 # B-CAN is forwarded to ACC-CAN radar side (CAN 0 on fake ethernet port)
|
|
return CANParser(DBC[CP.carFingerprint]["body"], signals, checks, bus_body)
|
|
return None
|
|
|