Compare commits

...

9 Commits

Author SHA1 Message Date
Jason Wen
e78b361444 wrong btn 2025-04-15 01:50:45 -04:00
Jason Wen
74540873bf bye 2025-04-15 01:38:50 -04:00
Jason Wen
f3ef8ff6ec try this 2025-04-15 01:28:30 -04:00
Jason Wen
79a4f25f77 even more 2025-04-15 01:25:08 -04:00
Jason Wen
efef671a3f gotta add it 2025-04-15 01:23:05 -04:00
Jason Wen
ded6049301 ty lint 2025-04-15 01:21:06 -04:00
Jason Wen
51f5193ec5 events 2025-04-15 01:14:20 -04:00
Jason Wen
5db7dbee6b UI this up! 2025-04-15 01:14:16 -04:00
Jason Wen
aab08b8527 init 2025-04-15 00:56:44 -04:00
9 changed files with 86 additions and 25 deletions

View File

@@ -11,7 +11,7 @@ from openpilot.selfdrive.locationd.calibrationd import MIN_SPEED_FILTER
from openpilot.sunnypilot.selfdrive.selfdrived.events_base import EventsBase, Priority, ET, Alert, \
NoEntryAlert, SoftDisableAlert, UserSoftDisableAlert, ImmediateDisableAlert, EngagementAlert, NormalPermanentAlert, \
StartupAlert, AlertCallbackType, wrong_car_mode_alert
StartupAlert, AlertCallbackType, AlertCallbackTypeSP, wrong_car_mode_alert
AlertSize = log.SelfdriveState.AlertSize
@@ -30,7 +30,7 @@ class Events(EventsBase):
super().__init__()
self.event_counters = dict.fromkeys(EVENTS.keys(), 0)
def get_events_mapping(self) -> dict[int, dict[str, Alert | AlertCallbackType]]:
def get_events_mapping(self) -> dict[int, dict[str, Alert | AlertCallbackType | AlertCallbackTypeSP]]:
return EVENTS
def get_event_name(self, event: int):
@@ -193,7 +193,7 @@ def personality_changed_alert(CP: car.CarParams, CS: car.CarState, sm: messaging
EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = {
EVENTS: dict[int, dict[str, Alert | AlertCallbackType | AlertCallbackTypeSP]] = {
# ********** events with no alerts **********
EventName.stockFcw: {},
@@ -828,7 +828,7 @@ if __name__ == '__main__':
for i, alerts in EVENTS.items():
for et, alert in alerts.items():
if callable(alert):
alert = alert(CP, CS, sm, False, 1, log.LongitudinalPersonality.standard)
alert = alert(CP, CS, sm, False, 1, log.LongitudinalPersonality.standard) # type: ignore[call-arg]
alerts_by_type[et][alert.priority].append(event_names[i])
all_alerts: dict[str, list[tuple[Priority, list[str]]]] = {}

View File

@@ -155,7 +155,7 @@ class SelfdriveD(CruiseHelper):
self.car_events_sp = CarSpecificEventsSP(self.CP, self.params)
CruiseHelper.__init__(self, self.CP)
CruiseHelper.__init__(self, self.CP, self)
def update_events(self, CS):
"""Compute onroadEvents from carState"""
@@ -394,7 +394,7 @@ class SelfdriveD(CruiseHelper):
if CS.gearShifter == car.CarState.GearShifter.park and self.mads.enabled:
self.events.remove(EventName.canBusMissing)
CruiseHelper.update(self, CS, self.events_sp, self.experimental_mode)
CruiseHelper.update(self, CS)
# decrement personality on distance button press
if self.CP.openpilotLongitudinalControl:
@@ -462,9 +462,11 @@ class SelfdriveD(CruiseHelper):
pers = LONGITUDINAL_PERSONALITY_MAP[self.personality]
callback_args = [self.CP, CS, self.sm, self.is_metric,
self.state_machine.soft_disable_timer, pers]
callback_args_sp = [self.CP, CS, self.sm, self.is_metric,
self.state_machine.soft_disable_timer, pers, self.experimental_mode, self.dynamic_experimental_control]
alerts = self.events.create_alerts(self.state_machine.current_alert_types, callback_args)
alerts_sp = self.events_sp.create_alerts(self.state_machine.current_alert_types, callback_args)
alerts_sp = self.events_sp.create_alerts(self.state_machine.current_alert_types, callback_args_sp)
self.AM.add_many(self.sm.frame, alerts + alerts_sp)
self.AM.process_alerts(self.sm.frame, clear_event_types)
@@ -546,6 +548,7 @@ class SelfdriveD(CruiseHelper):
self.mads.read_params()
self.car_events_sp.read_params()
CruiseHelper.read_params(self)
time.sleep(0.1)
def run(self):

View File

@@ -21,7 +21,9 @@ ExperimentalButton::ExperimentalButton(QWidget *parent) : experimental_mode(fals
engage_img = loadPixmap("../assets/img_chffr_wheel.png", {img_size, img_size});
experimental_img = loadPixmap("../assets/img_experimental.svg", {img_size, img_size});
#ifndef SUNNYPILOT
QObject::connect(this, &QPushButton::clicked, this, &ExperimentalButton::changeMode);
#endif
}
void ExperimentalButton::changeMode() {

View File

@@ -20,13 +20,12 @@ public:
private:
void paintEvent(QPaintEvent *event) override;
void changeMode();
Params params;
protected:
virtual void drawButton(QPainter &p);
virtual void changeMode();
Params params;
QPixmap engage_img;
QPixmap experimental_img;
bool experimental_mode;

View File

@@ -9,9 +9,36 @@
#include <QPainter>
#include "selfdrive/ui/qt/util.h"
ExperimentalButtonSP::ExperimentalButtonSP(QWidget *parent) : ExperimentalButton(parent) {
QObject::disconnect(uiState(), &UIState::uiUpdate, this, &ExperimentalButton::updateState);
QObject::connect(uiState(), &UIState::uiUpdate, this, &ExperimentalButtonSP::updateState);
QObject::connect(this, &QPushButton::clicked, this, &ExperimentalButtonSP::changeMode);
}
void ExperimentalButtonSP::changeMode() {
const auto cp = (*uiState()->sm)["carParams"].getCarParams();
bool can_change = hasLongitudinalControl(cp) && params.getBool("ExperimentalModeConfirmed");
if (can_change) {
bool experimental_mode_new;
bool dynamic_experimental_control_new;
if (!experimental_mode && !dynamic_experimental_control) {
experimental_mode_new = true;
dynamic_experimental_control_new = false;
} else if (experimental_mode && !dynamic_experimental_control) {
experimental_mode_new = true;
dynamic_experimental_control_new = true;
} else {
experimental_mode_new = false;
dynamic_experimental_control_new = false;
}
params.putBool("ExperimentalMode", experimental_mode_new);
params.putBool("DynamicExperimentalControl", dynamic_experimental_control_new);
}
}
void ExperimentalButtonSP::updateState(const UIState &s) {

View File

@@ -18,6 +18,7 @@ public:
private:
void drawButton(QPainter &p) override;
void changeMode() override;
bool dynamic_experimental_control;
int dec_mpc_mode;

View File

@@ -7,7 +7,6 @@ See the LICENSE.md file in the root directory for more details.
from cereal import car, custom
from opendbc.car import structs
from openpilot.common.params import Params
ButtonType = car.CarState.ButtonEvent.Type
EventNameSP = custom.OnroadEventSP.EventName
@@ -16,21 +15,27 @@ DISTANCE_LONG_PRESS = 50
class CruiseHelper:
def __init__(self, CP: structs.CarParams):
def __init__(self, CP: structs.CarParams, selfdrived):
self.CP = CP
self.params = Params()
self.selfdrived = selfdrived
self.params = self.selfdrived.params
self.events_sp = self.selfdrived.events_sp
self.button_frame_counts = {ButtonType.gapAdjustCruise: 0}
self._experimental_mode = False
self.experimental_mode_switched = False
self.experimental_mode = self.selfdrived.experimental_mode
self.dynamic_experimental_control = False
def update(self, CS, events, experimental_mode) -> None:
def read_params(self):
self.dynamic_experimental_control = self.params.get_bool("DynamicExperimentalControl")
def update(self, CS) -> None:
if self.CP.openpilotLongitudinalControl:
if CS.cruiseState.available:
self.update_button_frame_counts(CS)
# toggle experimental mode once on distance button hold
self.update_experimental_mode(events, experimental_mode)
self.update_experimental_mode()
def update_button_frame_counts(self, CS) -> None:
for button in self.button_frame_counts:
@@ -42,9 +47,23 @@ class CruiseHelper:
if button in self.button_frame_counts:
self.button_frame_counts[button] = int(button_event.pressed)
def update_experimental_mode(self, events, experimental_mode) -> None:
def update_experimental_mode(self) -> None:
if self.button_frame_counts[ButtonType.gapAdjustCruise] >= DISTANCE_LONG_PRESS and not self.experimental_mode_switched:
self._experimental_mode = not experimental_mode
self.params.put_bool_nonblocking("ExperimentalMode", self._experimental_mode)
events.add(EventNameSP.experimentalModeSwitched)
if not self.experimental_mode and not self.dynamic_experimental_control:
# State 1 -> 2: Turn on experimental mode only
experimental_mode = True
dynamic_experimental_control = False
elif self.experimental_mode and not self.dynamic_experimental_control:
# State 2 -> 3: Keep experimental mode on, turn on DEC
experimental_mode = True
dynamic_experimental_control = True
else:
# State 3 -> 1: Turn everything off, so back to chill mode
experimental_mode = False
dynamic_experimental_control = False
self.params.put_bool_nonblocking("ExperimentalMode", experimental_mode)
self.params.put_bool_nonblocking("DynamicExperimentalControl", dynamic_experimental_control)
self.events_sp.add(EventNameSP.experimentalModeSwitched)
self.experimental_mode_switched = True

View File

@@ -1,6 +1,7 @@
from cereal import log, car, custom
import cereal.messaging as messaging
from openpilot.sunnypilot.selfdrive.selfdrived.events_base import EventsBase, Priority, ET, Alert, \
NoEntryAlert, ImmediateDisableAlert, EngagementAlert, NormalPermanentAlert, AlertCallbackType, wrong_car_mode_alert
NoEntryAlert, ImmediateDisableAlert, EngagementAlert, NormalPermanentAlert, AlertCallbackType, AlertCallbackTypeSP, wrong_car_mode_alert
AlertSize = log.SelfdriveState.AlertSize
@@ -19,7 +20,7 @@ class EventsSP(EventsBase):
super().__init__()
self.event_counters = dict.fromkeys(EVENTS_SP.keys(), 0)
def get_events_mapping(self) -> dict[int, dict[str, Alert | AlertCallbackType]]:
def get_events_mapping(self) -> dict[int, dict[str, Alert | AlertCallbackType | AlertCallbackTypeSP]]:
return EVENTS_SP
def get_event_name(self, event: int):
@@ -29,7 +30,14 @@ class EventsSP(EventsBase):
return custom.OnroadEventSP.Event
EVENTS_SP: dict[int, dict[str, Alert | AlertCallbackType]] = {
def experimental_mode_changed_alert(CP: car.CarParams, CS: car.CarState, sm: messaging.SubMaster, metric: bool,
soft_disable_time: int, personality, experimental_mode, dynamic_experimental_control) -> Alert:
exp_mode_str = "ON" if experimental_mode else "OFF"
dec_str = "ON" if dynamic_experimental_control else "OFF"
return NormalPermanentAlert(f"Experimental Mode: {exp_mode_str}\nDynamic Experimental Control: {dec_str}", duration=1.5)
EVENTS_SP: dict[int, dict[str, Alert | AlertCallbackType | AlertCallbackTypeSP]] = {
# sunnypilot
EventNameSP.lkasEnable: {
ET.ENABLE: EngagementAlert(AudibleAlert.engage),
@@ -127,7 +135,7 @@ EVENTS_SP: dict[int, dict[str, Alert | AlertCallbackType]] = {
},
EventNameSP.experimentalModeSwitched: {
ET.WARNING: NormalPermanentAlert("Experimental Mode Switched", duration=1.5)
ET.WARNING: experimental_mode_changed_alert,
},
EventNameSP.wrongCarModeAlertOnly: {

View File

@@ -81,6 +81,8 @@ class AlertBase(Alert):
AlertCallbackType = Callable[[car.CarParams, car.CarState, messaging.SubMaster, bool, int, log.ControlsState], Alert]
AlertCallbackTypeSP = Callable[[car.CarParams, car.CarState, messaging.SubMaster, bool, int, log.ControlsState,
bool, bool], Alert]
# ********** alert callback functions **********
@@ -166,7 +168,7 @@ class EventsBase:
self.events.remove(event_name)
@abstractmethod
def get_events_mapping(self) -> dict[int, dict[str, Alert | AlertCallbackType]]:
def get_events_mapping(self) -> dict[int, dict[str, Alert | AlertCallbackType | AlertCallbackTypeSP]]:
raise NotImplementedError
@abstractmethod