From 0e06cf15d762f1547369a901d9f0f004b76dc9a8 Mon Sep 17 00:00:00 2001 From: lukasloetkolben <61192133+lukasloetkolben@users.noreply.github.com> Date: Sun, 19 Apr 2026 10:08:42 +0200 Subject: [PATCH 1/9] BYD: add Atto 3 support --- .github/labeler.yaml | 4 + opendbc/can/dbc.py | 4 + opendbc/car/byd/__init__.py | 0 opendbc/car/byd/bydcan.py | 45 +++++++ opendbc/car/byd/carcontroller.py | 43 ++++++ opendbc/car/byd/carstate.py | 74 ++++++++++ opendbc/car/byd/fingerprints.py | 13 ++ opendbc/car/byd/interface.py | 26 ++++ opendbc/car/byd/values.py | 98 ++++++++++++++ opendbc/car/car.capnp | 1 + opendbc/car/tests/routes.py | 3 + opendbc/car/tests/test_fw_fingerprint.py | 3 +- opendbc/car/torque_data/override.toml | 3 + opendbc/car/values.py | 3 +- opendbc/dbc/byd_atto3.dbc | 164 +++++++++++++++++++++++ opendbc/safety/declarations.h | 2 + opendbc/safety/modes/byd.h | 92 +++++++++++++ opendbc/safety/safety.h | 2 + opendbc/safety/tests/test_byd.py | 162 ++++++++++++++++++++++ 19 files changed, 740 insertions(+), 2 deletions(-) create mode 100644 opendbc/car/byd/__init__.py create mode 100644 opendbc/car/byd/bydcan.py create mode 100644 opendbc/car/byd/carcontroller.py create mode 100644 opendbc/car/byd/carstate.py create mode 100644 opendbc/car/byd/fingerprints.py create mode 100644 opendbc/car/byd/interface.py create mode 100644 opendbc/car/byd/values.py create mode 100644 opendbc/dbc/byd_atto3.dbc create mode 100644 opendbc/safety/modes/byd.h create mode 100644 opendbc/safety/tests/test_byd.py diff --git a/.github/labeler.yaml b/.github/labeler.yaml index 520e2d12a50..28f3ca874bb 100644 --- a/.github/labeler.yaml +++ b/.github/labeler.yaml @@ -23,6 +23,10 @@ body: - changed-files: - any-glob-to-any-file: 'opendbc/car/body/**' +byd: + - changed-files: + - any-glob-to-any-file: 'opendbc/car/byd/**' + chrysler: - changed-files: - any-glob-to-any-file: 'opendbc/car/chrysler/**' diff --git a/opendbc/can/dbc.py b/opendbc/can/dbc.py index 97300c55e5c..ee0fbe03c2b 100644 --- a/opendbc/can/dbc.py +++ b/opendbc/can/dbc.py @@ -16,6 +16,7 @@ from opendbc.car.volkswagen.mqbcan import volkswagen_mqb_meb_checksum, xor_checksum from opendbc.car.tesla.teslacan import tesla_checksum from opendbc.car.body.bodycan import body_checksum +from opendbc.car.byd.bydcan import byd_checksum from opendbc.car.psa.psacan import psa_checksum @@ -34,6 +35,7 @@ class SignalType: TESLA_CHECKSUM = 11 PSA_CHECKSUM = 12 VOLKSWAGEN_MLB_CHECKSUM = 13 + BYD_CHECKSUM = 14 @dataclass @@ -212,6 +214,8 @@ def get_checksum_state(dbc_name: str) -> ChecksumState | None: return ChecksumState(8, -1, 0, -1, True, SignalType.TESLA_CHECKSUM, tesla_checksum, tesla_setup_signal) elif dbc_name.startswith("psa_"): return ChecksumState(4, 4, 7, 3, False, SignalType.PSA_CHECKSUM, psa_checksum) + elif dbc_name.startswith("byd_"): + return ChecksumState(8, 4, 56, 55, True, SignalType.BYD_CHECKSUM, byd_checksum) return None diff --git a/opendbc/car/byd/__init__.py b/opendbc/car/byd/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/opendbc/car/byd/bydcan.py b/opendbc/car/byd/bydcan.py new file mode 100644 index 00000000000..be755b56c14 --- /dev/null +++ b/opendbc/car/byd/bydcan.py @@ -0,0 +1,45 @@ +def byd_checksum(address: int, sig, d: bytearray) -> int: + return (~sum(d[:7])) & 0xFF + + +def create_steering_control(packer, apply_angle: float, lat_active: bool, counter: int): + # Stock saturates the rate limits at ±299 when engaged, 0 when disengaged + rate_limit = 299 if lat_active else 0 + values = { + "STEER_REQ": 1 if lat_active else 0, + "STEER_REQ_ACTIVE_LOW": 0 if lat_active else 1, + "STEER_ANGLE": apply_angle, + "ANGLE_RATE_LIMIT_UPPER": rate_limit, + "ANGLE_RATE_LIMIT_LOWER": -rate_limit, + "SET_ME_1_1": 1, + "SET_ME_1_2": 1, + "SET_ME_FF": 0xFF, + "SET_ME_F": 0xF, + "COUNTER": counter, + } + return packer.make_can_msg("STEERING_MODULE_ADAS", 0, values) + + +def create_buttons(packer, cancel: bool): + values = { + "SET_ME_1_1": 1, + "SET_ME_1_2": 1, + "ACC_ON_BTN": 1 if cancel else 0, + } + return packer.make_can_msg("PCM_BUTTONS", 0, values) + + +def create_lkas_hud(packer, lat_active: bool, counter: int): + values = { + # TODO: test STEER_ACTIVE_1_1 to 3 individual + "STEER_ACTIVE_1_1": 1 if lat_active else 0, + "STEER_ACTIVE_1_2": 1 if lat_active else 0, + "STEER_ACTIVE_1_3": 1 if lat_active else 0, + "STEER_ACTIVE_ACTIVE_LOW": 0 if lat_active else 1, + "LSS_STATE": 2 if lat_active else 0, + "SET_ME_1_2": 1, + "SET_ME_X5F": 0x5F, + "SET_ME_XFF": 0xFF, + "COUNTER": counter, + } + return packer.make_can_msg("LKAS_HUD_ADAS", 0, values) diff --git a/opendbc/car/byd/carcontroller.py b/opendbc/car/byd/carcontroller.py new file mode 100644 index 00000000000..fb35212a23e --- /dev/null +++ b/opendbc/car/byd/carcontroller.py @@ -0,0 +1,43 @@ +from opendbc.can.packer import CANPacker +from opendbc.car import Bus +from opendbc.car.lateral import apply_steer_angle_limits_vm +from opendbc.car.interfaces import CarControllerBase +from opendbc.car.byd import bydcan +from opendbc.car.byd.values import CarControllerParams +from opendbc.car.vehicle_model import VehicleModel + + +def get_safety_CP(): + from opendbc.car.byd.interface import CarInterface + return CarInterface.get_non_essential_params("BYD_ATTO_3") + + +class CarController(CarControllerBase): + def __init__(self, dbc_names, CP): + super().__init__(dbc_names, CP) + self.packer = CANPacker(dbc_names[Bus.pt]) + self.apply_angle_last = 0.0 + + # Vehicle model used for lateral limiting + self.VM = VehicleModel(get_safety_CP()) + + def update(self, CC, CS, now_nanos): + can_sends = [] + actuators = CC.actuators + + if self.frame % 2: + self.apply_angle_last = apply_steer_angle_limits_vm(actuators.steeringAngleDeg, self.apply_angle_last, CS.out.vEgoRaw, + CS.out.steeringAngleDeg, CC.latActive, CarControllerParams, self.VM) + + cntr = (self.frame // 2) % 16 + can_sends.append(bydcan.create_steering_control(self.packer, self.apply_angle_last, CC.latActive, cntr)) + can_sends.append(bydcan.create_lkas_hud(self.packer, CC.latActive, cntr)) + + if CC.cruiseControl.cancel and self.frame % 10 == 0: + can_sends.append(bydcan.create_buttons(self.packer, cancel=True)) + + new_actuators = actuators.as_builder() + new_actuators.steeringAngleDeg = float(self.apply_angle_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 00000000000..96eea9e284b --- /dev/null +++ b/opendbc/car/byd/carstate.py @@ -0,0 +1,74 @@ +from opendbc.car import Bus, structs +from opendbc.can.parser import CANParser +from opendbc.car.common.conversions import Conversions as CV +from opendbc.car.byd.values import DBC, CarControllerParams as CCP +from opendbc.car.interfaces import CarStateBase + +GearShifter = structs.CarState.GearShifter + +# BYD gear enum from DRIVE_STATE.GEAR +GEAR_MAP = { + 1: GearShifter.park, + 2: GearShifter.reverse, + 3: GearShifter.neutral, + 4: GearShifter.drive, +} + + +class CarState(CarStateBase): + def update(self, can_parsers) -> structs.CarState: + cp = can_parsers[Bus.pt] + cp_cam = can_parsers[Bus.cam] + ret = structs.CarState() + + # speed + speed_kph = cp.vl["WHEELSPEED_CLEAN"]["WHEELSPEED_CLEAN"] + ret.vEgoRaw = speed_kph * CV.KPH_TO_MS + ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw) + ret.standstill = speed_kph < 0.1 + ret.vEgoCluster = ret.vEgo + + # steering wheel + ret.steeringAngleDeg = cp.vl["STEER_MODULE_2"]["STEER_ANGLE_2"] + ret.steeringTorque = cp.vl["STEERING_TORQUE"]["MAIN_TORQUE"] + ret.steeringTorqueEps = cp.vl["STEER_MODULE_2"]["DRIVER_EPS_TORQUE"] + ret.steeringPressed = self.update_steering_pressed(abs(ret.steeringTorqueEps) > CCP.STEER_DRIVER_OVERRIDE, 5) + ret.steeringDisengage = abs(ret.steeringTorqueEps) > CCP.STEER_DRIVER_DISENGAGE + + # gas / brake + ret.gasPressed = cp.vl["DRIVE_STATE"]["RAW_THROTTLE"] > 0 + ret.brake = cp.vl["PEDAL"]["BRAKE_PEDAL"] + ret.brakePressed = bool(cp.vl["DRIVE_STATE"]["BRAKE_PRESSED"]) + + # gear + ret.gearShifter = GEAR_MAP.get(int(cp.vl["DRIVE_STATE"]["GEAR"]), GearShifter.unknown) + + # blinkers + ret.leftBlinker = bool(cp.vl["STALKS"]["LEFT_BLINKER"]) + ret.rightBlinker = bool(cp.vl["STALKS"]["RIGHT_BLINKER"]) + + # doors / belt + ret.doorOpen = any(( + cp.vl["METER_CLUSTER"]["FRONT_LEFT_DOOR"], + cp.vl["METER_CLUSTER"]["FRONT_RIGHT_DOOR"], + cp.vl["METER_CLUSTER"]["BACK_LEFT_DOOR"], + cp.vl["METER_CLUSTER"]["BACK_RIGHT_DOOR"], + )) + ret.seatbeltUnlatched = not bool(cp.vl["METER_CLUSTER"]["SEATBELT_DRIVER"]) + + # cruise state: ACC messages come from camera bus on Atto 3 + # ACC_STATE: 0=OFF, 2=ACC_ON (available), 3=ACC_ACTIVE (enabled), 5=FORCE_ACCEL, 7=ERROR + ret.cruiseState.speed = cp_cam.vl["ACC_HUD_ADAS"]["SET_SPEED"] * CV.KPH_TO_MS + acc_state = int(cp_cam.vl["ACC_HUD_ADAS"]["ACC_STATE"]) + ret.cruiseState.available = acc_state in (2, 3, 5) + ret.cruiseState.enabled = acc_state in (3, 5) + ret.cruiseState.standstill = bool(cp_cam.vl["ACC_CMD"]["STANDSTILL_STATE"]) + + return ret + + @staticmethod + def get_can_parsers(CP): + return { + Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], [], 0), + Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], [], 2), + } diff --git a/opendbc/car/byd/fingerprints.py b/opendbc/car/byd/fingerprints.py new file mode 100644 index 00000000000..95f6bb18f37 --- /dev/null +++ b/opendbc/car/byd/fingerprints.py @@ -0,0 +1,13 @@ +""" AUTO-FORMATTED USING opendbc/car/debug/format_fingerprints.py, EDIT STRUCTURE THERE.""" +from opendbc.car.structs import CarParams +from opendbc.car.byd.values import CAR + +Ecu = CarParams.Ecu + +FW_VERSIONS = { + CAR.BYD_ATTO_3: { + (Ecu.engine, 0x7e0, None): [ + b'PLACEHOLDER_FOR_VIN_FINGERPRINT', + ], + }, +} diff --git a/opendbc/car/byd/interface.py b/opendbc/car/byd/interface.py new file mode 100644 index 00000000000..49209c3b412 --- /dev/null +++ b/opendbc/car/byd/interface.py @@ -0,0 +1,26 @@ +from opendbc.car import get_safety_config, structs +from opendbc.car.interfaces import CarInterfaceBase +from opendbc.car.byd.carcontroller import CarController +from opendbc.car.byd.carstate import CarState + + +class CarInterface(CarInterfaceBase): + CarState = CarState + CarController = CarController + + @staticmethod + def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams: + ret.brand = "byd" + + ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.byd)] + + ret.dashcamOnly = False + + ret.steerControlType = structs.CarParams.SteerControlType.angle + ret.steerActuatorDelay = 0.2 + ret.steerLimitTimer = 0.4 + + ret.radarUnavailable = True + ret.alphaLongitudinalAvailable = False + + return ret diff --git a/opendbc/car/byd/values.py b/opendbc/car/byd/values.py new file mode 100644 index 00000000000..a1f4ed3b1d5 --- /dev/null +++ b/opendbc/car/byd/values.py @@ -0,0 +1,98 @@ +from dataclasses import dataclass, field +from enum import IntFlag, StrEnum + +from opendbc.car import ACCELERATION_DUE_TO_GRAVITY, Bus, CarSpecs, DbcDict, PlatformConfig, Platforms, structs +from opendbc.car.lateral import AngleSteeringLimits, ISO_LATERAL_ACCEL +from opendbc.car.docs_definitions import CarDocs, CarHarness, CarParts +from opendbc.car.fw_query_definitions import FwQueryConfig +from opendbc.car.vin import Vin + +Ecu = structs.CarParams.Ecu + + +# Add extra tolerance for average banked road since safety doesn't have the roll +AVERAGE_ROAD_ROLL = 0.06 # ~3.4 degrees, 6% superelevation. higher actual roll lowers lateral acceleration + + +class CarControllerParams: + STEER_STEP = 2 # Angle command is sent at 50 Hz + + ANGLE_LIMITS: AngleSteeringLimits = AngleSteeringLimits( + 360, # deg + # BYD uses a vehicle model instead, check carcontroller.py for details + ([], []), + ([], []), + + # Vehicle model angle limits + # Add extra tolerance for average banked road since safety doesn't have the roll + MAX_LATERAL_ACCEL=ISO_LATERAL_ACCEL + (ACCELERATION_DUE_TO_GRAVITY * AVERAGE_ROAD_ROLL), # ~3.6 m/s^2 + MAX_LATERAL_JERK=3.0 + (ACCELERATION_DUE_TO_GRAVITY * AVERAGE_ROAD_ROLL), # ~3.6 m/s^3 + + # limit angle rate to both prevent a fault and for low speed comfort (~12 mph rate down to 0 mph) + MAX_ANGLE_RATE=5, # deg/20ms frame, EPS faults at 12 at a standstill + ) + + STEER_DRIVER_OVERRIDE = 10 # EPS torque threshold for soft override + STEER_DRIVER_DISENGAGE = 30 # EPS torque threshold for hard disengage + + +class BydSafetyFlags(IntFlag): + LONG_CONTROL = 1 + + +class WMI(StrEnum): + BYD_AUTO = "LGX" # BYD Auto Co., Ltd. (Shenzhen) + + +class ModelYear(StrEnum): + N_2022 = "N" + P_2023 = "P" + R_2024 = "R" + S_2025 = "S" + + +@dataclass +class BydCarDocs(CarDocs): + package: str = "All" + car_parts: CarParts = field(default_factory=CarParts.common([CarHarness.custom])) + + +@dataclass +class BydPlatformConfig(PlatformConfig): + dbc_dict: DbcDict = field(default_factory=lambda: { + Bus.pt: 'byd_atto3', + }) + wmis: set[WMI] = field(default_factory=set) + years: set[ModelYear] = field(default_factory=set) + + +class CAR(Platforms): + BYD_ATTO_3 = BydPlatformConfig( + [BydCarDocs("BYD Atto 3 2022-25")], + CarSpecs(mass=1750, wheelbase=2.72, steerRatio=14.8), + wmis={WMI.BYD_AUTO}, + years={ModelYear.N_2022, ModelYear.P_2023, ModelYear.R_2024, ModelYear.S_2025}, + ) + + +def match_fw_to_car_fuzzy(live_fw_versions, vin, offline_fw_versions) -> set[str]: + # BYD Atto 3 VIN: LGX (WMI) + + (VIS). + # TODO: currently we only match on WMI + model year + vin_obj = Vin(vin) + year = vin_obj.vis[:1] + + candidates = set() + for platform in CAR: + if vin_obj.wmi in platform.config.wmis and year in platform.config.years: + candidates.add(platform) + + return {str(c) for c in candidates} + + +FW_QUERY_CONFIG = FwQueryConfig( + requests=[], + match_fw_to_car_fuzzy=match_fw_to_car_fuzzy, +) + + +DBC = CAR.create_dbc_map() diff --git a/opendbc/car/car.capnp b/opendbc/car/car.capnp index d2b8d758a7c..62dfce64b9d 100644 --- a/opendbc/car/car.capnp +++ b/opendbc/car/car.capnp @@ -635,6 +635,7 @@ struct CarParams { fcaGiorgio @32; rivian @33; volkswagenMeb @34; + byd @35; } enum SteerControlType { diff --git a/opendbc/car/tests/routes.py b/opendbc/car/tests/routes.py index 2fe80c0f781..630296c4a40 100644 --- a/opendbc/car/tests/routes.py +++ b/opendbc/car/tests/routes.py @@ -15,6 +15,7 @@ from opendbc.car.values import Platform from opendbc.car.volkswagen.values import CAR as VOLKSWAGEN from opendbc.car.body.values import CAR as COMMA +from opendbc.car.byd.values import CAR as BYD from opendbc.car.psa.values import CAR as PSA # FIXME: add routes for these cars @@ -341,6 +342,8 @@ class CarTestRoute(NamedTuple): CarTestRoute("6a7075a4fdd765ee/0000004e--1f612006dd", PSA.PSA_PEUGEOT_208), + CarTestRoute("148fa33c79475c93/00000002--bb5e1aa449", BYD.BYD_ATTO_3), + CarTestRoute("bc095dc92e101734/000000db--ee9fe46e57", RIVIAN.RIVIAN_R1), CarTestRoute("c70d59e4150956fc/0000006e--48bfbfda01", RIVIAN.RIVIAN_R1), # GEN2 diff --git a/opendbc/car/tests/test_fw_fingerprint.py b/opendbc/car/tests/test_fw_fingerprint.py index 811347bb365..2d34e7a1231 100644 --- a/opendbc/car/tests/test_fw_fingerprint.py +++ b/opendbc/car/tests/test_fw_fingerprint.py @@ -262,10 +262,11 @@ def fake_get_ecu_addrs(*_, timeout): print(f'get_vin {name} case, query time={self.total_time / self.N} seconds') def test_fw_query_timing(self): - total_ref_time = 7.4 + total_ref_time = 7.6 brand_ref_times = { 'gm': 1.0, 'body': 0.1, + 'byd': 0.2, 'chrysler': 0.3, 'ford': 1.5, 'honda': 0.45, diff --git a/opendbc/car/torque_data/override.toml b/opendbc/car/torque_data/override.toml index f6bab7603f9..105f8fd3a10 100644 --- a/opendbc/car/torque_data/override.toml +++ b/opendbc/car/torque_data/override.toml @@ -10,6 +10,9 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"] # PSA angle based controllers "PSA_PEUGEOT_208" = [nan, 2.0, nan] +# BYD angle based controllers +"BYD_ATTO_3" = [nan, 2.0, nan] + # New subarus angle based controllers "SUBARU_FORESTER_2022" = [nan, 3.0, nan] "SUBARU_OUTBACK_2023" = [nan, 3.0, nan] diff --git a/opendbc/car/values.py b/opendbc/car/values.py index f606249a4e0..5a9a3a5d7b6 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 @@ -15,7 +16,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 | PSA | RIVIAN | SUBARU | TESLA | TOYOTA | VOLKSWAGEN +Platform = BODY | BYD | CHRYSLER | FORD | GM | HONDA | HYUNDAI | MAZDA | MOCK | NISSAN | PSA | RIVIAN | 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_atto3.dbc b/opendbc/dbc/byd_atto3.dbc new file mode 100644 index 00000000000..579a3b05d91 --- /dev/null +++ b/opendbc/dbc/byd_atto3.dbc @@ -0,0 +1,164 @@ +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_: EPS ESP_ECU BCM VCU MPC_CAM ADAS_ECU MCU + + +BO_ 287 STEER_MODULE_2: 5 EPS + SG_ STEER_ANGLE_2 : 0|16@1- (0.1,0) [-3276.8|3276.7] "deg" MCU,ADAS_ECU + SG_ DRIVER_EPS_TORQUE : 16|8@1+ (1,0) [0|255] "" MCU,ADAS_ECU + SG_ COUNTER : 35|4@0+ (1,0) [0|15] "" MCU + SG_ CHECKSUM_4BIT : 39|4@0+ (1,0) [0|15] "" MCU + +BO_ 307 STALKS: 8 BCM + SG_ LEFT_BLINKER : 37|1@0+ (1,0) [0|1] "" MCU + SG_ RIGHT_BLINKER : 38|1@0+ (1,0) [0|1] "" MCU + SG_ COUNTER : 48|4@1+ (1,0) [0|15] "" MCU + +BO_ 482 STEERING_MODULE_ADAS: 8 ADAS_ECU + SG_ ANGLE_RATE_LIMIT_UPPER : 0|10@1- (1,0) [-512|511] "" EPS + SG_ ANGLE_RATE_LIMIT_LOWER : 10|10@1- (1,0) [-512|511] "" EPS + SG_ STEER_REQ_ACTIVE_LOW : 20|1@0+ (1,0) [0|1] "" EPS + SG_ STEER_REQ : 21|1@0+ (1,0) [0|1] "" EPS + SG_ SET_ME_1_2 : 22|1@0+ (1,0) [0|1] "" EPS + SG_ SET_ME_1_1 : 23|1@0+ (1,0) [0|1] "" EPS + SG_ STEER_ANGLE : 24|16@1- (0.1,0) [-3276.8|3276.7] "deg" EPS + SG_ SET_ME_FF : 47|8@0+ (1,0) [0|255] "" EPS + SG_ SET_ME_F : 48|4@1+ (1,0) [0|15] "" EPS + SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" EPS + SG_ CHECKSUM : 56|8@1+ (1,0) [0|255] "" EPS + +BO_ 496 WHEELSPEED_CLEAN: 8 ESP_ECU + SG_ WHEELSPEED_CLEAN : 0|16@1+ (0.1,0) [0|6553.5] "kph" MCU + SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" MCU + SG_ CHECKSUM : 56|8@1+ (1,0) [0|255] "" MCU + +BO_ 508 STEERING_TORQUE: 8 EPS + SG_ MAIN_TORQUE : 0|16@1- (0.1,0) [-3276.8|3276.7] "" MCU,ADAS_ECU + SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" MCU + SG_ CHECKSUM : 56|8@1+ (1,0) [0|255] "" MCU + +BO_ 578 DRIVE_STATE: 8 VCU + SG_ RAW_THROTTLE : 30|7@0+ (1,0) [0|127] "" MCU + SG_ BRAKE_PRESSED : 37|1@0+ (1,0) [0|1] "" MCU,ADAS_ECU + SG_ GEAR : 40|3@1+ (1,0) [0|7] "" MCU + +BO_ 660 METER_CLUSTER: 8 BCM + SG_ FRONT_RIGHT_DOOR : 1|1@1+ (1,0) [0|1] "" MCU + SG_ FRONT_LEFT_DOOR : 3|1@0+ (1,0) [0|1] "" MCU + SG_ BACK_LEFT_DOOR : 5|1@1+ (1,0) [0|1] "" MCU + SG_ BACK_RIGHT_DOOR : 7|1@0+ (1,0) [0|1] "" MCU + SG_ SEATBELT_DRIVER : 17|1@0+ (1,0) [0|1] "" MCU + +BO_ 790 LKAS_HUD_ADAS: 8 MPC_CAM + SG_ HMA : 4|5@0+ (1,0) [0|31] "" MCU + SG_ STEER_ACTIVE_1_1 : 5|1@0+ (1,0) [0|1] "" MCU + SG_ LSS_STATE : 7|2@0+ (1,0) [0|3] "" MCU + SG_ HAND_ON_WHEEL_WARNING : 10|1@0+ (1,0) [0|1] "" MCU + SG_ SET_ME_XFF : 23|8@0+ (1,0) [0|255] "" MCU + SG_ SET_ME_X5F : 31|8@0+ (1,0) [0|255] "" MCU + SG_ SET_ME_1_2 : 32|1@0+ (1,0) [0|1] "" MCU + SG_ STEER_ACTIVE_1_3 : 35|1@0+ (1,0) [0|1] "" MCU + SG_ STEER_ACTIVE_ACTIVE_LOW : 36|1@0+ (1,0) [0|1] "" MCU + SG_ STEER_ACTIVE_1_2 : 37|1@0+ (1,0) [0|1] "" MCU + SG_ TSR : 47|8@0+ (1,0) [0|255] "" MCU + SG_ SETTINGS : 48|4@1+ (1,0) [0|15] "" MCU + SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" MCU + SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" MCU + +BO_ 813 ACC_HUD_ADAS: 8 ADAS_ECU + SG_ SET_SPEED : 0|8@1+ (0.5,0) [0|127.5] "kph" MCU + SG_ SET_DISTANCE : 12|3@0+ (1,0) [0|7] "" MCU + SG_ ACC_STATE : 19|3@1+ (1,0) [0|7] "" MCU + SG_ ACC_ON2 : 20|1@0+ (1,0) [0|1] "" MCU + SG_ ACC_ON1 : 22|1@0+ (1,0) [0|1] "" MCU + SG_ SET_ME_XFF : 47|8@0+ (1,0) [0|255] "" MCU + SG_ COUNTER : 48|4@1+ (1,0) [0|15] "" MCU + SG_ SET_ME_XF : 55|4@0+ (1,0) [0|15] "" MCU + SG_ CHECKSUM : 56|8@1+ (1,0) [0|255] "" MCU + +BO_ 814 ACC_CMD: 8 ADAS_ECU + SG_ ACCEL_CMD : 0|8@1+ (1,-100) [-100|155] "" MCU + SG_ ACC_ON_1 : 9|1@0+ (1,0) [0|1] "" MCU + SG_ SET_ME_25_1 : 10|6@1+ (1,0) [0|63] "" MCU + SG_ ACC_ON_2 : 17|1@0+ (1,0) [0|1] "" MCU + SG_ SET_ME_25_2 : 18|6@1+ (1,0) [0|63] "" MCU + SG_ DECEL_FACTOR : 24|4@1+ (1,0) [0|15] "" MCU + SG_ SET_ME_X8 : 31|4@0+ (1,0) [0|15] "" MCU + SG_ ACCEL_FACTOR : 32|4@1+ (1,0) [0|15] "" MCU + SG_ CMD_REQ_ACTIVE_LOW : 36|1@0+ (1,0) [0|1] "" MCU + SG_ SET_ME_1 : 38|1@0+ (1,0) [0|1] "" MCU + SG_ STANDSTILL_RESUME : 39|1@0+ (1,0) [0|1] "" MCU + SG_ STANDSTILL_STATE : 40|1@0+ (1,0) [0|1] "" MCU + SG_ ACC_REQ_NOT_STANDSTILL : 43|1@0+ (1,0) [0|1] "" MCU + SG_ ACC_CONTROLLABLE_AND_ON : 44|1@0+ (1,0) [0|1] "" MCU + SG_ ACC_OVERRIDE_OR_STANDSTILL : 45|1@0+ (1,0) [0|1] "" MCU + SG_ COUNTER : 48|4@1+ (1,0) [0|15] "" MCU + SG_ SET_ME_XF : 55|4@0+ (1,0) [0|15] "" MCU + SG_ CHECKSUM : 56|8@1+ (1,0) [0|255] "" MCU + +BO_ 834 PEDAL: 8 VCU + SG_ GAS_PEDAL : 0|8@1+ (0.01,0) [0|2.55] "" MCU + SG_ BRAKE_PEDAL : 8|8@1+ (0.01,0) [0|2.55] "" MCU + SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" MCU + SG_ CHECKSUM : 56|8@1+ (1,0) [0|255] "" MCU + +BO_ 944 PCM_BUTTONS: 8 MCU + SG_ SET_ME_1_1 : 2|1@0+ (1,0) [0|1] "" MCU + SG_ SET_BTN : 3|1@0+ (1,0) [0|1] "" MCU + SG_ RES_BTN : 4|1@0+ (1,0) [0|1] "" MCU + SG_ LKAS_ON_BTN : 6|1@0+ (1,0) [0|1] "" MCU + SG_ SET_ME_1_2 : 12|1@0+ (1,0) [0|1] "" MCU + SG_ DEC_DISTANCE_BTN : 15|1@0+ (1,0) [0|1] "" MCU + SG_ INC_DISTANCE_BTN : 16|1@0+ (1,0) [0|1] "" MCU + SG_ ACC_ON_BTN : 19|1@0+ (1,0) [0|1] "" MCU + SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" MCU + SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" MCU + +CM_ BO_ 287 "EPS steering wheel angle + driver torque. Validated: angle range plausible, DRIVER_EPS_TORQUE stays near 0 when hands-off."; +CM_ BO_ 307 "Turn signal / stalk info. Validated: LEFT_BLINKER and RIGHT_BLINKER transition 0->1 during lane change events."; +CM_ BO_ 482 "Lateral steering command sent by MPC camera/ADAS ECU to EPS. Blocked by panda on bus 2; panda injects its own on bus 0."; +CM_ BO_ 496 "Wheel speed (cleaned average). Validated: 0-127 km/h matching driving speed."; +CM_ BO_ 508 "Column steering torque from EPS."; +CM_ BO_ 578 "Drivetrain state: gear, brake pressed, raw throttle."; +CM_ BO_ 660 "Body/meter cluster: doors + seatbelt."; +CM_ BO_ 790 "LKAS HUD ADAS message from camera. Blocked by panda on bus 2; panda re-injects."; +CM_ BO_ 813 "ACC HUD ADAS message (cruise set speed, distance, ACC state)."; +CM_ BO_ 814 "ACC acceleration command from ADAS ECU. Blocked by panda on bus 2 when OP longitudinal active."; +CM_ BO_ 834 "Gas/brake pedal percentages."; +CM_ BO_ 944 "Steering-wheel cruise control buttons."; +VAL_ 578 GEAR 4 "D" 2 "R" 3 "N" 1 "P"; +VAL_ 813 SET_DISTANCE 4 "4bar" 3 "3bar" 2 "2bar" 1 "1bar"; +VAL_ 813 ACC_STATE 0 "OFF" 2 "ACC_ON" 3 "ACC_ACTIVE" 5 "FORCE_ACCEL" 7 "ERROR"; diff --git a/opendbc/safety/declarations.h b/opendbc/safety/declarations.h index 1a68549445b..700c8106eb7 100644 --- a/opendbc/safety/declarations.h +++ b/opendbc/safety/declarations.h @@ -34,6 +34,7 @@ #define SAFETY_PSA 31U #define SAFETY_RIVIAN 33U #define SAFETY_VOLKSWAGEN_MEB 34U +#define SAFETY_BYD 35U #define GET_BIT(msg, b) ((bool)!!(((msg)->data[((b) / 8U)] >> ((b) % 8U)) & 0x1U)) #define GET_FLAG(value, mask) (((value) & (mask)) == (mask)) @@ -343,3 +344,4 @@ extern const safety_hooks volkswagen_mqb_hooks; extern const safety_hooks volkswagen_pq_hooks; extern const safety_hooks rivian_hooks; extern const safety_hooks psa_hooks; +extern const safety_hooks byd_hooks; diff --git a/opendbc/safety/modes/byd.h b/opendbc/safety/modes/byd.h new file mode 100644 index 00000000000..0a31ea677df --- /dev/null +++ b/opendbc/safety/modes/byd.h @@ -0,0 +1,92 @@ +#pragma once + +#include "opendbc/safety/declarations.h" + +static void byd_rx_hook(const CANPacket_t *msg) { + + if (msg->bus == 0U) { + // Steering angle: 0.1 deg/LSB, signed + if (msg->addr == 0x11FU) { + int angle_meas_new = to_signed((msg->data[1] << 8) | msg->data[0], 16); // STEER_ANGLE_2 + update_sample(&angle_meas, angle_meas_new); + } + + // Vehicle speed: 0.1 kph/LSB + if (msg->addr == 0x1F0U) { + int speed = (msg->data[1] << 8) | msg->data[0]; // WHEELSPEED_CLEAN + vehicle_moving = speed > 0; + UPDATE_VEHICLE_SPEED(speed * 0.1 * KPH_TO_MS); + } + + // Gas and brake pressed + if (msg->addr == 0x242U) { + brake_pressed = (msg->data[4] >> 5) & 0x1U; // BRAKE_PRESSED + gas_pressed = (msg->data[3] & 0x7FU) > 0U; // RAW_THROTTLE + } + } + + if (msg->bus == 2U) { + // Cruise state + if (msg->addr == 0x32DU) { + // ACC_STATE: 0=OFF, 2=ACC_ON, 3=ACC_ACTIVE, 5=FORCE_ACCEL, 7=ERROR + uint8_t acc_state = (msg->data[2] >> 3) & 0x7U; + bool acc_on = (acc_state == 3U) || (acc_state == 5U); + pcm_cruise_check(acc_on); + } + } +} + + +static bool byd_tx_hook(const CANPacket_t *msg) { + const AngleSteeringLimits BYD_STEERING_LIMITS = { + .max_angle = 3900, // 390 deg + .angle_deg_to_can = 10, + .frequency = 50U, + }; + + // NOTE: based off BYD_ATTO_3 to match openpilot + const AngleSteeringParams BYD_STEERING_PARAMS = { + .slip_factor = -0.0006166479109059387, // calc_slip_factor(VM) + .steer_ratio = 14.8, + .wheelbase = 2.72, + }; + + bool tx = true; + + // Steering control: 0.1 deg/LSB, signed + if (msg->addr == 0x1E2U) { + int desired_angle = to_signed((msg->data[4] << 8) | msg->data[3], 16); // STEER_ANGLE + bool steer_req = ((msg->data[2] >> 5) & 0x1U) != 0U; // STEER_REQ + + if (steer_angle_cmd_checks_vm(desired_angle, steer_req, BYD_STEERING_LIMITS, BYD_STEERING_PARAMS)) { + tx = false; + } + } + + return tx; +} + +static safety_config byd_init(uint16_t param) { + SAFETY_UNUSED(param); + + static const CanMsg BYD_TX_MSGS[] = { + {0x1E2, 0, 8, .check_relay = true}, // STEERING_MODULE_ADAS (lateral steering command) + {0x316, 0, 8, .check_relay = true}, // LKAS_HUD_ADAS (dash HUD) + {0x3B0, 0, 8, .check_relay = false}, // PCM_BUTTONS (cruise cancel button spoof) + }; + + static RxCheck byd_rx_checks[] = { + {.msg = {{0x11F, 0, 5, 100U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // STEER_MODULE_2 (steering angle) + {.msg = {{0x1F0, 0, 8, 50U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // WHEELSPEED_CLEAN (vehicle speed) + {.msg = {{0x242, 0, 8, 50U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // DRIVE_STATE (gas and brake pressed) + {.msg = {{0x32D, 2, 8, 50U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // ACC_HUD_ADAS (cruise state) + }; + + return BUILD_SAFETY_CFG(byd_rx_checks, BYD_TX_MSGS); +} + +const safety_hooks byd_hooks = { + .init = byd_init, + .rx = byd_rx_hook, + .tx = byd_tx_hook, +}; diff --git a/opendbc/safety/safety.h b/opendbc/safety/safety.h index 6417881df12..b410c57f96e 100644 --- a/opendbc/safety/safety.h +++ b/opendbc/safety/safety.h @@ -27,6 +27,7 @@ #include "opendbc/safety/modes/elm327.h" #include "opendbc/safety/modes/body.h" #include "opendbc/safety/modes/psa.h" +#include "opendbc/safety/modes/byd.h" #include "opendbc/safety/modes/hyundai_canfd.h" uint32_t GET_BYTES(const CANPacket_t *msg, int start, int len) { @@ -407,6 +408,7 @@ int set_safety_hooks(uint16_t mode, uint16_t param) { #ifdef ALLOW_DEBUG {SAFETY_CHRYSLER_CUSW, &chrysler_cusw_hooks}, {SAFETY_PSA, &psa_hooks}, + {SAFETY_BYD, &byd_hooks}, {SAFETY_SUBARU_PREGLOBAL, &subaru_preglobal_hooks}, {SAFETY_VOLKSWAGEN_MLB, &volkswagen_mlb_hooks}, {SAFETY_VOLKSWAGEN_PQ, &volkswagen_pq_hooks}, diff --git a/opendbc/safety/tests/test_byd.py b/opendbc/safety/tests/test_byd.py new file mode 100644 index 00000000000..771e7c079e6 --- /dev/null +++ b/opendbc/safety/tests/test_byd.py @@ -0,0 +1,162 @@ +#!/usr/bin/env python3 +import unittest +import numpy as np + +from opendbc.car.byd.carcontroller import get_safety_CP +from opendbc.car.byd.values import CarControllerParams +from opendbc.car.lateral import get_max_angle_delta_vm, get_max_angle_vm +from opendbc.car.structs import CarParams +from opendbc.car.vehicle_model import VehicleModel +from opendbc.safety.tests.libsafety import libsafety_py +import opendbc.safety.tests.common as common +from opendbc.safety.tests.common import CANPackerSafety, away_round + +STEERING_MODULE_ADAS = 0x1E2 +LKAS_HUD_ADAS = 0x316 +PCM_BUTTONS = 0x3B0 + + +def safety_max_can(max_angle_float, can_offset=0): + # Matches C: max_angle_can = (int)(max_angle * 10 + 1.) which is floor(max_angle * 10) + 1 + return int(max_angle_float * 10 + 1.) + can_offset + + +class TestBydSafety(common.CarSafetyTest, common.AngleSteeringSafetyTest): + RELAY_MALFUNCTION_ADDRS = {0: (STEERING_MODULE_ADAS, LKAS_HUD_ADAS)} + FWD_BLACKLISTED_ADDRS = {2: [STEERING_MODULE_ADAS, LKAS_HUD_ADAS]} + TX_MSGS = [[STEERING_MODULE_ADAS, 0], [LKAS_HUD_ADAS, 0], [PCM_BUTTONS, 0]] + + MAIN_BUS = 0 + CAM_BUS = 2 + + STEER_ANGLE_MAX = 390 # deg, EPS fault limit + DEG_TO_CAN = 10 + + # BYD uses get_max_angle_delta_vm and get_max_angle_vm for lateral accel and jerk limits + ANGLE_RATE_BP = None + ANGLE_RATE_UP = None + ANGLE_RATE_DOWN = None + + # Real time limits + LATERAL_FREQUENCY = 50 # Hz + + def _get_steer_cmd_angle_max(self, speed): + return get_max_angle_vm(max(speed, 1), self.VM, CarControllerParams) + + def setUp(self): + self.VM = VehicleModel(get_safety_CP()) + self.packer = CANPackerSafety("byd_atto3") + self.safety = libsafety_py.libsafety + self.safety.set_safety_hooks(CarParams.SafetyModel.byd, 0) + self.safety.init_tests() + + def _angle_cmd_msg(self, angle: float, enabled: bool, increment_timer: bool = True): + values = {"STEER_ANGLE": angle, "STEER_REQ": 1 if enabled else 0, "STEER_REQ_ACTIVE_LOW": 0 if enabled else 1} + if increment_timer: + self.safety.set_timer(self.__class__.cnt_angle_cmd * int(1e6 / self.LATERAL_FREQUENCY)) + self.__class__.cnt_angle_cmd += 1 + return self.packer.make_can_msg_safety("STEERING_MODULE_ADAS", self.MAIN_BUS, values) + + cnt_angle_cmd = 0 + + def _angle_meas_msg(self, angle: float): + values = {"STEER_ANGLE_2": angle} + return self.packer.make_can_msg_safety("STEER_MODULE_2", self.MAIN_BUS, values) + + def _pcm_status_msg(self, enable): + # ACC_STATE: 0=OFF, 3=ACC_ACTIVE + values = {"ACC_STATE": 3 if enable else 0} + return self.packer.make_can_msg_safety("ACC_HUD_ADAS", self.CAM_BUS, values) + + def _speed_msg(self, speed): + values = {"WHEELSPEED_CLEAN": speed * 3.6} + return self.packer.make_can_msg_safety("WHEELSPEED_CLEAN", self.MAIN_BUS, values) + + def _user_brake_msg(self, brake): + values = {"BRAKE_PRESSED": 1 if brake else 0} + return self.packer.make_can_msg_safety("DRIVE_STATE", self.MAIN_BUS, values) + + def _user_gas_msg(self, gas): + values = {"RAW_THROTTLE": int(gas * 100)} + return self.packer.make_can_msg_safety("DRIVE_STATE", self.MAIN_BUS, values) + + def test_angle_cmd_when_enabled(self): + # We properly test lateral acceleration and jerk below + pass + + def test_lateral_accel_limit(self): + for speed in np.linspace(0, 40, 100): + speed = max(speed, 1) + # match both CAN encoding (0.1 kph/LSB) and VEHICLE_SPEED_FACTOR=1000 rounding in UPDATE_VEHICLE_SPEED + sent = speed + 1 + sent_can = away_round(sent / 0.1 * 3.6) * 0.1 / 3.6 + speed = round(sent_can * 1000) / 1000 - 1 + for sign in (-1, 1): + self.safety.set_controls_allowed(True) + self._reset_speed_measurement(speed + 1) # safety fudges the speed + + max_angle_float = get_max_angle_vm(speed, self.VM, CarControllerParams) + + # at limit (safety tolerance adds 1 CAN unit) + max_angle_can = safety_max_can(max_angle_float) + max_angle_can = min(max_angle_can, self.STEER_ANGLE_MAX * self.DEG_TO_CAN) + max_angle = sign * max_angle_can / self.DEG_TO_CAN + self.safety.set_desired_angle_last(sign * max_angle_can) + + self.assertTrue(self._tx(self._angle_cmd_msg(max_angle, True))) + + # 1 unit above limit + over_can = safety_max_can(max_angle_float, 1) + over_can_clipped = min(over_can, self.STEER_ANGLE_MAX * self.DEG_TO_CAN) + over_angle = sign * over_can_clipped / self.DEG_TO_CAN + self._tx(self._angle_cmd_msg(over_angle, True)) + + # at low speeds max angle is above STEER_ANGLE_MAX, so adding 1 has no effect + should_tx = over_can >= self.STEER_ANGLE_MAX * self.DEG_TO_CAN + self.assertEqual(should_tx, self._tx(self._angle_cmd_msg(over_angle, True))) + + def test_lateral_jerk_limit(self): + for speed in np.linspace(0, 40, 100): + speed = max(speed, 1) + # match both CAN encoding (0.1 kph/LSB) and VEHICLE_SPEED_FACTOR=1000 rounding in UPDATE_VEHICLE_SPEED + sent = speed + 1 + sent_can = away_round(sent / 0.1 * 3.6) * 0.1 / 3.6 + speed = round(sent_can * 1000) / 1000 - 1 + for sign in (-1, 1): + self.safety.set_controls_allowed(True) + self._reset_speed_measurement(speed + 1) # safety fudges the speed + self._tx(self._angle_cmd_msg(0, True)) + + max_delta_float = get_max_angle_delta_vm(speed, self.VM, CarControllerParams) + + # Stay within limits + # Up + max_delta_can = safety_max_can(max_delta_float) + max_angle_delta = sign * max_delta_can / self.DEG_TO_CAN + self.assertTrue(self._tx(self._angle_cmd_msg(max_angle_delta, True))) + + # Don't change + self.assertTrue(self._tx(self._angle_cmd_msg(max_angle_delta, True))) + + # Down + self.assertTrue(self._tx(self._angle_cmd_msg(0, True))) + + # Inject too high rates + # Up + over_delta_can = safety_max_can(max_delta_float, 1) + max_angle_delta = sign * over_delta_can / self.DEG_TO_CAN + self.assertFalse(self._tx(self._angle_cmd_msg(max_angle_delta, True))) + + # Don't change + self.safety.set_desired_angle_last(sign * over_delta_can) + self.assertTrue(self._tx(self._angle_cmd_msg(max_angle_delta, True))) + + # Down + self.assertFalse(self._tx(self._angle_cmd_msg(0, True))) + + # Recover + self.assertTrue(self._tx(self._angle_cmd_msg(0, True))) + + +if __name__ == "__main__": + unittest.main() From 085bdcf343cbbcd2049fdb987fec5393c2e7405a Mon Sep 17 00:00:00 2001 From: lukasloetkolben <61192133+lukasloetkolben@users.noreply.github.com> Date: Sun, 19 Apr 2026 10:41:35 +0200 Subject: [PATCH 2/9] =?UTF-8?q?390=C2=B0=20Angle=20limit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- opendbc/car/byd/values.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opendbc/car/byd/values.py b/opendbc/car/byd/values.py index a1f4ed3b1d5..a81fc668952 100644 --- a/opendbc/car/byd/values.py +++ b/opendbc/car/byd/values.py @@ -18,7 +18,7 @@ class CarControllerParams: STEER_STEP = 2 # Angle command is sent at 50 Hz ANGLE_LIMITS: AngleSteeringLimits = AngleSteeringLimits( - 360, # deg + 390, # deg # BYD uses a vehicle model instead, check carcontroller.py for details ([], []), ([], []), From 95ad9b471e6fd624e4d1337f0d2ddc28eda9f74b Mon Sep 17 00:00:00 2001 From: lukasloetkolben <61192133+lukasloetkolben@users.noreply.github.com> Date: Wed, 22 Apr 2026 15:42:56 +0200 Subject: [PATCH 3/9] BYD: LKAS_HUD_ADAS message --- opendbc/car/byd/bydcan.py | 20 +++++++------------- opendbc/car/byd/carcontroller.py | 2 +- opendbc/car/byd/carstate.py | 9 +++++++++ opendbc/dbc/byd_atto3.dbc | 30 ++++++++++++++++-------------- 4 files changed, 33 insertions(+), 28 deletions(-) diff --git a/opendbc/car/byd/bydcan.py b/opendbc/car/byd/bydcan.py index be755b56c14..cd356fc496f 100644 --- a/opendbc/car/byd/bydcan.py +++ b/opendbc/car/byd/bydcan.py @@ -29,17 +29,11 @@ def create_buttons(packer, cancel: bool): return packer.make_can_msg("PCM_BUTTONS", 0, values) -def create_lkas_hud(packer, lat_active: bool, counter: int): - values = { - # TODO: test STEER_ACTIVE_1_1 to 3 individual - "STEER_ACTIVE_1_1": 1 if lat_active else 0, - "STEER_ACTIVE_1_2": 1 if lat_active else 0, - "STEER_ACTIVE_1_3": 1 if lat_active else 0, - "STEER_ACTIVE_ACTIVE_LOW": 0 if lat_active else 1, - "LSS_STATE": 2 if lat_active else 0, - "SET_ME_1_2": 1, - "SET_ME_X5F": 0x5F, - "SET_ME_XFF": 0xFF, - "COUNTER": counter, - } +def create_lkas_hud(packer, lat_active: bool, counter: int, stock_lkas_hud: dict): + values = {**stock_lkas_hud, "COUNTER": counter, "HANDS_ON_WHEEL_REQ": 0} + if lat_active: + values["LKS_MODE"] = 2 + values["LKAS_STATE"] = 2 + values["LEFT_LANE_STATE"] = 2 + values["RIGHT_LANE_STATE"] = 2 return packer.make_can_msg("LKAS_HUD_ADAS", 0, values) diff --git a/opendbc/car/byd/carcontroller.py b/opendbc/car/byd/carcontroller.py index fb35212a23e..45e9e4785ea 100644 --- a/opendbc/car/byd/carcontroller.py +++ b/opendbc/car/byd/carcontroller.py @@ -31,7 +31,7 @@ def update(self, CC, CS, now_nanos): cntr = (self.frame // 2) % 16 can_sends.append(bydcan.create_steering_control(self.packer, self.apply_angle_last, CC.latActive, cntr)) - can_sends.append(bydcan.create_lkas_hud(self.packer, CC.latActive, cntr)) + can_sends.append(bydcan.create_lkas_hud(self.packer, CC.latActive, cntr, CS.lkas_hud)) if CC.cruiseControl.cancel and self.frame % 10 == 0: can_sends.append(bydcan.create_buttons(self.packer, cancel=True)) diff --git a/opendbc/car/byd/carstate.py b/opendbc/car/byd/carstate.py index 96eea9e284b..e0f4645a075 100644 --- a/opendbc/car/byd/carstate.py +++ b/opendbc/car/byd/carstate.py @@ -1,3 +1,5 @@ +import copy + from opendbc.car import Bus, structs from opendbc.can.parser import CANParser from opendbc.car.common.conversions import Conversions as CV @@ -16,6 +18,10 @@ class CarState(CarStateBase): + def __init__(self, CP): + super().__init__(CP) + self.lkas_hud = {} + def update(self, can_parsers) -> structs.CarState: cp = can_parsers[Bus.pt] cp_cam = can_parsers[Bus.cam] @@ -64,6 +70,9 @@ def update(self, can_parsers) -> structs.CarState: ret.cruiseState.enabled = acc_state in (3, 5) ret.cruiseState.standstill = bool(cp_cam.vl["ACC_CMD"]["STANDSTILL_STATE"]) + # forward stock LKAS HUD + self.lkas_hud = copy.copy(cp_cam.vl["LKAS_HUD_ADAS"]) + return ret @staticmethod diff --git a/opendbc/dbc/byd_atto3.dbc b/opendbc/dbc/byd_atto3.dbc index 579a3b05d91..42e94d46da1 100644 --- a/opendbc/dbc/byd_atto3.dbc +++ b/opendbc/dbc/byd_atto3.dbc @@ -83,20 +83,22 @@ BO_ 660 METER_CLUSTER: 8 BCM SG_ SEATBELT_DRIVER : 17|1@0+ (1,0) [0|1] "" MCU BO_ 790 LKAS_HUD_ADAS: 8 MPC_CAM - SG_ HMA : 4|5@0+ (1,0) [0|31] "" MCU - SG_ STEER_ACTIVE_1_1 : 5|1@0+ (1,0) [0|1] "" MCU - SG_ LSS_STATE : 7|2@0+ (1,0) [0|3] "" MCU - SG_ HAND_ON_WHEEL_WARNING : 10|1@0+ (1,0) [0|1] "" MCU - SG_ SET_ME_XFF : 23|8@0+ (1,0) [0|255] "" MCU - SG_ SET_ME_X5F : 31|8@0+ (1,0) [0|255] "" MCU - SG_ SET_ME_1_2 : 32|1@0+ (1,0) [0|1] "" MCU - SG_ STEER_ACTIVE_1_3 : 35|1@0+ (1,0) [0|1] "" MCU - SG_ STEER_ACTIVE_ACTIVE_LOW : 36|1@0+ (1,0) [0|1] "" MCU - SG_ STEER_ACTIVE_1_2 : 37|1@0+ (1,0) [0|1] "" MCU - SG_ TSR : 47|8@0+ (1,0) [0|255] "" MCU - SG_ SETTINGS : 48|4@1+ (1,0) [0|15] "" MCU - SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" MCU - SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" MCU + SG_ HMA_STATE : 3|4@0+ (1,0) [0|15] "" MCU + SG_ LEFT_LANE_STATE : 4|2@1+ (1,0) [0|3] "" MCU + SG_ LKS_MODE : 6|2@1+ (1,0) [0|3] "" MCU + SG_ HANDS_ON_WHEEL_REQ : 10|1@1+ (1,0) [0|1] "" MCU + SG_ TJA_ICA_STATE : 11|4@1+ (1,0) [0|15] "" MCU + SG_ HMA_ON_OFF : 15|1@0+ (1,0) [0|1] "" MCU + SG_ LKAS_OUTPUT : 16|11@1- (1,0) [-1024|1023] "" MCU + SG_ LKAS_REQ_PREPARE : 27|1@1+ (1,0) [0|1] "" MCU + SG_ LKAS_ACTIVE : 28|1@1+ (1,0) [0|1] "" MCU + SG_ SLA_ON_OFF : 30|1@0+ (1,0) [0|1] "" MCU + SG_ RIGHT_LANE_STATE : 34|2@1+ (1,0) [0|3] "" MCU + SG_ LKAS_STATE : 36|4@1+ (1,0) [0|15] "" MCU + SG_ SPEED_LIMIT_VALUE : 40|8@1+ (5,-5) [-5|1270] "kph" MCU + SG_ LKAS_ALARM_TYPE : 49|2@0+ (1,0) [0|3] "" MCU + SG_ COUNTER : 52|4@1+ (1,0) [0|15] "" MCU + SG_ CHECKSUM : 56|8@1+ (1,0) [0|255] "" MCU BO_ 813 ACC_HUD_ADAS: 8 ADAS_ECU SG_ SET_SPEED : 0|8@1+ (0.5,0) [0|127.5] "kph" MCU From cc711e05d2de3e9e157bcd7394670f7e5f44177b Mon Sep 17 00:00:00 2001 From: lukasloetkolben <61192133+lukasloetkolben@users.noreply.github.com> Date: Wed, 22 Apr 2026 16:52:28 +0200 Subject: [PATCH 4/9] BYD: improve DBC and add Blindspot --- opendbc/car/byd/bydcan.py | 4 ++-- opendbc/car/byd/carstate.py | 4 ++++ opendbc/dbc/byd_atto3.dbc | 43 ++++++++++++++++++++++++++++++------- 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/opendbc/car/byd/bydcan.py b/opendbc/car/byd/bydcan.py index cd356fc496f..24088f7c9b0 100644 --- a/opendbc/car/byd/bydcan.py +++ b/opendbc/car/byd/bydcan.py @@ -11,8 +11,8 @@ def create_steering_control(packer, apply_angle: float, lat_active: bool, counte "STEER_ANGLE": apply_angle, "ANGLE_RATE_LIMIT_UPPER": rate_limit, "ANGLE_RATE_LIMIT_LOWER": -rate_limit, - "SET_ME_1_1": 1, - "SET_ME_1_2": 1, + "E2E_ALIVE_1": 1, + "E2E_ALIVE_2": 1, "SET_ME_FF": 0xFF, "SET_ME_F": 0xF, "COUNTER": counter, diff --git a/opendbc/car/byd/carstate.py b/opendbc/car/byd/carstate.py index e0f4645a075..67579bd7cef 100644 --- a/opendbc/car/byd/carstate.py +++ b/opendbc/car/byd/carstate.py @@ -53,6 +53,10 @@ def update(self, can_parsers) -> structs.CarState: ret.leftBlinker = bool(cp.vl["STALKS"]["LEFT_BLINKER"]) ret.rightBlinker = bool(cp.vl["STALKS"]["RIGHT_BLINKER"]) + # blind spot monitor + ret.leftBlindspot = cp.vl["BSD_RADAR"]["LEFT_APPROACH"] != 0 + ret.rightBlindspot = cp.vl["BSD_RADAR"]["RIGHT_APPROACH"] != 0 + # doors / belt ret.doorOpen = any(( cp.vl["METER_CLUSTER"]["FRONT_LEFT_DOOR"], diff --git a/opendbc/dbc/byd_atto3.dbc b/opendbc/dbc/byd_atto3.dbc index 42e94d46da1..8fb321487b2 100644 --- a/opendbc/dbc/byd_atto3.dbc +++ b/opendbc/dbc/byd_atto3.dbc @@ -33,15 +33,21 @@ NS_ : BS_: -BU_: EPS ESP_ECU BCM VCU MPC_CAM ADAS_ECU MCU +BU_: EPS ESP_ECU BCM VCU MPC_CAM ADAS_ECU MCU BSD BO_ 287 STEER_MODULE_2: 5 EPS - SG_ STEER_ANGLE_2 : 0|16@1- (0.1,0) [-3276.8|3276.7] "deg" MCU,ADAS_ECU + SG_ STEER_ANGLE_2 : 0|16@1- (0.1,0) [-780|780] "deg" MCU,ADAS_ECU SG_ DRIVER_EPS_TORQUE : 16|8@1+ (1,0) [0|255] "" MCU,ADAS_ECU SG_ COUNTER : 35|4@0+ (1,0) [0|15] "" MCU SG_ CHECKSUM_4BIT : 39|4@0+ (1,0) [0|15] "" MCU +BO_ 290 WHEEL_SPEED: 8 ESP_ECU + SG_ WHEELSPEED_FL : 0|16@1+ (0.1,0) [0|6553.5] "kph" MCU,ADAS_ECU + SG_ WHEELSPEED_FR : 16|16@1+ (0.1,0) [0|6553.5] "kph" MCU,ADAS_ECU + SG_ WHEELSPEED_BL : 32|16@1+ (0.1,0) [0|6553.5] "kph" MCU,ADAS_ECU + SG_ WHEELSPEED_BR : 48|16@1+ (0.1,0) [0|6553.5] "kph" MCU,ADAS_ECU + BO_ 307 STALKS: 8 BCM SG_ LEFT_BLINKER : 37|1@0+ (1,0) [0|1] "" MCU SG_ RIGHT_BLINKER : 38|1@0+ (1,0) [0|1] "" MCU @@ -52,8 +58,8 @@ BO_ 482 STEERING_MODULE_ADAS: 8 ADAS_ECU SG_ ANGLE_RATE_LIMIT_LOWER : 10|10@1- (1,0) [-512|511] "" EPS SG_ STEER_REQ_ACTIVE_LOW : 20|1@0+ (1,0) [0|1] "" EPS SG_ STEER_REQ : 21|1@0+ (1,0) [0|1] "" EPS - SG_ SET_ME_1_2 : 22|1@0+ (1,0) [0|1] "" EPS - SG_ SET_ME_1_1 : 23|1@0+ (1,0) [0|1] "" EPS + SG_ E2E_ALIVE_2 : 22|1@0+ (1,0) [0|1] "" EPS + SG_ E2E_ALIVE_1 : 23|1@0+ (1,0) [0|1] "" EPS SG_ STEER_ANGLE : 24|16@1- (0.1,0) [-3276.8|3276.7] "deg" EPS SG_ SET_ME_FF : 47|8@0+ (1,0) [0|255] "" EPS SG_ SET_ME_F : 48|4@1+ (1,0) [0|15] "" EPS @@ -66,8 +72,15 @@ BO_ 496 WHEELSPEED_CLEAN: 8 ESP_ECU SG_ CHECKSUM : 56|8@1+ (1,0) [0|255] "" MCU BO_ 508 STEERING_TORQUE: 8 EPS - SG_ MAIN_TORQUE : 0|16@1- (0.1,0) [-3276.8|3276.7] "" MCU,ADAS_ECU - SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" MCU + SG_ LKS_PREPARED : 0|1@1+ (1,0) [0|1] "" MCU,ADAS_ECU + SG_ CRUISE_ACTIVATED : 1|1@1+ (1,0) [0|1] "" MCU,ADAS_ECU + SG_ TORQUE_FAILED : 2|1@1+ (1,0) [0|1] "" MCU,ADAS_ECU + SG_ DRIVER_TORQUE : 4|12@1- (0.1,0) [-204.8|204.7] "Nm" MCU,ADAS_ECU + SG_ TARGET_ANGLE : 16|16@1- (0.1,0) [-3276.8|3276.7] "deg" MCU,ADAS_ECU + SG_ MAIN_TORQUE : 32|12@1- (1,0) [-2048|2047] "" MCU,ADAS_ECU + SG_ HANDS_ON_WHEEL_WARN : 45|1@1+ (1,0) [0|1] "" MCU,ADAS_ECU + SG_ TORQUE_TEMP_FAILED : 46|2@1+ (1,0) [0|3] "" MCU,ADAS_ECU + SG_ COUNTER : 52|4@1+ (1,0) [0|15] "" MCU SG_ CHECKSUM : 56|8@1+ (1,0) [0|255] "" MCU BO_ 578 DRIVE_STATE: 8 VCU @@ -92,11 +105,11 @@ BO_ 790 LKAS_HUD_ADAS: 8 MPC_CAM SG_ LKAS_OUTPUT : 16|11@1- (1,0) [-1024|1023] "" MCU SG_ LKAS_REQ_PREPARE : 27|1@1+ (1,0) [0|1] "" MCU SG_ LKAS_ACTIVE : 28|1@1+ (1,0) [0|1] "" MCU - SG_ SLA_ON_OFF : 30|1@0+ (1,0) [0|1] "" MCU + SG_ SLA_STATE : 29|3@1+ (1,0) [0|7] "" MCU SG_ RIGHT_LANE_STATE : 34|2@1+ (1,0) [0|3] "" MCU SG_ LKAS_STATE : 36|4@1+ (1,0) [0|15] "" MCU SG_ SPEED_LIMIT_VALUE : 40|8@1+ (5,-5) [-5|1270] "kph" MCU - SG_ LKAS_ALARM_TYPE : 49|2@0+ (1,0) [0|3] "" MCU + SG_ LDSW_TYPE : 49|2@0+ (1,0) [0|3] "" MCU SG_ COUNTER : 52|4@1+ (1,0) [0|15] "" MCU SG_ CHECKSUM : 56|8@1+ (1,0) [0|255] "" MCU @@ -149,7 +162,13 @@ BO_ 944 PCM_BUTTONS: 8 MCU SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" MCU SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" MCU +BO_ 1048 BSD_RADAR: 8 BSD + SG_ LEFT_APPROACH : 9|2@0+ (1,0) [0|3] "" MCU,ADAS_ECU + SG_ RIGHT_APPROACH : 11|2@0+ (1,0) [0|3] "" MCU,ADAS_ECU + SG_ APPROACH : 17|1@0+ (1,0) [0|1] "" MCU,ADAS_ECU + CM_ BO_ 287 "EPS steering wheel angle + driver torque. Validated: angle range plausible, DRIVER_EPS_TORQUE stays near 0 when hands-off."; +CM_ BO_ 290 "Per-wheel speed from ESP (FL/FR/BL/BR). Scale 0.1 kph/bit. Use WHEELSPEED_CLEAN (0x1F0) for the aggregated filtered value openpilot consumes."; CM_ BO_ 307 "Turn signal / stalk info. Validated: LEFT_BLINKER and RIGHT_BLINKER transition 0->1 during lane change events."; CM_ BO_ 482 "Lateral steering command sent by MPC camera/ADAS ECU to EPS. Blocked by panda on bus 2; panda injects its own on bus 0."; CM_ BO_ 496 "Wheel speed (cleaned average). Validated: 0-127 km/h matching driving speed."; @@ -164,3 +183,11 @@ CM_ BO_ 944 "Steering-wheel cruise control buttons."; VAL_ 578 GEAR 4 "D" 2 "R" 3 "N" 1 "P"; VAL_ 813 SET_DISTANCE 4 "4bar" 3 "3bar" 2 "2bar" 1 "1bar"; VAL_ 813 ACC_STATE 0 "OFF" 2 "ACC_ON" 3 "ACC_ACTIVE" 5 "FORCE_ACCEL" 7 "ERROR"; +VAL_ 790 HMA_STATE 0 "OFF" 1 "PASSIVE" 2 "STANDBY" 3 "ACTIVE" 4 "FAULT" 5 "CAMERA_BLOCKED"; +VAL_ 790 LKS_MODE 0 "OFF" 1 "DIVERGE" 2 "KEEPING" 3 "ALL"; +VAL_ 790 TJA_ICA_STATE 0 "OFF" 1 "PASSIVE" 2 "ACTIVE1" 3 "ACTIVE2" 4 "FAULT"; +VAL_ 790 LDSW_TYPE 0 "VIBRATE" 1 "SOUND" 2 "ALL"; +VAL_ 790 SLA_STATE 0 "OFF" 1 "FUSION_MODE" 2 "VISION_MODE" 3 "NV_ONLY_MODE" 4 "DEFECT"; +VAL_ 790 LEFT_LANE_STATE 0 "OFF" 2 "WARNING"; +VAL_ 790 RIGHT_LANE_STATE 0 "OFF" 2 "WARNING"; +VAL_ 508 TORQUE_TEMP_FAILED 1 "TooLarge" 2 "TooFast" 3 "Both"; From adb6de75a5f50f58abfe1fc59b06e9a224eb7565 Mon Sep 17 00:00:00 2001 From: Martin Lillepuu Date: Thu, 16 Apr 2026 11:08:49 +0300 Subject: [PATCH 5/9] Add BYD Sealion 7 dbc --- opendbc/dbc/byd_sealion_7.dbc | 105 ++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 opendbc/dbc/byd_sealion_7.dbc diff --git a/opendbc/dbc/byd_sealion_7.dbc b/opendbc/dbc/byd_sealion_7.dbc new file mode 100644 index 00000000000..6fd00ae9caf --- /dev/null +++ b/opendbc/dbc/byd_sealion_7.dbc @@ -0,0 +1,105 @@ +BO_ 213 BRAKE_POSITION: 8 XXX + SG_ BRAKE_POSITION : 0|9@1+ (1,0) [0|1] "" XXX + +BO_ 287 STEER_ANGLE_SENSOR: 5 XXX + SG_ STEER_RACK_ANGLE : 0|16@1- (0.01,0) [-50|50] "deg" XXX + SG_ STEER_TORQUE_MAG : 16|8@1+ (1,0) [0|255] "Nm" XXX + +BO_ 289 NEW_MSG_121: 8 XXX + +BO_ 482 NEW_MSG_1E2: 8 XXX + SG_ STEER_ANGLE_2 : 24|16@1- (0.01,0) [0|65535] "" XXX + +BO_ 496 WHEEL_SPEEDS: 8 XXX + SG_ WHEEL_FL : 0|12@1+ (0.075,0) [0|4095] "" XXX + SG_ WHEEL_FR : 16|12@1+ (0.075,0) [0|4095] "" XXX + SG_ WHEEL_RL : 28|12@1+ (0.075,0) [0|31] "" XXX + SG_ WHEEL_RR : 40|12@1+ (0.075,0) [0|8191] "" XXX + SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" XXX + SG_ CHECKSUM : 56|8@1+ (1,0) [0|255] "" XXX + +BO_ 508 ICC_STEERING: 8 XXX + SG_ ICC_STEERING_STATE : 1|1@0+ (1,0) [0|1] "" XXX + SG_ STEER_ANGLE_EPS : 4|28@1- (1,0) [-1000|1000] "" XXX + SG_ EPS_STEERING : 32|12@1- (1,0) [-2048|2047] "" XXX + SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" XXX + SG_ CHECKSUM : 63|8@0+ (1,0) [0|15] "" XXX + +BO_ 537 BRAKE: 8 XXX + SG_ BRAKE_PRESSED : 2|1@0+ (1,0) [0|1] "" XXX + +BO_ 544 NEW_MSG_220: 8 XXX + +BO_ 546 YAW_RATE: 8 XXX + SG_ YAW_RATE : 0|11@1+ (1,-982) [0|2047] "" XXX + +BO_ 547 NEW_MSG_223: 8 XXX + +BO_ 578 NEW_MSG_242: 8 XXX + SG_ GAS_PEDAL_2 : 30|7@0+ (1,0) [0|127] "" XXX + SG_ BRAKE_STATE : 37|1@0+ (1,0) [0|1] "" XXX + +BO_ 660 SEATBELT: 8 XXX + SG_ DOOR_FL_OPEN : 1|1@0+ (1,0) [0|1] "" XXX + SG_ DOOR_FR_OPEN : 3|1@0+ (1,0) [0|1] "" XXX + SG_ DOOR_RL_OPEN : 5|1@0+ (1,0) [0|1] "" XXX + SG_ DOOR_RR_OPEN : 7|1@0+ (1,0) [0|1] "" XXX + SG_ SEATBELT_DRIVER_LATCHED : 17|1@0+ (1,0) [0|1] "" XXX + +BO_ 661 NEW_MSG_295: 8 XXX + +BO_ 790 ICC_STATE: 8 XXX + SG_ ACC_ON : 27|1@0+ (1,0) [0|1] "" XXX + SG_ ICC_ON : 28|1@0+ (1,0) [0|1] "" XXX + SG_ NEW_SIGNAL_1 : 55|4@0+ (1,0) [0|15] "" XXX + SG_ NEW_SIGNAL_2 : 63|4@0+ (1,0) [0|15] "" XXX + +BO_ 814 ICC_GAS_NOTSURE: 8 XXX + SG_ GAS_NOTSURE : 7|16@0+ (1,0) [0|65535] "" XXX + SG_ CHECKSUM : 51|12@0+ (1,0) [0|4095] "" XXX + +BO_ 834 PEDALS: 8 XXX + SG_ GAS_PEDAL : 6|7@0+ (1,0) [0|127] "" XXX + SG_ BRAKE_PRESSED : 14|7@0+ (1,0) [0|1] "" XXX + SG_ DRIVE_MODE : 22|3@0+ (1,0) [0|7] "" XXX + SG_ COUNTER : 55|12@0+ (1,0) [0|4095] "" XXX + +BO_ 854 NEW_MSG_356: 8 XXX + +BO_ 860 GEAR_STATE: 8 XXX + SG_ GEAR_STATE : 8|3@1+ (1,0) [0|7] "" XXX + +BO_ 906 LIGHTS: 8 XXX + SG_ BRIGHTS : 4|1@0+ (1,0) [0|1] "" XXX + SG_ LEFT_TURN : 37|1@0+ (1,0) [0|1] "" XXX + SG_ RIGHT_TURN : 38|1@0+ (1,0) [0|1] "" XXX + SG_ BRAKE_LIGHT : 59|1@0+ (1,0) [0|1] "" XXX + +BO_ 944 STEERING_WHEEL_BUTTONS: 8 XXX + SG_ ACC_SPEED_BUTTON_MINUS : 3|1@1+ (1,0) [0|3] "" XXX + SG_ ACC_SPEED_BUTTON_PLUS : 4|2@0+ (1,0) [0|3] "" XXX + SG_ ACC_BUTTON : 6|1@0+ (1,0) [0|1] "" XXX + SG_ ACC_DISTANCE_BUTTON_NOTSURE_MINUS : 15|1@0+ (1,0) [0|1] "" XXX + SG_ ACC_DISTANCE_BUTTON_NOTSURE_PLUS : 16|1@0+ (1,0) [0|1] "" XXX + +BO_ 1028 IGNITION: 8 XXX + SG_ IGNITION_ON : 6|1@0+ (1,0) [0|1] "" XXX + +BO_ 1033 NEW_MSG_409: 8 XXX + +BO_ 1040 xxxx: 8 XXX + +BO_ 1058 MAYBE_RPM: 8 XXX + +BO_ 1092 NEW_MSG_444: 8 XXX + +BO_ 1093 maybe_ignition: 8 XXX + +BO_ 1189 NEW_MSG_4A5: 8 XXX + +BO_ 1193 DRIVING_MODE_BUTTON: 8 XXX + SG_ DRIVING_MODE_BUTTON_PRESSED : 40|1@0+ (1,0) [0|1] "" XXX + +CM_ BO_ 1193 "to be deleted"; +VAL_ 834 DRIVE_MODE 0 "RESERVED" 1 "ECO" 2 "SPORT" 3 "SNOW" 4 "NORMAL" 5 "RESERVED" 6 "RESERVED" 7 "RESERVED"; +VAL_ 860 GEAR_STATE 1 "P" 2 "R" 3 "N" 4 "D" 0 "UNKNOWN" 5 "UNKNOWN" 6 "UNKNOWN" 7 "UNKNOWN"; From cdc35b6160c94b21b781a63fd336985fdeee04f8 Mon Sep 17 00:00:00 2001 From: Martin Lillepuu Date: Tue, 21 Apr 2026 22:03:04 +0300 Subject: [PATCH 6/9] BYD: update Sealion 7 dbc --- opendbc/dbc/byd_sealion_7.dbc | 249 ++++++++++++++++++++++------------ 1 file changed, 163 insertions(+), 86 deletions(-) diff --git a/opendbc/dbc/byd_sealion_7.dbc b/opendbc/dbc/byd_sealion_7.dbc index 6fd00ae9caf..b1c44ebeeb9 100644 --- a/opendbc/dbc/byd_sealion_7.dbc +++ b/opendbc/dbc/byd_sealion_7.dbc @@ -1,70 +1,143 @@ -BO_ 213 BRAKE_POSITION: 8 XXX - SG_ BRAKE_POSITION : 0|9@1+ (1,0) [0|1] "" XXX - -BO_ 287 STEER_ANGLE_SENSOR: 5 XXX - SG_ STEER_RACK_ANGLE : 0|16@1- (0.01,0) [-50|50] "deg" XXX - SG_ STEER_TORQUE_MAG : 16|8@1+ (1,0) [0|255] "Nm" XXX - -BO_ 289 NEW_MSG_121: 8 XXX - -BO_ 482 NEW_MSG_1E2: 8 XXX - SG_ STEER_ANGLE_2 : 24|16@1- (0.01,0) [0|65535] "" XXX - -BO_ 496 WHEEL_SPEEDS: 8 XXX - SG_ WHEEL_FL : 0|12@1+ (0.075,0) [0|4095] "" XXX - SG_ WHEEL_FR : 16|12@1+ (0.075,0) [0|4095] "" XXX - SG_ WHEEL_RL : 28|12@1+ (0.075,0) [0|31] "" XXX - SG_ WHEEL_RR : 40|12@1+ (0.075,0) [0|8191] "" XXX - SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" XXX - SG_ CHECKSUM : 56|8@1+ (1,0) [0|255] "" XXX - -BO_ 508 ICC_STEERING: 8 XXX - SG_ ICC_STEERING_STATE : 1|1@0+ (1,0) [0|1] "" XXX - SG_ STEER_ANGLE_EPS : 4|28@1- (1,0) [-1000|1000] "" XXX - SG_ EPS_STEERING : 32|12@1- (1,0) [-2048|2047] "" XXX - SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" XXX - SG_ CHECKSUM : 63|8@0+ (1,0) [0|15] "" XXX - -BO_ 537 BRAKE: 8 XXX +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_: EPS ESP_ECU BCM VCU MPC_CAM ADAS_ECU MCU + + +BO_ 287 STEER_MODULE_2: 5 EPS + SG_ STEER_ANGLE_2 : 0|16@1- (0.1,0) [-3276.8|3276.7] "deg" MCU,ADAS_ECU + SG_ DRIVER_EPS_TORQUE : 16|8@1+ (1,0) [0|255] "" MCU,ADAS_ECU + SG_ COUNTER : 35|4@0+ (1,0) [0|15] "" MCU + SG_ CHECKSUM_4BIT : 39|4@0+ (1,0) [0|15] "" MCU + +BO_ 307 STALKS: 8 BCM + SG_ LEFT_BLINKER : 37|1@0+ (1,0) [0|1] "" MCU + SG_ RIGHT_BLINKER : 38|1@0+ (1,0) [0|1] "" MCU + SG_ COUNTER : 48|4@1+ (1,0) [0|15] "" MCU + +BO_ 482 STEERING_MODULE_ADAS: 8 ADAS_ECU + SG_ ANGLE_RATE_LIMIT_UPPER : 0|10@1- (1,0) [-512|511] "" EPS + SG_ ANGLE_RATE_LIMIT_LOWER : 10|10@1- (1,0) [-512|511] "" EPS + SG_ STEER_REQ_ACTIVE_LOW : 20|1@0+ (1,0) [0|1] "" EPS + SG_ STEER_REQ : 21|1@0+ (1,0) [0|1] "" EPS + SG_ SET_ME_1_2 : 22|1@0+ (1,0) [0|1] "" EPS + SG_ SET_ME_1_1 : 23|1@0+ (1,0) [0|1] "" EPS + SG_ STEER_ANGLE : 24|16@1- (0.1,0) [-3276.8|3276.7] "deg" EPS + SG_ SET_ME_FF : 47|8@0+ (1,0) [0|255] "" EPS + SG_ SET_ME_F : 48|4@1+ (1,0) [0|15] "" EPS + SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" EPS + SG_ CHECKSUM : 56|8@1+ (1,0) [0|255] "" EPS + +BO_ 496 WHEELSPEED_CLEAN: 8 ESP_ECU + SG_ WHEELSPEED_CLEAN : 0|16@1+ (0.1,0) [0|6553.5] "kph" MCU + SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" MCU + SG_ CHECKSUM : 56|8@1+ (1,0) [0|255] "" MCU + +BO_ 508 STEERING_TORQUE: 8 EPS + SG_ MAIN_TORQUE : 0|16@1- (0.1,0) [-3276.8|3276.7] "" MCU,ADAS_ECU + SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" MCU + SG_ CHECKSUM : 56|8@1+ (1,0) [0|255] "" MCU + +BO_ 537 SL7_BRAKE: 8 XXX SG_ BRAKE_PRESSED : 2|1@0+ (1,0) [0|1] "" XXX -BO_ 544 NEW_MSG_220: 8 XXX - -BO_ 546 YAW_RATE: 8 XXX - SG_ YAW_RATE : 0|11@1+ (1,-982) [0|2047] "" XXX - -BO_ 547 NEW_MSG_223: 8 XXX - -BO_ 578 NEW_MSG_242: 8 XXX - SG_ GAS_PEDAL_2 : 30|7@0+ (1,0) [0|127] "" XXX - SG_ BRAKE_STATE : 37|1@0+ (1,0) [0|1] "" XXX - -BO_ 660 SEATBELT: 8 XXX - SG_ DOOR_FL_OPEN : 1|1@0+ (1,0) [0|1] "" XXX - SG_ DOOR_FR_OPEN : 3|1@0+ (1,0) [0|1] "" XXX - SG_ DOOR_RL_OPEN : 5|1@0+ (1,0) [0|1] "" XXX - SG_ DOOR_RR_OPEN : 7|1@0+ (1,0) [0|1] "" XXX - SG_ SEATBELT_DRIVER_LATCHED : 17|1@0+ (1,0) [0|1] "" XXX - -BO_ 661 NEW_MSG_295: 8 XXX - -BO_ 790 ICC_STATE: 8 XXX - SG_ ACC_ON : 27|1@0+ (1,0) [0|1] "" XXX - SG_ ICC_ON : 28|1@0+ (1,0) [0|1] "" XXX - SG_ NEW_SIGNAL_1 : 55|4@0+ (1,0) [0|15] "" XXX - SG_ NEW_SIGNAL_2 : 63|4@0+ (1,0) [0|15] "" XXX - -BO_ 814 ICC_GAS_NOTSURE: 8 XXX - SG_ GAS_NOTSURE : 7|16@0+ (1,0) [0|65535] "" XXX - SG_ CHECKSUM : 51|12@0+ (1,0) [0|4095] "" XXX - -BO_ 834 PEDALS: 8 XXX - SG_ GAS_PEDAL : 6|7@0+ (1,0) [0|127] "" XXX - SG_ BRAKE_PRESSED : 14|7@0+ (1,0) [0|1] "" XXX +BO_ 578 DRIVE_STATE: 8 VCU + SG_ RAW_THROTTLE : 30|7@0+ (1,0) [0|127] "" MCU + SG_ BRAKE_PRESSED : 37|1@0+ (1,0) [0|1] "" MCU,ADAS_ECU + SG_ GEAR : 40|3@1+ (1,0) [0|7] "" MCU + +BO_ 660 METER_CLUSTER: 8 BCM + SG_ FRONT_RIGHT_DOOR : 1|1@1+ (1,0) [0|1] "" MCU + SG_ FRONT_LEFT_DOOR : 3|1@0+ (1,0) [0|1] "" MCU + SG_ BACK_LEFT_DOOR : 5|1@1+ (1,0) [0|1] "" MCU + SG_ BACK_RIGHT_DOOR : 7|1@0+ (1,0) [0|1] "" MCU + SG_ SEATBELT_DRIVER : 17|1@0+ (1,0) [0|1] "" MCU + +BO_ 790 LKAS_HUD_ADAS: 8 MPC_CAM + SG_ HMA : 4|5@0+ (1,0) [0|31] "" MCU + SG_ STEER_ACTIVE_1_1 : 5|1@0+ (1,0) [0|1] "" MCU + SG_ LSS_STATE : 7|2@0+ (1,0) [0|3] "" MCU + SG_ HAND_ON_WHEEL_WARNING : 10|1@0+ (1,0) [0|1] "" MCU + SG_ SET_ME_XFF : 23|8@0+ (1,0) [0|255] "" MCU + SG_ SET_ME_X5F : 31|8@0+ (1,0) [0|255] "" MCU + SG_ SET_ME_1_2 : 32|1@0+ (1,0) [0|1] "" MCU + SG_ STEER_ACTIVE_1_3 : 35|1@0+ (1,0) [0|1] "" MCU + SG_ STEER_ACTIVE_ACTIVE_LOW : 36|1@0+ (1,0) [0|1] "" MCU + SG_ STEER_ACTIVE_1_2 : 37|1@0+ (1,0) [0|1] "" MCU + SG_ TSR : 47|8@0+ (1,0) [0|255] "" MCU + SG_ SETTINGS : 48|4@1+ (1,0) [0|15] "" MCU + SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" MCU + SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" MCU + +BO_ 813 ACC_HUD_ADAS: 8 ADAS_ECU + SG_ SET_SPEED : 0|8@1+ (0.5,0) [0|127.5] "kph" MCU + SG_ SET_DISTANCE : 12|3@0+ (1,0) [0|7] "" MCU + SG_ ACC_STATE : 19|3@1+ (1,0) [0|7] "" MCU + SG_ ACC_ON2 : 20|1@0+ (1,0) [0|1] "" MCU + SG_ ACC_ON1 : 22|1@0+ (1,0) [0|1] "" MCU + SG_ SET_ME_XFF : 47|8@0+ (1,0) [0|255] "" MCU + SG_ COUNTER : 48|4@1+ (1,0) [0|15] "" MCU + SG_ SET_ME_XF : 55|4@0+ (1,0) [0|15] "" MCU + SG_ CHECKSUM : 56|8@1+ (1,0) [0|255] "" MCU + +BO_ 814 ACC_CMD: 8 ADAS_ECU + SG_ ACCEL_CMD : 0|8@1+ (1,-100) [-100|155] "" MCU + SG_ ACC_ON_1 : 9|1@0+ (1,0) [0|1] "" MCU + SG_ SET_ME_25_1 : 10|6@1+ (1,0) [0|63] "" MCU + SG_ ACC_ON_2 : 17|1@0+ (1,0) [0|1] "" MCU + SG_ SET_ME_25_2 : 18|6@1+ (1,0) [0|63] "" MCU + SG_ DECEL_FACTOR : 24|4@1+ (1,0) [0|15] "" MCU + SG_ SET_ME_X8 : 31|4@0+ (1,0) [0|15] "" MCU + SG_ ACCEL_FACTOR : 32|4@1+ (1,0) [0|15] "" MCU + SG_ CMD_REQ_ACTIVE_LOW : 36|1@0+ (1,0) [0|1] "" MCU + SG_ SET_ME_1 : 38|1@0+ (1,0) [0|1] "" MCU + SG_ STANDSTILL_RESUME : 39|1@0+ (1,0) [0|1] "" MCU + SG_ STANDSTILL_STATE : 40|1@0+ (1,0) [0|1] "" MCU + SG_ ACC_REQ_NOT_STANDSTILL : 43|1@0+ (1,0) [0|1] "" MCU + SG_ ACC_CONTROLLABLE_AND_ON : 44|1@0+ (1,0) [0|1] "" MCU + SG_ ACC_OVERRIDE_OR_STANDSTILL : 45|1@0+ (1,0) [0|1] "" MCU + SG_ COUNTER : 48|4@1+ (1,0) [0|15] "" MCU + SG_ SET_ME_XF : 55|4@0+ (1,0) [0|15] "" MCU + SG_ CHECKSUM : 56|8@1+ (1,0) [0|255] "" MCU + +BO_ 834 PEDAL: 8 VCU + SG_ GAS_PEDAL : 0|8@1+ (0.01,0) [0|2.55] "" MCU + SG_ BRAKE_PEDAL : 8|8@1+ (0.01,0) [0|2.55] "" MCU SG_ DRIVE_MODE : 22|3@0+ (1,0) [0|7] "" XXX - SG_ COUNTER : 55|12@0+ (1,0) [0|4095] "" XXX - -BO_ 854 NEW_MSG_356: 8 XXX + SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" MCU + SG_ CHECKSUM : 56|8@1+ (1,0) [0|255] "" MCU BO_ 860 GEAR_STATE: 8 XXX SG_ GEAR_STATE : 8|3@1+ (1,0) [0|7] "" XXX @@ -75,31 +148,35 @@ BO_ 906 LIGHTS: 8 XXX SG_ RIGHT_TURN : 38|1@0+ (1,0) [0|1] "" XXX SG_ BRAKE_LIGHT : 59|1@0+ (1,0) [0|1] "" XXX -BO_ 944 STEERING_WHEEL_BUTTONS: 8 XXX - SG_ ACC_SPEED_BUTTON_MINUS : 3|1@1+ (1,0) [0|3] "" XXX - SG_ ACC_SPEED_BUTTON_PLUS : 4|2@0+ (1,0) [0|3] "" XXX - SG_ ACC_BUTTON : 6|1@0+ (1,0) [0|1] "" XXX - SG_ ACC_DISTANCE_BUTTON_NOTSURE_MINUS : 15|1@0+ (1,0) [0|1] "" XXX - SG_ ACC_DISTANCE_BUTTON_NOTSURE_PLUS : 16|1@0+ (1,0) [0|1] "" XXX +BO_ 944 PCM_BUTTONS: 8 MCU + SG_ SET_ME_1_1 : 2|1@0+ (1,0) [0|1] "" MCU + SG_ SET_BTN : 3|1@0+ (1,0) [0|1] "" MCU + SG_ RES_BTN : 4|1@0+ (1,0) [0|1] "" MCU + SG_ LKAS_ON_BTN : 6|1@0+ (1,0) [0|1] "" MCU + SG_ SET_ME_1_2 : 12|1@0+ (1,0) [0|1] "" MCU + SG_ DEC_DISTANCE_BTN : 15|1@0+ (1,0) [0|1] "" MCU + SG_ INC_DISTANCE_BTN : 16|1@0+ (1,0) [0|1] "" MCU + SG_ ACC_ON_BTN : 19|1@0+ (1,0) [0|1] "" MCU + SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" MCU + SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" MCU BO_ 1028 IGNITION: 8 XXX SG_ IGNITION_ON : 6|1@0+ (1,0) [0|1] "" XXX -BO_ 1033 NEW_MSG_409: 8 XXX - -BO_ 1040 xxxx: 8 XXX - -BO_ 1058 MAYBE_RPM: 8 XXX - -BO_ 1092 NEW_MSG_444: 8 XXX - -BO_ 1093 maybe_ignition: 8 XXX - -BO_ 1189 NEW_MSG_4A5: 8 XXX - -BO_ 1193 DRIVING_MODE_BUTTON: 8 XXX - SG_ DRIVING_MODE_BUTTON_PRESSED : 40|1@0+ (1,0) [0|1] "" XXX - -CM_ BO_ 1193 "to be deleted"; +CM_ BO_ 287 "EPS steering wheel angle + driver torque. Validated: angle range plausible, DRIVER_EPS_TORQUE stays near 0 when hands-off."; +CM_ BO_ 307 "Turn signal / stalk info. Validated: LEFT_BLINKER and RIGHT_BLINKER transition 0->1 during lane change events."; +CM_ BO_ 482 "Lateral steering command sent by MPC camera/ADAS ECU to EPS. Blocked by panda on bus 2; panda injects its own on bus 0."; +CM_ BO_ 496 "Wheel speed (cleaned average). Validated: 0-127 km/h matching driving speed."; +CM_ BO_ 508 "Column steering torque from EPS."; +CM_ BO_ 578 "Drivetrain state: gear, brake pressed, raw throttle."; +CM_ BO_ 660 "Body/meter cluster: doors + seatbelt."; +CM_ BO_ 790 "LKAS HUD ADAS message from camera. Blocked by panda on bus 2; panda re-injects."; +CM_ BO_ 813 "ACC HUD ADAS message (cruise set speed, distance, ACC state)."; +CM_ BO_ 814 "ACC acceleration command from ADAS ECU. Blocked by panda on bus 2 when OP longitudinal active."; +CM_ BO_ 834 "Gas/brake pedal percentages."; +CM_ BO_ 944 "Steering-wheel cruise control buttons."; +VAL_ 578 GEAR 4 "D" 2 "R" 3 "N" 1 "P"; +VAL_ 813 SET_DISTANCE 4 "4bar" 3 "3bar" 2 "2bar" 1 "1bar"; +VAL_ 813 ACC_STATE 0 "OFF" 2 "ACC_ON" 3 "ACC_ACTIVE" 5 "FORCE_ACCEL" 7 "ERROR"; VAL_ 834 DRIVE_MODE 0 "RESERVED" 1 "ECO" 2 "SPORT" 3 "SNOW" 4 "NORMAL" 5 "RESERVED" 6 "RESERVED" 7 "RESERVED"; VAL_ 860 GEAR_STATE 1 "P" 2 "R" 3 "N" 4 "D" 0 "UNKNOWN" 5 "UNKNOWN" 6 "UNKNOWN" 7 "UNKNOWN"; From f56b9231b90e1657c5f972da518b8537c582ad56 Mon Sep 17 00:00:00 2001 From: Martin Lillepuu Date: Tue, 21 Apr 2026 22:06:13 +0300 Subject: [PATCH 7/9] BYD: update Sealion 7 wheel speeds --- opendbc/dbc/byd_sealion_7.dbc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/opendbc/dbc/byd_sealion_7.dbc b/opendbc/dbc/byd_sealion_7.dbc index b1c44ebeeb9..bf2a5b3cdc4 100644 --- a/opendbc/dbc/byd_sealion_7.dbc +++ b/opendbc/dbc/byd_sealion_7.dbc @@ -61,7 +61,10 @@ BO_ 482 STEERING_MODULE_ADAS: 8 ADAS_ECU SG_ CHECKSUM : 56|8@1+ (1,0) [0|255] "" EPS BO_ 496 WHEELSPEED_CLEAN: 8 ESP_ECU - SG_ WHEELSPEED_CLEAN : 0|16@1+ (0.1,0) [0|6553.5] "kph" MCU + SG_ WHEEL_FL : 0|12@1+ (0.075,0) [0|4095] "" MCU + SG_ WHEEL_FR : 16|12@1+ (0.075,0) [0|4095] "" MCU + SG_ WHEEL_RL : 28|12@1+ (0.075,0) [0|4095] "" MCU + SG_ WHEEL_RR : 40|12@1+ (0.075,0) [0|4095] "" MCU SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" MCU SG_ CHECKSUM : 56|8@1+ (1,0) [0|255] "" MCU From 0837e047edcf248ea612e7cb8bb4f00ce2366a5d Mon Sep 17 00:00:00 2001 From: Martin Lillepuu Date: Tue, 21 Apr 2026 23:42:51 +0300 Subject: [PATCH 8/9] BYD: add initial Sealion 7 support --- opendbc/car/byd/carstate.py | 20 ++++++++++++++------ opendbc/car/byd/interface.py | 18 +++++++++++------- opendbc/car/byd/values.py | 13 ++++++++++++- opendbc/car/tests/routes.py | 1 + opendbc/car/tests/test_fw_fingerprint.py | 4 ++-- opendbc/car/torque_data/override.toml | 1 + opendbc/dbc/byd_sealion_7.dbc | 10 +++++----- 7 files changed, 46 insertions(+), 21 deletions(-) diff --git a/opendbc/car/byd/carstate.py b/opendbc/car/byd/carstate.py index 67579bd7cef..c87d9f149db 100644 --- a/opendbc/car/byd/carstate.py +++ b/opendbc/car/byd/carstate.py @@ -3,7 +3,7 @@ from opendbc.car import Bus, structs from opendbc.can.parser import CANParser from opendbc.car.common.conversions import Conversions as CV -from opendbc.car.byd.values import DBC, CarControllerParams as CCP +from opendbc.car.byd.values import CAR, DBC, CarControllerParams as CCP from opendbc.car.interfaces import CarStateBase GearShifter = structs.CarState.GearShifter @@ -27,12 +27,20 @@ def update(self, can_parsers) -> structs.CarState: cp_cam = can_parsers[Bus.cam] ret = structs.CarState() - # speed - speed_kph = cp.vl["WHEELSPEED_CLEAN"]["WHEELSPEED_CLEAN"] - ret.vEgoRaw = speed_kph * CV.KPH_TO_MS + if self.CP.carFingerprint == CAR.BYD_SEALION_7: + ret.wheelSpeeds.fl = cp.vl["WHEEL_SPEEDS"]["FL"] * CV.KPH_TO_MS + ret.wheelSpeeds.rl = cp.vl["WHEEL_SPEEDS"]["RL"] * CV.KPH_TO_MS + ret.vEgoRaw = (ret.wheelSpeeds.rl + ret.wheelSpeeds.fl) / 2.0 + ret.standstill = ret.vEgoRaw < 0.01 + ret.vEgoCluster = ret.vEgo * 1.068 # FIXME: update dbc multiplier to get correct kph + else: + # speed + speed_kph = cp.vl["WHEELSPEED_CLEAN"]["WHEELSPEED_CLEAN"] + ret.vEgoRaw = speed_kph * CV.KPH_TO_MS + ret.standstill = speed_kph < 0.1 + ret.vEgoCluster = ret.vEgo + ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw) - ret.standstill = speed_kph < 0.1 - ret.vEgoCluster = ret.vEgo # steering wheel ret.steeringAngleDeg = cp.vl["STEER_MODULE_2"]["STEER_ANGLE_2"] diff --git a/opendbc/car/byd/interface.py b/opendbc/car/byd/interface.py index 49209c3b412..0efe20b3c23 100644 --- a/opendbc/car/byd/interface.py +++ b/opendbc/car/byd/interface.py @@ -2,6 +2,7 @@ from opendbc.car.interfaces import CarInterfaceBase from opendbc.car.byd.carcontroller import CarController from opendbc.car.byd.carstate import CarState +from opendbc.car.byd.values import CAR class CarInterface(CarInterfaceBase): @@ -11,16 +12,19 @@ class CarInterface(CarInterfaceBase): @staticmethod def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, alpha_long, is_release, docs) -> structs.CarParams: ret.brand = "byd" + ret.dashcamOnly = True + ret.radarUnavailable = True + ret.alphaLongitudinalAvailable = False ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.byd)] - - ret.dashcamOnly = False - ret.steerControlType = structs.CarParams.SteerControlType.angle - ret.steerActuatorDelay = 0.2 - ret.steerLimitTimer = 0.4 - ret.radarUnavailable = True - ret.alphaLongitudinalAvailable = False + if candidate == CAR.BYD_ATTO_3: + ret.steerActuatorDelay = 0.2 + ret.steerLimitTimer = 0.4 + + elif candidate == CAR.BYD_SEALION_7: + ret.steerActuatorDelay = 0.1 + ret.steerLimitTimer = 0.4 return ret diff --git a/opendbc/car/byd/values.py b/opendbc/car/byd/values.py index a81fc668952..537c652bf24 100644 --- a/opendbc/car/byd/values.py +++ b/opendbc/car/byd/values.py @@ -56,7 +56,6 @@ class BydCarDocs(CarDocs): package: str = "All" car_parts: CarParts = field(default_factory=CarParts.common([CarHarness.custom])) - @dataclass class BydPlatformConfig(PlatformConfig): dbc_dict: DbcDict = field(default_factory=lambda: { @@ -65,6 +64,14 @@ class BydPlatformConfig(PlatformConfig): wmis: set[WMI] = field(default_factory=set) years: set[ModelYear] = field(default_factory=set) +@dataclass +class BydSealionPlatformConfig(PlatformConfig): + dbc_dict: DbcDict = field(default_factory=lambda: { + Bus.pt: 'byd_sealion_7', + }) + wmis: set[WMI] = field(default_factory=set) + years: set[ModelYear] = field(default_factory=set) + class CAR(Platforms): BYD_ATTO_3 = BydPlatformConfig( @@ -73,6 +80,10 @@ class CAR(Platforms): wmis={WMI.BYD_AUTO}, years={ModelYear.N_2022, ModelYear.P_2023, ModelYear.R_2024, ModelYear.S_2025}, ) + BYD_SEALION_7 = BydSealionPlatformConfig( + [BydCarDocs("BYD Sealion 7 2024")], + CarSpecs(mass=2090., wheelbase=2.72, steerRatio=16.0, centerToFrontRatio=0.44) + ) def match_fw_to_car_fuzzy(live_fw_versions, vin, offline_fw_versions) -> set[str]: diff --git a/opendbc/car/tests/routes.py b/opendbc/car/tests/routes.py index 630296c4a40..3e0af73e36a 100644 --- a/opendbc/car/tests/routes.py +++ b/opendbc/car/tests/routes.py @@ -343,6 +343,7 @@ class CarTestRoute(NamedTuple): CarTestRoute("6a7075a4fdd765ee/0000004e--1f612006dd", PSA.PSA_PEUGEOT_208), CarTestRoute("148fa33c79475c93/00000002--bb5e1aa449", BYD.BYD_ATTO_3), + CarTestRoute("148fa33c79475c93/00000002--bb5e1aa449", BYD.BYD_SEALION_7), # FIXME: add route for sealion 7 CarTestRoute("bc095dc92e101734/000000db--ee9fe46e57", RIVIAN.RIVIAN_R1), CarTestRoute("c70d59e4150956fc/0000006e--48bfbfda01", RIVIAN.RIVIAN_R1), # GEN2 diff --git a/opendbc/car/tests/test_fw_fingerprint.py b/opendbc/car/tests/test_fw_fingerprint.py index 2d34e7a1231..cc3686a265b 100644 --- a/opendbc/car/tests/test_fw_fingerprint.py +++ b/opendbc/car/tests/test_fw_fingerprint.py @@ -262,11 +262,11 @@ def fake_get_ecu_addrs(*_, timeout): print(f'get_vin {name} case, query time={self.total_time / self.N} seconds') def test_fw_query_timing(self): - total_ref_time = 7.6 + total_ref_time = 7.4 brand_ref_times = { 'gm': 1.0, 'body': 0.1, - 'byd': 0.2, + 'byd': 0.1, 'chrysler': 0.3, 'ford': 1.5, 'honda': 0.45, diff --git a/opendbc/car/torque_data/override.toml b/opendbc/car/torque_data/override.toml index 105f8fd3a10..ccb6c7dbe48 100644 --- a/opendbc/car/torque_data/override.toml +++ b/opendbc/car/torque_data/override.toml @@ -12,6 +12,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"] # BYD angle based controllers "BYD_ATTO_3" = [nan, 2.0, nan] +"BYD_SEALION_7" = [nan, 2.0, nan] # New subarus angle based controllers "SUBARU_FORESTER_2022" = [nan, 3.0, nan] diff --git a/opendbc/dbc/byd_sealion_7.dbc b/opendbc/dbc/byd_sealion_7.dbc index bf2a5b3cdc4..37c7048bead 100644 --- a/opendbc/dbc/byd_sealion_7.dbc +++ b/opendbc/dbc/byd_sealion_7.dbc @@ -60,11 +60,11 @@ BO_ 482 STEERING_MODULE_ADAS: 8 ADAS_ECU SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" EPS SG_ CHECKSUM : 56|8@1+ (1,0) [0|255] "" EPS -BO_ 496 WHEELSPEED_CLEAN: 8 ESP_ECU - SG_ WHEEL_FL : 0|12@1+ (0.075,0) [0|4095] "" MCU - SG_ WHEEL_FR : 16|12@1+ (0.075,0) [0|4095] "" MCU - SG_ WHEEL_RL : 28|12@1+ (0.075,0) [0|4095] "" MCU - SG_ WHEEL_RR : 40|12@1+ (0.075,0) [0|4095] "" MCU +BO_ 496 WHEEL_SPEEDS: 8 ESP_ECU + SG_ FL : 0|12@1+ (0.075,0) [0|4095] "" MCU + SG_ FR : 16|12@1+ (0.075,0) [0|4095] "" MCU + SG_ RL : 28|12@1+ (0.075,0) [0|4095] "" MCU + SG_ RR : 40|12@1+ (0.075,0) [0|4095] "" MCU SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" MCU SG_ CHECKSUM : 56|8@1+ (1,0) [0|255] "" MCU From 04359c94034bacfecb1edb324770a1a69a5fa152 Mon Sep 17 00:00:00 2001 From: Martin Lillepuu Date: Thu, 23 Apr 2026 12:16:04 +0300 Subject: [PATCH 9/9] update sealion dbc with atto3 --- opendbc/dbc/byd_sealion_7.dbc | 49 +++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 17 deletions(-) diff --git a/opendbc/dbc/byd_sealion_7.dbc b/opendbc/dbc/byd_sealion_7.dbc index 37c7048bead..0db9ab4c171 100644 --- a/opendbc/dbc/byd_sealion_7.dbc +++ b/opendbc/dbc/byd_sealion_7.dbc @@ -33,7 +33,7 @@ NS_ : BS_: -BU_: EPS ESP_ECU BCM VCU MPC_CAM ADAS_ECU MCU +BU_: EPS ESP_ECU BCM VCU MPC_CAM ADAS_ECU MCU BSD BO_ 287 STEER_MODULE_2: 5 EPS @@ -52,8 +52,8 @@ BO_ 482 STEERING_MODULE_ADAS: 8 ADAS_ECU SG_ ANGLE_RATE_LIMIT_LOWER : 10|10@1- (1,0) [-512|511] "" EPS SG_ STEER_REQ_ACTIVE_LOW : 20|1@0+ (1,0) [0|1] "" EPS SG_ STEER_REQ : 21|1@0+ (1,0) [0|1] "" EPS - SG_ SET_ME_1_2 : 22|1@0+ (1,0) [0|1] "" EPS - SG_ SET_ME_1_1 : 23|1@0+ (1,0) [0|1] "" EPS + SG_ E2E_ALIVE_2 : 22|1@0+ (1,0) [0|1] "" EPS + SG_ E2E_ALIVE_1 : 23|1@0+ (1,0) [0|1] "" EPS SG_ STEER_ANGLE : 24|16@1- (0.1,0) [-3276.8|3276.7] "deg" EPS SG_ SET_ME_FF : 47|8@0+ (1,0) [0|255] "" EPS SG_ SET_ME_F : 48|4@1+ (1,0) [0|15] "" EPS @@ -89,20 +89,22 @@ BO_ 660 METER_CLUSTER: 8 BCM SG_ SEATBELT_DRIVER : 17|1@0+ (1,0) [0|1] "" MCU BO_ 790 LKAS_HUD_ADAS: 8 MPC_CAM - SG_ HMA : 4|5@0+ (1,0) [0|31] "" MCU - SG_ STEER_ACTIVE_1_1 : 5|1@0+ (1,0) [0|1] "" MCU - SG_ LSS_STATE : 7|2@0+ (1,0) [0|3] "" MCU - SG_ HAND_ON_WHEEL_WARNING : 10|1@0+ (1,0) [0|1] "" MCU - SG_ SET_ME_XFF : 23|8@0+ (1,0) [0|255] "" MCU - SG_ SET_ME_X5F : 31|8@0+ (1,0) [0|255] "" MCU - SG_ SET_ME_1_2 : 32|1@0+ (1,0) [0|1] "" MCU - SG_ STEER_ACTIVE_1_3 : 35|1@0+ (1,0) [0|1] "" MCU - SG_ STEER_ACTIVE_ACTIVE_LOW : 36|1@0+ (1,0) [0|1] "" MCU - SG_ STEER_ACTIVE_1_2 : 37|1@0+ (1,0) [0|1] "" MCU - SG_ TSR : 47|8@0+ (1,0) [0|255] "" MCU - SG_ SETTINGS : 48|4@1+ (1,0) [0|15] "" MCU - SG_ COUNTER : 55|4@0+ (1,0) [0|15] "" MCU - SG_ CHECKSUM : 63|8@0+ (1,0) [0|255] "" MCU + SG_ HMA_STATE : 3|4@0+ (1,0) [0|15] "" MCU + SG_ LEFT_LANE_STATE : 4|2@1+ (1,0) [0|3] "" MCU + SG_ LKS_MODE : 6|2@1+ (1,0) [0|3] "" MCU + SG_ HANDS_ON_WHEEL_REQ : 10|1@1+ (1,0) [0|1] "" MCU + SG_ TJA_ICA_STATE : 11|4@1+ (1,0) [0|15] "" MCU + SG_ HMA_ON_OFF : 15|1@0+ (1,0) [0|1] "" MCU + SG_ LKAS_OUTPUT : 16|11@1- (1,0) [-1024|1023] "" MCU + SG_ LKAS_REQ_PREPARE : 27|1@1+ (1,0) [0|1] "" MCU + SG_ LKAS_ACTIVE : 28|1@1+ (1,0) [0|1] "" MCU + SG_ SLA_STATE : 29|3@1+ (1,0) [0|7] "" MCU + SG_ RIGHT_LANE_STATE : 34|2@1+ (1,0) [0|3] "" MCU + SG_ LKAS_STATE : 36|4@1+ (1,0) [0|15] "" MCU + SG_ SPEED_LIMIT_VALUE : 40|8@1+ (5,-5) [-5|1270] "kph" MCU + SG_ LDSW_TYPE : 49|2@0+ (1,0) [0|3] "" MCU + SG_ COUNTER : 52|4@1+ (1,0) [0|15] "" MCU + SG_ CHECKSUM : 56|8@1+ (1,0) [0|255] "" MCU BO_ 813 ACC_HUD_ADAS: 8 ADAS_ECU SG_ SET_SPEED : 0|8@1+ (0.5,0) [0|127.5] "kph" MCU @@ -166,6 +168,11 @@ BO_ 944 PCM_BUTTONS: 8 MCU BO_ 1028 IGNITION: 8 XXX SG_ IGNITION_ON : 6|1@0+ (1,0) [0|1] "" XXX +BO_ 1048 BSD_RADAR: 8 BSD + SG_ LEFT_APPROACH : 9|2@0+ (1,0) [0|3] "" MCU,ADAS_ECU + SG_ RIGHT_APPROACH : 11|2@0+ (1,0) [0|3] "" MCU,ADAS_ECU + SG_ APPROACH : 17|1@0+ (1,0) [0|1] "" MCU,ADAS_ECU + CM_ BO_ 287 "EPS steering wheel angle + driver torque. Validated: angle range plausible, DRIVER_EPS_TORQUE stays near 0 when hands-off."; CM_ BO_ 307 "Turn signal / stalk info. Validated: LEFT_BLINKER and RIGHT_BLINKER transition 0->1 during lane change events."; CM_ BO_ 482 "Lateral steering command sent by MPC camera/ADAS ECU to EPS. Blocked by panda on bus 2; panda injects its own on bus 0."; @@ -183,3 +190,11 @@ VAL_ 813 SET_DISTANCE 4 "4bar" 3 "3bar" 2 "2bar" 1 "1bar"; VAL_ 813 ACC_STATE 0 "OFF" 2 "ACC_ON" 3 "ACC_ACTIVE" 5 "FORCE_ACCEL" 7 "ERROR"; VAL_ 834 DRIVE_MODE 0 "RESERVED" 1 "ECO" 2 "SPORT" 3 "SNOW" 4 "NORMAL" 5 "RESERVED" 6 "RESERVED" 7 "RESERVED"; VAL_ 860 GEAR_STATE 1 "P" 2 "R" 3 "N" 4 "D" 0 "UNKNOWN" 5 "UNKNOWN" 6 "UNKNOWN" 7 "UNKNOWN"; +VAL_ 790 HMA_STATE 0 "OFF" 1 "PASSIVE" 2 "STANDBY" 3 "ACTIVE" 4 "FAULT" 5 "CAMERA_BLOCKED"; +VAL_ 790 LKS_MODE 0 "OFF" 1 "DIVERGE" 2 "KEEPING" 3 "ALL"; +VAL_ 790 TJA_ICA_STATE 0 "OFF" 1 "PASSIVE" 2 "ACTIVE1" 3 "ACTIVE2" 4 "FAULT"; +VAL_ 790 LDSW_TYPE 0 "VIBRATE" 1 "SOUND" 2 "ALL"; +VAL_ 790 SLA_STATE 0 "OFF" 1 "FUSION_MODE" 2 "VISION_MODE" 3 "NV_ONLY_MODE" 4 "DEFECT"; +VAL_ 790 LEFT_LANE_STATE 0 "OFF" 2 "WARNING"; +VAL_ 790 RIGHT_LANE_STATE 0 "OFF" 2 "WARNING"; +VAL_ 508 TORQUE_TEMP_FAILED 1 "TooLarge" 2 "TooFast" 3 "Both";