selfdrive/car: ban cereal and capnp (#33208)

* ban cereal and msgq

* common too

* do toyota/values.py

* do all fingerprints

* example without builder

* this still works, but no type checking anymore

* stash

* wtf, how does this work

* okay actually not bad

* safe

* epic!

* stash data_structures.py

* some clean up

* hell yeah

* clean up old file

* add to delete

* delete

This reverts commit 90239b7797.

* switch more CarParams stuff over

remove unused

* fix car tests by removing cereal! mypy forgets about dataclass if we wrap it :(

* fix this too

* fix this too

* remove more cereal and add some good hyundai tests

* bunch more typing

* override default with 20hz radar

* temp capnp converter helper

* more lateralTuning

* small union replicator is better than what i was trying, and fixes mypy dynamic typing issues

* can keep all this the same now!

* type ret: CarParams, add more missing structs, revert lateralTuning changes (smaller diff!)

* revert more

* get first enum automatically, but ofc mypy doesn't pick up the new metaclass so can't use :(

would have been `CarParams.NetworkLocation()`

* Revert "get first enum automatically, but ofc mypy doesn't pick up the new metaclass so can't use :("

This reverts commit bb28b228be.

* remove cereal from car_helpers (TODO: caching)

* remove a bunch of temp lines

* use dataclass_transform!

* remove some car.CarParams from the interfaces

* remove rest of car.CarParams from the interfaces

* same which() API

* sort

* from cereal/cache from fingerprinting!

* more typing

* dataclass to capnp helper for CarParams, cached it since it's kinda slow

* (partial) fix process replay fingerprintig for new API

* latcontrollers take capnp

* forgot this

* fix test_models

* fix unit tests

* not here

* VehicleModel and controller still takes capnp CP since they get it from Params()

* fix modeld test

* more fix

* need to namespace to structs, since CarState is both class and struct

* this was never in the base class?!

* clean that up again

* fix import error

fix import error

* cmts and more structs

* remove some more cereal from toyota + convert CarState to capnp

* bruh this was wrong

* replace more cereal

* EventName is one of the last things...

* replace a bunch more cereal.car

* missing imports

* more

* can fix this typing now

* proper toyota+others CS typing!

* mypy can detect return type of CS.update() now

* fix redeclaration of cruise_buttons type

* mypy is only complaining about events now

* temp fix

* add carControl struct

* replace CarControl

i hope there's no circular imports in hyundai's CC

* fine now

* lol this was wrong too

* fix crash

* include my failed attempts at recursively converting to dataclass (doesn't implicitly convert types/recursively :( )

but attrs does, maybe will switch in the future

* clean up

* try out attr.s for its converter (doesn't work recursively yet, but interesting!)

* Revert "try out attr.s for its converter (doesn't work recursively yet, but interesting!)"

This reverts commit ff2434f7bb.

* test processes doesn't fail anymore (on toyota)!

* fix honda crash

* stash

* Revert "stash"

This reverts commit c1762af4e7.

* remove a bunch more cereal!

* LET'S GOOO

* fix these tests

* and these

* and that

* stash, something is wrong with hyundai enable

* Revert "stash, something is wrong with hyundai enable"

This reverts commit 39cf327def.

* forgot these

* remove cereal from fw_versions

* Revert "remove cereal from fw_versions"

This reverts commit 232b37cd40.

* remove rest of the cereal exceptions!

* fix that

* add typing to radard since I didn't realize RI.update() switched from cereal to structs

* and here too!

* add TODO for slots

* needed CS to be capnp, fix comparisons, and type hint car_specific so it's easier to catch type issues (capnp isn't detected by mypy :( )

* remove the struct converter

* save ~4-5% CPU at 100hz, we don't modify after so no need to deepcopy

btw pickle.loads(pickle.dumps()) is faster by ~1% CPU

* deepcopy -> copy: we can technically make a reference, but copy is almost free and less error-prone

saves ~1% CPU

* add non-copying asdict function

* should save ~3% CPU (still 4% above baseline)

* fix that, no dict support

* ~27% decrease in time for 20k iterations on 3X (3.37857 -> 2.4821s)

* give a better name

* fix

* dont support none, capitalize

* sheesh, this called type() on every field

* remove CS.events, clean up

* bump card %

* this was a bug on master!

* add a which enum

* default to pid

* revert

* update refs

* not needed, but consistent

* just Ecu

* don't need to do this in this pr

* clean up

* no cast

* consistent typing

* rm

* fix

* can do this if we're desperate for the last few %

* Revert "can do this if we're desperate for the last few %"

This reverts commit 18e11ac788.

* type this

* don't need to convert carControl

* i guess don't support set either

* fix CP type hint

* simplify that
This commit is contained in:
Shane Smiskol 2024-08-16 15:13:00 -07:00 committed by GitHub
parent 51fae363e4
commit 6a15c42143
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
98 changed files with 1051 additions and 485 deletions

View File

@ -1,6 +1,8 @@
[importlinter]
root_packages =
openpilot
cereal
capnp
[importlinter:contract:1]
name = Forbid imports from openpilot.selfdrive.car to openpilot.system
@ -8,6 +10,8 @@ type = forbidden
source_modules =
openpilot.selfdrive.car
forbidden_modules =
cereal
capnp
openpilot.common
openpilot.selfdrive.controls
openpilot.selfdrive.debug
@ -44,5 +48,16 @@ ignore_imports =
openpilot.selfdrive.car.tests.test_car_interfaces -> openpilot.selfdrive.pandad
openpilot.selfdrive.car.tests.test_models -> openpilot.selfdrive.pandad
openpilot.selfdrive.car.tests.test_car_interfaces -> openpilot.selfdrive.test.fuzzy_generation
openpilot.selfdrive.car.tests.test_models -> capnp
openpilot.selfdrive.car.tests.test_car_interfaces -> cereal
openpilot.selfdrive.car.tests.test_car_interfaces -> cereal.messaging
openpilot.selfdrive.car.tests.test_car_interfaces -> openpilot.selfdrive.test.fuzzy_generation
openpilot.selfdrive.car.tests.test_models -> cereal
openpilot.selfdrive.car.tests.test_models -> cereal.messaging
openpilot.selfdrive.car.card -> cereal
openpilot.selfdrive.car.card -> cereal.messaging
openpilot.selfdrive.car.car_specific -> openpilot.selfdrive.controls.lib.events
openpilot.selfdrive.car.car_specific -> cereal
openpilot.selfdrive.car.car_specific -> cereal.messaging
openpilot.selfdrive.car.card -> capnp
unmatched_ignore_imports_alerting = warn

View File

@ -5,10 +5,8 @@ from dataclasses import dataclass
from enum import IntFlag, ReprEnum, EnumType
from dataclasses import replace
import capnp
from cereal import car
from panda.python.uds import SERVICE_TYPE
from openpilot.selfdrive.car import structs
from openpilot.selfdrive.car.can_definitions import CanData
from openpilot.selfdrive.car.docs_definitions import CarDocs
from openpilot.selfdrive.car.common.numpy_fast import clip, interp
@ -23,7 +21,7 @@ DT_CTRL = 0.01 # car state and control loop timestep (s)
# kg of standard extra cargo to count for drive, gas, etc...
STD_CARGO_KG = 136.
ButtonType = car.CarState.ButtonEvent.Type
ButtonType = structs.CarState.ButtonEvent.Type
AngleRateLimit = namedtuple('AngleRateLimit', ['speed_bp', 'angle_v'])
@ -35,9 +33,9 @@ def apply_hysteresis(val: float, val_steady: float, hyst_gap: float) -> float:
return val_steady
def create_button_events(cur_btn: int, prev_btn: int, buttons_dict: dict[int, capnp.lib.capnp._EnumModule],
unpressed_btn: int = 0) -> list[capnp.lib.capnp._DynamicStructBuilder]:
events: list[capnp.lib.capnp._DynamicStructBuilder] = []
def create_button_events(cur_btn: int, prev_btn: int, buttons_dict: dict[int, structs.CarState.ButtonEvent.Type],
unpressed_btn: int = 0) -> list[structs.CarState.ButtonEvent]:
events: list[structs.CarState.ButtonEvent] = []
if cur_btn == prev_btn:
return events
@ -45,8 +43,8 @@ def create_button_events(cur_btn: int, prev_btn: int, buttons_dict: dict[int, ca
# Add events for button presses, multiple when a button switches without going to unpressed
for pressed, btn in ((False, prev_btn), (True, cur_btn)):
if btn != unpressed_btn:
events.append(car.CarState.ButtonEvent(pressed=pressed,
type=buttons_dict.get(btn, ButtonType.unknown)))
events.append(structs.CarState.ButtonEvent(pressed=pressed,
type=buttons_dict.get(btn, ButtonType.unknown)))
return events
@ -183,7 +181,7 @@ def rate_limit(new_value, last_value, dw_step, up_step):
def get_friction(lateral_accel_error: float, lateral_accel_deadzone: float, friction_threshold: float,
torque_params: car.CarParams.LateralTorqueTuning, friction_compensation: bool) -> float:
torque_params: structs.CarParams.LateralTorqueTuning, friction_compensation: bool) -> float:
friction_interp = interp(
apply_center_deadzone(lateral_accel_error, lateral_accel_deadzone),
[-friction_threshold, friction_threshold],
@ -203,8 +201,8 @@ def make_tester_present_msg(addr, bus, subaddr=None, suppress_response=False):
return CanData(addr, bytes(dat), bus)
def get_safety_config(safety_model, safety_param = None):
ret = car.CarParams.SafetyConfig.new_message()
def get_safety_config(safety_model: structs.CarParams.SafetyModel, safety_param: int = None) -> structs.CarParams.SafetyConfig:
ret = structs.CarParams.SafetyConfig()
ret.safetyModel = safety_model
if safety_param is not None:
ret.safetyParam = safety_param

View File

@ -1,3 +1,4 @@
import copy
import numpy as np
from numbers import Number
@ -132,7 +133,7 @@ class CarController(CarControllerBase):
can_sends = []
can_sends.append(bodycan.create_control(self.packer, torque_l, torque_r))
new_actuators = CC.actuators.as_builder()
new_actuators = copy.copy(CC.actuators)
new_actuators.accel = torque_l
new_actuators.steer = torque_r
new_actuators.steerOutputCan = torque_r

View File

@ -1,12 +1,12 @@
from cereal import car
from opendbc.can.parser import CANParser
from openpilot.selfdrive.car import structs
from openpilot.selfdrive.car.interfaces import CarStateBase
from openpilot.selfdrive.car.body.values import DBC
class CarState(CarStateBase):
def update(self, cp, *_):
ret = car.CarState.new_message()
def update(self, cp, *_) -> structs.CarState:
ret = structs.CarState()
ret.wheelSpeeds.fl = cp.vl['MOTORS_DATA']['SPEED_L']
ret.wheelSpeeds.fr = cp.vl['MOTORS_DATA']['SPEED_R']
@ -23,7 +23,7 @@ class CarState(CarStateBase):
ret.fuelGauge = cp.vl["BODY_DATA"]["BATT_PERCENTAGE"] / 100
# irrelevant for non-car
ret.gearShifter = car.CarState.GearShifter.drive
ret.gearShifter = structs.CarState.GearShifter.drive
ret.cruiseState.enabled = True
ret.cruiseState.available = True

View File

@ -1,8 +1,8 @@
# ruff: noqa: E501
from cereal import car
from openpilot.selfdrive.car.structs import CarParams
from openpilot.selfdrive.car.body.values import CAR
Ecu = car.CarParams.Ecu
Ecu = CarParams.Ecu
# debug ecu fw version is the git hash of the firmware

View File

@ -1,16 +1,15 @@
import math
from cereal import car
from openpilot.selfdrive.car import get_safety_config
from openpilot.selfdrive.car import get_safety_config, structs
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
from openpilot.selfdrive.car.body.values import SPEED_FROM_RPM
class CarInterface(CarInterfaceBase):
@staticmethod
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs):
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, experimental_long, docs) -> structs.CarParams:
ret.notCar = True
ret.carName = "body"
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.body)]
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.body)]
ret.minSteerSpeed = -math.inf
ret.maxLateralAccel = math.inf # TODO: set to a reasonable value
@ -21,6 +20,6 @@ class CarInterface(CarInterfaceBase):
ret.radarUnavailable = True
ret.openpilotLongitudinalControl = True
ret.steerControlType = car.CarParams.SteerControlType.angle
ret.steerControlType = structs.CarParams.SteerControlType.angle
return ret

View File

@ -1,9 +1,9 @@
from cereal import car
from openpilot.selfdrive.car import CarSpecs, PlatformConfig, Platforms, dbc_dict
from openpilot.selfdrive.car.structs import CarParams
from openpilot.selfdrive.car.docs_definitions import CarDocs
from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries
Ecu = car.CarParams.Ecu
Ecu = CarParams.Ecu
SPEED_FROM_RPM = 0.008587

View File

@ -1,9 +1,9 @@
import os
import time
from cereal import car
from openpilot.selfdrive.car import carlog, gen_empty_fingerprint
from openpilot.selfdrive.car.can_definitions import CanRecvCallable, CanSendCallable
from openpilot.selfdrive.car.structs import CarParams
from openpilot.selfdrive.car.fingerprints import eliminate_incompatible_cars, all_legacy_fingerprint_cars
from openpilot.selfdrive.car.fw_versions import ObdCallback, get_fw_versions_ordered, get_present_ecus, match_fw_to_car
from openpilot.selfdrive.car.interfaces import get_interface_attr
@ -82,7 +82,7 @@ def can_fingerprint(can_recv: CanRecvCallable) -> tuple[str | None, dict[int, di
# **** for use live only ****
def fingerprint(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_multiplexing: ObdCallback, num_pandas: int,
cached_params: type[car.CarParams] | None) -> tuple[str | None, dict, str, list, int, bool]:
cached_params: CarParams | None) -> tuple[str | None, dict, str, list[CarParams.CarFw], CarParams.FingerprintSource, bool]:
fixed_fingerprint = os.environ.get('FINGERPRINT', "")
skip_fw_query = os.environ.get('SKIP_FW_QUERY', False)
disable_fw_cache = os.environ.get('DISABLE_FW_CACHE', False)
@ -129,17 +129,17 @@ def fingerprint(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_mu
car_fingerprint, finger = can_fingerprint(can_recv)
exact_match = True
source = car.CarParams.FingerprintSource.can
source = CarParams.FingerprintSource.can
# If FW query returns exactly 1 candidate, use it
if len(fw_candidates) == 1:
car_fingerprint = list(fw_candidates)[0]
source = car.CarParams.FingerprintSource.fw
source = CarParams.FingerprintSource.fw
exact_match = exact_fw_match
if fixed_fingerprint:
car_fingerprint = fixed_fingerprint
source = car.CarParams.FingerprintSource.fixed
source = CarParams.FingerprintSource.fixed
carlog.error({"event": "fingerprinted", "car_fingerprint": str(car_fingerprint), "source": source, "fuzzy": not exact_match,
"cached": cached, "fw_count": len(car_fw), "ecu_responses": list(ecu_rx_addrs), "vin_rx_addr": vin_rx_addr,
@ -148,13 +148,13 @@ def fingerprint(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_mu
return car_fingerprint, finger, vin, car_fw, source, exact_match
def get_car_interface(CP):
def get_car_interface(CP: CarParams):
CarInterface, CarController, CarState = interfaces[CP.carFingerprint]
return CarInterface(CP, CarController, CarState)
def get_car(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_multiplexing: ObdCallback, experimental_long_allowed: bool,
num_pandas: int = 1, cached_params: type[car.CarParams] | None = None):
num_pandas: int = 1, cached_params: CarParams | None = None):
candidate, fingerprints, vin, car_fw, source, exact_match = fingerprint(can_recv, can_send, set_obd_multiplexing, num_pandas, cached_params)
if candidate is None:
@ -162,7 +162,7 @@ def get_car(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_multip
candidate = "MOCK"
CarInterface, _, _ = interfaces[candidate]
CP = CarInterface.get_params(candidate, fingerprints, car_fw, experimental_long_allowed, docs=False)
CP: CarParams = CarInterface.get_params(candidate, fingerprints, car_fw, experimental_long_allowed, docs=False)
CP.carVin = vin
CP.carFw = car_fw
CP.fingerprintSource = source

View File

@ -1,16 +1,16 @@
from cereal import car
import cereal.messaging as messaging
from openpilot.selfdrive.car import DT_CTRL
from openpilot.selfdrive.car.interfaces import MAX_CTRL_SPEED
from openpilot.selfdrive.car import DT_CTRL, structs
from openpilot.selfdrive.car.interfaces import MAX_CTRL_SPEED, CarStateBase, CarControllerBase
from openpilot.selfdrive.car.volkswagen.values import CarControllerParams as VWCarControllerParams
from openpilot.selfdrive.car.hyundai.interface import ENABLE_BUTTONS as HYUNDAI_ENABLE_BUTTONS
from openpilot.selfdrive.controls.lib.events import Events
ButtonType = car.CarState.ButtonEvent.Type
GearShifter = car.CarState.GearShifter
ButtonType = structs.CarState.ButtonEvent.Type
GearShifter = structs.CarState.GearShifter
EventName = car.CarEvent.EventName
NetworkLocation = car.CarParams.NetworkLocation
NetworkLocation = structs.CarParams.NetworkLocation
# TODO: the goal is to abstract this file into the CarState struct and make events generic
@ -29,7 +29,7 @@ class MockCarState:
class CarSpecificEvents:
def __init__(self, CP: car.CarParams):
def __init__(self, CP: structs.CarParams):
self.CP = CP
self.steering_unpressed = 0
@ -37,7 +37,7 @@ class CarSpecificEvents:
self.no_steer_warning = False
self.silent_steer_warning = True
def update(self, CS, CS_prev, CC, CC_prev):
def update(self, CS: CarStateBase, CS_prev: car.CarState, CC: CarControllerBase, CC_prev: car.CarControl):
if self.CP.carName in ('body', 'mock'):
events = Events()
@ -50,15 +50,15 @@ class CarSpecificEvents:
elif self.CP.carName == 'nissan':
events = self.create_common_events(CS.out, CS_prev, extra_gears=[GearShifter.brake])
if CS.lkas_enabled:
if CS.lkas_enabled: # type: ignore[attr-defined]
events.add(EventName.invalidLkasSetting)
elif self.CP.carName == 'mazda':
events = self.create_common_events(CS.out, CS_prev)
if CS.lkas_disabled:
if CS.lkas_disabled: # type: ignore[attr-defined]
events.add(EventName.lkasDisabled)
elif CS.low_speed_alert:
elif CS.low_speed_alert: # type: ignore[attr-defined]
events.add(EventName.belowSteerSpeed)
elif self.CP.carName == 'chrysler':
@ -99,7 +99,7 @@ class CarSpecificEvents:
if self.CP.openpilotLongitudinalControl:
if CS.out.cruiseState.standstill and not CS.out.brakePressed:
events.add(EventName.resumeRequired)
if CS.low_speed_lockout:
if CS.low_speed_lockout: # type: ignore[attr-defined]
events.add(EventName.lowSpeedLockout)
if CS.out.vEgo < self.CP.minEnableSpeed:
events.add(EventName.belowEngageSpeed)
@ -121,7 +121,7 @@ class CarSpecificEvents:
# Enabling at a standstill with brake is allowed
# TODO: verify 17 Volt can enable for the first time at a stop and allow for all GMs
below_min_enable_speed = CS.out.vEgo < self.CP.minEnableSpeed or CS.moving_backward
below_min_enable_speed = CS.out.vEgo < self.CP.minEnableSpeed or CS.moving_backward # type: ignore[attr-defined]
if below_min_enable_speed and not (CS.out.standstill and CS.out.brake >= 20 and
self.CP.networkLocation == NetworkLocation.fwdCamera):
events.add(EventName.belowEngageSpeed)
@ -149,14 +149,14 @@ class CarSpecificEvents:
if CC_prev.enabled and CS.out.vEgo < self.CP.minEnableSpeed:
events.add(EventName.speedTooLow)
if CC.eps_timer_soft_disable_alert:
if CC.eps_timer_soft_disable_alert: # type: ignore[attr-defined]
events.add(EventName.steerTimeLimit)
elif self.CP.carName == 'hyundai':
# On some newer model years, the CANCEL button acts as a pause/resume button based on the PCM state
# To avoid re-engaging when openpilot cancels, check user engagement intention via buttons
# Main button also can trigger an engagement on these cars
allow_enable = any(btn in HYUNDAI_ENABLE_BUTTONS for btn in CS.cruise_buttons) or any(CS.main_buttons)
allow_enable = any(btn in HYUNDAI_ENABLE_BUTTONS for btn in CS.cruise_buttons) or any(CS.main_buttons) # type: ignore[attr-defined]
events = self.create_common_events(CS.out, CS_prev, pcm_enable=self.CP.pcmCruise, allow_enable=allow_enable)
# low speed steer alert hysteresis logic (only for cars with steer cut off above 10 m/s)
@ -172,8 +172,8 @@ class CarSpecificEvents:
return events
def create_common_events(self, CS, CS_prev, extra_gears=None, pcm_enable=True, allow_enable=True,
enable_buttons=(ButtonType.accelCruise, ButtonType.decelCruise)):
def create_common_events(self, CS: structs.CarState, CS_prev: car.CarState, extra_gears=None, pcm_enable=True,
allow_enable=True, enable_buttons=(ButtonType.accelCruise, ButtonType.decelCruise)):
events = Events()
if CS.doorOpen:

View File

@ -1,6 +1,8 @@
#!/usr/bin/env python3
import capnp
import os
import time
from typing import Any
import cereal.messaging as messaging
@ -13,7 +15,7 @@ from openpilot.common.realtime import config_realtime_process, Priority, Ratekee
from openpilot.common.swaglog import cloudlog, ForwardingHandler
from openpilot.selfdrive.pandad import can_capnp_to_list, can_list_to_can_capnp
from openpilot.selfdrive.car import DT_CTRL, carlog
from openpilot.selfdrive.car import DT_CTRL, carlog, structs
from openpilot.selfdrive.car.can_definitions import CanData, CanRecvCallable, CanSendCallable
from openpilot.selfdrive.car.car_specific import CarSpecificEvents, MockCarState
from openpilot.selfdrive.car.fw_versions import ObdCallback
@ -22,6 +24,7 @@ from openpilot.selfdrive.car.interfaces import CarInterfaceBase
from openpilot.selfdrive.controls.lib.events import Events
REPLAY = "REPLAY" in os.environ
_FIELDS = '__dataclass_fields__' # copy of dataclasses._FIELDS
EventName = car.CarEvent.EventName
@ -58,8 +61,74 @@ def can_comm_callbacks(logcan: messaging.SubSocket, sendcan: messaging.PubSocket
return can_recv, can_send
def is_dataclass(obj):
"""Similar to dataclasses.is_dataclass without instance type check checking"""
return hasattr(obj, _FIELDS)
def asdictref(obj) -> dict[str, Any]:
"""
Similar to dataclasses.asdict without recursive type checking and copy.deepcopy
Note that the resulting dict will contain references to the original struct as a result
"""
if not is_dataclass(obj):
raise TypeError("asdictref() should be called on dataclass instances")
def _asdictref_inner(obj) -> dict[str, Any] | Any:
if is_dataclass(obj):
ret = {}
for field in getattr(obj, _FIELDS): # similar to dataclasses.fields()
ret[field] = _asdictref_inner(getattr(obj, field))
return ret
elif isinstance(obj, (tuple, list)):
return type(obj)(_asdictref_inner(v) for v in obj)
else:
return obj
return _asdictref_inner(obj)
def convert_to_capnp(struct: structs.CarParams | structs.CarState | structs.CarControl.Actuators) -> capnp.lib.capnp._DynamicStructBuilder:
struct_dict = asdictref(struct)
if isinstance(struct, structs.CarParams):
del struct_dict['lateralTuning']
struct_capnp = car.CarParams.new_message(**struct_dict)
# this is the only union, special handling
which = struct.lateralTuning.which()
struct_capnp.lateralTuning.init(which)
lateralTuning_dict = asdictref(getattr(struct.lateralTuning, which))
setattr(struct_capnp.lateralTuning, which, lateralTuning_dict)
elif isinstance(struct, structs.CarState):
struct_capnp = car.CarState.new_message(**struct_dict)
elif isinstance(struct, structs.CarControl.Actuators):
struct_capnp = car.CarControl.Actuators.new_message(**struct_dict)
else:
raise ValueError(f"Unsupported struct type: {type(struct)}")
return struct_capnp
def convert_carControl(struct: capnp.lib.capnp._DynamicStructReader) -> structs.CarControl:
# TODO: recursively handle any car struct as needed
def remove_deprecated(s: dict) -> dict:
return {k: v for k, v in s.items() if not k.endswith('DEPRECATED')}
struct_dict = struct.to_dict()
struct_dataclass = structs.CarControl(**remove_deprecated({k: v for k, v in struct_dict.items() if not isinstance(k, dict)}))
struct_dataclass.actuators = structs.CarControl.Actuators(**remove_deprecated(struct_dict.get('actuators', {})))
struct_dataclass.cruiseControl = structs.CarControl.CruiseControl(**remove_deprecated(struct_dict.get('cruiseControl', {})))
struct_dataclass.hudControl = structs.CarControl.HUDControl(**remove_deprecated(struct_dict.get('hudControl', {})))
return struct_dataclass
class Car:
CI: CarInterfaceBase
CP: structs.CarParams
CP_capnp: car.CarParams
def __init__(self, CI=None) -> None:
self.can_sock = messaging.sub_sock('can', timeout=20)
@ -72,7 +141,7 @@ class Car:
self.CS_prev = car.CarState.new_message()
self.initialized_prev = False
self.last_actuators_output = car.CarControl.Actuators.new_message()
self.last_actuators_output = structs.CarControl.Actuators()
self.params = Params()
@ -93,7 +162,7 @@ class Car:
cached_params_raw = self.params.get("CarParamsCache")
if cached_params_raw is not None:
with car.CarParams.from_bytes(cached_params_raw) as _cached_params:
cached_params = _cached_params
cached_params = structs.CarParams(carName=_cached_params.carName, carFw=_cached_params.carFw, carVin=_cached_params.carVin)
self.CI = get_car(*self.can_callbacks, obd_callback(self.params), experimental_long_allowed, num_pandas, cached_params)
self.CP = self.CI.CP
@ -115,8 +184,8 @@ class Car:
self.CP.passive = not controller_available or self.CP.dashcamOnly
if self.CP.passive:
safety_config = car.CarParams.SafetyConfig.new_message()
safety_config.safetyModel = car.CarParams.SafetyModel.noOutput
safety_config = structs.CarParams.SafetyConfig()
safety_config.safetyModel = structs.CarParams.SafetyModel.noOutput
self.CP.safetyConfigs = [safety_config]
# Write previous route's CarParams
@ -125,7 +194,9 @@ class Car:
self.params.put("CarParamsPrevRoute", prev_cp)
# Write CarParams for controls and radard
cp_bytes = self.CP.to_bytes()
# convert to pycapnp representation for caching and logging
self.CP_capnp = convert_to_capnp(self.CP)
cp_bytes = self.CP_capnp.to_bytes()
self.params.put("CarParams", cp_bytes)
self.params.put_nonblocking("CarParamsCache", cp_bytes)
self.params.put_nonblocking("CarParamsPersistent", cp_bytes)
@ -143,7 +214,7 @@ class Car:
# Update carState from CAN
can_strs = messaging.drain_sock_raw(self.can_sock, wait_for_one=True)
CS = self.CI.update(can_capnp_to_list(can_strs))
CS = convert_to_capnp(self.CI.update(can_capnp_to_list(can_strs)))
if self.CP.carName == 'mock':
CS = self.mock_carstate.update(CS)
@ -189,13 +260,13 @@ class Car:
if self.sm.frame % int(50. / DT_CTRL) == 0:
cp_send = messaging.new_message('carParams')
cp_send.valid = True
cp_send.carParams = self.CP
cp_send.carParams = self.CP_capnp
self.pm.send('carParams', cp_send)
# publish new carOutput
co_send = messaging.new_message('carOutput')
co_send.valid = self.sm.all_checks(['carControl'])
co_send.carOutput.actuatorsOutput = self.last_actuators_output
co_send.carOutput.actuatorsOutput = convert_to_capnp(self.last_actuators_output)
self.pm.send('carOutput', co_send)
# kick off controlsd step while we actuate the latest carControl packet
@ -219,7 +290,7 @@ class Car:
if self.sm.all_alive(['carControl']):
# send car controls over can
now_nanos = self.can_log_mono_time if REPLAY else int(time.monotonic() * 1e9)
self.last_actuators_output, can_sends = self.CI.apply(CC, now_nanos)
self.last_actuators_output, can_sends = self.CI.apply(convert_carControl(CC), now_nanos)
self.pm.send('sendcan', can_list_to_can_capnp(can_sends, msgtype='sendcan', valid=CS.canValid))
self.CC_prev = CC

View File

@ -1,3 +1,4 @@
import copy
from opendbc.can.packer import CANPacker
from openpilot.selfdrive.car import DT_CTRL, apply_meas_steer_torque_limits
from openpilot.selfdrive.car.chrysler import chryslercan
@ -76,7 +77,7 @@ class CarController(CarControllerBase):
self.frame += 1
new_actuators = CC.actuators.as_builder()
new_actuators = copy.copy(CC.actuators)
new_actuators.steer = self.apply_steer_last / self.params.STEER_MAX
new_actuators.steerOutputCan = self.apply_steer_last

View File

@ -1,12 +1,11 @@
from cereal import car
from opendbc.can.parser import CANParser
from opendbc.can.can_define import CANDefine
from openpilot.selfdrive.car import create_button_events
from openpilot.selfdrive.car import create_button_events, structs
from openpilot.selfdrive.car.chrysler.values import DBC, STEER_THRESHOLD, RAM_CARS
from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.interfaces import CarStateBase
ButtonType = car.CarState.ButtonEvent.Type
ButtonType = structs.CarState.ButtonEvent.Type
class CarState(CarStateBase):
@ -26,9 +25,9 @@ class CarState(CarStateBase):
self.distance_button = 0
def update(self, cp, cp_cam, *_):
def update(self, cp, cp_cam, *_) -> structs.CarState:
ret = car.CarState.new_message()
ret = structs.CarState()
prev_distance_button = self.distance_button
self.distance_button = cp.vl["CRUISE_BUTTONS"]["ACC_Distance_Dec"]

View File

@ -1,8 +1,8 @@
from cereal import car
from openpilot.selfdrive.car import structs
from openpilot.selfdrive.car.chrysler.values import RAM_CARS
GearShifter = car.CarState.GearShifter
VisualAlert = car.CarControl.HUDControl.VisualAlert
GearShifter = structs.CarState.GearShifter
VisualAlert = structs.CarControl.HUDControl.VisualAlert
def create_lkas_hud(packer, CP, lkas_active, hud_alert, hud_count, car_model, auto_high_beam):
# LKAS_HUD - Controls what lane-keeping icon is displayed

View File

@ -1,7 +1,7 @@
from cereal import car
from openpilot.selfdrive.car.structs import CarParams
from openpilot.selfdrive.car.chrysler.values import CAR
Ecu = car.CarParams.Ecu
Ecu = CarParams.Ecu
FW_VERSIONS = {
CAR.CHRYSLER_PACIFICA_2018: {

View File

@ -1,14 +1,13 @@
#!/usr/bin/env python3
from cereal import car
from panda import Panda
from openpilot.selfdrive.car import get_safety_config
from openpilot.selfdrive.car import get_safety_config, structs
from openpilot.selfdrive.car.chrysler.values import CAR, RAM_HD, RAM_DT, RAM_CARS, ChryslerFlags
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
class CarInterface(CarInterfaceBase):
@staticmethod
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs):
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, experimental_long, docs) -> structs.CarParams:
ret.carName = "chrysler"
ret.dashcamOnly = candidate in RAM_HD
@ -18,7 +17,7 @@ class CarInterface(CarInterfaceBase):
ret.steerLimitTimer = 0.4
# safety config
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.chrysler)]
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.chrysler)]
if candidate in RAM_HD:
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_CHRYSLER_RAM_HD
elif candidate in RAM_DT:

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python3
from opendbc.can.parser import CANParser
from cereal import car
from openpilot.selfdrive.car import structs
from openpilot.selfdrive.car.interfaces import RadarInterfaceBase
from openpilot.selfdrive.car.chrysler.values import DBC
@ -53,7 +53,7 @@ class RadarInterface(RadarInterfaceBase):
if self.trigger_msg not in self.updated_messages:
return None
ret = car.RadarData.new_message()
ret = structs.RadarData()
errors = []
if not self.rcp.can_valid:
errors.append("canError")
@ -64,7 +64,7 @@ class RadarInterface(RadarInterfaceBase):
trackId = _address_to_track(ii)
if trackId not in self.pts:
self.pts[trackId] = car.RadarData.RadarPoint.new_message()
self.pts[trackId] = structs.RadarData.RadarPoint()
self.pts[trackId].trackId = trackId
self.pts[trackId].aRel = float('nan')
self.pts[trackId].yvRel = float('nan')

View File

@ -1,13 +1,13 @@
from enum import IntFlag
from dataclasses import dataclass, field
from cereal import car
from panda.python import uds
from openpilot.selfdrive.car import CarSpecs, DbcDict, PlatformConfig, Platforms, dbc_dict
from openpilot.selfdrive.car.structs import CarParams
from openpilot.selfdrive.car.docs_definitions import CarHarness, CarDocs, CarParts
from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, p16
Ecu = car.CarParams.Ecu
Ecu = CarParams.Ecu
class ChryslerFlags(IntFlag):

View File

@ -3,8 +3,8 @@ import jinja2
from enum import Enum
from natsort import natsorted
from cereal import car
from openpilot.selfdrive.car import gen_empty_fingerprint
from openpilot.selfdrive.car.structs import CarParams
from openpilot.selfdrive.car.docs_definitions import CarDocs, Column, CommonFootnote, PartType
from openpilot.selfdrive.car.car_helpers import interfaces, get_interface_attr
from openpilot.selfdrive.car.values import PLATFORMS
@ -24,7 +24,7 @@ def get_all_car_docs() -> list[CarDocs]:
car_docs = platform.config.car_docs
# If available, uses experimental longitudinal limits for the docs
CP = interfaces[model][0].get_params(platform, fingerprint=gen_empty_fingerprint(),
car_fw=[car.CarParams.CarFw(ecu="unknown")], experimental_long=True, docs=True)
car_fw=[CarParams.CarFw(ecu=CarParams.Ecu.unknown)], experimental_long=True, docs=True)
if CP.dashcamOnly or not len(car_docs):
continue

View File

@ -4,8 +4,8 @@ import copy
from dataclasses import dataclass, field
from enum import Enum
from cereal import car
from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.structs import CarParams
GOOD_TORQUE_THRESHOLD = 1.0 # m/s^2
MODEL_YEARS_RE = r"(?<= )((\d{4}-\d{2})|(\d{4}))(,|$)"
@ -248,7 +248,7 @@ class CarDocs:
self.make, self.model, self.years = split_name(self.name)
self.year_list = get_year_list(self.years)
def init(self, CP: car.CarParams, all_footnotes: dict[Enum, int]):
def init(self, CP: CarParams, all_footnotes: dict[Enum, int]):
self.car_name = CP.carName
self.car_fingerprint = CP.carFingerprint
@ -316,7 +316,7 @@ class CarDocs:
return self
def init_make(self, CP: car.CarParams):
def init_make(self, CP: CarParams):
"""CarDocs subclasses can add make-specific logic for harness selection, footnotes, etc."""
def get_detail_sentence(self, CP):

View File

@ -1,13 +1,13 @@
from cereal import car
import copy
from opendbc.can.packer import CANPacker
from openpilot.selfdrive.car import apply_std_steer_angle_limits
from openpilot.selfdrive.car import apply_std_steer_angle_limits, structs
from openpilot.selfdrive.car.ford import fordcan
from openpilot.selfdrive.car.ford.values import CarControllerParams, FordFlags
from openpilot.selfdrive.car.common.numpy_fast import clip
from openpilot.selfdrive.car.interfaces import CarControllerBase, V_CRUISE_MAX
LongCtrlState = car.CarControl.Actuators.LongControlState
VisualAlert = car.CarControl.HUDControl.VisualAlert
LongCtrlState = structs.CarControl.Actuators.LongControlState
VisualAlert = structs.CarControl.HUDControl.VisualAlert
def apply_ford_curvature_limits(apply_curvature, apply_curvature_last, current_curvature, v_ego_raw):
@ -111,7 +111,7 @@ class CarController(CarControllerBase):
self.steer_alert_last = steer_alert
self.lead_distance_bars_last = hud_control.leadDistanceBars
new_actuators = actuators.as_builder()
new_actuators = copy.copy(actuators)
new_actuators.curvature = self.apply_curvature_last
self.frame += 1

View File

@ -1,15 +1,14 @@
from cereal import car
from opendbc.can.can_define import CANDefine
from opendbc.can.parser import CANParser
from openpilot.selfdrive.car import create_button_events
from openpilot.selfdrive.car import create_button_events, structs
from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.ford.fordcan import CanBus
from openpilot.selfdrive.car.ford.values import DBC, CarControllerParams, FordFlags
from openpilot.selfdrive.car.interfaces import CarStateBase
ButtonType = car.CarState.ButtonEvent.Type
GearShifter = car.CarState.GearShifter
TransmissionType = car.CarParams.TransmissionType
ButtonType = structs.CarState.ButtonEvent.Type
GearShifter = structs.CarState.GearShifter
TransmissionType = structs.CarParams.TransmissionType
class CarState(CarStateBase):
@ -21,8 +20,8 @@ class CarState(CarStateBase):
self.distance_button = 0
def update(self, cp, cp_cam, *_):
ret = car.CarState.new_message()
def update(self, cp, cp_cam, *_) -> structs.CarState:
ret = structs.CarState()
# Occasionally on startup, the ABS module recalibrates the steering pinion offset, so we need to block engagement
# The vehicle usually recovers out of this state within a minute of normal driving

View File

@ -1,7 +1,7 @@
from cereal import car
from openpilot.selfdrive.car.structs import CarParams
from openpilot.selfdrive.car.ford.values import CAR
Ecu = car.CarParams.Ecu
Ecu = CarParams.Ecu
FW_VERSIONS = {
CAR.FORD_BRONCO_SPORT_MK1: {

View File

@ -1,7 +1,6 @@
from cereal import car
from openpilot.selfdrive.car import CanBusBase
from openpilot.selfdrive.car import CanBusBase, structs
HUDControl = car.CarControl.HUDControl
HUDControl = structs.CarControl.HUDControl
class CanBus(CanBusBase):

View File

@ -1,29 +1,28 @@
from cereal import car
from panda import Panda
from openpilot.selfdrive.car import get_safety_config
from openpilot.selfdrive.car import get_safety_config, structs
from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.ford.fordcan import CanBus
from openpilot.selfdrive.car.ford.values import Ecu, FordFlags
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
TransmissionType = car.CarParams.TransmissionType
TransmissionType = structs.CarParams.TransmissionType
class CarInterface(CarInterfaceBase):
@staticmethod
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs):
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, experimental_long, docs) -> structs.CarParams:
ret.carName = "ford"
ret.dashcamOnly = bool(ret.flags & FordFlags.CANFD)
ret.radarUnavailable = True
ret.steerControlType = car.CarParams.SteerControlType.angle
ret.steerControlType = structs.CarParams.SteerControlType.angle
ret.steerActuatorDelay = 0.2
ret.steerLimitTimer = 1.0
CAN = CanBus(fingerprint=fingerprint)
cfgs = [get_safety_config(car.CarParams.SafetyModel.ford)]
cfgs = [get_safety_config(structs.CarParams.SafetyModel.ford)]
if CAN.main >= 4:
cfgs.insert(0, get_safety_config(car.CarParams.SafetyModel.noOutput))
cfgs.insert(0, get_safety_config(structs.CarParams.SafetyModel.noOutput))
ret.safetyConfigs = cfgs
ret.experimentalLongitudinalAvailable = True

View File

@ -1,6 +1,6 @@
from math import cos, sin
from cereal import car
from opendbc.can.parser import CANParser
from openpilot.selfdrive.car import structs
from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.ford.fordcan import CanBus
from openpilot.selfdrive.car.ford.values import DBC, RADAR
@ -58,7 +58,7 @@ class RadarInterface(RadarInterfaceBase):
if self.trigger_msg not in self.updated_messages:
return None
ret = car.RadarData.new_message()
ret = structs.RadarData()
errors = []
if not self.rcp.can_valid:
errors.append("canError")
@ -89,7 +89,7 @@ class RadarInterface(RadarInterfaceBase):
# radar point only valid if there have been enough valid measurements
if self.valid_cnt[ii] > 0:
if ii not in self.pts:
self.pts[ii] = car.RadarData.RadarPoint.new_message()
self.pts[ii] = structs.RadarData.RadarPoint()
self.pts[ii].trackId = self.track_id
self.track_id += 1
self.pts[ii].dRel = cpt['X_Rel'] # from front of car
@ -112,7 +112,7 @@ class RadarInterface(RadarInterfaceBase):
i = (ii - 1) * 4 + scanIndex
if i not in self.pts:
self.pts[i] = car.RadarData.RadarPoint.new_message()
self.pts[i] = structs.RadarData.RadarPoint()
self.pts[i].trackId = self.track_id
self.pts[i].aRel = float('nan')
self.pts[i].yvRel = float('nan')

View File

@ -1,30 +1,28 @@
#!/usr/bin/env python3
from collections import defaultdict
from cereal import car
from openpilot.selfdrive.car.structs import CarParams
from openpilot.selfdrive.car.ford.values import get_platform_codes
from openpilot.selfdrive.car.ford.fingerprints import FW_VERSIONS
Ecu = car.CarParams.Ecu
ECU_NAME = {v: k for k, v in Ecu.schema.enumerants.items()}
Ecu = CarParams.Ecu
if __name__ == "__main__":
cars_for_code: defaultdict = defaultdict(lambda: defaultdict(set))
for car_model, ecus in FW_VERSIONS.items():
print(car_model)
for ecu in sorted(ecus, key=lambda x: int(x[0])):
for ecu in sorted(ecus):
platform_codes = get_platform_codes(ecus[ecu])
for code in platform_codes:
cars_for_code[ecu][code].add(car_model)
print(f' (Ecu.{ECU_NAME[ecu[0]]}, {hex(ecu[1])}, {ecu[2]}):')
print(f' (Ecu.{ecu[0]}, {hex(ecu[1])}, {ecu[2]}):')
print(f' Codes: {sorted(platform_codes)}')
print()
print('\nCar models vs. platform codes:')
for ecu, codes in cars_for_code.items():
print(f' (Ecu.{ECU_NAME[ecu[0]]}, {hex(ecu[1])}, {ecu[2]}):')
print(f' (Ecu.{ecu[0]}, {hex(ecu[1])}, {ecu[2]}):')
for code, cars in codes.items():
print(f' {code!r}: {sorted(map(str, cars))}')

View File

@ -1,16 +1,15 @@
import random
from collections.abc import Iterable
import capnp
from hypothesis import settings, given, strategies as st
from parameterized import parameterized
from cereal import car
from openpilot.selfdrive.car.structs import CarParams
from openpilot.selfdrive.car.fw_versions import build_fw_dict
from openpilot.selfdrive.car.ford.values import CAR, FW_QUERY_CONFIG, FW_PATTERN, get_platform_codes
from openpilot.selfdrive.car.ford.fingerprints import FW_VERSIONS
Ecu = car.CarParams.Ecu
Ecu = CarParams.Ecu
ECU_ADDRESSES = {
@ -49,7 +48,7 @@ class TestFordFW:
assert subaddr is None, "Unexpected ECU subaddress"
@parameterized.expand(FW_VERSIONS.items())
def test_fw_versions(self, car_model: str, fw_versions: dict[tuple[capnp.lib.capnp._EnumModule, int, int | None], Iterable[bytes]]):
def test_fw_versions(self, car_model: str, fw_versions: dict[tuple[Ecu, int, int | None], Iterable[bytes]]):
for (ecu, addr, subaddr), fws in fw_versions.items():
assert ecu in ECU_PART_NUMBER, "Unexpected ECU"
assert addr == ECU_ADDRESSES[ecu], "ECU address mismatch"
@ -93,10 +92,10 @@ class TestFordFW:
for ecu, fw_versions in fw_by_addr.items():
ecu_name, addr, sub_addr = ecu
fw = random.choice(fw_versions)
car_fw.append({"ecu": ecu_name, "fwVersion": fw, "address": addr,
"subAddress": 0 if sub_addr is None else sub_addr})
car_fw.append(CarParams.CarFw(ecu=ecu_name, fwVersion=fw, address=addr,
subAddress=0 if sub_addr is None else sub_addr))
CP = car.CarParams.new_message(carFw=car_fw)
CP = CarParams(carFw=car_fw)
matches = FW_QUERY_CONFIG.match_fw_to_car_fuzzy(build_fw_dict(CP.carFw), CP.carVin, FW_VERSIONS)
assert matches == {platform}

View File

@ -4,13 +4,13 @@ from dataclasses import dataclass, field, replace
from enum import Enum, IntFlag
import panda.python.uds as uds
from cereal import car
from openpilot.selfdrive.car import AngleRateLimit, CarSpecs, dbc_dict, DbcDict, PlatformConfig, Platforms
from openpilot.selfdrive.car.structs import CarParams
from openpilot.selfdrive.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column, \
Device
from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, LiveFwVersions, OfflineFwVersions, Request, StdQueries, p16
Ecu = car.CarParams.Ecu
Ecu = CarParams.Ecu
class CarControllerParams:
@ -65,7 +65,7 @@ class FordCarDocs(CarDocs):
hybrid: bool = False
plug_in_hybrid: bool = False
def init_make(self, CP: car.CarParams):
def init_make(self, CP: CarParams):
harness = CarHarness.ford_q4 if CP.flags & FordFlags.CANFD else CarHarness.ford_q3
if CP.carFingerprint in (CAR.FORD_BRONCO_SPORT_MK1, CAR.FORD_MAVERICK_MK1, CAR.FORD_F_150_MK14, CAR.FORD_F_150_LIGHTNING_MK1):
self.car_parts = CarParts([Device.threex_angled_mount, harness])

View File

@ -1,4 +1,3 @@
import capnp
import copy
from dataclasses import dataclass, field
import struct
@ -6,9 +5,11 @@ from collections.abc import Callable
import panda.python.uds as uds
from openpilot.selfdrive.car.structs import CarParams
AddrType = tuple[int, int | None]
EcuAddrBusType = tuple[int, int | None, int]
EcuAddrSubAddr = tuple[int, int, int | None]
EcuAddrSubAddr = tuple[CarParams.Ecu, int, int | None]
LiveFwVersions = dict[AddrType, set[bytes]]
OfflineFwVersions = dict[str, dict[EcuAddrSubAddr, list[bytes]]]
@ -77,7 +78,7 @@ class StdQueries:
class Request:
request: list[bytes]
response: list[bytes]
whitelist_ecus: list[int] = field(default_factory=list)
whitelist_ecus: list[CarParams.Ecu] = field(default_factory=list)
rx_offset: int = 0x8
bus: int = 1
# Whether this query should be run on the first auxiliary panda (CAN FD cars for example)
@ -93,9 +94,9 @@ class FwQueryConfig:
requests: list[Request]
# TODO: make this automatic and remove hardcoded lists, or do fingerprinting with ecus
# Overrides and removes from essential ecus for specific models and ecus (exact matching)
non_essential_ecus: dict[capnp.lib.capnp._EnumModule, list[str]] = field(default_factory=dict)
non_essential_ecus: dict[CarParams.Ecu, list[str]] = field(default_factory=dict)
# Ecus added for data collection, not to be fingerprinted on
extra_ecus: list[tuple[capnp.lib.capnp._EnumModule, int, int | None]] = field(default_factory=list)
extra_ecus: list[tuple[CarParams.Ecu, int, int | None]] = field(default_factory=list)
# Function a brand can implement to provide better fuzzy matching. Takes in FW versions and VIN,
# returns set of candidates. Only will match if one candidate is returned
match_fw_to_car_fuzzy: Callable[[LiveFwVersions, str, OfflineFwVersions], set[str]] | None = None

View File

@ -3,19 +3,18 @@ from collections.abc import Callable, Iterator
from typing import Protocol, TypeVar
from tqdm import tqdm
import capnp
import panda.python.uds as uds
from cereal import car
from openpilot.selfdrive.car import carlog
from openpilot.selfdrive.car.can_definitions import CanRecvCallable, CanSendCallable
from openpilot.selfdrive.car.structs import CarParams
from openpilot.selfdrive.car.ecu_addrs import get_ecu_addrs
from openpilot.selfdrive.car.fingerprints import FW_VERSIONS
from openpilot.selfdrive.car.can_definitions import CanRecvCallable, CanSendCallable
from openpilot.selfdrive.car.fw_query_definitions import AddrType, EcuAddrBusType, FwQueryConfig, LiveFwVersions, OfflineFwVersions
from openpilot.selfdrive.car.interfaces import get_interface_attr
from openpilot.selfdrive.car.isotp_parallel_query import IsoTpParallelQuery
Ecu = car.CarParams.Ecu
Ecu = CarParams.Ecu
ESSENTIAL_ECUS = [Ecu.engine, Ecu.eps, Ecu.abs, Ecu.fwdRadar, Ecu.fwdCamera, Ecu.vsa]
FUZZY_EXCLUDE_ECUS = [Ecu.fwdCamera, Ecu.fwdRadar, Ecu.eps, Ecu.debug]
@ -39,7 +38,7 @@ def is_brand(brand: str, filter_brand: str | None) -> bool:
return filter_brand is None or brand == filter_brand
def build_fw_dict(fw_versions: list[capnp.lib.capnp._DynamicStructBuilder], filter_brand: str = None) -> dict[AddrType, set[bytes]]:
def build_fw_dict(fw_versions: list[CarParams.CarFw], filter_brand: str = None) -> dict[AddrType, set[bytes]]:
fw_versions_dict: defaultdict[AddrType, set[bytes]] = defaultdict(set)
for fw in fw_versions:
if is_brand(fw.brand, filter_brand) and not fw.logging:
@ -144,8 +143,8 @@ def match_fw_to_car_exact(live_fw_versions: LiveFwVersions, match_brand: str = N
return set(candidates.keys()) - invalid
def match_fw_to_car(fw_versions: list[capnp.lib.capnp._DynamicStructBuilder], vin: str,
allow_exact: bool = True, allow_fuzzy: bool = True, log: bool = True) -> tuple[bool, set[str]]:
def match_fw_to_car(fw_versions: list[CarParams.CarFw], vin: str, allow_exact: bool = True,
allow_fuzzy: bool = True, log: bool = True) -> tuple[bool, set[str]]:
# Try exact matching first
exact_matches: list[tuple[bool, MatchFwToCar]] = []
if allow_exact:
@ -229,7 +228,7 @@ def get_brand_ecu_matches(ecu_rx_addrs: set[EcuAddrBusType]) -> dict[str, set[Ad
def get_fw_versions_ordered(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_multiplexing: ObdCallback, vin: str,
ecu_rx_addrs: set[EcuAddrBusType], timeout: float = 0.1, num_pandas: int = 1, debug: bool = False,
progress: bool = False) -> list[capnp.lib.capnp._DynamicStructBuilder]:
progress: bool = False) -> list[CarParams.CarFw]:
"""Queries for FW versions ordering brands by likelihood, breaks when exact match is found"""
all_car_fw = []
@ -254,7 +253,7 @@ def get_fw_versions_ordered(can_recv: CanRecvCallable, can_send: CanSendCallable
def get_fw_versions(can_recv: CanRecvCallable, can_send: CanSendCallable, set_obd_multiplexing: ObdCallback, query_brand: str = None,
extra: OfflineFwVersions = None, timeout: float = 0.1, num_pandas: int = 1, debug: bool = False,
progress: bool = False) -> list[capnp.lib.capnp._DynamicStructBuilder]:
progress: bool = False) -> list[CarParams.CarFw]:
versions = VERSIONS.copy()
if query_brand is not None:
@ -306,7 +305,7 @@ def get_fw_versions(can_recv: CanRecvCallable, can_send: CanSendCallable, set_ob
if query_addrs:
query = IsoTpParallelQuery(can_send, can_recv, r.bus, query_addrs, r.request, r.response, r.rx_offset, debug=debug)
for (tx_addr, sub_addr), version in query.get_data(timeout).items():
f = car.CarParams.CarFw.new_message()
f = CarParams.CarFw()
f.ecu = ecu_types.get((brand, tx_addr, sub_addr), Ecu.unknown)
f.fwVersion = version

View File

@ -1,15 +1,15 @@
from cereal import car
import copy
from opendbc.can.packer import CANPacker
from openpilot.selfdrive.car import DT_CTRL, apply_driver_steer_torque_limits
from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car import DT_CTRL, apply_driver_steer_torque_limits, structs
from openpilot.selfdrive.car.gm import gmcan
from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.gm.values import DBC, CanBus, CarControllerParams, CruiseButtons
from openpilot.selfdrive.car.common.numpy_fast import interp
from openpilot.selfdrive.car.interfaces import CarControllerBase
VisualAlert = car.CarControl.HUDControl.VisualAlert
NetworkLocation = car.CarParams.NetworkLocation
LongCtrlState = car.CarControl.Actuators.LongControlState
VisualAlert = structs.CarControl.HUDControl.VisualAlert
NetworkLocation = structs.CarParams.NetworkLocation
LongCtrlState = structs.CarControl.Actuators.LongControlState
# Camera cancels up to 0.1s after brake is pressed, ECM allows 0.5s
CAMERA_CANCEL_DELAY_FRAMES = 10
@ -153,7 +153,7 @@ class CarController(CarControllerBase):
if self.frame % 10 == 0:
can_sends.append(gmcan.create_pscm_status(self.packer_pt, CanBus.CAMERA, CS.pscm_status))
new_actuators = actuators.as_builder()
new_actuators = copy.copy(actuators)
new_actuators.steer = self.apply_steer_last / self.params.STEER_MAX
new_actuators.steerOutputCan = self.apply_steer_last
new_actuators.gas = self.apply_gas

View File

@ -1,16 +1,15 @@
import copy
from cereal import car
from opendbc.can.can_define import CANDefine
from opendbc.can.parser import CANParser
from openpilot.selfdrive.car import create_button_events
from openpilot.selfdrive.car import create_button_events, structs
from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.common.numpy_fast import mean
from openpilot.selfdrive.car.interfaces import CarStateBase
from openpilot.selfdrive.car.gm.values import DBC, AccState, CanBus, CruiseButtons, STEER_THRESHOLD
ButtonType = car.CarState.ButtonEvent.Type
TransmissionType = car.CarParams.TransmissionType
NetworkLocation = car.CarParams.NetworkLocation
ButtonType = structs.CarState.ButtonEvent.Type
TransmissionType = structs.CarParams.TransmissionType
NetworkLocation = structs.CarParams.NetworkLocation
STANDSTILL_THRESHOLD = 10 * 0.0311 * CV.KPH_TO_MS
@ -34,8 +33,8 @@ class CarState(CarStateBase):
self.distance_button = 0
def update(self, pt_cp, cam_cp, _, __, loopback_cp):
ret = car.CarState.new_message()
def update(self, pt_cp, cam_cp, _, __, loopback_cp) -> structs.CarState:
ret = structs.CarState()
prev_cruise_buttons = self.cruise_buttons
prev_distance_button = self.distance_button

View File

@ -1,18 +1,17 @@
#!/usr/bin/env python3
import os
from cereal import car
from math import fabs, exp
from panda import Panda
from openpilot.selfdrive.car import get_safety_config, get_friction
from openpilot.selfdrive.car import get_safety_config, get_friction, structs
from openpilot.selfdrive.car.common.basedir import BASEDIR
from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.gm.radar_interface import RADAR_HEADER_MSG
from openpilot.selfdrive.car.gm.values import CAR, CarControllerParams, EV_CAR, CAMERA_ACC_CAR, CanBus
from openpilot.selfdrive.car.interfaces import CarInterfaceBase, TorqueFromLateralAccelCallbackType, FRICTION_THRESHOLD, LatControlInputs, NanoFFModel
TransmissionType = car.CarParams.TransmissionType
NetworkLocation = car.CarParams.NetworkLocation
TransmissionType = structs.CarParams.TransmissionType
NetworkLocation = structs.CarParams.NetworkLocation
NON_LINEAR_TORQUE_PARAMS = {
CAR.CHEVROLET_BOLT_EUV: [2.6531724862969748, 1.0, 0.1919764879840985, 0.009054123646805178],
@ -41,8 +40,8 @@ class CarInterface(CarInterfaceBase):
else:
return CarInterfaceBase.get_steer_feedforward_default
def torque_from_lateral_accel_siglin(self, latcontrol_inputs: LatControlInputs, torque_params: car.CarParams.LateralTorqueTuning, lateral_accel_error: float,
lateral_accel_deadzone: float, friction_compensation: bool, gravity_adjusted: bool) -> float:
def torque_from_lateral_accel_siglin(self, latcontrol_inputs: LatControlInputs, torque_params: structs.CarParams.LateralTorqueTuning,
lateral_accel_error: float, lateral_accel_deadzone: float, friction_compensation: bool, gravity_adjusted: bool) -> float:
friction = get_friction(lateral_accel_error, lateral_accel_deadzone, FRICTION_THRESHOLD, torque_params, friction_compensation)
def sig(val):
@ -57,14 +56,14 @@ class CarInterface(CarInterfaceBase):
# An important thing to consider is that the slope at 0 should be > 0 (ideally >1)
# This has big effect on the stability about 0 (noise when going straight)
# ToDo: To generalize to other GMs, explore tanh function as the nonlinear
non_linear_torque_params = NON_LINEAR_TORQUE_PARAMS.get(self.CP.carFingerprint)
non_linear_torque_params = NON_LINEAR_TORQUE_PARAMS.get(self.CP.carFingerprint) # type: ignore[call-overload]
assert non_linear_torque_params, "The params are not defined"
a, b, c, _ = non_linear_torque_params
steer_torque = (sig(latcontrol_inputs.lateral_acceleration * a) * b) + (latcontrol_inputs.lateral_acceleration * c)
return float(steer_torque) + friction
def torque_from_lateral_accel_neural(self, latcontrol_inputs: LatControlInputs, torque_params: car.CarParams.LateralTorqueTuning, lateral_accel_error: float,
lateral_accel_deadzone: float, friction_compensation: bool, gravity_adjusted: bool) -> float:
def torque_from_lateral_accel_neural(self, latcontrol_inputs: LatControlInputs, torque_params: structs.CarParams.LateralTorqueTuning,
lateral_accel_error: float, lateral_accel_deadzone: float, friction_compensation: bool, gravity_adjusted: bool) -> float:
friction = get_friction(lateral_accel_error, lateral_accel_deadzone, FRICTION_THRESHOLD, torque_params, friction_compensation)
inputs = list(latcontrol_inputs)
if gravity_adjusted:
@ -81,9 +80,9 @@ class CarInterface(CarInterfaceBase):
return self.torque_from_lateral_accel_linear
@staticmethod
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs):
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, experimental_long, docs) -> structs.CarParams:
ret.carName = "gm"
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.gm)]
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.gm)]
ret.autoResumeSng = False
ret.enableBsm = 0x142 in fingerprint[CanBus.POWERTRAIN]

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python3
import math
from cereal import car
from opendbc.can.parser import CANParser
from openpilot.selfdrive.car import structs
from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.gm.values import DBC, CanBus
from openpilot.selfdrive.car.interfaces import RadarInterfaceBase
@ -52,7 +52,7 @@ class RadarInterface(RadarInterfaceBase):
if self.trigger_msg not in self.updated_messages:
return None
ret = car.RadarData.new_message()
ret = structs.RadarData()
header = self.rcp.vl[RADAR_HEADER_MSG]
fault = header['FLRRSnsrBlckd'] or header['FLRRSnstvFltPrsntInt'] or \
header['FLRRYawRtPlsblityFlt'] or header['FLRRHWFltPrsntInt'] or \
@ -82,7 +82,7 @@ class RadarInterface(RadarInterfaceBase):
targetId = cpt['TrkObjectID']
currentTargets.add(targetId)
if targetId not in self.pts:
self.pts[targetId] = car.RadarData.RadarPoint.new_message()
self.pts[targetId] = structs.RadarData.RadarPoint()
self.pts[targetId].trackId = targetId
distance = cpt['TrkRange']
self.pts[targetId].dRel = distance # from front of car

View File

@ -1,11 +1,11 @@
from dataclasses import dataclass, field
from cereal import car
from openpilot.selfdrive.car import dbc_dict, PlatformConfig, DbcDict, Platforms, CarSpecs
from openpilot.selfdrive.car.structs import CarParams
from openpilot.selfdrive.car.docs_definitions import CarHarness, CarDocs, CarParts
from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries
Ecu = car.CarParams.Ecu
Ecu = CarParams.Ecu
class CarControllerParams:
@ -63,8 +63,8 @@ class CarControllerParams:
class GMCarDocs(CarDocs):
package: str = "Adaptive Cruise Control (ACC)"
def init_make(self, CP: car.CarParams):
if CP.networkLocation == car.CarParams.NetworkLocation.fwdCamera:
def init_make(self, CP: CarParams):
if CP.networkLocation == CarParams.NetworkLocation.fwdCamera:
self.car_parts = CarParts.common([CarHarness.gm])
else:
self.car_parts = CarParts.common([CarHarness.obd_ii])

View File

@ -1,15 +1,15 @@
import copy
from collections import namedtuple
from cereal import car
from opendbc.can.packer import CANPacker
from openpilot.selfdrive.car import DT_CTRL, rate_limit, make_tester_present_msg
from openpilot.selfdrive.car import DT_CTRL, rate_limit, make_tester_present_msg, structs
from openpilot.selfdrive.car.common.numpy_fast import clip, interp
from openpilot.selfdrive.car.honda import hondacan
from openpilot.selfdrive.car.honda.values import CruiseButtons, VISUAL_HUD, HONDA_BOSCH, HONDA_BOSCH_RADARLESS, HONDA_NIDEC_ALT_PCM_ACCEL, CarControllerParams
from openpilot.selfdrive.car.interfaces import CarControllerBase
VisualAlert = car.CarControl.HUDControl.VisualAlert
LongCtrlState = car.CarControl.Actuators.LongControlState
VisualAlert = structs.CarControl.HUDControl.VisualAlert
LongCtrlState = structs.CarControl.Actuators.LongControlState
def compute_gb_honda_bosch(accel, speed):
@ -83,11 +83,11 @@ def process_hud_alert(hud_alert):
# priority is: FCW, steer required, all others
if hud_alert == VisualAlert.fcw:
fcw_display = VISUAL_HUD[hud_alert.raw]
fcw_display = VISUAL_HUD[hud_alert]
elif hud_alert in (VisualAlert.steerRequired, VisualAlert.ldw):
steer_required = VISUAL_HUD[hud_alert.raw]
steer_required = VISUAL_HUD[hud_alert]
else:
acc_alert = VISUAL_HUD[hud_alert.raw]
acc_alert = VISUAL_HUD[hud_alert]
return fcw_display, steer_required, acc_alert
@ -242,7 +242,7 @@ class CarController(CarControllerBase):
self.speed = pcm_speed
self.gas = pcm_accel / self.params.NIDEC_GAS_MAX
new_actuators = actuators.as_builder()
new_actuators = copy.copy(actuators)
new_actuators.speed = self.speed
new_actuators.accel = self.accel
new_actuators.gas = self.gas

View File

@ -1,9 +1,8 @@
from collections import defaultdict
from cereal import car
from opendbc.can.can_define import CANDefine
from opendbc.can.parser import CANParser
from openpilot.selfdrive.car import create_button_events
from openpilot.selfdrive.car import create_button_events, structs
from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.common.numpy_fast import interp
from openpilot.selfdrive.car.honda.hondacan import CanBus, get_cruise_speed_conversion
@ -12,8 +11,8 @@ from openpilot.selfdrive.car.honda.values import CAR, DBC, STEER_THRESHOLD, HOND
HondaFlags, CruiseButtons, CruiseSettings
from openpilot.selfdrive.car.interfaces import CarStateBase
TransmissionType = car.CarParams.TransmissionType
ButtonType = car.CarState.ButtonEvent.Type
TransmissionType = structs.CarParams.TransmissionType
ButtonType = structs.CarState.ButtonEvent.Type
BUTTONS_DICT = {CruiseButtons.RES_ACCEL: ButtonType.accelCruise, CruiseButtons.DECEL_SET: ButtonType.decelCruise,
CruiseButtons.MAIN: ButtonType.altButton3, CruiseButtons.CANCEL: ButtonType.cancel}
@ -110,8 +109,8 @@ class CarState(CarStateBase):
# However, on cars without a digital speedometer this is not always present (HRV, FIT, CRV 2016, ILX and RDX)
self.dash_speed_seen = False
def update(self, cp, cp_cam, _, cp_body, __):
ret = car.CarState.new_message()
def update(self, cp, cp_cam, _, cp_body, __) -> structs.CarState:
ret = structs.CarState()
# car params
v_weight_v = [0., 1.] # don't trust smooth speed at low values to avoid premature zero snapping
@ -198,7 +197,7 @@ class CarState(CarStateBase):
ret.steeringTorque = cp.vl["STEER_STATUS"]["STEER_TORQUE_SENSOR"]
ret.steeringTorqueEps = cp.vl["STEER_MOTOR_TORQUE"]["MOTOR_TORQUE"]
ret.steeringPressed = abs(ret.steeringTorque) > STEER_THRESHOLD.get(self.CP.carFingerprint, 1200)
ret.steeringPressed = abs(ret.steeringTorque) > STEER_THRESHOLD.get(self.CP.carFingerprint, 1200) # type: ignore[call-overload]
if self.CP.carFingerprint in HONDA_BOSCH:
# The PCM always manages its own cruise control state, but doesn't publish it

View File

@ -1,7 +1,7 @@
from cereal import car
from openpilot.selfdrive.car.structs import CarParams
from openpilot.selfdrive.car.honda.values import CAR
Ecu = car.CarParams.Ecu
Ecu = CarParams.Ecu
# Modified FW can be identified by the second dash being replaced by a comma
# For example: `b'39990-TVA,A150\x00\x00'`

View File

@ -1,16 +1,15 @@
#!/usr/bin/env python3
from cereal import car
from panda import Panda
from openpilot.selfdrive.car import get_safety_config, structs
from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.common.numpy_fast import interp
from openpilot.selfdrive.car.honda.hondacan import CanBus
from openpilot.selfdrive.car.honda.values import CarControllerParams, HondaFlags, CAR, HONDA_BOSCH, \
HONDA_NIDEC_ALT_SCM_MESSAGES, HONDA_BOSCH_RADARLESS
from openpilot.selfdrive.car import get_safety_config
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
from openpilot.selfdrive.car.disable_ecu import disable_ecu
TransmissionType = car.CarParams.TransmissionType
TransmissionType = structs.CarParams.TransmissionType
class CarInterface(CarInterfaceBase):
@ -26,13 +25,13 @@ class CarInterface(CarInterfaceBase):
return CarControllerParams.NIDEC_ACCEL_MIN, interp(current_speed, ACCEL_MAX_BP, ACCEL_MAX_VALS)
@staticmethod
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs):
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, experimental_long, docs) -> structs.CarParams:
ret.carName = "honda"
CAN = CanBus(ret, fingerprint)
if candidate in HONDA_BOSCH:
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.hondaBosch)]
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.hondaBosch)]
ret.radarUnavailable = True
# Disable the radar and let openpilot control longitudinal
# WARNING: THIS DISABLES AEB!
@ -41,7 +40,7 @@ class CarInterface(CarInterfaceBase):
ret.openpilotLongitudinalControl = experimental_long
ret.pcmCruise = not ret.openpilotLongitudinalControl
else:
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.hondaNidec)]
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.hondaNidec)]
ret.openpilotLongitudinalControl = True
ret.pcmCruise = True

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python3
from cereal import car
from opendbc.can.parser import CANParser
from openpilot.selfdrive.car import structs
from openpilot.selfdrive.car.interfaces import RadarInterfaceBase
from openpilot.selfdrive.car.honda.values import DBC
@ -47,7 +47,7 @@ class RadarInterface(RadarInterfaceBase):
return rr
def _update(self, updated_messages):
ret = car.RadarData.new_message()
ret = structs.RadarData()
for ii in sorted(updated_messages):
cpt = self.rcp.vl[ii]
@ -57,7 +57,7 @@ class RadarInterface(RadarInterfaceBase):
self.radar_wrong_config = cpt['RADAR_STATE'] == 0x69
elif cpt['LONG_DIST'] < 255:
if ii not in self.pts or cpt['NEW_TRACK']:
self.pts[ii] = car.RadarData.RadarPoint.new_message()
self.pts[ii] = structs.RadarData.RadarPoint()
self.pts[ii].trackId = self.track_id
self.track_id += 1
self.pts[ii].dRel = cpt['LONG_DIST'] # from front of car

View File

@ -1,15 +1,14 @@
from dataclasses import dataclass
from enum import Enum, IntFlag
from cereal import car
from panda.python import uds
from openpilot.selfdrive.car import CarSpecs, PlatformConfig, Platforms, dbc_dict
from openpilot.selfdrive.car import CarSpecs, PlatformConfig, Platforms, dbc_dict, structs
from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column
from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries, p16
Ecu = car.CarParams.Ecu
VisualAlert = car.CarControl.HUDControl.VisualAlert
Ecu = structs.CarParams.Ecu
VisualAlert = structs.CarControl.HUDControl.VisualAlert
class CarControllerParams:
@ -90,7 +89,7 @@ VISUAL_HUD = {
class HondaCarDocs(CarDocs):
package: str = "Honda Sensing"
def init_make(self, CP: car.CarParams):
def init_make(self, CP: structs.CarParams):
if CP.flags & HondaFlags.BOSCH:
self.car_parts = CarParts.common([CarHarness.bosch_b]) if CP.flags & HondaFlags.BOSCH_RADARLESS else CarParts.common([CarHarness.bosch_a])
else:

View File

@ -1,6 +1,6 @@
from cereal import car
import copy
from opendbc.can.packer import CANPacker
from openpilot.selfdrive.car import DT_CTRL, apply_driver_steer_torque_limits, common_fault_avoidance, make_tester_present_msg
from openpilot.selfdrive.car import DT_CTRL, apply_driver_steer_torque_limits, common_fault_avoidance, make_tester_present_msg, structs
from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.common.numpy_fast import clip
from openpilot.selfdrive.car.hyundai import hyundaicanfd, hyundaican
@ -9,8 +9,8 @@ from openpilot.selfdrive.car.hyundai.hyundaicanfd import CanBus
from openpilot.selfdrive.car.hyundai.values import HyundaiFlags, Buttons, CarControllerParams, CANFD_CAR, CAR
from openpilot.selfdrive.car.interfaces import CarControllerBase
VisualAlert = car.CarControl.HUDControl.VisualAlert
LongCtrlState = car.CarControl.Actuators.LongControlState
VisualAlert = structs.CarControl.HUDControl.VisualAlert
LongCtrlState = structs.CarControl.Actuators.LongControlState
# EPS faults if you apply torque while the steering angle is above 90 degrees for more than 1 second
# All slightly below EPS thresholds to avoid fault
@ -162,7 +162,7 @@ class CarController(CarControllerBase):
if self.frame % 50 == 0 and self.CP.openpilotLongitudinalControl:
can_sends.append(hyundaican.create_frt_radar_opt(self.packer))
new_actuators = actuators.as_builder()
new_actuators = copy.copy(actuators)
new_actuators.steer = apply_steer / self.params.STEER_MAX
new_actuators.steerOutputCan = apply_steer
new_actuators.accel = accel
@ -170,7 +170,7 @@ class CarController(CarControllerBase):
self.frame += 1
return new_actuators, can_sends
def create_button_messages(self, CC: car.CarControl, CS: CarState, use_clu11: bool):
def create_button_messages(self, CC: structs.CarControl, CS: CarState, use_clu11: bool):
can_sends = []
if use_clu11:
if CC.cruiseControl.cancel:

View File

@ -2,17 +2,16 @@ from collections import deque
import copy
import math
from cereal import car
from opendbc.can.parser import CANParser
from opendbc.can.can_define import CANDefine
from openpilot.selfdrive.car import create_button_events
from openpilot.selfdrive.car import create_button_events, structs
from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.hyundai.hyundaicanfd import CanBus
from openpilot.selfdrive.car.hyundai.values import HyundaiFlags, CAR, DBC, CAN_GEARS, CAMERA_SCC_CAR, \
CANFD_CAR, Buttons, CarControllerParams
from openpilot.selfdrive.car.interfaces import CarStateBase
ButtonType = car.CarState.ButtonEvent.Type
ButtonType = structs.CarState.ButtonEvent.Type
PREV_BUTTON_SAMPLES = 8
CLUSTER_SAMPLE_RATE = 20 # frames
@ -58,11 +57,11 @@ class CarState(CarStateBase):
self.params = CarControllerParams(CP)
def update(self, cp, cp_cam, *_):
def update(self, cp, cp_cam, *_) -> structs.CarState:
if self.CP.carFingerprint in CANFD_CAR:
return self.update_canfd(cp, cp_cam)
ret = car.CarState.new_message()
ret = structs.CarState()
cp_cruise = cp_cam if self.CP.carFingerprint in CAMERA_SCC_CAR else cp
self.is_metric = cp.vl["CLU11"]["CF_Clu_SPEED_UNIT"] == 0
speed_conv = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS
@ -177,8 +176,8 @@ class CarState(CarStateBase):
return ret
def update_canfd(self, cp, cp_cam):
ret = car.CarState.new_message()
def update_canfd(self, cp, cp_cam) -> structs.CarState:
ret = structs.CarState()
self.is_metric = cp.vl["CRUISE_BUTTONS_ALT"]["DISTANCE_UNIT"] != 1
speed_factor = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS

View File

@ -1,7 +1,7 @@
from cereal import car
from openpilot.selfdrive.car.structs import CarParams
from openpilot.selfdrive.car.hyundai.values import CAR
Ecu = car.CarParams.Ecu
Ecu = CarParams.Ecu
# The existence of SCC or RDR in the fwdRadar FW usually determines the radar's function,
# i.e. if it sends the SCC messages or if another ECU like the camera or ADAS Driving ECU does

View File

@ -1,6 +1,5 @@
from cereal import car
from panda import Panda
from openpilot.selfdrive.car import get_safety_config
from openpilot.selfdrive.car import get_safety_config, structs
from openpilot.selfdrive.car.hyundai.hyundaicanfd import CanBus
from openpilot.selfdrive.car.hyundai.values import HyundaiFlags, CAR, DBC, CANFD_CAR, CAMERA_SCC_CAR, CANFD_RADAR_SCC_CAR, \
CANFD_UNSUPPORTED_LONGITUDINAL_CAR, EV_CAR, HYBRID_CAR, LEGACY_SAFETY_MODE_CAR, \
@ -9,14 +8,14 @@ from openpilot.selfdrive.car.hyundai.radar_interface import RADAR_START_ADDR
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
from openpilot.selfdrive.car.disable_ecu import disable_ecu
Ecu = car.CarParams.Ecu
Ecu = structs.CarParams.Ecu
ENABLE_BUTTONS = (Buttons.RES_ACCEL, Buttons.SET_DECEL, Buttons.CANCEL)
class CarInterface(CarInterfaceBase):
@staticmethod
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs):
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, experimental_long, docs) -> structs.CarParams:
ret.carName = "hyundai"
ret.radarUnavailable = RADAR_START_ADDR not in fingerprint[1] or DBC[ret.carFingerprint]["radar"] is None
@ -97,9 +96,9 @@ class CarInterface(CarInterfaceBase):
# *** panda safety config ***
if candidate in CANFD_CAR:
cfgs = [get_safety_config(car.CarParams.SafetyModel.hyundaiCanfd), ]
cfgs = [get_safety_config(structs.CarParams.SafetyModel.hyundaiCanfd), ]
if CAN.ECAN >= 4:
cfgs.insert(0, get_safety_config(car.CarParams.SafetyModel.noOutput))
cfgs.insert(0, get_safety_config(structs.CarParams.SafetyModel.noOutput))
ret.safetyConfigs = cfgs
if ret.flags & HyundaiFlags.CANFD_HDA2:
@ -113,9 +112,9 @@ class CarInterface(CarInterfaceBase):
else:
if candidate in LEGACY_SAFETY_MODE_CAR:
# these cars require a special panda safety mode due to missing counters and checksums in the messages
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.hyundaiLegacy)]
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.hyundaiLegacy)]
else:
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.hyundai, 0)]
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.hyundai, 0)]
if candidate in CAMERA_SCC_CAR:
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_HYUNDAI_CAMERA_SCC

View File

@ -1,7 +1,7 @@
import math
from cereal import car
from opendbc.can.parser import CANParser
from openpilot.selfdrive.car import structs
from openpilot.selfdrive.car.interfaces import RadarInterfaceBase
from openpilot.selfdrive.car.hyundai.values import DBC
@ -44,7 +44,7 @@ class RadarInterface(RadarInterfaceBase):
return rr
def _update(self, updated_messages):
ret = car.RadarData.new_message()
ret = structs.RadarData()
if self.rcp is None:
return ret
@ -58,7 +58,7 @@ class RadarInterface(RadarInterfaceBase):
msg = self.rcp.vl[f"RADAR_TRACK_{addr:x}"]
if addr not in self.pts:
self.pts[addr] = car.RadarData.RadarPoint.new_message()
self.pts[addr] = structs.RadarData.RadarPoint()
self.pts[addr].trackId = self.track_id
self.track_id += 1

View File

@ -1,22 +1,21 @@
#!/usr/bin/env python3
from cereal import car
from openpilot.selfdrive.car.structs import CarParams
from openpilot.selfdrive.car.hyundai.values import PLATFORM_CODE_ECUS, get_platform_codes
from openpilot.selfdrive.car.hyundai.fingerprints import FW_VERSIONS
Ecu = car.CarParams.Ecu
ECU_NAME = {v: k for k, v in Ecu.schema.enumerants.items()}
Ecu = CarParams.Ecu
if __name__ == "__main__":
for car_model, ecus in FW_VERSIONS.items():
print()
print(car_model)
for ecu in sorted(ecus, key=lambda x: int(x[0])):
for ecu in sorted(ecus):
if ecu[0] not in PLATFORM_CODE_ECUS:
continue
platform_codes = get_platform_codes(ecus[ecu])
codes = {code for code, _ in platform_codes}
dates = {date for _, date in platform_codes if date is not None}
print(f' (Ecu.{ECU_NAME[ecu[0]]}, {hex(ecu[1])}, {ecu[2]}):')
print(f' (Ecu.{ecu[0]}, {hex(ecu[1])}, {ecu[2]}):')
print(f' Codes: {codes}')
print(f' Dates: {dates}')

View File

@ -2,8 +2,8 @@ from hypothesis import settings, given, strategies as st
import pytest
from cereal import car
from openpilot.selfdrive.car import gen_empty_fingerprint
from openpilot.selfdrive.car.structs import CarParams
from openpilot.selfdrive.car.fw_versions import build_fw_dict
from openpilot.selfdrive.car.hyundai.interface import CarInterface
from openpilot.selfdrive.car.hyundai.radar_interface import RADAR_START_ADDR
@ -13,8 +13,7 @@ from openpilot.selfdrive.car.hyundai.values import CAMERA_SCC_CAR, CANFD_CAR, CA
HyundaiFlags, get_platform_codes
from openpilot.selfdrive.car.hyundai.fingerprints import FW_VERSIONS
Ecu = car.CarParams.Ecu
ECU_NAME = {v: k for k, v in Ecu.schema.enumerants.items()}
Ecu = CarParams.Ecu
# Some platforms have date codes in a different format we don't yet parse (or are missing).
# For now, assert list of expected missing date cars
@ -46,7 +45,7 @@ class TestHyundaiFingerprint:
def test_feature_detection(self):
# HDA2
for has_adas in (True, False):
car_fw = [car.CarParams.CarFw(ecu=Ecu.adas if has_adas else Ecu.fwdCamera)]
car_fw = [CarParams.CarFw(ecu=Ecu.adas if has_adas else Ecu.fwdCamera)]
CP = CarInterface.get_params(CAR.KIA_EV6, gen_empty_fingerprint(), car_fw, False, False)
assert bool(CP.flags & HyundaiFlags.CANFD_HDA2) == has_adas
@ -76,7 +75,7 @@ class TestHyundaiFingerprint:
for car_model in CANFD_CAR:
ecus = {fw[0] for fw in FW_VERSIONS[car_model].keys()}
ecus_not_in_whitelist = ecus - CANFD_EXPECTED_ECUS
ecu_strings = ", ".join([f"Ecu.{ECU_NAME[ecu]}" for ecu in ecus_not_in_whitelist])
ecu_strings = ", ".join([f"Ecu.{ecu}" for ecu in ecus_not_in_whitelist])
assert len(ecus_not_in_whitelist) == 0, \
f"{car_model}: Car model has unexpected ECUs: {ecu_strings}"
@ -223,10 +222,10 @@ class TestHyundaiFingerprint:
for ecu, fw_versions in fw_by_addr.items():
ecu_name, addr, sub_addr = ecu
for fw in fw_versions:
car_fw.append({"ecu": ecu_name, "fwVersion": fw, "address": addr,
"subAddress": 0 if sub_addr is None else sub_addr})
car_fw.append(CarParams.CarFw(ecu=ecu_name, fwVersion=fw, address=addr,
subAddress=0 if sub_addr is None else sub_addr))
CP = car.CarParams.new_message(carFw=car_fw)
CP = CarParams(carFw=car_fw)
matches = FW_QUERY_CONFIG.match_fw_to_car_fuzzy(build_fw_dict(CP.carFw), CP.carVin, FW_VERSIONS)
if len(matches) == 1:
assert list(matches)[0] == platform

View File

@ -2,14 +2,14 @@ import re
from dataclasses import dataclass, field
from enum import Enum, IntFlag
from cereal import car
from panda.python import uds
from openpilot.selfdrive.car import CarSpecs, DbcDict, PlatformConfig, Platforms, dbc_dict
from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.structs import CarParams
from openpilot.selfdrive.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column
from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, p16
Ecu = car.CarParams.Ecu
Ecu = CarParams.Ecu
class CarControllerParams:
@ -107,7 +107,7 @@ class Footnote(Enum):
class HyundaiCarDocs(CarDocs):
package: str = "Smart Cruise Control (SCC)"
def init_make(self, CP: car.CarParams):
def init_make(self, CP: CarParams):
if CP.flags & HyundaiFlags.CANFD:
self.footnotes.insert(0, Footnote.CANFD)

View File

@ -8,8 +8,8 @@ from typing import Any, NamedTuple
from collections.abc import Callable
from functools import cache
from cereal import car
from openpilot.selfdrive.car import DT_CTRL, apply_hysteresis, gen_empty_fingerprint, scale_rot_inertia, scale_tire_stiffness, get_friction, STD_CARGO_KG
from openpilot.selfdrive.car import structs
from openpilot.selfdrive.car.can_definitions import CanData, CanRecvCallable, CanSendCallable
from openpilot.selfdrive.car.common.basedir import BASEDIR
from openpilot.selfdrive.car.conversions import Conversions as CV
@ -17,7 +17,7 @@ from openpilot.selfdrive.car.common.simple_kalman import KF1D, get_kalman_gain
from openpilot.selfdrive.car.common.numpy_fast import clip
from openpilot.selfdrive.car.values import PLATFORMS
GearShifter = car.CarState.GearShifter
GearShifter = structs.CarState.GearShifter
V_CRUISE_MAX = 145
MAX_CTRL_SPEED = (V_CRUISE_MAX + 4) * CV.KPH_TO_MS
@ -29,7 +29,7 @@ TORQUE_PARAMS_PATH = os.path.join(BASEDIR, 'torque_data/params.toml')
TORQUE_OVERRIDE_PATH = os.path.join(BASEDIR, 'torque_data/override.toml')
TORQUE_SUBSTITUTE_PATH = os.path.join(BASEDIR, 'torque_data/substitute.toml')
GEAR_SHIFTER_MAP: dict[str, car.CarState.GearShifter] = {
GEAR_SHIFTER_MAP: dict[str, GearShifter] = {
'P': GearShifter.park, 'PARK': GearShifter.park,
'R': GearShifter.reverse, 'REVERSE': GearShifter.reverse,
'N': GearShifter.neutral, 'NEUTRAL': GearShifter.neutral,
@ -49,7 +49,7 @@ class LatControlInputs(NamedTuple):
aego: float
TorqueFromLateralAccelCallbackType = Callable[[LatControlInputs, car.CarParams.LateralTorqueTuning, float, float, bool, bool], float]
TorqueFromLateralAccelCallbackType = Callable[[LatControlInputs, structs.CarParams.LateralTorqueTuning, float, float, bool, bool], float]
@cache
@ -84,7 +84,7 @@ def get_torque_params():
# generic car and radar interfaces
class CarInterfaceBase(ABC):
def __init__(self, CP: car.CarParams, CarController, CarState):
def __init__(self, CP: structs.CarParams, CarController, CarState):
self.CP = CP
self.frame = 0
@ -101,7 +101,7 @@ class CarInterfaceBase(ABC):
dbc_name = "" if self.cp is None else self.cp.dbc_name
self.CC: CarControllerBase = CarController(dbc_name, CP)
def apply(self, c: car.CarControl, now_nanos: int) -> tuple[car.CarControl.Actuators, list[CanData]]:
def apply(self, c: structs.CarControl, now_nanos: int) -> tuple[structs.CarControl.Actuators, list[CanData]]:
return self.CC.update(c, self.CS, now_nanos)
@staticmethod
@ -109,14 +109,15 @@ class CarInterfaceBase(ABC):
return ACCEL_MIN, ACCEL_MAX
@classmethod
def get_non_essential_params(cls, candidate: str) -> car.CarParams:
def get_non_essential_params(cls, candidate: str) -> structs.CarParams:
"""
Parameters essential to controlling the car may be incomplete or wrong without FW versions or fingerprints.
"""
return cls.get_params(candidate, gen_empty_fingerprint(), list(), False, False)
@classmethod
def get_params(cls, candidate: str, fingerprint: dict[int, dict[int, int]], car_fw: list[car.CarParams.CarFw], experimental_long: bool, docs: bool):
def get_params(cls, candidate: str, fingerprint: dict[int, dict[int, int]], car_fw: list[structs.CarParams.CarFw],
experimental_long: bool, docs: bool) -> structs.CarParams:
ret = CarInterfaceBase.get_std_params(candidate)
platform = PLATFORMS[candidate]
@ -143,12 +144,12 @@ class CarInterfaceBase(ABC):
@staticmethod
@abstractmethod
def _get_params(ret: car.CarParams, candidate, fingerprint: dict[int, dict[int, int]],
car_fw: list[car.CarParams.CarFw], experimental_long: bool, docs: bool) -> car.CarParams:
def _get_params(ret: structs.CarParams, candidate, fingerprint: dict[int, dict[int, int]],
car_fw: list[structs.CarParams.CarFw], experimental_long: bool, docs: bool) -> structs.CarParams:
raise NotImplementedError
@staticmethod
def init(CP: car.CarParams, can_recv: CanRecvCallable, can_send: CanSendCallable):
def init(CP: structs.CarParams, can_recv: CanRecvCallable, can_send: CanSendCallable):
pass
@staticmethod
@ -159,7 +160,7 @@ class CarInterfaceBase(ABC):
def get_steer_feedforward_function(self):
return self.get_steer_feedforward_default
def torque_from_lateral_accel_linear(self, latcontrol_inputs: LatControlInputs, torque_params: car.CarParams.LateralTorqueTuning,
def torque_from_lateral_accel_linear(self, latcontrol_inputs: LatControlInputs, torque_params: structs.CarParams.LateralTorqueTuning,
lateral_accel_error: float, lateral_accel_deadzone: float, friction_compensation: bool, gravity_adjusted: bool) -> float:
# The default is a linear relationship between torque and lateral acceleration (accounting for road roll and steering friction)
friction = get_friction(lateral_accel_error, lateral_accel_deadzone, FRICTION_THRESHOLD, torque_params, friction_compensation)
@ -170,8 +171,8 @@ class CarInterfaceBase(ABC):
# returns a set of default params to avoid repetition in car specific params
@staticmethod
def get_std_params(candidate):
ret = car.CarParams.new_message()
def get_std_params(candidate: str) -> structs.CarParams:
ret = structs.CarParams()
ret.carFingerprint = candidate
# Car docs fields
@ -180,7 +181,7 @@ class CarInterfaceBase(ABC):
# standard ALC params
ret.tireStiffnessFactor = 1.0
ret.steerControlType = car.CarParams.SteerControlType.torque
ret.steerControlType = structs.CarParams.SteerControlType.torque
ret.minSteerSpeed = 0.
ret.wheelSpeedFactor = 1.0
@ -204,7 +205,7 @@ class CarInterfaceBase(ABC):
return ret
@staticmethod
def configure_torque_tune(candidate: str, tune: car.CarParams.LateralTuning, steering_angle_deadzone_deg: float = 0.0, use_steering_angle: bool = True):
def configure_torque_tune(candidate: str, tune: structs.CarParams.LateralTuning, steering_angle_deadzone_deg: float = 0.0, use_steering_angle: bool = True):
params = get_torque_params()[candidate]
tune.init('torque')
@ -217,10 +218,10 @@ class CarInterfaceBase(ABC):
tune.torque.latAccelOffset = 0.0
tune.torque.steeringAngleDeadzoneDeg = steering_angle_deadzone_deg
def _update(self) -> car.CarState:
def _update(self) -> structs.CarState:
return self.CS.update(*self.can_parsers)
def update(self, can_packets: list[tuple[int, list[CanData]]]) -> car.CarState:
def update(self, can_packets: list[tuple[int, list[CanData]]]) -> structs.CarState:
# parse can
for cp in self.can_parsers:
if cp is not None:
@ -245,33 +246,33 @@ class CarInterfaceBase(ABC):
if ret.cruiseState.speedCluster == 0:
ret.cruiseState.speedCluster = ret.cruiseState.speed
# copy back for next iteration
self.CS.out = ret.as_reader()
# save for next iteration
self.CS.out = ret
return ret
class RadarInterfaceBase(ABC):
def __init__(self, CP: car.CarParams):
def __init__(self, CP: structs.CarParams):
self.CP = CP
self.rcp = None
self.pts: dict[int, car.RadarData.RadarPoint] = {}
self.pts: dict[int, structs.RadarData.RadarPoint] = {}
self.delay = 0
self.radar_ts = CP.radarTimeStep
self.frame = 0
def update(self, can_strings):
def update(self, can_strings) -> structs.RadarData | None:
self.frame += 1
if (self.frame % int(100 * self.radar_ts)) == 0:
return car.RadarData.new_message()
return structs.RadarData()
return None
class CarStateBase(ABC):
def __init__(self, CP: car.CarParams):
def __init__(self, CP: structs.CarParams):
self.CP = CP
self.car_fingerprint = CP.carFingerprint
self.out = car.CarState.new_message()
self.out = structs.CarState()
self.cruise_buttons = 0
self.left_blinker_cnt = 0
@ -291,7 +292,7 @@ class CarStateBase(ABC):
self.v_ego_kf = KF1D(x0=x0, A=A, C=C[0], K=K)
@abstractmethod
def update(self, cp, cp_cam, cp_adas, cp_body, cp_loopback) -> car.CarState:
def update(self, cp, cp_cam, cp_adas, cp_body, cp_loopback) -> structs.CarState:
pass
def update_speed_kf(self, v_ego_raw):
@ -304,7 +305,7 @@ class CarStateBase(ABC):
def get_wheel_speeds(self, fl, fr, rl, rr, unit=CV.KPH_TO_MS):
factor = unit * self.CP.wheelSpeedFactor
wheelSpeeds = car.CarState.WheelSpeeds.new_message()
wheelSpeeds = structs.CarState.WheelSpeeds()
wheelSpeeds.fl = fl * factor
wheelSpeeds.fr = fr * factor
wheelSpeeds.rl = rl * factor
@ -349,7 +350,7 @@ class CarStateBase(ABC):
return bool(left_blinker_stalk or self.left_blinker_cnt > 0), bool(right_blinker_stalk or self.right_blinker_cnt > 0)
@staticmethod
def parse_gear_shifter(gear: str | None) -> car.CarState.GearShifter:
def parse_gear_shifter(gear: str | None) -> GearShifter:
if gear is None:
return GearShifter.unknown
return GEAR_SHIFTER_MAP.get(gear.upper(), GearShifter.unknown)
@ -376,12 +377,12 @@ class CarStateBase(ABC):
class CarControllerBase(ABC):
def __init__(self, dbc_name: str, CP: car.CarParams):
def __init__(self, dbc_name: str, CP: structs.CarParams):
self.CP = CP
self.frame = 0
@abstractmethod
def update(self, CC: car.CarControl, CS: CarStateBase, now_nanos: int) -> tuple[car.CarControl.Actuators, list[CanData]]:
def update(self, CC: structs.CarControl, CS: CarStateBase, now_nanos: int) -> tuple[structs.CarControl.Actuators, list[CanData]]:
pass

View File

@ -1,11 +1,11 @@
from cereal import car
import copy
from opendbc.can.packer import CANPacker
from openpilot.selfdrive.car import apply_driver_steer_torque_limits
from openpilot.selfdrive.car import apply_driver_steer_torque_limits, structs
from openpilot.selfdrive.car.interfaces import CarControllerBase
from openpilot.selfdrive.car.mazda import mazdacan
from openpilot.selfdrive.car.mazda.values import CarControllerParams, Buttons
VisualAlert = car.CarControl.HUDControl.VisualAlert
VisualAlert = structs.CarControl.HUDControl.VisualAlert
class CarController(CarControllerBase):
@ -57,7 +57,7 @@ class CarController(CarControllerBase):
can_sends.append(mazdacan.create_steering_control(self.packer, self.CP,
self.frame, apply_steer, CS.cam_lkas))
new_actuators = CC.actuators.as_builder()
new_actuators = copy.copy(CC.actuators)
new_actuators.steer = apply_steer / CarControllerParams.STEER_MAX
new_actuators.steerOutputCan = apply_steer

View File

@ -1,12 +1,11 @@
from cereal import car
from opendbc.can.can_define import CANDefine
from opendbc.can.parser import CANParser
from openpilot.selfdrive.car import create_button_events
from openpilot.selfdrive.car import create_button_events, structs
from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.interfaces import CarStateBase
from openpilot.selfdrive.car.mazda.values import DBC, LKAS_LIMITS, MazdaFlags
ButtonType = car.CarState.ButtonEvent.Type
ButtonType = structs.CarState.ButtonEvent.Type
class CarState(CarStateBase):
@ -24,9 +23,9 @@ class CarState(CarStateBase):
self.distance_button = 0
def update(self, cp, cp_cam, *_):
def update(self, cp, cp_cam, *_) -> structs.CarState:
ret = car.CarState.new_message()
ret = structs.CarState()
prev_distance_button = self.distance_button
self.distance_button = cp.vl["CRZ_BTNS"]["DISTANCE_LESS"]

View File

@ -1,7 +1,7 @@
from cereal import car
from openpilot.selfdrive.car.structs import CarParams
from openpilot.selfdrive.car.mazda.values import CAR
Ecu = car.CarParams.Ecu
Ecu = CarParams.Ecu
FW_VERSIONS = {
CAR.MAZDA_CX5_2022: {

View File

@ -1,6 +1,5 @@
#!/usr/bin/env python3
from cereal import car
from openpilot.selfdrive.car import get_safety_config
from openpilot.selfdrive.car import get_safety_config, structs
from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.mazda.values import CAR, LKAS_LIMITS
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
@ -10,9 +9,9 @@ from openpilot.selfdrive.car.interfaces import CarInterfaceBase
class CarInterface(CarInterfaceBase):
@staticmethod
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs):
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, experimental_long, docs) -> structs.CarParams:
ret.carName = "mazda"
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.mazda)]
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.mazda)]
ret.radarUnavailable = True
ret.dashcamOnly = candidate not in (CAR.MAZDA_CX5_2022, CAR.MAZDA_CX9_2021)

View File

@ -1,13 +1,13 @@
from dataclasses import dataclass, field
from enum import IntFlag
from cereal import car
from openpilot.selfdrive.car import CarSpecs, DbcDict, PlatformConfig, Platforms, dbc_dict
from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.structs import CarParams
from openpilot.selfdrive.car.docs_definitions import CarHarness, CarDocs, CarParts
from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries
Ecu = car.CarParams.Ecu
Ecu = CarParams.Ecu
# Steer torque limits

View File

@ -1,5 +1,6 @@
from openpilot.selfdrive.car.interfaces import CarControllerBase
class CarController(CarControllerBase):
def update(self, CC, CS, now_nanos):
return CC.actuators.as_builder(), []
return CC.actuators, []

View File

@ -1,7 +1,7 @@
from cereal import car
from openpilot.selfdrive.car import structs
from openpilot.selfdrive.car.interfaces import CarStateBase
class CarState(CarStateBase):
def update(self, *_) -> car.CarState:
return car.CarState.new_message()
def update(self, *_) -> structs.CarState:
return structs.CarState()

View File

@ -1,4 +1,5 @@
#!/usr/bin/env python3
from openpilot.selfdrive.car import structs
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
@ -6,7 +7,7 @@ from openpilot.selfdrive.car.interfaces import CarInterfaceBase
class CarInterface(CarInterfaceBase):
@staticmethod
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs):
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, experimental_long, docs) -> structs.CarParams:
ret.carName = "mock"
ret.mass = 1700.
ret.wheelbase = 2.70

View File

@ -1,11 +1,11 @@
from cereal import car
import copy
from opendbc.can.packer import CANPacker
from openpilot.selfdrive.car import apply_std_steer_angle_limits
from openpilot.selfdrive.car import apply_std_steer_angle_limits, structs
from openpilot.selfdrive.car.interfaces import CarControllerBase
from openpilot.selfdrive.car.nissan import nissancan
from openpilot.selfdrive.car.nissan.values import CAR, CarControllerParams
VisualAlert = car.CarControl.HUDControl.VisualAlert
VisualAlert = structs.CarControl.HUDControl.VisualAlert
class CarController(CarControllerBase):
@ -74,7 +74,7 @@ class CarController(CarControllerBase):
self.packer, CS.lkas_hud_info_msg, steer_hud_alert
))
new_actuators = actuators.as_builder()
new_actuators = copy.copy(actuators)
new_actuators.steeringAngleDeg = apply_angle
self.frame += 1

View File

@ -1,14 +1,13 @@
import copy
from collections import deque
from cereal import car
from opendbc.can.can_define import CANDefine
from opendbc.can.parser import CANParser
from openpilot.selfdrive.car import create_button_events
from openpilot.selfdrive.car import create_button_events, structs
from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.interfaces import CarStateBase
from openpilot.selfdrive.car.nissan.values import CAR, DBC, CarControllerParams
ButtonType = car.CarState.ButtonEvent.Type
ButtonType = structs.CarState.ButtonEvent.Type
TORQUE_SAMPLES = 12
@ -26,8 +25,8 @@ class CarState(CarStateBase):
self.distance_button = 0
def update(self, cp, cp_cam, cp_adas, *_):
ret = car.CarState.new_message()
def update(self, cp, cp_cam, cp_adas, *_) -> structs.CarState:
ret = structs.CarState()
prev_distance_button = self.distance_button
self.distance_button = cp.vl["CRUISE_THROTTLE"]["FOLLOW_DISTANCE_BUTTON"]

View File

@ -1,8 +1,8 @@
# ruff: noqa: E501
from cereal import car
from openpilot.selfdrive.car.structs import CarParams
from openpilot.selfdrive.car.nissan.values import CAR
Ecu = car.CarParams.Ecu
Ecu = CarParams.Ecu
FINGERPRINTS = {
CAR.NISSAN_XTRAIL: [{

View File

@ -1,6 +1,5 @@
from cereal import car
from panda import Panda
from openpilot.selfdrive.car import get_safety_config
from openpilot.selfdrive.car import get_safety_config, structs
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
from openpilot.selfdrive.car.nissan.values import CAR
@ -8,16 +7,16 @@ from openpilot.selfdrive.car.nissan.values import CAR
class CarInterface(CarInterfaceBase):
@staticmethod
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs):
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, experimental_long, docs) -> structs.CarParams:
ret.carName = "nissan"
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.nissan)]
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.nissan)]
ret.autoResumeSng = False
ret.steerLimitTimer = 1.0
ret.steerActuatorDelay = 0.1
ret.steerControlType = car.CarParams.SteerControlType.angle
ret.steerControlType = structs.CarParams.SteerControlType.angle
ret.radarUnavailable = True
if candidate == CAR.NISSAN_ALTIMA:

View File

@ -1,12 +1,12 @@
from dataclasses import dataclass, field
from cereal import car
from panda.python import uds
from openpilot.selfdrive.car import AngleRateLimit, CarSpecs, DbcDict, PlatformConfig, Platforms, dbc_dict
from openpilot.selfdrive.car.structs import CarParams
from openpilot.selfdrive.car.docs_definitions import CarDocs, CarHarness, CarParts
from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries
Ecu = car.CarParams.Ecu
Ecu = CarParams.Ecu
class CarControllerParams:

499
selfdrive/car/structs.py Normal file
View File

@ -0,0 +1,499 @@
from dataclasses import dataclass as _dataclass, field, is_dataclass
from enum import Enum, StrEnum as _StrEnum, auto
from typing import dataclass_transform, get_origin
AUTO_OBJ = object()
def auto_field():
return AUTO_OBJ
@dataclass_transform()
def auto_dataclass(cls=None, /, **kwargs):
cls_annotations = cls.__dict__.get('__annotations__', {})
for name, typ in cls_annotations.items():
current_value = getattr(cls, name)
if current_value is AUTO_OBJ:
origin_typ = get_origin(typ) or typ
if isinstance(origin_typ, str):
raise TypeError(f"Forward references are not supported for auto_field: '{origin_typ}'. Use a default_factory with lambda instead.")
elif origin_typ in (int, float, str, bytes, list, tuple, bool) or is_dataclass(origin_typ):
setattr(cls, name, field(default_factory=origin_typ))
elif issubclass(origin_typ, Enum): # first enum is the default
setattr(cls, name, field(default=next(iter(origin_typ))))
else:
raise TypeError(f"Unsupported type for auto_field: {origin_typ}")
# TODO: use slots, this prevents accidentally setting attributes that don't exist
return _dataclass(cls, **kwargs)
class StrEnum(_StrEnum):
@staticmethod
def _generate_next_value_(name, *args):
# auto() defaults to name.lower()
return name
@auto_dataclass
class CarState:
# CAN health
canValid: bool = auto_field() # invalid counter/checksums
canTimeout: bool = auto_field() # CAN bus dropped out
canErrorCounter: int = auto_field()
# car speed
vEgo: float = auto_field() # best estimate of speed
aEgo: float = auto_field() # best estimate of acceleration
vEgoRaw: float = auto_field() # unfiltered speed from CAN sensors
vEgoCluster: float = auto_field() # best estimate of speed shown on car's instrument cluster, used for UI
yawRate: float = auto_field() # best estimate of yaw rate
standstill: bool = auto_field()
wheelSpeeds: 'CarState.WheelSpeeds' = field(default_factory=lambda: CarState.WheelSpeeds())
# gas pedal, 0.0-1.0
gas: float = auto_field() # this is user pedal only
gasPressed: bool = auto_field() # this is user pedal only
engineRpm: float = auto_field()
# brake pedal, 0.0-1.0
brake: float = auto_field() # this is user pedal only
brakePressed: bool = auto_field() # this is user pedal only
regenBraking: bool = auto_field() # this is user pedal only
parkingBrake: bool = auto_field()
brakeHoldActive: bool = auto_field()
# steering wheel
steeringAngleDeg: float = auto_field()
steeringAngleOffsetDeg: float = auto_field() # Offset betweens sensors in case there multiple
steeringRateDeg: float = auto_field()
steeringTorque: float = auto_field() # TODO: standardize units
steeringTorqueEps: float = auto_field() # TODO: standardize units
steeringPressed: bool = auto_field() # if the user is using the steering wheel
steerFaultTemporary: bool = auto_field() # temporary EPS fault
steerFaultPermanent: bool = auto_field() # permanent EPS fault
stockAeb: bool = auto_field()
stockFcw: bool = auto_field()
espDisabled: bool = auto_field()
accFaulted: bool = auto_field()
carFaultedNonCritical: bool = auto_field() # some ECU is faulted, but car remains controllable
espActive: bool = auto_field()
vehicleSensorsInvalid: bool = auto_field() # invalid steering angle readings, etc.
# cruise state
cruiseState: 'CarState.CruiseState' = field(default_factory=lambda: CarState.CruiseState())
# gear
gearShifter: 'CarState.GearShifter' = field(default_factory=lambda: CarState.GearShifter.unknown)
# button presses
buttonEvents: list['CarState.ButtonEvent'] = auto_field()
leftBlinker: bool = auto_field()
rightBlinker: bool = auto_field()
genericToggle: bool = auto_field()
# lock info
doorOpen: bool = auto_field()
seatbeltUnlatched: bool = auto_field()
# clutch (manual transmission only)
clutchPressed: bool = auto_field()
# blindspot sensors
leftBlindspot: bool = auto_field() # Is there something blocking the left lane change
rightBlindspot: bool = auto_field() # Is there something blocking the right lane change
fuelGauge: float = auto_field() # battery or fuel tank level from 0.0 to 1.0
charging: bool = auto_field()
# process meta
cumLagMs: float = auto_field()
@auto_dataclass
class WheelSpeeds:
# optional wheel speeds
fl: float = auto_field()
fr: float = auto_field()
rl: float = auto_field()
rr: float = auto_field()
@auto_dataclass
class CruiseState:
enabled: bool = auto_field()
speed: float = auto_field()
speedCluster: float = auto_field() # Set speed as shown on instrument cluster
available: bool = auto_field()
speedOffset: float = auto_field()
standstill: bool = auto_field()
nonAdaptive: bool = auto_field()
class GearShifter(StrEnum):
unknown = auto()
park = auto()
drive = auto()
neutral = auto()
reverse = auto()
sport = auto()
low = auto()
brake = auto()
eco = auto()
manumatic = auto()
# send on change
@auto_dataclass
class ButtonEvent:
pressed: bool = auto_field()
type: 'CarState.ButtonEvent.Type' = field(default_factory=lambda: CarState.ButtonEvent.Type.unknown)
class Type(StrEnum):
unknown = auto()
leftBlinker = auto()
rightBlinker = auto()
accelCruise = auto()
decelCruise = auto()
cancel = auto()
altButton1 = auto()
altButton2 = auto()
altButton3 = auto()
setCruise = auto()
resumeCruise = auto()
gapAdjustCruise = auto()
@auto_dataclass
class RadarData:
errors: list['Error'] = auto_field()
points: list['RadarPoint'] = auto_field()
class Error(StrEnum):
canError = auto()
fault = auto()
wrongConfig = auto()
@auto_dataclass
class RadarPoint:
trackId: int = auto_field() # no trackId reuse
# these 3 are the minimum required
dRel: float = auto_field() # m from the front bumper of the car
yRel: float = auto_field() # m
vRel: float = auto_field() # m/s
# these are optional and valid if they are not NaN
aRel: float = auto_field() # m/s^2
yvRel: float = auto_field() # m/s
# some radars flag measurements VS estimates
measured: bool = auto_field()
@auto_dataclass
class CarControl:
# must be true for any actuator commands to work
enabled: bool = auto_field()
latActive: bool = auto_field()
longActive: bool = auto_field()
# Actuator commands as computed by controlsd
actuators: 'CarControl.Actuators' = field(default_factory=lambda: CarControl.Actuators())
leftBlinker: bool = auto_field()
rightBlinker: bool = auto_field()
orientationNED: list[float] = auto_field()
angularVelocity: list[float] = auto_field()
cruiseControl: 'CarControl.CruiseControl' = field(default_factory=lambda: CarControl.CruiseControl())
hudControl: 'CarControl.HUDControl' = field(default_factory=lambda: CarControl.HUDControl())
@auto_dataclass
class Actuators:
# range from 0.0 - 1.0
gas: float = auto_field()
brake: float = auto_field()
# range from -1.0 - 1.0
steer: float = auto_field()
# value sent over can to the car
steerOutputCan: float = auto_field()
steeringAngleDeg: float = auto_field()
curvature: float = auto_field()
speed: float = auto_field() # m/s
accel: float = auto_field() # m/s^2
longControlState: 'CarControl.Actuators.LongControlState' = field(default_factory=lambda: CarControl.Actuators.LongControlState.off)
class LongControlState(StrEnum):
off = auto()
pid = auto()
stopping = auto()
starting = auto()
@auto_dataclass
class CruiseControl:
cancel: bool = auto_field()
resume: bool = auto_field()
override: bool = auto_field()
@auto_dataclass
class HUDControl:
speedVisible: bool = auto_field()
setSpeed: float = auto_field()
lanesVisible: bool = auto_field()
leadVisible: bool = auto_field()
visualAlert: 'CarControl.HUDControl.VisualAlert' = field(default_factory=lambda: CarControl.HUDControl.VisualAlert.none)
audibleAlert: 'CarControl.HUDControl.AudibleAlert' = field(default_factory=lambda: CarControl.HUDControl.AudibleAlert.none)
rightLaneVisible: bool = auto_field()
leftLaneVisible: bool = auto_field()
rightLaneDepart: bool = auto_field()
leftLaneDepart: bool = auto_field()
leadDistanceBars: int = auto_field() # 1-3: 1 is closest, 3 is farthest. some ports may utilize 2-4 bars instead
class VisualAlert(StrEnum):
# these are the choices from the Honda
# map as good as you can for your car
none = auto()
fcw = auto()
steerRequired = auto()
brakePressed = auto()
wrongGear = auto()
seatbeltUnbuckled = auto()
speedTooHigh = auto()
ldw = auto()
class AudibleAlert(StrEnum):
none = auto()
engage = auto()
disengage = auto()
refuse = auto()
warningSoft = auto()
warningImmediate = auto()
prompt = auto()
promptRepeat = auto()
promptDistracted = auto()
@auto_dataclass
class CarParams:
carName: str = auto_field()
carFingerprint: str = auto_field()
fuzzyFingerprint: bool = auto_field()
notCar: bool = auto_field() # flag for non-car robotics platforms
pcmCruise: bool = auto_field() # is openpilot's state tied to the PCM's cruise state?
enableDsu: bool = auto_field() # driving support unit
enableBsm: bool = auto_field() # blind spot monitoring
flags: int = auto_field() # flags for car specific quirks
experimentalLongitudinalAvailable: bool = auto_field()
minEnableSpeed: float = auto_field()
minSteerSpeed: float = auto_field()
safetyConfigs: list['CarParams.SafetyConfig'] = auto_field()
alternativeExperience: int = auto_field() # panda flag for features like no disengage on gas
maxLateralAccel: float = auto_field()
autoResumeSng: bool = auto_field() # describes whether car can resume from a stop automatically
mass: float = auto_field() # [kg] curb weight: all fluids no cargo
wheelbase: float = auto_field() # [m] distance from rear axle to front axle
centerToFront: float = auto_field() # [m] distance from center of mass to front axle
steerRatio: float = auto_field() # [] ratio of steering wheel angle to front wheel angle
steerRatioRear: float = auto_field() # [] ratio of steering wheel angle to rear wheel angle (usually 0)
rotationalInertia: float = auto_field() # [kg*m2] body rotational inertia
tireStiffnessFactor: float = auto_field() # scaling factor used in calculating tireStiffness[Front,Rear]
tireStiffnessFront: float = auto_field() # [N/rad] front tire coeff of stiff
tireStiffnessRear: float = auto_field() # [N/rad] rear tire coeff of stiff
longitudinalTuning: 'CarParams.LongitudinalPIDTuning' = field(default_factory=lambda: CarParams.LongitudinalPIDTuning())
lateralParams: 'CarParams.LateralParams' = field(default_factory=lambda: CarParams.LateralParams())
lateralTuning: 'CarParams.LateralTuning' = field(default_factory=lambda: CarParams.LateralTuning())
@auto_dataclass
class LateralTuning:
def init(self, which: str):
self.which = CarParams.LateralTuning.Which(which)
class Which(StrEnum):
pid = auto()
torque = auto()
def __call__(self):
return self.value
which: 'CarParams.LateralTuning.Which' = field(default_factory=lambda: CarParams.LateralTuning.Which.pid)
pid: 'CarParams.LateralPIDTuning' = field(default_factory=lambda: CarParams.LateralPIDTuning())
torque: 'CarParams.LateralTorqueTuning' = field(default_factory=lambda: CarParams.LateralTorqueTuning())
@auto_dataclass
class SafetyConfig:
safetyModel: 'CarParams.SafetyModel' = field(default_factory=lambda: CarParams.SafetyModel.silent)
safetyParam: int = auto_field()
@auto_dataclass
class LateralParams:
torqueBP: list[int] = auto_field()
torqueV: list[int] = auto_field()
@auto_dataclass
class LateralPIDTuning:
kpBP: list[float] = auto_field()
kpV: list[float] = auto_field()
kiBP: list[float] = auto_field()
kiV: list[float] = auto_field()
kf: float = auto_field()
@auto_dataclass
class LateralTorqueTuning:
useSteeringAngle: bool = auto_field()
kp: float = auto_field()
ki: float = auto_field()
friction: float = auto_field()
kf: float = auto_field()
steeringAngleDeadzoneDeg: float = auto_field()
latAccelFactor: float = auto_field()
latAccelOffset: float = auto_field()
steerLimitAlert: bool = auto_field()
steerLimitTimer: float = auto_field() # time before steerLimitAlert is issued
vEgoStopping: float = auto_field() # Speed at which the car goes into stopping state
vEgoStarting: float = auto_field() # Speed at which the car goes into starting state
stoppingControl: bool = auto_field() # Does the car allow full control even at lows speeds when stopping
steerControlType: 'CarParams.SteerControlType' = field(default_factory=lambda: CarParams.SteerControlType.torque)
radarUnavailable: bool = auto_field() # True when radar objects aren't visible on CAN or aren't parsed out
stopAccel: float = auto_field() # Required acceleration to keep vehicle stationary
stoppingDecelRate: float = auto_field() # m/s^2/s while trying to stop
startAccel: float = auto_field() # Required acceleration to get car moving
startingState: bool = auto_field() # Does this car make use of special starting state
steerActuatorDelay: float = auto_field() # Steering wheel actuator delay in seconds
longitudinalActuatorDelay: float = auto_field() # Gas/Brake actuator delay in seconds
openpilotLongitudinalControl: bool = auto_field() # is openpilot doing the longitudinal control?
carVin: str = auto_field() # VIN number queried during fingerprinting
dashcamOnly: bool = auto_field()
passive: bool = auto_field() # is openpilot in control?
transmissionType: 'CarParams.TransmissionType' = field(default_factory=lambda: CarParams.TransmissionType.unknown)
carFw: list['CarParams.CarFw'] = auto_field()
radarTimeStep: float = 0.05 # time delta between radar updates, 20Hz is very standard
fingerprintSource: 'CarParams.FingerprintSource' = field(default_factory=lambda: CarParams.FingerprintSource.can)
# Where Panda/C2 is integrated into the car's CAN network
networkLocation: 'CarParams.NetworkLocation' = field(default_factory=lambda: CarParams.NetworkLocation.fwdCamera)
wheelSpeedFactor: float = auto_field() # Multiplier on wheels speeds to computer actual speeds
@auto_dataclass
class LongitudinalPIDTuning:
kpBP: list[float] = auto_field()
kpV: list[float] = auto_field()
kiBP: list[float] = auto_field()
kiV: list[float] = auto_field()
kf: float = auto_field()
class SafetyModel(StrEnum):
silent = auto()
hondaNidec = auto()
toyota = auto()
elm327 = auto()
gm = auto()
hondaBoschGiraffe = auto()
ford = auto()
cadillac = auto()
hyundai = auto()
chrysler = auto()
tesla = auto()
subaru = auto()
gmPassive = auto()
mazda = auto()
nissan = auto()
volkswagen = auto()
toyotaIpas = auto()
allOutput = auto()
gmAscm = auto()
noOutput = auto() # like silent but without silent CAN TXs
hondaBosch = auto()
volkswagenPq = auto()
subaruPreglobal = auto() # pre-Global platform
hyundaiLegacy = auto()
hyundaiCommunity = auto()
volkswagenMlb = auto()
hongqi = auto()
body = auto()
hyundaiCanfd = auto()
volkswagenMqbEvo = auto()
chryslerCusw = auto()
psa = auto()
class SteerControlType(StrEnum):
torque = auto()
angle = auto()
class TransmissionType(StrEnum):
unknown = auto()
automatic = auto() # Traditional auto, including DSG
manual = auto() # True "stick shift" only
direct = auto() # Electric vehicle or other direct drive
cvt = auto()
@auto_dataclass
class CarFw:
ecu: 'CarParams.Ecu' = field(default_factory=lambda: CarParams.Ecu.unknown)
fwVersion: bytes = auto_field()
address: int = auto_field()
subAddress: int = auto_field()
responseAddress: int = auto_field()
request: list[bytes] = auto_field()
brand: str = auto_field()
bus: int = auto_field()
logging: bool = auto_field()
obdMultiplexing: bool = auto_field()
class Ecu(StrEnum):
eps = auto()
abs = auto()
fwdRadar = auto()
fwdCamera = auto()
engine = auto()
unknown = auto()
transmission = auto() # Transmission Control Module
hybrid = auto() # hybrid control unit, e.g. Chrysler's HCP, Honda's IMA Control Unit, Toyota's hybrid control computer
srs = auto() # airbag
gateway = auto() # can gateway
hud = auto() # heads up display
combinationMeter = auto() # instrument cluster
electricBrakeBooster = auto()
shiftByWire = auto()
adas = auto()
cornerRadar = auto()
hvac = auto()
parkingAdas = auto() # parking assist system ECU, e.g. Toyota's IPAS, Hyundai's RSPA, etc.
epb = auto() # electronic parking brake
telematics = auto()
body = auto() # body control module
# Toyota only
dsu = auto()
# Honda only
vsa = auto() # Vehicle Stability Assist
programmedFuelInjection = auto()
debug = auto()
class FingerprintSource(StrEnum):
can = auto()
fw = auto()
fixed = auto()
class NetworkLocation(StrEnum):
fwdCamera = auto() # Standard/default integration at LKAS camera
gateway = auto() # Integration at vehicle's CAN gateway

View File

@ -1,3 +1,4 @@
import copy
from opendbc.can.packer import CANPacker
from openpilot.selfdrive.car import apply_driver_steer_torque_limits, common_fault_avoidance, make_tester_present_msg
from openpilot.selfdrive.car.common.numpy_fast import clip, interp
@ -135,7 +136,7 @@ class CarController(CarControllerBase):
if self.frame % 2 == 0:
can_sends.append(subarucan.create_es_static_2(self.packer))
new_actuators = actuators.as_builder()
new_actuators = copy.copy(actuators)
new_actuators.steer = self.apply_steer_last / self.p.STEER_MAX
new_actuators.steerOutputCan = self.apply_steer_last

View File

@ -1,7 +1,7 @@
import copy
from cereal import car
from opendbc.can.can_define import CANDefine
from opendbc.can.parser import CANParser
from openpilot.selfdrive.car import structs
from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.interfaces import CarStateBase
from openpilot.selfdrive.car.subaru.values import DBC, CanBus, SubaruFlags
@ -16,8 +16,8 @@ class CarState(CarStateBase):
self.angle_rate_calulator = CanSignalRateCalculator(50)
def update(self, cp, cp_cam, _, cp_body, __):
ret = car.CarState.new_message()
def update(self, cp, cp_cam, _, cp_body, __) -> structs.CarState:
ret = structs.CarState()
throttle_msg = cp.vl["Throttle"] if not (self.CP.flags & SubaruFlags.HYBRID) else cp_body.vl["Throttle_Hybrid"]
ret.gas = throttle_msg["Throttle_Pedal"] / 255.

View File

@ -1,7 +1,7 @@
from cereal import car
from openpilot.selfdrive.car.structs import CarParams
from openpilot.selfdrive.car.subaru.values import CAR
Ecu = car.CarParams.Ecu
Ecu = CarParams.Ecu
FW_VERSIONS = {
CAR.SUBARU_ASCENT: {

View File

@ -1,6 +1,5 @@
from cereal import car
from panda import Panda
from openpilot.selfdrive.car import get_safety_config
from openpilot.selfdrive.car import get_safety_config, structs
from openpilot.selfdrive.car.disable_ecu import disable_ecu
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
from openpilot.selfdrive.car.subaru.values import CAR, GLOBAL_ES_ADDR, SubaruFlags
@ -9,7 +8,7 @@ from openpilot.selfdrive.car.subaru.values import CAR, GLOBAL_ES_ADDR, SubaruFla
class CarInterface(CarInterfaceBase):
@staticmethod
def _get_params(ret, candidate: CAR, fingerprint, car_fw, experimental_long, docs):
def _get_params(ret: structs.CarParams, candidate: CAR, fingerprint, car_fw, experimental_long, docs) -> structs.CarParams:
ret.carName = "subaru"
ret.radarUnavailable = True
# for HYBRID CARS to be upstreamed, we need:
@ -25,10 +24,10 @@ class CarInterface(CarInterfaceBase):
if ret.flags & SubaruFlags.PREGLOBAL:
ret.enableBsm = 0x25c in fingerprint[0]
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.subaruPreglobal)]
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.subaruPreglobal)]
else:
ret.enableBsm = 0x228 in fingerprint[0]
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.subaru)]
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.subaru)]
if ret.flags & SubaruFlags.GLOBAL_GEN2:
ret.safetyConfigs[0].safetyParam |= Panda.FLAG_SUBARU_GEN2
@ -36,7 +35,7 @@ class CarInterface(CarInterfaceBase):
ret.steerActuatorDelay = 0.1
if ret.flags & SubaruFlags.LKAS_ANGLE:
ret.steerControlType = car.CarParams.SteerControlType.angle
ret.steerControlType = structs.CarParams.SteerControlType.angle
else:
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)

View File

@ -1,7 +1,7 @@
from cereal import car
from openpilot.selfdrive.car import structs
from openpilot.selfdrive.car.subaru.values import CanBus
VisualAlert = car.CarControl.HUDControl.VisualAlert
VisualAlert = structs.CarControl.HUDControl.VisualAlert
def create_steering_control(packer, apply_steer, steer_req):

View File

@ -1,13 +1,13 @@
from dataclasses import dataclass, field
from enum import Enum, IntFlag
from cereal import car
from panda.python import uds
from openpilot.selfdrive.car import CarSpecs, DbcDict, PlatformConfig, Platforms, dbc_dict
from openpilot.selfdrive.car.structs import CarParams
from openpilot.selfdrive.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Tool, Column
from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries, p16
Ecu = car.CarParams.Ecu
Ecu = CarParams.Ecu
class CarControllerParams:
@ -93,7 +93,7 @@ class SubaruCarDocs(CarDocs):
car_parts: CarParts = field(default_factory=CarParts.common([CarHarness.subaru_a]))
footnotes: list[Enum] = field(default_factory=lambda: [Footnote.GLOBAL])
def init_make(self, CP: car.CarParams):
def init_make(self, CP: CarParams):
self.car_parts.parts.extend([Tool.socket_8mm_deep, Tool.pry_tool])
if CP.experimentalLongitudinalAvailable:

View File

@ -7,7 +7,9 @@ from parameterized import parameterized
from cereal import car, messaging
from openpilot.selfdrive.car import DT_CTRL, gen_empty_fingerprint
from openpilot.selfdrive.car.card import convert_carControl, convert_to_capnp
from openpilot.selfdrive.car.car_helpers import interfaces
from openpilot.selfdrive.car.structs import CarParams
from openpilot.selfdrive.car.fingerprints import all_known_cars
from openpilot.selfdrive.car.fw_versions import FW_VERSIONS, FW_QUERY_CONFIGS
from openpilot.selfdrive.car.interfaces import get_interface_attr
@ -43,8 +45,8 @@ def get_fuzzy_car_interface_args(draw: DrawType) -> dict:
})
params: dict = draw(params_strategy)
params['car_fw'] = [car.CarParams.CarFw(ecu=fw[0], address=fw[1], subAddress=fw[2] or 0,
request=draw(st.sampled_from(sorted(ALL_REQUESTS))))
params['car_fw'] = [CarParams.CarFw(ecu=fw[0], address=fw[1], subAddress=fw[2] or 0,
request=draw(st.sampled_from(sorted(ALL_REQUESTS))))
for fw in params['car_fw']]
return params
@ -63,7 +65,6 @@ class TestCarInterfaces:
car_params = CarInterface.get_params(car_name, args['fingerprints'], args['car_fw'],
experimental_long=args['experimental_long'], docs=False)
car_params = car_params.as_reader()
car_interface = CarInterface(car_params, CarController, CarState)
assert car_params
assert car_interface
@ -79,7 +80,7 @@ class TestCarInterfaces:
assert len(car_params.longitudinalTuning.kiV) == len(car_params.longitudinalTuning.kiBP)
# Lateral sanity checks
if car_params.steerControlType != car.CarParams.SteerControlType.angle:
if car_params.steerControlType != CarParams.SteerControlType.angle:
tune = car_params.lateralTuning
if tune.which() == 'pid':
if car_name != MOCK.MOCK:
@ -95,28 +96,31 @@ class TestCarInterfaces:
# Run car interface
now_nanos = 0
CC = car.CarControl.new_message(**cc_msg)
CC = convert_carControl(CC.as_reader())
for _ in range(10):
car_interface.update([])
car_interface.apply(CC.as_reader(), now_nanos)
car_interface.apply(CC, now_nanos)
now_nanos += DT_CTRL * 1e9 # 10 ms
CC = car.CarControl.new_message(**cc_msg)
CC.enabled = True
CC = convert_carControl(CC.as_reader())
for _ in range(10):
car_interface.update([])
car_interface.apply(CC.as_reader(), now_nanos)
car_interface.apply(CC, now_nanos)
now_nanos += DT_CTRL * 1e9 # 10ms
# Test controller initialization
# TODO: wait until card refactor is merged to run controller a few times,
# hypothesis also slows down significantly with just one more message draw
LongControl(car_params)
if car_params.steerControlType == car.CarParams.SteerControlType.angle:
LatControlAngle(car_params, car_interface)
car_params_capnp = convert_to_capnp(car_params).as_reader()
LongControl(car_params_capnp)
if car_params.steerControlType == CarParams.SteerControlType.angle:
LatControlAngle(car_params_capnp, car_interface)
elif car_params.lateralTuning.which() == 'pid':
LatControlPID(car_params, car_interface)
LatControlPID(car_params_capnp, car_interface)
elif car_params.lateralTuning.which() == 'torque':
LatControlTorque(car_params, car_interface)
LatControlTorque(car_params_capnp, car_interface)
# Test radar interface
RadarInterface = importlib.import_module(f'selfdrive.car.{car_params.carName}.radar_interface').RadarInterface

View File

@ -4,18 +4,16 @@ import time
from collections import defaultdict
from parameterized import parameterized
from cereal import car
from openpilot.selfdrive.car.can_definitions import CanData
from openpilot.selfdrive.car.car_helpers import interfaces
from openpilot.selfdrive.car.structs import CarParams
from openpilot.selfdrive.car.fingerprints import FW_VERSIONS
from openpilot.selfdrive.car.fw_versions import ESSENTIAL_ECUS, FW_QUERY_CONFIGS, FUZZY_EXCLUDE_ECUS, VERSIONS, build_fw_dict, \
match_fw_to_car, get_brand_ecu_matches, get_fw_versions, get_fw_versions_ordered, get_present_ecus
from openpilot.selfdrive.car.vin import get_vin
CarFw = car.CarParams.CarFw
Ecu = car.CarParams.Ecu
ECU_NAME = {v: k for k, v in Ecu.schema.enumerants.items()}
CarFw = CarParams.CarFw
Ecu = CarParams.Ecu
class TestFwFingerprint:
@ -27,7 +25,7 @@ class TestFwFingerprint:
@parameterized.expand([(b, c, e[c], n) for b, e in VERSIONS.items() for c in e for n in (True, False)])
def test_exact_match(self, brand, car_model, ecus, test_non_essential):
config = FW_QUERY_CONFIGS[brand]
CP = car.CarParams.new_message()
CP = CarParams()
for _ in range(100):
fw = []
for ecu, fw_versions in ecus.items():
@ -37,8 +35,8 @@ class TestFwFingerprint:
continue
ecu_name, addr, sub_addr = ecu
fw.append({"ecu": ecu_name, "fwVersion": random.choice(fw_versions), 'brand': brand,
"address": addr, "subAddress": 0 if sub_addr is None else sub_addr})
fw.append(CarFw(ecu=ecu_name, fwVersion=random.choice(fw_versions), brand=brand,
address=addr, subAddress=0 if sub_addr is None else sub_addr))
CP.carFw = fw
_, matches = match_fw_to_car(CP.carFw, CP.carVin, allow_fuzzy=False)
if not test_non_essential:
@ -55,13 +53,13 @@ class TestFwFingerprint:
if config.match_fw_to_car_fuzzy is None:
pytest.skip("Brand does not implement custom fuzzy fingerprinting function")
CP = car.CarParams.new_message()
CP = CarParams()
for _ in range(5):
fw = []
for ecu, fw_versions in ecus.items():
ecu_name, addr, sub_addr = ecu
fw.append({"ecu": ecu_name, "fwVersion": random.choice(fw_versions), 'brand': brand,
"address": addr, "subAddress": 0 if sub_addr is None else sub_addr})
fw.append(CarFw(ecu=ecu_name, fwVersion=random.choice(fw_versions), brand=brand,
address=addr, subAddress=0 if sub_addr is None else sub_addr))
CP.carFw = fw
_, matches = match_fw_to_car(CP.carFw, CP.carVin, allow_exact=False, log=False)
brand_matches = config.match_fw_to_car_fuzzy(build_fw_dict(CP.carFw), CP.carVin, VERSIONS[brand])
@ -82,13 +80,13 @@ class TestFwFingerprint:
ecu_name, addr, sub_addr = ecu
for _ in range(5):
# Add multiple FW versions to simulate ECU returning to multiple queries in a brand
fw.append({"ecu": ecu_name, "fwVersion": random.choice(ecus[ecu]), 'brand': brand,
"address": addr, "subAddress": 0 if sub_addr is None else sub_addr})
CP = car.CarParams.new_message(carFw=fw)
fw.append(CarFw(ecu=ecu_name, fwVersion=random.choice(ecus[ecu]), brand=brand,
address=addr, subAddress=0 if sub_addr is None else sub_addr))
CP = CarParams(carFw=fw)
_, matches = match_fw_to_car(CP.carFw, CP.carVin, allow_exact=False, log=False)
# Assert no match if there are not enough unique ECUs
unique_ecus = {(f['address'], f['subAddress']) for f in fw}
unique_ecus = {(f.address, f.subAddress) for f in fw}
if len(unique_ecus) < 2:
assert len(matches) == 0, car_model
# There won't always be a match due to shared FW, but if there is it should be correct
@ -99,10 +97,10 @@ class TestFwFingerprint:
for car_model, ecus in FW_VERSIONS.items():
with subtests.test(car_model=car_model.value):
for ecu, ecu_fw in ecus.items():
with subtests.test(ecu):
with subtests.test((ecu[0].value, ecu[1], ecu[2])):
duplicates = {fw for fw in ecu_fw if ecu_fw.count(fw) > 1}
assert not len(duplicates), f'{car_model}: Duplicate FW versions: Ecu.{ECU_NAME[ecu[0]]}, {duplicates}'
assert len(ecu_fw) > 0, f'{car_model}: No FW versions: Ecu.{ECU_NAME[ecu[0]]}'
assert not len(duplicates), f'{car_model}: Duplicate FW versions: Ecu.{ecu[0]}, {duplicates}'
assert len(ecu_fw) > 0, f'{car_model}: No FW versions: Ecu.{ecu[0]}'
def test_all_addrs_map_to_one_ecu(self):
for brand, cars in VERSIONS.items():
@ -111,7 +109,7 @@ class TestFwFingerprint:
for ecu_type, addr, sub_addr in ecus.keys():
addr_to_ecu[(addr, sub_addr)].add(ecu_type)
ecus_for_addr = addr_to_ecu[(addr, sub_addr)]
ecu_strings = ", ".join([f'Ecu.{ECU_NAME[ecu]}' for ecu in ecus_for_addr])
ecu_strings = ", ".join([f'Ecu.{ecu}' for ecu in ecus_for_addr])
assert len(ecus_for_addr) <= 1, f"{brand} has multiple ECUs that map to one address: {ecu_strings} -> ({hex(addr)}, {sub_addr})"
def test_data_collection_ecus(self, subtests):
@ -129,13 +127,13 @@ class TestFwFingerprint:
CP = interfaces[car_model][0].get_non_essential_params(car_model)
if CP.carName == 'subaru':
for ecu in ecus.keys():
assert ecu[1] not in blacklisted_addrs, f'{car_model}: Blacklisted ecu: (Ecu.{ECU_NAME[ecu[0]]}, {hex(ecu[1])})'
assert ecu[1] not in blacklisted_addrs, f'{car_model}: Blacklisted ecu: (Ecu.{ecu[0]}, {hex(ecu[1])})'
elif CP.carName == "chrysler":
# Some HD trucks have a combined TCM and ECM
if CP.carFingerprint.startswith("RAM_HD"):
for ecu in ecus.keys():
assert ecu[0] != Ecu.transmission, f"{car_model}: Blacklisted ecu: (Ecu.{ECU_NAME[ecu[0]]}, {hex(ecu[1])})"
assert ecu[0] != Ecu.transmission, f"{car_model}: Blacklisted ecu: (Ecu.{ecu[0]}, {hex(ecu[1])})"
def test_non_essential_ecus(self, subtests):
for brand, config in FW_QUERY_CONFIGS.items():
@ -143,7 +141,7 @@ class TestFwFingerprint:
# These ECUs are already not in ESSENTIAL_ECUS which the fingerprint functions give a pass if missing
unnecessary_non_essential_ecus = set(config.non_essential_ecus) - set(ESSENTIAL_ECUS)
assert unnecessary_non_essential_ecus == set(), "Declaring non-essential ECUs non-essential is not required: " + \
f"{', '.join([f'Ecu.{ECU_NAME[ecu]}' for ecu in unnecessary_non_essential_ecus])}"
f"{', '.join([f'Ecu.{ecu}' for ecu in unnecessary_non_essential_ecus])}"
def test_missing_versions_and_configs(self, subtests):
brand_versions = set(VERSIONS.keys())
@ -172,7 +170,7 @@ class TestFwFingerprint:
# each ecu in brand's fw versions + extra ecus needs to be whitelisted at least once
ecus_not_whitelisted = brand_ecus - whitelisted_ecus
ecu_strings = ", ".join([f'Ecu.{ECU_NAME[ecu]}' for ecu in ecus_not_whitelisted])
ecu_strings = ", ".join([f'Ecu.{ecu}' for ecu in ecus_not_whitelisted])
assert not (len(whitelisted_ecus) and len(ecus_not_whitelisted)), \
f'{brand.title()}: ECUs not in any FW query whitelists: {ecu_strings}'

View File

@ -1,4 +1,6 @@
import capnp
import copy
import dataclasses
import os
import importlib
import pytest
@ -13,12 +15,13 @@ from cereal import messaging, log, car
from openpilot.common.basedir import BASEDIR
from openpilot.common.params import Params
from openpilot.selfdrive.car import DT_CTRL, gen_empty_fingerprint
from openpilot.selfdrive.car import structs
from openpilot.selfdrive.car.fingerprints import all_known_cars, MIGRATION
from openpilot.selfdrive.car.car_helpers import FRAME_FINGERPRINT, interfaces
from openpilot.selfdrive.car.honda.values import CAR as HONDA, HondaFlags
from openpilot.selfdrive.car.tests.routes import non_tested_cars, routes, CarTestRoute
from openpilot.selfdrive.car.values import Platform
from openpilot.selfdrive.car.card import Car
from openpilot.selfdrive.car.card import Car, convert_to_capnp
from openpilot.selfdrive.pandad import can_capnp_to_list
from openpilot.selfdrive.test.helpers import read_segment_list
from openpilot.system.hardware.hw import DEFAULT_DOWNLOAD_CACHE_ROOT
@ -181,7 +184,7 @@ class TestCarModelBase(unittest.TestCase):
del cls.can_msgs
def setUp(self):
self.CI = self.CarInterface(self.CP.copy(), self.CarController, self.CarState)
self.CI = self.CarInterface(copy.deepcopy(self.CP), self.CarController, self.CarState)
assert self.CI
Params().put_bool("OpenpilotEnabledToggle", self.openpilot_enabled)
@ -189,7 +192,7 @@ class TestCarModelBase(unittest.TestCase):
# TODO: check safetyModel is in release panda build
self.safety = libpanda_py.libpanda
cfg = self.CP.safetyConfigs[-1]
cfg = car.CarParams.SafetyConfig(**dataclasses.asdict(self.CP.safetyConfigs[-1]))
set_status = self.safety.set_safety_hooks(cfg.safetyModel.raw, cfg.safetyParam)
self.assertEqual(0, set_status, f"failed to set safetyModel {cfg}")
self.safety.init_tests()
@ -201,7 +204,7 @@ class TestCarModelBase(unittest.TestCase):
# make sure car params are within a valid range
self.assertGreater(self.CP.mass, 1)
if self.CP.steerControlType != car.CarParams.SteerControlType.angle:
if self.CP.steerControlType != structs.CarParams.SteerControlType.angle:
tuning = self.CP.lateralTuning.which()
if tuning == 'pid':
self.assertTrue(len(self.CP.lateralTuning.pid.kpV))
@ -214,7 +217,7 @@ class TestCarModelBase(unittest.TestCase):
# TODO: also check for checksum violations from can parser
can_invalid_cnt = 0
can_valid = False
CC = car.CarControl.new_message().as_reader()
CC = structs.CarControl()
for i, msg in enumerate(self.can_msgs):
CS = self.CI.update(can_capnp_to_list((msg.as_builder().to_bytes(),)))
@ -238,9 +241,9 @@ class TestCarModelBase(unittest.TestCase):
# start parsing CAN messages after we've left ELM mode and can expect CAN traffic
error_cnt = 0
for i, msg in enumerate(self.can_msgs[self.elm_frame:]):
rr = RI.update(can_capnp_to_list((msg.as_builder().to_bytes(),)))
rr: structs.RadarData | None = RI.update(can_capnp_to_list((msg.as_builder().to_bytes(),)))
if rr is not None and i > 50:
error_cnt += car.RadarData.Error.canError in rr.errors
error_cnt += structs.RadarData.Error.canError in rr.errors
self.assertEqual(error_cnt, 0)
def test_panda_safety_rx_checks(self):
@ -306,18 +309,18 @@ class TestCarModelBase(unittest.TestCase):
self.assertGreater(msgs_sent, 50)
# Make sure we can send all messages while inactive
CC = car.CarControl.new_message()
test_car_controller(CC.as_reader())
CC = structs.CarControl()
test_car_controller(CC)
# Test cancel + general messages (controls_allowed=False & cruise_engaged=True)
self.safety.set_cruise_engaged_prev(True)
CC = car.CarControl.new_message(cruiseControl={'cancel': True})
test_car_controller(CC.as_reader())
CC = structs.CarControl(cruiseControl=structs.CarControl.CruiseControl(cancel=True))
test_car_controller(CC)
# Test resume + general messages (controls_allowed=True & cruise_engaged=True)
self.safety.set_controls_allowed(True)
CC = car.CarControl.new_message(cruiseControl={'resume': True})
test_car_controller(CC.as_reader())
CC = structs.CarControl(cruiseControl=structs.CarControl.CruiseControl(resume=True))
test_car_controller(CC)
# Skip stdout/stderr capture with pytest, causes elevated memory usage
@pytest.mark.nocapture
@ -403,7 +406,7 @@ class TestCarModelBase(unittest.TestCase):
checks = defaultdict(int)
card = Car(CI=self.CI)
for idx, can in enumerate(self.can_msgs):
CS = self.CI.update(can_capnp_to_list((can.as_builder().to_bytes(), )))
CS = convert_to_capnp(self.CI.update(can_capnp_to_list((can.as_builder().to_bytes(), ))))
for msg in filter(lambda m: m.src in range(64), can.can):
to_send = libpanda_py.make_CANPacket(msg.address, msg.src % 4, msg.dat)
ret = self.safety.safety_rx_hook(to_send)

View File

@ -1,5 +1,5 @@
from cereal import car
from openpilot.selfdrive.car import apply_meas_steer_torque_limits, apply_std_steer_angle_limits, common_fault_avoidance, make_tester_present_msg
import copy
from openpilot.selfdrive.car import apply_meas_steer_torque_limits, apply_std_steer_angle_limits, common_fault_avoidance, make_tester_present_msg, structs
from openpilot.selfdrive.car.can_definitions import CanData
from openpilot.selfdrive.car.common.numpy_fast import clip
from openpilot.selfdrive.car.interfaces import CarControllerBase
@ -9,8 +9,8 @@ from openpilot.selfdrive.car.toyota.values import CAR, STATIC_DSU_MSGS, NO_STOP_
UNSUPPORTED_DSU_CAR
from opendbc.can.packer import CANPacker
SteerControlType = car.CarParams.SteerControlType
VisualAlert = car.CarControl.HUDControl.VisualAlert
SteerControlType = structs.CarParams.SteerControlType
VisualAlert = structs.CarControl.HUDControl.VisualAlert
# LKA limits
# EPS faults if you apply torque while the steering rate is above 100 deg/s for too long
@ -168,7 +168,7 @@ class CarController(CarControllerBase):
if self.frame % 20 == 0 and self.CP.flags & ToyotaFlags.DISABLE_RADAR.value:
can_sends.append(make_tester_present_msg(0x750, 0, 0xF))
new_actuators = actuators.as_builder()
new_actuators = copy.copy(actuators)
new_actuators.steer = apply_steer / self.params.STEER_MAX
new_actuators.steerOutputCan = apply_steer
new_actuators.steeringAngleDeg = self.last_angle

View File

@ -1,9 +1,8 @@
import copy
from cereal import car
from opendbc.can.can_define import CANDefine
from opendbc.can.parser import CANParser
from openpilot.selfdrive.car import DT_CTRL, create_button_events
from openpilot.selfdrive.car import DT_CTRL, create_button_events, structs
from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.common.filter_simple import FirstOrderFilter
from openpilot.selfdrive.car.common.numpy_fast import mean
@ -11,8 +10,8 @@ from openpilot.selfdrive.car.interfaces import CarStateBase
from openpilot.selfdrive.car.toyota.values import ToyotaFlags, CAR, DBC, STEER_THRESHOLD, NO_STOP_TIMER_CAR, \
TSS2_CAR, RADAR_ACC_CAR, EPS_SCALE, UNSUPPORTED_DSU_CAR
ButtonType = car.CarState.ButtonEvent.Type
SteerControlType = car.CarParams.SteerControlType
ButtonType = structs.CarState.ButtonEvent.Type
SteerControlType = structs.CarParams.SteerControlType
# These steering fault definitions seem to be common across LKA (torque) and LTA (angle):
# - high steer rate fault: goes to 21 or 25 for 1 frame, then 9 for 2 seconds
@ -49,8 +48,8 @@ class CarState(CarStateBase):
self.acc_type = 1
self.lkas_hud = {}
def update(self, cp, cp_cam, *_):
ret = car.CarState.new_message()
def update(self, cp, cp_cam, *_) -> structs.CarState:
ret = structs.CarState()
ret.doorOpen = any([cp.vl["BODY_CONTROL_STATE"]["DOOR_OPEN_FL"], cp.vl["BODY_CONTROL_STATE"]["DOOR_OPEN_FR"],
cp.vl["BODY_CONTROL_STATE"]["DOOR_OPEN_RL"], cp.vl["BODY_CONTROL_STATE"]["DOOR_OPEN_RR"]])

View File

@ -1,7 +1,7 @@
from cereal import car
from openpilot.selfdrive.car.structs import CarParams
from openpilot.selfdrive.car.toyota.values import CAR
Ecu = car.CarParams.Ecu
Ecu = CarParams.Ecu
FW_VERSIONS = {
CAR.TOYOTA_AVALON: {

View File

@ -1,13 +1,12 @@
from cereal import car
from panda import Panda
from panda.python import uds
from openpilot.selfdrive.car import structs, get_safety_config
from openpilot.selfdrive.car.toyota.values import Ecu, CAR, DBC, ToyotaFlags, CarControllerParams, TSS2_CAR, RADAR_ACC_CAR, NO_DSU_CAR, \
MIN_ACC_SPEED, EPS_SCALE, UNSUPPORTED_DSU_CAR, NO_STOP_TIMER_CAR, ANGLE_CONTROL_CAR
from openpilot.selfdrive.car import get_safety_config
from openpilot.selfdrive.car.disable_ecu import disable_ecu
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
SteerControlType = car.CarParams.SteerControlType
SteerControlType = structs.CarParams.SteerControlType
class CarInterface(CarInterfaceBase):
@ -16,9 +15,9 @@ class CarInterface(CarInterfaceBase):
return CarControllerParams.ACCEL_MIN, CarControllerParams.ACCEL_MAX
@staticmethod
def _get_params(ret, candidate, fingerprint, car_fw, experimental_long, docs):
def _get_params(ret: structs.CarParams, candidate, fingerprint, car_fw, experimental_long, docs) -> structs.CarParams:
ret.carName = "toyota"
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.toyota)]
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.toyota)]
ret.safetyConfigs[0].safetyParam = EPS_SCALE[candidate]
# BRAKE_MODULE is on a different address for these cars

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python3
from opendbc.can.parser import CANParser
from cereal import car
from openpilot.selfdrive.car.structs import RadarData
from openpilot.selfdrive.car.toyota.values import DBC, TSS2_CAR
from openpilot.selfdrive.car.interfaces import RadarInterfaceBase
@ -54,7 +54,7 @@ class RadarInterface(RadarInterfaceBase):
return rr
def _update(self, updated_messages):
ret = car.RadarData.new_message()
ret = RadarData()
errors = []
if not self.rcp.can_valid:
errors.append("canError")
@ -77,7 +77,7 @@ class RadarInterface(RadarInterfaceBase):
# radar point only valid if it's a valid measurement and score is above 50
if cpt['VALID'] or (score > 50 and cpt['LONG_DIST'] < 255 and self.valid_cnt[ii] > 0):
if ii not in self.pts or cpt['NEW_TRACK']:
self.pts[ii] = car.RadarData.RadarPoint.new_message()
self.pts[ii] = RadarData.RadarPoint()
self.pts[ii].trackId = self.track_id
self.track_id += 1
self.pts[ii].dRel = cpt['LONG_DIST'] # from front of car

View File

@ -1,19 +1,15 @@
#!/usr/bin/env python3
from collections import defaultdict
from cereal import car
from openpilot.selfdrive.car.toyota.values import PLATFORM_CODE_ECUS, get_platform_codes
from openpilot.selfdrive.car.toyota.fingerprints import FW_VERSIONS
Ecu = car.CarParams.Ecu
ECU_NAME = {v: k for k, v in Ecu.schema.enumerants.items()}
if __name__ == "__main__":
parts_for_ecu: dict = defaultdict(set)
cars_for_code: dict = defaultdict(lambda: defaultdict(set))
for car_model, ecus in FW_VERSIONS.items():
print()
print(car_model)
for ecu in sorted(ecus, key=lambda x: int(x[0])):
for ecu in sorted(ecus):
if ecu[0] not in PLATFORM_CODE_ECUS:
continue
@ -21,15 +17,15 @@ if __name__ == "__main__":
parts_for_ecu[ecu] |= {code.split(b'-')[0] for code in platform_codes if code.count(b'-') > 1}
for code in platform_codes:
cars_for_code[ecu][b'-'.join(code.split(b'-')[:2])] |= {car_model}
print(f' (Ecu.{ECU_NAME[ecu[0]]}, {hex(ecu[1])}, {ecu[2]}):')
print(f' (Ecu.{ecu[0]}, {hex(ecu[1])}, {ecu[2]}):')
print(f' Codes: {platform_codes}')
print('\nECU parts:')
for ecu, parts in parts_for_ecu.items():
print(f' (Ecu.{ECU_NAME[ecu[0]]}, {hex(ecu[1])}, {ecu[2]}): {parts}')
print(f' (Ecu.{ecu[0]}, {hex(ecu[1])}, {ecu[2]}): {parts}')
print('\nCar models vs. platform codes (no major versions):')
for ecu, codes in cars_for_code.items():
print(f' (Ecu.{ECU_NAME[ecu[0]]}, {hex(ecu[1])}, {ecu[2]}):')
print(f' (Ecu.{ecu[0]}, {hex(ecu[1])}, {ecu[2]}):')
for code, cars in codes.items():
print(f' {code!r}: {sorted(cars)}')

View File

@ -1,14 +1,13 @@
from hypothesis import given, settings, strategies as st
from cereal import car
from openpilot.selfdrive.car.structs import CarParams
from openpilot.selfdrive.car.fw_versions import build_fw_dict
from openpilot.selfdrive.car.toyota.fingerprints import FW_VERSIONS
from openpilot.selfdrive.car.toyota.values import CAR, DBC, TSS2_CAR, ANGLE_CONTROL_CAR, RADAR_ACC_CAR, \
FW_QUERY_CONFIG, PLATFORM_CODE_ECUS, FUZZY_EXCLUDED_PLATFORMS, \
get_platform_codes
Ecu = car.CarParams.Ecu
ECU_NAME = {v: k for k, v in Ecu.schema.enumerants.items()}
Ecu = CarParams.Ecu
def check_fw_version(fw_version: bytes) -> bool:
@ -153,10 +152,10 @@ class TestToyotaFingerprint:
for ecu, fw_versions in fw_by_addr.items():
ecu_name, addr, sub_addr = ecu
for fw in fw_versions:
car_fw.append({"ecu": ecu_name, "fwVersion": fw, "address": addr,
"subAddress": 0 if sub_addr is None else sub_addr})
car_fw.append(CarParams.CarFw(ecu=ecu_name, fwVersion=fw, address=addr,
subAddress=0 if sub_addr is None else sub_addr))
CP = car.CarParams.new_message(carFw=car_fw)
CP = CarParams(carFw=car_fw)
matches = FW_QUERY_CONFIG.match_fw_to_car_fuzzy(build_fw_dict(CP.carFw), CP.carVin, FW_VERSIONS)
if len(matches) == 1:
assert list(matches)[0] == platform

View File

@ -1,6 +1,6 @@
from cereal import car
from openpilot.selfdrive.car.structs import CarParams
SteerControlType = car.CarParams.SteerControlType
SteerControlType = CarParams.SteerControlType
def create_steer_command(packer, steer, steer_req):

View File

@ -3,13 +3,13 @@ from collections import defaultdict
from dataclasses import dataclass, field
from enum import Enum, IntFlag
from cereal import car
from openpilot.selfdrive.car import CarSpecs, PlatformConfig, Platforms, AngleRateLimit, dbc_dict
from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.structs import CarParams
from openpilot.selfdrive.car.docs_definitions import CarFootnote, CarDocs, Column, CarParts, CarHarness
from openpilot.selfdrive.car.fw_query_definitions import FwQueryConfig, Request, StdQueries
Ecu = car.CarParams.Ecu
Ecu = CarParams.Ecu
MIN_ACC_SPEED = 19. * CV.MPH_TO_MS
PEDAL_TRANSITION = 10. * CV.MPH_TO_MS

View File

@ -1,14 +1,14 @@
from cereal import car
import copy
from opendbc.can.packer import CANPacker
from openpilot.selfdrive.car import DT_CTRL, apply_driver_steer_torque_limits
from openpilot.selfdrive.car import DT_CTRL, apply_driver_steer_torque_limits, structs
from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.common.numpy_fast import clip
from openpilot.selfdrive.car.interfaces import CarControllerBase
from openpilot.selfdrive.car.volkswagen import mqbcan, pqcan
from openpilot.selfdrive.car.volkswagen.values import CANBUS, CarControllerParams, VolkswagenFlags
VisualAlert = car.CarControl.HUDControl.VisualAlert
LongCtrlState = car.CarControl.Actuators.LongControlState
VisualAlert = structs.CarControl.HUDControl.VisualAlert
LongCtrlState = structs.CarControl.Actuators.LongControlState
class CarController(CarControllerBase):
@ -17,7 +17,7 @@ class CarController(CarControllerBase):
self.CCP = CarControllerParams(CP)
self.CCS = pqcan if CP.flags & VolkswagenFlags.PQ else mqbcan
self.packer_pt = CANPacker(dbc_name)
self.ext_bus = CANBUS.pt if CP.networkLocation == car.CarParams.NetworkLocation.fwdCamera else CANBUS.cam
self.ext_bus = CANBUS.pt if CP.networkLocation == structs.CarParams.NetworkLocation.fwdCamera else CANBUS.cam
self.apply_steer_last = 0
self.gra_acc_counter_last = None
@ -110,7 +110,7 @@ class CarController(CarControllerBase):
can_sends.append(self.CCS.create_acc_buttons_control(self.packer_pt, self.ext_bus, CS.gra_stock_values,
cancel=CC.cruiseControl.cancel, resume=CC.cruiseControl.resume))
new_actuators = actuators.as_builder()
new_actuators = copy.copy(actuators)
new_actuators.steer = self.apply_steer_last / self.CCP.STEER_MAX
new_actuators.steerOutputCan = self.apply_steer_last

View File

@ -1,6 +1,6 @@
import numpy as np
from cereal import car
from opendbc.can.parser import CANParser
from openpilot.selfdrive.car import structs
from openpilot.selfdrive.car.interfaces import CarStateBase
from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car.volkswagen.values import DBC, CANBUS, NetworkLocation, TransmissionType, GearShifter, \
@ -24,7 +24,7 @@ class CarState(CarStateBase):
for button in buttons:
state = pt_cp.vl[button.can_addr][button.can_msg] in button.values
if self.button_states[button.event_type] != state:
event = car.CarState.ButtonEvent.new_message()
event = structs.CarState.ButtonEvent()
event.type = button.event_type
event.pressed = state
button_events.append(event)
@ -32,14 +32,14 @@ class CarState(CarStateBase):
return button_events
def update(self, pt_cp, cam_cp, *_):
def update(self, pt_cp, cam_cp, *_) -> structs.CarState:
ext_cp = pt_cp if self.CP.networkLocation == NetworkLocation.fwdCamera else cam_cp
if self.CP.flags & VolkswagenFlags.PQ:
return self.update_pq(pt_cp, cam_cp, ext_cp)
ret = car.CarState.new_message()
ret = structs.CarState()
# Update vehicle speed and acceleration from ABS wheel speeds.
ret.wheelSpeeds = self.get_wheel_speeds(
pt_cp.vl["ESP_19"]["ESP_VL_Radgeschw_02"],
@ -158,8 +158,8 @@ class CarState(CarStateBase):
self.frame += 1
return ret
def update_pq(self, pt_cp, cam_cp, ext_cp):
ret = car.CarState.new_message()
def update_pq(self, pt_cp, cam_cp, ext_cp) -> structs.CarState:
ret = structs.CarState()
# Update vehicle speed and acceleration from ABS wheel speeds.
ret.wheelSpeeds = self.get_wheel_speeds(
pt_cp.vl["Bremse_3"]["Radgeschw__VL_4_1"],

View File

@ -1,7 +1,7 @@
from cereal import car
from openpilot.selfdrive.car.structs import CarParams
from openpilot.selfdrive.car.volkswagen.values import CAR
Ecu = car.CarParams.Ecu
Ecu = CarParams.Ecu
# TODO: Sharan Mk2 EPS and DQ250 auto trans both require KWP2000 support for fingerprinting

View File

@ -1,19 +1,18 @@
from cereal import car
from panda import Panda
from openpilot.selfdrive.car import get_safety_config
from openpilot.selfdrive.car import get_safety_config, structs
from openpilot.selfdrive.car.interfaces import CarInterfaceBase
from openpilot.selfdrive.car.volkswagen.values import CAR, NetworkLocation, TransmissionType, VolkswagenFlags
class CarInterface(CarInterfaceBase):
@staticmethod
def _get_params(ret, candidate: CAR, fingerprint, car_fw, experimental_long, docs):
def _get_params(ret: structs.CarParams, candidate: CAR, fingerprint, car_fw, experimental_long, docs) -> structs.CarParams:
ret.carName = "volkswagen"
ret.radarUnavailable = True
if ret.flags & VolkswagenFlags.PQ:
# Set global PQ35/PQ46/NMS parameters
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.volkswagenPq)]
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.volkswagenPq)]
ret.enableBsm = 0x3BA in fingerprint[0] # SWA_1
if 0x440 in fingerprint[0] or docs: # Getriebe_1
@ -36,7 +35,7 @@ class CarInterface(CarInterfaceBase):
else:
# Set global MQB parameters
ret.safetyConfigs = [get_safety_config(car.CarParams.SafetyModel.volkswagen)]
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.volkswagen)]
ret.enableBsm = 0x30F in fingerprint[0] # SWA_01
if 0xAD in fingerprint[0] or docs: # Getriebe_11

View File

@ -1,11 +1,11 @@
import random
import re
from cereal import car
from openpilot.selfdrive.car.structs import CarParams
from openpilot.selfdrive.car.volkswagen.values import CAR, FW_QUERY_CONFIG, WMI
from openpilot.selfdrive.car.volkswagen.fingerprints import FW_VERSIONS
Ecu = car.CarParams.Ecu
Ecu = CarParams.Ecu
CHASSIS_CODE_PATTERN = re.compile('[A-Z0-9]{2}')
# TODO: determine the unknown groups

View File

@ -2,19 +2,19 @@ from collections import defaultdict, namedtuple
from dataclasses import dataclass, field
from enum import Enum, IntFlag, StrEnum
from cereal import car
from panda.python import uds
from opendbc.can.can_define import CANDefine
from openpilot.selfdrive.car import dbc_dict, CarSpecs, DbcDict, PlatformConfig, Platforms
from openpilot.selfdrive.car.conversions import Conversions as CV
from openpilot.selfdrive.car import structs
from openpilot.selfdrive.car.docs_definitions import CarFootnote, CarHarness, CarDocs, CarParts, Column, \
Device
from openpilot.selfdrive.car.fw_query_definitions import EcuAddrSubAddr, FwQueryConfig, Request, p16
Ecu = car.CarParams.Ecu
NetworkLocation = car.CarParams.NetworkLocation
TransmissionType = car.CarParams.TransmissionType
GearShifter = car.CarState.GearShifter
Ecu = structs.CarParams.Ecu
NetworkLocation = structs.CarParams.NetworkLocation
TransmissionType = structs.CarParams.TransmissionType
GearShifter = structs.CarState.GearShifter
Button = namedtuple('Button', ['event_type', 'can_addr', 'can_msg', 'values'])
@ -54,12 +54,12 @@ class CarControllerParams:
self.hca_status_values = can_define.dv["Lenkhilfe_2"]["LH2_Sta_HCA"]
self.BUTTONS = [
Button(car.CarState.ButtonEvent.Type.setCruise, "GRA_Neu", "GRA_Neu_Setzen", [1]),
Button(car.CarState.ButtonEvent.Type.resumeCruise, "GRA_Neu", "GRA_Recall", [1]),
Button(car.CarState.ButtonEvent.Type.accelCruise, "GRA_Neu", "GRA_Up_kurz", [1]),
Button(car.CarState.ButtonEvent.Type.decelCruise, "GRA_Neu", "GRA_Down_kurz", [1]),
Button(car.CarState.ButtonEvent.Type.cancel, "GRA_Neu", "GRA_Abbrechen", [1]),
Button(car.CarState.ButtonEvent.Type.gapAdjustCruise, "GRA_Neu", "GRA_Zeitluecke", [1]),
Button(structs.CarState.ButtonEvent.Type.setCruise, "GRA_Neu", "GRA_Neu_Setzen", [1]),
Button(structs.CarState.ButtonEvent.Type.resumeCruise, "GRA_Neu", "GRA_Recall", [1]),
Button(structs.CarState.ButtonEvent.Type.accelCruise, "GRA_Neu", "GRA_Up_kurz", [1]),
Button(structs.CarState.ButtonEvent.Type.decelCruise, "GRA_Neu", "GRA_Down_kurz", [1]),
Button(structs.CarState.ButtonEvent.Type.cancel, "GRA_Neu", "GRA_Abbrechen", [1]),
Button(structs.CarState.ButtonEvent.Type.gapAdjustCruise, "GRA_Neu", "GRA_Zeitluecke", [1]),
]
self.LDW_MESSAGES = {
@ -85,12 +85,12 @@ class CarControllerParams:
self.hca_status_values = can_define.dv["LH_EPS_03"]["EPS_HCA_Status"]
self.BUTTONS = [
Button(car.CarState.ButtonEvent.Type.setCruise, "GRA_ACC_01", "GRA_Tip_Setzen", [1]),
Button(car.CarState.ButtonEvent.Type.resumeCruise, "GRA_ACC_01", "GRA_Tip_Wiederaufnahme", [1]),
Button(car.CarState.ButtonEvent.Type.accelCruise, "GRA_ACC_01", "GRA_Tip_Hoch", [1]),
Button(car.CarState.ButtonEvent.Type.decelCruise, "GRA_ACC_01", "GRA_Tip_Runter", [1]),
Button(car.CarState.ButtonEvent.Type.cancel, "GRA_ACC_01", "GRA_Abbrechen", [1]),
Button(car.CarState.ButtonEvent.Type.gapAdjustCruise, "GRA_ACC_01", "GRA_Verstellung_Zeitluecke", [1]),
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_Abbrechen", [1]),
Button(structs.CarState.ButtonEvent.Type.gapAdjustCruise, "GRA_ACC_01", "GRA_Verstellung_Zeitluecke", [1]),
]
self.LDW_MESSAGES = {
@ -190,7 +190,7 @@ class VWCarDocs(CarDocs):
package: str = "Adaptive Cruise Control (ACC) & Lane Assist"
car_parts: CarParts = field(default_factory=CarParts.common([CarHarness.vw_j533]))
def init_make(self, CP: car.CarParams):
def init_make(self, CP: structs.CarParams):
self.footnotes.append(Footnote.VW_EXP_LONG)
if "SKODA" in CP.carFingerprint:
self.footnotes.append(Footnote.SKODA_HEATED_WINDSHIELD)

View File

@ -1,6 +1,7 @@
from parameterized import parameterized
from cereal import car, log
from openpilot.selfdrive.car.card import convert_to_capnp
from openpilot.selfdrive.car.car_helpers import interfaces
from openpilot.selfdrive.car.honda.values import CAR as HONDA
from openpilot.selfdrive.car.toyota.values import CAR as TOYOTA
@ -20,6 +21,7 @@ class TestLatControl:
CarInterface, CarController, CarState = interfaces[car_name]
CP = CarInterface.get_non_essential_params(car_name)
CI = CarInterface(CP, CarController, CarState)
CP = convert_to_capnp(CP)
VM = VehicleModel(CP)
controller = controller(CP.as_reader(), CI)

View File

@ -3,6 +3,7 @@ import math
import numpy as np
from openpilot.selfdrive.car.card import convert_to_capnp
from openpilot.selfdrive.car.honda.interface import CarInterface
from openpilot.selfdrive.car.honda.values import CAR
from openpilot.selfdrive.controls.lib.vehicle_model import VehicleModel, dyn_ss_sol, create_dyn_state_matrices
@ -11,7 +12,7 @@ from openpilot.selfdrive.controls.lib.vehicle_model import VehicleModel, dyn_ss_
class TestVehicleModel:
def setup_method(self):
CP = CarInterface.get_non_essential_params(CAR.HONDA_CIVIC)
self.VM = VehicleModel(CP)
self.VM = VehicleModel(convert_to_capnp(CP))
def test_round_trip_yaw_rate(self):
# TODO: fix VM to work at zero speed

View File

@ -11,6 +11,7 @@ from openpilot.common.params import Params
from openpilot.common.realtime import DT_CTRL, Ratekeeper, Priority, config_realtime_process
from openpilot.common.swaglog import cloudlog
from openpilot.common.simple_kalman import KF1D
from openpilot.selfdrive.car import structs
from openpilot.selfdrive.pandad import can_capnp_to_list
@ -208,7 +209,7 @@ class RadarD:
self.ready = False
def update(self, sm: messaging.SubMaster, rr: car.RadarData):
def update(self, sm: messaging.SubMaster, rr: structs.RadarData):
self.ready = sm.seen['modelV2']
self.current_time = 1e-9*max(sm.logMonoTime.values())
@ -301,7 +302,7 @@ def main() -> None:
while 1:
can_strings = messaging.drain_sock_raw(can_sock, wait_for_one=True)
rr: car.RadarData | None = RI.update(can_capnp_to_list(can_strings))
rr: structs.RadarData | None = RI.update(can_capnp_to_list(can_strings))
sm.update(0)
if rr is None:
continue

View File

@ -2,28 +2,24 @@
import jinja2
import os
from cereal import car
from openpilot.common.basedir import BASEDIR
from openpilot.selfdrive.car.interfaces import get_interface_attr
Ecu = car.CarParams.Ecu
CARS = get_interface_attr('CAR')
FW_VERSIONS = get_interface_attr('FW_VERSIONS')
FINGERPRINTS = get_interface_attr('FINGERPRINTS')
ECU_NAME = {v: k for k, v in Ecu.schema.enumerants.items()}
FINGERPRINTS_PY_TEMPLATE = jinja2.Template("""
{%- if FINGERPRINTS[brand] %}
# ruff: noqa: E501
{% endif %}
{% if FW_VERSIONS[brand] %}
from cereal import car
from openpilot.selfdrive.car.structs import CarParams
{% endif %}
from openpilot.selfdrive.car.{{brand}}.values import CAR
{% if FW_VERSIONS[brand] %}
Ecu = car.CarParams.Ecu
Ecu = CarParams.Ecu
{% endif %}
{% if comments +%}
{{ comments | join() }}
@ -49,7 +45,7 @@ FW_VERSIONS{% if not FW_VERSIONS[brand] %}: dict[str, dict[tuple, list[bytes]]]{
{% for car, _ in FW_VERSIONS[brand].items() %}
CAR.{{car.name}}: {
{% for key, fw_versions in FW_VERSIONS[brand][car].items() %}
(Ecu.{{ECU_NAME[key[0]]}}, 0x{{"%0x" | format(key[1] | int)}}, \
(Ecu.{{key[0]}}, 0x{{"%0x" | format(key[1] | int)}}, \
{% if key[2] %}0x{{"%0x" | format(key[2] | int)}}{% else %}{{key[2]}}{% endif %}): [
{% for fw_version in (fw_versions + extra_fw_versions.get(car, {}).get(key, [])) | unique | sort %}
{{fw_version}},
@ -71,9 +67,8 @@ def format_brand_fw_versions(brand, extra_fw_versions: None | dict[str, dict[tup
comments = [line for line in f.readlines() if line.startswith("#") and "noqa" not in line]
with open(fingerprints_file, "w") as f:
f.write(FINGERPRINTS_PY_TEMPLATE.render(brand=brand, comments=comments, ECU_NAME=ECU_NAME,
FINGERPRINTS=FINGERPRINTS, FW_VERSIONS=FW_VERSIONS,
extra_fw_versions=extra_fw_versions))
f.write(FINGERPRINTS_PY_TEMPLATE.render(brand=brand, comments=comments, FINGERPRINTS=FINGERPRINTS,
FW_VERSIONS=FW_VERSIONS, extra_fw_versions=extra_fw_versions))
if __name__ == "__main__":

View File

@ -16,6 +16,7 @@ from openpilot.common.realtime import config_realtime_process
from openpilot.common.transformations.camera import DEVICE_CAMERAS
from openpilot.common.transformations.model import get_warp_matrix
from openpilot.system import sentry
from openpilot.selfdrive.car.card import convert_to_capnp
from openpilot.selfdrive.car.car_helpers import get_demo_car_params
from openpilot.selfdrive.controls.lib.desire_helper import DesireHelper
from openpilot.selfdrive.modeld.runners import ModelRunner, Runtime
@ -170,7 +171,7 @@ def main(demo=False):
if demo:
CP = get_demo_car_params()
CP = convert_to_capnp(get_demo_car_params())
else:
CP = messaging.log_from_bytes(params.get("CarParams", block=True), car.CarParams)

View File

@ -6,6 +6,7 @@ from msgq.visionipc import VisionIpcServer, VisionStreamType
from openpilot.common.params import Params
from openpilot.common.transformations.camera import DEVICE_CAMERAS
from openpilot.common.realtime import DT_MDL
from openpilot.selfdrive.car.card import convert_to_capnp
from openpilot.selfdrive.car.car_helpers import get_demo_car_params
from openpilot.system.manager.process_config import managed_processes
from openpilot.selfdrive.test.process_replay.vision_meta import meta_from_camera_state
@ -23,7 +24,7 @@ class TestModeld:
self.vipc_server.create_buffers(VisionStreamType.VISION_STREAM_DRIVER, 40, False, CAM.width, CAM.height)
self.vipc_server.create_buffers(VisionStreamType.VISION_STREAM_WIDE_ROAD, 40, False, CAM.width, CAM.height)
self.vipc_server.start_listener()
Params().put("CarParams", get_demo_car_params().to_bytes())
Params().put("CarParams", convert_to_capnp(get_demo_car_params()).to_bytes())
self.sm = messaging.SubMaster(['modelV2', 'cameraOdometry'])
self.pm = messaging.PubMaster(['roadCameraState', 'wideRoadCameraState', 'liveCalibration'])

View File

@ -22,8 +22,9 @@ from openpilot.common.prefix import OpenpilotPrefix
from openpilot.common.timeout import Timeout
from openpilot.common.realtime import DT_CTRL
from panda.python import ALTERNATIVE_EXPERIENCE
from openpilot.selfdrive.car.card import can_comm_callbacks
from openpilot.selfdrive.car.card import can_comm_callbacks, convert_to_capnp
from openpilot.selfdrive.car.car_helpers import get_car, interfaces
from openpilot.selfdrive.car import structs
from openpilot.system.manager.process_config import managed_processes
from openpilot.selfdrive.test.process_replay.vision_meta import meta_from_camera_state, available_streams
from openpilot.selfdrive.test.process_replay.migration import migrate_all
@ -362,14 +363,14 @@ def get_car_params_callback(rc, pm, msgs, fingerprint):
cached_params = None
if has_cached_cp:
with car.CarParams.from_bytes(cached_params_raw) as _cached_params:
cached_params = _cached_params
cached_params = structs.CarParams(carName=_cached_params.carName, carFw=_cached_params.carFw, carVin=_cached_params.carVin)
CP = get_car(*can_callbacks, lambda obd: None, Params().get_bool("ExperimentalLongitudinalEnabled"), cached_params=cached_params).CP
if not params.get_bool("DisengageOnAccelerator"):
CP.alternativeExperience |= ALTERNATIVE_EXPERIENCE.DISABLE_DISENGAGE_ON_GAS
params.put("CarParams", CP.to_bytes())
params.put("CarParams", convert_to_capnp(CP).to_bytes())
def controlsd_rcv_callback(msg, cfg, frame):

View File

@ -1 +1 @@
d768496a1a85bfe5b74c99a79203affdf9a0a065
fa4965a27dee4449ad8b255f9f7674d69327b6f7

View File

@ -36,7 +36,7 @@ MAX_TOTAL_CPU = 250. # total for all 8 cores
PROCS = {
# Baseline CPU usage by process
"selfdrive.controls.controlsd": 32.0,
"selfdrive.car.card": 22.0,
"selfdrive.car.card": 26.0,
"./loggerd": 14.0,
"./encoderd": 17.0,
"./camerad": 14.5,

View File

@ -9,6 +9,7 @@ import cereal.messaging as messaging
from cereal.services import SERVICE_LIST
from openpilot.common.mock import mock_messages
from openpilot.common.params import Params
from openpilot.selfdrive.car.card import convert_to_capnp
from openpilot.selfdrive.car.car_helpers import get_demo_car_params
from openpilot.system.hardware.tici.power_monitor import get_power
from openpilot.system.manager.process_config import managed_processes
@ -42,7 +43,7 @@ PROCS = [
class TestPowerDraw:
def setup_method(self):
Params().put("CarParams", get_demo_car_params().to_bytes())
Params().put("CarParams", convert_to_capnp(get_demo_car_params()).to_bytes())
# wait a bit for power save to disable
time.sleep(5)