mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-07-07 06:32:08 +08:00
mochi mochi mochi
This commit is contained in:
@@ -160,6 +160,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
|
||||
{"AggressiveJerkSpeed", {PERSISTENT, FLOAT, "50.0", "50.0", 3}},
|
||||
{"AggressiveJerkSpeedDecrease", {PERSISTENT, FLOAT, "50.0", "50.0", 3}},
|
||||
{"AlertVolumeControl", {PERSISTENT, BOOL, "0", "0", 2}},
|
||||
{"AllowImpossibleAcceleration", {PERSISTENT, BOOL, "0", "0", 3}},
|
||||
{"AlwaysOnLateral", {PERSISTENT, BOOL, "1", "0", 0}},
|
||||
{"AlwaysOnLateralLKAS", {PERSISTENT, BOOL, "1", "0", 2}},
|
||||
{"ApiCache_DriveStats", {PERSISTENT, JSON, "{}", "{}"}},
|
||||
|
||||
@@ -285,6 +285,8 @@ struct CarState {
|
||||
setCruise @9;
|
||||
resumeCruise @10;
|
||||
gapAdjustCruise @11;
|
||||
accelHardCruise @12;
|
||||
decelHardCruise @13;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,8 @@ AUTO_HOLD_REGEN_RELEASE_COOLDOWN_S = 1.0
|
||||
|
||||
BUTTONS_DICT = {CruiseButtons.RES_ACCEL: ButtonType.accelCruise, CruiseButtons.DECEL_SET: ButtonType.decelCruise,
|
||||
CruiseButtons.MAIN: ButtonType.mainCruise, CruiseButtons.CANCEL: ButtonType.cancel}
|
||||
HARD_BUTTONS_DICT = {CruiseButtons.RES_ACCEL: ButtonType.accelHardCruise, CruiseButtons.DECEL_SET: ButtonType.decelHardCruise}
|
||||
NORMAL_CRUISE_BUTTONS = (CruiseButtons.RES_ACCEL, CruiseButtons.DECEL_SET)
|
||||
|
||||
GearShifter = structs.CarState.GearShifter
|
||||
BOLT_GEN1_CANCEL_PERSONALITY_CARS = {
|
||||
@@ -64,6 +66,8 @@ class CarState(CarStateBase):
|
||||
|
||||
self.prev_distance_button = 0
|
||||
self.distance_button = 0
|
||||
self.hard_cruise_buttons = CruiseButtons.INIT
|
||||
self.force_reset_cruise_buttons = False
|
||||
|
||||
self.single_pedal_mode = False
|
||||
self.auto_hold_armed = False
|
||||
@@ -92,8 +96,8 @@ class CarState(CarStateBase):
|
||||
if not self.CP.pcmCruise:
|
||||
for b in buttonEvents:
|
||||
# The ECM allows enabling on falling edge of set, but only rising edge of resume
|
||||
if (b.type == ButtonType.accelCruise and b.pressed) or \
|
||||
(b.type == ButtonType.decelCruise and not b.pressed):
|
||||
if (b.type in (ButtonType.accelCruise, ButtonType.accelHardCruise) and b.pressed) or \
|
||||
(b.type in (ButtonType.decelCruise, ButtonType.decelHardCruise) and not b.pressed):
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -119,9 +123,11 @@ class CarState(CarStateBase):
|
||||
sdgm_non_volt = self.CP.carFingerprint in SDGM_CAR and self.CP.carFingerprint not in kaofui_state_cars
|
||||
|
||||
prev_cruise_buttons = self.cruise_buttons
|
||||
prev_hard_cruise_buttons = self.hard_cruise_buttons
|
||||
prev_distance_button = self.distance_button
|
||||
if not sdgm_non_volt:
|
||||
self.cruise_buttons = pt_cp.vl["ASCMSteeringButton"]["ACCButtons"]
|
||||
self.hard_cruise_buttons = pt_cp.vl["ASCMSteeringButton"]["ACCButtonsHard"]
|
||||
self.distance_button = pt_cp.vl["ASCMSteeringButton"]["DistanceButton"]
|
||||
self.buttons_counter = pt_cp.vl["ASCMSteeringButton"]["RollingCounter"]
|
||||
self.steering_button_checksum = pt_cp.vl["ASCMSteeringButton"]["SteeringButtonChecksum"]
|
||||
@@ -131,9 +137,20 @@ class CarState(CarStateBase):
|
||||
self.steering_button_prefix = (int(acc_always_one) & 1) | ((int(acc_hidden_bit) & 1) << 6)
|
||||
else:
|
||||
self.cruise_buttons = cam_cp.vl["ASCMSteeringButton"]["ACCButtons"]
|
||||
self.hard_cruise_buttons = cam_cp.vl["ASCMSteeringButton"]["ACCButtonsHard"]
|
||||
self.distance_button = cam_cp.vl["ASCMSteeringButton"]["DistanceButton"]
|
||||
self.buttons_counter = cam_cp.vl["ASCMSteeringButton"]["RollingCounter"]
|
||||
self.steering_button_ts_nanos = cam_cp.ts_nanos["ASCMSteeringButton"]["ACCButtons"]
|
||||
|
||||
# A GM hard press keeps the normal cruise button signal active too. Suppress
|
||||
# the normal button until the wheel reports a different normal state.
|
||||
if self.hard_cruise_buttons != CruiseButtons.INIT and self.cruise_buttons in NORMAL_CRUISE_BUTTONS:
|
||||
self.force_reset_cruise_buttons = True
|
||||
if self.force_reset_cruise_buttons and self.cruise_buttons in NORMAL_CRUISE_BUTTONS:
|
||||
self.cruise_buttons = CruiseButtons.UNPRESS
|
||||
elif self.force_reset_cruise_buttons and self.cruise_buttons not in NORMAL_CRUISE_BUTTONS:
|
||||
self.force_reset_cruise_buttons = False
|
||||
|
||||
self.pscm_status = copy.copy(pt_cp.vl["PSCMStatus"])
|
||||
self.moving_backward = (pt_cp.vl["EBCMWheelSpdRear"]["RLWheelDir"] == 2) or (pt_cp.vl["EBCMWheelSpdRear"]["RRWheelDir"] == 2)
|
||||
|
||||
@@ -178,7 +195,10 @@ class CarState(CarStateBase):
|
||||
ret.brakePressed = ret.brake >= VOLT_EBCM_BRAKE_PRESSED_THRESHOLD
|
||||
elif self.CP.carFingerprint in {CAR.CHEVROLET_MALIBU_CC} or (self.CP.carFingerprint == CAR.CHEVROLET_BLAZER and not no_accel_pos):
|
||||
ret.brakePressed = ret.brake >= 8
|
||||
elif (self.CP.flags & GMFlags.FORCE_BRAKE_C9.value) or ((self.CP.networkLocation == NetworkLocation.fwdCamera) and (self.CP.carFingerprint != CAR.CHEVROLET_BLAZER)):
|
||||
elif (self.CP.flags & GMFlags.FORCE_BRAKE_C9.value) or (
|
||||
self.CP.networkLocation == NetworkLocation.fwdCamera and
|
||||
self.CP.carFingerprint not in (SDGM_CAR | ASCM_INT | {CAR.CHEVROLET_BLAZER})
|
||||
):
|
||||
ret.brakePressed = pt_cp.vl["ECMEngineStatus"]["BrakePressed"] != 0
|
||||
else:
|
||||
# Some Volt 2016-17 have loose brake pedal push rod retainers which causes the ECM to believe
|
||||
@@ -374,13 +394,18 @@ class CarState(CarStateBase):
|
||||
lkas_events = [] if (suppress_malibu_side_buttons or suppress_bolt_cancel_lkas) else create_button_events(
|
||||
self.lkas_enabled, self.lkas_previously_enabled, {1: ButtonType.lkas}
|
||||
)
|
||||
hard_cruise_events = create_button_events(
|
||||
self.hard_cruise_buttons, prev_hard_cruise_buttons, HARD_BUTTONS_DICT, unpressed_btn=CruiseButtons.INIT
|
||||
)
|
||||
|
||||
# Don't add events if transitioning from INIT, unless it's to an actual button.
|
||||
if self.cruise_buttons != CruiseButtons.UNPRESS or prev_cruise_buttons != CruiseButtons.INIT:
|
||||
if (self.cruise_buttons != CruiseButtons.UNPRESS or prev_cruise_buttons != CruiseButtons.INIT or
|
||||
self.hard_cruise_buttons != CruiseButtons.INIT or prev_hard_cruise_buttons != CruiseButtons.INIT):
|
||||
ret.buttonEvents = [
|
||||
*cruise_events,
|
||||
*distance_events,
|
||||
*lkas_events,
|
||||
*hard_cruise_events,
|
||||
]
|
||||
|
||||
if ret.vEgo < self.CP.minSteerSpeed:
|
||||
|
||||
@@ -146,6 +146,7 @@ BO_ 481 ASCMSteeringButton: 7 K124_ASCM
|
||||
SG_ LKAButton : 23|1@0+ (1,0) [0|0] "" NEO
|
||||
SG_ ACCAlwaysOne : 24|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ ACCButtons : 46|3@0+ (1,0) [0|0] "" NEO
|
||||
SG_ ACCButtonsHard : 26|2@0+ (1,0) [0|3] "" XXX
|
||||
SG_ DriveModeButton : 39|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ RollingCounter : 33|2@0+ (1,0) [0|3] "" NEO
|
||||
SG_ SteeringButtonChecksum : 43|12@0+ (1,0) [0|255] "" NEO
|
||||
|
||||
@@ -166,6 +166,7 @@ BO_ 481 ASCMSteeringButton: 7 K124_ASCM
|
||||
SG_ LKAButton : 23|1@0+ (1,0) [0|0] "" NEO
|
||||
SG_ ACCAlwaysOne : 24|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ ACCButtons : 46|3@0+ (1,0) [0|0] "" NEO
|
||||
SG_ ACCButtonsHard : 26|2@0+ (1,0) [0|3] "" XXX
|
||||
SG_ DriveModeButton : 39|1@0+ (1,0) [0|1] "" XXX
|
||||
SG_ RollingCounter : 33|2@0+ (1,0) [0|3] "" NEO
|
||||
SG_ SteeringButtonChecksum : 43|12@0+ (1,0) [0|255] "" NEO
|
||||
|
||||
@@ -283,9 +283,9 @@ class Car:
|
||||
CS.vCruise = float(self.v_cruise_helper.v_cruise_kph)
|
||||
CS.vCruiseCluster = float(self.v_cruise_helper.v_cruise_cluster_kph)
|
||||
|
||||
if any(be.type in (ButtonType.accelCruise, ButtonType.resumeCruise) for be in filtered_CS.buttonEvents):
|
||||
if any(be.type in (ButtonType.accelCruise, ButtonType.accelHardCruise, ButtonType.resumeCruise) for be in filtered_CS.buttonEvents):
|
||||
self.resume_prev_button = True
|
||||
elif any(be.type in (ButtonType.decelCruise, ButtonType.setCruise) for be in filtered_CS.buttonEvents):
|
||||
elif any(be.type in (ButtonType.decelCruise, ButtonType.decelHardCruise, ButtonType.setCruise) for be in filtered_CS.buttonEvents):
|
||||
self.resume_prev_button = False
|
||||
|
||||
FPCS = self.starpilot_card.update(CS, FPCS, self.sm, self.starpilot_toggles)
|
||||
|
||||
+16
-5
@@ -24,11 +24,17 @@ CRUISE_LONG_PRESS = 50
|
||||
CRUISE_NEAREST_FUNC = {
|
||||
ButtonType.accelCruise: math.ceil,
|
||||
ButtonType.decelCruise: math.floor,
|
||||
ButtonType.accelHardCruise: math.ceil,
|
||||
ButtonType.decelHardCruise: math.floor,
|
||||
}
|
||||
CRUISE_INTERVAL_SIGN = {
|
||||
ButtonType.accelCruise: +1,
|
||||
ButtonType.decelCruise: -1,
|
||||
ButtonType.accelHardCruise: +1,
|
||||
ButtonType.decelHardCruise: -1,
|
||||
}
|
||||
HARD_CRUISE_BUTTONS = (ButtonType.accelHardCruise, ButtonType.decelHardCruise)
|
||||
ACCEL_CRUISE_BUTTONS = (ButtonType.accelCruise, ButtonType.accelHardCruise)
|
||||
|
||||
|
||||
class VCruiseHelper:
|
||||
@@ -37,7 +43,12 @@ class VCruiseHelper:
|
||||
self.v_cruise_kph = V_CRUISE_UNSET
|
||||
self.v_cruise_cluster_kph = V_CRUISE_UNSET
|
||||
self.v_cruise_kph_last = 0
|
||||
self.button_timers = {ButtonType.decelCruise: 0, ButtonType.accelCruise: 0}
|
||||
self.button_timers = {
|
||||
ButtonType.decelCruise: 0,
|
||||
ButtonType.accelCruise: 0,
|
||||
ButtonType.decelHardCruise: 0,
|
||||
ButtonType.accelHardCruise: 0,
|
||||
}
|
||||
self.button_change_states = {btn: {"standstill": False, "enabled": False} for btn in self.button_timers}
|
||||
|
||||
self.gm_cc_only = self.CP.carFingerprint in CC_ONLY_CAR and self.CP.flags & GMFlags.CC_LONG.value
|
||||
@@ -121,7 +132,7 @@ class VCruiseHelper:
|
||||
|
||||
# Don't adjust speed when pressing resume to exit standstill
|
||||
cruise_standstill = self.button_change_states[button_type]["standstill"] or CS.cruiseState.standstill
|
||||
if button_type == ButtonType.accelCruise and cruise_standstill:
|
||||
if button_type in ACCEL_CRUISE_BUTTONS and cruise_standstill:
|
||||
return
|
||||
|
||||
# Don't adjust speed if we've enabled since the button was depressed (some ports enable on rising edge)
|
||||
@@ -129,7 +140,7 @@ class VCruiseHelper:
|
||||
return
|
||||
|
||||
short_interval, long_interval = self._get_cruise_delta_intervals(starpilot_toggles)
|
||||
v_cruise_delta_interval = long_interval if long_press else short_interval
|
||||
v_cruise_delta_interval = long_interval if long_press or button_type in HARD_CRUISE_BUTTONS else short_interval
|
||||
v_cruise_delta = v_cruise_delta * v_cruise_delta_interval
|
||||
if v_cruise_delta_interval % 5 == 0 and self.v_cruise_kph % v_cruise_delta != 0: # partial interval
|
||||
self.v_cruise_kph = CRUISE_NEAREST_FUNC[button_type](self.v_cruise_kph / v_cruise_delta) * v_cruise_delta
|
||||
@@ -137,7 +148,7 @@ class VCruiseHelper:
|
||||
self.v_cruise_kph += v_cruise_delta * CRUISE_INTERVAL_SIGN[button_type]
|
||||
|
||||
# If set is pressed while overriding, clip cruise speed to minimum of vEgo
|
||||
if CS.gasPressed and button_type in (ButtonType.decelCruise, ButtonType.setCruise):
|
||||
if CS.gasPressed and button_type in (ButtonType.decelCruise, ButtonType.decelHardCruise, ButtonType.setCruise):
|
||||
self.v_cruise_kph = max(self.v_cruise_kph, CS.vEgo * CV.MS_TO_KPH)
|
||||
|
||||
self.v_cruise_kph = np.clip(round(self.v_cruise_kph, 1), V_CRUISE_MIN, V_CRUISE_MAX)
|
||||
@@ -161,7 +172,7 @@ class VCruiseHelper:
|
||||
return
|
||||
|
||||
engage_floor_kph = max(V_CRUISE_MIN, 7.0 * CV.MPH_TO_KPH)
|
||||
resume_pressed = any(b.type in (ButtonType.accelCruise, ButtonType.resumeCruise) for b in CS.buttonEvents)
|
||||
resume_pressed = any(b.type in (ButtonType.accelCruise, ButtonType.accelHardCruise, ButtonType.resumeCruise) for b in CS.buttonEvents)
|
||||
remembered_resume = resume_prev_button and (self.gm_cc_only or self.redneck_non_pcm)
|
||||
|
||||
if self.v_cruise_initialized and (resume_pressed or remembered_resume):
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import pytest
|
||||
import itertools
|
||||
import math
|
||||
import numpy as np
|
||||
|
||||
from parameterized import parameterized_class
|
||||
@@ -101,6 +102,62 @@ class TestVCruiseHelper:
|
||||
)
|
||||
assert pressed == (self.v_cruise_helper.v_cruise_kph == self.v_cruise_helper.v_cruise_kph_last)
|
||||
|
||||
def test_hard_press_uses_long_press_interval(self):
|
||||
self.enable(52 * CV.MPH_TO_MS, False)
|
||||
initial_v_cruise_kph = self.v_cruise_helper.v_cruise_kph
|
||||
|
||||
pressed_cs = car.CarState(cruiseState={"available": True})
|
||||
pressed_cs.buttonEvents = [ButtonEvent(type=ButtonType.accelHardCruise, pressed=True)]
|
||||
self.v_cruise_helper.update_v_cruise(
|
||||
pressed_cs,
|
||||
enabled=True,
|
||||
is_metric=False,
|
||||
speed_limit_changed=False,
|
||||
starpilot_toggles=self.starpilot_toggles,
|
||||
)
|
||||
|
||||
released_cs = car.CarState(cruiseState={"available": True})
|
||||
released_cs.buttonEvents = [ButtonEvent(type=ButtonType.accelHardCruise, pressed=False)]
|
||||
self.v_cruise_helper.update_v_cruise(
|
||||
released_cs,
|
||||
enabled=True,
|
||||
is_metric=False,
|
||||
speed_limit_changed=False,
|
||||
starpilot_toggles=self.starpilot_toggles,
|
||||
)
|
||||
|
||||
hard_interval = self.starpilot_toggles.cruise_increase_long * IMPERIAL_INCREMENT
|
||||
expected_kph = math.ceil(initial_v_cruise_kph / hard_interval) * hard_interval
|
||||
assert self.v_cruise_helper.v_cruise_kph == pytest.approx(expected_kph)
|
||||
|
||||
def test_hard_decel_press_uses_long_press_interval(self):
|
||||
self.enable(52 * CV.MPH_TO_MS, False)
|
||||
initial_v_cruise_kph = self.v_cruise_helper.v_cruise_kph
|
||||
|
||||
pressed_cs = car.CarState(cruiseState={"available": True})
|
||||
pressed_cs.buttonEvents = [ButtonEvent(type=ButtonType.decelHardCruise, pressed=True)]
|
||||
self.v_cruise_helper.update_v_cruise(
|
||||
pressed_cs,
|
||||
enabled=True,
|
||||
is_metric=False,
|
||||
speed_limit_changed=False,
|
||||
starpilot_toggles=self.starpilot_toggles,
|
||||
)
|
||||
|
||||
released_cs = car.CarState(cruiseState={"available": True})
|
||||
released_cs.buttonEvents = [ButtonEvent(type=ButtonType.decelHardCruise, pressed=False)]
|
||||
self.v_cruise_helper.update_v_cruise(
|
||||
released_cs,
|
||||
enabled=True,
|
||||
is_metric=False,
|
||||
speed_limit_changed=False,
|
||||
starpilot_toggles=self.starpilot_toggles,
|
||||
)
|
||||
|
||||
hard_interval = self.starpilot_toggles.cruise_increase_long * IMPERIAL_INCREMENT
|
||||
expected_kph = math.floor(initial_v_cruise_kph / hard_interval) * hard_interval
|
||||
assert self.v_cruise_helper.v_cruise_kph == pytest.approx(expected_kph)
|
||||
|
||||
def test_rising_edge_enable(self):
|
||||
"""
|
||||
Some car interfaces may enable on rising edge of a button,
|
||||
|
||||
@@ -22,11 +22,15 @@ class ExcessiveActuationCheck:
|
||||
self._excessive_counter = 0
|
||||
self._engaged_counter = 0
|
||||
|
||||
def update(self, sm: messaging.SubMaster, CS: car.CarState, calibrated_pose: Pose) -> ExcessiveActuationType | None:
|
||||
def update(self, sm: messaging.SubMaster, CS: car.CarState, calibrated_pose: Pose,
|
||||
allow_impossible_acceleration: bool = False) -> ExcessiveActuationType | None:
|
||||
# CS.aEgo can be noisy to bumps in the road, transitioning from standstill, losing traction, etc.
|
||||
# longitudinal
|
||||
accel_calibrated = calibrated_pose.acceleration.x
|
||||
excessive_long_actuation = sm['carControl'].longActive and (accel_calibrated > ACCEL_MAX * 2 or accel_calibrated < ACCEL_MIN * 2)
|
||||
excessive_long_actuation = (
|
||||
not allow_impossible_acceleration and sm['carControl'].longActive and
|
||||
(accel_calibrated > ACCEL_MAX * 2 or accel_calibrated < ACCEL_MIN * 2)
|
||||
)
|
||||
|
||||
# lateral
|
||||
yaw_rate = calibrated_pose.angular_velocity.yaw
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
import json
|
||||
import os
|
||||
import time
|
||||
import threading
|
||||
@@ -71,6 +72,9 @@ class SelfdriveD:
|
||||
self.pose_calibrator = PoseCalibrator()
|
||||
self.calibrated_pose: Pose | None = None
|
||||
self.excessive_actuation_check = ExcessiveActuationCheck()
|
||||
self.allow_impossible_acceleration = self.params.get_bool("AllowImpossibleAcceleration")
|
||||
if self.allow_impossible_acceleration:
|
||||
self.clear_longitudinal_excessive_actuation_alert()
|
||||
self.excessive_actuation = self.params.get("Offroad_ExcessiveActuation") is not None
|
||||
|
||||
# Setup sockets
|
||||
@@ -172,6 +176,32 @@ class SelfdriveD:
|
||||
|
||||
self.FPCP = messaging.log_from_bytes(self.params.get("StarPilotCarParams", block=True), custom.StarPilotCarParams)
|
||||
|
||||
def clear_longitudinal_excessive_actuation_alert(self):
|
||||
alert = self.params.get("Offroad_ExcessiveActuation")
|
||||
if not alert:
|
||||
return
|
||||
|
||||
if isinstance(alert, bytes):
|
||||
try:
|
||||
alert = json.loads(alert.decode("utf-8", errors="replace"))
|
||||
except json.JSONDecodeError:
|
||||
return
|
||||
elif isinstance(alert, str):
|
||||
try:
|
||||
alert = json.loads(alert)
|
||||
except json.JSONDecodeError:
|
||||
return
|
||||
|
||||
if not isinstance(alert, dict):
|
||||
return
|
||||
|
||||
extra = alert.get("extra", "")
|
||||
if isinstance(extra, bytes):
|
||||
extra = extra.decode("utf-8", errors="replace")
|
||||
|
||||
if str(extra).strip().lower() == "longitudinal":
|
||||
self.params.remove("Offroad_ExcessiveActuation")
|
||||
|
||||
def update_events(self, CS):
|
||||
"""Compute onroadEvents from carState"""
|
||||
|
||||
@@ -221,7 +251,7 @@ class SelfdriveD:
|
||||
return
|
||||
|
||||
# Block resume if cruise never previously enabled
|
||||
resume_pressed = any(be.type in (ButtonType.accelCruise, ButtonType.resumeCruise) for be in CS.buttonEvents)
|
||||
resume_pressed = any(be.type in (ButtonType.accelCruise, ButtonType.accelHardCruise, ButtonType.resumeCruise) for be in CS.buttonEvents)
|
||||
if not self.CP.pcmCruise and CS.vCruise > 250 and resume_pressed:
|
||||
self.events.add(EventName.resumeBlocked)
|
||||
|
||||
@@ -332,7 +362,9 @@ class SelfdriveD:
|
||||
self.calibrated_pose = self.pose_calibrator.build_calibrated_pose(device_pose)
|
||||
|
||||
if self.calibrated_pose is not None:
|
||||
excessive_actuation = self.excessive_actuation_check.update(self.sm, CS, self.calibrated_pose)
|
||||
excessive_actuation = self.excessive_actuation_check.update(
|
||||
self.sm, CS, self.calibrated_pose, self.allow_impossible_acceleration
|
||||
)
|
||||
if not self.excessive_actuation and excessive_actuation is not None:
|
||||
set_offroad_alert("Offroad_ExcessiveActuation", True, extra_text=str(excessive_actuation))
|
||||
self.excessive_actuation = True
|
||||
|
||||
@@ -3219,6 +3219,13 @@
|
||||
"description": "Only enable this if the wide camera is broken or for development!\n\nDisabling the wide camera may degrade driving performance and cause instability.\n\nRequires a reboot to take effect.",
|
||||
"data_type": "bool",
|
||||
"ui_type": "toggle"
|
||||
},
|
||||
{
|
||||
"key": "AllowImpossibleAcceleration",
|
||||
"label": "Allow Impossible Acceleration",
|
||||
"description": "WARNING: This suppresses openpilot's excessive longitudinal actuation diagnostic when measured acceleration looks impossible for the requested gas/brake command.\n\nLeave this OFF unless you are intentionally testing edge cases like shifting to neutral and understand that it can hide a real actuation problem.",
|
||||
"data_type": "bool",
|
||||
"ui_type": "toggle"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -2255,6 +2255,30 @@ def _serialize_param_write_value(raw_value):
|
||||
return raw_value.decode("utf-8", errors="replace")
|
||||
return str(raw_value or "")
|
||||
|
||||
def _offroad_excessive_actuation_type():
|
||||
alert = _safe_params_get_live_raw("Offroad_ExcessiveActuation")
|
||||
if not alert:
|
||||
return ""
|
||||
|
||||
if isinstance(alert, bytes):
|
||||
try:
|
||||
alert = json.loads(alert.decode("utf-8", errors="replace"))
|
||||
except json.JSONDecodeError:
|
||||
return ""
|
||||
elif isinstance(alert, str):
|
||||
try:
|
||||
alert = json.loads(alert)
|
||||
except json.JSONDecodeError:
|
||||
return ""
|
||||
|
||||
if not isinstance(alert, dict):
|
||||
return ""
|
||||
|
||||
extra = alert.get("extra", "")
|
||||
if isinstance(extra, bytes):
|
||||
extra = extra.decode("utf-8", errors="replace")
|
||||
return str(extra).strip().lower()
|
||||
|
||||
def _apply_cellular_metered_setting(metered_enabled):
|
||||
"""Apply GsmMetered changes to active NetworkManager GSM profiles."""
|
||||
if not shutil.which("nmcli"):
|
||||
@@ -3742,6 +3766,18 @@ def setup(app):
|
||||
if key == "AutomaticUpdates" and params.get_bool("IsOnroad"):
|
||||
return jsonify({"error": "Cannot change Automatic Updates while driving."}), 403
|
||||
|
||||
if key == "AllowImpossibleAcceleration":
|
||||
enabled = str_val.strip() in ("1", "true", "True")
|
||||
params.put_bool(key, enabled)
|
||||
if enabled and _offroad_excessive_actuation_type() == "longitudinal":
|
||||
params.remove("Offroad_ExcessiveActuation")
|
||||
|
||||
update_starpilot_toggles()
|
||||
return jsonify({
|
||||
"message": f"Parameter '{key}' updated successfully.",
|
||||
"updated": {key: enabled},
|
||||
}), 200
|
||||
|
||||
if key in {"EVTuning", "TruckTuning"}:
|
||||
enabled = str_val.strip() in ("1", "true", "True")
|
||||
params.put_bool(key, enabled)
|
||||
|
||||
Reference in New Issue
Block a user