VW: External Panda support (#2582)

* VW: External Panda support

* no init no work

* tidy up extended CAN pointer

* woops

* consistency

* reassert my right to verbosity

* consistency

* whitespace styling
This commit is contained in:
Jason Young
2025-07-29 01:22:48 -04:00
committed by GitHub
parent 379e8bac0f
commit bfa0891c88
4 changed files with 53 additions and 23 deletions

View File

@@ -4,7 +4,7 @@ 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.values import CANBUS, CarControllerParams, VolkswagenFlags
from opendbc.car.volkswagen.values import CanBus, CarControllerParams, VolkswagenFlags
VisualAlert = structs.CarControl.HUDControl.VisualAlert
LongCtrlState = structs.CarControl.Actuators.LongControlState
@@ -14,9 +14,9 @@ class CarController(CarControllerBase):
def __init__(self, dbc_names, CP):
super().__init__(dbc_names, CP)
self.CCP = CarControllerParams(CP)
self.CAN = CanBus(CP)
self.CCS = pqcan if CP.flags & VolkswagenFlags.PQ else 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.apply_torque_last = 0
@@ -63,7 +63,7 @@ class CarController(CarControllerBase):
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))
can_sends.append(self.CCS.create_steering_control(self.packer_pt, self.CAN.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
@@ -72,7 +72,7 @@ class CarController(CarControllerBase):
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))
can_sends.append(self.CCS.create_eps_update(self.packer_pt, self.CAN.cam, CS.eps_stock_values, ea_simulated_torque))
# **** Acceleration Controls ******************************************** #
@@ -82,7 +82,7 @@ class CarController(CarControllerBase):
accel = float(np.clip(actuators.accel, self.CCP.ACCEL_MIN, self.CCP.ACCEL_MAX) if CC.longActive else 0)
stopping = actuators.longControlState == LongCtrlState.stopping
starting = actuators.longControlState == LongCtrlState.pid and (CS.esp_hold_confirmation or CS.out.vEgo < self.CP.vEgoStopping)
can_sends.extend(self.CCS.create_acc_accel_control(self.packer_pt, CANBUS.pt, CS.acc_type, CC.longActive, accel,
can_sends.extend(self.CCS.create_acc_accel_control(self.packer_pt, self.CAN.pt, CS.acc_type, CC.longActive, accel,
acc_control, stopping, starting, CS.esp_hold_confirmation))
#if self.aeb_available:
@@ -97,7 +97,7 @@ class CarController(CarControllerBase):
hud_alert = 0
if hud_control.visualAlert in (VisualAlert.steerRequired, VisualAlert.ldw):
hud_alert = self.CCP.LDW_MESSAGES["laneAssistTakeOver"]
can_sends.append(self.CCS.create_lka_hud_control(self.packer_pt, CANBUS.pt, CS.ldw_stock_values, CC.latActive,
can_sends.append(self.CCS.create_lka_hud_control(self.packer_pt, self.CAN.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:
@@ -108,14 +108,14 @@ class CarController(CarControllerBase):
# FIXME: PQ may need to use the on-the-wire mph/kmh toggle to fix rounding errors
# FIXME: Detect clusters with vEgoCluster offsets and apply an identical vCruiseCluster offset
set_speed = hud_control.setSpeed * CV.MS_TO_KPH
can_sends.append(self.CCS.create_acc_hud_control(self.packer_pt, CANBUS.pt, acc_hud_status, set_speed,
can_sends.append(self.CCS.create_acc_hud_control(self.packer_pt, self.CAN.pt, acc_hud_status, set_speed,
lead_distance, hud_control.leadDistanceBars))
# **** Stock ACC Button Controls **************************************** #
gra_send_ready = self.CP.pcmCruise and CS.gra_stock_values["COUNTER"] != self.gra_acc_counter_last
if gra_send_ready and (CC.cruiseControl.cancel or CC.cruiseControl.resume):
can_sends.append(self.CCS.create_acc_buttons_control(self.packer_pt, self.ext_bus, CS.gra_stock_values,
can_sends.append(self.CCS.create_acc_buttons_control(self.packer_pt, self.CAN.ext, CS.gra_stock_values,
cancel=CC.cruiseControl.cancel, resume=CC.cruiseControl.resume))
new_actuators = actuators.as_builder()

View File

@@ -2,7 +2,7 @@ from opendbc.can import CANParser
from opendbc.car import Bus, structs
from opendbc.car.interfaces import CarStateBase
from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.volkswagen.values import DBC, CANBUS, NetworkLocation, TransmissionType, GearShifter, \
from opendbc.car.volkswagen.values import DBC, CanBus, NetworkLocation, TransmissionType, GearShifter, \
CarControllerParams, VolkswagenFlags
ButtonType = structs.CarState.ButtonEvent.Type
@@ -265,14 +265,14 @@ class CarState(CarStateBase):
Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], [
# the 50->1Hz is currently too much for the CANParser to figure out
("Blinkmodi_02", 1), # From J519 BCM (sent at 1Hz when no lights active, 50Hz when active)
], CANBUS.pt),
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], cam_messages, CANBUS.cam),
], CanBus(CP).pt),
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], cam_messages, CanBus(CP).cam),
}
@staticmethod
def get_can_parsers_pq(CP):
return {
Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CANBUS.pt),
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CANBUS.cam),
Bus.pt: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CanBus(CP).pt),
Bus.cam: CANParser(DBC[CP.carFingerprint][Bus.pt], [], CanBus(CP).cam),
}

View File

@@ -2,7 +2,7 @@ from opendbc.car import get_safety_config, structs
from opendbc.car.interfaces import CarInterfaceBase
from opendbc.car.volkswagen.carcontroller import CarController
from opendbc.car.volkswagen.carstate import CarState
from opendbc.car.volkswagen.values import CAR, NetworkLocation, TransmissionType, VolkswagenFlags, VolkswagenSafetyFlags
from opendbc.car.volkswagen.values import CanBus, CAR, NetworkLocation, TransmissionType, VolkswagenFlags, VolkswagenSafetyFlags
class CarInterface(CarInterfaceBase):
@@ -16,7 +16,7 @@ class CarInterface(CarInterfaceBase):
if ret.flags & VolkswagenFlags.PQ:
# Set global PQ35/PQ46/NMS parameters
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.volkswagenPq)]
safety_configs = [get_safety_config(structs.CarParams.SafetyModel.volkswagenPq)]
ret.enableBsm = 0x3BA in fingerprint[0] # SWA_1
if 0x440 in fingerprint[0] or docs: # Getriebe_1
@@ -39,7 +39,7 @@ class CarInterface(CarInterfaceBase):
else:
# Set global MQB parameters
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.volkswagen)]
safety_configs = [get_safety_config(structs.CarParams.SafetyModel.volkswagen)]
ret.enableBsm = 0x30F in fingerprint[0] # SWA_01
if 0xAD in fingerprint[0] or docs: # Getriebe_11
@@ -79,7 +79,7 @@ class CarInterface(CarInterfaceBase):
if alpha_long:
# Proof-of-concept, prep for E2E only. No radar points available. Panda ALLOW_DEBUG firmware required.
ret.openpilotLongitudinalControl = True
ret.safetyConfigs[0].safetyParam |= VolkswagenSafetyFlags.LONG_CONTROL.value
safety_configs[0].safetyParam |= VolkswagenSafetyFlags.LONG_CONTROL.value
if ret.transmissionType == TransmissionType.manual:
ret.minEnableSpeed = 4.5
@@ -89,4 +89,9 @@ class CarInterface(CarInterfaceBase):
ret.vEgoStopping = 0.5
ret.autoResumeSng = ret.minEnableSpeed == -1
CAN = CanBus(fingerprint=fingerprint)
if CAN.pt >= 4:
safety_configs.insert(0, get_safety_config(structs.CarParams.SafetyModel.noOutput))
ret.safetyConfigs = safety_configs
return ret

View File

@@ -2,7 +2,7 @@ from collections import defaultdict, namedtuple
from dataclasses import dataclass, field
from enum import Enum, IntFlag, StrEnum
from opendbc.car import Bus, CarSpecs, DbcDict, PlatformConfig, Platforms, structs, uds
from opendbc.car import Bus, CanBusBase, CarSpecs, DbcDict, PlatformConfig, Platforms, structs, uds
from opendbc.can import CANDefine
from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column, \
@@ -17,6 +17,36 @@ GearShifter = structs.CarState.GearShifter
Button = namedtuple('Button', ['event_type', 'can_addr', 'can_msg', 'values'])
class CanBus(CanBusBase):
def __init__(self, CP=None, fingerprint=None) -> None:
super().__init__(CP, fingerprint)
self._ext = self.offset
if CP is not None:
self._ext = self.offset + 2 if CP.networkLocation == NetworkLocation.gateway else self.offset
@property
def pt(self) -> int:
# ADAS / Extended CAN, gateway side of the relay
return self.offset
@property
def aux(self) -> int:
# NetworkLocation.fwdCamera: radar-camera object fusion CAN
# NetworkLocation.gateway: powertrain CAN
return self.offset + 1
@property
def cam(self) -> int:
# ADAS / Extended CAN, camera side of the relay
return self.offset + 2
@property
def ext(self) -> int:
# ADAS / Extended CAN, side of the relay with the ACC radar
return self._ext
class CarControllerParams:
STEER_STEP = 2 # HCA_01/HCA_1 message frequency 50Hz
ACC_CONTROL_STEP = 2 # ACC_06/ACC_07/ACC_System frequency 50Hz
@@ -107,11 +137,6 @@ class CarControllerParams:
}
class CANBUS:
pt = 0
cam = 2
class WMI(StrEnum):
VOLKSWAGEN_USA_SUV = "1V2"
VOLKSWAGEN_USA_CAR = "1VW"