mirror of
https://github.com/dragonpilot/dragonpilot.git
synced 2026-06-26 16:32:06 +08:00
Alerts documentation (#21172)
* Alerts documentation * fingerprinting * comment not necessary * spelling * openpilot * Apply suggestions from code review Co-authored-by: Chris McCammon <chrismccammon123@gmail.com> * Apply suggestions from code review Co-authored-by: Chris McCammon <chrismccammon123@gmail.com>
This commit is contained in:
@@ -13,6 +13,7 @@ VisualAlert = car.CarControl.HUDControl.VisualAlert
|
||||
AudibleAlert = car.CarControl.HUDControl.AudibleAlert
|
||||
EventName = car.CarEvent.EventName
|
||||
|
||||
|
||||
# Alert priorities
|
||||
class Priority(IntEnum):
|
||||
LOWEST = 0
|
||||
@@ -22,6 +23,7 @@ class Priority(IntEnum):
|
||||
HIGH = 4
|
||||
HIGHEST = 5
|
||||
|
||||
|
||||
# Event types
|
||||
class ET:
|
||||
ENABLE = 'enable'
|
||||
@@ -33,6 +35,7 @@ class ET:
|
||||
IMMEDIATE_DISABLE = 'immediateDisable'
|
||||
PERMANENT = 'permanent'
|
||||
|
||||
|
||||
# get event name from enum
|
||||
EVENT_NAME = {v: k for k, v in EventName.schema.enumerants.items()}
|
||||
|
||||
@@ -56,7 +59,7 @@ class Events:
|
||||
self.events.append(event_name)
|
||||
|
||||
def clear(self):
|
||||
self.events_prev = {k: (v+1 if k in self.events else 0) for k, v in self.events_prev.items()}
|
||||
self.events_prev = {k: (v + 1 if k in self.events else 0) for k, v in self.events_prev.items()}
|
||||
self.events = self.static_events.copy()
|
||||
|
||||
def any(self, event_type):
|
||||
@@ -94,10 +97,11 @@ class Events:
|
||||
event = car.CarEvent.new_message()
|
||||
event.name = event_name
|
||||
for event_type in EVENTS.get(event_name, {}).keys():
|
||||
setattr(event, event_type , True)
|
||||
setattr(event, event_type, True)
|
||||
ret.append(event)
|
||||
return ret
|
||||
|
||||
|
||||
class Alert:
|
||||
def __init__(self,
|
||||
alert_text_1: str,
|
||||
@@ -138,6 +142,7 @@ class Alert:
|
||||
def __gt__(self, alert2) -> bool:
|
||||
return self.alert_priority > alert2.alert_priority
|
||||
|
||||
|
||||
class NoEntryAlert(Alert):
|
||||
def __init__(self, alert_text_2, audible_alert=AudibleAlert.chimeError,
|
||||
visual_alert=VisualAlert.none, duration_hud_alert=2.):
|
||||
@@ -161,6 +166,7 @@ class ImmediateDisableAlert(Alert):
|
||||
Priority.HIGHEST, VisualAlert.steerRequired,
|
||||
AudibleAlert.chimeWarningRepeat, 2.2, 3., 4.),
|
||||
|
||||
|
||||
class EngagementAlert(Alert):
|
||||
def __init__(self, audible_alert=True):
|
||||
super().__init__("", "",
|
||||
@@ -168,14 +174,15 @@ class EngagementAlert(Alert):
|
||||
Priority.MID, VisualAlert.none,
|
||||
audible_alert, .2, 0., 0.),
|
||||
|
||||
|
||||
class NormalPermanentAlert(Alert):
|
||||
def __init__(self, alert_text_1: str, alert_text_2: str, duration_text: float = 0.2):
|
||||
super().__init__(alert_text_1, alert_text_2,
|
||||
AlertStatus.normal, AlertSize.mid if len(alert_text_2) else AlertSize.small,
|
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., duration_text),
|
||||
|
||||
# ********** alert callback functions **********
|
||||
|
||||
# ********** alert callback functions **********
|
||||
def below_steer_speed_alert(CP: car.CarParams, sm: messaging.SubMaster, metric: bool) -> Alert:
|
||||
speed = int(round(CP.minSteerSpeed * (CV.MS_TO_KPH if metric else CV.MS_TO_MPH)))
|
||||
unit = "km/h" if metric else "mph"
|
||||
@@ -185,6 +192,7 @@ def below_steer_speed_alert(CP: car.CarParams, sm: messaging.SubMaster, metric:
|
||||
AlertStatus.userPrompt, AlertSize.mid,
|
||||
Priority.MID, VisualAlert.steerRequired, AudibleAlert.none, 0., 0.4, .3)
|
||||
|
||||
|
||||
def calibration_incomplete_alert(CP: car.CarParams, sm: messaging.SubMaster, metric: bool) -> Alert:
|
||||
speed = int(MIN_SPEED_FILTER * (CV.MS_TO_KPH if metric else CV.MS_TO_MPH))
|
||||
unit = "km/h" if metric else "mph"
|
||||
@@ -194,6 +202,7 @@ def calibration_incomplete_alert(CP: car.CarParams, sm: messaging.SubMaster, met
|
||||
AlertStatus.normal, AlertSize.mid,
|
||||
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, 0., 0., .2)
|
||||
|
||||
|
||||
def no_gps_alert(CP: car.CarParams, sm: messaging.SubMaster, metric: bool) -> Alert:
|
||||
gps_integrated = sm['pandaState'].pandaType in [log.PandaState.PandaType.uno, log.PandaState.PandaType.dos]
|
||||
return Alert(
|
||||
@@ -202,12 +211,14 @@ def no_gps_alert(CP: car.CarParams, sm: messaging.SubMaster, metric: bool) -> Al
|
||||
AlertStatus.normal, AlertSize.mid,
|
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2, creation_delay=300.)
|
||||
|
||||
|
||||
def wrong_car_mode_alert(CP: car.CarParams, sm: messaging.SubMaster, metric: bool) -> Alert:
|
||||
text = "Cruise Mode Disabled"
|
||||
if CP.carName == "honda":
|
||||
text = "Main Switch Off"
|
||||
return NoEntryAlert(text, duration_hud_alert=0.)
|
||||
|
||||
|
||||
def startup_fuzzy_fingerprint_alert(CP: car.CarParams, sm: messaging.SubMaster, metric: bool) -> Alert:
|
||||
return Alert(
|
||||
"WARNING: No Exact Match on Car Model",
|
||||
@@ -215,6 +226,7 @@ def startup_fuzzy_fingerprint_alert(CP: car.CarParams, sm: messaging.SubMaster,
|
||||
AlertStatus.userPrompt, AlertSize.mid,
|
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., 15.)
|
||||
|
||||
|
||||
EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, bool], Alert]]]] = {
|
||||
# ********** events with no alerts **********
|
||||
|
||||
@@ -248,6 +260,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
|
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., 15.),
|
||||
},
|
||||
|
||||
# Car is recognized, but marked as dashcam only
|
||||
EventName.startupNoControl: {
|
||||
ET.PERMANENT: Alert(
|
||||
"Dashcam mode",
|
||||
@@ -256,6 +269,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
|
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., 15.),
|
||||
},
|
||||
|
||||
# Car is not recognized
|
||||
EventName.startupNoCar: {
|
||||
ET.PERMANENT: Alert(
|
||||
"Dashcam mode for unsupported car",
|
||||
@@ -264,6 +278,14 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
|
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., 15.),
|
||||
},
|
||||
|
||||
# openpilot uses the version strings from various ECUs to detect the correct car model.
|
||||
# Usually all ECUs are recognized and an exact match to a car model can be made. Sometimes
|
||||
# one or two ECUs have unrecognized versions, but the others are present in the database.
|
||||
# If openpilot is confident about the match to a car model, it fingerprints anyway.
|
||||
# In this case an alert is thrown since there is a small chance the wrong car was detected
|
||||
# and the user should pay extra attention.
|
||||
# This alert can be prevented by adding all ECU firmware version to openpilot:
|
||||
# https://github.com/commaai/openpilot/wiki/Fingerprinting
|
||||
EventName.startupFuzzyFingerprint: {
|
||||
ET.PERMANENT: startup_fuzzy_fingerprint_alert,
|
||||
},
|
||||
@@ -292,6 +314,9 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
|
||||
Priority.LOWER, VisualAlert.none, AudibleAlert.none, 0., 0., .2),
|
||||
},
|
||||
|
||||
# Some features or cars are marked as community features. If openpilot
|
||||
# detects the use of a community feature it switches to dashcam mode
|
||||
# until these features are allowed using a toggle in settings.
|
||||
EventName.communityFeatureDisallowed: {
|
||||
# LOW priority to overcome Cruise Error
|
||||
ET.PERMANENT: Alert(
|
||||
@@ -301,6 +326,9 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
|
||||
Priority.LOW, VisualAlert.none, AudibleAlert.none, 0., 0., .2),
|
||||
},
|
||||
|
||||
# openpilot doesn't recognize the car. This switches openpilot into a
|
||||
# read-only mode. This can be solved by adding your fingerprint.
|
||||
# See https://github.com/commaai/openpilot/wiki/Fingerprinting for more information
|
||||
EventName.carUnrecognized: {
|
||||
ET.PERMANENT: Alert(
|
||||
"Dashcam Mode",
|
||||
@@ -353,6 +381,14 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
|
||||
Priority.LOWEST, VisualAlert.none, AudibleAlert.none, .0, .0, .1, creation_delay=1.),
|
||||
},
|
||||
|
||||
# openpilot tries to learn certain parameters about your car by observing
|
||||
# how the car behaves to steering inputs from both human and openpilot driving.
|
||||
# This includes:
|
||||
# - steer ratio: gear ratio of the steering rack. Steering angle divided by tire angle
|
||||
# - tire stiffness: how much grip your tires have
|
||||
# - angle offset: most steering angle sensors are offset and measure a non zero angle when driving straight
|
||||
# This alert is thrown when any of these values exceed a sanity check. This can be caused by
|
||||
# bad alignment or bad sensor data. If this happens consistently consider creating an issue on GitHub
|
||||
EventName.vehicleModelInvalid: {
|
||||
ET.NO_ENTRY: NoEntryAlert("Vehicle Parameter Identification Failed"),
|
||||
ET.SOFT_DISABLE: SoftDisableAlert("Vehicle Parameter Identification Failed"),
|
||||
@@ -487,18 +523,24 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
|
||||
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimePrompt, 1., 1., 1.),
|
||||
},
|
||||
|
||||
# Thrown when the fan is driven at >50% but is not rotating
|
||||
EventName.fanMalfunction: {
|
||||
ET.PERMANENT: NormalPermanentAlert("Fan Malfunction", "Contact Support"),
|
||||
},
|
||||
|
||||
# Camera is not outputting frames at a constant framerate
|
||||
EventName.cameraMalfunction: {
|
||||
ET.PERMANENT: NormalPermanentAlert("Camera Malfunction", "Contact Support"),
|
||||
},
|
||||
|
||||
# Unused
|
||||
EventName.gpsMalfunction: {
|
||||
ET.PERMANENT: NormalPermanentAlert("GPS Malfunction", "Contact Support"),
|
||||
},
|
||||
|
||||
# When the GPS position and localizer diverge the localizer is reset to the
|
||||
# current GPS position. This alert is thrown when the localizer is reset
|
||||
# more often than expected.
|
||||
EventName.localizerMalfunction: {
|
||||
ET.PERMANENT: NormalPermanentAlert("Localizer unstable", "Contact Support"),
|
||||
},
|
||||
@@ -604,6 +646,11 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
|
||||
ET.NO_ENTRY: NoEntryAlert("Gear not D"),
|
||||
},
|
||||
|
||||
# This alert is thrown when the calibration angles are outside of the acceptable range.
|
||||
# For example if the device is pointed too much to the left or the right.
|
||||
# Usually this can only be solved by removing the mount from the windshield completely,
|
||||
# and attaching while making sure the device is pointed straight forward and is level.
|
||||
# See https://comma.ai/setup for more information
|
||||
EventName.calibrationInvalid: {
|
||||
ET.PERMANENT: NormalPermanentAlert("Calibration Invalid", "Remount Device and Recalibrate"),
|
||||
ET.SOFT_DISABLE: SoftDisableAlert("Calibration Invalid: Remount Device & Recalibrate"),
|
||||
@@ -636,12 +683,17 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
|
||||
ET.NO_ENTRY: NoEntryAlert("Low Battery"),
|
||||
},
|
||||
|
||||
# Different openpilot services communicate between each other at a certain
|
||||
# interval. If communication does not follow the regular schedule this alert
|
||||
# is thrown. This can mean a service crashed, did not broadcast a message for
|
||||
# ten times the regular interval, or the average interval is more than 10% too high.
|
||||
EventName.commIssue: {
|
||||
ET.SOFT_DISABLE: SoftDisableAlert("Communication Issue between Processes"),
|
||||
ET.NO_ENTRY: NoEntryAlert("Communication Issue between Processes",
|
||||
audible_alert=AudibleAlert.chimeDisengage),
|
||||
},
|
||||
|
||||
# Thrown when manager detects a service exited unexpectedly while driving
|
||||
EventName.processNotRunning: {
|
||||
ET.NO_ENTRY: NoEntryAlert("System Malfunction: Reboot Your Device",
|
||||
audible_alert=AudibleAlert.chimeDisengage),
|
||||
@@ -649,19 +701,29 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
|
||||
|
||||
EventName.radarFault: {
|
||||
ET.SOFT_DISABLE: SoftDisableAlert("Radar Error: Restart the Car"),
|
||||
ET.NO_ENTRY : NoEntryAlert("Radar Error: Restart the Car"),
|
||||
ET.NO_ENTRY: NoEntryAlert("Radar Error: Restart the Car"),
|
||||
},
|
||||
|
||||
# Every frame from the camera should be processed by the model. If modeld
|
||||
# is not processing frames fast enough they have to be dropped. This alert is
|
||||
# thrown when over 20% of frames are dropped.
|
||||
EventName.modeldLagging: {
|
||||
ET.SOFT_DISABLE: SoftDisableAlert("Driving model lagging"),
|
||||
ET.NO_ENTRY : NoEntryAlert("Driving model lagging"),
|
||||
ET.NO_ENTRY: NoEntryAlert("Driving model lagging"),
|
||||
},
|
||||
|
||||
# Besides predicting the path, lane lines and lead car data the model also
|
||||
# predicts the current velocity and rotation speed of the car. If the model is
|
||||
# very uncertain about the current velocity while the car is moving, this
|
||||
# usually means the model has trouble understanding the scene. This is used
|
||||
# as a heuristic to warn the driver.
|
||||
EventName.posenetInvalid: {
|
||||
ET.SOFT_DISABLE: SoftDisableAlert("Model Output Uncertain"),
|
||||
ET.NO_ENTRY: NoEntryAlert("Model Output Uncertain"),
|
||||
},
|
||||
|
||||
# When the localizer detects an acceleration of more than 40 m/s^2 (~4G) we
|
||||
# alert the driver the device might have fallen from the windshield.
|
||||
EventName.deviceFalling: {
|
||||
ET.SOFT_DISABLE: SoftDisableAlert("Device Fell Off Mount"),
|
||||
ET.NO_ENTRY: NoEntryAlert("Device Fell Off Mount"),
|
||||
@@ -670,7 +732,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
|
||||
EventName.lowMemory: {
|
||||
ET.SOFT_DISABLE: SoftDisableAlert("Low Memory: Reboot Your Device"),
|
||||
ET.PERMANENT: NormalPermanentAlert("Low Memory", "Reboot your Device"),
|
||||
ET.NO_ENTRY : NoEntryAlert("Low Memory: Reboot Your Device",
|
||||
ET.NO_ENTRY: NoEntryAlert("Low Memory: Reboot Your Device",
|
||||
audible_alert=AudibleAlert.chimeDisengage),
|
||||
},
|
||||
|
||||
@@ -699,12 +761,18 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
|
||||
duration_text=10.),
|
||||
},
|
||||
|
||||
# Sometimes the USB stack on the device can get into a bad state
|
||||
# causing the connection to the panda to be lost
|
||||
EventName.usbError: {
|
||||
ET.SOFT_DISABLE: SoftDisableAlert("USB Error: Reboot Your Device"),
|
||||
ET.PERMANENT: NormalPermanentAlert("USB Error: Reboot Your Device", ""),
|
||||
ET.NO_ENTRY: NoEntryAlert("USB Error: Reboot Your Device"),
|
||||
},
|
||||
|
||||
# This alert can be thrown for the following reasons:
|
||||
# - No CAN data received at all
|
||||
# - CAN data is received, but some message are not received at the right frequency
|
||||
# If you're not writing a new car port, this is usually cause by faulty wiring
|
||||
EventName.canError: {
|
||||
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("CAN Error: Check Connections"),
|
||||
ET.PERMANENT: Alert(
|
||||
@@ -745,15 +813,24 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
|
||||
ET.NO_ENTRY: NoEntryAlert("Reverse Gear"),
|
||||
},
|
||||
|
||||
# On cars that use stock ACC the car can decide to cancel ACC for various reasons.
|
||||
# When this happens we can no long control the car so the user needs to be warned immediately.
|
||||
EventName.cruiseDisabled: {
|
||||
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Cruise Is Off"),
|
||||
},
|
||||
|
||||
# For planning the trajectory Model Predictive Control (MPC) is used. This is
|
||||
# an optimization algorithm that is not guaranteed to find a feasible solution.
|
||||
# If no solution is found or the solution has a very high cost this alert is thrown.
|
||||
EventName.plannerError: {
|
||||
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Planner Solution Error"),
|
||||
ET.NO_ENTRY: NoEntryAlert("Planner Solution Error"),
|
||||
},
|
||||
|
||||
# When the relay in the harness box opens the CAN bus between the LKAS camera
|
||||
# and the rest of the car is separated. When messages from the LKAS camera
|
||||
# are received on the car side this usually means the relay hasn't opened correctly
|
||||
# and this alert is thrown.
|
||||
EventName.relayMalfunction: {
|
||||
ET.IMMEDIATE_DISABLE: ImmediateDisableAlert("Harness Malfunction"),
|
||||
ET.PERMANENT: NormalPermanentAlert("Harness Malfunction", "Check Hardware"),
|
||||
@@ -766,7 +843,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
|
||||
"No close lead car",
|
||||
AlertStatus.normal, AlertSize.mid,
|
||||
Priority.HIGH, VisualAlert.none, AudibleAlert.chimeDisengage, .4, 2., 3.),
|
||||
ET.NO_ENTRY : NoEntryAlert("No Close Lead Car"),
|
||||
ET.NO_ENTRY: NoEntryAlert("No Close Lead Car"),
|
||||
},
|
||||
|
||||
EventName.speedTooLow: {
|
||||
@@ -777,6 +854,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
|
||||
Priority.HIGH, VisualAlert.none, AudibleAlert.chimeDisengage, .4, 2., 3.),
|
||||
},
|
||||
|
||||
# When the car is driving faster than most cars in the training data the model outputs can be unpredictable
|
||||
EventName.speedTooHigh: {
|
||||
ET.WARNING: Alert(
|
||||
"Speed Too High",
|
||||
|
||||
Reference in New Issue
Block a user