diff --git a/opendbc/car/byd/bydcan.py b/opendbc/car/byd/bydcan.py new file mode 100644 index 0000000000..97251f71d7 --- /dev/null +++ b/opendbc/car/byd/bydcan.py @@ -0,0 +1,129 @@ +from opendbc.car import structs + +GearShifter = structs.CarState.GearShifter +VisualAlert = structs.CarControl.HUDControl.VisualAlert + +def byd_checksum(byte_key, dat): + first_bytes_sum = sum(byte >> 4 for byte in dat) + second_bytes_sum = sum(byte & 0xF for byte in dat) + remainder = second_bytes_sum >> 4 + second_bytes_sum += byte_key >> 4 + first_bytes_sum += byte_key & 0xF + first_part = ((-first_bytes_sum + 0x9) & 0xF) + second_part = ((-second_bytes_sum + 0x9) & 0xF) + return (((first_part + (-remainder + 5)) << 4) + second_part) & 0xFF + +# MPC -> Panda -> EPS +def create_steering_control(packer, CP, cam_msg: dict, req_torque, req_prepare, active, Counter): + values = {} + values = {s: cam_msg[s] for s in [ + "AutoFullBeamState", + "LeftLaneState", + "LKAS_Config", + "SETME2_0x1", + "MPC_State", + "AutoFullBeam_OnOff", + "LKAS_Output", + "LKAS_Active", + "SETME3_0x0", + "TrafficSignRecognition_OnOff", + "SETME4_0x0", + "SETME5_0x1", + "RightLaneState", + "LKAS_State", + "SETME6_0x0", + "TrafficSignRecognition_Result", + "LKAS_AlarmType", + "SETME7_0x3", + ]} + + values["ReqHandsOnSteeringWheel"] = 0 + values["LKAS_ReqPrepare"] = req_prepare + values["Counter"] = Counter + + if active: + values.update({ + "LKAS_Output" : req_torque, + "LKAS_Active" : 1, + "LKAS_State" : 2, + }) + + data = packer.make_can_msg("ACC_MPC_STATE", 0, values)[1] + values["CheckSum"] = byd_checksum(0xAF, data) + return packer.make_can_msg("ACC_MPC_STATE", 0, values) + +# reserved for long control +def acc_command(packer, CP, cam_msg: dict, speed, enabled): + values = {} + + values = {s: cam_msg[s] for s in [ + "AccelCmd", + "ComfortBandUpper", + "ComfortBandLower", + "JerkUpperLimit", + "SETME1_0x1", + "JerkLowerLimit", + "ResumeFromStandstill", + "StandstillState", + "BrakeBehaviour", + "AccReqNotStandstill", + "AccControlActive", + "AccOverrideOrStandstill", + "EspBehaviour", + "Counter", + "SETME2_0xF", + ]} + + data = packer.make_can_msg("ACC_CMD", 0, values)[1] + values["CheckSum"] = byd_checksum(0xAF, data) + return packer.make_can_msg("ACC_CMD", 0, values) + + +# send fake torque feedback from eps to trick MPC, preventing DTC, so that safety features such as AEB still working +def create_fake_318(packer, CP, esc_msg: dict, faketorque, laks_reqprepare, laks_active , enabled, counter): + values = {} + + values = {s: esc_msg[s] for s in [ + "LKAS_Prepared", + "CruiseActivated", + "TorqueFailed", + "SETME1_0x1", + "SteerWarning", + "SteerError_1", + "SteerError_2", + "SETME2_0x0", + "MainTorque", + "SETME3_0x1", + "SETME4_0x3", + "SteerDriverTorque", + "SETME5_0xFF", + "SETME6_0xFFF", + ]} + + values["ReportHandsNotOnSteeringWheel"] = 0 + values["Counter"] = counter + + if enabled : + if laks_active: + values.update({ + "LKAS_Prepared" : 0, + "CruiseActivated" : 1, + "MainTorque" : faketorque, + }) + elif laks_reqprepare: + values.update({ + "LKAS_Prepared" : 1, + "CruiseActivated" : 0, + "MainTorque" : 0, + }) + else: + values.update({ + "LKAS_Prepared" : 0, + "CruiseActivated" : 0, + "MainTorque" : 0, + }) + + + data = packer.make_can_msg("ACC_EPS_STATE", 2, values)[1] + values["CheckSum"] = byd_checksum(0xAF, data) + return packer.make_can_msg("ACC_EPS_STATE", 2, values) diff --git a/opendbc/car/byd/carcontroller.py b/opendbc/car/byd/carcontroller.py new file mode 100644 index 0000000000..be44163cab --- /dev/null +++ b/opendbc/car/byd/carcontroller.py @@ -0,0 +1,111 @@ +from opendbc.can.packer import CANPacker +from opendbc.car import apply_driver_steer_torque_limits, structs +from opendbc.car.byd import bydcan +from openpilot.common.numpy_fast import clip +from opendbc.car.byd.values import CarControllerParams +from opendbc.car.interfaces import CarControllerBase + +VisualAlert = structs.CarControl.HUDControl.VisualAlert +ButtonType = structs.CarState.ButtonEvent.Type + +STEER_STEP = 2 #100/2=50hz +ACC_STEP = 2 #50hz + +STEER_SOFTSTART_STEP = 6 # 20ms(50Hz) * 200 / 6 = 666ms. This means the clip ceiling will be increased to 200 in 666ms + +class CarController(CarControllerBase): + def __init__(self, dbc_name, CP): + super().__init__(dbc_name, CP) + + self.packer = CANPacker(dbc_name) + self.params = CarControllerParams(self.CP) + + self.last_steer_frame = 0 + self.last_acc_frame = 0 + + self.apply_steer_last = 0 + + self.mpc_lkas_counter = 0 + self.mpc_acc_counter = 0 + self.eps_fake318_counter = 0 + + self.lkas_req_prepare = 0 + self.lkas_active = 0 + + self.steer_softstart_limit = 0 + + self.first_start = True + + + def update(self, CC, CS, now_nanos): + can_sends = [] + + if (self.frame - self.last_steer_frame) >= STEER_STEP: + + #Resolve counter mismatch problem + if self.first_start: + self.mpc_lkas_counter = CS.acc_mpc_state_counter + self.mpc_acc_counter = CS.acc_cmd_counter + self.eps_fake318_counter = CS.eps_state_counter + self.first_start = False + + apply_steer = 0 + + if CC.latActive : + if self.lkas_active: + new_steer = int(round(CC.actuators.steer * CarControllerParams.STEER_MAX)) + + if self.steer_softstart_limit < CarControllerParams.STEER_MAX : + self.steer_softstart_limit = self.steer_softstart_limit + STEER_SOFTSTART_STEP + new_steer = clip(new_steer, -self.steer_softstart_limit, self.steer_softstart_limit) + + apply_steer = apply_driver_steer_torque_limits(new_steer, self.apply_steer_last, + CS.out.steeringTorque, CarControllerParams) + + else : + if CS.lkas_prepared: + self.lkas_active = 1 + self.lkas_req_prepare = 0 + self.steer_softstart_limit = 0 + else: + self.lkas_req_prepare = 1 + + else : + self.lkas_req_prepare = 0 + self.lkas_active = 0 + self.soft_start_torque_limit = 0 + self.steer_softstart_limit = 0 + + self.apply_steer_last = apply_steer + + self.mpc_lkas_counter = int(self.mpc_lkas_counter + 1) & 0xF + self.eps_fake318_counter = int(self.eps_fake318_counter + 1) & 0xF + self.last_steer_frame = self.frame + + # send steering command, op to esc + can_sends.append(bydcan.create_steering_control(self.packer, self.CP, CS.cam_lkas, + self.apply_steer_last, self.lkas_req_prepare, self.lkas_active, self.mpc_lkas_counter)) + + # send fake 318 from op to mpc + can_sends.append(bydcan.create_fake_318(self.packer, self.CP, CS.esc_eps, + CS.mpc_laks_output, CS.mpc_laks_reqprepare, CS.mpc_laks_active, + CC.latActive, self.eps_fake318_counter)) + + + #handle wrap around // note not necessary for python 3 as int has no limit, good for lazy people + #if self.frame < self.last_acc_frame: + # self.last_acc_frame = self.frame - 1 + + accel = 0 + if (self.frame - self.last_acc_frame) >= ACC_STEP: + accel = clip(CC.actuators.accel, CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX) + + self.last_acc_frame = self.frame + can_sends.append(bydcan.acc_command(self.packer, self.CP, CS.cam_acc, accel, CC.enabled)) + + new_actuators = CC.actuators.as_builder() + new_actuators.steer = self.apply_steer_last / CarControllerParams.STEER_MAX + new_actuators.steerOutputCan = self.apply_steer_last + + self.frame += 1 + return new_actuators, can_sends diff --git a/opendbc/car/byd/carstate.py b/opendbc/car/byd/carstate.py new file mode 100644 index 0000000000..ada5719260 --- /dev/null +++ b/opendbc/car/byd/carstate.py @@ -0,0 +1,179 @@ +import copy +from opendbc.can.can_define import CANDefine +from opendbc.can.parser import CANParser +from opendbc.car import structs +from opendbc.car.common.conversions import Conversions as CV +#from opendbc.car.common.numpy_fast import mean +from opendbc.car.interfaces import CarStateBase +from opendbc.car.byd.values import DBC + +ButtonType = structs.CarState.ButtonEvent.Type + +class CarState(CarStateBase): + def __init__(self, CP): + super().__init__(CP) + + can_define = CANDefine(DBC[CP.carFingerprint]["pt"]) + self.shifter_values = can_define.dv["DRIVE_STATE"]["Gear"] + + self.acc_hud_adas_counter = 0 + self.acc_mpc_state_counter = 0 + self.acc_cmd_counter = 0 + + self.acc_active_last = False + self.low_speed_alert = False + self.lkas_allowed_speed = False + + self.lkas_prepared = False #318, EPS to OP + self.acc_state = 0 + + self.mpc_laks_output = 0 + self.mpc_laks_active = False + self.mpc_laks_reqprepare = False + + self.cam_lkas = 0 + self.cam_acc = 0 + self.esc_eps = 0 + + #self.button_states = {button.event_type: False for button in BUTTONS} + + + def update(self, cp, cp_cam, *_) -> structs.CarState: # type: ignore + ret = structs.CarState() + + #self.distance_button = cp.vl["PCM_BUTTONS"]["BTN_AccDistanceIncrease"] + + self.lkas_prepared = cp.vl["ACC_EPS_STATE"]["LKAS_Prepared"] + + lkas_config_isAccOn = (cp_cam.vl["ACC_MPC_STATE"]["LKAS_Config"] != 0) + lkas_isMainSwOn = (cp.vl["PCM_BUTTONS"]["BTN_TOGGLE_ACC_OnOff"] == 1) + + lkas_hud_AccOn1 = (cp_cam.vl["ACC_HUD_ADAS"]["AccOn1"] == 1) + self.acc_state = cp_cam.vl["ACC_HUD_ADAS"]["AccState"] + + # use wheels averages if you like + # ret.wheelSpeeds = self.get_wheel_speeds( + # cp.vl["IPB1"]["WheelSpeed_FL"], + # cp.vl["IPB1"]["WheelSpeed_FR"], + # cp.vl["IPB1"]["WheelSpeed_RL"], + # cp.vl["IPB1"]["WheelSpeed_RR"], + # ) + #speed_kph = mean([ret.wheelSpeeds.fl, ret.wheelSpeeds.fr, ret.wheelSpeeds.rl, ret.wheelSpeeds.rr]) + + # use dash speedo as speed reference + speed_raw = int(cp.vl["CARSPEED"]["CarDisplaySpeed"]) + speed_kph = speed_raw * 0.07143644 #this constant varies with vehicles + ret.vEgoRaw = speed_kph * CV.KPH_TO_MS # KPH to m/s + ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw) + + ret.standstill = (speed_raw == 0) + + if self.CP.minSteerSpeed > 0: + if speed_kph > 2: + self.lkas_allowed_speed = True + elif speed_kph < 0.1: + self.lkas_allowed_speed = False + else: + self.lkas_allowed_speed = True + + can_gear = int(cp.vl["DRIVE_STATE"]["Gear"]) + ret.gearShifter = self.parse_gear_shifter(self.shifter_values.get(can_gear, None)) + + #for button in BUTTONS: + # state = (cp.vl[button.can_addr][button.can_msg] in button.values) + # if self.button_states[button.event_type] != state: + # event = structs.CarState.ButtonEvent.new_message() + # event.type = button.event_type + # event.pressed = state + # self.button_events.append(event) + # self.button_states[button.event_type] = state + + + #ret.genericToggle = bool(cp.vl["STALKS"]["HeadLight"]) + + #ret.leftBlindspot = cp.vl["BSD_RADAR"]["LEFT_ROACH"] != 0 + #ret.rightBlindspot = cp.vl["BSD_RADAR"]["RIGHT_ROACH"] != 0 + + ret.leftBlinker = (cp.vl["STALKS"]["LeftIndicator"] == 1) + ret.rightBlinker = (cp.vl["STALKS"]["RightIndicator"] == 1) + + ret.steeringAngleDeg = cp.vl["EPS"]["SteeringAngle"] + ret.steeringRateDeg = cp.vl["EPS"]["SteeringAngleRate"] + + ret.steeringTorque = cp.vl["ACC_EPS_STATE"]["SteerDriverTorque"] + ret.steeringTorqueEps = cp.vl["ACC_EPS_STATE"]["MainTorque"] + + self.eps_state_counter = int(cp.vl["ACC_EPS_STATE"]["Counter"]) + + ret.steeringPressed = abs(ret.steeringTorque) > 30 + + ret.brake = int(cp.vl["PEDAL"]["BrakePedal"]) + + ret.brakePressed = (ret.brake != 0) + + ret.seatbeltUnlatched = (cp.vl["BCM"]["DriverSeatBeltFasten"] != 1) + + ret.doorOpen = any([cp.vl["BCM"]["FrontLeftDoor"], cp.vl["BCM"]["FrontRightDoor"], + cp.vl["BCM"]["RearLeftDoor"], cp.vl["BCM"]["RearRightDoor"]]) + + ret.gas = cp.vl["PEDAL"]["AcceleratorPedal"] + ret.gasPressed = (ret.gas != 0) + + ret.cruiseState.available = lkas_isMainSwOn and lkas_config_isAccOn and lkas_hud_AccOn1 + ret.cruiseState.enabled = (self.acc_state == 3) or (self.acc_state == 5) + ret.cruiseState.standstill = ret.standstill + ret.cruiseState.speed = cp_cam.vl["ACC_HUD_ADAS"]["SetSpeed"] * CV.KPH_TO_MS + + if ret.cruiseState.enabled: + if not self.lkas_allowed_speed and self.acc_active_last: + self.low_speed_alert = True + else: + self.low_speed_alert = False + ret.lowSpeedAlert = self.low_speed_alert + + ret.steerFaultTemporary = (self.acc_state == 7) + + self.acc_active_last = ret.cruiseState.enabled + + self.mpc_laks_output = cp_cam.vl["ACC_MPC_STATE"]["LKAS_Output"] #use to fool mpc + self.mpc_laks_reqprepare = cp_cam.vl["ACC_MPC_STATE"]["LKAS_ReqPrepare"] != 0 #use to fool mpc + self.mpc_laks_active = cp_cam.vl["ACC_MPC_STATE"]["LKAS_Active"] != 0 #use to fool mpc + + self.acc_hud_adas_counter = cp_cam.vl["ACC_HUD_ADAS"]["Counter"] + self.acc_mpc_state_counter = cp_cam.vl["ACC_MPC_STATE"]["Counter"] + self.acc_cmd_counter = cp_cam.vl["ACC_CMD"]["Counter"] + + + self.cam_lkas = copy.copy(cp_cam.vl["ACC_MPC_STATE"]) + self.cam_adas = copy.copy(cp_cam.vl["ACC_HUD_ADAS"]) + self.cam_acc = copy.copy(cp_cam.vl["ACC_CMD"]) + self.esc_eps = copy.copy(cp.vl["ACC_EPS_STATE"]) + + ret.steerFaultPermanent = (cp.vl["ACC_EPS_STATE"]["TorqueFailed"] == 1) #EPS give up all inputs until restart + + return ret + + @staticmethod + def get_can_parser(CP): + messages = [ + ("EPS", 100), + ("CARSPEED", 50), + ("PEDAL", 50), + ("ACC_EPS_STATE", 50), + ("DRIVE_STATE", 50), + ("STALKS", 1), + ("BCM", 1), + ("PCM_BUTTONS", 20), + ] + + return CANParser(DBC[CP.carFingerprint]["pt"], messages, 0) + + @staticmethod + def get_cam_can_parser(CP): + messages = [ + ("ACC_HUD_ADAS", 50), + ("ACC_CMD", 50), + ("ACC_MPC_STATE", 50), + ] + + return CANParser(DBC[CP.carFingerprint]["pt"], messages, 2) diff --git a/opendbc/car/byd/fingerprints.py b/opendbc/car/byd/fingerprints.py new file mode 100644 index 0000000000..651819c52b --- /dev/null +++ b/opendbc/car/byd/fingerprints.py @@ -0,0 +1,15 @@ +from opendbc.car.byd.values import CAR + +FINGERPRINTS = { + CAR.HAN_DM_20: [{ + 85: 8, 140: 8, 213: 8, 269: 8, 287: 5, 289: 8, 290: 8, 291: 8, 301: 8, 303: 8, 307: 8, 309: 8, 315: 8, 384: 8, 496: 8, 530: 8, 536: 8, 544: 8, 546: 8, 547: 8, 576: 8, 578: 8, 588: 8, 660: 8, 694: 8, 790: 8, 792: 8, 797: 8, 798: 8, 801: 8, 802: 8, 813: 8, 814: 8, 815: 8, 833: 8, 834: 8, 836: 8, 843: 8, 860: 8, 884: 8, 916: 8, 918: 8, 926: 8, 940: 8, 941: 8, 944: 8, 948: 8, 985: 8, 988: 8, 1004: 8, 1020: 8, 1037: 8, 1040: 8, 1058: 8, 1074: 8, 1141: 8, 1172: 8, 1178: 8, 1180: 8, 1193: 8, 1246: 8, 1293: 8, 1793: 8, 1796: 8, 1804: 8, 1904: 8, 1905: 8, 1912: 8, 1913: 8, 1986: 8, 2004: 8, 2034: 8, 2042: 8 + }], + CAR.HAN_EV_20: [{ + 85: 8, 140: 8, 213: 8, 287: 5, 289: 8, 290: 8, 291: 8, 301: 8, 303: 8, 307: 8, 308: 8, 309: 8, 315: 8, 464: 8, 465: 8, 480: 8, 496: 8, 536: 8, 544: 8, 546: 8, 547: 8, 576: 8, 578: 8, 588: 8, 660: 8, 694: 8, 790: 8, 792: 8, 797: 8, 798: 8, 801: 8, 802: 8, 812: 8, 813: 8, 814: 8, 815: 8, 833: 8, 834: 8, 836: 8, 843: 8, 860: 8, 863: 8, 879: 8, 884: 8, 916: 8, 918: 8, 920: 8, 926: 8, 940: 8, 941: 8, 944: 8, 948: 8, 965: 8, 976: 8, 985: 8, 988: 8, 1004: 8, 1020: 8, 1036: 8, 1037: 8, 1040: 8, 1048: 8, 1058: 8, 1074: 8, 1141: 8, 1172: 8, 1178: 8, 1180: 8, 1193: 8, 1246: 8, 1268: 8, 1793: 8, 1794: 8, 1797: 8, + 1798: 8, 1801: 8, 1808: 8, 1809: 8, 1811: 8, 1812: 8, 1824: 8, 1827: 8, 1828: 8, 1829: 8, 1830: 8, 1842: 8, 1843: 8, 1845: 8, 1847: 8, 1858: 8, 1859: 8, 1862: 8, 1863: 8, 1872: 8, 1873: 8, 1874: 8, 1876: 8, 1890: 8, 1891: 8, 1894: 8, 1904: 8, 1905: 8, 1912: 8, 1913: 8, 1920: 8, 1921: 8, 1922: 8, 1923: 8, 1925: 8, 1927: 8, 1939: 8, 1940: 8, 1943: 8, 1959: 8, 1971: 8, 1973: 8, 1984: 8, 1986: 8, 1987: 8, 1991: 8, 1994: 8, 2002: 8, 2004: 8, 2006: 8, 2012: 8, 2033: 8, 2034: 8, 2042: 8 + }], +} + + +FW_VERSIONS: dict[str, dict[tuple, list[bytes]]] = { +} diff --git a/opendbc/car/byd/interface.py b/opendbc/car/byd/interface.py new file mode 100644 index 0000000000..95c8754344 --- /dev/null +++ b/opendbc/car/byd/interface.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 + +from opendbc.car import get_safety_config, structs +from opendbc.car.common.conversions import Conversions as CV +from opendbc.car.byd.values import CAR +from opendbc.car.interfaces import CarInterfaceBase + +ButtonType = structs.CarState.ButtonEvent.Type +GearShifter = structs.CarState.GearShifter + +class CarInterface(CarInterfaceBase): + @staticmethod + def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, experimental_long, docs) -> structs.CarParams: # type: ignore + ret.carName = "byd" + ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.byd)] + + ret.dashcamOnly = candidate not in (CAR.HAN_DM_20, CAR.HAN_EV_20) + + CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning) + + ret.experimentalLongitudinalAvailable = False + ret.radarUnavailable = True + + ret.minEnableSpeed = -1 + ret.minSteerSpeed = 2 * CV.KPH_TO_MS + + ret.steerActuatorDelay = 0.2 # Measured at 0.4s, however in torqued.py, line 55, code will add 0.2 + ret.steerLimitTimer = 0.4 + + ret.lateralTuning.init('pid') + ret.lateralTuning.pid.kpBP, ret.lateralTuning.pid.kiBP = [[10., 40.], [10., 40.]] + ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.16, 0.33], [0.015, 0.025]] + ret.lateralTuning.pid.kf = 0.00004 + + return ret diff --git a/opendbc/car/byd/radar_interface.py b/opendbc/car/byd/radar_interface.py new file mode 100644 index 0000000000..56bda583e2 --- /dev/null +++ b/opendbc/car/byd/radar_interface.py @@ -0,0 +1,5 @@ +#!/usr/bin/env python3 +from opendbc.car.interfaces import RadarInterfaceBase + +class RadarInterface(RadarInterfaceBase): + pass diff --git a/opendbc/car/byd/values.py b/opendbc/car/byd/values.py new file mode 100644 index 0000000000..056fb1ec4e --- /dev/null +++ b/opendbc/car/byd/values.py @@ -0,0 +1,68 @@ +from collections import namedtuple + +from opendbc.car import dbc_dict, PlatformConfig, Platforms, CarSpecs, structs +from opendbc.car.structs import CarParams +from opendbc.car.docs_definitions import CarDocs +from opendbc.car.fw_query_definitions import FwQueryConfig, Request, StdQueries + +Ecu = CarParams.Ecu +Button = namedtuple('Button', ['event_type', 'can_addr', 'can_msg', 'values']) + + +class CarControllerParams: + STEER_MAX = 300 + STEER_DELTA_UP = 17 + STEER_DELTA_DOWN = 17 + + STEER_DRIVER_ALLOWANCE = 68 + STEER_DRIVER_MULTIPLIER = 3 + STEER_DRIVER_FACTOR = 1 + STEER_ERROR_MAX = 50 + # Steer torque clip = STEER_MAX - (DriverTorque - STEER_DRIVER_ALLOWANCE) * STEER_DRIVER_MULTIPLIER (Only work when DriverTorque > STEER_DRIVER_ALLOWANCE) + # So DriverTorque(max) = STEER_MAX / STEER_DRIVER_MULTIPLIER + STEER_DRIVER_ALLOWANCE = 300/3+68 = 168 + # i.e. when drivertorque > 168, new_steer will be cliped to 0 + + STEER_STEP = 2 # 2=50 Hz + + def __init__(self, CP): + pass + + +class CAR(Platforms): + HAN_DM_20 = PlatformConfig( + [CarDocs("BYD HAN DM 20", "All")], + CarSpecs(mass=2080., wheelbase=2.920, steerRatio=15.0, centerToFrontRatio=0.44, tireStiffnessFactor=0.81), + dbc_dict('byd_han_dm_2020', None), + ) + HAN_EV_20 = PlatformConfig( + [CarDocs("BYD HAN EV 20", "All")], + CarSpecs(mass=2100., wheelbase=2.959, steerRatio=15.0), + dbc_dict('byd_han_dm_2020', None), + ) + + +FW_QUERY_CONFIG = FwQueryConfig( + requests=[ + Request( + [StdQueries.MANUFACTURER_SOFTWARE_VERSION_REQUEST], + [StdQueries.MANUFACTURER_SOFTWARE_VERSION_RESPONSE], + bus=0, + ), + ], +) + +class CanBus: + ESC = 0 + MRR = 1 + MPC = 2 + LOOPBACK = 128 + +BUTTONS = [ + Button(structs.CarState.ButtonEvent.Type.leftBlinker, "STALKS", "LeftIndicator", [0x01]), + Button(structs.CarState.ButtonEvent.Type.rightBlinker, "STALKS", "RightIndicator", [0x01]), + Button(structs.CarState.ButtonEvent.Type.accelCruise, "PCM_BUTTONS", "BTN_AccUpDown_Cmd", [0x02]), + Button(structs.CarState.ButtonEvent.Type.decelCruise, "PCM_BUTTONS", "BTN_AccUpDown_Cmd", [0x03]), + Button(structs.CarState.ButtonEvent.Type.cancel, "PCM_BUTTONS", "BTN_AccCancel", [0x01]), +] + +DBC = CAR.create_dbc_map() diff --git a/opendbc/car/car.capnp b/opendbc/car/car.capnp index 237ba2c26b..3d5ca8e4f2 100644 --- a/opendbc/car/car.capnp +++ b/opendbc/car/car.capnp @@ -622,6 +622,7 @@ struct CarParams { chryslerCusw @30; psa @31; fcaGiorgio @32; + byd @33; } enum SteerControlType { diff --git a/opendbc/car/fingerprints.py b/opendbc/car/fingerprints.py index 4619eb5443..40bbb5638a 100644 --- a/opendbc/car/fingerprints.py +++ b/opendbc/car/fingerprints.py @@ -1,5 +1,6 @@ from opendbc.car.interfaces import get_interface_attr from opendbc.car.body.values import CAR as BODY +from opendbc.car.byd.values import CAR as BYD from opendbc.car.chrysler.values import CAR as CHRYSLER from opendbc.car.ford.values import CAR as FORD from opendbc.car.gm.values import CAR as GM diff --git a/opendbc/car/values.py b/opendbc/car/values.py index 31406441f3..1773b19ffa 100644 --- a/opendbc/car/values.py +++ b/opendbc/car/values.py @@ -1,5 +1,6 @@ from typing import get_args from opendbc.car.body.values import CAR as BODY +from opendbc.car.byd.values import CAR as BYD from opendbc.car.chrysler.values import CAR as CHRYSLER from opendbc.car.ford.values import CAR as FORD from opendbc.car.gm.values import CAR as GM @@ -13,7 +14,7 @@ from opendbc.car.toyota.values import CAR as TOYOTA from opendbc.car.volkswagen.values import CAR as VOLKSWAGEN -Platform = BODY | CHRYSLER | FORD | GM | HONDA | HYUNDAI | MAZDA | MOCK | NISSAN | SUBARU | TESLA | TOYOTA | VOLKSWAGEN +Platform = BODY | BYD | CHRYSLER | FORD | GM | HONDA | HYUNDAI | MAZDA | MOCK | NISSAN | SUBARU | TESLA | TOYOTA | VOLKSWAGEN BRANDS = get_args(Platform) PLATFORMS: dict[str, Platform] = {str(platform): platform for brand in BRANDS for platform in brand} diff --git a/opendbc/dbc/byd_han_dm_2020.dbc b/opendbc/dbc/byd_han_dm_2020.dbc new file mode 100644 index 0000000000..753bfd0b31 --- /dev/null +++ b/opendbc/dbc/byd_han_dm_2020.dbc @@ -0,0 +1,217 @@ +VERSION "" + + +NS_ : + NS_DESC_ + CM_ + BA_DEF_ + BA_ + VAL_ + CAT_DEF_ + CAT_ + FILTER + BA_DEF_DEF_ + EV_DATA_ + ENVVAR_DATA_ + SGTYPE_ + SGTYPE_VAL_ + BA_DEF_SGTYPE_ + BA_SGTYPE_ + SIG_TYPE_REF_ + VAL_TABLE_ + SIG_GROUP_ + SIG_VALTYPE_ + SIGTYPE_VALTYPE_ + BO_TX_BU_ + BA_DEF_REL_ + BA_REL_ + BA_DEF_DEF_REL_ + BU_SG_REL_ + BU_EV_REL_ + BU_BO_REL_ + SG_MUL_VAL_ + +BS_: + +BU_: XXX + +BO_ 287 EPS: 5 XXX + SG_ SteeringAngle : 0|16@1- (0.1,0) [-450|450] "" XXX + SG_ SteeringAngleRate : 16|8@1+ (0.1,0) [0|1020] "" XXX + SG_ Counter : 32|8@1+ (1,0) [0|255] "" XXX + +BO_ 289 CARSPEED: 8 XXX + SG_ CarDisplaySpeed : 0|12@1+ (1,0) [0|255] "" XXX + +BO_ 301 BCM: 8 XXX + SG_ FrontLeftDoor : 0|1@0+ (1,0) [0|1] "" XXX + SG_ FrontRightDoor : 1|1@0+ (1,0) [0|1] "" XXX + SG_ RearLeftDoor : 2|1@0+ (1,0) [0|1] "" XXX + SG_ RearRightDoor : 3|1@0+ (1,0) [0|1] "" XXX + SG_ BootDoor : 4|1@0+ (1,0) [0|1] "" XXX + SG_ DriverSeatBeltFasten : 6|1@0+ (1,0) [0|1] "" XXX + SG_ BrakeLight : 8|1@0+ (1,0) [0|1] "" XXX + SG_ FrontRightPassengerSeatBelt : 55|1@0+ (1,0) [0|1] "" XXX + +BO_ 307 STALKS: 8 XXX + SG_ FrontFogLight : 0|1@0+ (1,0) [0|1] "" XXX + SG_ LightsOn : 1|1@1+ (1,0) [0|1] "" XXX + SG_ HeadLight : 2|1@1+ (1,0) [0|1] "" XXX + SG_ FullBeam : 3|1@1+ (1,0) [0|1] "" XXX + SG_ LeftIndicator : 4|1@0+ (1,0) [0|1] "" XXX + SG_ RightIndicator : 5|1@0+ (1,0) [0|1] "" XXX + SG_ RearFogLight : 7|1@0+ (1,0) [0|1] "" XXX + SG_ AutoHeadlight : 40|1@0+ (1,0) [0|1] "" XXX + SG_ Heartbeat : 63|4@0+ (1,0) [0|15] "" XXX + +BO_ 496 IPB1: 8 XXX + SG_ WheelSpeed_FL : 0|12@1+ (0.06875,0) [0|281.4625] "kph" XXX + SG_ FaultFlag_FR : 12|1@1+ (1,0) [0|1] "" XXX + SG_ FaultFlag_FL : 13|1@1+ (1,0) [0|1] "" XXX + SG_ FaultFlag_RR : 14|1@1+ (1,0) [0|1] "" XXX + SG_ FaultFlag_RL : 15|1@1+ (1,0) [0|1] "" XXX + SG_ WheelSpeed_FR : 16|12@1+ (0.06875,0) [0|281.4625] "kph" XXX + SG_ WheelSpeed_RL : 28|12@1+ (0.06875,0) [0|281.4625] "kph" XXX + SG_ WheelSpeed_RR : 40|12@1+ (0.06875,0) [0|281.4625] "kph" XXX + SG_ Counter : 52|4@1+ (1,0) [0|15] "" XXX + SG_ CheckSum : 56|8@1+ (1,0) [0|255] "" XXX + +BO_ 578 DRIVE_STATE: 8 XXX + SG_ SETME_FFFF : 0|16@1+ (0.01706666666,-512) [0|65535] "" XXX + SG_ ReqThrottle : 30|7@0+ (1,0) [0|127] "" XXX + SG_ BrakePressed : 37|1@0+ (1,0) [0|1] "" XXX + SG_ Gear : 40|3@1+ (1,0) [0|7] "" XXX + SG_ Counter : 55|4@0+ (1,0) [0|15] "" XXX + SG_ CheckSum : 56|8@1+ (1,0) [0|255] "" XXX + +BO_ 694 DATETIME: 8 XXX + SG_ YY : 7|8@0+ (1,0) [0|255] "" XXX + SG_ MM : 15|8@0+ (1,0) [0|255] "" XXX + SG_ DD : 23|8@0+ (1,0) [0|255] "" XXX + SG_ hh : 31|8@0+ (1,0) [0|255] "" XXX + SG_ mm : 39|8@0+ (1,0) [0|255] "" XXX + SG_ ss : 47|8@0+ (1,0) [0|255] "" XXX + +BO_ 790 ACC_MPC_STATE: 8 XXX + SG_ AutoFullBeamState : 3|4@0+ (1,0) [0|1] "" XXX + SG_ LeftLaneState : 4|2@1+ (1,0) [0|3] "" XXX + SG_ LKAS_Config : 6|2@1+ (1,0) [0|3] "" XXX + SG_ SETME2_0x1 : 8|2@1+ (1,0) [0|3] "" XXX + SG_ ReqHandsOnSteeringWheel : 10|1@1+ (1,0) [0|1] "" XXX + SG_ MPC_State : 11|4@1+ (1,0) [0|1] "" XXX + SG_ AutoFullBeam_OnOff : 15|1@0+ (1,0) [0|1] "" XXX + SG_ LKAS_Output : 16|11@1- (1,0) [-1024|1023] "" XXX + SG_ LKAS_ReqPrepare : 27|1@1+ (1,0) [0|1] "" XXX + SG_ LKAS_Active : 28|1@1+ (1,0) [0|3] "" XXX + SG_ SETME3_0x0 : 29|1@0+ (1,0) [0|1] "" XXX + SG_ TrafficSignRecognition_OnOff : 30|1@0+ (1,0) [0|1] "" XXX + SG_ SETME4_0x0 : 31|1@0+ (1,0) [0|1] "" XXX + SG_ SETME5_0x1 : 32|2@1+ (1,0) [0|3] "" XXX + SG_ RightLaneState : 34|2@1+ (1,0) [0|3] "" XXX + SG_ LKAS_State : 36|2@1+ (1,0) [0|3] "" XXX + SG_ SETME6_0x0 : 38|2@1+ (1,0) [0|3] "" XXX + SG_ TrafficSignRecognition_Result : 40|8@1+ (5,-5) [-5|1270] "" XXX + SG_ LKAS_AlarmType : 49|2@0+ (1,0) [0|3] "" XXX + SG_ SETME7_0x3 : 51|2@0+ (1,0) [0|3] "" XXX + SG_ Counter : 52|4@1+ (1,0) [0|15] "" XXX + SG_ CheckSum : 56|8@1+ (1,0) [0|15] "" XXX + +BO_ 792 ACC_EPS_STATE: 8 XXX + SG_ LKAS_Prepared : 0|1@1+ (1,0) [0|1] "" XXX + SG_ CruiseActivated : 1|1@1+ (1,0) [0|1] "" XXX + SG_ TorqueFailed : 2|1@1+ (1,0) [0|1] "" XXX + SG_ SETME1_0x1 : 3|1@1+ (1,0) [0|1] "" XXX + SG_ SteerWarning : 4|1@1+ (1,0) [0|1] "" XXX + SG_ SteerError_1 : 5|1@1+ (1,0) [0|1] "" XXX + SG_ SteerError_2 : 6|1@1+ (1,0) [0|1] "" XXX + SG_ SETME2_0x0 : 7|1@0+ (1,0) [0|1] "" XXX + SG_ MainTorque : 8|12@1- (1,0) [-2048|2047] "" XXX + SG_ SETME3_0x1 : 20|1@1+ (1,0) [0|1] "" XXX + SG_ ReportHandsNotOnSteeringWheel : 21|1@1+ (1,0) [0|1] "" XXX + SG_ SETME4_0x3 : 22|2@1+ (1,0) [0|15] "" XXX + SG_ SteerDriverTorque : 24|12@1- (1,0) [-2048|2047] "" XXX + SG_ SETME5_0xFF : 36|4@1+ (1,0) [0|15] "" XXX + SG_ SETME6_0xFFF : 40|12@1+ (1,0) [0|4095] "" XXX + SG_ Counter : 52|4@1+ (1,0) [0|15] "" XXX + SG_ CheckSum : 56|8@1+ (1,0) [0|255] "" XXX + +BO_ 813 ACC_HUD_ADAS: 8 XXX + SG_ SetSpeed : 0|9@1+ (0.5,0) [0|255.5] "" XXX + SG_ HasLeadTarget : 9|1@1+ (1,0) [0|1] "" XXX + SG_ SetDistance : 10|3@1+ (1,0) [0|7] "" XXX + SG_ LeadingTargetDistance : 13|3@1+ (1,0) [0|7] "" XXX + SG_ AEB : 16|1@1+ (1,0) [0|1] "" XXX + SG_ FCW : 17|1@1+ (1,0) [0|1] "" XXX + SG_ SETME1_0x1 : 18|1@1+ (1,0) [0|1] "" XXX + SG_ AccState : 19|3@1+ (1,0) [0|1] "" XXX + SG_ AccOn1 : 22|1@0+ (1,0) [0|1] "" XXX + SG_ CloseWarning : 23|1@0+ (1,0) [0|1] "" XXX + SG_ SETME2_0x1 : 24|1@1+ (1,0) [0|1] "" XXX + SG_ Notify : 25|7@1+ (1,0) [0|127] "" XXX + SG_ Status : 32|4@1+ (1,0) [0|15] "" XXX + SG_ SETME3_0xFFF : 36|12@1+ (1,0) [0|4095] "" XXX + SG_ Counter : 48|4@1+ (1,0) [0|15] "" XXX + SG_ SETME4_0xF : 55|4@0+ (1,0) [0|15] "" XXX + SG_ CheckSum : 56|8@1+ (1,0) [0|255] "" XXX + +BO_ 814 ACC_CMD: 8 XXX + SG_ AccelCmd : 0|8@1+ (0.05,-5) [-100|155] "m/s^2" XXX + SG_ ComfortBandUpper : 8|8@1+ (0.05,-5) [0|1.26] "m/s^2" XXX + SG_ ComfortBandLower : 16|8@1+ (0.05,-5) [0|1.26] "m/s^2" XXX + SG_ JerkUpperLimit : 24|7@1+ (0.2,0) [0|12.7] "m/s^3" XXX + SG_ SETME1_0x1 : 31|1@0+ (1,0) [0|1] "" XXX + SG_ JerkLowerLimit : 32|7@1+ (0.2,-16) [0|12.7] "m/s^3" XXX + SG_ ResumeFromStandstill : 39|1@0+ (1,0) [0|1] "" XXX + SG_ StandstillState : 40|1@0+ (1,0) [0|1] "" XXX + SG_ BrakeBehaviour : 41|2@1+ (1,0) [0|3] "" XXX + SG_ AccReqNotStandstill : 43|1@1+ (1,0) [0|1] "" XXX + SG_ AccControlActive : 44|1@0+ (1,0) [0|1] "" XXX + SG_ AccOverrideOrStandstill : 45|1@0+ (1,0) [0|1] "" XXX + SG_ EspBehaviour : 46|2@1+ (1,0) [0|3] "" XXX + SG_ Counter : 48|4@1+ (1,0) [0|15] "" XXX + SG_ SETME2_0xF : 55|4@0+ (1,0) [0|15] "" XXX + SG_ CheckSum : 56|8@1+ (1,0) [0|255] "" XXX + +BO_ 834 PEDAL: 8 XXX + SG_ AcceleratorPedal : 0|8@1+ (0.01,0) [0|2.55] "" XXX + SG_ BrakePedal : 8|8@1+ (0.01,0) [0|2.55] "" XXX + SG_ ForceGeneratorMode : 19|1@1+ (1,0) [0|1] "" XXX + SG_ DriveMode : 20|2@1+ (1,0) [0|255] "" XXX + SG_ PowerMode : 28|2@1+ (1,0) [0|1] "" XXX + SG_ CheckSum : 56|8@1+ (1,0) [0|255] "" XXX + +BO_ 944 PCM_BUTTONS: 8 XXX + SG_ SETME_1 : 2|1@0+ (1,0) [0|1] "" XXX + SG_ BTN_AccUpDown_Cmd : 4|2@0+ (1,0) [0|3] "" XXX + SG_ BTN_AccCancel : 6|1@0+ (1,0) [0|1] "" XXX + SG_ BTN_TOGGLE_ACC_OnOff : 8|1@0+ (1,0) [0|1] "" XXX + SG_ SETME2_1 : 12|1@0+ (1,0) [0|1] "" XXX + SG_ BTN_AccDistanceDecrease : 15|1@0+ (1,0) [0|1] "" XXX + SG_ BTN_AccDistanceIncrease : 16|1@0+ (1,0) [0|1] "" XXX + SG_ Counter : 52|4@1+ (1,0) [0|15] "" XXX + SG_ CheckSum : 56|8@1+ (1,0) [0|255] "" XXX + +BO_ 1048 BSD_RADAR: 8 XXX + SG_ LEFT_APPROACH : 9|2@0+ (1,0) [0|1] "" XXX + SG_ RIGHT_APPROACH : 11|2@0+ (1,0) [0|1] "" XXX + SG_ APPROACH : 17|1@0+ (1,0) [0|1] "" XXX + +BO_ 1193 SUBPANEL_BUTTONS: 8 XXX + SG_ BTN_LKAS : 8|1@0+ (1,0) [0|1] "" XXX + SG_ BTN_ESPOFF : 18|1@0+ (1,0) [0|1] "" XXX + SG_ BTN_SnowMode : 22|1@0+ (1,0) [0|1] "" XXX + + +VAL_ 578 Gear 4 "D" 2 "R" 3 "N" 1 "P" ; +VAL_ 790 AutoFullBeamState 11 "AutoFullBeamActive" 2 "AutoFullBeamInactive" ; +VAL_ 790 LeftLaneState 0 "GRAY" 1 "GREEN" 2 "YELLOW" 3 "RED" ; +VAL_ 790 LKAS_Config 3 "ALARM_AND_LKA" 2 "LKA" 1 "ALARM" 0 "DISABLE" ; +VAL_ 790 RightLaneState 0 "GRAY" 1 "GREEN" 2 "YELLOW" 3 "RED" ; +VAL_ 790 LKAS_AlarmType 0 "VIBRATION" 1 "AUDIO" 2 "AUDIO_AND_VIBRATION" ; +VAL_ 813 SetDistance 4 "4BAR" 3 "3BAR" 2 "2BAR" 1 "1BAR" ; +VAL_ 813 AccState 0 "OFF" 2 "ACC_ON" 3 "ACC_ACTIVE" 5 "FORCE_ACCEL" 7 "ERROR" ; +VAL_ 813 Notify 36 "ACC_ERROR" 22 "OVERRIDE" 12 "ENGAGE" 8 "DISENGAGE" 20 "ACC_ON" 32 "ACC_OFF" 48 "CHECK_GEAR_D" 16 "FORCE_ACCEL" 0 "NONE" ; +VAL_ 834 DriveMode 2 "SPORT" 1 "ECO" 0 "SNOW" ; +VAL_ 834 PowerMode 3 "HEV" 2 "FORCE_EV" 1 "EV" ; +VAL_ 944 BTN_AccUpDown_Cmd 0 "NOTPRESSED" 1 "DOWN_SETSPEED" 3 "UP_RESETSPEED" ; +