This commit is contained in:
1okko
2025-04-15 22:05:32 +08:00
parent ba7f7fd7a6
commit f18e42f9a8
73 changed files with 919 additions and 365 deletions
+2 -2
View File
@@ -57,9 +57,9 @@ ChecksumState* get_checksum(const std::string& dbc_name) {
s = new ChecksumState({8, -1, 7, -1, false, TOYOTA_CHECKSUM, &toyota_checksum});
} else if (startswith(dbc_name, "hyundai_canfd_generated")) {
s = new ChecksumState({16, -1, 0, -1, true, HKG_CAN_FD_CHECKSUM, &hkg_can_fd_checksum});
} else if (startswith(dbc_name, {"vw_mqb_2010", "vw_mqbevo", "vw_meb"})) {
} else if (startswith(dbc_name, {"vw_mqb", "vw_mqbevo", "vw_meb"})) {
s = new ChecksumState({8, 4, 0, 0, true, VOLKSWAGEN_MQB_MEB_CHECKSUM, &volkswagen_mqb_meb_checksum});
} else if (startswith(dbc_name, "vw_golf_mk4")) {
} else if (startswith(dbc_name, "vw_pq")) {
s = new ChecksumState({8, 4, 0, -1, true, XOR_CHECKSUM, &xor_checksum});
} else if (startswith(dbc_name, "subaru_global_")) {
s = new ChecksumState({8, -1, 0, -1, true, SUBARU_CHECKSUM, &subaru_checksum});
Binary file not shown.
@@ -93,7 +93,7 @@ class TestCanChecksums:
def verify_volkswagen_mqb_crc(self, subtests, msg_name: str, msg_addr: int, test_messages: list[bytes], counter_field: str = 'COUNTER'):
"""Test AUTOSAR E2E Profile 2 CRCs"""
assert len(test_messages) == 16 # All counter values must be tested
self.verify_checksum(subtests, "vw_mqb_2010", msg_name, msg_addr, test_messages, counter_field=counter_field)
self.verify_checksum(subtests, "vw_mqb", msg_name, msg_addr, test_messages, counter_field=counter_field)
def test_volkswagen_mqb_crc_lwi_01(self, subtests):
self.verify_volkswagen_mqb_crc(subtests, "LWI_01", 0x86, [
+8 -5
View File
@@ -98,13 +98,16 @@ class Bus(StrEnum):
ap_party = auto()
def apply_driver_steer_torque_limits(apply_torque, apply_torque_last, driver_torque, LIMITS):
def apply_driver_steer_torque_limits(apply_torque: int, apply_torque_last: int, driver_torque: float, LIMITS, steer_max: int = None):
# some safety modes utilize a dynamic max steer
if steer_max is None:
steer_max = LIMITS.STEER_MAX
# limits due to driver torque
driver_max_torque = LIMITS.STEER_MAX + (LIMITS.STEER_DRIVER_ALLOWANCE + driver_torque * LIMITS.STEER_DRIVER_FACTOR) * LIMITS.STEER_DRIVER_MULTIPLIER
driver_min_torque = -LIMITS.STEER_MAX + (-LIMITS.STEER_DRIVER_ALLOWANCE + driver_torque * LIMITS.STEER_DRIVER_FACTOR) * LIMITS.STEER_DRIVER_MULTIPLIER
max_steer_allowed = max(min(LIMITS.STEER_MAX, driver_max_torque), 0)
min_steer_allowed = min(max(-LIMITS.STEER_MAX, driver_min_torque), 0)
driver_max_torque = steer_max + (LIMITS.STEER_DRIVER_ALLOWANCE + driver_torque * LIMITS.STEER_DRIVER_FACTOR) * LIMITS.STEER_DRIVER_MULTIPLIER
driver_min_torque = -steer_max + (-LIMITS.STEER_DRIVER_ALLOWANCE + driver_torque * LIMITS.STEER_DRIVER_FACTOR) * LIMITS.STEER_DRIVER_MULTIPLIER
max_steer_allowed = max(min(steer_max, driver_max_torque), 0)
min_steer_allowed = min(max(-steer_max, driver_min_torque), 0)
apply_torque = np.clip(apply_torque, min_steer_allowed, max_steer_allowed)
# slow rate if steer torque increases in magnitude
+2 -1
View File
@@ -470,10 +470,11 @@ struct CarParams {
minEnableSpeed @7 :Float32;
minSteerSpeed @8 :Float32;
steerAtStandstill @77 :Bool; # is steering available at standstill? just check if it faults
safetyConfigs @62 :List(SafetyConfig);
alternativeExperience @65 :Int16; # panda flag for features like no disengage on gas
# Car docs fields
# Car docs fields, not used for control
maxLateralAccel @68 :Float32;
autoResumeSng @69 :Bool; # describes whether car can resume from a stop automatically
+13 -12
View File
@@ -75,7 +75,7 @@ class Mount(EnumBase):
class Cable(EnumBase):
long_obdc_cable = BasePart("long OBD-C cable")
long_obdc_cable = BasePart("long OBD-C cable (9.5 ft)")
usb_a_2_a_cable = BasePart("USB A-A cable")
usbc_otg_cable = BasePart("USB C OTG cable")
usbc_coupler = BasePart("USB-C coupler")
@@ -85,12 +85,12 @@ class Cable(EnumBase):
class Accessory(EnumBase):
harness_box = BasePart("harness box")
comma_power_v2 = BasePart("comma power v2")
comma_power = BasePart("comma power v3")
@dataclass
class BaseCarHarness(BasePart):
parts: list[Enum] = field(default_factory=lambda: [Accessory.harness_box, Accessory.comma_power_v2])
parts: list[Enum] = field(default_factory=lambda: [Accessory.harness_box, Accessory.comma_power])
has_connector: bool = True # without are hidden on the harness connector page
@@ -108,7 +108,8 @@ class CarHarness(EnumBase):
fca = BaseCarHarness("FCA connector")
ram = BaseCarHarness("Ram connector")
vw_a = BaseCarHarness("VW A connector")
vw_j533 = BaseCarHarness("VW J533 connector", parts=[Accessory.harness_box, Cable.long_obdc_cable, Cable.usbc_coupler, Accessory.comma_power_v2])
vw_c = BaseCarHarness("VW C connector")
vw_j533 = BaseCarHarness("VW J533 connector", parts=[Accessory.harness_box, Cable.long_obdc_cable, Cable.usbc_coupler])
hyundai_a = BaseCarHarness("Hyundai A connector")
hyundai_b = BaseCarHarness("Hyundai B connector")
hyundai_c = BaseCarHarness("Hyundai C connector")
@@ -128,17 +129,17 @@ class CarHarness(EnumBase):
hyundai_q = BaseCarHarness("Hyundai Q connector")
hyundai_r = BaseCarHarness("Hyundai R connector")
custom = BaseCarHarness("Developer connector")
obd_ii = BaseCarHarness("OBD-II connector", parts=[Cable.long_obdc_cable], has_connector=False)
obd_ii = BaseCarHarness("OBD-II connector", parts=[Cable.long_obdc_cable, Cable.usbc_coupler], has_connector=False)
gm = BaseCarHarness("GM connector", parts=[Accessory.harness_box])
gmsdgm = BaseCarHarness("GM SDGM connector", parts=[Accessory.harness_box, Cable.long_obdc_cable, Cable.usbc_coupler, Accessory.comma_power_v2])
nissan_a = BaseCarHarness("Nissan A connector", parts=[Accessory.harness_box, Cable.long_obdc_cable, Cable.usbc_coupler])
nissan_b = BaseCarHarness("Nissan B connector", parts=[Accessory.harness_box, Cable.long_obdc_cable, Cable.usbc_coupler])
gmsdgm = BaseCarHarness("GM SDGM connector", parts=[Accessory.harness_box, Accessory.comma_power, Cable.long_obdc_cable, Cable.usbc_coupler])
nissan_a = BaseCarHarness("Nissan A connector", parts=[Accessory.harness_box, Accessory.comma_power, Cable.long_obdc_cable, Cable.usbc_coupler])
nissan_b = BaseCarHarness("Nissan B connector", parts=[Accessory.harness_box, Accessory.comma_power, Cable.long_obdc_cable, Cable.usbc_coupler])
mazda = BaseCarHarness("Mazda connector")
ford_q3 = BaseCarHarness("Ford Q3 connector")
ford_q4 = BaseCarHarness("Ford Q4 connector", parts=[Accessory.harness_box, Accessory.comma_power_v2, Cable.long_obdc_cable, Cable.usbc_coupler])
rivian = BaseCarHarness("Rivian A connector", parts=[Accessory.harness_box, Cable.long_obdc_cable, Cable.usbc_coupler])
tesla_a = BaseCarHarness("Tesla A connector", parts=[Accessory.harness_box, Cable.long_obdc_cable, Cable.usbc_coupler])
tesla_b = BaseCarHarness("Tesla B connector", parts=[Accessory.harness_box, Cable.long_obdc_cable, Cable.usbc_coupler])
ford_q4 = BaseCarHarness("Ford Q4 connector", parts=[Accessory.harness_box, Accessory.comma_power, Cable.long_obdc_cable, Cable.usbc_coupler])
rivian = BaseCarHarness("Rivian A connector", parts=[Accessory.harness_box, Accessory.comma_power, Cable.long_obdc_cable, Cable.usbc_coupler])
tesla_a = BaseCarHarness("Tesla A connector", parts=[Accessory.harness_box, Accessory.comma_power, Cable.long_obdc_cable, Cable.usbc_coupler])
tesla_b = BaseCarHarness("Tesla B connector", parts=[Accessory.harness_box, Accessory.comma_power, Cable.long_obdc_cable, Cable.usbc_coupler])
class Device(EnumBase):
@@ -33,6 +33,7 @@ class CarInterface(CarInterfaceBase):
ret.steerControlType = structs.CarParams.SteerControlType.angle
ret.steerActuatorDelay = 0.2
ret.steerLimitTimer = 1.0
ret.steerAtStandstill = True
ret.longitudinalTuning.kiBP = [0.]
ret.longitudinalTuning.kiV = [0.5]
@@ -56,6 +56,11 @@ class StdQueries:
SUPPLIER_SOFTWARE_VERSION_RESPONSE = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER + 0x40]) + \
p16(uds.DATA_IDENTIFIER_TYPE.SYSTEM_SUPPLIER_ECU_SOFTWARE_VERSION_NUMBER)
MANUFACTURER_ECU_HARDWARE_NUMBER_REQUEST = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \
p16(uds.DATA_IDENTIFIER_TYPE.VEHICLE_MANUFACTURER_ECU_HARDWARE_NUMBER)
MANUFACTURER_ECU_HARDWARE_NUMBER_RESPONSE = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER + 0x40]) + \
p16(uds.DATA_IDENTIFIER_TYPE.VEHICLE_MANUFACTURER_ECU_HARDWARE_NUMBER)
UDS_VERSION_REQUEST = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \
p16(uds.DATA_IDENTIFIER_TYPE.APPLICATION_SOFTWARE_IDENTIFICATION)
UDS_VERSION_RESPONSE = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER + 0x40]) + \
+1 -1
View File
@@ -89,7 +89,7 @@ class CarController(CarControllerBase):
self.apply_gas = self.params.INACTIVE_REGEN
self.apply_brake = 0
else:
self.apply_gas = int(round(np.interp(actuators.accel, self.params.GAS_LOOKUP_BP, self.params.GAS_LOOKUP_V)))
self.apply_gas = float(np.interp(actuators.accel, self.params.GAS_LOOKUP_BP, self.params.GAS_LOOKUP_V))
self.apply_brake = int(round(np.interp(actuators.accel, self.params.BRAKE_LOOKUP_BP, self.params.BRAKE_LOOKUP_V)))
# Don't allow any gas above inactive regen while stopping
# FIXME: brakes aren't applied immediately when enabling at a stop
+3 -5
View File
@@ -56,16 +56,14 @@ def create_gas_regen_command(packer, bus, throttle, idx, enabled, at_full_stop):
values = {
"GasRegenCmdActive": enabled,
"RollingCounter": idx,
"GasRegenCmdActiveInv": 1 - enabled,
"GasRegenCmd": throttle,
"GasRegenFullStopActive": at_full_stop,
"GasRegenAlwaysOne": 1,
"GasRegenAlwaysOne2": 1,
"GasRegenAlwaysOne3": 1,
"GasRegenAccType": 1,
}
dat = packer.make_can_msg("ASCMGasRegenCmd", bus, values)[1]
values["GasRegenChecksum"] = (((0xff - dat[1]) & 0xff) << 16) | \
values["GasRegenChecksum"] = ((1 - enabled) << 24) | \
(((0xff - dat[1]) & 0xff) << 16) | \
(((0xff - dat[2]) & 0xff) << 8) | \
((0x100 - dat[3] - idx) & 0xff)
+3 -2
View File
@@ -7,7 +7,7 @@ from opendbc.car.common.basedir import BASEDIR
from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.gm.carcontroller import CarController
from opendbc.car.gm.carstate import CarState
from opendbc.car.gm.radar_interface import RadarInterface, RADAR_HEADER_MSG
from opendbc.car.gm.radar_interface import RadarInterface, RADAR_HEADER_MSG, CAMERA_DATA_HEADER_MSG
from opendbc.car.gm.values import CAR, CarControllerParams, EV_CAR, CAMERA_ACC_CAR, SDGM_CAR, ALT_ACCS, CanBus, GMSafetyFlags
from opendbc.car.interfaces import CarInterfaceBase, TorqueFromLateralAccelCallbackType, FRICTION_THRESHOLD, LatControlInputs, NanoFFModel
@@ -127,7 +127,8 @@ class CarInterface(CarInterfaceBase):
else: # ASCM, OBD-II harness
ret.openpilotLongitudinalControl = True
ret.networkLocation = NetworkLocation.gateway
ret.radarUnavailable = RADAR_HEADER_MSG not in fingerprint[CanBus.OBSTACLE] and not docs
# LRR messages can take up to a few seconds to start sending after ignition, check camera data as well which starts earlier
ret.radarUnavailable = RADAR_HEADER_MSG not in fingerprint[CanBus.OBSTACLE] and CAMERA_DATA_HEADER_MSG not in fingerprint[CanBus.OBSTACLE] and not docs
ret.pcmCruise = False # stock non-adaptive cruise control is kept off
# supports stop and go, but initial engage must (conservatively) be above 18mph
ret.minEnableSpeed = 18 * CV.MPH_TO_MS
@@ -6,7 +6,8 @@ from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.gm.values import DBC, CanBus
from opendbc.car.interfaces import RadarInterfaceBase
RADAR_HEADER_MSG = 1120
RADAR_HEADER_MSG = 1120 # F_LRR_Obj_Header
CAMERA_DATA_HEADER_MSG = 1056 # F_Vision_Obj_Header
SLOT_1_MSG = RADAR_HEADER_MSG + 1
NUM_SLOTS = 20
+8 -9
View File
@@ -34,27 +34,26 @@ class CarControllerParams:
def __init__(self, CP):
# Gas/brake lookups
self.ZERO_GAS = 2048 # Coasting
self.MAX_BRAKE = 400 # ~ -4.0 m/s^2 with regen
if CP.carFingerprint in (CAMERA_ACC_CAR | SDGM_CAR):
self.MAX_GAS = 3400
self.MAX_ACC_REGEN = 1514
self.INACTIVE_REGEN = 1554
self.MAX_GAS = 1346.0
self.MAX_ACC_REGEN = -540.0
self.INACTIVE_REGEN = -500.0
# Camera ACC vehicles have no regen while enabled.
# Camera transitions to MAX_ACC_REGEN from ZERO_GAS and uses friction brakes instantly
# Camera transitions to MAX_ACC_REGEN from zero gas and uses friction brakes instantly
max_regen_acceleration = 0.
else:
self.MAX_GAS = 3072 # Safety limit, not ACC max. Stock ACC >4096 from standstill.
self.MAX_ACC_REGEN = 1404 # Max ACC regen is slightly less than max paddle regen
self.INACTIVE_REGEN = 1404
self.MAX_GAS = 1018.0 # Safety limit, not ACC max. Stock ACC >2042 from standstill.
self.MAX_ACC_REGEN = -650.0 # Max ACC regen is slightly less than max paddle regen
self.INACTIVE_REGEN = -650.0
# ICE has much less engine braking force compared to regen in EVs,
# lower threshold removes some braking deadzone
max_regen_acceleration = -1. if CP.carFingerprint in EV_CAR else -0.1
self.GAS_LOOKUP_BP = [max_regen_acceleration, 0., self.ACCEL_MAX]
self.GAS_LOOKUP_V = [self.MAX_ACC_REGEN, self.ZERO_GAS, self.MAX_GAS]
self.GAS_LOOKUP_V = [self.MAX_ACC_REGEN, 0., self.MAX_GAS]
self.BRAKE_LOOKUP_BP = [self.ACCEL_MIN, max_regen_acceleration]
self.BRAKE_LOOKUP_V = [self.MAX_BRAKE, 0.]
+1 -1
View File
@@ -255,7 +255,7 @@ class CAR(Platforms):
HONDA_PILOT = HondaNidecPlatformConfig(
[
HondaCarDocs("Honda Pilot 2016-22", min_steer_speed=12. * CV.MPH_TO_MS),
HondaCarDocs("Honda Passport 2019-23", "All", min_steer_speed=12. * CV.MPH_TO_MS),
HondaCarDocs("Honda Passport 2019-25", "All", min_steer_speed=12. * CV.MPH_TO_MS),
],
CarSpecs(mass=4278 * CV.LB_TO_KG, wheelbase=2.86, centerToFrontRatio=0.428, steerRatio=16.0, tireStiffnessFactor=0.444), # as spec
radar_dbc_dict('acura_ilx_2016_can_generated'),
@@ -53,11 +53,13 @@ FW_VERSIONS = {
b'\xf1\x00AE MDPS C 1.00 1.05 56310/G2501 4AEHC105',
b'\xf1\x00AE MDPS C 1.00 1.07 56310/G2301 4AEHC107',
b'\xf1\x00AE MDPS C 1.00 1.07 56310/G2501 4AEHC107',
b'\xf1\x00AE MDPS C 1.00 1.07 56310/G2551 4AEHC107',
],
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00AEH MFC AT EUR LHD 1.00 1.00 95740-G2400 180222',
b'\xf1\x00AEH MFC AT EUR LHD 1.00 1.00 95740-G7200 160418',
b'\xf1\x00AEH MFC AT USA LHD 1.00 1.00 95740-G2400 180222',
b'\xf1\x00AEH MFC AT EUR RHD 1.00 1.00 95740-G2400 180222',
],
},
CAR.HYUNDAI_IONIQ_PHEV_2019: {
@@ -728,9 +730,11 @@ FW_VERSIONS = {
},
CAR.KIA_NIRO_EV_2ND_GEN: {
(Ecu.fwdRadar, 0x7d0, None): [
b'\xf1\x00SG__ RDR ----- 1.00 1.00 99110-AT200 ',
b'\xf1\x00SG2_ RDR ----- 1.00 1.01 99110-AT000 ',
],
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00SG2EMFC AT EUR LHD 1.00 1.00 99211-AT200 240315',
b'\xf1\x00SG2EMFC AT EUR LHD 1.01 1.09 99211-AT000 220801',
b'\xf1\x00SG2EMFC AT USA LHD 1.01 1.09 99211-AT000 220801',
],
@@ -1043,6 +1047,7 @@ FW_VERSIONS = {
(Ecu.fwdCamera, 0x7c4, None): [
b'\xf1\x00NX4 FR_CMR AT CAN LHD 1.00 1.00 99211-N9260 14Y',
b'\xf1\x00NX4 FR_CMR AT CAN LHD 1.00 1.01 99211-N9100 14A',
b'\xf1\x00NX4 FR_CMR AT CAN LHD 1.00 1.00 99211-N9220 14K',
b'\xf1\x00NX4 FR_CMR AT EUR LHD 1.00 1.00 99211-N9220 14K',
b'\xf1\x00NX4 FR_CMR AT EUR LHD 1.00 2.02 99211-N9000 14E',
b'\xf1\x00NX4 FR_CMR AT USA LHD 1.00 1.00 99211-N9210 14G',
+1 -1
View File
@@ -413,7 +413,7 @@ class CAR(Platforms):
flags=HyundaiFlags.MANDO_RADAR | HyundaiFlags.EV,
)
KIA_NIRO_EV_2ND_GEN = HyundaiCanFDPlatformConfig(
[HyundaiCarDocs("Kia Niro EV 2023", "All", car_parts=CarParts.common([CarHarness.hyundai_a]))],
[HyundaiCarDocs("Kia Niro EV 2023-24", "All", car_parts=CarParts.common([CarHarness.hyundai_a]))],
KIA_NIRO_EV.specs,
flags=HyundaiFlags.EV,
)
@@ -1,3 +1,4 @@
import numpy as np
from opendbc.can.packer import CANPacker
from opendbc.car import Bus, apply_driver_steer_torque_limits
from opendbc.car.interfaces import CarControllerBase
@@ -18,21 +19,24 @@ class CarController(CarControllerBase):
can_sends = []
apply_torque = 0
steer_max = round(float(np.interp(CS.out.vEgoRaw, CarControllerParams.STEER_MAX_LOOKUP[0],
CarControllerParams.STEER_MAX_LOOKUP[1])))
if CC.latActive:
new_torque = int(round(CC.actuators.torque * CarControllerParams.STEER_MAX))
new_torque = int(round(CC.actuators.torque * steer_max))
apply_torque = apply_driver_steer_torque_limits(new_torque, self.apply_torque_last,
CS.out.steeringTorque, CarControllerParams)
CS.out.steeringTorque, CarControllerParams, steer_max)
# send steering command
self.apply_torque_last = apply_torque
can_sends.append(create_lka_steering(self.packer, CS.acm_lka_hba_cmd, apply_torque, CC.latActive))
can_sends.append(create_lka_steering(self.packer, self.frame, CS.acm_lka_hba_cmd, apply_torque, CC.enabled, CC.latActive))
if self.frame % 5 == 0:
can_sends.append(create_wheel_touch(self.packer, CS.sccm_wheel_touch, CC.enabled))
# Longitudinal control
if self.CP.openpilotLongitudinalControl:
can_sends.append(create_longitudinal(self.packer, self.frame % 15, actuators.accel, CC.enabled))
accel = float(np.clip(actuators.accel, CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX))
can_sends.append(create_longitudinal(self.packer, self.frame, accel, CC.enabled))
else:
interface_status = None
if CC.cruiseControl.cancel:
@@ -46,7 +50,7 @@ class CarController(CarControllerBase):
can_sends.append(create_adas_status(self.packer, CS.vdm_adas_status, interface_status))
new_actuators = actuators.as_builder()
new_actuators.torque = apply_torque / CarControllerParams.STEER_MAX
new_actuators.torque = apply_torque / steer_max
new_actuators.torqueOutputCan = apply_torque
self.frame += 1
+3 -2
View File
@@ -3,6 +3,7 @@ from opendbc.car.interfaces import CarInterfaceBase
from opendbc.car.rivian.carcontroller import CarController
from opendbc.car.rivian.carstate import CarState
from opendbc.car.rivian.radar_interface import RadarInterface
from opendbc.car.rivian.values import RivianSafetyFlags
class CarInterface(CarInterfaceBase):
@@ -16,7 +17,7 @@ class CarInterface(CarInterfaceBase):
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.rivian)]
ret.steerActuatorDelay = 0.25
ret.steerActuatorDelay = 0.15
ret.steerLimitTimer = 0.4
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
@@ -27,7 +28,7 @@ class CarInterface(CarInterfaceBase):
ret.experimentalLongitudinalAvailable = False
if experimental_long:
ret.openpilotLongitudinalControl = True
#ret.safetyConfigs[0].safetyParam |= Panda.FLAG_RIVIAN_LONG_CONTROL
ret.safetyConfigs[0].safetyParam |= RivianSafetyFlags.LONG_CONTROL.value
ret.longitudinalActuatorDelay = 0.35
ret.vEgoStopping = 0.25
+23 -31
View File
@@ -11,40 +11,32 @@ def checksum(data, poly, xor_output):
return crc ^ xor_output
def create_lka_steering(packer, acm_lka_hba_cmd, apply_torque, enabled):
values = {s: acm_lka_hba_cmd[s] for s in [
"ACM_lkaHbaCmd_Counter",
"ACM_lkaHbaCmd_Checksum",
"ACM_HapticRequest",
"ACM_lkaStrToqReq",
"ACM_lkaSymbolState",
"ACM_lkaToiFlt",
"ACM_lkaActToi",
def create_lka_steering(packer, frame, acm_lka_hba_cmd, apply_torque, enabled, active):
# forward auto high beam and speed limit status and nothing else
values = {s: acm_lka_hba_cmd[s] for s in (
"ACM_hbaSysState",
"ACM_FailinfoAeb",
"ACM_lkaRHWarning",
"ACM_lkaLHWarning",
"ACM_lkaLaneRecogState",
"ACM_hbaOpt",
"ACM_hbaLamp",
"ACM_lkaHandsoffSoundWarning",
"ACM_lkaHandsoffDisplayWarning",
"ACM_unkown1",
"ACM_unkown2",
"ACM_unkown3",
"ACM_unkown4",
"ACM_unkown6",
]}
"ACM_hbaOnOffState",
"ACM_slifOnOffState",
)}
if enabled:
values["ACM_lkaActToi"] = 1
values["ACM_lkaSymbolState"] = 3
values["ACM_lkaLaneRecogState"] = 3
values["ACM_lkaStrToqReq"] = apply_torque
values["ACM_unkown2"] = 1
values["ACM_unkown3"] = 4
values["ACM_unkown4"] = 160
values["ACM_unkown6"] = 1
values |= {
"ACM_lkaHbaCmd_Counter": frame % 15,
"ACM_lkaStrToqReq": apply_torque,
"ACM_lkaActToi": active,
"ACM_lkaLaneRecogState": 3 if enabled else 0,
"ACM_lkaSymbolState": 3 if enabled else 0,
# static values
"ACM_lkaElkRequest": 0,
"ACM_ldwlkaOnOffState": 2, # 2=LKAS+LDW on
"ACM_elkOnOffState": 1, # 1=LKAS on
# TODO: what are these used for?
"ACM_ldwWarnTypeState": 2, # always 2
"ACM_ldwWarnTimingState": 1, # always 1
#"ACM_lkaHandsoffDisplayWarning": 1, # TODO: we can send this when openpilot wants you to pay attention
}
data = packer.make_can_msg("ACM_lkaHbaCmd", 0, values)[1]
values["ACM_lkaHbaCmd_Checksum"] = checksum(data[1:], 0x1D, 0x63)
+31 -7
View File
@@ -1,9 +1,9 @@
from dataclasses import dataclass, field
from enum import StrEnum, IntFlag
from opendbc.car import Bus, CarSpecs, DbcDict, PlatformConfig, Platforms, structs
from opendbc.car import Bus, CarSpecs, DbcDict, PlatformConfig, Platforms, structs, uds
from opendbc.car.docs_definitions import CarHarness, CarDocs, CarParts, Device
from opendbc.car.fw_query_definitions import FwQueryConfig, Request, StdQueries
from opendbc.car.fw_query_definitions import FwQueryConfig, Request, StdQueries, p16
from opendbc.car.vin import Vin
@@ -66,6 +66,10 @@ def match_fw_to_car_fuzzy(live_fw_versions, vin, offline_fw_versions) -> set[str
return {str(c) for c in candidates}
RIVIAN_VERSION_REQUEST = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER]) + \
p16(0xf1a0)
RIVIAN_VERSION_RESPONSE = bytes([uds.SERVICE_TYPE.READ_DATA_BY_IDENTIFIER + 0x40])
FW_QUERY_CONFIG = FwQueryConfig(
requests=[
Request(
@@ -73,7 +77,21 @@ FW_QUERY_CONFIG = FwQueryConfig(
[StdQueries.TESTER_PRESENT_RESPONSE, StdQueries.SUPPLIER_SOFTWARE_VERSION_RESPONSE],
rx_offset=0x40,
bus=0,
)
),
Request(
[StdQueries.TESTER_PRESENT_REQUEST, StdQueries.MANUFACTURER_ECU_HARDWARE_NUMBER_REQUEST],
[StdQueries.TESTER_PRESENT_RESPONSE, StdQueries.MANUFACTURER_ECU_HARDWARE_NUMBER_RESPONSE],
rx_offset=0x40,
bus=0,
logging=True,
),
Request(
[StdQueries.TESTER_PRESENT_REQUEST, RIVIAN_VERSION_REQUEST],
[StdQueries.TESTER_PRESENT_RESPONSE, RIVIAN_VERSION_RESPONSE],
rx_offset=0x40,
bus=0,
logging=True,
),
],
match_fw_to_car_fuzzy=match_fw_to_car_fuzzy,
)
@@ -88,10 +106,16 @@ GEAR_MAP = {
class CarControllerParams:
# The Rivian R1T we tested on achieves slightly more lateral acceleration going left vs. right
# and lateral acceleration rises as speed increases. This value is set conservatively to
# reach a maximum of 2.5-3.0 m/s^2 turning left at 80 mph, but is less at lower speeds
STEER_MAX = 250 # ~2.5 m/s^2
# The R1T 2023 and R1S 2023 we tested on achieves slightly more lateral acceleration going left vs. right
# and lateral acceleration falls linearly as speed decreases from 38 mph to 20 mph. These values are set
# conservatively to reach a maximum of 3.0 m/s^2 turning left at 80 mph
# These refer to turning left:
# 250 is ~2.8 m/s^2 above 17 m/s, then linearly ramps to ~1.6 m/s^2 from 17 m/s to 9 m/s
# TODO: it is theorized older models have different steering racks and achieve down to half the
# lateral acceleration referenced here at all speeds. detect this and ship a torque increase for those models
STEER_MAX = 250 # 350 is intended to maintain lateral accel, not increase it
STEER_MAX_LOOKUP = [9, 17], [350, 250]
STEER_STEP = 1
STEER_DELTA_UP = 3 # torque increase per refresh
STEER_DELTA_DOWN = 5 # torque decrease per refresh
@@ -54,6 +54,7 @@ FW_VERSIONS = {
(Ecu.abs, 0x7b0, None): [
b'\xa1 \x02\x01',
b'\xa1 \x02\x02',
b'\xa1 \x03\x02',
b'\xa1 \x03\x03',
b'\xa1 \x04\x01',
],
@@ -67,6 +68,7 @@ FW_VERSIONS = {
],
(Ecu.engine, 0x7e0, None): [
b'\xde"a0\x07',
b'\xe2"a0\x07',
b'\xde,\xa0@\x07',
b'\xe2"aq\x07',
b'\xe2,\xa0@\x07',
@@ -463,6 +465,7 @@ FW_VERSIONS = {
b'\xa1 \x06\x00',
b'\xa1 \x06\x01',
b'\xa1 \x06\x02',
b'\xa1 \x06\x03',
b'\xa1 \x07\x00',
b'\xa1 \x07\x02',
b'\xa1 \x07\x03',
@@ -496,6 +499,7 @@ FW_VERSIONS = {
b'\xe2"`p\x07',
b'\xe2"`q\x07',
b'\xe3,\xa0@\x07',
b'\xe2,\xa0p\x07',
],
(Ecu.transmission, 0x7e1, None): [
b'\xa5\xf6D@\x00',
@@ -505,6 +509,7 @@ FW_VERSIONS = {
b'\xa7\x8e\xf40\x00',
b'\xa7\xf6D@\x00',
b'\xa7\xfe\xf4@\x00',
b'\xa7\xfe\xf6@\x00',
],
},
CAR.SUBARU_FORESTER_2022: {
+6 -2
View File
@@ -71,8 +71,8 @@ class CarState(CarStateBase):
ret.doorOpen = cp_party.vl["UI_warning"]["anyDoorOpen"] == 1
# Blinkers
ret.leftBlinker = cp_party.vl["UI_warning"]["leftBlinkerOn"] != 0
ret.rightBlinker = cp_party.vl["UI_warning"]["rightBlinkerOn"] != 0
ret.leftBlinker = cp_party.vl["UI_warning"]["leftBlinkerBlinking"] in (1, 2)
ret.rightBlinker = cp_party.vl["UI_warning"]["rightBlinkerBlinking"] in (1, 2)
# Seatbelt
ret.seatbeltUnlatched = cp_party.vl["UI_warning"]["buckleStatus"] != 1
@@ -84,6 +84,9 @@ class CarState(CarStateBase):
# AEB
ret.stockAeb = cp_ap_party.vl["DAS_control"]["DAS_aebEvent"] == 1
# Stock Autosteer should be off (includes FSD)
ret.invalidLkasSetting = cp_ap_party.vl["DAS_settings"]["DAS_autosteerEnabled"] != 0
# Buttons # ToDo: add Gap adjust button
# Messages needed by carcontroller
@@ -106,6 +109,7 @@ class CarState(CarStateBase):
ap_party_messages = [
("DAS_control", 25),
("DAS_status", 2),
("DAS_settings", 2),
("SCCM_steeringAngleSensor", 100),
]
@@ -8,6 +8,7 @@ FW_VERSIONS = {
(Ecu.eps, 0x730, None): [
b'TeM3_E014p10_0.0.0 (16),E014.17.00',
b'TeM3_E014p10_0.0.0 (16),EL014.17.00',
b'TeM3_ES014p11_0.0.0 (25),ES014.19.0',
b'TeMYG4_DCS_Update_0.0.0 (13),E4014.28.1',
b'TeMYG4_DCS_Update_0.0.0 (9),E4014.26.0',
b'TeMYG4_Main_0.0.0 (59),E4H014.29.0',
@@ -25,6 +26,7 @@ FW_VERSIONS = {
b'TeMYG4_DCS_Update_0.0.0 (13),Y4P002.27.1',
b'TeMYG4_DCS_Update_0.0.0 (9),Y4P002.25.0',
b'TeMYG4_Legacy3Y_0.0.0 (2),Y4003.02.0',
b'TeMYG4_Legacy3Y_0.0.0 (5),Y4003.03.2',
b'TeMYG4_Legacy3Y_0.0.0 (2),Y4P003.02.0',
b'TeMYG4_SingleECU_0.0.0 (33),Y4S002.26',
],
+1 -1
View File
@@ -12,12 +12,12 @@ class CarInterface(CarInterfaceBase):
@staticmethod
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, experimental_long, docs) -> structs.CarParams:
ret.brand = "tesla"
ret.dashcamOnly = True
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.tesla)]
ret.steerLimitTimer = 1.0
ret.steerActuatorDelay = 0.1
ret.steerAtStandstill = True
ret.steerControlType = structs.CarParams.SteerControlType.angle
ret.radarUnavailable = True
+2
View File
@@ -214,6 +214,7 @@ routes = [
CarTestRoute("2475fb3eb2ffcc2e|2022-04-29--12-46-23", TOYOTA.TOYOTA_RAV4_TSS2_2022), # hybrid
CarTestRoute("20ba9ade056a8c7b|2021-02-08--21-57-35", TOYOTA.TOYOTA_RAV4_PRIME), # SecOC
CarTestRoute("8bfb000e03b2a257/00000004--f9eee5f52e", TOYOTA.TOYOTA_SIENNA_4TH_GEN), # SecOC
CarTestRoute("0b54d0594d924cd9/00000057--b6206a3205", TOYOTA.TOYOTA_YARIS), # SecOC
CarTestRoute("7a31f030957b9c85|2023-04-01--14-12-51", TOYOTA.LEXUS_ES),
CarTestRoute("37041c500fd30100|2020-12-30--12-17-24", TOYOTA.LEXUS_ES), # hybrid
CarTestRoute("e6a24be49a6cd46e|2019-10-29--10-52-42", TOYOTA.LEXUS_ES_TSS2),
@@ -251,6 +252,7 @@ routes = [
CarTestRoute("ffcd23abbbd02219|2024-02-28--14-59-38", VOLKSWAGEN.VOLKSWAGEN_CADDY_MK3),
CarTestRoute("cae14e88932eb364|2021-03-26--14-43-28", VOLKSWAGEN.VOLKSWAGEN_GOLF_MK7), # Stock ACC
CarTestRoute("3cfdec54aa035f3f|2022-10-13--14-58-58", VOLKSWAGEN.VOLKSWAGEN_GOLF_MK7), # openpilot longitudinal
CarTestRoute("17fbdc1cd49dc9af/00000027--ee57555e5b", VOLKSWAGEN.VOLKSWAGEN_ID4_MK1), # FIXME: temporary, replace later
CarTestRoute("578742b26807f756|00000010--41ee3e5bec", VOLKSWAGEN.VOLKSWAGEN_JETTA_MK6),
CarTestRoute("58a7d3b707987d65|2021-03-25--17-26-37", VOLKSWAGEN.VOLKSWAGEN_JETTA_MK7),
CarTestRoute("4d134e099430fba2|2021-03-26--00-26-06", VOLKSWAGEN.VOLKSWAGEN_PASSAT_MK8),
@@ -260,7 +260,7 @@ class TestFwFingerprintTiming:
print(f'get_vin {name} case, query time={self.total_time / self.N} seconds')
def test_fw_query_timing(self, subtests, mocker):
total_ref_time = {1: 7.1, 2: 7.7}
total_ref_time = {1: 7.3, 2: 7.9}
brand_ref_times = {
1: {
'gm': 1.0,
@@ -275,7 +275,7 @@ class TestFwFingerprintTiming:
'tesla': 0.1,
'toyota': 0.7,
'volkswagen': 0.65,
'rivian': 0.1,
'rivian': 0.3,
},
2: {
'ford': 1.6,
@@ -48,6 +48,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"CHEVROLET_EQUINOX" = [2.5, 2.5, 0.05]
"CHEVROLET_VOLT_2019" = [1.4, 1.4, 0.16]
"VOLKSWAGEN_CADDY_MK3" = [1.2, 1.2, 0.1]
"VOLKSWAGEN_ID4_MK1" = [nan, 2.5, nan]
"VOLKSWAGEN_PASSAT_NMS" = [2.5, 2.5, 0.1]
"VOLKSWAGEN_SHARAN_MK2" = [2.5, 2.5, 0.1]
"HYUNDAI_SANTA_CRUZ_1ST_GEN" = [2.7, 2.7, 0.1]
@@ -73,6 +74,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"HYUNDAI_STARIA_4TH_GEN" = [1.8, 2.0, 0.15]
"GENESIS_GV70_ELECTRIFIED_1ST_GEN" = [1.9, 1.9, 0.09]
"GENESIS_G80_2ND_GEN_FL" = [2.5819356441497803, 2.5, 0.11244568973779678]
# Note that some Rivians achieve significantly less lateral acceleration than this
"RIVIAN_R1_GEN1" = [2.8, 2.5, 0.07]
"HYUNDAI_NEXO_1ST_GEN" = [2.5, 2.5, 0.1]
@@ -73,6 +73,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"TOYOTA_RAV4H" = [1.9796257271652042, 1.7503987331707576, 0.14628860048885406]
"TOYOTA_RAV4_TSS2_2022" = [2.241883248393209, 1.9304407208090029, 0.112174]
"TOYOTA_SIENNA" = [1.689726, 1.3208264576110418, 0.140456]
"TOYOTA_YARIS" = [2.22984, 1.86145, 0.168189]
"VOLKSWAGEN_ARTEON_MK1" = [1.45136518053819, 1.3639364049316804, 0.23806361745695032]
"VOLKSWAGEN_ATLAS_MK1" = [1.4677006726964945, 1.6733266634075656, 0.12959584092073367]
"VOLKSWAGEN_GOLF_MK7" = [1.3750394140491293, 1.5814743077200641, 0.2018321939386586]
@@ -59,6 +59,7 @@ legend = ["LAT_ACCEL_FACTOR", "MAX_LAT_ACCEL_MEASURED", "FRICTION"]
"CHEVROLET_MALIBU" = "CHEVROLET_VOLT"
"HOLDEN_ASTRA" = "CHEVROLET_VOLT"
"SKODA_ENYAQ_MK1" = "VOLKSWAGEN_ID4_MK1"
"SKODA_FABIA_MK4" = "VOLKSWAGEN_GOLF_MK7"
"SKODA_OCTAVIA_MK3" = "SKODA_SUPERB_MK3"
"SKODA_KODIAQ_MK1" = "SKODA_SUPERB_MK3"
@@ -1783,4 +1783,21 @@ FW_VERSIONS = {
b'\x028646FV201000\x00\x00\x00\x008646G2601400\x00\x00\x00\x00',
],
},
CAR.TOYOTA_YARIS: {
(Ecu.engine, 0x700, None): [
b'\x0189663K015300\x00\x00\x00\x00',
],
(Ecu.eps, 0x7a1, None): [
b'\x018965BK003200\x00\x00\x00\x00',
],
(Ecu.abs, 0x7b0, None): [
b'\x01F1526K007500\x00\x00\x00\x00',
],
(Ecu.fwdRadar, 0x750, 0xf): [
b'\x018821F0D05300\x00\x00\x00\x00',
],
(Ecu.fwdCamera, 0x750, 0x6d): [
b'\x028646F5205200\x00\x00\x00\x008646G5202200\x00\x00\x00\x00',
],
},
}
@@ -31,7 +31,6 @@ class CarInterface(CarInterfaceBase):
ret.safetyConfigs[0].safetyParam |= ToyotaSafetyFlags.ALT_BRAKE.value
if ret.flags & ToyotaFlags.SECOC.value:
ret.dashcamOnly = True
ret.secOcRequired = True
ret.safetyConfigs[0].safetyParam |= ToyotaSafetyFlags.SECOC.value
+6 -1
View File
@@ -271,7 +271,7 @@ class CAR(Platforms):
)
TOYOTA_RAV4_TSS2_2023 = ToyotaTSS2PlatformConfig(
[
ToyotaCarDocs("Toyota RAV4 2023-24"),
ToyotaCarDocs("Toyota RAV4 2023-25"),
ToyotaCarDocs("Toyota RAV4 Hybrid 2023-25", video_link="https://youtu.be/4eIsEq4L4Ng"),
],
TOYOTA_RAV4_TSS2.specs,
@@ -281,6 +281,11 @@ class CAR(Platforms):
[ToyotaCarDocs("Toyota RAV4 Prime 2021-23", min_enable_speed=MIN_ACC_SPEED)],
CarSpecs(mass=4372. * CV.LB_TO_KG, wheelbase=2.68, steerRatio=16.88, tireStiffnessFactor=0.5533),
)
TOYOTA_YARIS = ToyotaSecOCPlatformConfig(
[ToyotaCarDocs("Toyota Yaris 2023 (Non-US only)", min_enable_speed=MIN_ACC_SPEED)],
CarSpecs(mass=1170, wheelbase=2.55, steerRatio=14.80, tireStiffnessFactor=0.5533),
flags=ToyotaFlags.RADAR_ACC,
)
TOYOTA_MIRAI = ToyotaTSS2PlatformConfig( # TSS 2.5
[ToyotaCarDocs("Toyota Mirai 2021")],
CarSpecs(mass=4300. * CV.LB_TO_KG, wheelbase=2.91, steerRatio=14.8, tireStiffnessFactor=0.8),
@@ -3,7 +3,7 @@ from opendbc.can.packer import CANPacker
from opendbc.car import Bus, DT_CTRL, apply_driver_steer_torque_limits, structs
from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.interfaces import CarControllerBase
from opendbc.car.volkswagen import mqbcan, pqcan
from opendbc.car.volkswagen import mqbcan, pqcan, mebcan
from opendbc.car.volkswagen.values import CANBUS, CarControllerParams, VolkswagenFlags
VisualAlert = structs.CarControl.HUDControl.VisualAlert
@@ -14,12 +14,20 @@ class CarController(CarControllerBase):
def __init__(self, dbc_names, CP):
super().__init__(dbc_names, CP)
self.CCP = CarControllerParams(CP)
self.CCS = pqcan if CP.flags & VolkswagenFlags.PQ else mqbcan
if CP.flags & VolkswagenFlags.PQ:
self.CCS = pqcan
elif CP.flags & VolkswagenFlags.MEB:
self.CCS = mebcan
else:
self.CCS = mqbcan
self.packer_pt = CANPacker(dbc_names[Bus.pt])
self.ext_bus = CANBUS.pt if CP.networkLocation == structs.CarParams.NetworkLocation.fwdCamera else CANBUS.cam
self.aeb_available = not CP.flags & VolkswagenFlags.PQ
self.openpilot_longitudinal = self.CP.openpilotLongitudinalControl and not self.CP.flags & VolkswagenFlags.MEB
self.apply_torque_last = 0
self.apply_curvature_last = 0
self.apply_steer_power_last = 0
self.gra_acc_counter_last = None
self.eps_timer_soft_disable_alert = False
self.hca_frame_timer_running = 0
@@ -33,50 +41,83 @@ class CarController(CarControllerBase):
# **** Steering Controls ************************************************ #
if self.frame % self.CCP.STEER_STEP == 0:
# Logic to avoid HCA state 4 "refused":
# * Don't steer unless HCA is in state 3 "ready" or 5 "active"
# * Don't steer at standstill
# * Don't send > 3.00 Newton-meters torque
# * Don't send the same torque for > 6 seconds
# * Don't send uninterrupted steering for > 360 seconds
# MQB racks reset the uninterrupted steering timer after a single frame
# of HCA disabled; this is done whenever output happens to be zero.
if self.CP.flags & VolkswagenFlags.MEB:
# The QFK (lateral control coordinator) control loop compares actuation curvature to its own current curvature
# Calibrate our actuator command by the offset between openpilot's vehicle model and QFK perceived curvatures
apply_curvature = actuators.curvature + (CS.qfk_curvature - CC.currentCurvature)
if CC.latActive:
new_torque = int(round(actuators.torque * self.CCP.STEER_MAX))
apply_torque = apply_driver_steer_torque_limits(new_torque, self.apply_torque_last, CS.out.steeringTorque, self.CCP)
self.hca_frame_timer_running += self.CCP.STEER_STEP
if self.apply_torque_last == apply_torque:
self.hca_frame_same_torque += self.CCP.STEER_STEP
if self.hca_frame_same_torque > self.CCP.STEER_TIME_STUCK_TORQUE / DT_CTRL:
apply_torque -= (1, -1)[apply_torque < 0]
self.hca_frame_same_torque = 0
# Progressive QFK power control: smooth engage and disengage, reduce power when the driver is overriding
qfk_enable = True
if CC.latActive:
min_power = max(self.apply_steer_power_last - self.CCP.STEERING_POWER_STEP, self.CCP.STEERING_POWER_MIN)
max_power = max(self.apply_steer_power_last + self.CCP.STEERING_POWER_STEP, self.CCP.STEERING_POWER_MAX)
target_power = int(np.interp(CS.out.steeringTorque, [self.CCP.STEER_DRIVER_ALLOWANCE, self.CCP.STEER_DRIVER_MAX],
[self.CCP.STEERING_POWER_MAX, self.CCP.STEERING_POWER_MIN]))
apply_steer_power = min(max(target_power, min_power), max_power)
elif self.apply_steer_power_last > 0:
apply_steer_power = max(self.apply_steer_power_last - self.CCP.STEERING_POWER_STEP, 0)
else:
self.hca_frame_same_torque = 0
hca_enabled = abs(apply_torque) > 0
qfk_enable = False
apply_curvature = 0
apply_steer_power = 0
can_sends.append(mebcan.create_steering_control(self.packer_pt, CANBUS.pt, apply_curvature, qfk_enable, apply_steer_power))
self.apply_curvature_last = apply_curvature
self.apply_steer_power_last = apply_steer_power
else:
hca_enabled = False
apply_torque = 0
# Logic to avoid HCA state 4 "refused":
# * Don't steer unless HCA is in state 3 "ready" or 5 "active"
# * Don't steer at standstill
# * Don't send > 3.00 Newton-meters torque
# * Don't send the same torque for > 6 seconds
# * Don't send uninterrupted steering for > 360 seconds
# MQB racks reset the uninterrupted steering timer after a single frame
# of HCA disabled; this is done whenever output happens to be zero.
if not hca_enabled:
self.hca_frame_timer_running = 0
if CC.latActive:
new_torque = int(round(actuators.torque * self.CCP.STEER_MAX))
apply_torque = apply_driver_steer_torque_limits(new_torque, self.apply_torque_last, CS.out.steeringTorque, self.CCP)
self.hca_frame_timer_running += self.CCP.STEER_STEP
if self.apply_torque_last == apply_torque:
self.hca_frame_same_torque += self.CCP.STEER_STEP
if self.hca_frame_same_torque > self.CCP.STEER_TIME_STUCK_TORQUE / DT_CTRL:
apply_torque -= (1, -1)[apply_torque < 0]
self.hca_frame_same_torque = 0
else:
self.hca_frame_same_torque = 0
hca_enabled = abs(apply_torque) > 0
else:
hca_enabled = False
apply_torque = 0
self.eps_timer_soft_disable_alert = self.hca_frame_timer_running > self.CCP.STEER_TIME_ALERT / DT_CTRL
self.apply_torque_last = apply_torque
can_sends.append(self.CCS.create_steering_control(self.packer_pt, CANBUS.pt, apply_torque, hca_enabled))
if not hca_enabled:
self.hca_frame_timer_running = 0
if self.CP.flags & VolkswagenFlags.STOCK_HCA_PRESENT:
# Pacify VW Emergency Assist driver inactivity detection by changing its view of driver steering input torque
# to the greatest of actual driver input or 2x openpilot's output (1x openpilot output is not enough to
# consistently reset inactivity detection on straight level roads). See commaai/openpilot#23274 for background.
ea_simulated_torque = float(np.clip(apply_torque * 2, -self.CCP.STEER_MAX, self.CCP.STEER_MAX))
if abs(CS.out.steeringTorque) > abs(ea_simulated_torque):
ea_simulated_torque = CS.out.steeringTorque
can_sends.append(self.CCS.create_eps_update(self.packer_pt, CANBUS.cam, CS.eps_stock_values, ea_simulated_torque))
self.eps_timer_soft_disable_alert = self.hca_frame_timer_running > self.CCP.STEER_TIME_ALERT / DT_CTRL
self.apply_torque_last = apply_torque
can_sends.append(self.CCS.create_steering_control(self.packer_pt, CANBUS.pt, apply_torque, hca_enabled))
if self.CP.flags & VolkswagenFlags.STOCK_HCA_PRESENT:
# Pacify VW Emergency Assist driver inactivity detection by changing its view of driver steering input torque
# to the greatest of actual driver input or 2x openpilot's output (1x openpilot output is not enough to
# consistently reset inactivity detection on straight level roads). See commaai/openpilot#23274 for background.
ea_simulated_torque = float(np.clip(apply_torque * 2, -self.CCP.STEER_MAX, self.CCP.STEER_MAX))
if abs(CS.out.steeringTorque) > abs(ea_simulated_torque):
ea_simulated_torque = CS.out.steeringTorque
can_sends.append(self.CCS.create_eps_update(self.packer_pt, CANBUS.cam, CS.eps_stock_values, ea_simulated_torque))
# TODO: refactor a bit
if self.CP.flags & VolkswagenFlags.MEB:
if self.frame % 2 == 0:
can_sends.append(mebcan.create_ea_control(self.packer_pt, CANBUS.pt))
if self.frame % 50 == 0:
can_sends.append(mebcan.create_ea_hud(self.packer_pt, CANBUS.pt))
# **** Acceleration Controls ******************************************** #
if self.CP.openpilotLongitudinalControl:
if self.openpilot_longitudinal:
if self.frame % self.CCP.ACC_CONTROL_STEP == 0:
acc_control = self.CCS.acc_control_value(CS.out.cruiseState.available, CS.out.accFaulted, CC.longActive)
accel = float(np.clip(actuators.accel, self.CCP.ACCEL_MIN, self.CCP.ACCEL_MAX) if CC.longActive else 0)
@@ -100,7 +141,7 @@ class CarController(CarControllerBase):
can_sends.append(self.CCS.create_lka_hud_control(self.packer_pt, CANBUS.pt, CS.ldw_stock_values, CC.latActive,
CS.out.steeringPressed, hud_alert, hud_control))
if self.frame % self.CCP.ACC_HUD_STEP == 0 and self.CP.openpilotLongitudinalControl:
if self.frame % self.CCP.ACC_HUD_STEP == 0 and self.openpilot_longitudinal:
lead_distance = 0
if hud_control.leadVisible and self.frame * DT_CTRL > 1.0: # Don't display lead until we know the scaling factor
lead_distance = 512 if CS.upscale_lead_car_signal else 8
@@ -120,6 +161,7 @@ class CarController(CarControllerBase):
new_actuators = actuators.as_builder()
new_actuators.torque = self.apply_torque_last / self.CCP.STEER_MAX
new_actuators.torqueOutputCan = self.apply_torque_last
new_actuators.curvature = float(self.apply_curvature_last)
self.gra_acc_counter_last = CS.gra_stock_values["COUNTER"]
self.frame += 1
+109 -1
View File
@@ -19,6 +19,7 @@ class CarState(CarStateBase):
self.esp_hold_confirmation = False
self.upscale_lead_car_signal = False
self.eps_stock_values = False
self.qfk_curvature = 0.
def update_button_enable(self, buttonEvents: list[structs.CarState.ButtonEvent]):
if not self.CP.pcmCruise:
@@ -63,7 +64,55 @@ class CarState(CarStateBase):
else:
ret.gearShifter = self.parse_gear_shifter(self.CCP.shifter_values.get(pt_cp.vl["Gateway_73"]["GE_Fahrstufe"], None))
if True:
if self.CP.flags & VolkswagenFlags.MEB:
# MEB-specific
self.qfk_curvature = -pt_cp.vl["QFK_01"]["Curvature"] * (1, -1)[int(pt_cp.vl["QFK_01"]["Curvature_VZ"])]
ret.fuelGauge = pt_cp.vl["Motor_16"]["MO_Energieinhalt_BMS"] # TODO: is this available on MQB as well?
ret.wheelSpeeds = self.get_wheel_speeds(
pt_cp.vl["ESC_51"]["VL_Radgeschw"],
pt_cp.vl["ESC_51"]["VR_Radgeschw"],
pt_cp.vl["ESC_51"]["HL_Radgeschw"],
pt_cp.vl["ESC_51"]["HR_Radgeschw"],
)
ret.yawRate = pt_cp.vl["ESC_50"]["Yaw_Rate"] * (1, -1)[int(pt_cp.vl["ESC_50"]["Yaw_Rate_Sign"])] * CV.DEG_TO_RAD
hca_status = self.CCP.hca_status_values.get(pt_cp.vl["QFK_01"]["LatCon_HCA_Status"])
drive_mode = ret.gearShifter == GearShifter.drive
ret.gas = pt_cp.vl["Motor_54"]["Accelerator_Pressure"]
ret.brake = pt_cp.vl["ESC_51"]["Brake_Pressure"]
ret.brakePressed = bool(pt_cp.vl["Motor_14"]["MO_Fahrer_bremst"]) # includes regen braking by user
ret.parkingBrake = pt_cp.vl["Gateway_73"]["EPB_Status"] in (1, 4) # EPB closing or closed
ret.doorOpen = any([pt_cp.vl["ZV_02"]["ZV_FT_offen"],
pt_cp.vl["ZV_02"]["ZV_BT_offen"],
pt_cp.vl["ZV_02"]["ZV_HFS_offen"],
pt_cp.vl["ZV_02"]["ZV_HBFS_offen"],
pt_cp.vl["ZV_02"]["ZV_HD_offen"]])
if self.CP.enableBsm:
ret.leftBlindspot = bool(ext_cp.vl["MEB_Side_Assist_01"]["Blind_Spot_Info_Left"]) or bool(ext_cp.vl["MEB_Side_Assist_01"]["Blind_Spot_Warn_Left"])
ret.rightBlindspot = bool(ext_cp.vl["MEB_Side_Assist_01"]["Blind_Spot_Info_Right"]) or bool(ext_cp.vl["MEB_Side_Assist_01"]["Blind_Spot_Warn_Right"])
ret.stockFcw = bool(pt_cp.vl["VMM_02"]["FCW_Active"]) or bool(ext_cp.vl["AWV_03"]["FCW_Active"])
ret.stockAeb = bool(pt_cp.vl["VMM_02"]["AEB_Active"])
self.travel_assist_available = bool(cam_cp.vl["TA_01"]["Travel_Assist_Available"])
self.acc_type = ext_cp.vl["ACC_18"]["ACC_Typ"]
self.esp_hold_confirmation = bool(pt_cp.vl["VMM_02"]["ESP_Hold"])
acc_limiter_mode = bool(ext_cp.vl["MEB_ACC_01"]["ACC_Limiter_Mode"])
speed_limiter_mode = bool(pt_cp.vl["Motor_51"]["TSK_Limiter_ausgewaehlt"])
ret.cruiseState.available = pt_cp.vl["Motor_51"]["TSK_Status"] in (2, 3, 4, 5)
ret.cruiseState.enabled = pt_cp.vl["Motor_51"]["TSK_Status"] in (3, 4, 5)
ret.cruiseState.speed = int(round(ext_cp.vl["MEB_ACC_01"]["ACC_Wunschgeschw_02"])) * CV.KPH_TO_MS if self.CP.pcmCruise else 0
ret.accFaulted = drive_mode and pt_cp.vl["Motor_51"]["TSK_Status"] in (6, 7)
ret.leftBlinker = bool(pt_cp.vl["Blinkmodi_02"]["BM_links"])
ret.rightBlinker = bool(pt_cp.vl["Blinkmodi_02"]["BM_rechts"])
else:
# MQB-specific
self.upscale_lead_car_signal = bool(pt_cp.vl["Kombi_03"]["KBI_Variante"]) # Analog vs digital instrument cluster
@@ -256,6 +305,8 @@ class CarState(CarStateBase):
def get_can_parsers(CP):
if CP.flags & VolkswagenFlags.PQ:
return CarState.get_can_parsers_pq(CP)
elif CP.flags & VolkswagenFlags.MEB:
return CarState.get_can_parsers_meb(CP)
pt_messages = [
# sig_address, frequency
@@ -356,6 +407,51 @@ class CarState(CarStateBase):
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], cam_messages, CANBUS.cam),
}
@staticmethod
def get_can_parsers_meb(CP):
pt_messages = [
# sig_address, frequency
("LWI_01", 100), # From J500 Steering Assist with integrated sensors
("GRA_ACC_01", 33), # From J533 CAN gateway (via LIN from steering wheel controls)
("Airbag_02", 5), # From J234 Airbag control module
("Motor_14", 10), # From J623 Engine control module
("Motor_16", 2), # From J623 Engine control module
("Blinkmodi_02", 1), # From J519 BCM (sent at 1Hz when no lights active, 50Hz when active)
("LH_EPS_03", 100), # From J500 Steering Assist with integrated sensors
("ZV_02", 5), # From ZV
("QFK_01", 100), # From Steering
("ESP_21", 50), #
("ESC_51", 100), #
("Motor_54", 10), #
("ESC_50", 50), #
("VMM_02", 50), #
("Gateway_73", 20), #
("Motor_51", 50), #
]
if CP.networkLocation == NetworkLocation.fwdCamera:
# Radars are here on CANBUS.pt
pt_messages += MebExtraSignals.fwd_radar_messages
if CP.enableBsm:
pt_messages += MebExtraSignals.bsm_radar_messages
cam_messages = [
# sig_address, frequency
("LDW_02", 10), # From R242 Driver assistance camera
("TA_01", 10), # From R242 Driver assistance camera (Travel Assist)
]
if CP.networkLocation == NetworkLocation.gateway:
# Radars are here on CANBUS.cam
cam_messages += MebExtraSignals.fwd_radar_messages
if CP.enableBsm:
cam_messages += MebExtraSignals.bsm_radar_messages
return {
Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], pt_messages, CANBUS.pt),
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], cam_messages, CANBUS.cam),
}
class MqbExtraSignals:
# Additional signal and message lists for optional or bus-portable controllers
@@ -378,3 +474,15 @@ class PqExtraSignals:
bsm_radar_messages = [
("SWA_1", 20), # From J1086 Lane Change Assist
]
class MebExtraSignals:
# Additional signal and message lists for optional or bus-portable controllers
fwd_radar_messages = [
("MEB_ACC_01", 17), #
("ACC_18", 50), #
("AWV_03", 1), # Front Collision Detection (1 Hz when inactive, 50 Hz when active)
]
bsm_radar_messages = [
("MEB_Side_Assist_01", 20),
]
@@ -977,6 +977,19 @@ FW_VERSIONS = {
b'\xf1\x875Q0907572R \xf1\x890771',
],
},
CAR.VOLKSWAGEN_ID4_MK1: {
(Ecu.srs, 0x715, None): [
b'\xf1\x875WA959655R \xf1\x890717',
],
(Ecu.fwdRadar, 0x757, None): [
b'\xf1\x871EA907572H \xf1\x890234',
],
},
CAR.SKODA_ENYAQ_MK1: {
(Ecu.fwdRadar, 0x757, None): [
b'\xf1\x871EA907567B \xf1\x890232',
],
},
CAR.SKODA_FABIA_MK4: {
(Ecu.engine, 0x7e0, None): [
b'\xf1\x8705E906018CF\xf1\x891905',
@@ -37,6 +37,18 @@ class CarInterface(CarInterfaceBase):
# Panda ALLOW_DEBUG firmware required.
ret.dashcamOnly = True
elif ret.flags & VolkswagenFlags.MEB:
# Set global MEB parameters
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.noOutput),get_safety_config(structs.CarParams.SafetyModel.volkswagenMeb)]
ret.enableBsm = 0x24C in fingerprint[0] # MEB_Side_Assist_01
ret.steerControlType = structs.CarParams.SteerControlType.angle
ret.transmissionType = TransmissionType.automatic
if any(msg in fingerprint[1] for msg in (0x520, 0x86, 0xFD, 0x13D)): # Airbag_02, LWI_01, ESP_21, QFK_01
ret.networkLocation = NetworkLocation.gateway
else:
ret.networkLocation = NetworkLocation.fwdCamera
else:
# Set global MQB parameters
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.volkswagen)]
@@ -63,6 +75,8 @@ class CarInterface(CarInterfaceBase):
if ret.flags & VolkswagenFlags.PQ:
ret.steerActuatorDelay = 0.2
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif ret.flags & VolkswagenFlags.MEB:
ret.steerActuatorDelay = 0.2
else:
ret.steerActuatorDelay = 0.1
ret.lateralTuning.pid.kpBP = [0.]
@@ -73,7 +87,7 @@ class CarInterface(CarInterfaceBase):
# Global longitudinal tuning defaults, can be overridden per-vehicle
ret.experimentalLongitudinalAvailable = ret.networkLocation == NetworkLocation.gateway or docs
ret.experimentalLongitudinalAvailable = not ret.flags & VolkswagenFlags.MEB and (ret.networkLocation == NetworkLocation.gateway or docs)
if experimental_long:
# Proof-of-concept, prep for E2E only. No radar points available. Panda ALLOW_DEBUG firmware required.
ret.openpilotLongitudinalControl = True
+71 -6
View File
@@ -72,6 +72,38 @@ class CarControllerParams:
"laneAssistDeactivTrailer": 5, # "Lane Assist: no function with trailer"
}
elif CP.flags & VolkswagenFlags.MEB:
self.LDW_STEP = 10 # LDW_02 message frequency 10Hz
self.ACC_HUD_STEP = 6 # MEB_ACC_01 message frequency 16Hz
self.STEER_DRIVER_ALLOWANCE = 60 # Driver torque 0.6 Nm, begin steering reduction from MAX
self.STEER_DRIVER_MAX = 300 # Driver torque 3.0 Nm, stop steering reduction at MIN
self.STEERING_POWER_MAX = 50 # HCA_03 maximum steering power, percentage
self.STEERING_POWER_MIN = 20 # HCA_03 minimum steering power, percentage
self.STEERING_POWER_STEP = 2 # HCA_03 steering power step increments
self.shifter_values = can_define.dv["Gateway_73"]["GE_Fahrstufe"]
self.hca_status_values = can_define.dv["QFK_01"]["LatCon_HCA_Status"]
self.BUTTONS = [
Button(structs.CarState.ButtonEvent.Type.setCruise, "GRA_ACC_01", "GRA_Tip_Setzen", [1]),
Button(structs.CarState.ButtonEvent.Type.resumeCruise, "GRA_ACC_01", "GRA_Tip_Wiederaufnahme", [1]),
Button(structs.CarState.ButtonEvent.Type.accelCruise, "GRA_ACC_01", "GRA_Tip_Hoch", [1]),
Button(structs.CarState.ButtonEvent.Type.decelCruise, "GRA_ACC_01", "GRA_Tip_Runter", [1]),
Button(structs.CarState.ButtonEvent.Type.cancel, "GRA_ACC_01", "GRA_Hauptschalter", [1]),
Button(structs.CarState.ButtonEvent.Type.gapAdjustCruise, "GRA_ACC_01", "GRA_Verstellung_Zeitluecke", [3]),
]
self.LDW_MESSAGES = {
"none": 0, # Nothing to display
"laneAssistTakeOverUrgent": 4, # "Lane Assist: Please Take Over Steering" (red)
"laneAssistTakeOver": 8, # "Lane Assist: Please Take Over Steering" (white)
}
self.LDW_SOUNDS = {
"None": 0, # No sound
"Chime": 1, # Play a chime
"Beep": 2, # Play a loud beep
}
else:
self.LDW_STEP = 10 # LDW_02 message frequency 10Hz
self.ACC_HUD_STEP = 6 # ACC_02 message frequency 16Hz
@@ -108,8 +140,8 @@ class CarControllerParams:
class CANBUS:
pt = 0
cam = 2
pt = 4
cam = 6
class WMI(StrEnum):
@@ -143,20 +175,33 @@ class VolkswagenFlags(IntFlag):
# Static flags
PQ = 2
MEB = 4
@dataclass
class VolkswagenMQBPlatformConfig(PlatformConfig):
dbc_dict: DbcDict = field(default_factory=lambda: {Bus.pt: 'vw_mqb_2010'})
dbc_dict: DbcDict = field(default_factory=lambda: {Bus.pt: 'vw_mqb'})
# Volkswagen uses the VIN WMI and chassis code to match in the absence of the comma power
# on camera-integrated cars, as we lose too many ECUs to reliably identify the vehicle
chassis_codes: set[str] = field(default_factory=set)
wmis: set[WMI] = field(default_factory=set)
@dataclass
class VolkswagenMEBPlatformConfig(PlatformConfig):
dbc_dict: DbcDict = field(default_factory=lambda: {Bus.pt: 'vw_meb', Bus.radar: 'vw_meb'})
# Volkswagen uses the VIN WMI and chassis code to match in the absence of the comma power
# on camera-integrated cars, as we lose too many ECUs to reliably identify the vehicle
chassis_codes: set[str] = field(default_factory=set)
wmis: set[WMI] = field(default_factory=set)
def init(self):
self.flags |= VolkswagenFlags.MEB
@dataclass
class VolkswagenPQPlatformConfig(VolkswagenMQBPlatformConfig):
dbc_dict: DbcDict = field(default_factory=lambda: {Bus.pt: 'vw_golf_mk4'})
dbc_dict: DbcDict = field(default_factory=lambda: {Bus.pt: 'vw_pq'})
def init(self):
self.flags |= VolkswagenFlags.PQ
@@ -188,6 +233,9 @@ class Footnote(Enum):
"Model-years 2022 and beyond may have a combined CAN gateway and BCM, which is supported by openpilot " +
"in software, but doesn't yet have a harness available from the comma store.",
Column.HARDWARE)
VW_MEB = CarFootnote(
"Volkswagen MEB plattform is using CAN-FD, which is supported by comma 3x or red panda.",
Column.HARDWARE)
@dataclass
@@ -200,7 +248,9 @@ class VWCarDocs(CarDocs):
if "SKODA" in CP.carFingerprint:
self.footnotes.append(Footnote.SKODA_HEATED_WINDSHIELD)
if CP.carFingerprint in (CAR.VOLKSWAGEN_CRAFTER_MK2, CAR.VOLKSWAGEN_TRANSPORTER_T61):
if CP.flags & VolkswagenFlags.MEB:
self.car_parts = CarParts.common([CarHarness.vw_c])
elif CP.carFingerprint in (CAR.VOLKSWAGEN_CRAFTER_MK2, CAR.VOLKSWAGEN_TRANSPORTER_T61):
self.car_parts = CarParts([Device.threex_angled_mount, CarHarness.vw_j533])
if abs(CP.minSteerSpeed - CarControllerParams.DEFAULT_MIN_STEER_SPEED) < 1e-3:
@@ -212,7 +262,7 @@ class VWCarDocs(CarDocs):
# FW_VERSIONS for that existing CAR.
class CAR(Platforms):
config: VolkswagenMQBPlatformConfig | VolkswagenPQPlatformConfig
config: VolkswagenMQBPlatformConfig | VolkswagenPQPlatformConfig | VolkswagenMEBPlatformConfig
VOLKSWAGEN_ARTEON_MK1 = VolkswagenMQBPlatformConfig(
[
@@ -274,6 +324,12 @@ class CAR(Platforms):
chassis_codes={"5G", "AU", "BA", "BE"},
wmis={WMI.VOLKSWAGEN_MEXICO_CAR, WMI.VOLKSWAGEN_EUROPE_CAR},
)
VOLKSWAGEN_ID4_MK1 = VolkswagenMEBPlatformConfig(
[VWCarDocs("Volkswagen ID.4 2021-25", footnotes=[Footnote.VW_MEB])],
VolkswagenCarSpecs(mass=2099, wheelbase=2.77),
chassis_codes={"E2", "E8"},
wmis={WMI.VOLKSWAGEN_EUROPE_SUV, WMI.VOLKSWAGEN_USA_SUV},
)
VOLKSWAGEN_JETTA_MK6 = VolkswagenPQPlatformConfig(
[VWCarDocs("Volkswagen Jetta 2015-18")],
VolkswagenCarSpecs(mass=1518, wheelbase=2.65, minSteerSpeed=50 * CV.KPH_TO_MS, minEnableSpeed=20 * CV.KPH_TO_MS),
@@ -398,6 +454,15 @@ class CAR(Platforms):
chassis_codes={"5F"},
wmis={WMI.SEAT},
)
SKODA_ENYAQ_MK1 = VolkswagenMEBPlatformConfig(
[
VWCarDocs("Škoda Enyaq 2021-25"),
VWCarDocs("Škoda Enyaq Coupe 2023-25"),
],
VolkswagenCarSpecs(mass=2137, wheelbase=2.77),
chassis_codes={"NY"},
wmis={WMI.SKODA},
)
SKODA_FABIA_MK4 = VolkswagenMQBPlatformConfig(
[VWCarDocs("Škoda Fabia 2022-23", footnotes=[Footnote.VW_MQB_A0])],
VolkswagenCarSpecs(mass=1266, wheelbase=2.56),
@@ -194,15 +194,12 @@ BO_ 711 BECMBatteryVoltageCurrent: 6 K17_EBCM
SG_ HVBatteryCurrent : 12|13@0- (0.15,0) [-614.4|614.25] "A" NEO
BO_ 715 ASCMGasRegenCmd: 8 K124_ASCM
SG_ GasRegenAlwaysOne2 : 9|1@0+ (1,0) [0|1] "" NEO
SG_ GasRegenAlwaysOne : 14|1@0+ (1,0) [0|1] "" NEO
SG_ GasRegenChecksum : 47|24@0+ (1,0) [0|0] "" NEO
SG_ GasRegenCmdActiveInv : 32|1@0+ (1,0) [0|0] "" NEO
SG_ GasRegenAccType : 15|2@0+ (1,0) [0|3] "" NEO
SG_ GasRegenChecksum : 32|25@0+ (1,0) [0|0] "" NEO
SG_ GasRegenFullStopActive : 13|1@0+ (1,0) [0|0] "" NEO
SG_ GasRegenCmdActive : 0|1@0+ (1,0) [0|0] "" NEO
SG_ RollingCounter : 7|2@0+ (1,0) [0|0] "" NEO
SG_ GasRegenAlwaysOne3 : 23|1@0+ (1,0) [0|1] "" NEO
SG_ GasRegenCmd : 22|12@0+ (1,0) [0|0] "" NEO
SG_ GasRegenCmd : 10|19@0+ (0.125,-22534) [-22534|43001.875] "Nm" NEO
BO_ 717 ASCM_2CD: 5 K124_ASCM
@@ -107,7 +107,7 @@ BO_ 1227 LKAS_SETTINGS: 8 XXX
VAL_ 1228 PROPILOT_NA_MSGS 0 "NO_MSG" 1 "NA_FRONT_CAMERA_IMPARED" 2 "STEERING_ASSIST_ON_STANDBY" 3 "NA_PARKING_ASSIST_ENABLED" 4 "STEER_ASSIST_CURRENTLY_NA" 5 "NA_BAD_WEATHER" 6 "NA_PARK_BRAKE_ON" 7 "NA_SEATBELT_NOT_FASTENED" ;
VAL_ 1228 BOTTOM_MSG 0 "OK_STEER_ASSIST_SETTINGS" 1 "NO_MSG" 2 "PRESS_SET_TO_SET_SPEED" 3 "PRESS_RES_SET_TO_CHANGE_SPEED" 4 "PRESS_RES_TO_RESTART" 5 "NO_MSG" 6 "CRUISE_NOT_AVAIL" 7 "NO_MSG" ;
VAL_ 689 FOLLOW_DISTANCE 0 "NO_FOLLOW_DISTANCE" 1 "FOLLOW_DISTANCE_1" 2 "FOLLOW_DISTANCE_2" 3 "FOLLOW_DISANCE_3" ;
VAL_ 689 FOLLOW_DISTANCE 0 "NO_FOLLOW_DISTANCE" 1 "FOLLOW_DISTANCE_1" 2 "FOLLOW_DISTANCE_2" 3 "FOLLOW_DISTANCE_3" ;
VAL_ 689 AUDIBLE_TONE 0 "NO_TONE" 1 "CONT" 2 "FAST_BEEP_CONT" 3 "TRIPLE_FAST_BEEP_CONT" 4 "SLOW_BEEP_CONT" 5 "QUAD_SLOW_BEEP_CONT" 6 "SINGLE_BEEP_ONCE" 7 "DOUBLE_BEEP_ONCE" ;
VAL_ 689 SMALL_STEERING_WHEEL_ICON 0 "NO_ICON" 1 "GRAY_ICON" 2 "GRAY_ICON_FLASHING" 3 "GREEN_ICON" 4 "GREEN_ICON_FLASHING" 5 "RED_ICON" 6 "RED_ICON_FLASHING" 7 "YELLOW_ICON" ;
VAL_ 689 LARGE_STEERING_WHEEL_ICON 0 "NO_STEERINGWHEEL" 1 "GRAY_STEERINGWHEEL" 2 "GREEN_STEERINGWHEEL" 3 "GREEN_STEERINGWHEEL_FLASHING" ;
@@ -197,15 +197,12 @@ BO_ 711 BECMBatteryVoltageCurrent: 6 K17_EBCM
SG_ HVBatteryCurrent : 12|13@0- (0.15,0) [-614.4|614.25] "A" NEO
BO_ 715 ASCMGasRegenCmd: 8 K124_ASCM
SG_ GasRegenAlwaysOne2 : 9|1@0+ (1,0) [0|1] "" NEO
SG_ GasRegenAlwaysOne : 14|1@0+ (1,0) [0|1] "" NEO
SG_ GasRegenChecksum : 47|24@0+ (1,0) [0|0] "" NEO
SG_ GasRegenCmdActiveInv : 32|1@0+ (1,0) [0|0] "" NEO
SG_ GasRegenAccType : 15|2@0+ (1,0) [0|3] "" NEO
SG_ GasRegenChecksum : 32|25@0+ (1,0) [0|0] "" NEO
SG_ GasRegenFullStopActive : 13|1@0+ (1,0) [0|0] "" NEO
SG_ GasRegenCmdActive : 0|1@0+ (1,0) [0|0] "" NEO
SG_ RollingCounter : 7|2@0+ (1,0) [0|0] "" NEO
SG_ GasRegenAlwaysOne3 : 23|1@0+ (1,0) [0|1] "" NEO
SG_ GasRegenCmd : 22|12@0+ (1,0) [0|0] "" NEO
SG_ GasRegenCmd : 10|19@0+ (0.125,-22534) [-22534|43001.875] "Nm" NEO
BO_ 717 ASCM_2CD: 5 K124_ASCM
@@ -111,7 +111,7 @@ BO_ 1227 LKAS_SETTINGS: 8 XXX
VAL_ 1228 PROPILOT_NA_MSGS 0 "NO_MSG" 1 "NA_FRONT_CAMERA_IMPARED" 2 "STEERING_ASSIST_ON_STANDBY" 3 "NA_PARKING_ASSIST_ENABLED" 4 "STEER_ASSIST_CURRENTLY_NA" 5 "NA_BAD_WEATHER" 6 "NA_PARK_BRAKE_ON" 7 "NA_SEATBELT_NOT_FASTENED" ;
VAL_ 1228 BOTTOM_MSG 0 "OK_STEER_ASSIST_SETTINGS" 1 "NO_MSG" 2 "PRESS_SET_TO_SET_SPEED" 3 "PRESS_RES_SET_TO_CHANGE_SPEED" 4 "PRESS_RES_TO_RESTART" 5 "NO_MSG" 6 "CRUISE_NOT_AVAIL" 7 "NO_MSG" ;
VAL_ 689 FOLLOW_DISTANCE 0 "NO_FOLLOW_DISTANCE" 1 "FOLLOW_DISTANCE_1" 2 "FOLLOW_DISTANCE_2" 3 "FOLLOW_DISANCE_3" ;
VAL_ 689 FOLLOW_DISTANCE 0 "NO_FOLLOW_DISTANCE" 1 "FOLLOW_DISTANCE_1" 2 "FOLLOW_DISTANCE_2" 3 "FOLLOW_DISTANCE_3" ;
VAL_ 689 AUDIBLE_TONE 0 "NO_TONE" 1 "CONT" 2 "FAST_BEEP_CONT" 3 "TRIPLE_FAST_BEEP_CONT" 4 "SLOW_BEEP_CONT" 5 "QUAD_SLOW_BEEP_CONT" 6 "SINGLE_BEEP_ONCE" 7 "DOUBLE_BEEP_ONCE" ;
VAL_ 689 SMALL_STEERING_WHEEL_ICON 0 "NO_ICON" 1 "GRAY_ICON" 2 "GRAY_ICON_FLASHING" 3 "GREEN_ICON" 4 "GREEN_ICON_FLASHING" 5 "RED_ICON" 6 "RED_ICON_FLASHING" 7 "YELLOW_ICON" ;
VAL_ 689 LARGE_STEERING_WHEEL_ICON 0 "NO_STEERINGWHEEL" 1 "GRAY_STEERINGWHEEL" 2 "GREEN_STEERINGWHEEL" 3 "GREEN_STEERINGWHEEL_FLASHING" ;
@@ -111,7 +111,7 @@ BO_ 1227 LKAS_SETTINGS: 8 XXX
VAL_ 1228 PROPILOT_NA_MSGS 0 "NO_MSG" 1 "NA_FRONT_CAMERA_IMPARED" 2 "STEERING_ASSIST_ON_STANDBY" 3 "NA_PARKING_ASSIST_ENABLED" 4 "STEER_ASSIST_CURRENTLY_NA" 5 "NA_BAD_WEATHER" 6 "NA_PARK_BRAKE_ON" 7 "NA_SEATBELT_NOT_FASTENED" ;
VAL_ 1228 BOTTOM_MSG 0 "OK_STEER_ASSIST_SETTINGS" 1 "NO_MSG" 2 "PRESS_SET_TO_SET_SPEED" 3 "PRESS_RES_SET_TO_CHANGE_SPEED" 4 "PRESS_RES_TO_RESTART" 5 "NO_MSG" 6 "CRUISE_NOT_AVAIL" 7 "NO_MSG" ;
VAL_ 689 FOLLOW_DISTANCE 0 "NO_FOLLOW_DISTANCE" 1 "FOLLOW_DISTANCE_1" 2 "FOLLOW_DISTANCE_2" 3 "FOLLOW_DISANCE_3" ;
VAL_ 689 FOLLOW_DISTANCE 0 "NO_FOLLOW_DISTANCE" 1 "FOLLOW_DISTANCE_1" 2 "FOLLOW_DISTANCE_2" 3 "FOLLOW_DISTANCE_3" ;
VAL_ 689 AUDIBLE_TONE 0 "NO_TONE" 1 "CONT" 2 "FAST_BEEP_CONT" 3 "TRIPLE_FAST_BEEP_CONT" 4 "SLOW_BEEP_CONT" 5 "QUAD_SLOW_BEEP_CONT" 6 "SINGLE_BEEP_ONCE" 7 "DOUBLE_BEEP_ONCE" ;
VAL_ 689 SMALL_STEERING_WHEEL_ICON 0 "NO_ICON" 1 "GRAY_ICON" 2 "GRAY_ICON_FLASHING" 3 "GREEN_ICON" 4 "GREEN_ICON_FLASHING" 5 "RED_ICON" 6 "RED_ICON_FLASHING" 7 "YELLOW_ICON" ;
VAL_ 689 LARGE_STEERING_WHEEL_ICON 0 "NO_STEERINGWHEEL" 1 "GRAY_STEERINGWHEEL" 2 "GREEN_STEERINGWHEEL" 3 "GREEN_STEERINGWHEEL_FLASHING" ;
@@ -85,28 +85,27 @@ BO_ 272 ACM_SteeringControl: 8 ACM
SG_ ACM_SteeringAngleRequest : 23|15@0+ (0.1,-1638.4) [-1638.4|1638.3] "deg" EPAS_P
BO_ 288 ACM_lkaHbaCmd: 8 ACM
SG_ ACM_lkaHbaCmd_Checksum : 7|8@0+ (1,0) [0|0] "" EPAS_P
SG_ ACM_lkaHbaCmd_Counter : 11|4@0+ (1,0) [0|0] "" EPAS_P
SG_ ACM_unkown1 : 12|1@0+ (1,0) [0|1] "" XXX
SG_ ACM_unkown6 : 13|1@0+ (1,0) [0|1] "" XXX
SG_ ACM_unkown5 : 14|1@0+ (1,0) [0|1] "" XXX
SG_ ACM_lkaHbaCmd_Checksum : 7|8@0+ (1,0) [0|255] "" EPAS_P
SG_ ACM_lkaHbaCmd_Counter : 11|4@0+ (1,0) [0|15] "" EPAS_P
SG_ ACM_lkaElkRequest : 14|3@0+ (1,0) [0|7] "" EPAS_P
SG_ ACM_HapticRequest : 15|1@0+ (1,0) [0|1] "" EPAS_P
SG_ ACM_lkaStrToqReq : 23|11@0+ (1,-1024) [-1024|1024] "" EPAS_P
SG_ ACM_lkaSymbolState : 26|3@0+ (1,0) [0|7] "" EPAS_P
SG_ ACM_lkaToiFlt : 27|1@0+ (1,0) [0|1] "" EPAS_P
SG_ ACM_lkaActToi : 28|1@0+ (1,0) [0|1] "" EPAS_P
SG_ ACM_hbaSysState : 34|3@0+ (1,0) [0|7] "" EPAS_P
SG_ ACM_FailinfoAeb : 37|3@0+ (1,0) [0|7] "" EPAS_P
SG_ ACM_unkown2 : 38|2@1+ (1,0) [0|3] "" XXX
SG_ ACM_lkaRHWarning : 41|2@0+ (1,0) [0|3] "" EPAS_P
SG_ ACM_lkaLHWarning : 43|2@0+ (1,0) [0|3] "" EPAS_P
SG_ ACM_hbaLamp : 35|1@0+ (1,0) [0|1] "" EPAS_P
SG_ ACM_slifOnOffState : 37|2@0+ (1,0) [0|3] "" EPAS_P
SG_ ACM_elkOnOffState : 39|2@0+ (1,0) [0|3] "" EPAS_P
SG_ ACM_ldwLHWarning : 43|3@0+ (1,0) [0|7] "" EPAS_P
SG_ ACM_lkaLaneRecogState : 45|2@0+ (1,0) [0|3] "" EPAS_P
SG_ ACM_hbaOpt : 46|1@0+ (1,0) [0|1] "" EPAS_P
SG_ ACM_hbaLamp : 47|1@0+ (1,0) [0|1] "" EPAS_P
SG_ ACM_unkown3 : 51|4@0+ (1,0) [0|15] "" XXX
SG_ ACM_hbaOnOffState : 47|2@0+ (1,0) [0|3] "" EPAS_P
SG_ ACM_ldwlkaOnOffState : 48|3@0+ (1,0) [0|7] "" EPAS_P
SG_ ACM_ldwWarnTimingState : 51|3@0+ (1,0) [0|7] "" EPAS_P
SG_ ACM_lkaHandsoffSoundWarning : 53|2@0+ (1,0) [0|3] "" EPAS_P
SG_ ACM_lkaHandsoffDisplayWarning : 55|2@0+ (1,0) [0|3] "" EPAS_P
SG_ ACM_unkown4 : 56|8@1+ (1,0) [0|255] "" XXX
SG_ ACM_ldwRHWarning : 58|3@0+ (1,0) [0|7] "" EPAS_P
SG_ ACM_ldwWarnTypeState : 61|3@0+ (1,0) [0|7] "" EPAS_P
BO_ 304 RCM_IMU_LatAccYaw: 8 RCM
SG_ RCM_LateralAccelYaw_Checksum : 7|8@0+ (1,0) [0|25] "" ACM,ESP,VDM
@@ -828,14 +827,15 @@ VAL_ 288 ACM_lkaSymbolState 0 "ACM_LKASYMBOLSTATE_OFF" 1 "ACM_LKASYMBOLSTATE_WHI
VAL_ 288 ACM_lkaToiFlt 0 "ACM_LKATOIFLT_NO_FAULT" 1 "ACM_LKATOIFLT_FAULT_PRESENT";
VAL_ 288 ACM_lkaActToi 0 "ACM_LKAACTTOI_DE_ACTIVATE_TOI" 1 "ACM_LKAACTTOI_ACTIVATE_TOI";
VAL_ 288 ACM_hbaSysState 0 "ACM_HBASYSSTATE_DEFAULT_DISABLE" 1 "ACM_HBASYSSTATE_HBA_ENABLE_HIGH_BEAM_OFF" 2 "ACM_HBASYSSTATE_HBA_ENABLE_HIGH_BEAM_ON" 7 "ACM_HBASYSSTATE_SYSTEM_FAIL";
VAL_ 288 ACM_FailinfoAeb 0 "ACM_FAILINFOAEB_NORMAL" 1 "ACM_FAILINFOAEB_CAMERA_FAILURE" 2 "ACM_FAILINFOAEB_FRONT_RADAR_COM_ERR" 3 "ACM_FAILINFOAEB_CAMERA_BLOCKAGE" 4 "ACM_FAILINFOAEB_RESERVED_4" 5 "ACM_FAILINFOAEB_RESERVED_5" 6 "ACM_FAILINFOAEB_RESERVED_6";
VAL_ 288 ACM_lkaRHWarning 0 "ACM_LKARHWARNING_NO_WARNING" 1 "ACM_LKARHWARNING_HAPTIC_WARNING_AND_DISPLAY" 2 "ACM_LKARHWARNING_ACOUSTIC_WARNING_AND_DISPLAY" 3 "ACM_LKARHWARNING_HAPTIC_ACOUSTIC_AND_DISPLAY";
VAL_ 288 ACM_lkaLHWarning 0 "ACM_LKALHWARNING_NO_WARNING" 1 "ACM_LKALHWARNING_HAPTIC_WARNING_AND_DISPLAY" 2 "ACM_LKALHWARNING_ACOUSTIC_WARNING_AND_DISPLAY" 3 "ACM_LKALHWARNING_HAPTIC_ACOUSTIC_AND_DISPLAY";
VAL_ 288 ACM_ldwRHWarning 0 "ACM_LKARHWARNING_NO_WARNING" 1 "ACM_LKARHWARNING_HAPTIC_WARNING_AND_DISPLAY" 2 "ACM_LKARHWARNING_ACOUSTIC_WARNING_AND_DISPLAY" 3 "ACM_LKARHWARNING_HAPTIC_ACOUSTIC_AND_DISPLAY";
VAL_ 288 ACM_ldwLHWarning 0 "ACM_LKALHWARNING_NO_WARNING" 1 "ACM_LKALHWARNING_HAPTIC_WARNING_AND_DISPLAY" 2 "ACM_LKALHWARNING_ACOUSTIC_WARNING_AND_DISPLAY" 3 "ACM_LKALHWARNING_HAPTIC_ACOUSTIC_AND_DISPLAY";
VAL_ 288 ACM_lkaLaneRecogState 0 "ACM_LKALANERECOGSTATE_NOT_RECOGNITION" 1 "ACM_LKALANERECOGSTATE_LEFT_LANE_RECOGNITION" 2 "ACM_LKALANERECOGSTATE_RIGHT_LANE_RECOGNITION" 3 "ACM_LKALANERECOGSTATE_FULL_LANE_RECOGNITION";
VAL_ 288 ACM_hbaOpt 0 "ACM_HBAOPT_NONE_HBA_OPTION_DEFAULT" 1 "ACM_HBAOPT_HBA_SYSTEM_ENABLE";
VAL_ 288 ACM_hbaLamp 0 "ACM_HBALAMP_HBA_INDICATOR_LAMP_OFF" 1 "ACM_HBALAMP_HBA_INDICATOR_LAMP_ON";
VAL_ 288 ACM_lkaHandsoffSoundWarning 0 "ACM_LKAHANDSOFFSOUNDWARNING_NO_INFO" 1 "ACM_LKAHANDSOFFSOUNDWARNING_WARNING" 2 "ACM_LKAHANDSOFFSOUNDWARNING_RESERVED_2" 3 "ACM_LKAHANDSOFFSOUNDWARNING_RESERVED_3";
VAL_ 288 ACM_lkaHandsoffDisplayWarning 0 "ACM_LKAHANDSOFFDISPLAYWARNING_NO_INFO" 1 "ACM_LKAHANDSOFFDISPLAYWARNING_WARNING" 2 "ACM_LKAHANDSOFFDISPLAYWARNING_RESERVED_2" 3 "ACM_LKAHANDSOFFDISPLAYWARNING_RESERVED_3";
VAL_ 288 ACM_lkaElkRequest 0 "off" 1 "applying torque right for left departure" 2 "applying torque left for right departure";
VAL_ 288 ACM_ldwlkaOnOffState 1 "LDW on" 2 "LKAS+LDW on" 3 "all off";
VAL_ 288 ACM_elkOnOffState 1 "LKAS toggled on" 2 "LKAS toggled off";
VAL_ 304 RCM_IMU_LatAcc_Stat_SensAvail 0 "RCM_IMU_LatAcc_Stat_SensAvail_InSpec" 1 "RCM_IMU_LatAcc_Stat_SensAvail_NotInSpec";
VAL_ 304 RCM_IMU_LatAcc_Stat_Fail 0 "RCM_IMU_LatAcc_Stat_Fail_NotFailed" 1 "RCM_IMU_LatAcc_Stat_Fail_Failed";
VAL_ 304 RCM_IMU_LatAcc_Stat_Init 0 "RCM_IMU_LatAcc_Stat_Init_Finished" 1 "RCM_IMU_LatAcc_Stat_Init_Running";
@@ -189,6 +189,8 @@ BO_ 599 DI_speed: 8 PARTY
SG_ DI_speedCounter : 8|4@1+ (1,0) [0|15] "" park
SG_ DI_speedChecksum : 0|8@1+ (1,0) [0|255] "" park
BO_ 605 XXX_longitudinalRelated: 6 XXX
BO_ 1160 DAS_steeringControl: 4 PARTY
SG_ DAS_steeringControlChecksum : 31|8@0+ (1,0) [0|255] "" aps
SG_ DAS_steeringControlCounter : 19|4@0+ (1,0) [0|15] "" aps
@@ -224,15 +226,28 @@ BO_ 646 DI_state: 8 ETH
SG_ DI_locStatusChecksum : 0|8@1+ (1,0) [0|0] "" X
BO_ 659 DAS_settings: 8 XXX
SG_ DAS_autopilotEnabled : 38|1@0+ (1,0) [0|1] "" XXX
SG_ DAS_driverSteeringWeight : 1|2@0+ (1,0) [0|255] "" XXX
SG_ DAS_slipStart : 2|1@0+ (1,0) [0|1] "" XXX
SG_ DAS_offRoadAssist : 3|2@1+ (1,0) [0|63] "" XXX
SG_ DAS_distanceUnits : 13|1@1+ (1,0) [0|255] "" XXX
SG_ DAS_aebEnabled : 18|1@0+ (1,0) [0|255] "" XXX
SG_ DAS_adaptiveHeadlights : 22|1@1+ (1,0) [0|31] "" XXX
SG_ DAS_autosteerEnabled2 : 24|1@0+ (1,0) [0|1] "" XXX
SG_ DAS_fcwEnabled : 34|1@0+ (1,0) [0|1] "" XXX
SG_ DAS_fcwSensitivity : 37|2@0+ (1,0) [0|63] "" XXX
SG_ DAS_autosteerEnabled : 38|1@0+ (1,0) [0|1] "" XXX
SG_ DAS_obstacleAwareAcceleration : 42|1@0+ (1,0) [0|1] "" XXX
SG_ DAS_driverAccelerationMode : 44|1@1+ (1,0) [0|127] "" XXX
SG_ DAS_settingCounter : 52|4@1+ (1,0) [0|15] "" XXX
SG_ DAS_settingChecksum : 63|8@0+ (1,0) [0|255] "" XXX
BO_ 785 UI_warning: 7 XXX
SG_ buckleStatus : 13|1@0+ (1,0) [0|1] "" XXX
SG_ scrollWheelRightTilt : 21|1@0+ (1,0) [0|1] "" XXX
SG_ scrollWheelPressed : 21|1@0+ (1,0) [0|1] "" XXX
SG_ leftBlinkerOn : 22|1@0+ (1,0) [0|1] "" XXX
SG_ rightBlinkerOn : 23|1@0+ (1,0) [0|1] "" XXX
SG_ leftBlinkerBlinking : 25|2@0+ (1,0) [0|3] "" XXX
SG_ rightBlinkerBlinking : 26|2@1+ (1,0) [0|15] "" XXX
SG_ anyDoorOpen : 28|1@0+ (1,0) [0|1] "" XXX
SG_ wiperSettings : 39|8@0+ (1,0) [0|255] "" XXX
SG_ highBeam : 50|1@0+ (1,0) [0|1] "" XXX
@@ -266,11 +281,12 @@ BO_ 923 DAS_status: 8 PARTY
SG_ DAS_autopilotState : 0|4@1+ (1,0) [0|15] "" aps
CM_ BO_ 605 "Bytes change when toggling between FSD and AP, as well as Traffic Light and Stop Sign Control in TACC";
CM_ SG_ 659 DAS_autosteerEnabled "1 if Autosteer or FSD is enabled, 0 otherwise";
CM_ SG_ 785 leftBlinkerOn "only describes stalk position if half pressed without auto-cancel blinkers. otherwise acts as expected";
CM_ SG_ 785 rightBlinkerOn "only describes stalk position if half pressed without auto-cancel blinkers. otherwise acts as expected";
CM_ SG_ 785 scrollWheelPressed "captures either scroll wheel left, right or down press";
VAL_ 545 VCFRONT_uiAudioLVState 1 "LV_ON" 2 "LV_GOING_DOWN" 3 "LV_FAULT" 0 "LV_OFF" ;
VAL_ 545 VCFRONT_uiHiCurrentLVState 1 "LV_ON" 2 "LV_GOING_DOWN" 3 "LV_FAULT" 0 "LV_OFF" ;
@@ -385,8 +401,15 @@ VAL_ 646 DI_parkBrakeState 0 "UNAVAILABLE" 1 "RELEASED" 2 "REQUESTED" 3 "APPLIED
VAL_ 646 DI_autoparkState 0 "UNAVAILABLE" 1 "STANDBY" 2 "STARTED" 3 "ACTIVE" 4 "COMPLETE" 5 "PAUSED" 6 "ABORTED" 7 "RESUMED" 8 "UNPARK_COMPLETE" 9 "SELFPARK_STARTED" 15 "SNA" ;
VAL_ 646 DI_speedUnits 0 "MPH" 1 "KPH" ;
VAL_ 646 DI_cruiseState 0 "UNAVAILABLE" 1 "STANDBY" 2 "ENABLED" 3 "STANDSTILL" 4 "OVERRIDE" 5 "FAULT" 6 "PRE_FAULT" 7 "PRE_CANCEL" ;
VAL_ 659 DAS_driverSteeringWeight 0 "light" 1 "standard" 2 "heavy";
VAL_ 659 DAS_offRoadAssist 0 "disabled" 3 "enabled";
VAL_ 659 DAS_distanceUnits 1 "miles" 0 "kilometers";
VAL_ 659 DAS_fcwSensitivity 0 "early" 1 "medium" 2 "late" 3 "off";
VAL_ 659 DAS_driverAccelerationMode 0 "chill" 1 "standard";
VAL_ 785 buckleStatus 1 "LATCHED" 0 "UNLATCHED" ;
VAL_ 785 anyDoorOpen 1 "OPEN" 0 "CLOSED" ;
VAL_ 785 leftBlinkerBlinking 0 "off" 1 "blinking, off" 2 "blinking, on";
VAL_ 785 rightBlinkerBlinking 0 "off" 1 "blinking, off" 2 "blinking, on";
VAL_ 923 DAS_autoLaneChangeState 5 "ALC_UNAVAILABLE_VEHICLE_SPEED" 17 "ALC_ABORT_POOR_VIEW_RANGE" 23 "ALC_BLOCKED_VEH_TTC_AND_USS_L" 0 "ALC_UNAVAILABLE_DISABLED" 26 "ALC_BLOCKED_LANE_TYPE_L" 29 "ALC_ABORT_TIMEOUT" 9 "ALC_IN_PROGRESS_L" 4 "ALC_UNAVAILABLE_EXITING_HIGHWAY" 22 "ALC_BLOCKED_VEH_TTC_L" 12 "ALC_WAITING_FOR_SIDE_OBST_TO_PASS_R" 18 "ALC_ABORT_LC_HEALTH_BAD" 28 "ALC_WAITING_HANDS_ON" 8 "ALC_AVAILABLE_BOTH" 11 "ALC_WAITING_FOR_SIDE_OBST_TO_PASS_L" 3 "ALC_UNAVAILABLE_TP_FOLLOW" 2 "ALC_UNAVAILABLE_SONICS_INVALID" 21 "ALC_UNAVAILABLE_SOLID_LANE_LINE" 24 "ALC_BLOCKED_VEH_TTC_R" 1 "ALC_UNAVAILABLE_NO_LANES" 25 "ALC_BLOCKED_VEH_TTC_AND_USS_R" 30 "ALC_ABORT_MISSION_PLAN_INVALID" 27 "ALC_BLOCKED_LANE_TYPE_R" 19 "ALC_ABORT_BLINKER_TURNED_OFF" 31 "ALC_SNA" 13 "ALC_WAITING_FOR_FWD_OBST_TO_PASS_L" 16 "ALC_ABORT_SIDE_OBSTACLE_PRESENT_R" 6 "ALC_AVAILABLE_ONLY_L" 20 "ALC_ABORT_OTHER_REASON" 15 "ALC_ABORT_SIDE_OBSTACLE_PRESENT_L" 7 "ALC_AVAILABLE_ONLY_R" 14 "ALC_WAITING_FOR_FWD_OBST_TO_PASS_R" 10 "ALC_IN_PROGRESS_R" ;
VAL_ 923 DAS_autopilotHandsOnState 8 "LC_HANDS_ON_SUSPENDED" 15 "LC_HANDS_ON_SNA" 7 "LC_HANDS_ON_REQD_STRUCK_OUT" 3 "LC_HANDS_ON_REQD_VISUAL" 4 "LC_HANDS_ON_REQD_CHIME_1" 6 "LC_HANDS_ON_REQD_SLOWING" 1 "LC_HANDS_ON_REQD_DETECTED" 2 "LC_HANDS_ON_REQD_NOT_DETECTED" 5 "LC_HANDS_ON_REQD_CHIME_2" 0 "LC_HANDS_ON_NOT_REQD" ;
VAL_ 923 DAS_fleetSpeedState 0 "FLEETSPEED_UNAVAILABLE" 1 "FLEETSPEED_AVAILABLE" 2 "FLEETSPEED_ACTIVE" 3 "FLEETSPEED_HOLD" ;
@@ -404,6 +427,3 @@ VAL_ 923 DAS_fusedSpeedLimit 31 "NONE" 0 "UNKNOWN_SNA" ;
VAL_ 923 DAS_blindSpotRearRight 3 "SNA" 0 "NO_WARNING" 1 "WARNING_LEVEL_1" 2 "WARNING_LEVEL_2" ;
VAL_ 923 DAS_blindSpotRearLeft 3 "SNA" 0 "NO_WARNING" 1 "WARNING_LEVEL_1" 2 "WARNING_LEVEL_2" ;
VAL_ 923 DAS_autopilotState 15 "SNA" 8 "ABORTING" 3 "ACTIVE_NOMINAL" 0 "DISABLED" 4 "ACTIVE_RESTRICTED" 5 "ACTIVE_NAV" 14 "FAULT" 1 "UNAVAILABLE" 9 "ABORTED" 2 "AVAILABLE" ;
+8 -8
View File
@@ -169,7 +169,7 @@ BO_ 192 EM1_01: 32 XXX
SG_ Schubbetrieb : 79|1@0+ (1,0) [0|1] "" XXX
BO_ 219 AWV_03: 48 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ XCHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ FCW_Active : 64|1@0+ (1,0) [0|1] "" XXX
SG_ Pre_Brake_Fill : 76|1@0+ (1,0) [0|1] "" XXX
@@ -180,8 +180,8 @@ BO_ 247 MEB_HVEM_02: 8 XXX
SG_ NEW_SIGNAL_3 : 44|10@1+ (1,0) [0|7] "" XXX
SG_ NEW_SIGNAL_2 : 54|7@1+ (1,0) [0|3] "" XXX
BO_ 252 ESC_51: 48 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
BO_ 252 ESC_51: 64 XXX
SG_ XCHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ AEB_Breaking_01 : 24|8@1+ (1,0) [0|255] "" XXX
SG_ AEB_Breaking_02 : 32|8@1+ (1,0) [0|255] "" XXX
@@ -223,7 +223,7 @@ BO_ 253 ESP_21: 8 Gateway
SG_ ESC_Neutralschaltung : 63|1@1+ (1,0) [0|1] "" Vector__XXX
BO_ 258 ESC_50: 48 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ XCHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ Lateral_Accel : 16|8@1+ (0.15,-18.9) [0|255] "Unit_MeterPerSquareSecond" XXX
SG_ Longitudinal_Accel : 24|10@1+ (0.03125,-16) [0|255] "Unit_MeterPerSquareSecond" XXX
@@ -242,8 +242,8 @@ BO_ 261 VMM_01: 8 XXX
SG_ NEW_SIGNAL_1 : 40|2@1+ (1,0) [0|3] "" XXX
SG_ Brake : 53|7@1+ (1,0) [0|3] "" XXX
BO_ 267 Motor_51: 32 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
BO_ 267 Motor_51: 48 XXX
SG_ XCHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ Accel_Pedal_Pressure : 12|9@1+ (0.4,0) [0|255] "" XXX
SG_ Accel_Low_Pressed_Support : 21|1@1+ (1,0) [0|7] "" XXX
@@ -319,7 +319,7 @@ BO_ 299 GRA_ACC_01: 8 Gateway
BO_ 312 IPA_01: 32 XXX
BO_ 313 VMM_02: 32 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ XCHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ Brake_Pressed_1 : 16|1@0+ (1,0) [0|1] "" XXX
SG_ Brake_Pressed_2 : 27|1@0+ (1,0) [0|1] "" XXX
@@ -330,7 +330,7 @@ BO_ 313 VMM_02: 32 XXX
SG_ Brake_Pressure : 76|11@1+ (1,0) [0|100] "" XXX
BO_ 317 QFK_01: 32 XXX
SG_ CHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ XCHECKSUM : 0|8@1+ (1,0) [0|255] "" XXX
SG_ COUNTER : 8|4@1+ (1,0) [0|15] "" XXX
SG_ NEW_SIGNAL_5 : 12|1@0+ (1,0) [0|1] "" XXX
SG_ NEW_SIGNAL_9 : 14|1@0+ (1,0) [0|1] "" XXX
+15 -3
View File
@@ -25,6 +25,7 @@
// CAN-FD only safety modes
#ifdef CANFD
#include "safety/safety_hyundai_canfd.h"
#include "safety/safety_volkswagen_meb.h"
#endif
// from cereal.car.CarParams.SafetyModel
@@ -417,6 +418,9 @@ int set_safety_hooks(uint16_t mode, uint16_t param) {
{SAFETY_RIVIAN, &rivian_hooks},
#ifdef CANFD
{SAFETY_HYUNDAI_CANFD, &hyundai_canfd_hooks},
#ifdef ALLOW_DEBUG
{SAFETY_VOLKSWAGEN_MEB, &volkswagen_meb_hooks},
#endif
#endif
#ifdef ALLOW_DEBUG
{SAFETY_TESLA, &tesla_hooks},
@@ -643,13 +647,21 @@ bool steer_torque_cmd_checks(int desired_torque, int steer_req, const TorqueStee
uint32_t ts = microsecond_timer_get();
if (controls_allowed) {
// Some safety models support variable torque limit based on vehicle speed
int max_torque = limits.max_torque;
if (limits.dynamic_max_torque) {
const float fudged_speed = (vehicle_speed.min / VEHICLE_SPEED_FACTOR) - 1.;
max_torque = interpolate(limits.max_torque_lookup, fudged_speed) + 1;
max_torque = CLAMP(max_torque, -limits.max_torque, limits.max_torque);
}
// *** global torque limit check ***
violation |= max_limit_check(desired_torque, limits.max_steer, -limits.max_steer);
violation |= max_limit_check(desired_torque, max_torque, -max_torque);
// *** torque rate limit check ***
if (limits.type == TorqueDriverLimited) {
violation |= driver_limit_check(desired_torque, desired_torque_last, &torque_driver,
limits.max_steer, limits.max_rate_up, limits.max_rate_down,
max_torque, limits.max_rate_up, limits.max_rate_down,
limits.driver_torque_allowance, limits.driver_torque_multiplier);
} else {
violation |= dist_to_meas_check(desired_torque, desired_torque_last, &torque_meas,
@@ -662,7 +674,7 @@ bool steer_torque_cmd_checks(int desired_torque, int steer_req, const TorqueStee
// every RT_INTERVAL set the new limits
uint32_t ts_elapsed = get_ts_elapsed(ts, ts_torque_check_last);
if (ts_elapsed > limits.max_rt_interval) {
if (ts_elapsed > MAX_TORQUE_RT_INTERVAL) {
rt_torque_last = desired_torque;
ts_torque_check_last = ts;
}
@@ -104,9 +104,8 @@ static void chrysler_rx_hook(const CANPacket_t *to_push) {
static bool chrysler_tx_hook(const CANPacket_t *to_send) {
const TorqueSteeringLimits CHRYSLER_STEERING_LIMITS = {
.max_steer = 261,
.max_torque = 261,
.max_rt_delta = 112,
.max_rt_interval = 250000,
.max_rate_up = 3,
.max_rate_down = 3,
.max_torque_error = 80,
@@ -114,9 +113,8 @@ static bool chrysler_tx_hook(const CANPacket_t *to_send) {
};
const TorqueSteeringLimits CHRYSLER_RAM_DT_STEERING_LIMITS = {
.max_steer = 350,
.max_torque = 350,
.max_rt_delta = 112,
.max_rt_interval = 250000,
.max_rate_up = 6,
.max_rate_down = 6,
.max_torque_error = 80,
@@ -124,9 +122,8 @@ static bool chrysler_tx_hook(const CANPacket_t *to_send) {
};
const TorqueSteeringLimits CHRYSLER_RAM_HD_STEERING_LIMITS = {
.max_steer = 361,
.max_torque = 361,
.max_rt_delta = 182,
.max_rt_interval = 250000,
.max_rate_up = 14,
.max_rate_down = 14,
.max_torque_error = 80,
@@ -69,7 +69,6 @@ static uint32_t ford_compute_checksum(const CANPacket_t *to_push) {
chksum = 0xFFU - chksum;
} else {
}
return chksum;
}
@@ -154,6 +153,7 @@ static void ford_rx_hook(const CANPacket_t *to_push) {
// Signal: Veh_V_ActlEng
float filtered_pcm_speed = ((GET_BYTE(to_push, 6) << 8) | GET_BYTE(to_push, 7)) * 0.01 / 3.6;
bool is_invalid_speed = ABS(filtered_pcm_speed - ((float)vehicle_speed.values[0] / VEHICLE_SPEED_FACTOR)) > FORD_MAX_SPEED_DELTA;
// TODO: this should generically cause rx valid to fall until re-enable
if (is_invalid_speed) {
controls_allowed = false;
}
+12 -9
View File
@@ -98,13 +98,12 @@ static void gm_rx_hook(const CANPacket_t *to_push) {
static bool gm_tx_hook(const CANPacket_t *to_send) {
const TorqueSteeringLimits GM_STEERING_LIMITS = {
.max_steer = 300,
.max_torque = 300,
.max_rate_up = 10,
.max_rate_down = 15,
.driver_torque_allowance = 65,
.driver_torque_multiplier = 4,
.max_rt_delta = 128,
.max_rt_interval = 250000,
.type = TorqueDriverLimited,
};
@@ -135,7 +134,8 @@ static bool gm_tx_hook(const CANPacket_t *to_send) {
// GAS/REGEN: safety check
if (addr == 0x2CB) {
bool apply = GET_BIT(to_send, 0U);
int gas_regen = ((GET_BYTE(to_send, 2) & 0x7FU) << 5) + ((GET_BYTE(to_send, 3) & 0xF8U) >> 3);
// convert float CAN signal to an int for gas checks: 22534 / 0.125 = 180272
int gas_regen = (((GET_BYTE(to_send, 1) & 0x7U) << 16) | (GET_BYTE(to_send, 2) << 8) | GET_BYTE(to_send, 3)) - 180272U;
bool violation = false;
// Allow apply bit in pre-enabled and overriding states
@@ -189,10 +189,13 @@ static safety_config gm_init(uint16_t param) {
const uint16_t GM_PARAM_HW_CAM = 1;
const uint16_t GM_PARAM_EV = 4;
// common safety checks assume unscaled integer values
static const int GM_GAS_TO_CAN = 8; // 1 / 0.125
static const LongitudinalLimits GM_ASCM_LONG_LIMITS = {
.max_gas = 3072,
.min_gas = 1404,
.inactive_gas = 1404,
.max_gas = 1018 * GM_GAS_TO_CAN,
.min_gas = -650 * GM_GAS_TO_CAN,
.inactive_gas = -650 * GM_GAS_TO_CAN,
.max_brake = 400,
};
@@ -202,9 +205,9 @@ static safety_config gm_init(uint16_t param) {
static const LongitudinalLimits GM_CAM_LONG_LIMITS = {
.max_gas = 3400,
.min_gas = 1514,
.inactive_gas = 1554,
.max_gas = 1346 * GM_GAS_TO_CAN,
.min_gas = -540 * GM_GAS_TO_CAN,
.inactive_gas = -500 * GM_GAS_TO_CAN,
.max_brake = 400,
};
@@ -4,11 +4,10 @@
#include "safety_hyundai_common.h"
#define HYUNDAI_LIMITS(steer, rate_up, rate_down) { \
.max_steer = (steer), \
.max_torque = (steer), \
.max_rate_up = (rate_up), \
.max_rate_down = (rate_down), \
.max_rt_delta = 112, \
.max_rt_interval = 250000, \
.driver_torque_allowance = 50, \
.driver_torque_multiplier = 2, \
.type = TorqueDriverLimited, \
@@ -139,9 +139,8 @@ static void hyundai_canfd_rx_hook(const CANPacket_t *to_push) {
static bool hyundai_canfd_tx_hook(const CANPacket_t *to_send) {
const TorqueSteeringLimits HYUNDAI_CANFD_STEERING_LIMITS = {
.max_steer = 270,
.max_torque = 270,
.max_rt_delta = 112,
.max_rt_interval = 250000,
.max_rate_up = 2,
.max_rate_down = 3,
.driver_torque_allowance = 250,
@@ -50,11 +50,10 @@ static void mazda_rx_hook(const CANPacket_t *to_push) {
static bool mazda_tx_hook(const CANPacket_t *to_send) {
const TorqueSteeringLimits MAZDA_STEERING_LIMITS = {
.max_steer = 800,
.max_torque = 800,
.max_rate_up = 10,
.max_rate_down = 25,
.max_rt_delta = 300,
.max_rt_interval = 250000,
.driver_torque_multiplier = 1,
.driver_torque_allowance = 15,
.type = TorqueDriverLimited,
@@ -2,8 +2,78 @@
#include "safety_declarations.h"
#define RIVIAN_MAX_SPEED_DELTA 2.0 // m/s
static bool rivian_longitudinal = false;
static uint8_t rivian_get_counter(const CANPacket_t *to_push) {
int addr = GET_ADDR(to_push);
uint8_t cnt = 0;
if ((addr == 0x208) || (addr == 0x150)) {
// Signal: ESP_Status_Counter, VDM_PropStatus_Counter
cnt = GET_BYTE(to_push, 1) & 0xFU;
} else {
}
return cnt;
}
static uint32_t rivian_get_checksum(const CANPacket_t *to_push) {
int addr = GET_ADDR(to_push);
uint8_t chksum = 0;
if ((addr == 0x208) || (addr == 0x150)) {
// Signal: ESP_Status_Checksum, VDM_PropStatus_Checksum
chksum = GET_BYTE(to_push, 0);
} else {
}
return chksum;
}
static uint8_t _rivian_compute_checksum(const CANPacket_t *to_push, uint8_t poly, uint8_t xor_output) {
int len = GET_LEN(to_push);
uint8_t crc = 0;
// Skip the checksum byte
for (int i = 1; i < len; i++) {
crc ^= GET_BYTE(to_push, i);
for (int j = 0; j < 8; j++) {
if ((crc & 0x80U) != 0U) {
crc = (crc << 1) ^ poly;
} else {
crc <<= 1;
}
}
}
return crc ^ xor_output;
}
static uint32_t rivian_compute_checksum(const CANPacket_t *to_push) {
int addr = GET_ADDR(to_push);
uint8_t chksum = 0;
if (addr == 0x208) {
chksum = _rivian_compute_checksum(to_push, 0x1D, 0xB1);
} else if (addr == 0x150) {
chksum = _rivian_compute_checksum(to_push, 0x1D, 0x9A);
} else {
}
return chksum;
}
static bool rivian_get_quality_flag_valid(const CANPacket_t *to_push) {
int addr = GET_ADDR(to_push);
bool valid = false;
if (addr == 0x208) {
valid = ((GET_BYTE(to_push, 3) >> 3) & 0x3U) == 0x1U; // ESP_Vehicle_Speed_Q
} else if (addr == 0x150) {
valid = (GET_BYTE(to_push, 1) >> 6) == 0x1U; // VDM_VehicleSpeedQ
} else {
}
return valid;
}
static void rivian_rx_hook(const CANPacket_t *to_push) {
int bus = GET_BUS(to_push);
int addr = GET_ADDR(to_push);
@@ -11,7 +81,22 @@ static void rivian_rx_hook(const CANPacket_t *to_push) {
if (bus == 0) {
// Vehicle speed
if (addr == 0x208) {
vehicle_moving = GET_BYTE(to_push, 6) | GET_BYTE(to_push, 7);
float speed = ((GET_BYTE(to_push, 6) << 8) | GET_BYTE(to_push, 7)) * 0.01;
vehicle_moving = speed > 0.0;
UPDATE_VEHICLE_SPEED(speed / 3.6);
}
// Gas pressed and second speed source for variable torque limit
if (addr == 0x150) {
gas_pressed = GET_BYTE(to_push, 3) | (GET_BYTE(to_push, 4) & 0xC0U);
// Disable controls if speeds from VDM and ESP ECUs are too far apart.
float vdm_speed = ((GET_BYTE(to_push, 5) << 8) | GET_BYTE(to_push, 6)) * 0.01 / 3.6;
bool is_invalid_speed = ABS(vdm_speed - ((float)vehicle_speed.values[0] / VEHICLE_SPEED_FACTOR)) > RIVIAN_MAX_SPEED_DELTA;
// TODO: this should generically cause rx valid to fall until re-enable
if (is_invalid_speed) {
controls_allowed = false;
}
}
// Driver torque
@@ -20,11 +105,6 @@ static void rivian_rx_hook(const CANPacket_t *to_push) {
update_sample(&torque_driver, torque_driver_new);
}
// Gas pressed
if (addr == 0x150) {
gas_pressed = GET_BYTE(to_push, 3) | (GET_BYTE(to_push, 4) & 0xC0U);
}
// Brake pressed
if (addr == 0x38f) {
brake_pressed = GET_BIT(to_push, 23U);
@@ -41,12 +121,17 @@ static void rivian_rx_hook(const CANPacket_t *to_push) {
}
static bool rivian_tx_hook(const CANPacket_t *to_send) {
// Rivian utilizes more torque at low speed to maintain the same lateral accel
const TorqueSteeringLimits RIVIAN_STEERING_LIMITS = {
.max_steer = 250,
.max_torque = 350,
.dynamic_max_torque = true,
.max_torque_lookup = {
{9., 17., 17.},
{350, 250, 250},
},
.max_rate_up = 3,
.max_rate_down = 5,
.max_rt_delta = 125,
.max_rt_interval = 250000,
.driver_torque_multiplier = 2,
.driver_torque_allowance = 100,
.type = TorqueDriverLimited,
@@ -125,9 +210,9 @@ static safety_config rivian_init(uint16_t param) {
static const CanMsg RIVIAN_LONG_TX_MSGS[] = {{0x120, 0, 8, true}, {0x321, 2, 7, false}, {0x160, 0, 5, true}};
static RxCheck rivian_rx_checks[] = {
{.msg = {{0x208, 0, 8, .frequency = 50U, .ignore_checksum = true, .ignore_counter = true}, { 0 }, { 0 }}}, // ESP_Status (speed)
{.msg = {{0x208, 0, 8, .frequency = 50U, .max_counter = 14U, .quality_flag = true}, { 0 }, { 0 }}}, // ESP_Status (speed)
{.msg = {{0x150, 0, 7, .frequency = 50U, .max_counter = 14U, .quality_flag = true}, { 0 }, { 0 }}}, // VDM_PropStatus (gas pedal & 2nd speed)
{.msg = {{0x380, 0, 5, .frequency = 100U, .ignore_checksum = true, .ignore_counter = true}, { 0 }, { 0 }}}, // EPAS_SystemStatus (driver torque)
{.msg = {{0x150, 0, 7, .frequency = 50U, .ignore_checksum = true, .ignore_counter = true}, { 0 }, { 0 }}}, // VDM_PropStatus (gas pedal)
{.msg = {{0x38f, 0, 6, .frequency = 50U, .ignore_checksum = true, .ignore_counter = true}, { 0 }, { 0 }}}, // iBESP2 (brakes)
{.msg = {{0x100, 2, 8, .frequency = 100U, .ignore_checksum = true, .ignore_counter = true}, { 0 }, { 0 }}}, // ACM_Status (cruise state)
};
@@ -150,4 +235,8 @@ const safety_hooks rivian_hooks = {
.rx = rivian_rx_hook,
.tx = rivian_tx_hook,
.fwd = rivian_fwd_hook,
.get_counter = rivian_get_counter,
.get_checksum = rivian_get_checksum,
.compute_checksum = rivian_compute_checksum,
.get_quality_flag_valid = rivian_get_quality_flag_valid,
};
@@ -4,9 +4,8 @@
#define SUBARU_STEERING_LIMITS_GENERATOR(steer_max, rate_up, rate_down) \
{ \
.max_steer = (steer_max), \
.max_torque = (steer_max), \
.max_rt_delta = 940, \
.max_rt_interval = 250000, \
.max_rate_up = (rate_up), \
.max_rate_down = (rate_down), \
.driver_torque_multiplier = 50, \
@@ -55,9 +55,8 @@ static void subaru_preglobal_rx_hook(const CANPacket_t *to_push) {
static bool subaru_preglobal_tx_hook(const CANPacket_t *to_send) {
const TorqueSteeringLimits SUBARU_PG_STEERING_LIMITS = {
.max_steer = 2047,
.max_torque = 2047,
.max_rt_delta = 940,
.max_rt_interval = 250000,
.max_rate_up = 50,
.max_rate_down = 70,
.driver_torque_multiplier = 10,
@@ -155,19 +155,18 @@ static void toyota_rx_hook(const CANPacket_t *to_push) {
static bool toyota_tx_hook(const CANPacket_t *to_send) {
const TorqueSteeringLimits TOYOTA_TORQUE_STEERING_LIMITS = {
.max_steer = 1500,
.max_torque = 1500,
.max_rate_up = 15, // ramp up slow
.max_rate_down = 25, // ramp down fast
.max_torque_error = 350, // max torque cmd in excess of motor torque
.max_rt_delta = 450, // the real time limit is 1800/sec, a 20% buffer
.max_rt_interval = 250000,
.type = TorqueMotorLimited,
// the EPS faults when the steering angle rate is above a certain threshold for too long. to prevent this,
// we allow setting STEER_REQUEST bit to 0 while maintaining the requested torque value for a single frame
.min_valid_request_frames = 18,
.max_invalid_request_frames = 1,
.min_valid_request_rt_interval = 170000, // 170ms; a ~10% buffer on cutting every 19 frames
.min_valid_request_rt_interval = 171000, // 171ms; a ~10% buffer on cutting every 19 frames
.has_steer_req_tolerance = true,
};
@@ -17,13 +17,26 @@ bool volkswagen_resume_button_prev = false;
#define MSG_LH_EPS_03 0x09F // RX from EPS, for driver steering torque
#define MSG_ESP_19 0x0B2 // RX from ABS, for wheel speeds
#define MSG_ESC_51 0x0FC // RX, for wheel speeds
#define MSG_ESC_50 0x102 // RX, for yaw rate
#define MSG_ESP_05 0x106 // RX from ABS, for brake switch state
#define MSG_Motor_51 0x10B // RX for TSK state
#define MSG_TSK_06 0x120 // RX from ECU, for ACC status from drivetrain coordinator
#define MSG_MOTOR_20 0x121 // RX from ECU, for driver throttle input
#define MSG_ACC_06 0x122 // TX by OP, ACC control instructions to the drivetrain coordinator
#define MSG_HCA_01 0x126 // TX by OP, Heading Control Assist steering torque
#define MSG_GRA_ACC_01 0x12B // TX by OP, ACC control buttons for cancel/resume
#define MSG_ACC_07 0x12E // TX by OP, ACC control instructions to the drivetrain coordinator
#define MSG_VMM_02 0x139 // RX, for ESP hold management
#define MSG_QFK_01 0x13D // RX, for steering angle
#define MSG_Motor_54 0x14C // RX, for accel pedal
#define MSG_ACC_18 0x14D // RX from ECU, for ACC status
#define MSG_EA_01 0x1A4 // TX, for EA mitigation
#define MSG_EA_02 0x1F0 // TX, for EA mitigation
#define MSG_EML_06 0x20A // RX, for yaw rate
#define MSG_TA_01 0x26B // TX for Travel Assist status
#define MSG_MEB_ACC_01 0x300 // RX from ECU, for ACC status
#define MSG_HCA_03 0x303 // TX by OP, Heading Control Assist steering torque
#define MSG_ACC_02 0x30C // TX by OP, ACC HUD data to the instrument cluster
#define MSG_LDW_02 0x397 // TX by OP, Lane line recognition and text alerts
#define MSG_MOTOR_14 0x3BE // RX from ECU, for brake switch status
@@ -56,12 +69,22 @@ static uint32_t volkswagen_mqb_meb_compute_crc(const CANPacket_t *to_push) {
crc ^= (uint8_t[]){0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5,0xF5}[counter];
} else if (addr == MSG_ESP_05) {
crc ^= (uint8_t[]){0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07,0x07}[counter];
} else if (addr == MSG_QFK_01) {
crc ^= (uint8_t[]){0x20,0xCA,0x68,0xD5,0x1B,0x31,0xE2,0xDA,0x08,0x0A,0xD4,0xDE,0x9C,0xE4,0x35,0x5B}[counter];
} else if (addr == MSG_TSK_06) {
crc ^= (uint8_t[]){0xC4,0xE2,0x4F,0xE4,0xF8,0x2F,0x56,0x81,0x9F,0xE5,0x83,0x44,0x05,0x3F,0x97,0xDF}[counter];
} else if (addr == MSG_MOTOR_20) {
crc ^= (uint8_t[]){0xE9,0x65,0xAE,0x6B,0x7B,0x35,0xE5,0x5F,0x4E,0xC7,0x86,0xA2,0xBB,0xDD,0xEB,0xB4}[counter];
} else if (addr == MSG_GRA_ACC_01) {
crc ^= (uint8_t[]){0x6A,0x38,0xB4,0x27,0x22,0xEF,0xE1,0xBB,0xF8,0x80,0x84,0x49,0xC7,0x9E,0x1E,0x2B}[counter];
} else if (addr == MSG_ESC_51) {
crc ^= (uint8_t[]){0x77,0x5C,0xA0,0x89,0x4B,0x7C,0xBB,0xD6,0x1F,0x6C,0x4F,0xF6,0x20,0x2B,0x43,0xDD}[counter];
} else if (addr == MSG_Motor_54) {
crc ^= (uint8_t[]){0x16,0x35,0x59,0x15,0x9A,0x2A,0x97,0xB8,0x0E,0x4E,0x30,0xCC,0xB3,0x07,0x01,0xAD}[counter];
} else if (addr == MSG_Motor_51) {
crc ^= (uint8_t[]){0x77,0x5C,0xA0,0x89,0x4B,0x7C,0xBB,0xD6,0x1F,0x6C,0x4F,0xF6,0x20,0x2B,0x43,0xDD}[counter];
} else if (addr == MSG_MOTOR_14) {
crc ^= (uint8_t[]){0x1F,0x28,0xC6,0x85,0xE6,0xF8,0xB0,0x19,0x5B,0x64,0x35,0x21,0xE4,0xF7,0x9C,0x24}[counter];
} else {
// Undefined CAN message, CRC check expected to fail
}
@@ -127,9 +127,8 @@ static void volkswagen_mqb_rx_hook(const CANPacket_t *to_push) {
static bool volkswagen_mqb_tx_hook(const CANPacket_t *to_send) {
// lateral limits
const TorqueSteeringLimits VOLKSWAGEN_MQB_STEERING_LIMITS = {
.max_steer = 300, // 3.0 Nm (EPS side max of 3.0Nm with fault if violated)
.max_torque = 300, // 3.0 Nm (EPS side max of 3.0Nm with fault if violated)
.max_rt_delta = 75, // 4 max rate up * 50Hz send rate * 250000 RT interval / 1000000 = 50 ; 50 * 1.5 for safety pad = 75
.max_rt_interval = 250000, // 250ms between real time checks
.max_rate_up = 4, // 2.0 Nm/s RoC limit (EPS rack has own soft-limit of 5.0 Nm/s)
.max_rate_down = 10, // 5.0 Nm/s RoC limit (EPS rack has own soft-limit of 5.0 Nm/s)
.driver_torque_allowance = 80,
@@ -154,9 +154,8 @@ static void volkswagen_pq_rx_hook(const CANPacket_t *to_push) {
static bool volkswagen_pq_tx_hook(const CANPacket_t *to_send) {
// lateral limits
const TorqueSteeringLimits VOLKSWAGEN_PQ_STEERING_LIMITS = {
.max_steer = 300, // 3.0 Nm (EPS side max of 3.0Nm with fault if violated)
.max_torque = 300, // 3.0 Nm (EPS side max of 3.0Nm with fault if violated)
.max_rt_delta = 113, // 6 max rate up * 50Hz send rate * 250000 RT interval / 1000000 = 75 ; 125 * 1.5 for safety pad = 113
.max_rt_interval = 250000, // 250ms between real time checks
.max_rate_up = 6, // 3.0 Nm/s RoC limit (EPS rack has own soft-limit of 5.0 Nm/s)
.max_rate_down = 10, // 5.0 Nm/s RoC limit (EPS rack has own soft-limit of 5.0 Nm/s)
.driver_torque_multiplier = 3,
@@ -33,6 +33,7 @@ extern const int MAX_WRONG_COUNTERS;
#define MAX_SAMPLE_VALS 6
// used to represent floating point vehicle speed in a sample_t
#define VEHICLE_SPEED_FACTOR 1000.0
#define MAX_TORQUE_RT_INTERVAL 250000U
// sample struct that keeps 6 samples in memory
@@ -62,11 +63,13 @@ typedef enum {
typedef struct {
// torque cmd limits
const int max_steer;
const int max_torque; // this upper limit is always enforced
const bool dynamic_max_torque; // use max_torque_lookup to apply torque limit based on speed
const struct lookup_t max_torque_lookup;
const int max_rate_up;
const int max_rate_down;
const int max_rt_delta;
const uint32_t max_rt_interval;
const int max_rt_delta; // max change in torque per 250ms interval (MAX_TORQUE_RT_INTERVAL)
const SteeringControlType type;
@@ -293,3 +296,4 @@ extern const safety_hooks toyota_hooks;
extern const safety_hooks volkswagen_mqb_hooks;
extern const safety_hooks volkswagen_pq_hooks;
extern const safety_hooks rivian_hooks;
extern const safety_hooks volkswagen_meb_hooks;
+130 -73
View File
@@ -166,6 +166,7 @@ class LongitudinalGasBrakeSafetyTest(PandaSafetyTestBase, abc.ABC):
MIN_GAS: int = 0
MAX_GAS: int | None = None
INACTIVE_GAS = 0
MIN_POSSIBLE_GAS: int = 0.
MAX_POSSIBLE_GAS: int | None = None
def test_gas_brake_limits_correct(self):
@@ -187,16 +188,17 @@ class LongitudinalGasBrakeSafetyTest(PandaSafetyTestBase, abc.ABC):
self._generic_limit_safety_check(self._send_brake_msg, self.MIN_BRAKE, self.MAX_BRAKE, 0, self.MAX_POSSIBLE_BRAKE, 1)
def test_gas_safety_check(self):
self._generic_limit_safety_check(self._send_gas_msg, self.MIN_GAS, self.MAX_GAS, 0, self.MAX_POSSIBLE_GAS, 1, self.INACTIVE_GAS)
self._generic_limit_safety_check(self._send_gas_msg, self.MIN_GAS, self.MAX_GAS, self.MIN_POSSIBLE_GAS, self.MAX_POSSIBLE_GAS, 1, self.INACTIVE_GAS)
class TorqueSteeringSafetyTestBase(PandaSafetyTestBase, abc.ABC):
MAX_RATE_UP = 0
MAX_RATE_DOWN = 0
MAX_TORQUE = 0
MAX_TORQUE_LOOKUP: tuple[list[float], list[int]] = ([0], [0])
DYNAMIC_MAX_TORQUE = False
MAX_RT_DELTA = 0
RT_INTERVAL = 0
RT_INTERVAL = 250000
NO_STEER_REQ_BIT = False
@@ -206,23 +208,53 @@ class TorqueSteeringSafetyTestBase(PandaSafetyTestBase, abc.ABC):
cls.safety = None
raise unittest.SkipTest
@property
def MAX_TORQUE(self):
return max(self.MAX_TORQUE_LOOKUP[1])
@property
def _torque_speed_range(self):
if not self.DYNAMIC_MAX_TORQUE:
return [0]
else:
# test with more precision inside breakpoint range
min_speed = min(self.MAX_TORQUE_LOOKUP[0])
max_speed = max(self.MAX_TORQUE_LOOKUP[0])
return np.concatenate([np.arange(0, min_speed, 5), np.arange(min_speed, max_speed, 0.5), np.arange(max_speed, 40, 5)])
def _get_max_torque(self, speed):
# matches safety fudge
torque = int(np.interp(speed - 1, self.MAX_TORQUE_LOOKUP[0], self.MAX_TORQUE_LOOKUP[1]) + 1)
return min(torque, self.MAX_TORQUE)
@abc.abstractmethod
def _torque_cmd_msg(self, torque, steer_req=1):
pass
@abc.abstractmethod
def _speed_msg(self, speed):
pass
def _reset_speed_measurement(self, speed):
for _ in range(MAX_SAMPLE_VALS):
self._rx(self._speed_msg(speed))
def _set_prev_torque(self, t):
self.safety.set_desired_torque_last(t)
self.safety.set_rt_torque_last(t)
def test_steer_safety_check(self):
for enabled in [0, 1]:
for t in range(int(-self.MAX_TORQUE * 1.5), int(self.MAX_TORQUE * 1.5)):
self.safety.set_controls_allowed(enabled)
self._set_prev_torque(t)
if abs(t) > self.MAX_TORQUE or (not enabled and abs(t) > 0):
self.assertFalse(self._tx(self._torque_cmd_msg(t)))
else:
self.assertTrue(self._tx(self._torque_cmd_msg(t)))
for speed in self._torque_speed_range:
self._reset_speed_measurement(speed)
max_torque = self._get_max_torque(speed)
for enabled in [0, 1]:
for t in range(int(-max_torque * 1.5), int(max_torque * 1.5)):
self.safety.set_controls_allowed(enabled)
self._set_prev_torque(t)
if abs(t) > max_torque or (not enabled and abs(t) > 0):
self.assertFalse(self._tx(self._torque_cmd_msg(t)))
else:
self.assertTrue(self._tx(self._torque_cmd_msg(t)))
def test_non_realtime_limit_up(self):
self.safety.set_controls_allowed(True)
@@ -266,7 +298,12 @@ class SteerRequestCutSafetyTest(TorqueSteeringSafetyTestBase, abc.ABC):
# Safety around steering request bit mismatch tolerance
MIN_VALID_STEERING_FRAMES: int
MAX_INVALID_STEERING_FRAMES: int
MIN_VALID_STEERING_RT_INTERVAL: int
STEER_STEP: int = 1
@property
def MIN_VALID_STEERING_RT_INTERVAL(self):
# a ~10% buffer
return int((self.MIN_VALID_STEERING_FRAMES + 1) * self.STEER_STEP * 10000 * 0.9)
def test_steer_req_bit_frames(self):
"""
@@ -389,40 +426,44 @@ class DriverTorqueSteeringSafetyTest(TorqueSteeringSafetyTestBase, abc.ABC):
# Tests down limits and driver torque blending
self.safety.set_controls_allowed(True)
# Cannot stay at MAX_TORQUE if above DRIVER_TORQUE_ALLOWANCE
for sign in [-1, 1]:
for driver_torque in np.arange(0, self.DRIVER_TORQUE_ALLOWANCE * 2, 1):
self._reset_torque_driver_measurement(-driver_torque * sign)
self._set_prev_torque(self.MAX_TORQUE * sign)
should_tx = abs(driver_torque) <= self.DRIVER_TORQUE_ALLOWANCE
self.assertEqual(should_tx, self._tx(self._torque_cmd_msg(self.MAX_TORQUE * sign)))
for speed in self._torque_speed_range:
self._reset_speed_measurement(speed)
max_torque = self._get_max_torque(speed)
# arbitrary high driver torque to ensure max steer torque is allowed
max_driver_torque = int(self.MAX_TORQUE / self.DRIVER_TORQUE_FACTOR + self.DRIVER_TORQUE_ALLOWANCE + 1)
# Cannot stay at MAX_TORQUE if above DRIVER_TORQUE_ALLOWANCE
for sign in [-1, 1]:
for driver_torque in np.arange(0, self.DRIVER_TORQUE_ALLOWANCE * 2, 1):
self._reset_torque_driver_measurement(-driver_torque * sign)
self._set_prev_torque(max_torque * sign)
should_tx = abs(driver_torque) <= self.DRIVER_TORQUE_ALLOWANCE
self.assertEqual(should_tx, self._tx(self._torque_cmd_msg(max_torque * sign)))
# spot check some individual cases
for sign in [-1, 1]:
# Ensure we wind down factor units for every unit above allowance
driver_torque = (self.DRIVER_TORQUE_ALLOWANCE + 10) * sign
torque_desired = (self.MAX_TORQUE - 10 * self.DRIVER_TORQUE_FACTOR) * sign
delta = 1 * sign
self._set_prev_torque(torque_desired)
self._reset_torque_driver_measurement(-driver_torque)
self.assertTrue(self._tx(self._torque_cmd_msg(torque_desired)))
self._set_prev_torque(torque_desired + delta)
self._reset_torque_driver_measurement(-driver_torque)
self.assertFalse(self._tx(self._torque_cmd_msg(torque_desired + delta)))
# arbitrary high driver torque to ensure max steer torque is allowed
max_driver_torque = int(max_torque / self.DRIVER_TORQUE_FACTOR + self.DRIVER_TORQUE_ALLOWANCE + 1)
# If we're well past the allowance, minimum wind down is MAX_RATE_DOWN
self._set_prev_torque(self.MAX_TORQUE * sign)
self._reset_torque_driver_measurement(-max_driver_torque * sign)
self.assertTrue(self._tx(self._torque_cmd_msg((self.MAX_TORQUE - self.MAX_RATE_DOWN) * sign)))
self._set_prev_torque(self.MAX_TORQUE * sign)
self._reset_torque_driver_measurement(-max_driver_torque * sign)
self.assertTrue(self._tx(self._torque_cmd_msg(0)))
self._set_prev_torque(self.MAX_TORQUE * sign)
self._reset_torque_driver_measurement(-max_driver_torque * sign)
self.assertFalse(self._tx(self._torque_cmd_msg((self.MAX_TORQUE - self.MAX_RATE_DOWN + 1) * sign)))
# spot check some individual cases
for sign in [-1, 1]:
# Ensure we wind down factor units for every unit above allowance
driver_torque = (self.DRIVER_TORQUE_ALLOWANCE + 10) * sign
torque_desired = (max_torque - 10 * self.DRIVER_TORQUE_FACTOR) * sign
delta = 1 * sign
self._set_prev_torque(torque_desired)
self._reset_torque_driver_measurement(-driver_torque)
self.assertTrue(self._tx(self._torque_cmd_msg(torque_desired)))
self._set_prev_torque(torque_desired + delta)
self._reset_torque_driver_measurement(-driver_torque)
self.assertFalse(self._tx(self._torque_cmd_msg(torque_desired + delta)))
# If we're well past the allowance, minimum wind down is MAX_RATE_DOWN
self._set_prev_torque(max_torque * sign)
self._reset_torque_driver_measurement(-max_driver_torque * sign)
self.assertTrue(self._tx(self._torque_cmd_msg((max_torque - self.MAX_RATE_DOWN) * sign)))
self._set_prev_torque(max_torque * sign)
self._reset_torque_driver_measurement(-max_driver_torque * sign)
self.assertTrue(self._tx(self._torque_cmd_msg(0)))
self._set_prev_torque(max_torque * sign)
self._reset_torque_driver_measurement(-max_driver_torque * sign)
self.assertFalse(self._tx(self._torque_cmd_msg((max_torque - self.MAX_RATE_DOWN + 1) * sign)))
def test_realtime_limits(self):
self.safety.set_controls_allowed(True)
@@ -479,34 +520,41 @@ class MotorTorqueSteeringSafetyTest(TorqueSteeringSafetyTestBase, abc.ABC):
self.safety.set_torque_meas(t, t)
def test_torque_absolute_limits(self):
for controls_allowed in [True, False]:
for torque in np.arange(-self.MAX_TORQUE - 1000, self.MAX_TORQUE + 1000, self.MAX_RATE_UP):
self.safety.set_controls_allowed(controls_allowed)
self.safety.set_rt_torque_last(torque)
self.safety.set_torque_meas(torque, torque)
self.safety.set_desired_torque_last(torque - self.MAX_RATE_UP)
for speed in self._torque_speed_range:
self._reset_speed_measurement(speed)
max_torque = self._get_max_torque(speed)
for controls_allowed in [True, False]:
for torque in np.arange(-max_torque - 1000, max_torque + 1000, self.MAX_RATE_UP):
self.safety.set_controls_allowed(controls_allowed)
self.safety.set_rt_torque_last(torque)
self.safety.set_torque_meas(torque, torque)
self.safety.set_desired_torque_last(torque - self.MAX_RATE_UP)
if controls_allowed:
send = (-self.MAX_TORQUE <= torque <= self.MAX_TORQUE)
else:
send = torque == 0
if controls_allowed:
send = (-max_torque <= torque <= max_torque)
else:
send = torque == 0
self.assertEqual(send, self._tx(self._torque_cmd_msg(torque)))
self.assertEqual(send, self._tx(self._torque_cmd_msg(torque)))
def test_non_realtime_limit_down(self):
self.safety.set_controls_allowed(True)
torque_meas = self.MAX_TORQUE - self.MAX_TORQUE_ERROR - 50
for speed in self._torque_speed_range:
self._reset_speed_measurement(speed)
max_torque = self._get_max_torque(speed)
self.safety.set_rt_torque_last(self.MAX_TORQUE)
self.safety.set_torque_meas(torque_meas, torque_meas)
self.safety.set_desired_torque_last(self.MAX_TORQUE)
self.assertTrue(self._tx(self._torque_cmd_msg(self.MAX_TORQUE - self.MAX_RATE_DOWN)))
torque_meas = max_torque - self.MAX_TORQUE_ERROR - 50
self.safety.set_rt_torque_last(self.MAX_TORQUE)
self.safety.set_torque_meas(torque_meas, torque_meas)
self.safety.set_desired_torque_last(self.MAX_TORQUE)
self.assertFalse(self._tx(self._torque_cmd_msg(self.MAX_TORQUE - self.MAX_RATE_DOWN + 1)))
self.safety.set_rt_torque_last(max_torque)
self.safety.set_torque_meas(torque_meas, torque_meas)
self.safety.set_desired_torque_last(max_torque)
self.assertTrue(self._tx(self._torque_cmd_msg(max_torque - self.MAX_RATE_DOWN)))
self.safety.set_rt_torque_last(max_torque)
self.safety.set_torque_meas(torque_meas, torque_meas)
self.safety.set_desired_torque_last(max_torque)
self.assertFalse(self._tx(self._torque_cmd_msg(max_torque - self.MAX_RATE_DOWN + 1)))
def test_exceed_torque_sensor(self):
self.safety.set_controls_allowed(True)
@@ -577,7 +625,23 @@ class MotorTorqueSteeringSafetyTest(TorqueSteeringSafetyTestBase, abc.ABC):
self.assertEqual(self.safety.get_torque_meas_max(), 0)
class AngleSteeringSafetyTest(PandaSafetyTestBase):
class VehicleSpeedSafetyTest(PandaSafetyTestBase):
@classmethod
def setUpClass(cls):
if cls.__name__ == "VehicleSpeedSafetyTest":
cls.safety = None
raise unittest.SkipTest
@abc.abstractmethod
def _speed_msg(self, speed):
pass
def test_vehicle_speed_measurements(self):
# TODO: lower tolerance on these tests
self._common_measurement_test(self._speed_msg, 0, 80, 1, self.safety.get_vehicle_speed_min, self.safety.get_vehicle_speed_max)
class AngleSteeringSafetyTest(VehicleSpeedSafetyTest):
STEER_ANGLE_MAX: float = 300
DEG_TO_CAN: float
@@ -591,10 +655,6 @@ class AngleSteeringSafetyTest(PandaSafetyTestBase):
cls.safety = None
raise unittest.SkipTest
@abc.abstractmethod
def _speed_msg(self, speed):
pass
@abc.abstractmethod
def _angle_cmd_msg(self, angle: float, enabled: bool):
pass
@@ -615,10 +675,6 @@ class AngleSteeringSafetyTest(PandaSafetyTestBase):
for _ in range(MAX_SAMPLE_VALS):
self._rx(self._speed_msg(speed))
def test_vehicle_speed_measurements(self):
# TODO: lower tolerance on these tests
self._common_measurement_test(self._speed_msg, 0, 80, 1, self.safety.get_vehicle_speed_min, self.safety.get_vehicle_speed_max)
def test_steering_angle_measurements(self):
self._common_measurement_test(self._angle_meas_msg, -self.STEER_ANGLE_MAX, self.STEER_ANGLE_MAX, self.DEG_TO_CAN,
self.safety.get_angle_meas_min, self.safety.get_angle_meas_max)
@@ -776,7 +832,8 @@ class PandaSafetyTest(PandaSafetyTestBase):
continue
if {attr, current_test}.issubset({'TestHyundaiLongitudinalSafety', 'TestHyundaiLongitudinalSafetyCameraSCC', 'TestHyundaiSafetyFCEVLong'}):
continue
if {attr, current_test}.issubset({'TestVolkswagenMqbSafety', 'TestVolkswagenMqbStockSafety', 'TestVolkswagenMqbLongSafety'}):
if {attr, current_test}.issubset({'TestVolkswagenMqbSafety', 'TestVolkswagenMqbStockSafety', 'TestVolkswagenMqbLongSafety',
'TestVolkswagenMebSafety', 'TestVolkswagenMebStockSafety',}):
continue
# overlapping TX addrs, but they're not actuating messages for either car
@@ -18,7 +18,7 @@ def is_steering_msg(mode, param, addr):
ret = addr == (0x191 if param & ToyotaSafetyFlags.LTA else 0x2E4)
elif mode == CarParams.SafetyModel.gm:
ret = addr == 384
elif mode == CarParams.SafetyModel.hyundai:
elif mode in (CarParams.SafetyModel.hyundai, CarParams.SafetyModel.hyundaiLegacy):
ret = addr == 832
elif mode == CarParams.SafetyModel.hyundaiCanfd:
ret = addr == (0x110 if param & HyundaiSafetyFlags.CANFD_LKA_STEERING_ALT else
@@ -52,7 +52,7 @@ def get_steer_value(mode, param, to_send):
elif mode == CarParams.SafetyModel.gm:
torque = ((to_send.data[0] & 0x7) << 8) | to_send.data[1]
torque = to_signed(torque, 11)
elif mode == CarParams.SafetyModel.hyundai:
elif mode in (CarParams.SafetyModel.hyundai, CarParams.SafetyModel.hyundaiLegacy):
torque = (((to_send.data[3] & 0x7) << 8) | to_send.data[2]) - 1024
elif mode == CarParams.SafetyModel.hyundaiCanfd:
torque = ((to_send.data[5] >> 1) | (to_send.data[6] & 0xF) << 7) - 1024
@@ -15,9 +15,8 @@ class TestChryslerSafety(common.PandaCarSafetyTest, common.MotorTorqueSteeringSa
MAX_RATE_UP = 3
MAX_RATE_DOWN = 3
MAX_TORQUE = 261
MAX_TORQUE_LOOKUP = [0], [261]
MAX_RT_DELTA = 112
RT_INTERVAL = 250000
MAX_TORQUE_ERROR = 80
LKAS_ACTIVE_VALUE = 1
@@ -80,7 +79,7 @@ class TestChryslerRamDTSafety(TestChryslerSafety):
MAX_RATE_UP = 6
MAX_RATE_DOWN = 6
MAX_TORQUE = 350
MAX_TORQUE_LOOKUP = [0], [350]
DAS_BUS = 2
@@ -101,7 +100,7 @@ class TestChryslerRamHDSafety(TestChryslerSafety):
RELAY_MALFUNCTION_ADDRS = {0: (0x276,)}
FWD_BLACKLISTED_ADDRS = {2: [0x275, 0x276]}
MAX_TORQUE = 361
MAX_TORQUE_LOOKUP = [0], [361]
MAX_RATE_UP = 14
MAX_RATE_DOWN = 14
MAX_RT_DELTA = 182
+9 -9
View File
@@ -23,7 +23,8 @@ class GmLongitudinalBase(common.PandaCarSafetyTest, common.LongitudinalGasBrakeS
MAX_POSSIBLE_BRAKE = 2 ** 12
MAX_BRAKE = 400
MAX_POSSIBLE_GAS = 2 ** 12
MAX_POSSIBLE_GAS = 4000 # reasonably excessive limits, not signal max
MIN_POSSIBLE_GAS = -4000
PCM_CRUISE = False # openpilot can control the PCM state if longitudinal
@@ -80,9 +81,8 @@ class TestGmSafetyBase(common.PandaCarSafetyTest, common.DriverTorqueSteeringSaf
MAX_RATE_UP = 10
MAX_RATE_DOWN = 15
MAX_TORQUE = 300
MAX_TORQUE_LOOKUP = [0], [300]
MAX_RT_DELTA = 128
RT_INTERVAL = 250000
DRIVER_TORQUE_ALLOWANCE = 65
DRIVER_TORQUE_FACTOR = 4
@@ -151,9 +151,9 @@ class TestGmAscmSafety(GmLongitudinalBase, TestGmSafetyBase):
FWD_BUS_LOOKUP: dict[int, int] = {}
BRAKE_BUS = 2
MAX_GAS = 3072
MIN_GAS = 1404 # maximum regen
INACTIVE_GAS = 1404
MAX_GAS = 1018
MIN_GAS = -650 # maximum regen
INACTIVE_GAS = -650
def setUp(self):
self.packer = CANPackerPanda("gm_global_a_powertrain_generated")
@@ -211,9 +211,9 @@ class TestGmCameraLongitudinalSafety(GmLongitudinalBase, TestGmCameraSafetyBase)
FWD_BLACKLISTED_ADDRS = {2: [0x180, 0x2CB, 0x370, 0x315], 0: [0x184]} # block LKAS, ACC messages and PSCMStatus
BUTTONS_BUS = 0 # rx only
MAX_GAS = 3400
MIN_GAS = 1514 # maximum regen
INACTIVE_GAS = 1554
MAX_GAS = 1346
MIN_GAS = -540 # maximum regen
INACTIVE_GAS = -500
def setUp(self):
self.packer = CANPackerPanda("gm_global_a_powertrain_generated")
@@ -53,16 +53,14 @@ class TestHyundaiSafety(HyundaiButtonBase, common.PandaCarSafetyTest, common.Dri
MAX_RATE_UP = 3
MAX_RATE_DOWN = 7
MAX_TORQUE = 384
MAX_TORQUE_LOOKUP = [0], [384]
MAX_RT_DELTA = 112
RT_INTERVAL = 250000
DRIVER_TORQUE_ALLOWANCE = 50
DRIVER_TORQUE_FACTOR = 2
# Safety around steering req bit
MIN_VALID_STEERING_FRAMES = 89
MAX_INVALID_STEERING_FRAMES = 2
MIN_VALID_STEERING_RT_INTERVAL = 810000 # a ~10% buffer, can send steer up to 110Hz
cnt_gas = 0
cnt_speed = 0
@@ -117,7 +115,7 @@ class TestHyundaiSafety(HyundaiButtonBase, common.PandaCarSafetyTest, common.Dri
class TestHyundaiSafetyAltLimits(TestHyundaiSafety):
MAX_RATE_UP = 2
MAX_RATE_DOWN = 3
MAX_TORQUE = 270
MAX_TORQUE_LOOKUP = [0], [270]
def setUp(self):
self.packer = CANPackerPanda("hyundai_kia_generic")
@@ -129,7 +127,7 @@ class TestHyundaiSafetyAltLimits(TestHyundaiSafety):
class TestHyundaiSafetyAltLimits2(TestHyundaiSafety):
MAX_RATE_UP = 2
MAX_RATE_DOWN = 3
MAX_TORQUE = 170
MAX_TORQUE_LOOKUP = [0], [170]
def setUp(self):
self.packer = CANPackerPanda("hyundai_kia_generic")
@@ -30,10 +30,9 @@ class TestHyundaiCanfdBase(HyundaiButtonBase, common.PandaCarSafetyTest, common.
MAX_RATE_UP = 2
MAX_RATE_DOWN = 3
MAX_TORQUE = 270
MAX_TORQUE_LOOKUP = [0], [270]
MAX_RT_DELTA = 112
RT_INTERVAL = 250000
DRIVER_TORQUE_ALLOWANCE = 250
DRIVER_TORQUE_FACTOR = 2
@@ -41,7 +40,6 @@ class TestHyundaiCanfdBase(HyundaiButtonBase, common.PandaCarSafetyTest, common.
# Safety around steering req bit
MIN_VALID_STEERING_FRAMES = 89
MAX_INVALID_STEERING_FRAMES = 2
MIN_VALID_STEERING_RT_INTERVAL = 810000 # a ~10% buffer, can send steer up to 110Hz
PT_BUS = 0
SCC_BUS = 2
@@ -16,10 +16,9 @@ class TestMazdaSafety(common.PandaCarSafetyTest, common.DriverTorqueSteeringSafe
MAX_RATE_UP = 10
MAX_RATE_DOWN = 25
MAX_TORQUE = 800
MAX_TORQUE_LOOKUP = [0], [800]
MAX_RT_DELTA = 300
RT_INTERVAL = 250000
DRIVER_TORQUE_ALLOWANCE = 15
DRIVER_TORQUE_FACTOR = 1
@@ -1,29 +1,51 @@
#!/usr/bin/env python3
import unittest
import numpy as np
from opendbc.car.structs import CarParams
from opendbc.safety.tests.libsafety import libsafety_py
import opendbc.safety.tests.common as common
from opendbc.safety.tests.common import CANPackerPanda
from opendbc.car.rivian.values import RivianSafetyFlags
from opendbc.car.rivian.riviancan import checksum as _checksum
class TestRivianSafetyBase(common.PandaCarSafetyTest, common.DriverTorqueSteeringSafetyTest, common.LongitudinalAccelSafetyTest):
def checksum(msg):
addr, dat, bus = msg
ret = bytearray(dat)
# ESP_Status
if addr == 0x208:
ret[0] = _checksum(ret[1:], 0x1D, 0xB1)
elif addr == 0x150:
ret[0] = _checksum(ret[1:], 0x1D, 0x9A)
return addr, ret, bus
class TestRivianSafetyBase(common.PandaCarSafetyTest, common.DriverTorqueSteeringSafetyTest, common.LongitudinalAccelSafetyTest,
common.VehicleSpeedSafetyTest):
TX_MSGS = [[0x120, 0], [0x321, 2], [0x162, 2]]
RELAY_MALFUNCTION_ADDRS = {0: (0x120,)}
FWD_BLACKLISTED_ADDRS = {0: [0x321, 0x162], 2: [0x120]}
MAX_TORQUE = 250
MAX_TORQUE_LOOKUP = [9, 17], [350, 250]
DYNAMIC_MAX_TORQUE = True
MAX_RATE_UP = 3
MAX_RATE_DOWN = 5
MAX_RT_DELTA = 125
RT_INTERVAL = 250000
DRIVER_TORQUE_ALLOWANCE = 100
DRIVER_TORQUE_FACTOR = 2
# Max allowed delta between car speeds
MAX_SPEED_DELTA = 2.0 # m/s
cnt_speed = 0
cnt_speed_2 = 0
def _torque_driver_msg(self, torque):
values = {"EPAS_TorsionBarTorque": torque / 100.0}
return self.packer.make_can_msg_panda("EPAS_SystemStatus", 0, values)
@@ -32,26 +54,29 @@ class TestRivianSafetyBase(common.PandaCarSafetyTest, common.DriverTorqueSteerin
values = {"ACM_lkaStrToqReq": torque, "ACM_lkaActToi": steer_req}
return self.packer.make_can_msg_panda("ACM_lkaHbaCmd", 0, values)
def _speed_msg(self, speed):
values = {"ESP_Status": speed * 3.6}
return self.packer.make_can_msg_panda("ESP_Vehicle_Speed", 0, values)
def _speed_msg(self, speed, quality_flag=True):
values = {"ESP_Vehicle_Speed": speed * 3.6, "ESP_Status_Counter": self.cnt_speed % 15,
"ESP_Vehicle_Speed_Q": 1 if quality_flag else 0}
self.__class__.cnt_speed += 1
return self.packer.make_can_msg_panda("ESP_Status", 0, values, fix_checksum=checksum)
def _speed_msg_2(self, speed, quality_flag=True):
return self._user_gas_msg(0, speed, quality_flag)
def _user_brake_msg(self, brake):
values = {"iBESP2_BrakePedalApplied": brake}
return self.packer.make_can_msg_panda("iBESP2", 0, values)
def _user_gas_msg(self, gas):
values = {"VDM_AcceleratorPedalPosition": gas}
return self.packer.make_can_msg_panda("VDM_PropStatus", 0, values)
def _user_gas_msg(self, gas, speed=0, quality_flag=True):
values = {"VDM_AcceleratorPedalPosition": gas, "VDM_VehicleSpeed": speed * 3.6,
"VDM_PropStatus_Counter": self.cnt_speed_2 % 15, "VDM_VehicleSpeedQ": 1 if quality_flag else 0}
self.__class__.cnt_speed_2 += 1
return self.packer.make_can_msg_panda("VDM_PropStatus", 0, values, fix_checksum=checksum)
def _pcm_status_msg(self, enable):
values = {"ACM_FeatureStatus": enable, "ACM_Unkown1": 1}
return self.packer.make_can_msg_panda("ACM_Status", 2, values)
def _vehicle_moving_msg(self, speed: float):
values = {"ESP_Vehicle_Speed": speed}
return self.packer.make_can_msg_panda("ESP_Status", 0, values)
def _accel_msg(self, accel: float):
values = {"ACM_AccelerationRequest": accel}
return self.packer.make_can_msg_panda("ACM_longitudinalRequest", 0, values)
@@ -67,6 +92,40 @@ class TestRivianSafetyBase(common.PandaCarSafetyTest, common.DriverTorqueSteerin
}
self.assertTrue(self._tx(self.packer.make_can_msg_panda("SCCM_WheelTouch", 2, values)))
def test_rx_hook(self):
# checksum, counter, and quality flag checks
for quality_flag in (True, False):
for msg in ("speed", "speed_2"):
self.safety.set_controls_allowed(True)
# send multiple times to verify counter checks
for _ in range(10):
if msg == "speed":
to_push = self._speed_msg(0, quality_flag=quality_flag)
elif msg == "speed_2":
to_push = self._speed_msg_2(0, quality_flag=quality_flag)
self.assertEqual(quality_flag, self._rx(to_push))
self.assertEqual(quality_flag, self.safety.get_controls_allowed())
# Mess with checksum to make it fail
to_push[0].data[0] = 0xff
self.assertFalse(self._rx(to_push))
self.assertFalse(self.safety.get_controls_allowed())
def test_rx_hook_speed_mismatch(self):
# TODO: this can be a common test w/ Ford
# Rivian has a dynamic max torque limit based on speed, so it checks two sources
for speed in np.arange(0, 40, 0.5):
for speed_delta in np.arange(-5, 5, 0.1):
speed_2 = round(max(speed + speed_delta, 0), 1)
# Set controls allowed in between rx since first message can reset it
self._rx(self._speed_msg(speed))
self.safety.set_controls_allowed(True)
self._rx(self._speed_msg_2(speed_2))
within_delta = abs(speed - speed_2) <= self.MAX_SPEED_DELTA
self.assertEqual(self.safety.get_controls_allowed(), within_delta)
class TestRivianStockSafety(TestRivianSafetyBase):
@@ -60,7 +60,6 @@ class TestSubaruSafetyBase(common.PandaCarSafetyTest):
FWD_BLACKLISTED_ADDRS = fwd_blacklisted_addr()
MAX_RT_DELTA = 940
RT_INTERVAL = 250000
DRIVER_TORQUE_ALLOWANCE = 60
DRIVER_TORQUE_FACTOR = 50
@@ -155,12 +154,12 @@ class TestSubaruLongitudinalSafetyBase(TestSubaruSafetyBase, common.Longitudinal
class TestSubaruTorqueSafetyBase(TestSubaruSafetyBase, common.DriverTorqueSteeringSafetyTest, common.SteerRequestCutSafetyTest):
MAX_RATE_UP = 50
MAX_RATE_DOWN = 70
MAX_TORQUE = 2047
MAX_TORQUE_LOOKUP = [0], [2047]
# Safety around steering req bit
MIN_VALID_STEERING_FRAMES = 7
MAX_INVALID_STEERING_FRAMES = 1
MIN_VALID_STEERING_RT_INTERVAL = 144000
STEER_STEP = 2
def _torque_cmd_msg(self, torque, steer_req=1):
values = {"LKAS_Output": torque, "LKAS_Request": steer_req}
@@ -178,7 +177,7 @@ class TestSubaruGen2TorqueSafetyBase(TestSubaruTorqueSafetyBase):
MAX_RATE_UP = 40
MAX_RATE_DOWN = 40
MAX_TORQUE = 1000
MAX_TORQUE_LOOKUP = [0], [1000]
class TestSubaruGen2TorqueStockLongitudinalSafety(TestSubaruStockLongitudinalSafetyBase, TestSubaruGen2TorqueSafetyBase):
@@ -17,10 +17,9 @@ class TestSubaruPreglobalSafety(common.PandaCarSafetyTest, common.DriverTorqueSt
MAX_RATE_UP = 50
MAX_RATE_DOWN = 70
MAX_TORQUE = 2047
MAX_TORQUE_LOOKUP = [0], [2047]
MAX_RT_DELTA = 940
RT_INTERVAL = 250000
DRIVER_TORQUE_ALLOWANCE = 75
DRIVER_TORQUE_FACTOR = 10
@@ -124,16 +124,14 @@ class TestToyotaSafetyTorque(TestToyotaSafetyBase, common.MotorTorqueSteeringSaf
MAX_RATE_UP = 15
MAX_RATE_DOWN = 25
MAX_TORQUE = 1500
MAX_TORQUE_LOOKUP = [0], [1500]
MAX_RT_DELTA = 450
RT_INTERVAL = 250000
MAX_TORQUE_ERROR = 350
TORQUE_MEAS_TOLERANCE = 1 # toyota safety adds one to be conservative for rounding
# Safety around steering req bit
MIN_VALID_STEERING_FRAMES = 18
MAX_INVALID_STEERING_FRAMES = 1
MIN_VALID_STEERING_RT_INTERVAL = 170000 # a ~10% buffer, can send steer up to 110Hz
def setUp(self):
self.packer = CANPackerPanda("toyota_nodsu_pt_generated")
@@ -28,9 +28,8 @@ class TestVolkswagenMqbSafetyBase(common.PandaCarSafetyTest, common.DriverTorque
MAX_RATE_UP = 4
MAX_RATE_DOWN = 10
MAX_TORQUE = 300
MAX_TORQUE_LOOKUP = [0], [300]
MAX_RT_DELTA = 75
RT_INTERVAL = 250000
DRIVER_TORQUE_ALLOWANCE = 80
DRIVER_TORQUE_FACTOR = 3
@@ -133,7 +132,7 @@ class TestVolkswagenMqbStockSafety(TestVolkswagenMqbSafetyBase):
FWD_BLACKLISTED_ADDRS = {0: [MSG_LH_EPS_03], 2: [MSG_HCA_01, MSG_LDW_02]}
def setUp(self):
self.packer = CANPackerPanda("vw_mqb_2010")
self.packer = CANPackerPanda("vw_mqb")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.volkswagen, 0)
self.safety.init_tests()
@@ -154,7 +153,7 @@ class TestVolkswagenMqbLongSafety(TestVolkswagenMqbSafetyBase):
INACTIVE_ACCEL = 3.01
def setUp(self):
self.packer = CANPackerPanda("vw_mqb_2010")
self.packer = CANPackerPanda("vw_mqb")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.volkswagen, VolkswagenSafetyFlags.LONG_CONTROL)
self.safety.init_tests()
@@ -26,9 +26,8 @@ class TestVolkswagenPqSafetyBase(common.PandaCarSafetyTest, common.DriverTorqueS
MAX_RATE_UP = 6
MAX_RATE_DOWN = 10
MAX_TORQUE = 300
MAX_TORQUE_LOOKUP = [0], [300]
MAX_RT_DELTA = 113
RT_INTERVAL = 250000
DRIVER_TORQUE_ALLOWANCE = 80
DRIVER_TORQUE_FACTOR = 3
@@ -116,7 +115,7 @@ class TestVolkswagenPqStockSafety(TestVolkswagenPqSafetyBase):
FWD_BLACKLISTED_ADDRS = {2: [MSG_HCA_1, MSG_LDW_1]}
def setUp(self):
self.packer = CANPackerPanda("vw_golf_mk4")
self.packer = CANPackerPanda("vw_pq")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.volkswagenPq, 0)
self.safety.init_tests()
@@ -137,7 +136,7 @@ class TestVolkswagenPqLongSafety(TestVolkswagenPqSafetyBase, common.Longitudinal
INACTIVE_ACCEL = 3.01
def setUp(self):
self.packer = CANPackerPanda("vw_golf_mk4")
self.packer = CANPackerPanda("vw_pq")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.volkswagenPq, VolkswagenSafetyFlags.LONG_CONTROL)
self.safety.init_tests()