Conditional Chill

This commit is contained in:
firestar5683
2026-06-06 21:25:18 -05:00
parent a888c5602a
commit f8934840da
26 changed files with 1152 additions and 1387 deletions
+9
View File
@@ -42,7 +42,9 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"ExperimentalLongitudinalEnabled", {PERSISTENT, BOOL}},
{"ExperimentalMode", {PERSISTENT, BOOL}},
{"ExperimentalModeConfirmed", {PERSISTENT, BOOL}},
{"PersistChillState", {PERSISTENT, BOOL, "0", "0", 1}},
{"PersistExperimentalState", {PERSISTENT, BOOL, "0", "0", 1}},
{"PersistedCCStatus", {PERSISTENT, INT, "0", "0"}},
{"PersistedCEStatus", {PERSISTENT, INT, "0", "0"}},
{"FirmwareQueryDone", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}},
{"ForcePowerDown", {PERSISTENT, BOOL}},
@@ -196,6 +198,11 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"CESlowerLead", {PERSISTENT, BOOL, "1", "0", 1}},
{"CESpeed", {PERSISTENT, FLOAT, "0.0", "0.0", 1}},
{"CESpeedLead", {PERSISTENT, FLOAT, "0.0", "0.0", 1}},
{"CCMLead", {PERSISTENT, BOOL, "1", "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}},
{"CCStatus", {CLEAR_ON_OFFROAD_TRANSITION, INT, "0", "0"}},
{"CEStatus", {CLEAR_ON_OFFROAD_TRANSITION, INT, "0", "0"}},
{"CEStopLights", {PERSISTENT, BOOL, "1", "0", 1}},
{"CEStoppedLead", {PERSISTENT, BOOL, "0", "0", 1}},
@@ -205,6 +212,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"BootLogoToDownload", {CLEAR_ON_MANAGER_START, STRING, "", ""}},
{"Compass", {PERSISTENT, BOOL, "0", "0", 1}},
{"CommunityFavorites", {PERSISTENT, STRING, "", "", 1}},
{"ConditionalChill", {PERSISTENT, BOOL, "0", "0", 1}},
{"ConditionalExperimental", {PERSISTENT, BOOL, "1", "0", 1}},
{"CurvatureData", {PERSISTENT | DONT_LOG, JSON, "{}", "{}"}},
{"CurveSpeedController", {PERSISTENT, BOOL, "1", "0", 1}},
@@ -487,6 +495,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
{"SetSpeedLimit", {PERSISTENT, BOOL, "0", "0", 1}},
{"SetSpeedOffset", {PERSISTENT, FLOAT, "0.0", "0.0", 2}},
{"ShowCEMStatus", {PERSISTENT, BOOL, "1", "0", 2}},
{"ShowCCMStatus", {PERSISTENT, BOOL, "0", "0", 2}},
{"ShowCPU", {PERSISTENT, BOOL, "1", "0", 3}},
{"ShowCSCStatus", {PERSISTENT, BOOL, "1", "0", 2}},
{"ShowGPU", {PERSISTENT, BOOL, "0", "0", 3}},
@@ -0,0 +1,226 @@
from types import SimpleNamespace
from openpilot.common.constants import CV
from openpilot.starpilot.common.experimental_state import CCStatus
from openpilot.starpilot.controls.lib.conditional_chill_mode import ConditionalChillMode
class FakeParams:
def __init__(self, bools=None, ints=None):
self.bools = dict(bools or {})
self.ints = dict(ints or {})
def get_bool(self, key):
return bool(self.bools.get(key, False))
def put_bool(self, key, value):
self.bools[key] = bool(value)
def get_int(self, key, default=0):
return int(self.ints.get(key, default))
def put_int(self, key, value):
self.ints[key] = int(value)
class FakeDetector:
def __init__(self):
self.curve_detected = False
self.slow_lead_detected = False
self.stop_light_detected = False
self.stop_light_model_detected = False
def curve_detection(self, *_args, **_kwargs):
return None
def slow_lead(self, *_args, **_kwargs):
return None
def stop_sign_and_light(self, *_args, **_kwargs):
return None
def make_sm():
return {
"carState": SimpleNamespace(standstill=False, leftBlinker=False, rightBlinker=False),
"starpilotCarState": SimpleNamespace(trafficModeEnabled=False),
"starpilotRadarState": SimpleNamespace(
leadLeft=SimpleNamespace(status=False, dRel=float("inf"), vLead=0.0),
leadRight=SimpleNamespace(status=False, dRel=float("inf"), vLead=0.0),
),
}
def make_toggles():
return SimpleNamespace(
conditional_chill_speed=45 * CV.MPH_TO_MS,
conditional_chill_speed_lead=35 * CV.MPH_TO_MS,
conditional_chill_speed_margin=3 * CV.MPH_TO_MS,
conditional_chill_lead=True,
)
def make_ccm():
planner = SimpleNamespace(
params=FakeParams(),
params_memory=FakeParams(),
starpilot_vcruise=SimpleNamespace(
stop_sign_confirmed=False,
forcing_stop=False,
slc=SimpleNamespace(experimental_mode=False),
),
raw_model_stopped=False,
model_stopped=False,
tracking_lead=False,
lead_one=SimpleNamespace(
status=False,
dRel=float("inf"),
vLead=0.0,
aLeadK=0.0,
modelProb=0.0,
radar=False,
),
)
detector = FakeDetector()
return planner, detector, ConditionalChillMode(planner, detector)
def test_ccm_stays_experimental_when_no_chill_condition_matches(monkeypatch):
planner, _detector, ccm = make_ccm()
sm = make_sm()
toggles = make_toggles()
monkeypatch.setattr("openpilot.starpilot.controls.lib.conditional_chill_mode.time.monotonic", lambda: 1.0)
ccm.update(20 * CV.MPH_TO_MS, 21 * CV.MPH_TO_MS, sm, toggles)
assert ccm.experimental_mode
assert ccm.status_value == CCStatus["OFF"]
def test_ccm_enters_chill_for_open_road_speed_recovery(monkeypatch):
planner, _detector, ccm = make_ccm()
sm = make_sm()
toggles = make_toggles()
monotonic_values = iter([10.0, 10.5])
monkeypatch.setattr("openpilot.starpilot.controls.lib.conditional_chill_mode.time.monotonic", lambda: next(monotonic_values))
v_ego = 55 * CV.MPH_TO_MS
v_cruise = v_ego + 5 * CV.MPH_TO_MS
ccm.update(v_ego, v_cruise, sm, toggles)
ccm.update(v_ego, v_cruise, sm, toggles)
assert not ccm.experimental_mode
assert ccm.status_value == CCStatus["SPEED"]
assert planner.params_memory.get_int("CCStatus") == CCStatus["SPEED"]
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])
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 not ccm.experimental_mode
assert ccm.status_value == CCStatus["LEAD"]
def test_ccm_hard_vetoes_force_experimental(monkeypatch):
planner, detector, ccm = make_ccm()
sm = make_sm()
toggles = make_toggles()
v_ego = 60 * CV.MPH_TO_MS
v_cruise = v_ego + 5 * CV.MPH_TO_MS
veto_scenes = []
detector.slow_lead_detected = True
veto_scenes.append(("slow_lead", make_sm()))
detector.slow_lead_detected = False
traffic_sm = make_sm()
traffic_sm["starpilotCarState"].trafficModeEnabled = True
veto_scenes.append(("traffic_mode", traffic_sm))
adjacent_sm = make_sm()
adjacent_sm["starpilotRadarState"].leadLeft = SimpleNamespace(status=True, dRel=25.0, vLead=12.0)
veto_scenes.append(("adjacent_lead", adjacent_sm))
for index, (_name, scene_sm) in enumerate(veto_scenes, start=1):
monkeypatch.setattr("openpilot.starpilot.controls.lib.conditional_chill_mode.time.monotonic", lambda idx=index: float(idx))
if _name == "slow_lead":
detector.slow_lead_detected = True
else:
detector.slow_lead_detected = False
ccm.update(v_ego, v_cruise, scene_sm, toggles)
assert ccm.experimental_mode
assert ccm.status_value == CCStatus["OFF"]
planner.starpilot_vcruise.slc.experimental_mode = True
monkeypatch.setattr("openpilot.starpilot.controls.lib.conditional_chill_mode.time.monotonic", lambda: 10.0)
ccm.update(v_ego, v_cruise, sm, toggles)
assert ccm.experimental_mode
assert ccm.status_value == CCStatus["OFF"]
def test_ccm_immediately_exits_chill_when_scene_turns_into_slow_lead(monkeypatch):
planner, detector, ccm = make_ccm()
sm = make_sm()
toggles = make_toggles()
monotonic_values = iter([10.0, 10.5, 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 = 40.0
planner.lead_one.vLead = 24.9
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 not ccm.experimental_mode
detector.slow_lead_detected = True
ccm.update(v_ego, v_ego, 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()
toggles = make_toggles()
planner.params_memory.put_int("CCStatus", CCStatus["USER_CHILL"])
monkeypatch.setattr("openpilot.starpilot.controls.lib.conditional_chill_mode.time.monotonic", lambda: 1.0)
ccm.update(55 * CV.MPH_TO_MS, 60 * CV.MPH_TO_MS, sm, toggles)
assert not ccm.experimental_mode
assert ccm.status_value == CCStatus["USER_CHILL"]
def test_ccm_restores_persisted_manual_experimental_override(monkeypatch):
planner, _detector, ccm = make_ccm()
sm = make_sm()
toggles = make_toggles()
planner.params.put_bool("PersistChillState", True)
planner.params.put_int("PersistedCCStatus", CCStatus["USER_EXPERIMENTAL"])
monkeypatch.setattr("openpilot.starpilot.controls.lib.conditional_chill_mode.time.monotonic", lambda: 1.0)
ccm.update(55 * CV.MPH_TO_MS, 60 * CV.MPH_TO_MS, sm, toggles)
assert ccm.experimental_mode
assert ccm.status_value == CCStatus["USER_EXPERIMENTAL"]
assert planner.params_memory.get_int("CCStatus") == CCStatus["USER_EXPERIMENTAL"]
+1 -1
View File
@@ -593,7 +593,7 @@ class SelfdriveD:
self.starpilot_events.add_from_msg(self.sm['starpilotPlan'].starpilotEvents)
if self.starpilot_toggles.conditional_experimental_mode:
if self.starpilot_toggles.conditional_experimental_mode or getattr(self.starpilot_toggles, "conditional_chill_mode", False):
self.experimental_mode = self.sm['starpilotPlan'].experimentalMode
else:
self.experimental_mode |= self.sm['starpilotPlan'].experimentalMode
+13 -2
View File
@@ -12,8 +12,13 @@ ExperimentalModeButton::ExperimentalModeButton(QWidget *parent) : QPushButton(pa
chill_pixmap = QPixmap("../assets/icons/couch.svg").scaledToWidth(img_width, Qt::SmoothTransformation);
experimental_pixmap = QPixmap("../assets/icons/experimental_grey.svg").scaledToWidth(img_width, Qt::SmoothTransformation);
// go to toggles and expand experimental mode description
connect(this, &QPushButton::clicked, [=]() { emit openSettings(2, "ExperimentalMode"); });
// go to toggles and expand whichever mode control is actually active
connect(this, &QPushButton::clicked, [=]() {
const QString toggle = params.getBool("ConditionalExperimental") ? "ConditionalExperimental" :
params.getBool("ConditionalChill") ? "ConditionalChill" :
"ExperimentalMode";
emit openSettings(2, toggle);
});
setFixedHeight(125);
QHBoxLayout *main_layout = new QHBoxLayout;
@@ -76,6 +81,12 @@ void ExperimentalModeButton::showEvent(QShowEvent *event) {
status = params.getInt("PersistedCEStatus");
}
experimental_mode = !params.getBool("SafeMode") && status == 2;
} else if (params.getBool("ConditionalChill")) {
int status = params_memory.getInt("CCStatus");
if ((status != 1 && status != 2) && params.getBool("PersistChillState")) {
status = params.getInt("PersistedCCStatus");
}
experimental_mode = !params.getBool("SafeMode") && (status == 0 || status == 1);
} else {
experimental_mode = params.getBool("ExperimentalMode") && !params.getBool("SafeMode");
}
+21 -2
View File
@@ -4,6 +4,16 @@
#include "selfdrive/ui/qt/util.h"
namespace {
bool ccmManualOverride(int status) {
return status == 1 || status == 2;
}
bool cemManualOverride(int status) {
return status == 1 || status == 2;
}
} // namespace
void drawIcon(QPainter &p, const QPoint &center, const QPixmap &img, const QBrush &bg, float opacity, const int &angle) {
p.setRenderHint(QPainter::Antialiasing);
p.setOpacity(1.0); // bg dictates opacity of ellipse
@@ -38,9 +48,13 @@ void ExperimentalButton::changeMode() {
bool can_change = hasLongitudinalControl(cp) && params.getBool("ExperimentalModeConfirmed");
if (can_change) {
if (starpilot_toggles.value("conditional_experimental_mode").toBool()) {
int override_value = (starpilot_scene.conditional_status == 1 || starpilot_scene.conditional_status == 2) ? 0 : experimental_mode ? 1 : 2;
int override_value = cemManualOverride(starpilot_scene.conditional_status) ? 0 : experimental_mode ? 1 : 2;
params_memory.putInt("CEStatus", override_value);
params.putInt("PersistedCEStatus", params.getBool("PersistExperimentalState") ? override_value : 0);
} else if (starpilot_toggles.value("conditional_chill_mode").toBool()) {
int override_value = ccmManualOverride(starpilot_scene.conditional_status) ? 0 : experimental_mode ? 2 : 1;
params_memory.putInt("CCStatus", override_value);
params.putInt("PersistedCCStatus", params.getBool("PersistChillState") ? override_value : 0);
} else {
params.putBool("ExperimentalMode", !experimental_mode);
}
@@ -97,6 +111,11 @@ void ExperimentalButton::showEvent(QShowEvent *event) {
}
void ExperimentalButton::updateBackgroundColor() {
const bool conditional_experimental_mode = starpilot_toggles.value("conditional_experimental_mode").toBool();
const bool conditional_chill_mode = starpilot_toggles.value("conditional_chill_mode").toBool();
const bool highlight_override =
(conditional_experimental_mode && starpilot_scene.conditional_status == 1) ||
(conditional_chill_mode && ccmManualOverride(starpilot_scene.conditional_status));
if (starpilot_toggles.value("simple_mode").toBool()) {
background_color = QColor(0, 0, 0, 166);
} else if (isDown() || !engageable) {
@@ -105,7 +124,7 @@ void ExperimentalButton::updateBackgroundColor() {
background_color = bg_colors[STATUS_SWITCHBACK_MODE_ENABLED];
} else if (starpilot_scene.always_on_lateral_active) {
background_color = bg_colors[STATUS_ALWAYS_ON_LATERAL_ACTIVE];
} else if (starpilot_scene.conditional_status == 1) {
} else if (highlight_override) {
background_color = bg_colors[STATUS_CEM_DISABLED];
} else if (experimental_mode) {
background_color = bg_colors[STATUS_EXPERIMENTAL_MODE_ENABLED];
+7 -4
View File
@@ -59,13 +59,19 @@ void OnroadWindow::updateState(const UIState &s, const StarPilotUIState &fs) {
nvg->updateState(s, fs);
const StarPilotUIScene &starpilot_scene = fs.starpilot_scene;
const QJsonObject &starpilot_toggles = starpilot_scene.starpilot_toggles;
const auto selfdriveState = (*s.sm)["selfdriveState"].getSelfdriveState();
QColor bgColor = bg_colors[s.status];
const bool conditional_experimental_mode = starpilot_toggles.value("conditional_experimental_mode").toBool();
const bool conditional_chill_mode = starpilot_toggles.value("conditional_chill_mode").toBool();
const bool highlight_override =
(conditional_experimental_mode && starpilot_scene.conditional_status == 1) ||
(conditional_chill_mode && (starpilot_scene.conditional_status == 1 || starpilot_scene.conditional_status == 2));
if (starpilot_scene.switchback_mode_enabled && (selfdriveState.getEnabled() || starpilot_scene.always_on_lateral_active)) {
bgColor = bg_colors[STATUS_SWITCHBACK_MODE_ENABLED];
} else if (starpilot_scene.always_on_lateral_active) {
bgColor = bg_colors[STATUS_ALWAYS_ON_LATERAL_ACTIVE];
} else if (starpilot_scene.conditional_status == 1) {
} else if (highlight_override) {
bgColor = bg_colors[STATUS_CEM_DISABLED];
} else if (selfdriveState.getExperimentalMode()) {
bgColor = bg_colors[STATUS_EXPERIMENTAL_MODE_ENABLED];
@@ -78,9 +84,6 @@ void OnroadWindow::updateState(const UIState &s, const StarPilotUIState &fs) {
bg = bgColor;
update();
}
const QJsonObject &starpilot_toggles = starpilot_scene.starpilot_toggles;
starpilot_nvg->alertHeight = alerts->alertHeight;
starpilot_onroad->bg = bg;
+13
View File
@@ -139,6 +139,11 @@ void ParamControl::toggleClicked(bool state) {
if (!confirm || confirmed || !state || do_confirm()) {
if (store_confirm && state) params.putBool(key + "Confirmed", true);
params.putBool(key, state);
if (state && key == "ConditionalExperimental") {
params.putBool("ConditionalChill", false);
} else if (state && key == "ConditionalChill") {
params.putBool("ConditionalExperimental", false);
}
if (key == "PersistExperimentalState") {
static Params params_memory{"", true};
int persisted_status = 0;
@@ -147,6 +152,14 @@ void ParamControl::toggleClicked(bool state) {
persisted_status = (current_status == 1 || current_status == 2) ? current_status : 0;
}
params.putInt("PersistedCEStatus", persisted_status);
} else if (key == "PersistChillState") {
static Params params_memory{"", true};
int persisted_status = 0;
if (state) {
int current_status = params_memory.getInt("CCStatus");
persisted_status = (current_status == 1 || current_status == 2) ? current_status : 0;
}
params.putInt("PersistedCCStatus", persisted_status);
}
setIcon(state);
} else {
+88
View File
@@ -6,6 +6,9 @@ from openpilot.common.params import Params
PERSIST_EXPERIMENTAL_STATE_PARAM = "PersistExperimentalState"
PERSISTED_CE_STATUS_PARAM = "PersistedCEStatus"
CE_STATUS_PARAM = "CEStatus"
PERSIST_CHILL_STATE_PARAM = "PersistChillState"
PERSISTED_CC_STATUS_PARAM = "PersistedCCStatus"
CC_STATUS_PARAM = "CCStatus"
CEStatus = {
"OFF": 0,
@@ -19,35 +22,71 @@ CEStatus = {
"STOP_LIGHT": 8,
}
CCStatus = {
"OFF": 0,
"USER_EXPERIMENTAL": 1,
"USER_CHILL": 2,
"LEAD": 4,
"SPEED": 6,
}
MANUAL_CE_STATUSES = {
CEStatus["USER_DISABLED"],
CEStatus["USER_OVERRIDDEN"],
}
MANUAL_CC_STATUSES = {
CCStatus["USER_EXPERIMENTAL"],
CCStatus["USER_CHILL"],
}
def is_manual_ce_status(status: int) -> bool:
return int(status) in MANUAL_CE_STATUSES
def is_manual_cc_status(status: int) -> bool:
return int(status) in MANUAL_CC_STATUSES
def normalize_persisted_ce_status(status: int) -> int:
status = int(status)
return status if status in MANUAL_CE_STATUSES else CEStatus["OFF"]
def normalize_persisted_cc_status(status: int) -> int:
status = int(status)
return status if status in MANUAL_CC_STATUSES else CCStatus["OFF"]
def get_persisted_ce_status(params: Params) -> int:
return normalize_persisted_ce_status(params.get_int(PERSISTED_CE_STATUS_PARAM, default=CEStatus["OFF"]))
def get_persisted_cc_status(params: Params) -> int:
return normalize_persisted_cc_status(params.get_int(PERSISTED_CC_STATUS_PARAM, default=CCStatus["OFF"]))
def set_persisted_ce_status(params: Params, status: int) -> int:
normalized = normalize_persisted_ce_status(status)
params.put_int(PERSISTED_CE_STATUS_PARAM, normalized)
return normalized
def set_persisted_cc_status(params: Params, status: int) -> int:
normalized = normalize_persisted_cc_status(status)
params.put_int(PERSISTED_CC_STATUS_PARAM, normalized)
return normalized
def clear_persisted_ce_status(params: Params) -> None:
params.put_int(PERSISTED_CE_STATUS_PARAM, CEStatus["OFF"])
def clear_persisted_cc_status(params: Params) -> None:
params.put_int(PERSISTED_CC_STATUS_PARAM, CCStatus["OFF"])
def sync_persist_experimental_state(params: Params, params_memory: Params | None, enabled: bool) -> None:
params.put_bool(PERSIST_EXPERIMENTAL_STATE_PARAM, enabled)
if enabled:
@@ -57,21 +96,45 @@ def sync_persist_experimental_state(params: Params, params_memory: Params | None
clear_persisted_ce_status(params)
def sync_persist_chill_state(params: Params, params_memory: Params | None, enabled: bool) -> None:
params.put_bool(PERSIST_CHILL_STATE_PARAM, enabled)
if enabled:
current_status = params_memory.get_int(CC_STATUS_PARAM, default=CCStatus["OFF"]) if params_memory is not None else CCStatus["OFF"]
set_persisted_cc_status(params, current_status)
else:
clear_persisted_cc_status(params)
def sync_manual_ce_state(params: Params, status: int) -> int:
return set_persisted_ce_status(params, status) if params.get_bool(PERSIST_EXPERIMENTAL_STATE_PARAM) else clear_and_return_off(params)
def sync_manual_cc_state(params: Params, status: int) -> int:
return set_persisted_cc_status(params, status) if params.get_bool(PERSIST_CHILL_STATE_PARAM) else clear_cc_and_return_off(params)
def clear_and_return_off(params: Params) -> int:
clear_persisted_ce_status(params)
return CEStatus["OFF"]
def clear_cc_and_return_off(params: Params) -> int:
clear_persisted_cc_status(params)
return CCStatus["OFF"]
def next_manual_ce_status(current_status: int, experimental_mode: bool) -> int:
if is_manual_ce_status(current_status):
return CEStatus["OFF"]
return CEStatus["USER_DISABLED"] if experimental_mode else CEStatus["USER_OVERRIDDEN"]
def next_manual_cc_status(current_status: int, experimental_mode: bool) -> int:
if is_manual_cc_status(current_status):
return CCStatus["OFF"]
return CCStatus["USER_CHILL"] if experimental_mode else CCStatus["USER_EXPERIMENTAL"]
def requested_experimental_mode(params: Params, params_memory: Params | None = None) -> bool:
if params.get_bool("SafeMode"):
return False
@@ -82,6 +145,14 @@ def requested_experimental_mode(params: Params, params_memory: Params | None = N
status = get_persisted_ce_status(params)
return status == CEStatus["USER_OVERRIDDEN"]
if params.get_bool("ConditionalChill"):
status = params_memory.get_int(CC_STATUS_PARAM, default=CCStatus["OFF"]) if params_memory is not None else CCStatus["OFF"]
if not is_manual_cc_status(status):
status = get_persisted_cc_status(params)
if not is_manual_cc_status(status):
return True
return status == CCStatus["USER_EXPERIMENTAL"]
return params.get_bool("ExperimentalMode")
@@ -100,3 +171,20 @@ def restore_persisted_ce_state(params: Params, params_memory: Params) -> int:
return restored_status
return current_status
def restore_persisted_cc_state(params: Params, params_memory: Params) -> int:
current_status = params_memory.get_int(CC_STATUS_PARAM, default=CCStatus["OFF"])
if is_manual_cc_status(current_status):
sync_manual_cc_state(params, current_status)
return current_status
if not params.get_bool(PERSIST_CHILL_STATE_PARAM):
return current_status
restored_status = get_persisted_cc_status(params)
if restored_status != CCStatus["OFF"]:
params_memory.put_int(CC_STATUS_PARAM, restored_status)
return restored_status
return current_status
+8
View File
@@ -104,6 +104,7 @@ SAFE_MODE_MANAGED_KEYS = (
"ReduceLateralAccelerationRainStorm",
"ReduceLateralAccelerationSnow",
"ConditionalExperimental",
"ConditionalChill",
"CECurves",
"CECurvesLead",
"CELead",
@@ -111,10 +112,16 @@ SAFE_MODE_MANAGED_KEYS = (
"CEStoppedLead",
"CESpeed",
"CESpeedLead",
"CCMLead",
"CCMSetSpeedMargin",
"CCMSpeed",
"CCMSpeedLead",
"CEModelStopTime",
"CEStopLights",
"CESignalSpeed",
"CESignalLaneDetection",
"PersistChillState",
"ShowCCMStatus",
"CurveSpeedController",
"SpeedLimitController",
"SetSpeedLimit",
@@ -199,6 +206,7 @@ SAFE_MODE_STOCK_PARAM_MAP = {
}
SAFE_MODE_MEMORY_VALUES = {
"CCStatus": 0,
"CEStatus": 0,
}
+11 -1
View File
@@ -229,6 +229,7 @@ EXCLUDED_KEYS = {
"openpilotMinutes",
"OverpassRequests",
"PandaSignatures",
"PersistedCCStatus",
"PersistedCEStatus",
"SpeedLimits",
"SpeedLimitsFiltered",
@@ -707,6 +708,7 @@ class StarPilotVariables:
toggle.cluster_offset = self.get_value("ClusterOffset", cast=float, condition=toggle.car_make == "toyota")
toggle.conditional_experimental_mode = toggle.openpilot_longitudinal and self.get_value("ConditionalExperimental")
toggle.conditional_chill_mode = toggle.openpilot_longitudinal and not toggle.conditional_experimental_mode and self.get_value("ConditionalChill")
toggle.conditional_curves = self.get_value("CECurves", condition=toggle.conditional_experimental_mode)
toggle.conditional_curves_lead = self.get_value("CECurvesLead", condition=toggle.conditional_curves)
toggle.conditional_lead = self.get_value("CELead", condition=toggle.conditional_experimental_mode)
@@ -717,7 +719,15 @@ class StarPilotVariables:
toggle.conditional_model_stop_time = self.get_value("CEModelStopTime", cast=float, condition=toggle.conditional_experimental_mode and self.get_value("CEStopLights"))
toggle.conditional_signal = self.get_value("CESignalSpeed", cast=float, condition=toggle.conditional_experimental_mode, conversion=speed_conversion)
toggle.conditional_signal_lane_detection = self.get_value("CESignalLaneDetection", condition=toggle.conditional_signal != 0)
toggle.cem_status = self.get_value("ShowCEMStatus", condition=toggle.conditional_experimental_mode) or toggle.debug_mode
toggle.conditional_chill_speed = self.get_value("CCMSpeed", cast=float, condition=toggle.conditional_chill_mode, conversion=speed_conversion)
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.cem_status = (
self.get_value("ShowCEMStatus", condition=toggle.conditional_experimental_mode) or
self.get_value("ShowCCMStatus", condition=toggle.conditional_chill_mode) or
toggle.debug_mode
)
toggle.curve_speed_controller = toggle.openpilot_longitudinal and self.get_value("CurveSpeedController")
toggle.csc_status = self.get_value("ShowCSCStatus", condition=toggle.curve_speed_controller) or toggle.debug_mode
@@ -0,0 +1,79 @@
from openpilot.starpilot.common.experimental_state import (
CC_STATUS_PARAM,
CCStatus,
CE_STATUS_PARAM,
CEStatus,
requested_experimental_mode,
restore_persisted_cc_state,
)
class FakeParams:
def __init__(self, bools=None, ints=None):
self.bools = dict(bools or {})
self.ints = dict(ints or {})
def get_bool(self, key):
return bool(self.bools.get(key, False))
def put_bool(self, key, value):
self.bools[key] = bool(value)
def get_int(self, key, default=0):
return int(self.ints.get(key, default))
def put_int(self, key, value):
self.ints[key] = int(value)
def test_requested_experimental_mode_defaults_to_experimental_in_ccm_auto():
params = FakeParams(bools={"ConditionalChill": True})
params_memory = FakeParams(ints={CC_STATUS_PARAM: CCStatus["OFF"]})
assert requested_experimental_mode(params, params_memory) is True
def test_requested_experimental_mode_respects_ccm_manual_override():
params = FakeParams(bools={"ConditionalChill": True})
params_memory = FakeParams(ints={CC_STATUS_PARAM: CCStatus["USER_CHILL"]})
assert requested_experimental_mode(params, params_memory) is False
params_memory = FakeParams(ints={CC_STATUS_PARAM: CCStatus["USER_EXPERIMENTAL"]})
assert requested_experimental_mode(params, params_memory) is True
def test_requested_experimental_mode_prefers_cem_if_both_conditional_modes_are_enabled():
params = FakeParams(bools={"ConditionalExperimental": True, "ConditionalChill": True})
params_memory = FakeParams(ints={
CE_STATUS_PARAM: CEStatus["OFF"],
CC_STATUS_PARAM: CCStatus["USER_EXPERIMENTAL"],
})
assert requested_experimental_mode(params, params_memory) is False
params_memory = FakeParams(ints={
CE_STATUS_PARAM: CEStatus["USER_OVERRIDDEN"],
CC_STATUS_PARAM: CCStatus["USER_CHILL"],
})
assert requested_experimental_mode(params, params_memory) is True
def test_requested_experimental_mode_safe_mode_overrides_ccm():
params = FakeParams(bools={"SafeMode": True, "ConditionalChill": True})
params_memory = FakeParams(ints={CC_STATUS_PARAM: CCStatus["USER_EXPERIMENTAL"]})
assert requested_experimental_mode(params, params_memory) is False
def test_restore_persisted_cc_state_rehydrates_manual_override():
params = FakeParams(
bools={"PersistChillState": True},
ints={"PersistedCCStatus": CCStatus["USER_CHILL"]},
)
params_memory = FakeParams(ints={CC_STATUS_PARAM: CCStatus["OFF"]})
restored_status = restore_persisted_cc_state(params, params_memory)
assert restored_status == CCStatus["USER_CHILL"]
assert params_memory.get_int(CC_STATUS_PARAM) == CCStatus["USER_CHILL"]
@@ -0,0 +1,214 @@
#!/usr/bin/env python3
import time
from openpilot.common.constants import CV
from openpilot.starpilot.common.experimental_state import (
CCStatus,
is_manual_cc_status,
restore_persisted_cc_state,
)
class ConditionalChillMode:
CCM_STOP_MODEL_TIME = 7.0
CHILL_ENTRY_CONFIRM_TIME = 0.35
CHILL_EXIT_BUFFER_TIME = 0.35
CHILL_MIN_DWELL_TIME = 1.2
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
ADJACENT_LEAD_VETO_MIN_SPEED = 1.0
ADJACENT_LEAD_VETO_MAX_DISTANCE = 65.0
ADJACENT_LEAD_VETO_MAX_DISTANCE_TIME = 3.5
LOW_SPEED_STOP_SCENE_MAX_SPEED = 18 * CV.MPH_TO_MS
def __init__(self, StarPilotPlanner, detector):
self.starpilot_planner = StarPilotPlanner
self.detector = detector
self.params = self.starpilot_planner.params
self.params_memory = self.starpilot_planner.params_memory
self.experimental_mode = True
self.status_value = CCStatus["OFF"]
self._active_auto_status = CCStatus["OFF"]
self._candidate_since = 0.0
self._soft_exit_since = 0.0
self._chill_hold_until = 0.0
self._prev_cc_status = None
def update(self, v_ego, v_cruise, sm, starpilot_toggles):
now = time.monotonic()
safe_mode = self.params.get_bool("SafeMode")
self.status_value = CCStatus["OFF"] if safe_mode else restore_persisted_cc_state(self.params, self.params_memory)
if is_manual_cc_status(self.status_value):
self._reset_timers()
self.experimental_mode = self.status_value == CCStatus["USER_EXPERIMENTAL"]
self._write_status(self.status_value)
return
self._refresh_detector(v_ego, sm)
if safe_mode or self._has_hard_veto(v_ego, sm):
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"]
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:
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)
self.status_value = self._active_auto_status if not self.experimental_mode else CCStatus["OFF"]
else:
self._candidate_since = 0.0
if not self.experimental_mode:
if self._soft_exit_since == 0.0:
self._soft_exit_since = now
hold_active = now < self._chill_hold_until
exit_buffer_active = (now - self._soft_exit_since) < self.CHILL_EXIT_BUFFER_TIME
if hold_active or exit_buffer_active:
self.status_value = self._active_auto_status
else:
self.experimental_mode = True
self._active_auto_status = CCStatus["OFF"]
self.status_value = CCStatus["OFF"]
else:
self._soft_exit_since = 0.0
self.status_value = CCStatus["OFF"]
self._write_status(self.status_value if not self.experimental_mode else CCStatus["OFF"])
def _reset_timers(self):
self._active_auto_status = CCStatus["OFF"]
self._candidate_since = 0.0
self._soft_exit_since = 0.0
self._chill_hold_until = 0.0
def _refresh_detector(self, v_ego, sm):
detector_toggles = type("DetectorToggles", (), {
"conditional_curves": True,
"conditional_curves_lead": True,
"conditional_lead": True,
"conditional_slower_lead": True,
"conditional_stopped_lead": True,
})()
self.detector.curve_detection(v_ego, detector_toggles)
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:
return True
if sm["carState"].leftBlinker or sm["carState"].rightBlinker:
return True
if sm["starpilotCarState"].trafficModeEnabled:
return True
if self.starpilot_planner.starpilot_vcruise.slc.experimental_mode:
return True
if self.detector.curve_detected or self.detector.slow_lead_detected or self.detector.stop_light_detected:
return True
if self.starpilot_planner.starpilot_vcruise.stop_sign_confirmed or self.starpilot_planner.starpilot_vcruise.forcing_stop:
return True
if self._adjacent_lead_ambiguous(sm, v_ego):
return True
return self._low_speed_stop_scene(v_ego)
def _low_speed_stop_scene(self, v_ego):
if v_ego >= self.LOW_SPEED_STOP_SCENE_MAX_SPEED:
return False
if self.starpilot_planner.raw_model_stopped or self.starpilot_planner.model_stopped or self.detector.stop_light_model_detected:
return True
lead = self.starpilot_planner.lead_one
if not getattr(lead, "status", False):
return False
lead_distance = float(getattr(lead, "dRel", float("inf")))
lead_speed = float(getattr(lead, "vLead", float("inf")))
lead_distance_limit = max(40.0, v_ego * self.STABLE_LEAD_MAX_DISTANCE_TIME)
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):
lead = self.starpilot_planner.lead_one
lead_status = bool(getattr(lead, "status", False))
tracking_lead = bool(getattr(self.starpilot_planner, "tracking_lead", False))
set_speed_error = max(0.0, v_cruise - v_ego)
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"]
if not starpilot_toggles.conditional_chill_lead:
return CCStatus["OFF"]
if v_ego < starpilot_toggles.conditional_chill_speed_lead or not lead_status or not tracking_lead:
return CCStatus["OFF"]
lead_distance = float(getattr(lead, "dRel", float("inf")))
lead_speed = float(getattr(lead, "vLead", 0.0))
lead_brake = max(0.0, -float(getattr(lead, "aLeadK", 0.0)))
lead_prob = float(getattr(lead, "modelProb", 0.0))
closing_speed = max(0.0, v_ego - lead_speed)
max_closing_speed = max(self.STABLE_LEAD_MAX_CLOSING_SPEED, self.STABLE_LEAD_MAX_CLOSING_RATIO * v_ego)
max_distance = min(self.STABLE_LEAD_MAX_DISTANCE, max(35.0, v_ego * self.STABLE_LEAD_MAX_DISTANCE_TIME))
lead_confident = bool(getattr(lead, "radar", False)) or lead_prob >= self.STABLE_LEAD_MIN_MODEL_PROB
if not lead_confident:
return CCStatus["OFF"]
if lead_distance >= max_distance or lead_speed <= self.STABLE_LEAD_MIN_SPEED:
return CCStatus["OFF"]
if lead_brake > self.STABLE_LEAD_MAX_BRAKE or closing_speed > max_closing_speed:
return CCStatus["OFF"]
return CCStatus["LEAD"]
def _adjacent_lead_ambiguous(self, sm, v_ego):
radar_state = sm.get("starpilotRadarState")
if radar_state is None:
return False
max_distance = min(self.ADJACENT_LEAD_VETO_MAX_DISTANCE, max(25.0, v_ego * self.ADJACENT_LEAD_VETO_MAX_DISTANCE_TIME))
for lead in (getattr(radar_state, "leadLeft", None), getattr(radar_state, "leadRight", None)):
if lead is None or not getattr(lead, "status", False):
continue
if float(getattr(lead, "dRel", float("inf"))) < max_distance and float(getattr(lead, "vLead", 0.0)) > self.ADJACENT_LEAD_VETO_MIN_SPEED:
return True
return False
def _write_status(self, status_value):
if status_value != self._prev_cc_status:
self.params_memory.put_int("CCStatus", status_value)
self._prev_cc_status = status_value
+8
View File
@@ -6,8 +6,11 @@ from openpilot.selfdrive.car.cruise import CRUISE_LONG_PRESS, ButtonType
from openpilot.selfdrive.selfdrived.events import ET
from openpilot.starpilot.common.experimental_state import (
CCStatus,
CEStatus,
next_manual_cc_status,
next_manual_ce_status,
sync_manual_cc_state,
sync_manual_ce_state,
)
from openpilot.starpilot.common.starpilot_utilities import is_FrogsGoMoo
@@ -80,6 +83,11 @@ class StarPilotCard:
override_value = next_manual_ce_status(current_status, sm["selfdriveState"].experimentalMode)
self.params_memory.put_int("CEStatus", override_value)
sync_manual_ce_state(self.params, override_value)
elif getattr(starpilot_toggles, "conditional_chill_mode", False):
current_status = self.params_memory.get_int("CCStatus", default=CCStatus["OFF"])
override_value = next_manual_cc_status(current_status, sm["selfdriveState"].experimentalMode)
self.params_memory.put_int("CCStatus", override_value)
sync_manual_cc_state(self.params, override_value)
else:
self.params.put_bool_nonblocking("ExperimentalMode", not sm["selfdriveState"].experimentalMode)
+17 -3
View File
@@ -16,6 +16,7 @@ from openpilot.selfdrive.controls.lib.longitudinal_mpc_lib.long_mpc import A_CHA
from openpilot.starpilot.common.starpilot_utilities import calculate_lane_width, calculate_road_curvature
from openpilot.starpilot.common.starpilot_variables import CRUISING_SPEED, MINIMUM_LATERAL_ACCELERATION, PLANNER_TIME, THRESHOLD
from openpilot.starpilot.controls.lib.conditional_chill_mode import ConditionalChillMode
from openpilot.starpilot.controls.lib.conditional_experimental_mode import ConditionalExperimentalMode
from openpilot.starpilot.controls.lib.starpilot_acceleration import StarPilotAcceleration
from openpilot.starpilot.controls.lib.starpilot_events import StarPilotEvents
@@ -47,6 +48,7 @@ class StarPilotPlanner:
self.starpilot_acceleration = StarPilotAcceleration(self)
self.starpilot_cem = ConditionalExperimentalMode(self)
self.starpilot_ccm = ConditionalChillMode(self, self.starpilot_cem)
self.starpilot_events = StarPilotEvents(self, error_log, ThemeManager)
self.starpilot_following = StarPilotFollowing(self)
self.starpilot_vcruise = StarPilotVCruise(self)
@@ -194,11 +196,17 @@ class StarPilotPlanner:
self.starpilot_following.update(controls_enabled, v_ego, sm, starpilot_toggles)
cem_tracking_active = controls_enabled or sm["starpilotCarState"].alwaysOnLateralEnabled
if cem_tracking_active and starpilot_toggles.conditional_experimental_mode:
conditional_tracking_active = controls_enabled or sm["starpilotCarState"].alwaysOnLateralEnabled
if conditional_tracking_active and starpilot_toggles.conditional_experimental_mode:
# Keep CEM's filters warm in AOL so engagement can inherit the current scene.
self.starpilot_cem.update(v_ego, sm, starpilot_toggles)
self.starpilot_ccm.experimental_mode = True
elif conditional_tracking_active and starpilot_toggles.conditional_chill_mode:
self.starpilot_ccm.update(v_ego, v_cruise, sm, starpilot_toggles)
self.starpilot_cem.experimental_mode = False
else:
self.starpilot_ccm.experimental_mode = True
self.starpilot_cem.experimental_mode = False
self.starpilot_cem.curve_detected = False
self.starpilot_cem.stop_sign_and_light(v_ego, sm, PLANNER_TIME - 2)
@@ -263,7 +271,13 @@ class StarPilotPlanner:
starpilotPlan.disableThrottle = self.starpilot_following.disable_throttle
starpilotPlan.trackingLead = self.tracking_lead
starpilotPlan.experimentalMode = self.starpilot_cem.experimental_mode or self.starpilot_vcruise.slc.experimental_mode
conditional_experimental_mode = False
if starpilot_toggles.conditional_experimental_mode:
conditional_experimental_mode = self.starpilot_cem.experimental_mode
elif starpilot_toggles.conditional_chill_mode:
conditional_experimental_mode = self.starpilot_ccm.experimental_mode
starpilotPlan.experimentalMode = conditional_experimental_mode or self.starpilot_vcruise.slc.experimental_mode
starpilotPlan.forcingStop = self.starpilot_vcruise.forcing_stop
starpilotPlan.forcingStopLength = self.starpilot_vcruise.tracked_model_length
@@ -235,6 +235,23 @@ def test_pacifica_hybrid_main_aol_waits_for_set_press(monkeypatch, tmp_path):
assert ret.alwaysOnLateralEnabled is False
def test_conditional_chill_wheel_override_cycles_manual_state(monkeypatch, tmp_path):
monkeypatch.setattr(spc, "Params", FakeParams)
monkeypatch.setattr(spc, "is_FrogsGoMoo", lambda: False)
monkeypatch.setattr(spc, "ERROR_LOGS_PATH", tmp_path)
card = spc.StarPilotCard(SimpleNamespace(brand="gm"), SimpleNamespace(alternativeExperience=0))
sm = make_sm()
toggles = make_toggles(conditional_chill_mode=True)
sm["selfdriveState"].experimentalMode = True
card.handle_experimental_mode(sm, toggles)
assert card.params_memory.get_int("CCStatus") == spc.CCStatus["USER_CHILL"]
card.handle_experimental_mode(sm, toggles)
assert card.params_memory.get_int("CCStatus") == spc.CCStatus["OFF"]
def test_cancel_button_short_press_can_run_independent_mapping(monkeypatch, tmp_path):
monkeypatch.setattr(spc, "Params", FakeParams)
monkeypatch.setattr(spc, "is_FrogsGoMoo", lambda: False)
+1 -1
View File
@@ -199,7 +199,7 @@ def starpilot_thread():
sm = messaging.SubMaster(["carControl", "carState", "controlsState", "deviceState", "driverMonitoringState",
"gpsLocation", "gpsLocationExternal", "liveParameters", "managerState", "modelV2",
"onroadEvents", "pandaStates", "radarState", "selfdriveState", "starpilotCarState",
"starpilotSelfdriveState", "starpilotModelV2", "starpilotOnroadEvents", "mapdOut"],
"starpilotRadarState", "starpilotSelfdriveState", "starpilotModelV2", "starpilotOnroadEvents", "mapdOut"],
poll="modelV2")
params = Params(return_defaults=True)
File diff suppressed because it is too large Load Diff
+29 -1
View File
@@ -65,7 +65,7 @@ from openpilot.starpilot.common.model_versions import (
uses_combined_driving_artifacts,
uses_split_off_policy_artifacts,
)
from openpilot.starpilot.common.experimental_state import sync_persist_experimental_state
from openpilot.starpilot.common.experimental_state import sync_persist_chill_state, sync_persist_experimental_state
from openpilot.starpilot.common.starpilot_utilities import delete_file, get_lock_status, run_cmd
from openpilot.starpilot.common.starpilot_variables import ACTIVE_THEME_PATH, ERROR_LOGS_PATH, EXCLUDED_KEYS, LEGACY_STARPILOT_PARAM_RENAMES, MAPS_PATH, MODELS_PATH, RESOURCES_REPO, SCREEN_RECORDINGS_PATH, STOCK_THEME_PATH, THEME_SAVE_PATH,\
default_ev_tuning_enabled, migrate_cancel_button_controls, update_starpilot_toggles
@@ -3794,6 +3794,22 @@ def setup(app):
"updated": updated,
}), 200
if key in {"ConditionalExperimental", "ConditionalChill"}:
enabled = str_val.strip() in ("1", "true", "True")
params.put_bool(key, enabled)
updated = {key: enabled}
if enabled:
other_key = "ConditionalChill" if key == "ConditionalExperimental" else "ConditionalExperimental"
params.put_bool(other_key, False)
updated[other_key] = False
update_starpilot_toggles()
return jsonify({
"message": f"Parameter '{key}' updated successfully.",
"updated": updated,
}), 200
if key == "CustomAccelProfile":
enabled = str_val.strip() in ("1", "true", "True")
params.put_bool(key, enabled)
@@ -3825,6 +3841,18 @@ def setup(app):
},
}), 200
if key == "PersistChillState":
enabled = str_val.strip() in ("1", "true", "True")
sync_persist_chill_state(params, params_memory, enabled)
update_starpilot_toggles()
return jsonify({
"message": f"Parameter '{key}' updated successfully.",
"updated": {
"PersistChillState": enabled,
"PersistedCCStatus": params.get_int("PersistedCCStatus", default=0),
},
}), 200
if key == "IsRHD":
enabled = str_val.strip() in ("1", "true", "True")
params.put_bool("IsRHD", enabled)
@@ -16,6 +16,7 @@ StarPilotLongitudinalPanel::StarPilotLongitudinalPanel(StarPilotSettingsWindow *
StarPilotListWidget *advancedLongitudinalTuneList = new StarPilotListWidget(this);
StarPilotListWidget *aggressivePersonalityList = new StarPilotListWidget(this);
StarPilotListWidget *conditionalChillList = new StarPilotListWidget(this);
StarPilotListWidget *conditionalExperimentalList = new StarPilotListWidget(this);
StarPilotListWidget *curveSpeedList = new StarPilotListWidget(this);
StarPilotListWidget *customDrivingPersonalityList = new StarPilotListWidget(this);
@@ -36,6 +37,7 @@ StarPilotLongitudinalPanel::StarPilotLongitudinalPanel(StarPilotSettingsWindow *
ScrollView *advancedLongitudinalTunePanel = new ScrollView(advancedLongitudinalTuneList, this);
ScrollView *aggressivePersonalityPanel = new ScrollView(aggressivePersonalityList, this);
ScrollView *conditionalChillPanel = new ScrollView(conditionalChillList, this);
ScrollView *conditionalExperimentalPanel = new ScrollView(conditionalExperimentalList, this);
ScrollView *curveSpeedPanel = new ScrollView(curveSpeedList, this);
ScrollView *customDrivingPersonalityPanel = new ScrollView(customDrivingPersonalityList, this);
@@ -56,6 +58,7 @@ StarPilotLongitudinalPanel::StarPilotLongitudinalPanel(StarPilotSettingsWindow *
longitudinalLayout->addWidget(advancedLongitudinalTunePanel);
longitudinalLayout->addWidget(aggressivePersonalityPanel);
longitudinalLayout->addWidget(conditionalChillPanel);
longitudinalLayout->addWidget(conditionalExperimentalPanel);
longitudinalLayout->addWidget(curveSpeedPanel);
longitudinalLayout->addWidget(customDrivingPersonalityPanel);
@@ -95,6 +98,12 @@ StarPilotLongitudinalPanel::StarPilotLongitudinalPanel(StarPilotSettingsWindow *
{"CEModelStopTime", tr("Predicted Stop In"), tr("<b>Switch to \"Experimental Mode\" when openpilot predicts a stop within the set time.</b> This is usually triggered when the model \"sees\" a red light or stop sign ahead.<br><br><i><b>Disclaimer</b>: openpilot does not explicitly detect traffic lights or stop signs. In \"Experimental Mode\", openpilot makes end-to-end driving decisions from camera input, which means it may stop even when there's no clear reason!</i>"), ""},
{"CESignalSpeed", tr("Turn Signal Below"), tr("<b>Switch to \"Experimental Mode\" when using a turn signal below the set speed</b> to allow the model to choose an appropriate speed for smoother left and right turns."), ""},
{"ShowCEMStatus", tr("Status Widget"), tr("<b>Show which condition triggered \"Experimental Mode\"</b> on the driving screen."), ""},
{"ConditionalChill", tr("Conditional Chill Mode"), tr("<b>Keep \"Experimental Mode\" on by default, but temporarily switch to \"Chill Mode\" in simple cruising scenes where speed holding is usually better.</b>"), "../../starpilot/assets/toggle_icons/icon_conditional.png"},
{"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>"), ""},
{"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."), ""},
{"CurveSpeedController", tr("Curve Speed Controller"), tr("<b>Automatically slow down for upcoming curves</b> using data learned from your driving style, adapting to curves as you would."), "../../starpilot/assets/toggle_icons/icon_speed_map.png"},
{"CalibratedLateralAcceleration", tr("Calibrated Lateral Acceleration"), tr("<b>The learned lateral acceleration from collected driving data.</b> This sets how fast openpilot will take curves. Higher values allow faster cornering; lower values slow the vehicle for gentler turns."), ""},
@@ -253,11 +262,22 @@ StarPilotLongitudinalPanel::StarPilotLongitudinalPanel(StarPilotSettingsWindow *
longitudinalLayout->setCurrentWidget(conditionalExperimentalPanel);
});
longitudinalToggle = conditionalExperimentalToggle;
} else if (param == "ConditionalChill") {
StarPilotManageControl *conditionalChillToggle = new StarPilotManageControl(param, title, desc, icon);
QObject::connect(conditionalChillToggle, &StarPilotManageControl::manageButtonClicked, [longitudinalLayout, conditionalChillPanel]() {
longitudinalLayout->setCurrentWidget(conditionalChillPanel);
});
longitudinalToggle = conditionalChillToggle;
} else if (param == "CESpeed") {
StarPilotParamValueControl *CESpeed = new StarPilotParamValueControl(param, title, desc, icon, 0, 99, tr(" mph"), std::map<float, QString>(), 1, true, 175);
StarPilotParamValueControl *CESpeedLead = new StarPilotParamValueControl("CESpeedLead", tr("With Lead"), tr("<b>Switch to \"Experimental Mode\" when driving below this speed with a lead</b> to help openpilot handle low-speed situations more smoothly."), icon, 0, 99, tr(" mph"), std::map<float, QString>(), 1, true, 175);
StarPilotDualParamValueControl *conditionalSpeeds = new StarPilotDualParamValueControl(CESpeed, CESpeedLead);
longitudinalToggle = reinterpret_cast<AbstractControl*>(conditionalSpeeds);
} else if (param == "CCMSpeed") {
StarPilotParamValueControl *CCMSpeed = new StarPilotParamValueControl(param, title, desc, icon, 0, 99, tr(" mph"), std::map<float, QString>(), 1, true, 175);
StarPilotParamValueControl *CCMSpeedLead = new StarPilotParamValueControl("CCMSpeedLead", tr("With Lead"), tr("<b>Switch to \"Chill Mode\" when a stable lead is being followed above this speed.</b>"), icon, 0, 99, tr(" mph"), std::map<float, QString>(), 1, true, 175);
StarPilotDualParamValueControl *conditionalSpeeds = new StarPilotDualParamValueControl(CCMSpeed, CCMSpeedLead);
longitudinalToggle = reinterpret_cast<AbstractControl*>(conditionalSpeeds);
} else if (param == "CECurves") {
std::vector<QString> curveToggles{"CECurvesLead"};
std::vector<QString> curveToggleNames{tr("With Lead")};
@@ -266,6 +286,8 @@ StarPilotLongitudinalPanel::StarPilotLongitudinalPanel(StarPilotSettingsWindow *
std::vector<QString> leadToggles{"CESlowerLead", "CEStoppedLead"};
std::vector<QString> leadToggleNames{tr("Slower Lead"), tr("Stopped Lead")};
longitudinalToggle = new StarPilotButtonToggleControl(param, title, desc, icon, leadToggles, leadToggleNames);
} else if (param == "CCMSetSpeedMargin") {
longitudinalToggle = new StarPilotParamValueControl(param, title, desc, icon, 0, 15, tr(" mph"), std::map<float, QString>(), 1, true, 175);
} else if (param == "CEModelStopTime") {
std::map<float, QString> stopTimeLabels;
for (int i = 0; i <= 10; ++i) {
@@ -586,6 +608,8 @@ StarPilotLongitudinalPanel::StarPilotLongitudinalPanel(StarPilotSettingsWindow *
advancedLongitudinalTuneList->addItem(longitudinalToggle);
} else if (aggressivePersonalityKeys.contains(param)) {
aggressivePersonalityList->addItem(longitudinalToggle);
} else if (conditionalChillKeys.contains(param)) {
conditionalChillList->addItem(longitudinalToggle);
} else if (conditionalExperimentalKeys.contains(param)) {
conditionalExperimentalList->addItem(longitudinalToggle);
} else if (curveSpeedKeys.contains(param)) {
@@ -658,6 +682,20 @@ StarPilotLongitudinalPanel::StarPilotLongitudinalPanel(StarPilotSettingsWindow *
}
updateToggles();
});
QObject::connect(static_cast<ToggleControl*>(toggles["ConditionalExperimental"]), &ToggleControl::toggleFlipped, this, [this]() {
if (params.getBool("ConditionalExperimental")) {
params.putBool("ConditionalChill", false);
static_cast<ParamControl*>(toggles["ConditionalChill"])->refresh();
}
updateToggles();
});
QObject::connect(static_cast<ToggleControl*>(toggles["ConditionalChill"]), &ToggleControl::toggleFlipped, this, [this]() {
if (params.getBool("ConditionalChill")) {
params.putBool("ConditionalExperimental", false);
static_cast<ParamControl*>(toggles["ConditionalExperimental"])->refresh();
}
updateToggles();
});
StarPilotParamValueControl *trafficFollowToggle = static_cast<StarPilotParamValueControl*>(toggles["TrafficFollow"]);
StarPilotParamValueControl *trafficAccelerationToggle = static_cast<StarPilotParamValueControl*>(toggles["TrafficJerkAcceleration"]);
@@ -831,6 +869,9 @@ void StarPilotLongitudinalPanel::updateMetric(bool metric, bool bootRun) {
params.putIntNonBlocking("IncreasedStoppedDistanceRainStorm", params.getInt("IncreasedStoppedDistanceRainStorm") * distanceConversion);
params.putIntNonBlocking("IncreasedStoppedDistanceSnow", params.getInt("IncreasedStoppedDistanceSnow") * distanceConversion);
params.putIntNonBlocking("CCMSpeed", params.getInt("CCMSpeed") * speedConversion);
params.putIntNonBlocking("CCMSpeedLead", params.getInt("CCMSpeedLead") * speedConversion);
params.putIntNonBlocking("CCMSetSpeedMargin", params.getInt("CCMSetSpeedMargin") * speedConversion);
params.putIntNonBlocking("CESignalSpeed", params.getInt("CESignalSpeed") * speedConversion);
params.putIntNonBlocking("CESpeed", params.getInt("CESpeed") * speedConversion);
params.putIntNonBlocking("CESpeedLead", params.getInt("CESpeedLead") * speedConversion);
@@ -881,7 +922,9 @@ void StarPilotLongitudinalPanel::updateMetric(bool metric, bool bootRun) {
labelsInitialized = true;
}
StarPilotDualParamValueControl *ccmSpeedToggle = reinterpret_cast<StarPilotDualParamValueControl*>(toggles["CCMSpeed"]);
StarPilotDualParamValueControl *ceSpeedToggle = reinterpret_cast<StarPilotDualParamValueControl*>(toggles["CESpeed"]);
StarPilotParamValueControl *ccmSetSpeedMarginToggle = static_cast<StarPilotParamValueControl*>(toggles["CCMSetSpeedMargin"]);
StarPilotParamValueButtonControl *ceSignal = static_cast<StarPilotParamValueButtonControl*>(toggles["CESignalSpeed"]);
StarPilotParamValueControl *customCruiseToggle = static_cast<StarPilotParamValueControl*>(toggles["CustomCruise"]);
StarPilotParamValueControl *customCruiseLongToggle = static_cast<StarPilotParamValueControl*>(toggles["CustomCruiseLong"]);
@@ -922,6 +965,8 @@ void StarPilotLongitudinalPanel::updateMetric(bool metric, bool bootRun) {
increasedStoppedDistanceRainStormToggle->updateControl(0, 3, metricDistanceLabels);
increasedStoppedDistanceSnowToggle->updateControl(0, 3, metricDistanceLabels);
ccmSpeedToggle->updateControl(0, 150, metricSpeedLabels);
ccmSetSpeedMarginToggle->updateControl(0, 25, metricSpeedLabels);
ceSignal->updateControl(0, 150, metricSpeedLabels);
ceSpeedToggle->updateControl(0, 150, metricSpeedLabels);
customCruiseToggle->updateControl(1, 150, metricSpeedLabels);
@@ -957,6 +1002,8 @@ void StarPilotLongitudinalPanel::updateMetric(bool metric, bool bootRun) {
increasedStoppedDistanceRainStormToggle->updateControl(0, 10, imperialDistanceLabels);
increasedStoppedDistanceSnowToggle->updateControl(0, 10, imperialDistanceLabels);
ccmSpeedToggle->updateControl(0, 99, imperialSpeedLabels);
ccmSetSpeedMarginToggle->updateControl(0, 15, imperialSpeedLabels);
ceSignal->updateControl(0, 99, imperialSpeedLabels);
ceSpeedToggle->updateControl(0, 99, imperialSpeedLabels);
customCruiseToggle->updateControl(1, 99, imperialSpeedLabels);
@@ -1041,6 +1088,8 @@ void StarPilotLongitudinalPanel::updateToggles() {
toggles["AdvancedLongitudinalTune"]->setVisible(true);
} else if (aggressivePersonalityKeys.contains(key)) {
toggles["AggressivePersonalityProfile"]->setVisible(true);
} else if (conditionalChillKeys.contains(key)) {
toggles["ConditionalChill"]->setVisible(true);
} else if (conditionalExperimentalKeys.contains(key)) {
toggles["ConditionalExperimental"]->setVisible(true);
} else if (curveSpeedKeys.contains(key)) {
@@ -30,6 +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> conditionalExperimentalKeys = {"PersistExperimentalState", "CESpeed", "CESpeedLead", "CECurves", "CELead", "CEModelStopTime", "CESignalSpeed", "CEStopLights", "ShowCEMStatus"};
QSet<QString> curveSpeedKeys = {"CalibratedLateralAcceleration", "CalibrationProgress", "ResetCurveData", "ShowCSCStatus"};
QSet<QString> customDrivingPersonalityKeys = {"AggressivePersonalityProfile", "RelaxedPersonalityProfile", "StandardPersonalityProfile", "TrafficPersonalityProfile"};
@@ -468,9 +468,14 @@ void StarPilotAnnotatedCameraWidget::paintCEMStatus(QPainter &p) {
cemStatusPosition.setY(dmIconPosition.y() - widget_size / 2);
QRect cemWidget(cemStatusPosition, QSize(widget_size, widget_size));
const bool conditionalExperimentalMode = starpilot_toggles.value("conditional_experimental_mode").toBool();
const bool conditionalChillMode = starpilot_toggles.value("conditional_chill_mode").toBool();
const bool manualOverride =
(conditionalExperimentalMode && starpilot_scene.conditional_status == 1) ||
(conditionalChillMode && (starpilot_scene.conditional_status == 1 || starpilot_scene.conditional_status == 2));
p.setBrush(blackColor(166));
if (starpilot_scene.conditional_status == 1) {
if (manualOverride) {
p.setPen(QPen(QColor(bg_colors[STATUS_CEM_DISABLED]), 10));
} else if (experimentalMode) {
p.setPen(QPen(QColor(bg_colors[STATUS_EXPERIMENTAL_MODE_ENABLED]), 10));
@@ -480,7 +485,19 @@ void StarPilotAnnotatedCameraWidget::paintCEMStatus(QPainter &p) {
p.drawRoundedRect(cemWidget, 24, 24);
QSharedPointer<QMovie> icon = chillModeIcon;
if (experimentalMode) {
if (conditionalChillMode && !conditionalExperimentalMode) {
if (starpilot_scene.conditional_status == 1) {
icon = experimentalModeIcon;
} else if (starpilot_scene.conditional_status == 2) {
icon = chillModeIcon;
} else if (starpilot_scene.conditional_status == 4) {
icon = cemLeadIcon;
} else if (starpilot_scene.conditional_status == 6) {
icon = cemSpeedIcon;
} else {
icon = experimentalMode ? experimentalModeIcon : chillModeIcon;
}
} else if (experimentalMode) {
if (starpilot_scene.conditional_status == 1) {
icon = chillModeIcon;
} else if (starpilot_scene.conditional_status == 2) {
@@ -786,12 +803,17 @@ void StarPilotAnnotatedCameraWidget::paintPathEdges(QPainter &p, int height) {
gradient.setColorAt(0.5f, QColor(baseColor.red(), baseColor.green(), baseColor.blue(), 255.0f * 0.35f));
gradient.setColorAt(1.0f, QColor(baseColor.red(), baseColor.green(), baseColor.blue(), 255.0f * 0.0f));
};
const bool conditionalExperimentalMode = starpilot_toggles.value("conditional_experimental_mode").toBool();
const bool conditionalChillMode = starpilot_toggles.value("conditional_chill_mode").toBool();
const bool highlightOverride =
(conditionalExperimentalMode && starpilot_scene.conditional_status == 1) ||
(conditionalChillMode && (starpilot_scene.conditional_status == 1 || starpilot_scene.conditional_status == 2));
if (starpilot_scene.switchback_mode_enabled) {
setPathEdgeColors(bg_colors[STATUS_SWITCHBACK_MODE_ENABLED]);
} else if (starpilot_scene.always_on_lateral_active) {
setPathEdgeColors(bg_colors[STATUS_ALWAYS_ON_LATERAL_ACTIVE]);
} else if (starpilot_scene.conditional_status == 1) {
} else if (highlightOverride) {
setPathEdgeColors(bg_colors[STATUS_CEM_DISABLED]);
} else if (experimentalMode) {
setPathEdgeColors(bg_colors[STATUS_EXPERIMENTAL_MODE_ENABLED]);
@@ -128,7 +128,7 @@ void loadImage(const QString &basePath, QPixmap &pixmap, QSharedPointer<QMovie>
void openDescriptions(bool forceOpenDescriptions, std::map<QString, AbstractControl*> toggles) {
if (forceOpenDescriptions) {
for (auto &[key, toggle] : toggles) {
if (key != "CESpeed") {
if (key != "CESpeed" && key != "CCMSpeed") {
toggle->showDescription();
}
}
+6 -1
View File
@@ -114,6 +114,11 @@ StarPilotUIState *starpilotUIState() {
void StarPilotUIState::update() {
update_state(this);
starpilot_scene.conditional_status = starpilot_scene.enabled ? params_memory.getInt("CEStatus") : 0;
if (starpilot_scene.enabled && starpilot_scene.starpilot_toggles.value("conditional_chill_mode").toBool() &&
!starpilot_scene.starpilot_toggles.value("conditional_experimental_mode").toBool()) {
starpilot_scene.conditional_status = params_memory.getInt("CCStatus");
} else {
starpilot_scene.conditional_status = starpilot_scene.enabled ? params_memory.getInt("CEStatus") : 0;
}
starpilot_scene.driver_camera_timer = starpilot_scene.reverse && starpilot_scene.starpilot_toggles.value("driver_camera_in_reverse").toBool() ? starpilot_scene.driver_camera_timer + 1 : 0;
}
+11 -9
View File
@@ -17,7 +17,7 @@ def get_repo_root() -> str:
# Constants
REPO_ROOT = get_repo_root()
PARAMS_CC_PATH = os.path.join(REPO_ROOT, 'common/params.cc')
PARAMS_KEYS_PATH = os.path.join(REPO_ROOT, 'common/params_keys.h')
UI_DIRECTORIES = [
os.path.join(REPO_ROOT, 'selfdrive/ui'),
os.path.join(REPO_ROOT, 'starpilot/ui')
@@ -27,6 +27,7 @@ UI_DIRECTORIES = [
# rather than user-toggled configurations.
KNOWN_READ_ONLY = {
"ApiCache_Device", "ApiCache_DriveStats", "ApiCache_NavDestinations",
"CCStatus", "CEStatus",
"CarMake", "CarModel", "CarModelName", "CarParamsPersistent", "CarVin",
"ClusterOffset", "Compass", "DeveloperSidebarMetric1", "DeveloperSidebarMetric2",
"DeveloperSidebarMetric3", "DeveloperSidebarMetric4", "DeveloperSidebarMetric5",
@@ -36,25 +37,26 @@ KNOWN_READ_ONLY = {
"GitRemote", "GithubSshKeys", "GithubUsername", "HardwareSerial", "IMEI",
"InstallDate", "IsRhdDetected", "KonikMinutes", "LastGPSPosition",
"LastMapsUpdate", "LastUpdateTime", "ModelDrivesAndScores", "ModelReleasedDates",
"ModelVersions", "PrimeType", "TermsVersion", "TrainingVersion", "Version",
"ModelVersions", "PersistedCCStatus", "PersistedCEStatus", "PrimeType",
"TermsVersion", "TrainingVersion", "Version",
"openpilotMinutes", "CompletedTrainingVersion"
}
def extract_registered_keys(params_path: str) -> set:
"""Extracts all legally registered parameter keys from common/params.cc"""
"""Extracts all legally registered parameter keys from common/params_keys.h"""
registered_keys = set()
try:
with open(params_path, 'r', encoding='utf-8') as f:
content = f.read()
# Isolate the keys `unordered_map` block
keys_block_match = re.search(r'unordered_map<std::string, uint32_t> keys = \{(.*?)\};', content, re.DOTALL)
# Isolate the registered keys block.
keys_block_match = re.search(r'keys\s*=\s*\{(.*?)\n\};', content, re.DOTALL)
if not keys_block_match:
print("Error: Could not locate 'keys' map in params.cc")
print("Error: Could not locate 'keys' map in params_keys.h")
return registered_keys
# Extract {"KeyName", FLAG} entries
for match in re.finditer(r'\{"([A-Za-z0-9_]+)",\s*([^}]+)\}', keys_block_match.group(1)):
# Extract {"KeyName", {FLAGS...}} entries.
for match in re.finditer(r'\{"([A-Za-z0-9_]+)",\s*\{([^}]*)\}\s*\}', keys_block_match.group(1)):
key, flag = match.group(1), match.group(2)
# Remove keys that are strictly internal ephemeral states
if 'CLEAR_ON_MANAGER_START' not in flag:
@@ -90,7 +92,7 @@ def main():
print(f"Starting parameter derivation inside {REPO_ROOT}...")
# 1. Fetch
registered_keys = extract_registered_keys(PARAMS_CC_PATH)
registered_keys = extract_registered_keys(PARAMS_KEYS_PATH)
ui_strings = extract_ui_string_literals(UI_DIRECTORIES)
# 2. Intersect
+93 -52
View File
@@ -1,14 +1,13 @@
Dynamically Derived Feasible Param Candidates (The Golden List)
===============================================================
Total globally registered C++ keys: 417
Total explicit UI string references: 369
Total Editable/Toggleable targets: 331
Total globally registered C++ keys: 507
Total explicit UI string references: 415
Total Editable/Toggleable targets: 378
AMapKey1
AMapKey2
AccelerationPath
AccelerationProfile
AdbEnabled
AdjacentLeadsUI
AdjacentPath
AdjacentPathMetrics
@@ -24,55 +23,52 @@ AggressiveJerkSpeed
AggressiveJerkSpeedDecrease
AggressivePersonalityProfile
AlertVolumeControl
AlphaLongitudinalEnabled
AlwaysOnDM
AlwaysOnLateral
AlwaysOnLateralLKAS
AlwaysOnLateralMain
AutomaticUpdates
AutomaticallyDownloadModels
AvailableModelNames
AvailableModelSeries
AvailableModels
BigMap
BelowSteerSpeedVolume
BlacklistedModels
BlindSpotMetrics
BlindSpotPath
BootLogo
BorderMetrics
BorderWidth
CCMLead
CCMSetSpeedMargin
CCMSpeed
CCMSpeedLead
CECurves
CECurvesLead
CELead
CEModelStopTime
CENavigation
CENavigationIntersections
CENavigationLead
CENavigationTurns
CESignalLaneDetection
CESignalSpeed
CESlowerLead
CESpeed
CESpeedLead
CEStatus
CEStopLights
CEStoppedLead
CalibratedLateralAcceleration
CalibrationParams
CalibrationProgress
CameraView
CancelButtonControl
CoastUpToLeads
ColorScheme
CommunityFavorites
ConditionalChill
ConditionalExperimental
CurvatureData
CurveSpeedController
CustomAlerts
CustomColors
CustomCruise
CustomCruiseLong
CustomDistanceIcons
CustomIcons
CustomPersonalities
CustomSignals
CustomSounds
CustomThemes
CustomUI
CancelButtonControl
DebugMode
DecelerationProfile
DeveloperMetrics
@@ -83,12 +79,12 @@ DeviceManagement
DeviceShutdown
DisableOnroadUploads
DisableOpenpilotLongitudinal
DisableWideRoad
DiscordUsername
DisengageOnAccelerator
DisengageVolume
DistanceButtonControl
DoToggleReset
DoToggleResetStock
DistanceIconPack
DownloadableBootLogos
DownloadableColors
DownloadableDistanceIcons
@@ -97,98 +93,118 @@ DownloadableSignals
DownloadableSounds
DownloadableWheels
DriverCamera
DrivingModel
DrivingModelName
DrivingModelVersion
DynamicPathWidth
DynamicPedalsOnUI
EVTuning
EngageVolume
ExperimentalLongitudinalEnabled
ExperimentalMode
ExperimentalModeConfirmed
FPSCounter
Fahrenheit
FavoriteDestinations
ForceAutoTune
ForceAutoTuneOff
ForceFingerprint
ForceMPHDashboard
ForceStandstill
ForceStopDistanceOffset
ForceStops
ForceTorqueController
StarPilotStats
FrogsGoMoosTweak
FullMap
GMDashSpoofOffsets
GMPedalLongitudinal
GoatScream
GoatScreamCriticalAlerts
GreenLightAlert
GsmApn
GsmMetered
GsmRoaming
HasAcceptedTerms
HideAlerts
HideChangingLanesBanner
HideDMIcon
HideDistanceProfileBanner
HideLeadMarker
HideMap
HideMapIcon
HideMaxSpeed
HideSpeed
HideSpeedLimit
HideTurningBanner
HigherBitrate
HolidayThemes
HumanAcceleration
HumanLaneChanges
IconPack
IncreaseFollowingLowVisibility
IncreaseFollowingRain
IncreaseFollowingRainStorm
IncreaseFollowingSnow
IncreaseThermalLimits
IncreasedStoppedDistance
IsDriverViewEnabled
IncreasedStoppedDistanceLowVisibility
IncreasedStoppedDistanceRain
IncreasedStoppedDistanceRainStorm
IncreasedStoppedDistanceSnow
IsLdwEnabled
IsMetric
IsRHD
IsRHDOverride
KonikDongleId
LKASButtonControl
LaneChangeSmoothing
LaneChangeTime
LaneChanges
LaneDetectionWidth
LaneLinesColor
LaneLinesWidth
LanguageSetting
LateralResumeDelay
LateralTune
LeadDepartingAlert
LeadDetectionThreshold
LeadIndicator
LeadInfo
LiveDelay
LiveParameters
LiveParametersV2
LiveTorqueParameters
LockDoors
LockDoorsTimer
LongCancelButtonControl
LongDistanceButtonControl
LongModeButtonControl
LongPitch
LongStarButtonControl
LongitudinalActuatorDelay
LongitudinalActuatorDelayStock
LongitudinalPersonality
LongitudinalTune
LoudBlindspotAlert
LowVoltageShutdown
MainCruiseButtonControl
MapAcceleration
MapDeceleration
MapGears
MapStyle
MapboxPublicKey
MapboxSecretKey
MapsSelected
MaxDesiredAcceleration
MinimumLaneChangeSpeed
ModeButtonControl
Model
ModelRandomizer
ModelSortMode
ModelUI
ModelVersion
NNFF
NNFFLite
NavPastDestinations
NavSettingLeftSide
NavSettingTime24h
NavDesiresAllowed
NavLongitudinalAllowed
NavigationUI
NewLongAPI
NoLogging
NoUploads
NostalgiaMode
NudgelessLaneChange
NumericalTemp
OSMDownloadLocations
Offroad_ExcessiveActuation
Offset1
Offset2
Offset3
@@ -199,30 +215,38 @@ Offset7
OneLaneChange
OnroadDistanceButton
OpenpilotEnabledToggle
OverpassRequests
PathColor
PathEdgesColor
PathEdgeWidth
PathWidth
PauseAOLOnBrake
PauseLateralOnSignal
PauseLateralSpeed
PedalsOnUI
PersonalizeOpenpilot
PersistChillState
PersistExperimentalState
PreferredSchedule
PromptDistractedVolume
PromptVolume
QOLLateral
QOLLongitudinal
QOLVisuals
RadarTakeoffs
RadarTracksUI
RainbowPath
RandomEvents
RandomThemes
RandomThemesHolidays
RecordAudio
RecordFront
RecordFrontLock
RecoveryPower
RedPanda
ReduceAccelerationLowVisibility
ReduceAccelerationRain
ReduceAccelerationRainStorm
ReduceAccelerationSnow
ReduceLateralAccelerationLowVisibility
ReduceLateralAccelerationRain
ReduceLateralAccelerationRainStorm
ReduceLateralAccelerationSnow
RefuseVolume
RelaxedFollow
RelaxedFollowHigh
@@ -232,11 +256,14 @@ RelaxedJerkDeceleration
RelaxedJerkSpeed
RelaxedJerkSpeedDecrease
RelaxedPersonalityProfile
RemapCancelToDistance
RemoteStartBootsComma
ReverseCruise
RoadEdgesWidth
RoadNameUI
RotatingWheel
SLCAbbreviatedSources
SLCActiveSourcesOnly
SLCConfirmation
SLCConfirmationHigher
SLCConfirmationLower
@@ -245,23 +272,26 @@ SLCLookaheadHigher
SLCLookaheadLower
SLCMapboxFiller
SLCOverride
SLCPriority
SLCPriority2
SNGHack
SafeMode
ScreenBrightness
ScreenBrightnessOnroad
ScreenManagement
ScreenRecorder
ScreenTimeout
ScreenTimeoutOnroad
SearchInput
SetSpeedLimit
SetSpeedOffset
ShowAllToggles
ShowCCMStatus
ShowCEMStatus
ShowCPU
ShowCSCStatus
ShowGPU
ShowIP
ShowMemoryUsage
ShowModeStatusBanner
ShowSLCOffset
ShowSpeedLimits
ShowSteering
@@ -269,13 +299,18 @@ ShowStoppingPoint
ShowStoppingPointMetrics
ShowStorageLeft
ShowStorageUsed
ShownToggleDescriptions
Sidebar
SidebarMetrics
SidebarOpen
SignalAnimation
SignalMetrics
SimpleMode
SoundPack
SpeedLimitChangedAlert
SpeedLimitController
SpeedLimitFiller
SpeedLimitSources
SpeedLimits
SpeedLimitsFiltered
SshEnabled
StandardFollow
StandardFollowHigh
@@ -286,6 +321,7 @@ StandardJerkSpeed
StandardJerkSpeedDecrease
StandardPersonalityProfile
StandbyMode
StarButtonControl
StartAccel
StartAccelStock
StartupMessageBottom
@@ -299,8 +335,6 @@ SteerKP
SteerKPStock
SteerLatAccel
SteerLatAccelStock
SteerOffset
SteerOffsetStock
SteerRatio
SteerRatioStock
StopAccel
@@ -309,6 +343,9 @@ StopDistance
StoppedTimer
StoppingDecelRate
StoppingDecelRateStock
SubaruSNG
SwitchbackModeCooldown
SwitchbackModeEnabled
TacoTune
TetheringEnabled
ToyotaDoors
@@ -319,15 +356,14 @@ TrafficJerkDeceleration
TrafficJerkSpeed
TrafficJerkSpeedDecrease
TrafficPersonalityProfile
TrailerLoad
TruckTuning
TuningLevel
TuningLevelConfirmed
TurnDesires
UnlimitedLength
UnlockDoors
UpdaterAvailableBranches
UseKonikServer
UsePrebuilt
UseSI
UseVienna
UserFavorites
@@ -337,8 +373,13 @@ VEgoStopping
VEgoStoppingStock
VeryLongCancelButtonControl
VeryLongDistanceButtonControl
VeryLongModeButtonControl
VeryLongStarButtonControl
VisionSpeedLimitDetection
VoltSNG
WarningImmediateVolume
WarningSoftVolume
WeatherPresets
WheelControls
WheelIcon
WheelSpeed
+16 -3
View File
@@ -116,6 +116,7 @@ PARENT_KEYS_MAPPING = {
"longitudinal_settings.cc": {
"advancedLongitudinalTuneKeys": "AdvancedLongitudinalTune",
"aggressivePersonalityKeys": "AggressivePersonalityProfile",
"conditionalChillKeys": "ConditionalChill",
"conditionalExperimentalKeys": "ConditionalExperimental",
"curveSpeedKeys": "CurveSpeedController",
"customDrivingPersonalityKeys": "CustomPersonalities",
@@ -453,9 +454,9 @@ def parse_cpp_file(filename):
if step_match:
step = step_match.group(1)
# CESpeed is rendered in Qt with a dual numeric control (CESpeed + CESpeedLead),
# CESpeed/CCMSpeed are rendered in Qt with dual numeric controls,
# so the generic assignment matcher cannot infer it reliably.
if key == "CESpeed":
if key in {"CESpeed", "CCMSpeed"}:
widget_type = "numeric"
data_type = "int"
min_val, max_val, step = "0", "99", "1"
@@ -519,7 +520,7 @@ def parse_cpp_file(filename):
},
])
# Mirror CESpeed's dual slider (with-lead variant) from Qt.
# Mirror CESpeed/CCMSpeed's dual sliders (with-lead variants) from Qt.
if key == "CESpeed":
items.append({
"key": "CESpeedLead",
@@ -532,6 +533,18 @@ def parse_cpp_file(filename):
"step": 1.0,
"parent_key": "ConditionalExperimental",
})
elif key == "CCMSpeed":
items.append({
"key": "CCMSpeedLead",
"label": "Above (With Lead)",
"description": "Switch to \"Chill Mode\" when following a stable lead above this speed.",
"data_type": "int",
"ui_type": "numeric",
"min": 0.0,
"max": 99.0,
"step": 1.0,
"parent_key": "ConditionalChill",
})
return items