Alert cleanup (#2274)

* no more focus recover active

* consistency

* more permanent

* dm alerts

* sanity check test

* no please

* clean that up

* update refs

* one more

* bump cereal
old-commit-hash: ae4b4bd125
commatwo_master
Adeeb Shihadeh 5 years ago committed by GitHub
parent 9118c3377d
commit aea2faaa98
  1. 2
      cereal
  2. 7
      selfdrive/controls/controlsd.py
  3. 110
      selfdrive/controls/lib/events.py
  4. 27
      selfdrive/controls/tests/test_alerts.py
  5. 2
      selfdrive/test/process_replay/ref_commit

@ -1 +1 @@
Subproject commit 32024acdc0fe2147f6aa62a61a5609dad56bc4f6 Subproject commit 1e7810dbbfe31003b85f11f948ac6e03b1134570

@ -52,7 +52,7 @@ class Controls:
self.sm = sm self.sm = sm
if self.sm is None: if self.sm is None:
self.sm = messaging.SubMaster(['thermal', 'health', 'frame', 'model', 'liveCalibration', self.sm = messaging.SubMaster(['thermal', 'health', 'model', 'liveCalibration',
'dMonitoringState', 'plan', 'pathPlan', 'liveLocationKalman']) 'dMonitoringState', 'plan', 'pathPlan', 'liveLocationKalman'])
self.can_sock = can_sock self.can_sock = can_sock
@ -227,9 +227,6 @@ class Controls:
self.events.add(EventName.posenetInvalid) self.events.add(EventName.posenetInvalid)
if not self.sm['liveLocationKalman'].deviceStable: if not self.sm['liveLocationKalman'].deviceStable:
self.events.add(EventName.deviceFalling) self.events.add(EventName.deviceFalling)
if not self.sm['frame'].recoverState < 2:
# counter>=2 is active
self.events.add(EventName.focusRecoverActive)
if not self.sm['plan'].radarValid: if not self.sm['plan'].radarValid:
self.events.add(EventName.radarFault) self.events.add(EventName.radarFault)
if self.sm['plan'].radarCanError: if self.sm['plan'].radarCanError:
@ -447,7 +444,7 @@ class Controls:
if CC.hudControl.rightLaneDepart or CC.hudControl.leftLaneDepart: if CC.hudControl.rightLaneDepart or CC.hudControl.leftLaneDepart:
self.events.add(EventName.ldw) self.events.add(EventName.ldw)
clear_event = ET.WARNING if ET.WARNING in self.current_alert_types else None clear_event = ET.WARNING if ET.WARNING not in self.current_alert_types else None
alerts = self.events.create_alerts(self.current_alert_types, [self.CP, self.sm, self.is_metric]) alerts = self.events.create_alerts(self.current_alert_types, [self.CP, self.sm, self.is_metric])
self.AM.add_many(self.sm.frame, alerts, self.enabled) self.AM.add_many(self.sm.frame, alerts, self.enabled)
self.AM.process_alerts(self.sm.frame, clear_event) self.AM.process_alerts(self.sm.frame, clear_event)

@ -167,6 +167,11 @@ class EngagementAlert(Alert):
Priority.MID, VisualAlert.none, Priority.MID, VisualAlert.none,
audible_alert, .2, 0., 0.), audible_alert, .2, 0., 0.),
class NormalPermanentAlert(Alert):
def __init__(self, alert_text_1, alert_text_2):
super().__init__(alert_text_1, alert_text_2,
AlertStatus.normal, AlertSize.mid,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2),
# ********** alert callback functions ********** # ********** alert callback functions **********
@ -257,11 +262,11 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
EventName.whitePandaUnsupported: { EventName.whitePandaUnsupported: {
ET.PERMANENT: Alert( ET.PERMANENT: Alert(
"White Panda Is No Longer Supported", "White Panda No Longer Supported",
"Upgrade to comma two or black panda", "Upgrade to comma two or black panda",
AlertStatus.normal, AlertSize.mid, AlertStatus.normal, AlertSize.mid,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2), Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2),
ET.NO_ENTRY: NoEntryAlert("White panda is no longer supported"), ET.NO_ENTRY: NoEntryAlert("Unsupported Hardware"),
}, },
EventName.invalidLkasSetting: { EventName.invalidLkasSetting: {
@ -352,13 +357,13 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
"KEEP EYES ON ROAD: Driver Distracted", "KEEP EYES ON ROAD: Driver Distracted",
"", "",
AlertStatus.normal, AlertSize.small, AlertStatus.normal, AlertSize.small,
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.none, .0, .1, .1, alert_rate=0.75), Priority.LOW, VisualAlert.steerRequired, AudibleAlert.none, .0, .1, .1),
}, },
EventName.promptDriverDistracted: { EventName.promptDriverDistracted: {
ET.WARNING: Alert( ET.WARNING: Alert(
"KEEP EYES ON ROAD", "KEEP EYES ON ROAD",
"Driver Appears Distracted", "Driver Distracted",
AlertStatus.userPrompt, AlertSize.mid, AlertStatus.userPrompt, AlertSize.mid,
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarning2Repeat, .1, .1, .1), Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarning2Repeat, .1, .1, .1),
}, },
@ -366,7 +371,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
EventName.driverDistracted: { EventName.driverDistracted: {
ET.WARNING: Alert( ET.WARNING: Alert(
"DISENGAGE IMMEDIATELY", "DISENGAGE IMMEDIATELY",
"Driver Was Distracted", "Driver Distracted",
AlertStatus.critical, AlertSize.full, AlertStatus.critical, AlertSize.full,
Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, .1, .1), Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, .1, .1),
}, },
@ -382,7 +387,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
EventName.promptDriverUnresponsive: { EventName.promptDriverUnresponsive: {
ET.WARNING: Alert( ET.WARNING: Alert(
"TOUCH STEERING WHEEL", "TOUCH STEERING WHEEL",
"Driver Is Unresponsive", "Driver Unresponsive",
AlertStatus.userPrompt, AlertSize.mid, AlertStatus.userPrompt, AlertSize.mid,
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarning2Repeat, .1, .1, .1), Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarning2Repeat, .1, .1, .1),
}, },
@ -390,7 +395,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
EventName.driverUnresponsive: { EventName.driverUnresponsive: {
ET.WARNING: Alert( ET.WARNING: Alert(
"DISENGAGE IMMEDIATELY", "DISENGAGE IMMEDIATELY",
"Driver Was Unresponsive", "Driver Unresponsive",
AlertStatus.critical, AlertSize.full, AlertStatus.critical, AlertSize.full,
Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, .1, .1), Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeat, .1, .1, .1),
}, },
@ -398,7 +403,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
EventName.driverMonitorLowAcc: { EventName.driverMonitorLowAcc: {
ET.WARNING: Alert( ET.WARNING: Alert(
"CHECK DRIVER FACE VISIBILITY", "CHECK DRIVER FACE VISIBILITY",
"Driver Monitor Model Output Uncertain", "Driver Monitoring Uncertain",
AlertStatus.normal, AlertSize.mid, AlertStatus.normal, AlertSize.mid,
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.none, .4, 0., 1.5), Priority.LOW, VisualAlert.steerRequired, AudibleAlert.none, .4, 0., 1.5),
}, },
@ -460,15 +465,11 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
"TAKE CONTROL", "TAKE CONTROL",
"Turn Exceeds Steering Limit", "Turn Exceeds Steering Limit",
AlertStatus.userPrompt, AlertSize.mid, AlertStatus.userPrompt, AlertSize.mid,
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimePrompt, 1., 2., 3.), Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimePrompt, 1., 1., 1.),
}, },
EventName.fanMalfunction: { EventName.fanMalfunction: {
ET.PERMANENT: Alert( ET.PERMANENT: NormalPermanentAlert("Fan Malfunction", "Contact Support"),
"Fan Malfunction",
"Contact Support",
AlertStatus.normal, AlertSize.mid,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2)
}, },
# ********** events that affect controls state transitions ********** # ********** events that affect controls state transitions **********
@ -525,15 +526,12 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
duration_hud_alert=0.), duration_hud_alert=0.),
}, },
EventName.focusRecoverActive: {
ET.WARNING: Alert(
"TAKE CONTROL",
"Attempting Refocus: Camera Focus Invalid",
AlertStatus.userPrompt, AlertSize.mid,
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimeWarning1, .4, 2., 3., creation_delay=3.1),
},
EventName.outOfSpace: { EventName.outOfSpace: {
ET.PERMANENT: Alert(
"Out of Storage",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2),
ET.NO_ENTRY: NoEntryAlert("Out of Storage Space", ET.NO_ENTRY: NoEntryAlert("Out of Storage Space",
duration_hud_alert=0.), duration_hud_alert=0.),
}, },
@ -542,15 +540,6 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
ET.NO_ENTRY: NoEntryAlert("Speed Too Low"), ET.NO_ENTRY: NoEntryAlert("Speed Too Low"),
}, },
EventName.neosUpdateRequired: {
ET.PERMANENT: Alert(
"NEOS Update Required",
"Please Wait for Update",
AlertStatus.normal, AlertSize.mid,
Priority.HIGHEST, VisualAlert.none, AudibleAlert.none, 0., 0., .2),
ET.NO_ENTRY: NoEntryAlert("NEOS Update Required"),
},
EventName.sensorDataInvalid: { EventName.sensorDataInvalid: {
ET.PERMANENT: Alert( ET.PERMANENT: Alert(
"No Data from Device Sensors", "No Data from Device Sensors",
@ -565,11 +554,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
}, },
EventName.soundsUnavailable: { EventName.soundsUnavailable: {
ET.PERMANENT: Alert( ET.PERMANENT: NormalPermanentAlert("Speaker not found", "Reboot your Device"),
"Speaker not found",
"Reboot your Device",
AlertStatus.normal, AlertSize.mid,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2),
ET.NO_ENTRY: NoEntryAlert("Speaker not found"), ET.NO_ENTRY: NoEntryAlert("Speaker not found"),
}, },
@ -578,8 +563,13 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
}, },
EventName.overheat: { EventName.overheat: {
ET.PERMANENT: Alert(
"System Overheated",
"",
AlertStatus.normal, AlertSize.small,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2),
ET.SOFT_DISABLE: SoftDisableAlert("System Overheated"), ET.SOFT_DISABLE: SoftDisableAlert("System Overheated"),
ET.NO_ENTRY: NoEntryAlert("System overheated"), ET.NO_ENTRY: NoEntryAlert("System Overheated"),
}, },
EventName.wrongGear: { EventName.wrongGear: {
@ -588,29 +578,25 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
}, },
EventName.calibrationInvalid: { EventName.calibrationInvalid: {
ET.PERMANENT: Alert( ET.PERMANENT: NormalPermanentAlert("Calibration Invalid", "Remount Device and Recalibrate"),
"Calibration Invalid", ET.SOFT_DISABLE: SoftDisableAlert("Calibration Invalid: Remount Device & Recalibrate"),
"Reposition Device and Recalibrate", ET.NO_ENTRY: NoEntryAlert("Calibration Invalid: Remount Device & Recalibrate"),
AlertStatus.normal, AlertSize.mid,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2),
ET.SOFT_DISABLE: SoftDisableAlert("Calibration Invalid: Reposition Device & Recalibrate"),
ET.NO_ENTRY: NoEntryAlert("Calibration Invalid: Reposition Device & Recalibrate"),
}, },
EventName.calibrationIncomplete: { EventName.calibrationIncomplete: {
ET.SOFT_DISABLE: SoftDisableAlert("Calibration in Progress"),
ET.PERMANENT: calibration_incomplete_alert, ET.PERMANENT: calibration_incomplete_alert,
ET.SOFT_DISABLE: SoftDisableAlert("Calibration in Progress"),
ET.NO_ENTRY: NoEntryAlert("Calibration in Progress"), ET.NO_ENTRY: NoEntryAlert("Calibration in Progress"),
}, },
EventName.doorOpen: { EventName.doorOpen: {
ET.SOFT_DISABLE: SoftDisableAlert("Door Open"), ET.SOFT_DISABLE: SoftDisableAlert("Door Open"),
ET.NO_ENTRY: NoEntryAlert("Door open"), ET.NO_ENTRY: NoEntryAlert("Door Open"),
}, },
EventName.seatbeltNotLatched: { EventName.seatbeltNotLatched: {
ET.SOFT_DISABLE: SoftDisableAlert("Seatbelt Unlatched"), ET.SOFT_DISABLE: SoftDisableAlert("Seatbelt Unlatched"),
ET.NO_ENTRY: NoEntryAlert("Seatbelt unlatched"), ET.NO_ENTRY: NoEntryAlert("Seatbelt Unlatched"),
}, },
EventName.espDisabled: { EventName.espDisabled: {
@ -651,8 +637,8 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
}, },
EventName.posenetInvalid: { EventName.posenetInvalid: {
ET.SOFT_DISABLE: SoftDisableAlert("Vision Model Output Uncertain"), ET.SOFT_DISABLE: SoftDisableAlert("Model Output Uncertain"),
ET.NO_ENTRY: NoEntryAlert("Vision Model Output Uncertain"), ET.NO_ENTRY: NoEntryAlert("Model Output Uncertain"),
}, },
EventName.deviceFalling: { EventName.deviceFalling: {
@ -662,11 +648,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
EventName.lowMemory: { EventName.lowMemory: {
ET.SOFT_DISABLE: SoftDisableAlert("Low Memory: Reboot Your Device"), ET.SOFT_DISABLE: SoftDisableAlert("Low Memory: Reboot Your Device"),
ET.PERMANENT: Alert( ET.PERMANENT: NormalPermanentAlert("Low Memory", "Reboot your Device"),
"RAM Critically Low",
"Reboot your Device",
AlertStatus.normal, AlertSize.mid,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2),
ET.NO_ENTRY : NoEntryAlert("Low Memory: Reboot Your Device", ET.NO_ENTRY : NoEntryAlert("Low Memory: Reboot Your Device",
audible_alert=AudibleAlert.chimeDisengage), audible_alert=AudibleAlert.chimeDisengage),
}, },
@ -710,11 +692,6 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
ET.NO_ENTRY: NoEntryAlert("Cruise Fault: Restart the Car"), ET.NO_ENTRY: NoEntryAlert("Cruise Fault: Restart the Car"),
}, },
EventName.gasUnavailable: {
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Gas Fault: Restart the Car"),
ET.NO_ENTRY: NoEntryAlert("Gas Error: Restart the Car"),
},
EventName.reverseGear: { EventName.reverseGear: {
ET.PERMANENT: Alert( ET.PERMANENT: Alert(
"Reverse\nGear", "Reverse\nGear",
@ -736,11 +713,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
EventName.relayMalfunction: { EventName.relayMalfunction: {
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Harness Malfunction"), ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Harness Malfunction"),
ET.PERMANENT: Alert( ET.PERMANENT: NormalPermanentAlert("Harness Malfunction", "Check Hardware"),
"Harness Malfunction",
"Please Check Hardware",
AlertStatus.normal, AlertSize.mid,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2),
ET.NO_ENTRY: NoEntryAlert("Harness Malfunction"), ET.NO_ENTRY: NoEntryAlert("Harness Malfunction"),
}, },
@ -774,13 +747,10 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.), Priority.LOW, VisualAlert.none, AudibleAlert.chimeError, .4, 2., 3.),
}, },
# TODO: this is unclear, update check only happens offroad
EventName.internetConnectivityNeeded: { EventName.internetConnectivityNeeded: {
ET.PERMANENT: Alert( ET.PERMANENT: NormalPermanentAlert("Connect to Internet", "An Update Check Is Required to Engage"),
"Please connect to Internet", ET.NO_ENTRY: NoEntryAlert("Connect to Internet",
"An Update Check Is Required to Engage",
AlertStatus.normal, AlertSize.mid,
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2),
ET.NO_ENTRY: NoEntryAlert("Please Connect to Internet",
audible_alert=AudibleAlert.chimeDisengage), audible_alert=AudibleAlert.chimeDisengage),
}, },

@ -15,6 +15,14 @@ AlertSize = log.ControlsState.AlertSize
OFFROAD_ALERTS_PATH = os.path.join(BASEDIR, "selfdrive/controls/lib/alerts_offroad.json") OFFROAD_ALERTS_PATH = os.path.join(BASEDIR, "selfdrive/controls/lib/alerts_offroad.json")
# TODO: add callback alerts
ALERTS = []
for event_types in EVENTS.values():
for alert in event_types.values():
if isinstance(alert, Alert):
ALERTS.append(alert)
class TestAlerts(unittest.TestCase): class TestAlerts(unittest.TestCase):
@classmethod @classmethod
@ -50,13 +58,7 @@ class TestAlerts(unittest.TestCase):
ImageFont.truetype(regular_font_path, int(36 * font_scale_factor))], ImageFont.truetype(regular_font_path, int(36 * font_scale_factor))],
} }
alerts = [] for alert in ALERTS:
for event_types in EVENTS.values():
for alert in event_types.values():
if isinstance(alert, Alert):
alerts.append(alert)
for alert in alerts:
# for full size alerts, both text fields wrap the text, # for full size alerts, both text fields wrap the text,
# so it's unlikely that they would go past the max width # so it's unlikely that they would go past the max width
if alert.alert_size in [AlertSize.none, AlertSize.full]: if alert.alert_size in [AlertSize.none, AlertSize.full]:
@ -71,6 +73,17 @@ class TestAlerts(unittest.TestCase):
msg = "type: %s msg: %s" % (alert.alert_type, txt) msg = "type: %s msg: %s" % (alert.alert_type, txt)
self.assertLessEqual(w, max_text_width, msg=msg) self.assertLessEqual(w, max_text_width, msg=msg)
def test_alert_sanity_check(self):
for a in ALERTS:
if a.alert_size == AlertSize.none:
self.assertEqual(0, len(a.alert_text_1))
self.assertEqual(0, len(a.alert_text_2))
else:
if a.alert_size == AlertSize.small:
self.assertEqual(0, len(a.alert_text_2))
self.assertTrue(all([n >= 0. for n in [a.duration_sound, a.duration_hud_alert, a.duration_text]]))
def test_offroad_alerts(self): def test_offroad_alerts(self):
params = Params() params = Params()
for a in self.offroad_alerts: for a in self.offroad_alerts:

@ -1 +1 @@
6f90ffa4970c48edc018ee733bf81b3231b4c463 fe7f0cbcead73a8ee5f91507238b933505bb53de
Loading…
Cancel
Save