This commit is contained in:
firestar5683
2026-08-14 21:38:09 -05:00
parent 21ba6ab7cd
commit c2e2c24e8c
10 changed files with 193 additions and 31 deletions
+2 -7
View File
@@ -367,10 +367,8 @@ class Car:
was_openpilot_long = self.CP.openpilotLongitudinalControl
self.CI.init(self.CP, *self.can_callbacks)
# If ECU disable was skipped/failed, strip LONG safety flag from BOTH CarParams
# and StarPilotCarParams (pandad ORs both safetyParams together)
# Use the pre-init longitudinal state here, since Hyundai init() may already
# flip CP.openpilotLongitudinalControl to False as part of the fallback.
if was_openpilot_long and self.CP.brand in ("hyundai", "nissan") and self.params.get_bool("EcuDisableFailed"):
nissan_leaf_alpha_long = self.CP.brand == "nissan" and self.CP.carFingerprint == "NISSAN_LEAF"
if was_openpilot_long and (self.CP.brand == "hyundai" or nissan_leaf_alpha_long) and self.params.get_bool("EcuDisableFailed"):
# ECU disable failed/rejected - switch to lateral-only mode with stock ACC
# Keep this local to avoid importing every brand's values into card.py.
LONG_FLAG = 4 if self.CP.brand == "hyundai" else 2 if self.CP.brand == "nissan" else 0
@@ -378,9 +376,6 @@ class Car:
cfg.safetyParam &= ~LONG_FLAG
for cfg in self.FPCP.safetyConfigs:
cfg.safetyParam &= ~LONG_FLAG
# Let stock ACC manage cruise (prevents "controls mismatch" error)
# Clear openpilotLongitudinalControl so controlsd doesn't set
# cruiseControl.override=True (which fights stock ACC and causes engage flicker)
self.CP.pcmCruise = True
self.CP.openpilotLongitudinalControl = False
self.params.put("CarParams", self.CP.to_bytes())
+4 -2
View File
@@ -12,6 +12,7 @@ from openpilot.common.swaglog import cloudlog
from opendbc.car.car_helpers import interfaces
from opendbc.car.chrysler.values import pacifica_hybrid_aol_stock_acc_mode
from opendbc.car.gm.values import CAR as GM_CAR
from opendbc.car.nissan.values import CAR as NISSAN_CAR
from opendbc.car.vehicle_model import VehicleModel
from openpilot.selfdrive.controls.lib.drive_helpers import MAX_LATERAL_JERK, clip_curvature, get_lateral_active
from openpilot.selfdrive.controls.lib.lane_centering import LaneCenteringController
@@ -365,11 +366,12 @@ class Controls:
if self.ecu_disable_failed_checked:
return
# ControlsReady is set after CarInterface.init(), where Hyundai ECU disable
# writes EcuDisableFailed. Once init has completed, the value is stable.
if self.params.get_bool("ControlsReady"):
self.ecu_disable_failed = self.params.get_bool("EcuDisableFailed")
self.ecu_disable_failed_checked = True
if self.ecu_disable_failed and self.CP.carFingerprint == NISSAN_CAR.NISSAN_LEAF:
self.CP.openpilotLongitudinalControl = False
self.CP.pcmCruise = True
def state_control(self):
CS = self.sm['carState']
+23
View File
@@ -13,6 +13,7 @@ from msgq.visionipc import VisionIpcClient, VisionStreamType
from opendbc.car.chrysler.values import pacifica_hybrid_aol_stock_acc_mode
from opendbc.car.gm.values import GMFlags
from opendbc.car.hyundai.values import CAR as HYUNDAI_CAR
from opendbc.car.nissan.values import CAR as NISSAN_CAR
from openpilot.common.params import Params
from openpilot.common.realtime import config_realtime_process, Priority, Ratekeeper, DT_CTRL
@@ -223,6 +224,10 @@ class SelfdriveD:
self.logged_comm_issue = None
self.not_running_prev = None
self.experimental_mode = False
self.ecu_disable_failed = False
self.ecu_disable_failed_checked = not (
self.CP.openpilotLongitudinalControl and self.CP.carFingerprint == NISSAN_CAR.NISSAN_LEAF
)
self.safe_mode = self.params.get_bool("SafeMode")
self.personality = log.LongitudinalPersonality.relaxed if self.safe_mode else self.params.get("LongitudinalPersonality", return_default=True)
self.recalibrating_seen = False
@@ -276,6 +281,23 @@ class SelfdriveD:
self.FPCP = messaging.log_from_bytes(self.params.get("StarPilotCarParams", block=True), custom.StarPilotCarParams)
def update_ecu_disable_failed(self):
if self.ecu_disable_failed_checked:
return
if self.CP.carFingerprint != NISSAN_CAR.NISSAN_LEAF:
self.ecu_disable_failed_checked = True
return
if self.params.get_bool("ControlsReady"):
self.ecu_disable_failed = self.params.get_bool("EcuDisableFailed")
self.ecu_disable_failed_checked = True
if self.ecu_disable_failed:
fallback_cp = messaging.log_from_bytes(self.params.get("CarParams"), car.CarParams)
fallback_fpcp = messaging.log_from_bytes(self.params.get("StarPilotCarParams"), custom.StarPilotCarParams)
self.CP.openpilotLongitudinalControl = fallback_cp.openpilotLongitudinalControl
self.CP.pcmCruise = fallback_cp.pcmCruise
self.FPCP = fallback_fpcp
def clear_longitudinal_excessive_actuation_alert(self):
alert = self.params.get("Offroad_ExcessiveActuation")
if not alert:
@@ -305,6 +327,7 @@ class SelfdriveD:
def update_events(self, CS):
"""Compute onroadEvents from carState"""
self.update_ecu_disable_failed()
self.events.clear()
self.starpilot_events.clear()
+80 -2
View File
@@ -1,7 +1,24 @@
from cereal import car
from cereal import car, custom
from opendbc.car.hyundai.values import CAR as HYUNDAI_CAR
from opendbc.car.nissan.values import CAR as NISSAN_CAR
from openpilot.selfdrive.selfdrived.selfdrived import commanded_torque_at_max_for_saturation
from openpilot.selfdrive.selfdrived.selfdrived import SelfdriveD, commanded_torque_at_max_for_saturation
class FakeFallbackParams:
def __init__(self, controls_ready, ecu_disable_failed, fallback_cp, fallback_fpcp):
self.controls_ready = controls_ready
self.ecu_disable_failed = ecu_disable_failed
self.values = {
"CarParams": fallback_cp.to_bytes(),
"StarPilotCarParams": fallback_fpcp.to_bytes(),
}
def get_bool(self, key):
return self.controls_ready if key == "ControlsReady" else self.ecu_disable_failed
def get(self, key):
return self.values[key]
def test_immediate_max_output_saturation_is_torque_controller_only():
@@ -27,3 +44,64 @@ def test_gv70_uses_normal_saturation_timer_at_max_output():
CP.lateralTuning.init("torque")
assert not commanded_torque_at_max_for_saturation(CP, 1.0)
def test_ecu_disable_fallback_synchronizes_behavior_and_safety_params():
initial_cp = car.CarParams.new_message()
initial_cp.carFingerprint = NISSAN_CAR.NISSAN_LEAF
initial_cp.openpilotLongitudinalControl = True
initial_cp.pcmCruise = False
initial_cp.safetyConfigs = [car.CarParams.SafetyConfig.new_message(safetyParam=2)]
initial_fpcp = custom.StarPilotCarParams.new_message()
initial_fpcp.safetyConfigs = [custom.StarPilotCarParams.SafetyConfig.new_message(safetyParam=2)]
fallback_cp = car.CarParams.new_message()
fallback_cp.openpilotLongitudinalControl = False
fallback_cp.pcmCruise = True
fallback_cp.safetyConfigs = [car.CarParams.SafetyConfig.new_message(safetyParam=0)]
fallback_fpcp = custom.StarPilotCarParams.new_message()
fallback_fpcp.safetyConfigs = [custom.StarPilotCarParams.SafetyConfig.new_message(safetyParam=0)]
selfdrived = SelfdriveD.__new__(SelfdriveD)
selfdrived.CP = initial_cp
selfdrived.FPCP = initial_fpcp
selfdrived.params = FakeFallbackParams(True, True, fallback_cp, fallback_fpcp)
selfdrived.ecu_disable_failed = False
selfdrived.ecu_disable_failed_checked = False
selfdrived.update_ecu_disable_failed()
assert selfdrived.ecu_disable_failed
assert selfdrived.ecu_disable_failed_checked
assert not selfdrived.CP.openpilotLongitudinalControl
assert selfdrived.CP.pcmCruise
assert selfdrived.FPCP.safetyConfigs[0].safetyParam == 0
def test_ecu_disable_fallback_does_not_change_other_cars():
initial_cp = car.CarParams.new_message()
initial_cp.carFingerprint = HYUNDAI_CAR.HYUNDAI_SONATA
initial_cp.openpilotLongitudinalControl = True
initial_cp.pcmCruise = False
initial_fpcp = custom.StarPilotCarParams.new_message()
initial_fpcp.safetyConfigs = [custom.StarPilotCarParams.SafetyConfig.new_message(safetyParam=4)]
fallback_cp = car.CarParams.new_message()
fallback_cp.openpilotLongitudinalControl = False
fallback_cp.pcmCruise = True
fallback_fpcp = custom.StarPilotCarParams.new_message()
fallback_fpcp.safetyConfigs = [custom.StarPilotCarParams.SafetyConfig.new_message(safetyParam=0)]
selfdrived = SelfdriveD.__new__(SelfdriveD)
selfdrived.CP = initial_cp
selfdrived.FPCP = initial_fpcp
selfdrived.params = FakeFallbackParams(True, True, fallback_cp, fallback_fpcp)
selfdrived.ecu_disable_failed = False
selfdrived.ecu_disable_failed_checked = False
selfdrived.update_ecu_disable_failed()
assert selfdrived.ecu_disable_failed_checked
assert selfdrived.CP.openpilotLongitudinalControl
assert not selfdrived.CP.pcmCruise
assert selfdrived.FPCP.safetyConfigs[0].safetyParam == 4