This commit is contained in:
firestar5683
2026-05-12 21:10:14 -05:00
parent d7e43b7ecc
commit af84c8802b
17 changed files with 820 additions and 151 deletions
Binary file not shown.
+243 -61
View File
@@ -1,73 +1,255 @@
from openpilot.common.params_pyx import Params as _Params, ParamKeyFlag, ParamKeyType, UnknownKeyName
assert _Params
assert ParamKeyFlag
assert ParamKeyType
assert UnknownKeyName
from __future__ import annotations
from enum import IntEnum, IntFlag
from pathlib import Path
import tempfile
class Params(_Params):
def get(self, key, block=False, return_default=False, encoding=None, default=None):
try:
value = super().get(key, block=block, return_default=return_default)
except UnknownKeyName:
return default
if value is None:
return default
if encoding is not None and isinstance(value, bytes):
try:
from openpilot.common.params_pyx import Params as _Params, ParamKeyFlag, ParamKeyType, UnknownKeyName
except Exception:
class UnknownKeyName(KeyError):
pass
class ParamKeyFlag(IntFlag):
PERSISTENT = 0x02
CLEAR_ON_MANAGER_START = 0x04
CLEAR_ON_ONROAD_TRANSITION = 0x08
CLEAR_ON_OFFROAD_TRANSITION = 0x10
DONT_LOG = 0x20
DEVELOPMENT_ONLY = 0x40
CLEAR_ON_IGNITION_ON = 0x80
ALL = 0xFFFFFFFF
class ParamKeyType(IntEnum):
STRING = 0
BOOL = 1
INT = 2
FLOAT = 3
TIME = 4
JSON = 5
BYTES = 6
def _load_key_types() -> dict[str, ParamKeyType]:
key_types: dict[str, ParamKeyType] = {}
params_keys = Path(__file__).with_name("params_keys.h")
if not params_keys.exists():
return key_types
for line in params_keys.read_text(encoding="utf-8", errors="ignore").splitlines():
if not line.lstrip().startswith('{"'):
continue
parts = line.split('"')
if len(parts) < 2:
continue
key = parts[1]
for type_name in ParamKeyType.__members__:
if f", {type_name}" in line:
key_types[key] = ParamKeyType[type_name]
break
else:
key_types[key] = ParamKeyType.STRING
return key_types
_KEY_TYPES = _load_key_types()
_PERSISTENT_STORE: dict[str, object] = {}
_MEMORY_STORE: dict[str, object] = {}
class Params:
def __init__(self, d: str | None = None, memory: bool = False, return_defaults: bool = False):
self.d = d if d is not None else ""
self.m = memory
self.return_defaults = return_defaults
self._store = _MEMORY_STORE if memory else _PERSISTENT_STORE
def __reduce__(self):
return type(self), (self.d, self.m, self.return_defaults)
def clear_all(self, tx_flag=ParamKeyFlag.ALL):
self._store.clear()
def check_key(self, key):
if isinstance(key, bytes):
key = key.decode("utf-8")
return str(key)
def _coerce_bool(self, value) -> bool:
if isinstance(value, bool):
return value
if isinstance(value, (int, float)):
return bool(value)
if isinstance(value, bytes):
return value == b"1"
if isinstance(value, str):
return value.strip().lower() not in ("", "0", "false", "none", "null")
return bool(value)
def _coerce_value(self, key: str, value):
value_type = self.get_type(key)
if value_type == ParamKeyType.BOOL:
return self._coerce_bool(value)
if value_type == ParamKeyType.INT:
return int(float(value))
if value_type == ParamKeyType.FLOAT:
return float(value)
if value_type == ParamKeyType.BYTES and isinstance(value, str):
return value.encode("utf-8")
return value
def get(self, key, block: bool = False, return_default: bool = False, encoding=None, default=None):
key = self.check_key(key)
value = self._store.get(key, default)
if value is None:
return default
if encoding is not None and isinstance(value, bytes):
try:
return value.decode(encoding)
except Exception:
return value.decode("utf-8", errors="replace")
return value
def get_bool(self, key, block: bool = False, default: bool = False):
value = self.get(key, block=block, return_default=True, default=default)
return self._coerce_bool(value)
def get_int(self, key, block: bool = False, return_default: bool = False, default: int = 0):
value = self.get(key, block=block, return_default=return_default, encoding="utf-8", default=default)
if value is None or value == "":
return default
try:
return value.decode(encoding)
except Exception:
return value.decode("utf-8", errors="replace")
return value
return int(float(value))
except (TypeError, ValueError):
return default
def get_bool(self, key, block=False, default=False):
try:
result = super().get(key, block=block, return_default=True)
if result is None:
def get_float(self, key, block: bool = False, return_default: bool = False, default: float = 0.0):
value = self.get(key, block=block, return_default=return_default, encoding="utf-8", default=default)
if value is None or value == "":
return default
try:
return float(value)
except (TypeError, ValueError):
return default
def put(self, key, dat):
key = self.check_key(key)
self._store[key] = self._coerce_value(key, dat)
def put_bool(self, key, val: bool):
self.put(key, bool(val))
def put_nonblocking(self, key, dat):
self.put(key, dat)
def put_bool_nonblocking(self, key, val: bool):
self.put_bool(key, val)
def put_int(self, key, val):
self.put(key, int(val))
def put_float(self, key, val):
self.put(key, float(val))
def remove(self, key):
self._store.pop(self.check_key(key), None)
def get_param_path(self, key: str = ""):
base = Path(tempfile.gettempdir()) / ("params_memory" if self.m else "params")
base.mkdir(parents=True, exist_ok=True)
return str(base / key) if key else str(base)
def get_type(self, key):
return _KEY_TYPES.get(self.check_key(key), ParamKeyType.STRING)
def all_keys(self):
return list(_KEY_TYPES)
def get_default_value(self, key):
return None
def cpp2python(self, key, value):
return self._coerce_value(self.check_key(key), value)
def get_key_flag(self, key):
return ParamKeyFlag.PERSISTENT
def get_stock_value(self, key):
return None
def get_tuning_level(self, key):
return 0
else:
assert _Params
assert ParamKeyFlag
assert ParamKeyType
assert UnknownKeyName
class Params(_Params):
def get(self, key, block=False, return_default=False, encoding=None, default=None):
try:
value = super().get(key, block=block, return_default=return_default)
except UnknownKeyName:
return default
if value is None:
return default
if encoding is not None and isinstance(value, bytes):
try:
return value.decode(encoding)
except Exception:
return value.decode("utf-8", errors="replace")
return value
def get_bool(self, key, block=False, default=False):
try:
result = super().get(key, block=block, return_default=True)
if result is None:
return bool(default)
return bool(result)
except UnknownKeyName:
return bool(default)
return bool(result)
except UnknownKeyName:
return bool(default)
def get_int(self, key, block=False, return_default=False, default=0):
val = self.get(key, block=block, return_default=return_default, encoding="utf-8")
if val is None or val == "":
return default
try:
return int(float(val))
except ValueError:
return default
def get_int(self, key, block=False, return_default=False, default=0):
val = self.get(key, block=block, return_default=return_default, encoding="utf-8")
if val is None or val == "":
return default
try:
return int(float(val))
except ValueError:
return default
def get_float(self, key, block=False, return_default=False, default=0.0):
val = self.get(key, block=block, return_default=return_default, encoding="utf-8")
if val is None or val == "":
return default
try:
return float(val)
except ValueError:
return default
def get_float(self, key, block=False, return_default=False, default=0.0):
val = self.get(key, block=block, return_default=return_default, encoding="utf-8")
if val is None or val == "":
return default
try:
return float(val)
except ValueError:
return default
def put_int(self, key, val):
t = self.get_type(key)
if t == ParamKeyType.FLOAT:
self.put(key, float(val))
elif t == ParamKeyType.INT:
self.put(key, int(val))
elif t == ParamKeyType.BOOL:
self.put(key, bool(val))
else:
self.put(key, str(int(val)))
def put_int(self, key, val):
t = self.get_type(key)
if t == ParamKeyType.FLOAT:
self.put(key, float(val))
elif t == ParamKeyType.INT:
self.put(key, int(val))
elif t == ParamKeyType.BOOL:
self.put(key, bool(val))
else:
self.put(key, str(int(val)))
def put_float(self, key, val):
t = self.get_type(key)
if t == ParamKeyType.FLOAT:
self.put(key, float(val))
elif t == ParamKeyType.INT:
self.put(key, int(val))
elif t == ParamKeyType.BOOL:
self.put(key, bool(val))
else:
self.put(key, str(float(val)))
def put_float(self, key, val):
t = self.get_type(key)
if t == ParamKeyType.FLOAT:
self.put(key, float(val))
elif t == ParamKeyType.INT:
self.put(key, int(val))
elif t == ParamKeyType.BOOL:
self.put(key, bool(val))
else:
self.put(key, str(float(val)))
if __name__ == "__main__":
import sys
+2
View File
@@ -59,6 +59,8 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"GsmRoaming", {PERSISTENT, BOOL}},
{"HardwareSerial", {PERSISTENT, STRING}},
{"HasAcceptedTerms", {PERSISTENT, STRING, "0"}},
{"HondaGasFactorParams", {PERSISTENT, FLOAT}},
{"HondaWindFactorParams", {PERSISTENT, FLOAT}},
{"InstallDate", {PERSISTENT, TIME}},
{"IsDriverViewEnabled", {CLEAR_ON_MANAGER_START, BOOL}},
{"IsEngaged", {PERSISTENT, BOOL}},
Binary file not shown.
+97 -26
View File
@@ -2,7 +2,8 @@ import math
import numpy as np
from opendbc.can import CANPacker
from opendbc.car import ACCELERATION_DUE_TO_GRAVITY, Bus, DT_CTRL, rate_limit, make_tester_present_msg, structs
from opendbc.car import ACCELERATION_DUE_TO_GRAVITY, Bus, DT_CTRL, create_gas_interceptor_command, rate_limit, make_tester_present_msg, structs
from opendbc.car.common.pid import PIDController
from opendbc.car.honda import hondacan
from opendbc.car.honda.values import (
CAR,
@@ -16,6 +17,7 @@ from opendbc.car.honda.values import (
HondaFlags,
)
from opendbc.car.interfaces import CarControllerBase
from openpilot.common.params import Params
VisualAlert = structs.CarControl.HUDControl.VisualAlert
LongCtrlState = structs.CarControl.Actuators.LongControlState
@@ -206,6 +208,7 @@ class CarController(CarControllerBase):
super().__init__(dbc_names, CP)
self.packer = CANPacker(dbc_names[Bus.pt])
self.params = CarControllerParams(CP)
self.param_store = Params()
self.CAN = hondacan.CanBus(CP)
self.tja_control = CP.carFingerprint in HONDA_BOSCH_TJA_CONTROL
@@ -225,10 +228,15 @@ class CarController(CarControllerBase):
self.prev_torque_cmd = 0.0
self.steering_pressed_filter_s = 0.0
self.steering_pressed_robust_prev = False
self.bosch_gas_factor = 1.0
self.bosch_wind_factor = 1.0
self.bosch_wind_factor_before_brake = 0.0
self.bosch_last_gas = 0.0
self.bosch_gas_factor = self.param_store.get_float("HondaGasFactorParams", default=1.0)
self.bosch_wind_factor = self.param_store.get_float("HondaWindFactorParams", default=1.0)
self.bosch_wind_factor_before_brake = self.bosch_wind_factor
self.bosch_gas_factor_before_gasmax = self.bosch_gas_factor
self.bosch_wind_factor_before_gasmax = self.bosch_wind_factor
self.pitch = 0.0
self.brake_pid = PIDController(k_p=([0.0], [0.0]), k_i=([0.0], [0.5]), pos_limit=0.0, neg_limit=-2.0, rate=50)
self.brake_pid.reset()
def _modified_civic_standard_active(self) -> bool:
return self.CP.carFingerprint == CAR.HONDA_CIVIC_BOSCH and bool(self.CP.flags & HondaFlags.EPS_MODIFIED)
@@ -249,6 +257,7 @@ class CarController(CarControllerBase):
hud_control = CC.hudControl
hud_v_cruise = hud_control.setSpeed / CS.v_cruise_factor if hud_control.speedVisible else 255
pcm_cancel_cmd = CC.cruiseControl.cancel
gas_interceptor_command = 0.0
if len(CC.orientationNED) == 3:
self.pitch = CC.orientationNED[1]
hill_brake = math.sin(self.pitch) * ACCELERATION_DUE_TO_GRAVITY
@@ -305,20 +314,21 @@ class CarController(CarControllerBase):
# tester present - w/ no response (keeps radar disabled)
if self.CP.carFingerprint in (HONDA_BOSCH - HONDA_BOSCH_RADARLESS) and self.CP.openpilotLongitudinalControl:
if self.frame % 10 == 0:
can_sends.append(make_tester_present_msg(0x18DAB0F1, 1, suppress_response=True))
can_sends.append(make_tester_present_msg(0x18DAB0F1, self.CAN.pt, suppress_response=True))
# Send steering command.
can_sends.append(hondacan.create_steering_control(self.packer, self.CAN, apply_torque, CC.latActive, self.tja_control))
# wind brake from air resistance decel at high speed
wind_brake = np.interp(CS.out.vEgo, [0.0, 2.3, 35.0], [0.001, 0.002, 0.15])
wind_brake = float(np.interp(CS.out.vEgo, [0.0, 2.3, 35.0], [0.001, 0.002, 0.15]))
wind_brake_mps2 = get_honda_bosch_wind_brake_mps2(CS.out.vEgo)
# all of this is only relevant for HONDA NIDEC
max_accel = np.interp(CS.out.vEgo, self.params.NIDEC_MAX_ACCEL_BP, self.params.NIDEC_MAX_ACCEL_V)
# TODO this 1.44 is just to maintain previous behavior
pcm_speed_BP = [-wind_brake, -wind_brake * (3 / 4), 0.0, 0.5]
# The Honda ODYSSEY seems to have different PCM_ACCEL
# msgs, is it other cars too?
if not CC.longActive:
if self.CP.enableGasInterceptorDEPRECATED or not CC.longActive:
pcm_speed = 0.0
pcm_accel = int(0.0)
elif self.CP.carFingerprint in HONDA_NIDEC_ALT_PCM_ACCEL:
@@ -345,27 +355,54 @@ class CarController(CarControllerBase):
ts = self.frame * DT_CTRL
if self.CP.carFingerprint in HONDA_BOSCH:
self.accel = float(np.clip(accel, self.params.BOSCH_ACCEL_MIN, self.params.BOSCH_ACCEL_MAX))
gas_pedal_force = self.accel
if accel < 0.0 and CS.out.vEgo > 1e-3:
brake_addon = self.brake_pid.update(error=accel - CS.out.aEgo, speed=CS.out.vEgo)
target_accel = min(accel, accel + brake_addon)
else:
self.brake_pid.reset()
target_accel = accel
self.accel = float(np.clip(target_accel, self.params.BOSCH_ACCEL_MIN, self.params.BOSCH_ACCEL_MAX))
gas_pedal_force = self.accel + hill_brake
if self.CP.carFingerprint not in HONDA_BOSCH_RADARLESS:
wind_brake_mps2 = get_honda_bosch_wind_brake_mps2(CS.out.vEgo)
if (actuators.longControlState == LongCtrlState.pid) and (not CS.out.gasPressed):
gas_pedal_force += wind_brake_mps2 * self.bosch_wind_factor + hill_brake
self.bosch_gas_factor, self.bosch_wind_factor, self.bosch_wind_factor_before_brake = update_honda_bosch_live_learning(
self.bosch_gas_factor,
self.bosch_wind_factor,
self.bosch_wind_factor_before_brake,
self.accel,
CS.out.aEgo,
gas_pedal_force,
wind_brake_mps2,
bool(CS.out.brakePressed),
CS.out.vEgo,
)
else:
gas_pedal_force += wind_brake_mps2 + hill_brake
gas_pedal_force += wind_brake_mps2 * self.bosch_wind_factor
if actuators.longControlState == LongCtrlState.pid and not CS.out.gasPressed:
gas_error = self.accel - CS.out.aEgo
if gas_error != 0.0 and gas_pedal_force > 0.0:
if self.CP.carFingerprint == CAR.HONDA_INSIGHT:
gas_learn_speed = 150.0
elif self.CP.carFingerprint in (CAR.ACURA_RDX_3G, CAR.ACURA_RDX_3G_MMR):
gas_learn_speed = 300.0
else:
gas_learn_speed = 50.0
self.bosch_gas_factor = float(np.clip(self.bosch_gas_factor + gas_error / gas_learn_speed * gas_pedal_force, 0.1, 3.0))
if gas_error != 0.0 and not CS.out.brakePressed and CS.out.vEgo > 0.0:
wind_learn_speed = 100.0 if self.CP.carFingerprint in (CAR.ACURA_RDX_3G, CAR.ACURA_RDX_3G_MMR) else 1000.0
wind_adjust = 1.0 + wind_brake_mps2 / wind_learn_speed
if gas_error > 0.0:
self.bosch_wind_factor = float(np.clip(self.bosch_wind_factor * wind_adjust, 0.1, 3.0))
else:
self.bosch_wind_factor = float(np.clip(self.bosch_wind_factor / wind_adjust, 0.1, 3.0))
if gas_pedal_force <= 0.0:
self.bosch_wind_factor = max(self.bosch_wind_factor, self.bosch_wind_factor_before_brake)
else:
self.bosch_wind_factor_before_brake = self.bosch_wind_factor
if gas_pedal_force >= self.params.BOSCH_ACCEL_MAX:
self.bosch_gas_factor = min(self.bosch_gas_factor, self.bosch_gas_factor_before_gasmax)
self.bosch_wind_factor = min(self.bosch_wind_factor, self.bosch_wind_factor_before_gasmax)
else:
self.bosch_gas_factor_before_gasmax = self.bosch_gas_factor
self.bosch_wind_factor_before_gasmax = self.bosch_wind_factor
self.gas = float(np.interp(gas_pedal_force * self.bosch_gas_factor, self.params.BOSCH_GAS_LOOKUP_BP, self.params.BOSCH_GAS_LOOKUP_V))
self.gas = min(self.gas, max(60.0, self.bosch_last_gas + 60.0))
self.bosch_last_gas = self.gas
stopping = actuators.longControlState == LongCtrlState.stopping
self.stopping_counter = self.stopping_counter + 1 if stopping else 0
@@ -386,6 +423,33 @@ class CarController(CarControllerBase):
self.apply_brake_last = apply_brake
self.brake = apply_brake / self.params.NIDEC_BRAKE_MAX
if self.CP.enableGasInterceptorDEPRECATED:
gas_error = actuators.accel - CS.out.aEgo
if not CS.out.gasPressed and actuators.longControlState == LongCtrlState.pid:
if gas_error != 0.0 and gas > 0.0:
self.bosch_gas_factor = float(np.clip(self.bosch_gas_factor + gas_error / 150.0 * (gas * 4.8), 0.1, 3.0))
if gas_error != 0.0 and not CS.out.brakePressed and CS.out.vEgo > 0.0:
wind_adjust = 1.0 + (wind_brake * 4.8) / 1000.0
if gas_error > 0.0:
self.bosch_wind_factor = float(np.clip(self.bosch_wind_factor * wind_adjust, 0.1, 5.0))
else:
self.bosch_wind_factor = float(np.clip(self.bosch_wind_factor / wind_adjust, 0.1, 5.0))
if gas <= 0.0:
self.bosch_wind_factor = max(self.bosch_wind_factor, self.bosch_wind_factor_before_brake)
else:
self.bosch_wind_factor_before_brake = self.bosch_wind_factor
gas_mult = float(np.interp(CS.out.vEgo, [0.0, 10.0], [0.4, 1.0]))
if CC.longActive:
gas_interceptor_command = float(np.clip(
gas_mult * ((gas * self.bosch_gas_factor) - brake + (wind_brake * self.bosch_wind_factor * 3.0 / 4.0)),
0.0,
1.0,
))
idx = (self.frame // 2) % 0x10
can_sends.append(create_gas_interceptor_command(self.packer, gas_interceptor_command, idx))
# Send dashboard UI commands.
if self.frame % 10 == 0:
if self.CP.openpilotLongitudinalControl:
@@ -410,7 +474,14 @@ class CarController(CarControllerBase):
can_sends.append(hondacan.create_legacy_brake_command(self.packer, self.CAN.pt))
if self.CP.carFingerprint not in HONDA_BOSCH:
self.speed = pcm_speed
self.gas = pcm_accel / self.params.NIDEC_GAS_MAX
if self.CP.enableGasInterceptorDEPRECATED:
self.gas = gas_interceptor_command
else:
self.gas = pcm_accel / self.params.NIDEC_GAS_MAX
if self.frame > 0 and self.frame % 6000 == 0:
self.param_store.put_float("HondaGasFactorParams", self.bosch_gas_factor)
self.param_store.put_float("HondaWindFactorParams", self.bosch_wind_factor)
new_actuators = actuators.as_builder()
new_actuators.speed = self.speed
+49 -22
View File
@@ -3,11 +3,11 @@ from collections import defaultdict
from cereal import custom
from opendbc.can import CANDefine, CANParser
from opendbc.car import Bus, create_button_events, structs
from opendbc.car import Bus, DT_CTRL, create_button_events, structs
from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.honda.hondacan import CanBus
from opendbc.car.honda.values import CAR, DBC, STEER_THRESHOLD, HONDA_BOSCH, HONDA_BOSCH_ALT_RADAR, HONDA_BOSCH_CANFD, \
HONDA_NIDEC_ALT_SCM_MESSAGES, HONDA_BOSCH_RADARLESS, \
HONDA_NIDEC_ALT_SCM_MESSAGES, HONDA_BOSCH_RADARLESS, HONDA_BOSCH_TJA_CONTROL, \
HondaFlags, CruiseButtons, CruiseSettings, GearShifter, CarControllerParams, HondaStarPilotFlags
from opendbc.car.interfaces import CarStateBase
@@ -54,13 +54,19 @@ class CarState(CarStateBase):
self.brake_switch_active = False
self.low_speed_alert = False
self.dynamic_v_cruise_units = self.CP.carFingerprint in (HONDA_BOSCH_RADARLESS | HONDA_BOSCH_ALT_RADAR | HONDA_BOSCH_CANFD)
self.dynamic_v_cruise_units = self.CP.carFingerprint in (HONDA_BOSCH_RADARLESS | HONDA_BOSCH_ALT_RADAR |
HONDA_BOSCH_TJA_CONTROL | HONDA_BOSCH_CANFD)
self.cruise_setting = 0
self.v_cruise_pcm_prev = 0
# When available we use cp.vl["CAR_SPEED"]["ROUGH_CAR_SPEED_2"] to populate vEgoCluster
# However, on cars without a digital speedometer this is not always present (HRV, FIT, CRV 2016, ILX and RDX)
self.dash_speed_seen = False
self.is_metric = False
self.v_cruise_factor = 1.
self.initial_accFault_cleared = False
self.initial_accFault_cleared_timer = int(10 / DT_CTRL)
def update(self, can_parsers, starpilot_toggles) -> structs.CarState:
cp = can_parsers[Bus.pt]
@@ -81,18 +87,19 @@ class CarState(CarStateBase):
self.cruise_buttons = cp.vl["SCM_BUTTONS"]["CRUISE_BUTTONS"]
# used for car hud message
self.is_metric = not cp.vl["CAR_SPEED"]["IMPERIAL_UNIT"]
self.is_metric = self.CP.carFingerprint in (CAR.HONDA_ODYSSEY_TWN,) or not cp.vl["CAR_SPEED"]["IMPERIAL_UNIT"]
self.v_cruise_factor = CV.MPH_TO_MS if self.dynamic_v_cruise_units and not self.is_metric else CV.KPH_TO_MS
# ******************* parse out can *******************
# blend in transmission speed at low speed, since it has more low speed accuracy
# STANDSTILL->WHEELS_MOVING bit can be noisy around zero, so use XMISSION_SPEED
lowspeed_source = cp.vl["CAR_SPEED"]["CAR_SPEED"] if self.CP.carFingerprint == CAR.ACURA_INTEGRA else cp.vl["ENGINE_DATA"]["XMISSION_SPEED"]
v_wheel = sum([cp.vl["WHEEL_SPEEDS"][f"WHEEL_SPEED_{s}"] for s in ("FL", "FR", "RL", "RR")]) / 4.0 * CV.KPH_TO_MS
v_weight = float(np.interp(v_wheel, v_weight_bp, v_weight_v))
ret.vEgoRaw = (1. - v_weight) * cp.vl["ENGINE_DATA"]["XMISSION_SPEED"] * CV.KPH_TO_MS * self.CP.wheelSpeedFactor + v_weight * v_wheel
ret.vEgoRaw = (1. - v_weight) * lowspeed_source * CV.KPH_TO_MS * self.CP.wheelSpeedFactor + v_weight * v_wheel
ret.vEgo, ret.aEgo = self.update_speed_kf(ret.vEgoRaw)
ret.standstill = cp.vl["ENGINE_DATA"]["XMISSION_SPEED"] < 1e-5
ret.standstill = lowspeed_source < 1e-5
# doorOpen is true if we can find any door open, but signal locations vary, and we may only see the driver's door
# TODO: Test the eight Nidec cars without SCM signals for driver's door state, may be able to consolidate further
@@ -107,7 +114,8 @@ class CarState(CarStateBase):
ret.seatbeltUnlatched = bool(cp.vl["SEATBELT_STATUS"]["SEATBELT_DRIVER_LAMP"] or not cp.vl["SEATBELT_STATUS"]["SEATBELT_DRIVER_LATCHED"])
steer_status = self.steer_status_values[cp.vl["STEER_STATUS"]["STEER_STATUS"]]
ret.steerFaultPermanent = steer_status not in ("NORMAL", "NO_TORQUE_ALERT_1", "NO_TORQUE_ALERT_2", "LOW_SPEED_LOCKOUT", "TMP_FAULT")
ret.steerFaultPermanent = steer_status not in ("NORMAL", "NO_TORQUE_ALERT_1", "NO_TORQUE_ALERT_2", "LOW_SPEED_LOCKOUT", "TJA_LOW_SPEED_LOCKOUT",
"TMP_FAULT")
if self.CP.carFingerprint in HONDA_BOSCH_ALT_RADAR:
# TODO: See if this logic works for all other Honda
min_steer_speed = max(CarControllerParams.STEER_GLOBAL_MIN_SPEED, self.CP.minSteerSpeed)
@@ -117,7 +125,11 @@ class CarState(CarStateBase):
# LOW_SPEED_LOCKOUT is not worth a warning
# NO_TORQUE_ALERT_2 can be caused by bump or steering nudge from driver
# FIXME: the stock camera stops steering on NO_TORQUE_ALERT_1
ret.steerFaultTemporary = steer_status not in ("NORMAL", "LOW_SPEED_LOCKOUT", "NO_TORQUE_ALERT_2")
ret.steerFaultTemporary = steer_status not in ("NORMAL", "LOW_SPEED_LOCKOUT", "TJA_LOW_SPEED_LOCKOUT", "NO_TORQUE_ALERT_2")
if self.CP.carFingerprint == CAR.ACURA_MDX_4G and steer_status == "TJA_LOW_SPEED_LOCKOUT":
ret.steerFaultPermanent = False
ret.steerFaultTemporary = False
# All Honda EPS cut off slightly above standstill, some much higher
# Don't alert in the near-standstill range, but alert for per-vehicle configured minimums above that
@@ -128,22 +140,23 @@ class CarState(CarStateBase):
self.low_speed_alert = False
ret.lowSpeedAlert = self.low_speed_alert
if self.CP.carFingerprint in HONDA_BOSCH_RADARLESS:
if self.CP.carFingerprint not in HONDA_BOSCH:
ret.carFaultedNonCritical = bool(cp_cam.vl["ACC_HUD"]["ACC_PROBLEM"] or cp_cam.vl["LKAS_HUD"]["LKAS_PROBLEM"])
elif self.CP.carFingerprint in HONDA_BOSCH_RADARLESS:
ret.accFaulted = bool(cp.vl["CRUISE_FAULT_STATUS"]["CRUISE_FAULT"])
else:
if self.CP.openpilotLongitudinalControl:
elif self.CP.openpilotLongitudinalControl:
if self.CP.carFingerprint in (HONDA_BOSCH_CANFD | HONDA_BOSCH_TJA_CONTROL) and (self.CP.flags & HondaFlags.BOSCH_ALT_BRAKE):
ret.accFaulted = bool(cp.vl["BRAKE_MODULE"]["CRUISE_FAULT"])
else:
ret.accFaulted = bool(cp.vl[self.brake_error_msg]["BRAKE_ERROR_1"] or cp.vl[self.brake_error_msg]["BRAKE_ERROR_2"])
# Log non-critical stock ACC/LKAS faults if Nidec (camera)
if self.CP.carFingerprint not in HONDA_BOSCH:
ret.carFaultedNonCritical = bool(cp_cam.vl["ACC_HUD"]["ACC_PROBLEM"] or cp_cam.vl["LKAS_HUD"]["LKAS_PROBLEM"])
ret.espDisabled = cp.vl["VSA_STATUS"]["ESP_DISABLED"] != 0
self.dash_speed_seen = self.dash_speed_seen or cp.vl["CAR_SPEED"]["ROUGH_CAR_SPEED_2"] > 1e-3
if self.dash_speed_seen:
conversion = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS
ret.vEgoCluster = cp.vl["CAR_SPEED"]["ROUGH_CAR_SPEED_2"] * conversion
if self.CP.carFingerprint not in (CAR.HONDA_ODYSSEY_TWN,):
self.dash_speed_seen = self.dash_speed_seen or cp.vl["CAR_SPEED"]["ROUGH_CAR_SPEED_2"] > 1e-3
if self.dash_speed_seen:
conversion = CV.KPH_TO_MS if self.is_metric else CV.MPH_TO_MS
ret.vEgoCluster = cp.vl["CAR_SPEED"]["ROUGH_CAR_SPEED_2"] * conversion
ret.steeringAngleDeg = cp.vl["STEERING_SENSORS"]["STEER_ANGLE"]
ret.steeringRateDeg = cp.vl["STEERING_SENSORS"]["STEER_ANGLE_RATE"]
@@ -154,12 +167,16 @@ class CarState(CarStateBase):
ret.parkingBrake = bool(cp.vl[self.car_state_scm_msg]["PARKING_BRAKE_ON"])
if self.CP.transmissionType == TransmissionType.manual:
ret.gearShifter = GearShifter.reverse if bool(cp.vl["SCM_FEEDBACK"]["REVERSE_LIGHT"]) else GearShifter.drive
ret.gearShifter = GearShifter.reverse if bool(cp.vl[self.car_state_scm_msg]["REVERSE_LIGHT"]) else GearShifter.drive
else:
gear_position = self.shifter_values.get(cp.vl[self.gearbox_msg]["GEAR_SHIFTER"], None)
ret.gearShifter = self.parse_gear_shifter(gear_position)
ret.gasPressed = cp.vl["POWERTRAIN_DATA"]["PEDAL_GAS"] > 1e-5
if self.CP.enableGasInterceptorDEPRECATED:
gas = (cp.vl["GAS_SENSOR"]["INTERCEPTOR_GAS"] + cp.vl["GAS_SENSOR"]["INTERCEPTOR_GAS2"]) / 2.
ret.gasPressed = gas > 492
else:
ret.gasPressed = cp.vl["POWERTRAIN_DATA"]["PEDAL_GAS"] > 1e-5
ret.steeringTorque = cp.vl["STEER_STATUS"]["STEER_TORQUE_SENSOR"]
ret.steeringPressed = abs(ret.steeringTorque) > STEER_THRESHOLD.get(self.CP.carFingerprint, 1200)
@@ -200,6 +217,16 @@ class CarState(CarStateBase):
ret.cruiseState.enabled = cp.vl["POWERTRAIN_DATA"]["ACC_STATUS"] != 0
ret.cruiseState.available = bool(cp.vl[self.car_state_scm_msg]["MAIN_ON"])
if ret.accFaulted:
if self.CP.carFingerprint in HONDA_BOSCH and not self.initial_accFault_cleared:
ret.accFaulted = False
ret.cruiseState.available = False
elif self.initial_accFault_cleared_timer == 0:
self.initial_accFault_cleared = True
if self.initial_accFault_cleared_timer > 0:
self.initial_accFault_cleared_timer -= 1
# Gets rid of Pedal Grinding noise when brake is pressed at slow speeds for some models
if self.CP.carFingerprint in (CAR.HONDA_PILOT, CAR.HONDA_RIDGELINE):
if ret.brake > 0.1:
@@ -218,7 +245,7 @@ class CarState(CarStateBase):
ret.stockFcw = cp_cam.vl["BRAKE_COMMAND"]["FCW"] != 0
self.acc_hud = cp_cam.vl["ACC_HUD"]
self.stock_brake = cp_cam.vl["BRAKE_COMMAND"]
if self.CP.carFingerprint in HONDA_BOSCH_RADARLESS:
if self.CP.carFingerprint in (HONDA_BOSCH_RADARLESS | HONDA_BOSCH_CANFD):
self.lkas_hud = cp_cam.vl["LKAS_HUD"]
if self.CP.enableBsm:
+101 -10
View File
@@ -23,6 +23,8 @@ class CarInterface(CarInterfaceBase):
def get_pid_accel_limits(CP, current_speed, cruise_speed):
if CP.carFingerprint in HONDA_BOSCH:
return CarControllerParams.BOSCH_ACCEL_MIN, CarControllerParams.BOSCH_ACCEL_MAX
elif CP.enableGasInterceptorDEPRECATED:
return CarControllerParams.NIDEC_ACCEL_MIN, CarControllerParams.NIDEC_ACCEL_MAX
else:
# NIDECs don't allow acceleration near cruise_speed,
# so limit limits of pid to prevent windup
@@ -46,15 +48,17 @@ class CarInterface(CarInterfaceBase):
# Disable the radar and let openpilot control longitudinal
# WARNING: THIS DISABLES AEB!
# If Bosch radarless, this blocks ACC messages from the camera
# TODO: get radar disable working on Bosch CANFD
ret.alphaLongitudinalAvailable = candidate not in HONDA_BOSCH_CANFD
ret.openpilotLongitudinalControl = alpha_long and (candidate not in HONDA_BOSCH_CANFD)
ret.alphaLongitudinalAvailable = True
ret.openpilotLongitudinalControl = alpha_long
ret.pcmCruise = not ret.openpilotLongitudinalControl
else:
ret.safetyConfigs = [get_safety_config(structs.CarParams.SafetyModel.hondaNidec)]
ret.openpilotLongitudinalControl = True
ret.pcmCruise = True
ret.enableGasInterceptorDEPRECATED = 0x201 in fingerprint[CAN.pt]
if ret.enableGasInterceptorDEPRECATED:
ret.pcmCruise = False
if candidate == CAR.HONDA_CRV_5G:
ret.enableBsm = 0x12f8bfa7 in fingerprint[CAN.radar]
@@ -80,6 +84,7 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kpBP = [[0.], [0.]]
ret.lateralTuning.pid.kf = 0.00006 # conservative feed-forward
ret.steerActuatorDelay = 0.1
ret.stoppingDecelRate = 0.3
if candidate in HONDA_BOSCH:
ret.longitudinalActuatorDelay = 0.5 # s
@@ -98,6 +103,11 @@ class CarInterface(CarInterfaceBase):
if eps_modified:
ret.flags |= HondaFlags.EPS_MODIFIED.value
if candidate == CAR.HONDA_CITY_7G:
ret.vEgoStopping = 2.0
ret.vEgoStarting = ret.vEgoStopping
ret.stoppingDecelRate = 0.3
if candidate == CAR.HONDA_CIVIC:
if eps_modified:
# stock request input values: 0x0000, 0x00DE, 0x014D, 0x01EF, 0x0290, 0x0377, 0x0454, 0x0610, 0x06EE
@@ -129,6 +139,13 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.3], [0.09]]
else:
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.18]]
if ret.transmissionType == TransmissionType.manual:
CarControllerParams.BOSCH_GAS_LOOKUP_BP = [-0.2, 2.0]
elif candidate == CAR.HONDA_ACCORD_11G:
ret.steerActuatorDelay = 0.22
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560, 5200], [0, 2560, 12747]]
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate == CAR.ACURA_ILX:
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 3840], [0, 3840]] # TODO: determine if there is a dead zone at the top end
@@ -156,6 +173,13 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.18]]
ret.wheelSpeedFactor = 1.025
elif candidate == CAR.HONDA_CRV_6G:
ret.steerActuatorDelay = 0.15
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 5100], [0, 5100]]
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
if ret.flags & HondaFlags.HYBRID:
CarControllerParams.BOSCH_GAS_LOOKUP_BP = [-0.3, 2.0]
elif candidate == CAR.HONDA_FIT:
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.2], [0.05]]
@@ -182,16 +206,38 @@ class CarInterface(CarInterfaceBase):
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.8], [0.24]]
elif candidate == CAR.ACURA_RDX_3G:
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 3840], [0, 3840]]
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4095], [0, 4095]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.2], [0.06]]
CarControllerParams.BOSCH_GAS_LOOKUP_V = [0, 2200]
elif candidate == CAR.ACURA_RDX_3G_MMR:
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 3840], [0, 3840]]
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
CarControllerParams.BOSCH_GAS_LOOKUP_V = [0, 2000]
if not ret.openpilotLongitudinalControl:
ret.minSteerSpeed = 70. * CV.KPH_TO_MS
elif candidate == CAR.HONDA_ODYSSEY:
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.28], [0.08]]
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end
elif candidate == CAR.HONDA_PILOT:
elif candidate == CAR.HONDA_ODYSSEY_TWN:
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.28], [0.08]]
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 32767], [0, 32767]]
elif candidate in (CAR.HONDA_PILOT, CAR.HONDA_PILOT_4G):
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.38], [0.11]]
ret.lateralTuning.pid.kpBP, ret.lateralTuning.pid.kpV = [[0, 10], [0.05, 0.5]]
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kiV = [[0, 10], [0.0125, 0.125]]
elif candidate == CAR.ACURA_MDX_4G:
ret.steerActuatorDelay = 0.15
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560, 4209], [0, 2560, 9150]]
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate == CAR.ACURA_MDX_4G_MMR:
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560, 4920], [0, 2560, 12000]]
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate == CAR.HONDA_RIDGELINE:
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end
@@ -201,7 +247,7 @@ class CarInterface(CarInterfaceBase):
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.18]]
elif candidate == CAR.HONDA_E:
elif candidate in (CAR.HONDA_E, CAR.HONDA_E_ADVANCE):
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]] # TODO: determine if there is a dead zone at the top end
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.6], [0.18]] # TODO: can probably use some tuning
@@ -217,19 +263,48 @@ class CarInterface(CarInterfaceBase):
# When using stock ACC, the radar intercepts and filters steering commands the EPS would otherwise accept
ret.minSteerSpeed = 70. * CV.KPH_TO_MS
elif candidate == CAR.ACURA_TLX_2G_MMR:
ret.steerActuatorDelay = 0.15
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]]
ret.lateralTuning.pid.kpBP, ret.lateralTuning.pid.kpV = [[0, 10], [0.05, 0.5]]
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kiV = [[0, 10], [0.0125, 0.125]]
elif candidate in (CAR.HONDA_FIT_4G,):
ret.steerActuatorDelay = 0.15
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]]
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
elif candidate == CAR.ACURA_INTEGRA:
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 4096], [0, 4096]]
ret.lateralTuning.pid.kpV, ret.lateralTuning.pid.kiV = [[0.8], [0.24]]
elif candidate == CAR.ACURA_ADX:
ret.steerActuatorDelay = 0.15
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 5000], [0, 5000]]
ret.lateralTuning.pid.kpBP, ret.lateralTuning.pid.kpV = [[0, 10], [0.05, 0.5]]
ret.lateralTuning.pid.kiBP, ret.lateralTuning.pid.kiV = [[0, 10], [0.0125, 0.125]]
elif candidate == CAR.HONDA_PASSPORT_4G:
ret.steerActuatorDelay = 0.15
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560, 5120], [0, 2560, 12789]]
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
else:
ret.steerActuatorDelay = 0.15
ret.lateralParams.torqueBP, ret.lateralParams.torqueV = [[0, 2560], [0, 2560]]
CarInterfaceBase.configure_torque_tune(candidate, ret.lateralTuning)
# These cars use alternate user brake msg (0x1BE)
if 0x1BE in fingerprint[CAN.pt] and candidate in (CAR.HONDA_ACCORD, CAR.HONDA_HRV_3G, *HONDA_BOSCH_CANFD):
if 0x1BE in fingerprint[CAN.pt] and candidate in (CAR.HONDA_ACCORD, CAR.HONDA_HRV_3G, CAR.ACURA_RDX_3G, CAR.ACURA_MDX_4G,
CAR.ACURA_ADX, *HONDA_BOSCH_CANFD):
ret.flags |= HondaFlags.BOSCH_ALT_BRAKE.value
if ret.flags & HondaFlags.BOSCH_ALT_BRAKE:
ret.safetyConfigs[-1].safetyParam |= HondaSafetyFlags.ALT_BRAKE.value
if candidate in HONDA_NIDEC_ALT_SCM_MESSAGES:
ret.safetyConfigs[-1].safetyParam |= HondaSafetyFlags.NIDEC_ALT.value
if ret.enableGasInterceptorDEPRECATED:
ret.safetyConfigs[-1].safetyParam |= HondaSafetyFlags.GAS_INTERCEPTOR.value
if ret.openpilotLongitudinalControl and candidate in HONDA_BOSCH:
ret.safetyConfigs[-1].safetyParam |= HondaSafetyFlags.BOSCH_LONG.value
if candidate in HONDA_BOSCH_RADARLESS:
@@ -240,8 +315,24 @@ class CarInterface(CarInterfaceBase):
# min speed to enable ACC. if car can do stop and go, then set enabling speed
# to a negative value, so it won't matter. Otherwise, add 0.5 mph margin to not
# conflict with PCM acc
ret.autoResumeSng = candidate in (HONDA_BOSCH | {CAR.HONDA_CIVIC, CAR.HONDA_CLARITY})
ret.minEnableSpeed = -1. if ret.autoResumeSng else 25.51 * CV.MPH_TO_MS
if candidate == CAR.HONDA_FIT_4G and not ret.openpilotLongitudinalControl:
ret.autoResumeSng = False
elif ret.transmissionType == TransmissionType.manual and not ret.openpilotLongitudinalControl:
ret.autoResumeSng = False
else:
ret.autoResumeSng = candidate in (HONDA_BOSCH | {CAR.HONDA_CIVIC, CAR.HONDA_CLARITY}) or ret.enableGasInterceptorDEPRECATED
if ret.autoResumeSng:
ret.minEnableSpeed = -1.
elif candidate == CAR.HONDA_ODYSSEY_TWN:
ret.minEnableSpeed = 19. * CV.MPH_TO_MS
elif candidate == CAR.HONDA_FIT_4G:
ret.minEnableSpeed = 30. * CV.KPH_TO_MS
else:
ret.minEnableSpeed = 25.51 * CV.MPH_TO_MS
if candidate == CAR.HONDA_PILOT_4G:
CarControllerParams.BOSCH_GAS_LOOKUP_V = [0, 2200]
ret.steerLimitTimer = 0.8
ret.radarDelay = 0.1
@@ -6,6 +6,7 @@ from opendbc.car.structs import CarParams
from opendbc.car import gen_empty_fingerprint
from opendbc.car.honda.interface import CarInterface
from opendbc.car.honda.carcontroller import (
CarController,
get_civic_bosch_modified_steering_pressed,
get_civic_bosch_modified_torque_lpf_tau,
get_honda_bosch_wind_brake_mps2,
@@ -13,11 +14,16 @@ from opendbc.car.honda.carcontroller import (
)
from opendbc.car.honda.hondacan import create_lkas_hud
from opendbc.car.honda.fingerprints import FW_VERSIONS
from opendbc.car.honda.values import CAR, HONDA_BOSCH, HONDA_BOSCH_TJA_CONTROL, HondaFlags
from opendbc.car.honda.values import CAR, DBC, HONDA_BOSCH, HONDA_BOSCH_TJA_CONTROL, CarControllerParams, HondaFlags, HondaSafetyFlags, \
HondaStarPilotFlags
HONDA_FW_VERSION_RE = rb"[A-Z0-9]{5}-[A-Z0-9]{3}(-|,)[A-Z0-9]{4}(\x00){2}$"
def get_test_toggles() -> SimpleNamespace:
return SimpleNamespace(always_on_lateral_lkas=False, force_torque_controller=False, nnff=False, nnff_lite=False)
class TestHondaFingerprint:
def test_honda_lkas_hud_shows_lane_lines_when_lateral_only_is_active(self):
class FakePacker:
@@ -178,3 +184,54 @@ class TestHondaFingerprint:
torque_cp = CarInterface.get_params(CAR.HONDA_CLARITY, gen_empty_fingerprint(), car_fw, False, False, False, torque_toggles)
assert torque_cp.lateralTuning.which() == "torque"
def test_canfd_bosch_alpha_long_is_available(self):
toggles = get_test_toggles()
CP = CarInterface.get_params(CAR.HONDA_PILOT_4G, gen_empty_fingerprint(), [], True, False, False, toggles)
assert CP.alphaLongitudinalAvailable
assert CP.openpilotLongitudinalControl
assert CP.safetyConfigs[-1].safetyParam & HondaSafetyFlags.BOSCH_CANFD
assert CP.safetyConfigs[-1].safetyParam & HondaSafetyFlags.BOSCH_LONG
def test_nidec_pedal_detection_enables_interceptor_path(self):
toggles = get_test_toggles()
fingerprint = gen_empty_fingerprint()
fingerprint[0][0x201] = 6
CP = CarInterface.get_params(CAR.HONDA_CIVIC, fingerprint, [], False, False, False, toggles)
accel_limits = CarInterface.get_pid_accel_limits(CP, current_speed=5.0, cruise_speed=12.0)
assert CP.enableGasInterceptorDEPRECATED
assert not CP.pcmCruise
assert accel_limits == (CarControllerParams.NIDEC_ACCEL_MIN, CarControllerParams.NIDEC_ACCEL_MAX)
def test_honda_camera_message_flag_uses_fingerprint_detection(self):
toggles = get_test_toggles()
fingerprint = gen_empty_fingerprint()
fingerprint[0][0x35E] = 8
CP = CarInterface.get_params(CAR.HONDA_ACCORD, fingerprint, [], True, False, False, toggles)
FPCP = CarInterface.get_starpilot_params(CAR.HONDA_ACCORD, fingerprint, [], CP, toggles)
assert FPCP.flags & HondaStarPilotFlags.HAS_CAMERA_MESSAGES
def test_honda_live_learning_params_reload(self, monkeypatch):
toggles = get_test_toggles()
class FakeParams:
def get_float(self, key, block=False, return_default=False, default=0.0):
if key == "HondaGasFactorParams":
return 1.25
if key == "HondaWindFactorParams":
return 0.85
return default
monkeypatch.setattr("opendbc.car.honda.carcontroller.Params", lambda: FakeParams())
CP = CarInterface.get_params(CAR.HONDA_ACCORD, gen_empty_fingerprint(), [], True, False, False, toggles)
controller = CarController(DBC[CP.carFingerprint], CP)
assert controller.bosch_gas_factor == pytest.approx(1.25)
assert controller.bosch_wind_factor == pytest.approx(0.85)
+107 -2
View File
@@ -56,6 +56,7 @@ class HondaSafetyFlags(IntFlag):
NIDEC_ALT = 4
RADARLESS = 8
BOSCH_CANFD = 16
GAS_INTERCEPTOR = 32
class HondaFlags(IntFlag):
@@ -247,6 +248,12 @@ class CAR(Platforms):
{Bus.pt: 'acura_rdx_2020_can_generated'},
flags=HondaFlags.BOSCH_ALT_BRAKE,
)
ACURA_RDX_3G_MMR = HondaBoschPlatformConfig(
[HondaCarDocs("Acura RDX 2022-26", "All", min_steer_speed=70. * CV.KPH_TO_MS)],
CarSpecs(mass=4079 * CV.LB_TO_KG, wheelbase=2.75, centerToFrontRatio=0.41, steerRatio=16.2),
{Bus.pt: 'acura_rdx_2020_can_generated'},
flags=HondaFlags.BOSCH_ALT_BRAKE | HondaFlags.BOSCH_ALT_RADAR,
)
HONDA_INSIGHT = HondaBoschPlatformConfig(
[HondaCarDocs("Honda Insight 2019-22", "All", min_steer_speed=3. * CV.MPH_TO_MS)],
CarSpecs(mass=2987 * CV.LB_TO_KG, wheelbase=2.7, steerRatio=15.0, centerToFrontRatio=0.39, tireStiffnessFactor=0.82), # as spec
@@ -257,6 +264,11 @@ class CAR(Platforms):
CarSpecs(mass=3338.8 * CV.LB_TO_KG, wheelbase=2.5, centerToFrontRatio=0.5, steerRatio=16.71, tireStiffnessFactor=0.82),
{Bus.pt: 'acura_rdx_2020_can_generated'},
)
HONDA_E_ADVANCE = HondaBoschPlatformConfig(
[], # don't show in docs, base trim already in docs
CarSpecs(mass=1527, wheelbase=2.5, centerToFrontRatio=0.5, steerRatio=16.71, tireStiffnessFactor=0.82),
{Bus.pt: 'honda_e_advance_2020_can_generated'},
)
HONDA_PILOT_4G = HondaBoschCANFDPlatformConfig(
[HondaCarDocs("Honda Pilot 2023-25", "All")],
CarSpecs(mass=4660 * CV.LB_TO_KG, wheelbase=2.89, centerToFrontRatio=0.442, steerRatio=17.5),
@@ -265,6 +277,12 @@ class CAR(Platforms):
[HondaCarDocs("Honda Passport 2026", "All")],
CarSpecs(mass=4620 * CV.LB_TO_KG, wheelbase=2.89, centerToFrontRatio=0.442, steerRatio=18.5),
)
ACURA_MDX_4G = HondaBoschPlatformConfig(
[HondaCarDocs("Acura MDX 2022-24", "All", min_steer_speed=70. * CV.KPH_TO_MS)],
CarSpecs(mass=4788 * CV.LB_TO_KG, wheelbase=2.89, steerRatio=15.8, centerToFrontRatio=0.428),
{Bus.pt: 'honda_common_canfd_generated'},
flags=HondaFlags.BOSCH_ALT_RADAR | HondaFlags.BOSCH_TJA_CONTROL,
)
# mid-model refresh
ACURA_MDX_4G_MMR = HondaBoschCANFDPlatformConfig(
[HondaCarDocs("Acura MDX 2025", "All except Type S")],
@@ -282,6 +300,34 @@ class CAR(Platforms):
{Bus.pt: 'honda_civic_hatchback_ex_2017_can_generated'},
flags=HondaFlags.BOSCH_ALT_RADAR,
)
ACURA_TLX_2G_MMR = HondaBoschCANFDPlatformConfig(
[HondaCarDocs("Acura TLX 2024-25", "All")],
CarSpecs(mass=3990 * CV.LB_TO_KG, wheelbase=2.87, centerToFrontRatio=0.43, steerRatio=13.7),
)
HONDA_FIT_4G = HondaBoschPlatformConfig(
[
HondaCarDocs("Honda Fit (Taiwan) 2021", "All"),
HondaCarDocs("Honda Fit (Taiwan) 2024-25", "All"),
],
CarSpecs(mass=1229, wheelbase=2.53, steerRatio=19.7, centerToFrontRatio=0.39, minSteerSpeed=23. * CV.KPH_TO_MS),
{Bus.pt: 'honda_bosch_radarless_generated'},
flags=HondaFlags.BOSCH_RADARLESS,
)
ACURA_INTEGRA = HondaBoschPlatformConfig(
[
HondaCarDocs("Acura Integra 2023-26", "All"),
HondaCarDocs("Honda Prelude 2026", "All"),
],
CarSpecs(mass=3338.8 * CV.LB_TO_KG, wheelbase=2.5, centerToFrontRatio=0.5, steerRatio=16.71, tireStiffnessFactor=0.82),
{Bus.pt: 'honda_bosch_radarless_generated'},
flags=HondaFlags.BOSCH_RADARLESS,
)
ACURA_ADX = HondaBoschPlatformConfig(
[HondaCarDocs("Acura ADX 2025-26", "All")],
CarSpecs(mass=3578 * CV.LB_TO_KG, wheelbase=2.65, steerRatio=16.6, centerToFrontRatio=0.43),
{Bus.pt: 'honda_bosch_radarless_generated'},
flags=HondaFlags.BOSCH_RADARLESS,
)
# Nidec Cars
ACURA_ILX = HondaNidecPlatformConfig(
@@ -305,6 +351,12 @@ class CAR(Platforms):
radar_dbc_dict('honda_crv_touring_2016_can_generated'),
flags=HondaFlags.NIDEC_ALT_SCM_MESSAGES | HondaFlags.HAS_ALL_DOOR_STATES,
)
HONDA_CRV_SA = HondaNidecPlatformConfig(
[], # South Africa version of CRV Touring, don't show in docs
HONDA_CRV.specs,
radar_dbc_dict('acura_rdx_2018_can_generated'),
flags=HondaFlags.NIDEC_ALT_SCM_MESSAGES | HondaFlags.HAS_ALL_DOOR_STATES,
)
HONDA_FIT = HondaNidecPlatformConfig(
[HondaCarDocs("Honda Fit 2018-20", min_steer_speed=12. * CV.MPH_TO_MS)],
CarSpecs(mass=2644 * CV.LB_TO_KG, wheelbase=2.53, steerRatio=13.06, centerToFrontRatio=0.39, tireStiffnessFactor=0.75),
@@ -335,6 +387,15 @@ class CAR(Platforms):
radar_dbc_dict('honda_odyssey_exl_2018_generated'),
flags=HondaFlags.NIDEC_ALT_PCM_ACCEL | HondaFlags.HAS_ALL_DOOR_STATES,
)
HONDA_ODYSSEY_TWN = HondaNidecPlatformConfig(
[
HondaCarDocs("Honda Odyssey (Taiwan) 2018-19"),
HondaCarDocs("Honda Odyssey (Singapore) 2021"),
],
CarSpecs(mass=1865, wheelbase=2.9, steerRatio=14.35, centerToFrontRatio=0.44, tireStiffnessFactor=0.82),
radar_dbc_dict('honda_odyssey_twn_2018_generated'),
flags=HondaFlags.NIDEC_ALT_SCM_MESSAGES,
)
ACURA_RDX = HondaNidecPlatformConfig(
[HondaCarDocs("Acura RDX 2016-18", "AcuraWatch Plus or Advance Package", min_steer_speed=12. * CV.MPH_TO_MS)],
CarSpecs(mass=3925 * CV.LB_TO_KG, wheelbase=2.68, steerRatio=15.0, centerToFrontRatio=0.38, tireStiffnessFactor=0.444), # as spec
@@ -362,6 +423,43 @@ class CAR(Platforms):
radar_dbc_dict('honda_civic_touring_2016_can_generated'),
flags=HondaFlags.HAS_ALL_DOOR_STATES
)
HONDA_ACCORD_9G = HondaNidecPlatformConfig(
[
HondaCarDocs("Honda Accord 2016-17"),
HondaCarDocs("Honda Accord Hybrid 2017", "All"),
],
CarSpecs(mass=3343 * CV.LB_TO_KG, wheelbase=2.78, steerRatio=17.5, centerToFrontRatio=0.37),
radar_dbc_dict('honda_accord_2017_can_ext_generated'),
flags=HondaFlags.NIDEC_ALT_SCM_MESSAGES | HondaFlags.HAS_ALL_DOOR_STATES,
)
ACURA_MDX_3G = HondaNidecPlatformConfig(
[
HondaCarDocs("Acura MDX 2014-16", "Advance Package"),
HondaCarDocs("Acura MDX 2017-19", "All"),
HondaCarDocs("Acura MDX Hybrid 2017-19", "All"),
],
CarSpecs(mass=4215 * CV.LB_TO_KG, wheelbase=2.82, steerRatio=16.8, centerToFrontRatio=0.428),
radar_dbc_dict('acura_mdx_2017_can_ext_generated'),
flags=HondaFlags.NIDEC_ALT_SCM_MESSAGES,
)
ACURA_MDX_3G_MMR = HondaNidecPlatformConfig(
[
HondaCarDocs("Acura MDX 2020", "All"),
HondaCarDocs("Acura MDX Hybrid 2020", "All"),
],
CarSpecs(mass=4215 * CV.LB_TO_KG, wheelbase=2.82, steerRatio=16.8, centerToFrontRatio=0.428),
radar_dbc_dict('acura_ilx_2016_can_generated'),
flags=HondaFlags.NIDEC_ALT_SCM_MESSAGES,
)
ACURA_TLX_1G = HondaNidecPlatformConfig(
[
HondaCarDocs("Acura TLX 2015-17", "Advance Package"),
HondaCarDocs("Acura TLX 2018-20", "All"),
],
CarSpecs(mass=3680 * CV.LB_TO_KG, wheelbase=2.78, steerRatio=17.0, centerToFrontRatio=0.40, tireStiffnessFactor=0.18),
radar_dbc_dict('acura_mdx_2017_can_ext_generated'),
flags=HondaFlags.NIDEC_ALT_SCM_MESSAGES | HondaFlags.HAS_ALL_DOOR_STATES,
)
HONDA_NIDEC_ALT_PCM_ACCEL = CAR.with_flags(HondaFlags.NIDEC_ALT_PCM_ACCEL)
@@ -396,6 +494,11 @@ STEER_THRESHOLD = {
CAR.HONDA_CRV_6G: 600,
CAR.HONDA_CITY_7G: 600,
CAR.HONDA_NBOX_2G: 600,
CAR.HONDA_ODYSSEY_5G_MMR: 600,
CAR.HONDA_ACCORD_9G: 30,
CAR.ACURA_MDX_3G: 30,
CAR.ACURA_MDX_3G_MMR: 30,
CAR.ACURA_TLX_1G: 30,
}
@@ -440,9 +543,11 @@ FW_QUERY_CONFIG = FwQueryConfig(
# Note that we still attempt to match with them when they are present
# This is or'd with (ALL_ECUS - ESSENTIAL_ECUS) from fw_versions.py
non_essential_ecus={
Ecu.eps: [CAR.ACURA_RDX_3G, CAR.HONDA_ACCORD, CAR.HONDA_E, *HONDA_BOSCH_ALT_RADAR, *HONDA_BOSCH_RADARLESS, *HONDA_BOSCH_CANFD],
Ecu.eps: [CAR.ACURA_RDX_3G, CAR.HONDA_ACCORD, CAR.HONDA_E, CAR.HONDA_E_ADVANCE, CAR.ACURA_MDX_4G, CAR.HONDA_CRV_SA,
CAR.ACURA_MDX_3G, CAR.HONDA_ACCORD_9G, *HONDA_BOSCH_ALT_RADAR, *HONDA_BOSCH_RADARLESS, *HONDA_BOSCH_CANFD],
Ecu.vsa: [CAR.ACURA_RDX_3G, CAR.HONDA_ACCORD, CAR.HONDA_CIVIC, CAR.HONDA_CIVIC_BOSCH, CAR.HONDA_CRV_5G, CAR.HONDA_CRV_HYBRID,
CAR.HONDA_E, CAR.HONDA_INSIGHT, CAR.HONDA_NBOX_2G, *HONDA_BOSCH_ALT_RADAR, *HONDA_BOSCH_RADARLESS, *HONDA_BOSCH_CANFD],
CAR.HONDA_E, CAR.HONDA_E_ADVANCE, CAR.HONDA_INSIGHT, CAR.HONDA_NBOX_2G, CAR.ACURA_MDX_4G, CAR.HONDA_ACCORD_9G,
*HONDA_BOSCH_ALT_RADAR, *HONDA_BOSCH_RADARLESS, *HONDA_BOSCH_CANFD],
},
extra_ecus=[
(Ecu.combinationMeter, 0x18da60f1, None),
+2 -3
View File
@@ -18,7 +18,7 @@ from opendbc.car.common.basedir import BASEDIR
from opendbc.car.common.conversions import Conversions as CV
from opendbc.car.common.simple_kalman import KF1D, get_kalman_gain
from opendbc.car.gm.values import CAR as GM
from opendbc.car.honda.values import CAR as HONDA, HONDA_BOSCH, HONDA_CAMERA_MESSAGE_CARS, HondaFlags, HondaSafetyFlags, HondaStarPilotFlags
from opendbc.car.honda.values import CAR as HONDA, HONDA_BOSCH, HondaFlags, HondaSafetyFlags, HondaStarPilotFlags
from opendbc.car.hyundai.hyundaicanfd import CanBus
from opendbc.car.hyundai.values import CAR as HYUNDAI, CANFD_CAR, HyundaiFlags, HyundaiStarPilotFlags, HyundaiStarPilotSafetyFlags
from opendbc.car.mock.values import CAR as MOCK
@@ -215,8 +215,7 @@ class CarInterfaceBase(ABC):
elif platform in HONDA:
fp_ret.canUsePedal = candidate not in HONDA_BOSCH
# Only enable TSR parsing on Hondas confirmed to publish CAMERA_MESSAGES.
if candidate in HONDA_CAMERA_MESSAGE_CARS:
if any(0x35E in bus_fingerprint for bus_fingerprint in fingerprint.values()):
fp_ret.flags |= int(HondaStarPilotFlags.HAS_CAMERA_MESSAGES)
elif platform in HYUNDAI:
+78 -11
View File
@@ -6,7 +6,8 @@
#define HONDA_COMMON_NO_SCM_FEEDBACK_RX_CHECKS(pt_bus) \
{.msg = {{0x1A6, (pt_bus), 8, 25U, .max_counter = 3U, .ignore_quality_flag = true}, /* SCM_BUTTONS */ \
{0x296, (pt_bus), 4, 25U, .max_counter = 3U, .ignore_quality_flag = true}, { 0 }}}, \
{.msg = {{0x158, (pt_bus), 8, 100U, .max_counter = 3U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, /* ENGINE_DATA */ \
{.msg = {{0x158, (pt_bus), 8, 100U, .max_counter = 3U, .ignore_quality_flag = true}, /* ENGINE_DATA */ \
{0x309, (pt_bus), 8, 10U, .max_counter = 3U, .ignore_quality_flag = true}, { 0 }}}, /* CAR_SPEED */ \
{.msg = {{0x17C, (pt_bus), 8, 100U, .max_counter = 3U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, /* POWERTRAIN_DATA */ \
#define HONDA_COMMON_RX_CHECKS(pt_bus) \
@@ -17,6 +18,17 @@
#define HONDA_ALT_BRAKE_ADDR_CHECK(pt_bus) \
{.msg = {{0x1BE, (pt_bus), 3, 50U, .max_counter = 3U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, /* BRAKE_MODULE */ \
#define HONDA_GAS_INTERCEPTOR_ADDR_CHECK \
{.msg = {{0x201, 0, 6, 50U, .max_counter = 15U, .ignore_checksum = true, .ignore_counter = true, .ignore_quality_flag = true}, \
{ 0 }, { 0 }}}, \
#define HONDA_N_COMMON_TX_MSGS \
{0xE4, 0, 5, .check_relay = true}, \
{0x194, 0, 4, .check_relay = true}, \
{0x1FA, 0, 8, .check_relay = false}, \
{0x30C, 0, 8, .check_relay = true}, \
{0x33D, 0, 5, .check_relay = true}, \
enum {
HONDA_BTN_NONE = 0,
HONDA_BTN_MAIN = 1,
@@ -63,16 +75,26 @@ static uint32_t honda_compute_checksum(const CANPacket_t *msg) {
}
static uint8_t honda_get_counter(const CANPacket_t *msg) {
if (msg->addr == 0x201U) {
return msg->data[4] & 0xFU;
}
int counter_byte = GET_LEN(msg) - 1U;
return (msg->data[counter_byte] >> 4U) & 0x3U;
}
static int HONDA_GET_INTERCEPTOR(const CANPacket_t *msg) {
uint16_t val1 = ((uint16_t)msg->data[0] << 8U) | (uint16_t)msg->data[1];
uint16_t val2 = ((uint16_t)msg->data[2] << 8U) | (uint16_t)msg->data[3];
return (int)((val1 + val2) / 2U);
}
static void honda_rx_hook(const CANPacket_t *msg) {
const bool pcm_cruise = ((honda_hw == HONDA_BOSCH) && !honda_bosch_long) || (honda_hw == HONDA_NIDEC);
const bool pcm_cruise = ((honda_hw == HONDA_BOSCH) && !honda_bosch_long) || ((honda_hw == HONDA_NIDEC) && !enable_gas_interceptor);
unsigned int pt_bus = honda_get_pt_bus();
// sample speed
if (msg->addr == 0x158U) {
if ((msg->addr == 0x158U) || (msg->addr == 0x309U)) {
vehicle_moving = msg->data[0] | msg->data[1];
}
@@ -139,7 +161,14 @@ static void honda_rx_hook(const CANPacket_t *msg) {
}
}
if (msg->addr == 0x17CU) {
if (msg->addr == 0x201U) {
const int honda_gas_interceptor_thrsld = 492;
int gas_interceptor = HONDA_GET_INTERCEPTOR(msg);
gas_pressed = gas_interceptor > honda_gas_interceptor_thrsld;
gas_interceptor_prev = gas_interceptor;
}
if (!enable_gas_interceptor && (msg->addr == 0x17CU)) {
gas_pressed = msg->data[0] != 0U;
}
@@ -168,7 +197,7 @@ static bool honda_tx_hook(const CANPacket_t *msg) {
.max_accel = 200, // accel is used for brakes
.min_accel = -350,
.max_gas = 2000,
.max_gas = 2200,
.inactive_gas = -30000,
};
@@ -269,6 +298,13 @@ static bool honda_tx_hook(const CANPacket_t *msg) {
}
}
// GAS: safety check (interceptor)
if (msg->addr == 0x200U) {
if (longitudinal_interceptor_checks(msg)) {
tx = false;
}
}
return tx;
}
@@ -276,10 +312,14 @@ static safety_config honda_nidec_init(uint16_t param) {
// 0x1FA is dynamically forwarded based on stock AEB
// 0xE4 is steering on all cars except CRV and RDX, 0x194 for CRV and RDX,
// 0x1FA is brake control, 0x30C is acc hud, 0x33D is lkas hud
static CanMsg HONDA_N_TX_MSGS[] = {{0xE4, 0, 5, .check_relay = true}, {0x194, 0, 4, .check_relay = true}, {0x1FA, 0, 8, .check_relay = false},
{0x30C, 0, 8, .check_relay = true}, {0x33D, 0, 5, .check_relay = true}};
static CanMsg HONDA_N_TX_MSGS[] = {HONDA_N_COMMON_TX_MSGS};
static CanMsg HONDA_N_INTERCEPTOR_TX_MSGS[] = {
HONDA_N_COMMON_TX_MSGS
{0x200, 0, 6, .check_relay = false},
};
const uint16_t HONDA_PARAM_NIDEC_ALT = 4;
const uint16_t HONDA_PARAM_GAS_INTERCEPTOR = 32;
honda_hw = HONDA_NIDEC;
honda_brake = 0;
@@ -289,12 +329,22 @@ static safety_config honda_nidec_init(uint16_t param) {
honda_bosch_long = false;
honda_bosch_radarless = false;
honda_bosch_canfd = false;
enable_gas_interceptor = GET_FLAG(param, HONDA_PARAM_GAS_INTERCEPTOR);
safety_config ret;
bool enable_nidec_alt = GET_FLAG(param, HONDA_PARAM_NIDEC_ALT);
if (enable_nidec_alt) {
if (enable_nidec_alt && enable_gas_interceptor) {
static RxCheck honda_nidec_alt_interceptor_rx_checks[] = {
HONDA_COMMON_NO_SCM_FEEDBACK_RX_CHECKS(0)
{.msg = {{0x1FA, 2, 8, 50U, .max_counter = 3U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // BRAKE_COMMAND
HONDA_GAS_INTERCEPTOR_ADDR_CHECK
};
SET_RX_CHECKS(honda_nidec_alt_interceptor_rx_checks, ret);
SET_TX_MSGS(HONDA_N_INTERCEPTOR_TX_MSGS, ret);
} else if (enable_nidec_alt) {
// For Nidecs with main on signal on an alternate msg (missing 0x326)
static RxCheck honda_nidec_alt_rx_checks[] = {
HONDA_COMMON_NO_SCM_FEEDBACK_RX_CHECKS(0)
@@ -302,6 +352,16 @@ static safety_config honda_nidec_init(uint16_t param) {
};
SET_RX_CHECKS(honda_nidec_alt_rx_checks, ret);
SET_TX_MSGS(HONDA_N_TX_MSGS, ret);
} else if (enable_gas_interceptor) {
static RxCheck honda_nidec_common_interceptor_rx_checks[] = {
HONDA_COMMON_RX_CHECKS(0)
{.msg = {{0x1FA, 2, 8, 50U, .max_counter = 3U, .ignore_quality_flag = true}, { 0 }, { 0 }}}, // BRAKE_COMMAND
HONDA_GAS_INTERCEPTOR_ADDR_CHECK
};
SET_RX_CHECKS(honda_nidec_common_interceptor_rx_checks, ret);
SET_TX_MSGS(HONDA_N_INTERCEPTOR_TX_MSGS, ret);
} else {
// Nidec includes BRAKE_COMMAND
static RxCheck honda_nidec_common_rx_checks[] = {
@@ -310,10 +370,9 @@ static safety_config honda_nidec_init(uint16_t param) {
};
SET_RX_CHECKS(honda_nidec_common_rx_checks, ret);
SET_TX_MSGS(HONDA_N_TX_MSGS, ret);
}
SET_TX_MSGS(HONDA_N_TX_MSGS, ret);
return ret;
}
@@ -332,6 +391,9 @@ static safety_config honda_bosch_init(uint16_t param) {
{0x30C, 0, 8, .check_relay = true}}; // Bosch radarless w/ gas and brakes
static CanMsg HONDA_CANFD_TX_MSGS[] = {{0xE4, 0, 5, .check_relay = true}, {0x296, 0, 4, .check_relay = false}, {0x33D, 0, 8, .check_relay = true}};
static CanMsg HONDA_CANFD_LONG_TX_MSGS[] = {{0xE4, 0, 5, .check_relay = true}, {0x1DF, 0, 8, .check_relay = false}, {0x1EF, 0, 8, .check_relay = false},
{0x30C, 0, 8, .check_relay = false}, {0x33D, 0, 8, .check_relay = true}, {0x18DAB0F1, 0, 8, .check_relay = false},
{0x39F, 0, 8, .check_relay = false}};
const uint16_t HONDA_PARAM_ALT_BRAKE = 1;
@@ -364,6 +426,7 @@ static safety_config honda_bosch_init(uint16_t param) {
honda_bosch_canfd = GET_FLAG(param, HONDA_PARAM_BOSCH_CANFD);
// Checking for alternate brake override from safety parameter
honda_alt_brake_msg = GET_FLAG(param, HONDA_PARAM_ALT_BRAKE);
enable_gas_interceptor = false;
// radar disabled so allow gas/brakes
#ifdef ALLOW_DEBUG
@@ -393,7 +456,11 @@ static safety_config honda_bosch_init(uint16_t param) {
SET_TX_MSGS(HONDA_RADARLESS_TX_MSGS, ret);
}
} else if (honda_bosch_canfd) {
SET_TX_MSGS(HONDA_CANFD_TX_MSGS, ret);
if (honda_bosch_long) {
SET_TX_MSGS(HONDA_CANFD_LONG_TX_MSGS, ret);
} else {
SET_TX_MSGS(HONDA_CANFD_TX_MSGS, ret);
}
} else {
if (honda_bosch_long) {
SET_TX_MSGS(HONDA_BOSCH_LONG_TX_MSGS, ret);
@@ -77,7 +77,7 @@ static uint32_t hyundai_canfd_get_checksum(const CANPacket_t *msg) {
}
static void hyundai_canfd_rx_all_hook(const CANPacket_t *msg) {
UNUSED(msg);
SAFETY_UNUSED(msg);
}
static void hyundai_canfd_rx_hook(const CANPacket_t *msg) {
+8 -8
View File
@@ -476,6 +476,14 @@ int set_safety_hooks(uint16_t mode, uint16_t param) {
current_safety_config.tx_msgs_len = 0;
current_safety_config.disable_forwarding = false;
enable_gas_interceptor = false;
gas_interceptor_prev = 0;
aol_allowed = false;
lkas_button_prev = false;
lkas_on = false;
main_button_prev = false;
int set_status = -1; // not set
int hook_config_count = sizeof(safety_hook_registry) / sizeof(safety_hook_config);
for (int i = 0; i < hook_config_count; i++) {
@@ -499,14 +507,6 @@ int set_safety_hooks(uint16_t mode, uint16_t param) {
}
}
enable_gas_interceptor = false;
gas_interceptor_prev = 0;
aol_allowed = false;
lkas_button_prev = false;
lkas_on = false;
main_button_prev = false;
return set_status;
}
+1 -1
View File
@@ -1003,7 +1003,7 @@ class SafetyTest(SafetyTestBase):
tx = list(filter(lambda m: m[0] not in [0x30c, ], tx))
# Volkswagen MQB and Honda Bosch Radarless ACC HUD messages overlap
if attr == 'TestVolkswagenMqbLongSafety' and current_test.startswith('TestHondaBoschRadarless'):
if attr == 'TestVolkswagenMqbLongSafety' and current_test.startswith(('TestHondaBoschRadarless', 'TestHondaBoschCANFDLong')):
tx = list(filter(lambda m: m[0] not in [0x30c, ], tx))
# TODO: Temporary, should be fixed in panda firmware, safety_honda.h
@@ -6,7 +6,7 @@ from opendbc.car.honda.values import HondaSafetyFlags
from opendbc.safety.tests.libsafety import libsafety_py
import opendbc.safety.tests.common as common
from opendbc.car.structs import CarParams
from opendbc.safety.tests.common import CANPackerSafety, MAX_WRONG_COUNTERS
from opendbc.safety.tests.common import CANPackerSafety, GasInterceptorSafetyTest, MAX_WRONG_COUNTERS
HONDA_N_COMMON_TX_MSGS = [[0xE4, 0], [0x194, 0], [0x1FA, 0], [0x30C, 0], [0x33D, 0]]
@@ -18,6 +18,16 @@ class Btn:
SET = 3
RESUME = 4
def honda_interceptor_msg(gas: int, addr: int, counter: int = 0):
to_send = common.make_msg(0, addr, 6)
to_send[0].data[0] = (gas >> 8) & 0xFF
to_send[0].data[1] = gas & 0xFF
to_send[0].data[2] = (gas >> 8) & 0xFF
to_send[0].data[3] = gas & 0xFF
to_send[0].data[4] = counter & 0xF
return to_send
# Honda safety has several different configurations tested here:
# * Nidec
# * normal (PCM-enable)
@@ -366,6 +376,45 @@ class TestHondaNidecPcmAltSafety(TestHondaNidecPcmSafety):
return self.packer.make_can_msg_safety("SCM_BUTTONS", bus, values)
class TestHondaNidecGasInterceptorSafety(GasInterceptorSafetyTest, HondaButtonEnableBase, TestHondaNidecSafetyBase):
TX_MSGS = HONDA_N_COMMON_TX_MSGS + [[0x200, 0]]
INTERCEPTOR_THRESHOLD = 492
def setUp(self):
self.packer = CANPackerSafety("honda_civic_touring_2016_can_generated")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.hondaNidec, HondaSafetyFlags.GAS_INTERCEPTOR)
self.safety.init_tests()
def _interceptor_gas_cmd(self, gas: int):
self.__class__.cnt_gas_cmd += 1
return honda_interceptor_msg(gas, 0x200)
def _interceptor_user_gas(self, gas: int):
msg = honda_interceptor_msg(gas, 0x201, self.__class__.cnt_user_gas)
self.__class__.cnt_user_gas += 1
return msg
class TestHondaNidecAltGasInterceptorSafety(TestHondaNidecGasInterceptorSafety):
def setUp(self):
self.packer = CANPackerSafety("acura_ilx_2016_can_generated")
self.safety = libsafety_py.libsafety
self.safety.set_safety_hooks(CarParams.SafetyModel.hondaNidec, HondaSafetyFlags.NIDEC_ALT | HondaSafetyFlags.GAS_INTERCEPTOR)
self.safety.init_tests()
def _acc_state_msg(self, main_on):
values = {"MAIN_ON": main_on, "COUNTER": self.cnt_acc_state % 4}
self.__class__.cnt_acc_state += 1
return self.packer.make_can_msg_safety("SCM_BUTTONS", self.PT_BUS, values)
def _button_msg(self, buttons, main_on=False, bus=None):
bus = self.PT_BUS if bus is None else bus
values = {"CRUISE_BUTTONS": buttons, "MAIN_ON": main_on, "COUNTER": self.cnt_button % 4}
self.__class__.cnt_button += 1
return self.packer.make_can_msg_safety("SCM_BUTTONS", bus, values)
# ********************* Honda Bosch **********************
@@ -454,7 +503,7 @@ class TestHondaBoschLongSafety(HondaButtonEnableBase, TestHondaBoschSafetyBase):
Covers the Honda Bosch safety mode with longitudinal control
"""
NO_GAS = -30000
MAX_GAS = 2000
MAX_GAS = 2200
MAX_ACCEL = 2.0 # accel is used for brakes, but openpilot can set positive values
MIN_ACCEL = -3.5
@@ -491,7 +540,7 @@ class TestHondaBoschLongSafety(HondaButtonEnableBase, TestHondaBoschSafetyBase):
def test_gas_safety_check(self):
for controls_allowed in [True, False]:
for gas in np.arange(self.NO_GAS, self.MAX_GAS + 2000, 100):
accel = 0 if gas < 0 else gas / 1000
accel = 0 if gas < 0 else min(gas / 1000, self.MAX_ACCEL)
self.safety.set_controls_allowed(controls_allowed)
send = (controls_allowed and 0 <= gas <= self.MAX_GAS) or gas == self.NO_GAS
self.assertEqual(send, self._tx(self._send_gas_brake_msg(gas, accel)), (controls_allowed, gas, accel))
@@ -604,6 +653,25 @@ class TestHondaBoschCANFDAltBrakeSafety(HondaPcmEnableBase, TestHondaBoschCANFDS
self.safety.init_tests()
class TestHondaBoschCANFDLongSafety(TestHondaBoschLongSafety, TestHondaBoschCANFDSafetyBase):
"""
Covers the Honda Bosch CANFD safety mode with longitudinal control
"""
PT_BUS = 0
STEER_BUS = 0
BUTTONS_BUS = 0
TX_MSGS = [[0xE4, 0], [0x1DF, 0], [0x1EF, 0], [0x30C, 0], [0x33D, 0], [0x39F, 0], [0x18DAB0F1, 0]]
FWD_BLACKLISTED_ADDRS = {2: [0xE4, 0x33D]}
RELAY_MALFUNCTION_ADDRS = {0: (0xE4, 0x33D)}
def setUp(self):
super().setUp()
self.safety.set_safety_hooks(CarParams.SafetyModel.hondaBosch, HondaSafetyFlags.BOSCH_CANFD | HondaSafetyFlags.BOSCH_LONG)
self.safety.init_tests()
if __name__ == "__main__":
unittest.main()
+1 -1
View File
@@ -1,2 +1,2 @@
extern const uint8_t gitversion[19];
const uint8_t gitversion[19] = "DEV-334481c7-DEBUG";
const uint8_t gitversion[19] = "DEV-471a33d6-DEBUG";
+1 -1
View File
@@ -1 +1 @@
DEV-334481c7-DEBUG
DEV-471a33d6-DEBUG