New stoofs

This commit is contained in:
firestar5683
2026-06-07 15:01:59 -05:00
parent cdcc8da555
commit a6758eb9e6
21 changed files with 423 additions and 26 deletions
+3
View File
@@ -199,6 +199,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"CESpeed", {PERSISTENT, FLOAT, "0.0", "0.0", 1}},
{"CESpeedLead", {PERSISTENT, FLOAT, "0.0", "0.0", 1}},
{"CCMLead", {PERSISTENT, BOOL, "1", "0", 1}},
{"CCMLaunchAssist", {PERSISTENT, BOOL, "0", "0", 1}},
{"CCMSetSpeedMargin", {PERSISTENT, FLOAT, "3.0", "0.0", 1}},
{"CCMSpeed", {PERSISTENT, FLOAT, "45.0", "0.0", 1}},
{"CCMSpeedLead", {PERSISTENT, FLOAT, "35.0", "0.0", 1}},
@@ -283,6 +284,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"FlashPanda", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
{"GMDashSpoofOffsets", {PERSISTENT, BOOL, "0", "0", 2}},
{"GMPedalLongitudinal", {PERSISTENT, BOOL, "1", "1", 2}},
{"GMStockDashWhenNotEngaged", {PERSISTENT, BOOL, "0", "0", 2}},
{"LongPitch", {PERSISTENT, BOOL, "1", "0", 2}},
{"RemoteStartBootsComma", {PERSISTENT, BOOL, "0", "0"}},
{"RemapCancelToDistance", {PERSISTENT, BOOL, "0", "0"}},
@@ -376,6 +378,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"LongitudinalManeuverStatus", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, JSON, "{}", "{}"}},
{"LongitudinalTune", {PERSISTENT, BOOL, "1", "0", 0}},
{"LoudBlindspotAlert", {PERSISTENT, BOOL, "0", "0", 0}},
{"LoudBlindspotAlertWhenDisengaged", {PERSISTENT, BOOL, "0", "0", 0}},
{"LowVoltageShutdown", {PERSISTENT, FLOAT, "11.8", "11.8", 3}},
{"MainCruiseButtonControl", {PERSISTENT, INT, "9", "9", 2}},
{"ManualUpdateInitiated", {CLEAR_ON_MANAGER_START, BOOL, "0", "0"}},
+5 -3
View File
@@ -68,13 +68,14 @@ def should_spoof_dash_speed(CP, starpilot_toggles):
return True
def should_send_acc_dashboard_status(CP, dash_speed_spoof_active):
def should_send_acc_dashboard_status(CP, dash_speed_spoof_active, enabled=True, stock_dash_when_not_engaged=False):
status_car = CP.carFingerprint not in CC_ONLY_CAR or CP.carFingerprint == CAR.CHEVROLET_BOLT_ACC_2022_2023_PEDAL
volt_camera_no_camera = (
CP.carFingerprint == CAR.CHEVROLET_VOLT_CAMERA and
bool(getattr(CP, "flags", 0) & GMFlags.NO_CAMERA.value)
)
return status_car and (dash_speed_spoof_active or volt_camera_no_camera)
should_spoof = dash_speed_spoof_active and (enabled or not stock_dash_when_not_engaged)
return status_car and (should_spoof or volt_camera_no_camera)
def get_acc_dashboard_fcw_alert(hud_alert, CS):
@@ -725,7 +726,8 @@ class CarController(CarControllerBase):
idx, CC.enabled, near_stop, at_full_stop, self.CP))
CS.auto_hold_engaged = False
if should_send_acc_dashboard_status(self.CP, dash_speed_spoof_active):
stock_dash_when_not_engaged = getattr(starpilot_toggles, "gm_stock_dash_when_not_engaged", False)
if should_send_acc_dashboard_status(self.CP, dash_speed_spoof_active, CC.enabled, stock_dash_when_not_engaged):
acc_dashboard_status = get_acc_dashboard_status_values(CC.enabled, hud_v_cruise * CV.MS_TO_KPH, hud_control, CS)
fcw_alert = get_acc_dashboard_fcw_alert(hud_alert, CS)
can_sends.append(gmcan.create_acc_dashboard_command(self.packer_pt, CanBus.POWERTRAIN,
@@ -265,6 +265,33 @@ class TestGMCarController:
assert should_send_acc_dashboard_status(cp, dash_speed_spoof_active=False)
def test_stock_dash_toggle_suppresses_disabled_dash_spoof(self):
cp = SimpleNamespace(carFingerprint=CAR.CADILLAC_XT4, flags=0)
assert should_send_acc_dashboard_status(cp, dash_speed_spoof_active=True, enabled=False)
assert not should_send_acc_dashboard_status(
cp,
dash_speed_spoof_active=True,
enabled=False,
stock_dash_when_not_engaged=True,
)
assert should_send_acc_dashboard_status(
cp,
dash_speed_spoof_active=True,
enabled=True,
stock_dash_when_not_engaged=True,
)
def test_stock_dash_toggle_keeps_no_camera_exception(self):
cp = SimpleNamespace(carFingerprint=CAR.CHEVROLET_VOLT_CAMERA, flags=GMFlags.NO_CAMERA.value)
assert should_send_acc_dashboard_status(
cp,
dash_speed_spoof_active=True,
enabled=False,
stock_dash_when_not_engaged=True,
)
def test_acc_dashboard_no_camera_exception_is_volt_camera_only(self):
assert not should_send_acc_dashboard_status(
SimpleNamespace(carFingerprint=CAR.CHEVROLET_VOLT_CAMERA, flags=0),
@@ -15,6 +15,7 @@ class CarState(CarStateBase):
self.shifter_values = can_define.dv["Transmission"]["Gear"]
self.angle_rate_calulator = CanSignalRateCalculator(50)
self.sng_cruise_enabled = False
def update(self, can_parsers, starpilot_toggles) -> structs.CarState:
cp = can_parsers[Bus.pt]
@@ -133,6 +134,22 @@ class CarState(CarStateBase):
self.cruise_state = cp_cam.vl["ES_DashStatus"]["Cruise_State"]
self.throttle_msg = copy.copy(cp.vl["Throttle"])
sng_standstill_hold = (
ret.cruiseState.available and
ret.standstill and
self.car_follow == 1 and
self.cruise_state == 3 and
not ret.gasPressed
)
if ret.cruiseState.enabled:
self.sng_cruise_enabled = True
elif self.sng_cruise_enabled and sng_standstill_hold:
ret.cruiseState.enabled = True
else:
self.sng_cruise_enabled = False
else:
self.sng_cruise_enabled = False
return ret, fp_ret
@staticmethod
+1 -1
View File
@@ -37,7 +37,7 @@ def select_redneck_target_speed(v_cruise_kph: float, speed_cluster_ms: float,
target_speed_ms = float(starpilot_target_speed_ms)
if allow_plan_decrease and len(plan_speeds_ms) > 0:
if lead_present and plan_speeds_ms[0] > speed_cluster_ms:
if lead_present and target_speed_ms > speed_cluster_ms and plan_speeds_ms[0] > speed_cluster_ms:
recovery_lookahead_points = min(len(plan_speeds_ms), LEAD_RECOVERY_LOOKAHEAD_POINTS)
recovery_target_speed_ms = max(speed_cluster_ms, min(plan_speeds_ms[:recovery_lookahead_points]))
return min(target_speed_ms, recovery_target_speed_ms)
@@ -182,6 +182,19 @@ class TestRedneckCruise(unittest.TestCase):
)
self.assertAlmostEqual(55.8 * CV.MPH_TO_MS, target_speed)
def test_target_speed_does_not_use_recovery_branch_when_cluster_is_above_internal_max(self):
target_speed = select_redneck_target_speed(
45.0,
46.0 * CV.KPH_TO_MS,
0.0,
[46.6 * CV.KPH_TO_MS, 46.4 * CV.KPH_TO_MS, 46.2 * CV.KPH_TO_MS, 46.0 * CV.KPH_TO_MS,
44.0 * CV.KPH_TO_MS, 42.0 * CV.KPH_TO_MS, 39.0 * CV.KPH_TO_MS],
7,
allow_plan_decrease=True,
lead_present=True,
)
self.assertLess(target_speed * CV.MS_TO_KPH, 45.0)
def test_target_speed_stays_on_lead_target_when_cluster_drops_below_it(self):
target_speed = select_redneck_target_speed(
76.9,
@@ -51,6 +51,8 @@ class FakeSubMaster:
def make_sm():
return {
"carState": SimpleNamespace(standstill=False, leftBlinker=False, rightBlinker=False),
"selfdriveState": SimpleNamespace(enabled=True),
"longitudinalPlan": SimpleNamespace(allowThrottle=True, shouldStop=False),
"starpilotCarState": SimpleNamespace(trafficModeEnabled=False),
"starpilotRadarState": SimpleNamespace(
leadLeft=SimpleNamespace(status=False, dRel=float("inf"), vLead=0.0),
@@ -69,6 +71,7 @@ def make_toggles():
conditional_chill_speed_lead=35 * CV.MPH_TO_MS,
conditional_chill_speed_margin=3 * CV.MPH_TO_MS,
conditional_chill_lead=True,
conditional_chill_launch_assist=False,
)
@@ -130,7 +133,7 @@ def test_ccm_enters_chill_for_stable_lead_cruising(monkeypatch):
planner, _detector, ccm = make_ccm()
sm = make_sm()
toggles = make_toggles()
monotonic_values = iter([10.0, 10.5])
monotonic_values = iter([10.0, 11.1])
monkeypatch.setattr("openpilot.starpilot.controls.lib.conditional_chill_mode.time.monotonic", lambda: next(monotonic_values))
planner.tracking_lead = True
@@ -147,6 +150,27 @@ def test_ccm_enters_chill_for_stable_lead_cruising(monkeypatch):
assert ccm.status_value == CCStatus["LEAD"]
def test_ccm_stable_lead_requires_longer_entry_debounce(monkeypatch):
planner, _detector, ccm = make_ccm()
sm = make_sm()
toggles = make_toggles()
monotonic_values = iter([10.0, 10.6])
monkeypatch.setattr("openpilot.starpilot.controls.lib.conditional_chill_mode.time.monotonic", lambda: next(monotonic_values))
planner.tracking_lead = True
planner.lead_one.status = True
planner.lead_one.dRel = 45.0
planner.lead_one.vLead = 24.8
planner.lead_one.radar = True
v_ego = 58 * CV.MPH_TO_MS
ccm.update(v_ego, v_ego, sm, toggles)
ccm.update(v_ego, v_ego, sm, toggles)
assert ccm.experimental_mode
assert ccm.status_value == CCStatus["OFF"]
def test_ccm_hard_vetoes_force_experimental(monkeypatch):
planner, detector, ccm = make_ccm()
sm = make_sm()
@@ -210,6 +234,88 @@ def test_ccm_immediately_exits_chill_when_scene_turns_into_slow_lead(monkeypatch
assert ccm.status_value == CCStatus["OFF"]
def test_ccm_launch_assist_enters_chill_from_standstill_when_planner_wants_to_go(monkeypatch):
planner, _detector, ccm = make_ccm()
sm = make_sm()
sm["carState"].standstill = True
toggles = make_toggles()
toggles.conditional_chill_launch_assist = True
monkeypatch.setattr("openpilot.starpilot.controls.lib.conditional_chill_mode.time.monotonic", lambda: 20.0)
ccm.update(0.0, 25 * CV.MPH_TO_MS, sm, toggles)
assert not ccm.experimental_mode
assert ccm.status_value == CCStatus["SPEED"]
def test_ccm_launch_assist_does_not_bypass_real_stop_scene(monkeypatch):
planner, detector, ccm = make_ccm()
sm = make_sm()
sm["carState"].standstill = True
sm["longitudinalPlan"].shouldStop = True
toggles = make_toggles()
toggles.conditional_chill_launch_assist = True
monkeypatch.setattr("openpilot.starpilot.controls.lib.conditional_chill_mode.time.monotonic", lambda: 21.0)
ccm.update(0.0, 25 * CV.MPH_TO_MS, sm, toggles)
assert ccm.experimental_mode
assert ccm.status_value == CCStatus["OFF"]
detector.stop_light_detected = True
sm["longitudinalPlan"].shouldStop = False
ccm.update(0.0, 25 * CV.MPH_TO_MS, sm, toggles)
assert ccm.experimental_mode
assert ccm.status_value == CCStatus["OFF"]
def test_ccm_launch_assist_exits_once_launch_speed_is_reached(monkeypatch):
planner, _detector, ccm = make_ccm()
sm = make_sm()
sm["carState"].standstill = True
toggles = make_toggles()
toggles.conditional_chill_launch_assist = True
monotonic_values = iter([30.0, 30.2])
monkeypatch.setattr("openpilot.starpilot.controls.lib.conditional_chill_mode.time.monotonic", lambda: next(monotonic_values))
ccm.update(0.0, 25 * CV.MPH_TO_MS, sm, toggles)
assert not ccm.experimental_mode
sm["carState"].standstill = False
ccm.update(16 * CV.MPH_TO_MS, 25 * CV.MPH_TO_MS, sm, toggles)
assert ccm.experimental_mode
assert ccm.status_value == CCStatus["OFF"]
def test_ccm_launch_assist_exits_immediately_if_lead_slows_again(monkeypatch):
planner, _detector, ccm = make_ccm()
sm = make_sm()
sm["carState"].standstill = True
toggles = make_toggles()
toggles.conditional_chill_launch_assist = True
monotonic_values = iter([40.0, 40.1])
monkeypatch.setattr("openpilot.starpilot.controls.lib.conditional_chill_mode.time.monotonic", lambda: next(monotonic_values))
planner.tracking_lead = True
planner.lead_one.status = True
planner.lead_one.dRel = 18.0
planner.lead_one.vLead = 2.0
planner.lead_one.radar = True
ccm.update(0.0, 25 * CV.MPH_TO_MS, sm, toggles)
assert not ccm.experimental_mode
assert ccm.status_value == CCStatus["LEAD"]
sm["carState"].standstill = False
planner.lead_one.vLead = 0.2
planner.lead_one.aLeadK = -0.4
ccm.update(3 * CV.MPH_TO_MS, 25 * CV.MPH_TO_MS, sm, toggles)
assert ccm.experimental_mode
assert ccm.status_value == CCStatus["OFF"]
def test_ccm_respects_manual_chill_override(monkeypatch):
planner, _detector, ccm = make_ccm()
sm = make_sm()
@@ -223,6 +329,19 @@ def test_ccm_respects_manual_chill_override(monkeypatch):
assert ccm.status_value == CCStatus["USER_CHILL"]
def test_ccm_launch_assist_is_disabled_by_default(monkeypatch):
planner, _detector, ccm = make_ccm()
sm = make_sm()
sm["carState"].standstill = True
toggles = make_toggles()
monkeypatch.setattr("openpilot.starpilot.controls.lib.conditional_chill_mode.time.monotonic", lambda: 50.0)
ccm.update(0.0, 25 * CV.MPH_TO_MS, sm, toggles)
assert ccm.experimental_mode
assert ccm.status_value == CCStatus["OFF"]
def test_ccm_restores_persisted_manual_experimental_override(monkeypatch):
planner, _detector, ccm = make_ccm()
sm = make_sm()
+26
View File
@@ -52,6 +52,27 @@ StarPilotEventName = custom.StarPilotOnroadEvent.EventName
IGNORED_SAFETY_MODES = (SafetyModel.silent, SafetyModel.noOutput)
def should_loud_blindspot_alert_without_lateral(CS, sm, starpilot_toggles) -> bool:
if not (getattr(starpilot_toggles, "loud_blindspot_alert", False) and
getattr(starpilot_toggles, "loud_blindspot_alert_when_disengaged", False)):
return False
if sm['modelV2'].meta.laneChangeState == LaneChangeState.preLaneChange:
return False
left_signal_blocked = bool(CS.leftBlinker and CS.leftBlindspot)
right_signal_blocked = bool(CS.rightBlinker and CS.rightBlindspot)
one_blinker = bool(CS.leftBlinker) != bool(CS.rightBlinker)
if not (one_blinker and (left_signal_blocked or right_signal_blocked)):
return False
return (
not sm['carControl'].latActive or
not sm['starpilotPlan'].lateralCheck or
sm['starpilotCarState'].pauseLateral
)
class SelfdriveD:
def __init__(self, CP=None):
self.params = Params()
@@ -374,10 +395,12 @@ class SelfdriveD:
# ******************************************************************************************
# Handle lane change
blindspot_alert_added = False
if self.sm['modelV2'].meta.laneChangeState == LaneChangeState.preLaneChange:
direction = self.sm['modelV2'].meta.laneChangeDirection
if (CS.leftBlindspot and direction == LaneChangeDirection.left) or \
(CS.rightBlindspot and direction == LaneChangeDirection.right):
blindspot_alert_added = True
if self.starpilot_toggles.loud_blindspot_alert:
self.starpilot_events.add(StarPilotEventName.laneChangeBlockedLoud)
else:
@@ -398,6 +421,9 @@ class SelfdriveD:
LaneChangeState.laneChangeFinishing):
self.events.add(EventName.laneChange)
if not blindspot_alert_added and should_loud_blindspot_alert_without_lateral(CS, self.sm, self.starpilot_toggles):
self.starpilot_events.add(StarPilotEventName.laneChangeBlockedLoud)
for i, pandaState in enumerate(self.sm['pandaStates']):
# All pandas must match the list of safetyConfigs, and if outside this list, must be silent or noOutput
if i < len(self.CP.safetyConfigs):
@@ -0,0 +1,58 @@
from types import SimpleNamespace
from cereal import log
from openpilot.selfdrive.selfdrived.selfdrived import should_loud_blindspot_alert_without_lateral
LaneChangeState = log.LaneChangeState
def _car_state(left_blinker=False, right_blinker=False, left_blindspot=False, right_blindspot=False):
return SimpleNamespace(
leftBlinker=left_blinker,
rightBlinker=right_blinker,
leftBlindspot=left_blindspot,
rightBlindspot=right_blindspot,
)
def _sm(lane_change_state=LaneChangeState.off, lat_active=False, lateral_check=False, pause_lateral=False):
return {
"modelV2": SimpleNamespace(meta=SimpleNamespace(laneChangeState=lane_change_state)),
"carControl": SimpleNamespace(latActive=lat_active),
"starpilotPlan": SimpleNamespace(lateralCheck=lateral_check),
"starpilotCarState": SimpleNamespace(pauseLateral=pause_lateral),
}
def _toggles(enabled=True):
return SimpleNamespace(
loud_blindspot_alert=True,
loud_blindspot_alert_when_disengaged=enabled,
)
def test_loud_blindspot_alert_without_lateral_for_matching_signal():
CS = _car_state(left_blinker=True, left_blindspot=True)
assert should_loud_blindspot_alert_without_lateral(CS, _sm(lat_active=False), _toggles())
assert should_loud_blindspot_alert_without_lateral(CS, _sm(lat_active=True, lateral_check=False), _toggles())
assert should_loud_blindspot_alert_without_lateral(CS, _sm(lat_active=True, lateral_check=True, pause_lateral=True), _toggles())
def test_loud_blindspot_alert_without_lateral_ignores_active_lateral():
CS = _car_state(right_blinker=True, right_blindspot=True)
assert not should_loud_blindspot_alert_without_lateral(CS, _sm(lat_active=True, lateral_check=True), _toggles())
def test_loud_blindspot_alert_without_lateral_requires_matching_side_and_toggle():
assert not should_loud_blindspot_alert_without_lateral(_car_state(left_blinker=True, right_blindspot=True), _sm(), _toggles())
assert not should_loud_blindspot_alert_without_lateral(_car_state(left_blinker=True, right_blinker=True, left_blindspot=True), _sm(), _toggles())
assert not should_loud_blindspot_alert_without_lateral(_car_state(left_blinker=True, left_blindspot=True), _sm(), _toggles(enabled=False))
def test_loud_blindspot_alert_without_lateral_skips_normal_lane_change_alert_path():
CS = _car_state(left_blinker=True, left_blindspot=True)
assert not should_loud_blindspot_alert_without_lateral(CS, _sm(lane_change_state=LaneChangeState.preLaneChange), _toggles())
@@ -404,6 +404,7 @@ class StarPilotSoundsLayout(_SettingsPage):
"GreenLightAlert",
"LeadDepartingAlert",
"LoudBlindspotAlert",
"LoudBlindspotAlertWhenDisengaged",
"SpeedLimitChangedAlert",
]
@@ -445,6 +446,12 @@ class StarPilotSoundsLayout(_SettingsPage):
"is_enabled": lambda: starpilot_state.car_state.hasBSM,
"disabled_label": tr_noop("Needs BSM")
},
"LoudBlindspotAlertWhenDisengaged": {
"title": tr_noop("Loud While Paused"),
"subtitle": tr_noop("When lateral is off or paused"),
"is_enabled": lambda: starpilot_state.car_state.hasBSM and self._params.get_bool("LoudBlindspotAlert"),
"disabled_label": tr_noop("Enable Loud Blindspot")
},
"SpeedLimitChangedAlert": {
"title": tr_noop("Speed Limit"),
"subtitle": tr_noop("When posted speed limit changes"),
@@ -144,7 +144,13 @@ class VehicleSettingsManagerView(AetherInteractiveMixin, Widget):
"get_state": lambda: self._controller._params.get_bool("GMDashSpoofOffsets"),
"set_state": lambda s: self._controller._on_toggle("GMDashSpoofOffsets"),
})
if cs.isGM:
if cs.isGM and cs.hasOpenpilotLongitudinal:
toggles.append({
"title": tr("Stock Dash Disengaged"),
"subtitle": tr("Use the stock GM dash set speed while openpilot is not engaged."),
"get_state": lambda: self._controller._params.get_bool("GMStockDashWhenNotEngaged"),
"set_state": lambda s: self._controller._on_toggle("GMStockDashWhenNotEngaged"),
})
toggles.append({
"title": tr("Remote Start Panda"),
"get_state": lambda: self._controller._params.get_bool("RemoteStartBootsComma"),
+2
View File
@@ -113,6 +113,7 @@ SAFE_MODE_MANAGED_KEYS = (
"CESpeed",
"CESpeedLead",
"CCMLead",
"CCMLaunchAssist",
"CCMSetSpeedMargin",
"CCMSpeed",
"CCMSpeedLead",
@@ -183,6 +184,7 @@ SAFE_MODE_MANAGED_KEYS = (
"GMAutoHold",
"GMPedalLongitudinal",
"GMDashSpoofOffsets",
"GMStockDashWhenNotEngaged",
"LongPitch",
)
+7
View File
@@ -723,6 +723,7 @@ class StarPilotVariables:
toggle.conditional_chill_speed_lead = self.get_value("CCMSpeedLead", cast=float, condition=toggle.conditional_chill_mode, conversion=speed_conversion)
toggle.conditional_chill_speed_margin = self.get_value("CCMSetSpeedMargin", cast=float, condition=toggle.conditional_chill_mode, conversion=speed_conversion)
toggle.conditional_chill_lead = self.get_value("CCMLead", condition=toggle.conditional_chill_mode)
toggle.conditional_chill_launch_assist = self.get_value("CCMLaunchAssist", condition=toggle.conditional_chill_mode)
toggle.cem_status = (
self.get_value("ShowCEMStatus", condition=toggle.conditional_experimental_mode) or
self.get_value("ShowCCMStatus", condition=toggle.conditional_chill_mode) or
@@ -738,6 +739,7 @@ class StarPilotVariables:
toggle.green_light_alert = self.get_value("GreenLightAlert", condition=custom_alerts)
toggle.lead_departing_alert = self.get_value("LeadDepartingAlert", condition=custom_alerts)
toggle.loud_blindspot_alert = self.get_value("LoudBlindspotAlert", condition=custom_alerts and has_bsm)
toggle.loud_blindspot_alert_when_disengaged = self.get_value("LoudBlindspotAlertWhenDisengaged", condition=toggle.loud_blindspot_alert)
toggle.speed_limit_changed_alert = self.get_value("SpeedLimitChangedAlert", condition=custom_alerts)
toggle.custom_personalities = toggle.openpilot_longitudinal and self.get_value("CustomPersonalities")
@@ -1305,6 +1307,7 @@ class StarPilotVariables:
toggle.green_light_alert = False
toggle.lead_departing_alert = False
toggle.loud_blindspot_alert = False
toggle.loud_blindspot_alert_when_disengaged = False
toggle.speed_limit_changed_alert = False
toggle.startup_alert_top = "Be ready to take over at any time"
@@ -1326,6 +1329,10 @@ class StarPilotVariables:
"GMDashSpoofOffsets",
condition=toggle.car_make == "gm" and toggle.has_pedal,
)
toggle.gm_stock_dash_when_not_engaged = self.get_value(
"GMStockDashWhenNotEngaged",
condition=toggle.car_make == "gm" and toggle.openpilot_longitudinal,
)
toggle.long_pitch = self.get_value(
"LongPitch",
condition=toggle.openpilot_longitudinal and toggle.car_make == "gm",
@@ -12,17 +12,24 @@ from openpilot.starpilot.common.experimental_state import (
class ConditionalChillMode:
CCM_STOP_MODEL_TIME = 7.0
CHILL_ENTRY_CONFIRM_TIME = 0.35
CHILL_SPEED_ENTRY_CONFIRM_TIME = 0.35
CHILL_LEAD_ENTRY_CONFIRM_TIME = 1.0
CHILL_LAUNCH_ENTRY_CONFIRM_TIME = 0.0
CHILL_EXIT_BUFFER_TIME = 0.35
CHILL_MIN_DWELL_TIME = 1.2
CHILL_LAUNCH_EXIT_SPEED = 15 * CV.MPH_TO_MS
CHILL_LAUNCH_MAX_ENTRY_SPEED = 1.0
CHILL_LAUNCH_MAX_BRAKE = 0.2
CHILL_LAUNCH_MAX_CLOSING_SPEED = 0.75
STABLE_LEAD_MIN_MODEL_PROB = 0.9
STABLE_LEAD_MAX_BRAKE = 0.2
STABLE_LEAD_MIN_SPEED = 1.5
STABLE_LEAD_MAX_DISTANCE = 90.0
STABLE_LEAD_MAX_DISTANCE_TIME = 4.5
STABLE_LEAD_MAX_CLOSING_SPEED = 0.75
STABLE_LEAD_MAX_CLOSING_RATIO = 0.03
STABLE_LEAD_MAX_CLOSING_SPEED = 1.25
STABLE_LEAD_MAX_CLOSING_RATIO = 0.05
ADJACENT_LEAD_VETO_MIN_SPEED = 1.0
ADJACENT_LEAD_VETO_MAX_DISTANCE = 65.0
@@ -43,6 +50,7 @@ class ConditionalChillMode:
self._soft_exit_since = 0.0
self._chill_hold_until = 0.0
self._prev_cc_status = None
self._launch_active = False
def update(self, v_ego, v_cruise, sm, starpilot_toggles):
now = time.monotonic()
@@ -57,23 +65,24 @@ class ConditionalChillMode:
return
self._refresh_detector(v_ego, sm)
auto_status, launch_candidate = self._get_chill_status(v_ego, v_cruise, sm, starpilot_toggles)
if safe_mode or self._has_hard_veto(v_ego, sm):
if safe_mode or self._has_hard_veto(v_ego, sm, allow_launch=launch_candidate):
self._reset_timers()
self.experimental_mode = False if safe_mode else True
self.status_value = CCStatus["OFF"]
self._write_status(CCStatus["OFF"])
return
auto_status = self._get_chill_status(v_ego, v_cruise, sm, starpilot_toggles)
chill_candidate = auto_status != CCStatus["OFF"]
entry_confirm_time = self._get_entry_confirm_time(auto_status, launch_candidate)
if chill_candidate:
if self._candidate_since == 0.0:
self._candidate_since = now
self._soft_exit_since = 0.0
if not self.experimental_mode or (now - self._candidate_since) >= self.CHILL_ENTRY_CONFIRM_TIME:
if not self.experimental_mode or (now - self._candidate_since) >= entry_confirm_time:
self.experimental_mode = False
self._active_auto_status = auto_status
self._chill_hold_until = max(self._chill_hold_until, now + self.CHILL_MIN_DWELL_TIME)
@@ -103,6 +112,7 @@ class ConditionalChillMode:
self._candidate_since = 0.0
self._soft_exit_since = 0.0
self._chill_hold_until = 0.0
self._launch_active = False
def _refresh_detector(self, v_ego, sm):
detector_toggles = type("DetectorToggles", (), {
@@ -116,8 +126,8 @@ class ConditionalChillMode:
self.detector.slow_lead(detector_toggles, v_ego)
self.detector.stop_sign_and_light(v_ego, sm, self.CCM_STOP_MODEL_TIME)
def _has_hard_veto(self, v_ego, sm):
if sm["carState"].standstill:
def _has_hard_veto(self, v_ego, sm, allow_launch=False):
if sm["carState"].standstill and not allow_launch:
return True
if sm["carState"].leftBlinker or sm["carState"].rightBlinker:
@@ -138,7 +148,7 @@ class ConditionalChillMode:
if self._adjacent_lead_ambiguous(sm, v_ego):
return True
return self._low_speed_stop_scene(v_ego)
return self._low_speed_stop_scene(v_ego) and not allow_launch
def _low_speed_stop_scene(self, v_ego):
if v_ego >= self.LOW_SPEED_STOP_SCENE_MAX_SPEED:
@@ -157,6 +167,11 @@ class ConditionalChillMode:
return lead_distance < lead_distance_limit and lead_speed < max(6.0, v_ego + 0.5)
def _get_chill_status(self, v_ego, v_cruise, sm, starpilot_toggles):
if getattr(starpilot_toggles, "conditional_chill_launch_assist", False):
launch_status = self._get_launch_status(v_ego, sm)
if launch_status != CCStatus["OFF"]:
return launch_status, True
lead = self.starpilot_planner.lead_one
lead_status = bool(getattr(lead, "status", False))
tracking_lead = bool(getattr(self.starpilot_planner, "tracking_lead", False))
@@ -165,13 +180,13 @@ class ConditionalChillMode:
if (not lead_status and not tracking_lead and
v_ego >= starpilot_toggles.conditional_chill_speed and
set_speed_error >= starpilot_toggles.conditional_chill_speed_margin):
return CCStatus["SPEED"]
return CCStatus["SPEED"], False
if not starpilot_toggles.conditional_chill_lead:
return CCStatus["OFF"]
return CCStatus["OFF"], False
if v_ego < starpilot_toggles.conditional_chill_speed_lead or not lead_status or not tracking_lead:
return CCStatus["OFF"]
return CCStatus["OFF"], False
lead_distance = float(getattr(lead, "dRel", float("inf")))
lead_speed = float(getattr(lead, "vLead", 0.0))
@@ -183,15 +198,80 @@ class ConditionalChillMode:
lead_confident = bool(getattr(lead, "radar", False)) or lead_prob >= self.STABLE_LEAD_MIN_MODEL_PROB
if not lead_confident:
return CCStatus["OFF"]
return CCStatus["OFF"], False
if lead_distance >= max_distance or lead_speed <= self.STABLE_LEAD_MIN_SPEED:
return CCStatus["OFF"]
return CCStatus["OFF"], False
if lead_brake > self.STABLE_LEAD_MAX_BRAKE or closing_speed > max_closing_speed:
return CCStatus["OFF"], False
return CCStatus["LEAD"], False
def _get_launch_status(self, v_ego, sm):
if self._launch_active and self._launch_exit_required(v_ego, sm):
self._launch_active = False
return CCStatus["OFF"]
return CCStatus["LEAD"]
if self._launch_active:
return self._get_launch_cc_status()
if not self._launch_scene_eligible(v_ego, sm):
return CCStatus["OFF"]
self._launch_active = True
return self._get_launch_cc_status()
def _launch_scene_eligible(self, v_ego, sm):
if v_ego > self.CHILL_LAUNCH_MAX_ENTRY_SPEED and not self._launch_active:
return False
selfdrive_state = self._get_sm_service(sm, "selfdriveState")
longitudinal_plan = self._get_sm_service(sm, "longitudinalPlan")
if selfdrive_state is None or longitudinal_plan is None:
return False
if not bool(getattr(selfdrive_state, "enabled", False)):
return False
if bool(getattr(longitudinal_plan, "shouldStop", False)) or not bool(getattr(longitudinal_plan, "allowThrottle", False)):
return False
lead = getattr(self.starpilot_planner, "lead_one", None)
lead_status = bool(getattr(lead, "status", False))
tracking_lead = bool(getattr(self.starpilot_planner, "tracking_lead", False))
if not lead_status and not tracking_lead:
return True
lead_speed = float(getattr(lead, "vLead", 0.0))
lead_brake = max(0.0, -float(getattr(lead, "aLeadK", 0.0)))
closing_speed = max(0.0, v_ego - lead_speed)
return lead_speed > self.STABLE_LEAD_MIN_SPEED and lead_brake <= self.CHILL_LAUNCH_MAX_BRAKE and closing_speed <= self.CHILL_LAUNCH_MAX_CLOSING_SPEED
def _launch_exit_required(self, v_ego, sm):
if v_ego >= self.CHILL_LAUNCH_EXIT_SPEED:
return True
if not self._launch_scene_eligible(v_ego, sm):
return True
return False
def _get_launch_cc_status(self):
lead = getattr(self.starpilot_planner, "lead_one", None)
lead_status = bool(getattr(lead, "status", False))
tracking_lead = bool(getattr(self.starpilot_planner, "tracking_lead", False))
return CCStatus["LEAD"] if lead_status or tracking_lead else CCStatus["SPEED"]
def _get_entry_confirm_time(self, auto_status, launch_candidate):
if launch_candidate:
return self.CHILL_LAUNCH_ENTRY_CONFIRM_TIME
if auto_status == CCStatus["LEAD"]:
return self.CHILL_LEAD_ENTRY_CONFIRM_TIME
return self.CHILL_SPEED_ENTRY_CONFIRM_TIME
def _adjacent_lead_ambiguous(self, sm, v_ego):
radar_state = self._get_sm_service(sm, "starpilotRadarState")
@@ -1665,6 +1665,14 @@
"ui_type": "toggle",
"parent_key": "ConditionalChill"
},
{
"key": "CCMLaunchAssist",
"label": "Launch Assist",
"description": "Temporarily switch to \"Chill Mode\" when starting from a stop if planner is already allowing throttle. Useful if your car launches too slowly from lights or stop signs.",
"data_type": "bool",
"ui_type": "toggle",
"parent_key": "ConditionalChill"
},
{
"key": "CCMSetSpeedMargin",
"label": "Set Speed Margin",
@@ -2242,6 +2250,14 @@
"ui_type": "toggle",
"parent_key": "CustomAlerts"
},
{
"key": "LoudBlindspotAlertWhenDisengaged",
"label": "Blind Spot Alert When Disengaged",
"description": "Play the loud blind spot alert while lateral control is off or paused. Useful when steering pauses on turn signal, since the lane-change state machine is inactive then.",
"data_type": "bool",
"ui_type": "toggle",
"parent_key": "CustomAlerts"
},
{
"key": "SpeedLimitChangedAlert",
"label": "Speed Limit Changed Alert",
@@ -2401,6 +2417,13 @@
"data_type": "bool",
"ui_type": "toggle"
},
{
"key": "GMStockDashWhenNotEngaged",
"label": "Stock Dash When Disengaged",
"description": "Use the stock GM dashboard set speed while openpilot is not engaged. When off, StarPilot keeps the existing dashboard spoof behavior.",
"data_type": "bool",
"ui_type": "toggle"
},
{
"key": "LongPitch",
"label": "Smooth Pedal Response on Hills",
@@ -3331,4 +3354,4 @@
}
]
}
]
]
@@ -102,6 +102,7 @@ StarPilotLongitudinalPanel::StarPilotLongitudinalPanel(StarPilotSettingsWindow *
{"PersistChillState", tr("Persist Chill State"), tr("<b>Keep your manual Conditional Chill override through reboots</b> until you manually clear it."), ""},
{"CCMSpeed", tr("Above"), tr("<b>Switch to \"Chill Mode\" on open roads above this speed when no lead is detected and the car is still below the set speed.</b>"), ""},
{"CCMLead", tr("Stable Lead Ahead"), tr("<b>Switch to \"Chill Mode\" when following a steady, well-tracked lead vehicle at cruising speeds.</b>"), ""},
{"CCMLaunchAssist", tr("Launch Assist"), tr("<b>Temporarily switch to \"Chill Mode\" when starting from a stop if planner is already allowing throttle.</b> Useful if your car launches too slowly from lights or stop signs."), ""},
{"CCMSetSpeedMargin", tr("Set Speed Margin"), tr("<b>How far below the set speed the car must be before open-road Conditional Chill can engage.</b>"), ""},
{"ShowCCMStatus", tr("Status Widget"), tr("<b>Show which condition triggered \"Chill Mode\"</b> on the driving screen."), ""},
@@ -30,7 +30,7 @@ private:
QSet<QString> advancedLongitudinalTuneKeys = {"EVTuning", "TruckTuning", "LongitudinalActuatorDelay", "MaxDesiredAcceleration", "StartAccel", "StopAccel", "StoppingDecelRate", "VEgoStarting", "VEgoStopping"};
QSet<QString> aggressivePersonalityKeys = {"AggressiveFollow", "AggressiveFollowHigh", "AggressiveJerkAcceleration", "AggressiveJerkDeceleration", "AggressiveJerkDanger", "AggressiveJerkSpeed", "AggressiveJerkSpeedDecrease", "ResetAggressivePersonality"};
QSet<QString> conditionalChillKeys = {"PersistChillState", "CCMSpeed", "CCMSpeedLead", "CCMLead", "CCMSetSpeedMargin", "ShowCCMStatus"};
QSet<QString> conditionalChillKeys = {"PersistChillState", "CCMSpeed", "CCMSpeedLead", "CCMLead", "CCMLaunchAssist", "CCMSetSpeedMargin", "ShowCCMStatus"};
QSet<QString> conditionalExperimentalKeys = {"PersistExperimentalState", "CESpeed", "CESpeedLead", "CECurves", "CELead", "CEModelStopTime", "CESignalSpeed", "CEStopLights", "ShowCEMStatus"};
QSet<QString> curveSpeedKeys = {"CalibratedLateralAcceleration", "CalibrationProgress", "ResetCurveData", "ShowCSCStatus"};
QSet<QString> customDrivingPersonalityKeys = {"AggressivePersonalityProfile", "RelaxedPersonalityProfile", "StandardPersonalityProfile", "TrafficPersonalityProfile"};
@@ -39,6 +39,7 @@ StarPilotSoundsPanel::StarPilotSoundsPanel(StarPilotSettingsWindow *parent, bool
{"GreenLightAlert", tr("Green Light Alert"), tr("<b>Play an alert when the model predicts a red light has turned green.</b><br><br><i><b>Disclaimer</b>: openpilot does not explicitly detect traffic lights. This alert is based on end-to-end model predictions from camera input and may trigger even when the light has not changed.</i>"), ""},
{"LeadDepartingAlert", tr("Lead Departing Alert"), tr("<b>Play an alert when the lead vehicle departs from a stop.</b>"), ""},
{"LoudBlindspotAlert", tr("Loud \"Car Detected in Blindspot\" Alert"), tr("<b>Play a louder alert if a vehicle is in the blind spot when attempting to change lanes.</b> Based on the \"Car Detected in Blindspot\" event."), ""},
{"LoudBlindspotAlertWhenDisengaged", tr("Blind Spot Alert When Disengaged"), tr("<b>Play the loud blind spot alert while lateral control is off or paused.</b><br><br>Useful when steering pauses on turn signal, since the lane-change state machine is inactive then."), ""},
{"SpeedLimitChangedAlert", tr("Speed Limit Changed Alert"), tr("<b>Play an alert when the posted speed limit changes.</b>"), ""}
};
@@ -192,6 +193,10 @@ void StarPilotSoundsPanel::updateToggles() {
setVisible &= parent->hasBSM;
}
else if (key == "LoudBlindspotAlertWhenDisengaged") {
setVisible &= parent->hasBSM && params.getBool("LoudBlindspotAlert");
}
else if (key == "SpeedLimitChangedAlert") {
setVisible &= params.getBool("ShowSpeedLimits") || (parent->hasOpenpilotLongitudinal && params.getBool("SpeedLimitController"));
}
+1 -1
View File
@@ -27,7 +27,7 @@ private:
QSet<QString> alertCooldownKeys {"SwitchbackModeCooldown"};
QSet<QString> alertVolumeControlKeys {"BelowSteerSpeedVolume", "DisengageVolume", "EngageVolume", "PromptDistractedVolume", "PromptVolume", "RefuseVolume", "WarningImmediateVolume", "WarningSoftVolume"};
QSet<QString> customAlertsKeys {"GoatScream", "GoatScreamCriticalAlerts", "GreenLightAlert", "LeadDepartingAlert", "LoudBlindspotAlert", "SpeedLimitChangedAlert"};
QSet<QString> customAlertsKeys {"GoatScream", "GoatScreamCriticalAlerts", "GreenLightAlert", "LeadDepartingAlert", "LoudBlindspotAlert", "LoudBlindspotAlertWhenDisengaged", "SpeedLimitChangedAlert"};
QSet<QString> parentKeys;
@@ -173,6 +173,7 @@ StarPilotVehiclesPanel::StarPilotVehiclesPanel(StarPilotSettingsWindow *parent,
{"GMToggles", tr("General Motors Settings"), tr("<b>StarPilot features for General Motors vehicles.</b>"), ""},
{"GMPedalLongitudinal", tr("Use Pedal For Longitudinal"), tr("<b>Use the pedal interceptor for full longitudinal control</b> on supported GM vehicles."), ""},
{"GMDashSpoofOffsets", tr("Apply Offsets To Dash Spoof"), tr("<b>On GM pedal-long cars, add the configured set-speed offset</b> to the spoofed dash set speed so it matches the on-screen set speed."), ""},
{"GMStockDashWhenNotEngaged", tr("Stock Dash When Disengaged"), tr("<b>Use the stock GM dashboard set speed while openpilot is not engaged.</b><br><br>When off, StarPilot keeps the existing dashboard spoof behavior."), ""},
{"LongPitch", tr("Smooth Pedal Response on Hills"), tr("<b>Smoothen acceleration and braking</b> when driving downhill/uphill."), ""},
{"RemoteStartBootsComma", tr("Remote Start Boots comma"), tr("<b>Use the remote-start GM panda firmware at boot.</b><br><br>Required for GM remote-start startup signal behavior."), ""},
{"RemapCancelToDistance", tr("Remap Cancel Button"), tr("<b>On pedal-interceptor Bolts, treat the steering-wheel CANCEL button as an extra mappable button.</b>"), ""},
+2 -2
View File
@@ -23,8 +23,8 @@ private:
std::map<QString, AbstractControl*> toggles;
QSet<QString> gmKeys = {"GMPedalLongitudinal", "GMDashSpoofOffsets", "LongPitch", "RemoteStartBootsComma", "RemapCancelToDistance", "VoltSNG"};
QSet<QString> longitudinalKeys = {"FrogsGoMoosTweak", "GMDashSpoofOffsets", "LongPitch", "RemapCancelToDistance", "SNGHack", "VoltSNG"};
QSet<QString> gmKeys = {"GMPedalLongitudinal", "GMDashSpoofOffsets", "GMStockDashWhenNotEngaged", "LongPitch", "RemoteStartBootsComma", "RemapCancelToDistance", "VoltSNG"};
QSet<QString> longitudinalKeys = {"FrogsGoMoosTweak", "GMDashSpoofOffsets", "GMStockDashWhenNotEngaged", "LongPitch", "RemapCancelToDistance", "SNGHack", "VoltSNG"};
QSet<QString> subaruKeys = {"SubaruSNG"};
QSet<QString> toyotaKeys = {"ClusterOffset", "FrogsGoMoosTweak", "LockDoorsTimer", "SNGHack", "ToyotaDoors"};
QSet<QString> vehicleInfoKeys = {"BlindSpotSupport", "HardwareDetected", "OpenpilotLongitudinal", "PedalSupport", "RadarSupport", "SDSUSupport", "SNGSupport"};