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
+4 -4
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, \ from openpilot.sunnypilot.selfdrive.selfdrived.events_base import EventsBase, Priority, ET, Alert, \
NoEntryAlert, SoftDisableAlert, UserSoftDisableAlert, ImmediateDisableAlert, EngagementAlert, NormalPermanentAlert, \ NoEntryAlert, SoftDisableAlert, UserSoftDisableAlert, ImmediateDisableAlert, EngagementAlert, NormalPermanentAlert, \
StartupAlert, AlertCallbackType, wrong_car_mode_alert StartupAlert, AlertCallbackType, AlertCallbackTypeSP, wrong_car_mode_alert
AlertSize = log.SelfdriveState.AlertSize AlertSize = log.SelfdriveState.AlertSize
@@ -30,7 +30,7 @@ class Events(EventsBase):
super().__init__() super().__init__()
self.event_counters = dict.fromkeys(EVENTS.keys(), 0) 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 return EVENTS
def get_event_name(self, event: int): 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 ********** # ********** events with no alerts **********
EventName.stockFcw: {}, EventName.stockFcw: {},
@@ -828,7 +828,7 @@ if __name__ == '__main__':
for i, alerts in EVENTS.items(): for i, alerts in EVENTS.items():
for et, alert in alerts.items(): for et, alert in alerts.items():
if callable(alert): 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]) alerts_by_type[et][alert.priority].append(event_names[i])
all_alerts: dict[str, list[tuple[Priority, list[str]]]] = {} all_alerts: dict[str, list[tuple[Priority, list[str]]]] = {}
+6 -3
View File
@@ -155,7 +155,7 @@ class SelfdriveD(CruiseHelper):
self.car_events_sp = CarSpecificEventsSP(self.CP, self.params) 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): def update_events(self, CS):
"""Compute onroadEvents from carState""" """Compute onroadEvents from carState"""
@@ -394,7 +394,7 @@ class SelfdriveD(CruiseHelper):
if CS.gearShifter == car.CarState.GearShifter.park and self.mads.enabled: if CS.gearShifter == car.CarState.GearShifter.park and self.mads.enabled:
self.events.remove(EventName.canBusMissing) 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 # decrement personality on distance button press
if self.CP.openpilotLongitudinalControl: if self.CP.openpilotLongitudinalControl:
@@ -462,9 +462,11 @@ class SelfdriveD(CruiseHelper):
pers = LONGITUDINAL_PERSONALITY_MAP[self.personality] pers = LONGITUDINAL_PERSONALITY_MAP[self.personality]
callback_args = [self.CP, CS, self.sm, self.is_metric, callback_args = [self.CP, CS, self.sm, self.is_metric,
self.state_machine.soft_disable_timer, pers] 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 = 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.add_many(self.sm.frame, alerts + alerts_sp)
self.AM.process_alerts(self.sm.frame, clear_event_types) self.AM.process_alerts(self.sm.frame, clear_event_types)
@@ -546,6 +548,7 @@ class SelfdriveD(CruiseHelper):
self.mads.read_params() self.mads.read_params()
self.car_events_sp.read_params() self.car_events_sp.read_params()
CruiseHelper.read_params(self)
time.sleep(0.1) time.sleep(0.1)
def run(self): def run(self):
+2
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}); engage_img = loadPixmap("../assets/img_chffr_wheel.png", {img_size, img_size});
experimental_img = loadPixmap("../assets/img_experimental.svg", {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); QObject::connect(this, &QPushButton::clicked, this, &ExperimentalButton::changeMode);
#endif
} }
void ExperimentalButton::changeMode() { void ExperimentalButton::changeMode() {
+2 -3
View File
@@ -20,13 +20,12 @@ public:
private: private:
void paintEvent(QPaintEvent *event) override; void paintEvent(QPaintEvent *event) override;
void changeMode();
Params params;
protected: protected:
virtual void drawButton(QPainter &p); virtual void drawButton(QPainter &p);
virtual void changeMode();
Params params;
QPixmap engage_img; QPixmap engage_img;
QPixmap experimental_img; QPixmap experimental_img;
bool experimental_mode; bool experimental_mode;
@@ -9,9 +9,36 @@
#include <QPainter> #include <QPainter>
#include "selfdrive/ui/qt/util.h"
ExperimentalButtonSP::ExperimentalButtonSP(QWidget *parent) : ExperimentalButton(parent) { ExperimentalButtonSP::ExperimentalButtonSP(QWidget *parent) : ExperimentalButton(parent) {
QObject::disconnect(uiState(), &UIState::uiUpdate, this, &ExperimentalButton::updateState); QObject::disconnect(uiState(), &UIState::uiUpdate, this, &ExperimentalButton::updateState);
QObject::connect(uiState(), &UIState::uiUpdate, this, &ExperimentalButtonSP::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) { void ExperimentalButtonSP::updateState(const UIState &s) {
@@ -18,6 +18,7 @@ public:
private: private:
void drawButton(QPainter &p) override; void drawButton(QPainter &p) override;
void changeMode() override;
bool dynamic_experimental_control; bool dynamic_experimental_control;
int dec_mpc_mode; int dec_mpc_mode;
+29 -10
View File
@@ -7,7 +7,6 @@ See the LICENSE.md file in the root directory for more details.
from cereal import car, custom from cereal import car, custom
from opendbc.car import structs from opendbc.car import structs
from openpilot.common.params import Params
ButtonType = car.CarState.ButtonEvent.Type ButtonType = car.CarState.ButtonEvent.Type
EventNameSP = custom.OnroadEventSP.EventName EventNameSP = custom.OnroadEventSP.EventName
@@ -16,21 +15,27 @@ DISTANCE_LONG_PRESS = 50
class CruiseHelper: class CruiseHelper:
def __init__(self, CP: structs.CarParams): def __init__(self, CP: structs.CarParams, selfdrived):
self.CP = CP 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.button_frame_counts = {ButtonType.gapAdjustCruise: 0}
self._experimental_mode = False
self.experimental_mode_switched = 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 self.CP.openpilotLongitudinalControl:
if CS.cruiseState.available: if CS.cruiseState.available:
self.update_button_frame_counts(CS) self.update_button_frame_counts(CS)
# toggle experimental mode once on distance button hold # 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: def update_button_frame_counts(self, CS) -> None:
for button in self.button_frame_counts: for button in self.button_frame_counts:
@@ -42,9 +47,23 @@ class CruiseHelper:
if button in self.button_frame_counts: if button in self.button_frame_counts:
self.button_frame_counts[button] = int(button_event.pressed) 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: if self.button_frame_counts[ButtonType.gapAdjustCruise] >= DISTANCE_LONG_PRESS and not self.experimental_mode_switched:
self._experimental_mode = not experimental_mode if not self.experimental_mode and not self.dynamic_experimental_control:
self.params.put_bool_nonblocking("ExperimentalMode", self._experimental_mode) # State 1 -> 2: Turn on experimental mode only
events.add(EventNameSP.experimentalModeSwitched) 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 self.experimental_mode_switched = True
+12 -4
View File
@@ -1,6 +1,7 @@
from cereal import log, car, custom from cereal import log, car, custom
import cereal.messaging as messaging
from openpilot.sunnypilot.selfdrive.selfdrived.events_base import EventsBase, Priority, ET, Alert, \ 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 AlertSize = log.SelfdriveState.AlertSize
@@ -19,7 +20,7 @@ class EventsSP(EventsBase):
super().__init__() super().__init__()
self.event_counters = dict.fromkeys(EVENTS_SP.keys(), 0) 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 return EVENTS_SP
def get_event_name(self, event: int): def get_event_name(self, event: int):
@@ -29,7 +30,14 @@ class EventsSP(EventsBase):
return custom.OnroadEventSP.Event 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 # sunnypilot
EventNameSP.lkasEnable: { EventNameSP.lkasEnable: {
ET.ENABLE: EngagementAlert(AudibleAlert.engage), ET.ENABLE: EngagementAlert(AudibleAlert.engage),
@@ -127,7 +135,7 @@ EVENTS_SP: dict[int, dict[str, Alert | AlertCallbackType]] = {
}, },
EventNameSP.experimentalModeSwitched: { EventNameSP.experimentalModeSwitched: {
ET.WARNING: NormalPermanentAlert("Experimental Mode Switched", duration=1.5) ET.WARNING: experimental_mode_changed_alert,
}, },
EventNameSP.wrongCarModeAlertOnly: { EventNameSP.wrongCarModeAlertOnly: {
@@ -81,6 +81,8 @@ class AlertBase(Alert):
AlertCallbackType = Callable[[car.CarParams, car.CarState, messaging.SubMaster, bool, int, log.ControlsState], 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 ********** # ********** alert callback functions **********
@@ -166,7 +168,7 @@ class EventsBase:
self.events.remove(event_name) self.events.remove(event_name)
@abstractmethod @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 raise NotImplementedError
@abstractmethod @abstractmethod