Skip to content

Commit ff22326

Browse files
authored
Lock out for excessive actuation (#35792)
* excessive actuation * text * software * check * logic * whoops * dont want to lose alert unless user interacts with it * implement * try x2 * counter * try to false trigger * use livepose * need to check for livePose noise * cmt * nl * add back * organization * setVisible and isVisible consecutively don't work * style * cant do this sadly * actually we can! * clean up * clean up * clean up * need to match torqued, paramsd, lagd, etc. (fix op sim)
1 parent bddeca6 commit ff22326

File tree

8 files changed

+69
-13
lines changed

8 files changed

+69
-13
lines changed

cereal/log.capnp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,7 @@ struct OnroadEvent @0xc4fa6047f024e718 {
128128
personalityChanged @91;
129129
aeb @92;
130130
userFlag @95;
131+
excessiveActuation @96;
131132

132133
soundsUnavailableDEPRECATED @47;
133134
}

common/params_keys.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ inline static std::unordered_map<std::string, ParamKeyAttributes> keys = {
8787
{"Offroad_CarUnrecognized", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, JSON}},
8888
{"Offroad_ConnectivityNeeded", {CLEAR_ON_MANAGER_START, JSON}},
8989
{"Offroad_ConnectivityNeededPrompt", {CLEAR_ON_MANAGER_START, JSON}},
90+
{"Offroad_ExcessiveActuation", {PERSISTENT, JSON}},
9091
{"Offroad_IsTakingSnapshot", {CLEAR_ON_MANAGER_START, JSON}},
9192
{"Offroad_NeosUpdate", {CLEAR_ON_MANAGER_START, JSON}},
9293
{"Offroad_NoFirmware", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, JSON}},

selfdrive/selfdrived/alerts_offroad.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,10 @@
4040
"Offroad_Recalibration": {
4141
"text": "openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield.",
4242
"severity": 0
43+
},
44+
"Offroad_ExcessiveActuation": {
45+
"text": "openpilot has detected excessive %1 actuation. This may be due to a software bug. Please contact support at https://comma.ai/support.",
46+
"severity": 1,
47+
"_comment": "Set extra field to lateral or longitudinal."
4348
}
4449
}

selfdrive/selfdrived/events.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -758,6 +758,11 @@ def invalid_lkas_setting_alert(CP: car.CarParams, CS: car.CarState, sm: messagin
758758
ET.NO_ENTRY: NoEntryAlert("Distraction Level Too High"),
759759
},
760760

761+
EventName.excessiveActuation: {
762+
ET.SOFT_DISABLE: soft_disable_alert("Excessive Actuation"),
763+
ET.NO_ENTRY: NoEntryAlert("Excessive Actuation"),
764+
},
765+
761766
EventName.overheat: {
762767
ET.PERMANENT: overheat_alert,
763768
ET.SOFT_DISABLE: soft_disable_alert("System Overheated"),

selfdrive/selfdrived/selfdrived.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
from cereal import car, log
99
from msgq.visionipc import VisionIpcClient, VisionStreamType
10+
from opendbc.car.interfaces import ACCEL_MIN, ACCEL_MAX
1011

1112

1213
from openpilot.common.params import Params
@@ -15,6 +16,7 @@
1516
from openpilot.common.gps import get_gps_location_service
1617

1718
from openpilot.selfdrive.car.car_specific import CarSpecificEvents
19+
from openpilot.selfdrive.locationd.helpers import PoseCalibrator, Pose
1820
from openpilot.selfdrive.selfdrived.events import Events, ET
1921
from openpilot.selfdrive.selfdrived.state import StateMachine
2022
from openpilot.selfdrive.selfdrived.alertmanager import AlertManager, set_offroad_alert
@@ -25,7 +27,9 @@
2527
REPLAY = "REPLAY" in os.environ
2628
SIMULATION = "SIMULATION" in os.environ
2729
TESTING_CLOSET = "TESTING_CLOSET" in os.environ
30+
2831
LONGITUDINAL_PERSONALITY_MAP = {v: k for k, v in log.LongitudinalPersonality.schema.enumerants.items()}
32+
MIN_EXCESSIVE_ACTUATION_COUNT = int(0.25 / DT_CTRL)
2933

3034
ThermalStatus = log.DeviceState.ThermalStatus
3135
State = log.SelfdriveState.OpenpilotState
@@ -39,6 +43,21 @@
3943
IGNORED_SAFETY_MODES = (SafetyModel.silent, SafetyModel.noOutput)
4044

4145

46+
def check_excessive_actuation(sm: messaging.SubMaster, CS: car.CarState, calibrator: PoseCalibrator, counter: int) -> tuple[int, bool]:
47+
# CS.aEgo can be noisy to bumps in the road, transitioning from standstill, losing traction, etc.
48+
device_pose = Pose.from_live_pose(sm['livePose'])
49+
calibrated_pose = calibrator.build_calibrated_pose(device_pose)
50+
accel_calibrated = calibrated_pose.acceleration.x
51+
52+
# livePose acceleration can be noisy due to bad mounting or aliased livePose measurements
53+
accel_valid = abs(CS.aEgo - accel_calibrated) < 2
54+
55+
excessive_actuation = accel_calibrated > ACCEL_MAX * 2 or accel_calibrated < ACCEL_MIN * 2
56+
counter = counter + 1 if sm['carControl'].longActive and excessive_actuation and accel_valid else 0
57+
58+
return counter, counter > MIN_EXCESSIVE_ACTUATION_COUNT
59+
60+
4261
class SelfdriveD:
4362
def __init__(self, CP=None):
4463
self.params = Params()
@@ -54,6 +73,7 @@ def __init__(self, CP=None):
5473
self.CP = CP
5574

5675
self.car_events = CarSpecificEvents(self.CP)
76+
self.calibrator = PoseCalibrator()
5777

5878
# Setup sockets
5979
self.pm = messaging.PubMaster(['selfdriveState', 'onroadEvents'])
@@ -111,6 +131,8 @@ def __init__(self, CP=None):
111131
self.experimental_mode = False
112132
self.personality = self.params.get("LongitudinalPersonality", return_default=True)
113133
self.recalibrating_seen = False
134+
self.excessive_actuation = self.params.get("Offroad_ExcessiveActuation") is not None
135+
self.excessive_actuation_counter = 0
114136
self.state_machine = StateMachine()
115137
self.rk = Ratekeeper(100, print_delay_threshold=None)
116138

@@ -227,6 +249,18 @@ def update_events(self, CS):
227249
if self.sm['driverAssistance'].leftLaneDeparture or self.sm['driverAssistance'].rightLaneDeparture:
228250
self.events.add(EventName.ldw)
229251

252+
# Check for excessive (longitudinal) actuation
253+
if self.sm.updated['liveCalibration']:
254+
self.calibrator.feed_live_calib(self.sm['liveCalibration'])
255+
256+
self.excessive_actuation_counter, excessive_actuation = check_excessive_actuation(self.sm, CS, self.calibrator, self.excessive_actuation_counter)
257+
if not self.excessive_actuation and excessive_actuation:
258+
set_offroad_alert("Offroad_ExcessiveActuation", True, extra_text="longitudinal")
259+
self.excessive_actuation = True
260+
261+
if self.excessive_actuation:
262+
self.events.add(EventName.excessiveActuation)
263+
230264
# Handle lane change
231265
if self.sm['modelV2'].meta.laneChangeState == LaneChangeState.preLaneChange:
232266
direction = self.sm['modelV2'].meta.laneChangeDirection

selfdrive/ui/qt/widgets/offroad_alerts.cc

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,19 @@ AbstractAlert::AbstractAlert(bool hasRebootBtn, QWidget *parent) : QFrame(parent
3232
footer_layout->addWidget(dismiss_btn, 0, Qt::AlignBottom | Qt::AlignLeft);
3333
QObject::connect(dismiss_btn, &QPushButton::clicked, this, &AbstractAlert::dismiss);
3434

35-
snooze_btn = new QPushButton(tr("Snooze Update"));
36-
snooze_btn->setVisible(false);
37-
snooze_btn->setFixedSize(550, 125);
38-
footer_layout->addWidget(snooze_btn, 0, Qt::AlignBottom | Qt::AlignRight);
39-
QObject::connect(snooze_btn, &QPushButton::clicked, [=]() {
40-
params.putBool("SnoozeUpdate", true);
35+
action_btn = new QPushButton();
36+
action_btn->setVisible(false);
37+
action_btn->setFixedHeight(125);
38+
footer_layout->addWidget(action_btn, 0, Qt::AlignBottom | Qt::AlignRight);
39+
QObject::connect(action_btn, &QPushButton::clicked, [=]() {
40+
if (!alerts["Offroad_ExcessiveActuation"]->text().isEmpty()) {
41+
params.remove("Offroad_ExcessiveActuation");
42+
} else {
43+
params.putBool("SnoozeUpdate", true);
44+
}
4145
});
42-
QObject::connect(snooze_btn, &QPushButton::clicked, this, &AbstractAlert::dismiss);
43-
snooze_btn->setStyleSheet(R"(color: white; background-color: #4F4F4F;)");
46+
QObject::connect(action_btn, &QPushButton::clicked, this, &AbstractAlert::dismiss);
47+
action_btn->setStyleSheet("color: white; background-color: #4F4F4F; padding-left: 60px; padding-right: 60px;");
4448

4549
if (hasRebootBtn) {
4650
QPushButton *rebootBtn = new QPushButton(tr("Reboot and Update"));
@@ -107,7 +111,14 @@ int OffroadAlert::refresh() {
107111
label->setVisible(!text.isEmpty());
108112
alertCount += !text.isEmpty();
109113
}
110-
snooze_btn->setVisible(!alerts["Offroad_ConnectivityNeeded"]->text().isEmpty());
114+
115+
action_btn->setVisible(!alerts["Offroad_ExcessiveActuation"]->text().isEmpty() || !alerts["Offroad_ConnectivityNeeded"]->text().isEmpty());
116+
if (!alerts["Offroad_ExcessiveActuation"]->text().isEmpty()) {
117+
action_btn->setText(tr("Acknowledge Excessive Actuation"));
118+
} else {
119+
action_btn->setText(tr("Snooze Update"));
120+
}
121+
111122
return alertCount;
112123
}
113124

selfdrive/ui/qt/widgets/offroad_alerts.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,10 @@ class AbstractAlert : public QFrame {
1515
protected:
1616
AbstractAlert(bool hasRebootBtn, QWidget *parent = nullptr);
1717

18-
QPushButton *snooze_btn;
18+
QPushButton *action_btn;
1919
QVBoxLayout *scrollable_layout;
2020
Params params;
21+
std::map<std::string, QLabel*> alerts;
2122

2223
signals:
2324
void dismiss();
@@ -40,7 +41,4 @@ class OffroadAlert : public AbstractAlert {
4041
public:
4142
explicit OffroadAlert(QWidget *parent = 0) : AbstractAlert(false, parent) {}
4243
int refresh();
43-
44-
private:
45-
std::map<std::string, QLabel*> alerts;
4644
};

system/hardware/hardwared.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,7 @@ def hardware_thread(end_event, hw_queue) -> None:
303303
# **** starting logic ****
304304

305305
startup_conditions["up_to_date"] = params.get("Offroad_ConnectivityNeeded") is None or params.get_bool("DisableUpdates") or params.get_bool("SnoozeUpdate")
306+
startup_conditions["no_excessive_actuation"] = params.get("Offroad_ExcessiveActuation") is None
306307
startup_conditions["not_uninstalling"] = not params.get_bool("DoUninstall")
307308
startup_conditions["accepted_terms"] = params.get("HasAcceptedTerms") == terms_version
308309

0 commit comments

Comments
 (0)