comma four: experimental mode explainer (#37961)

* exp mode confirm dialog

* full

* base

* clean up

* too diff

* fix?

* rmnl

* only toggle if exp mode is confirmed

---------

Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com>
This commit is contained in:
Shane Smiskol
2026-08-05 02:30:00 -07:00
committed by GitHub
parent aa0ac919ba
commit 4db21dd4f8
3 changed files with 48 additions and 3 deletions
+1 -1
View File
@@ -174,7 +174,7 @@ class MiciHomeLayout(Widget):
if self._mouse_down_t is not None:
if time.monotonic() - self._mouse_down_t > 0.5:
# long gating for experimental mode - only allow toggle if longitudinal control is available
if ui_state.has_longitudinal_control:
if ui_state.has_longitudinal_control and ui_state.experimental_mode_confirmed:
ui_state.experimental_mode = not ui_state.experimental_mode
ui_state.params.put("ExperimentalMode", ui_state.experimental_mode, block=True)
self._mouse_down_t = None
@@ -1,7 +1,10 @@
from collections.abc import Callable
from openpilot.cereal import log
from openpilot.system.ui.widgets.scroller import NavScroller
from openpilot.selfdrive.ui.mici.widgets.button import BigParamControl, BigMultiParamToggle
from openpilot.selfdrive.ui.mici.widgets.button import BigParamControl, BigMultiParamToggle, BigToggle, GreyBigButton
from openpilot.selfdrive.ui.mici.widgets.dialog import BigConfirmationCircleButton
from openpilot.system.ui.lib.application import gui_app
from openpilot.selfdrive.ui.layouts.settings.common import restart_needed_callback
from openpilot.selfdrive.ui.ui_state import ui_state
@@ -9,12 +12,38 @@ from openpilot.selfdrive.ui.ui_state import ui_state
PERSONALITY_TO_INT = log.LongitudinalPersonality.schema.enumerants
class ExperimentalModeConfirmPage(NavScroller):
def __init__(self, on_confirm: Callable[[], None]):
super().__init__()
accept = BigConfirmationCircleButton("enable\nexperimental mode",
gui_app.texture("icons_mici/setup/driver_monitoring/dm_check.png", 64, 64),
lambda: self.dismiss(on_confirm))
self._scroller.add_widgets([
GreyBigButton("enabling\nexperimental mode", "scroll to continue",
gui_app.texture("icons_mici/setup/warning.png", 64, 64)),
GreyBigButton("", "openpilot defaults to driving in chill mode."),
GreyBigButton("", "Experimental mode enables alpha-level features that aren't ready for chill mode."),
GreyBigButton("End-to-End Longitudinal Control"),
GreyBigButton("", "Let the driving model control the gas and brakes."),
GreyBigButton("", "openpilot will drive as it thinks a human would, including stopping for red lights and stop signs."),
GreyBigButton("", "The set speed will only act as an upper bound."),
GreyBigButton("", "This is an alpha quality feature; mistakes should be expected."),
GreyBigButton("New Driving Visualization"),
GreyBigButton("", "The path will change colors to communicate acceleration intent."),
GreyBigButton("", "Red for braking, green for acceleration, and gray for coasting."),
accept,
])
class TogglesLayoutMici(NavScroller):
def __init__(self):
super().__init__()
self._personality_toggle = BigMultiParamToggle("driving personality", "LongitudinalPersonality", ["aggressive", "standard", "relaxed"])
self._experimental_btn = BigParamControl("experimental mode", "ExperimentalMode")
self._experimental_btn = BigToggle("experimental mode", initial_state=ui_state.params.get_bool("ExperimentalMode"),
toggle_callback=self._on_experimental_mode)
is_metric_toggle = BigParamControl("use metric units", "IsMetric")
ldw_toggle = BigParamControl("lane departure warnings", "IsLdwEnabled")
always_on_dm_toggle = BigParamControl("always-on driver monitor", "AlwaysOnDM")
@@ -85,3 +114,17 @@ class TogglesLayoutMici(NavScroller):
# Refresh toggles from params to mirror external changes
for key, item in self._refresh_toggles:
item.set_checked(ui_state.params.get_bool(key))
def _on_experimental_mode(self, state: bool):
if state and not ui_state.params.get_bool("ExperimentalModeConfirmed"):
# Don't show enabled state until confirm
self._experimental_btn.set_checked(False)
def on_confirm():
ui_state.params.put_bool("ExperimentalModeConfirmed", True)
ui_state.params.put_bool("ExperimentalMode", True)
self._experimental_btn.set_checked(True)
gui_app.push_widget(ExperimentalModeConfirmPage(on_confirm))
else:
ui_state.params.put_bool("ExperimentalMode", state)
+2
View File
@@ -76,6 +76,7 @@ class UIState:
self.is_release = self.params.get_bool("IsReleaseBranch")
self.always_on_dm: bool = self.params.get_bool("AlwaysOnDM")
self.experimental_mode: bool = self.params.get_bool("ExperimentalMode")
self.experimental_mode_confirmed: bool = self.params.get_bool("ExperimentalModeConfirmed")
self.usbgpu: bool = False
self.usbgpu_compiled: bool = usbgpu_compiled()
self.usbgpu_active: bool | None = self.params.get("UsbGpuActive")
@@ -206,6 +207,7 @@ class UIState:
self.is_metric = self.params.get_bool("IsMetric")
self.always_on_dm = self.params.get_bool("AlwaysOnDM")
self.experimental_mode = self.params.get_bool("ExperimentalMode")
self.experimental_mode_confirmed = self.params.get_bool("ExperimentalModeConfirmed")
# keep usbgpu UI active until offroad transition when gpu disappears
self.usbgpu = self.sm["deviceState"].chestnutPresent or (self.usbgpu and self.started)
if not self.usbgpu_compiled: