mirror of
https://github.com/MoreTore/openpilot.git
synced 2026-07-26 12:22:04 +08:00
HonDeez
This commit is contained in:
Binary file not shown.
+243
-61
@@ -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
|
||||
|
||||
@@ -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.
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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,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 @@
|
||||
DEV-334481c7-DEBUG
|
||||
DEV-471a33d6-DEBUG
|
||||
Reference in New Issue
Block a user