New sounds (#22652)

* new engage/disengage + amp config

* first family

* cleanup audible alerts

* tici isn't special

* fix up debug cycle alerts

* these were better

* extend range

* use distracted sound

* log scaling

* getting closer

* slightly louder

* prompt

* update tests

* update refs

* fix c2 test

* resolve todo

* adjust tolerance

* revert for now

* should work

Co-authored-by: Comma Device <device@comma.ai>
pull/23092/head
Adeeb Shihadeh 2021-11-30 19:47:33 -08:00 committed by GitHub
parent b3b5beb627
commit e679d05d9e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 132 additions and 115 deletions

2
cereal

@ -1 +1 @@
Subproject commit d6f233bf7bd6d1ee3508b17667e44420ce38de0d Subproject commit 9ce45916c6c27e8cfbbe2aa6b796fac41eeeba00

View File

@ -4,7 +4,6 @@ selfdrive/timezoned.py
selfdrive/assets/navigation/* selfdrive/assets/navigation/*
selfdrive/assets/training_wide/* selfdrive/assets/training_wide/*
selfdrive/assets/sounds_tici/*
selfdrive/camerad/cameras/camera_qcom2.cc selfdrive/camerad/cameras/camera_qcom2.cc
selfdrive/camerad/cameras/camera_qcom2.h selfdrive/camerad/cameras/camera_qcom2.h

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -41,6 +41,7 @@ class AlertManager:
self.activealerts: Dict[str, AlertEntry] = defaultdict(AlertEntry) self.activealerts: Dict[str, AlertEntry] = defaultdict(AlertEntry)
def reset(self) -> None: def reset(self) -> None:
self.alert: Optional[Alert] = None
self.alert_type: str = "" self.alert_type: str = ""
self.alert_text_1: str = "" self.alert_text_1: str = ""
self.alert_text_2: str = "" self.alert_text_2: str = ""
@ -74,13 +75,13 @@ class AlertManager:
# clear current alert # clear current alert
self.reset() self.reset()
a = current_alert.alert self.alert = current_alert.alert
if a is not None: if self.alert is not None:
self.alert_type = a.alert_type self.alert_type = self.alert.alert_type
self.audible_alert = a.audible_alert self.audible_alert = self.alert.audible_alert
self.visual_alert = a.visual_alert self.visual_alert = self.alert.visual_alert
self.alert_text_1 = a.alert_text_1 self.alert_text_1 = self.alert.alert_text_1
self.alert_text_2 = a.alert_text_2 self.alert_text_2 = self.alert.alert_text_2
self.alert_status = a.alert_status self.alert_status = self.alert.alert_status
self.alert_size = a.alert_size self.alert_size = self.alert.alert_size
self.alert_rate = a.alert_rate self.alert_rate = self.alert.alert_rate

View File

@ -139,11 +139,10 @@ class Alert:
class NoEntryAlert(Alert): class NoEntryAlert(Alert):
def __init__(self, alert_text_2, audible_alert=AudibleAlert.chimeError, def __init__(self, alert_text_2, visual_alert=VisualAlert.none):
visual_alert=VisualAlert.none):
super().__init__("openpilot Unavailable", alert_text_2, AlertStatus.normal, super().__init__("openpilot Unavailable", alert_text_2, AlertStatus.normal,
AlertSize.mid, Priority.LOW, visual_alert, AlertSize.mid, Priority.LOW, visual_alert,
audible_alert, 3.) AudibleAlert.refuse, 3.)
class SoftDisableAlert(Alert): class SoftDisableAlert(Alert):
@ -151,7 +150,7 @@ class SoftDisableAlert(Alert):
super().__init__("TAKE CONTROL IMMEDIATELY", alert_text_2, super().__init__("TAKE CONTROL IMMEDIATELY", alert_text_2,
AlertStatus.userPrompt, AlertSize.full, AlertStatus.userPrompt, AlertSize.full,
Priority.MID, VisualAlert.steerRequired, Priority.MID, VisualAlert.steerRequired,
AudibleAlert.chimeWarningRepeatInfinite, 2.), AudibleAlert.warningSoft, 2.),
class ImmediateDisableAlert(Alert): class ImmediateDisableAlert(Alert):
@ -159,7 +158,7 @@ class ImmediateDisableAlert(Alert):
super().__init__("TAKE CONTROL IMMEDIATELY", alert_text_2, super().__init__("TAKE CONTROL IMMEDIATELY", alert_text_2,
AlertStatus.critical, AlertSize.full, AlertStatus.critical, AlertSize.full,
Priority.HIGHEST, VisualAlert.steerRequired, Priority.HIGHEST, VisualAlert.steerRequired,
AudibleAlert.chimeWarningRepeatInfinite, 4.), AudibleAlert.warningImmediate, 4.),
class EngagementAlert(Alert): class EngagementAlert(Alert):
@ -201,7 +200,7 @@ def below_steer_speed_alert(CP: car.CarParams, sm: messaging.SubMaster, metric:
f"Steer Unavailable Below {get_display_speed(CP.minSteerSpeed, metric)}", f"Steer Unavailable Below {get_display_speed(CP.minSteerSpeed, metric)}",
"", "",
AlertStatus.userPrompt, AlertSize.small, AlertStatus.userPrompt, AlertSize.small,
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimePrompt, 0.4) Priority.MID, VisualAlert.steerRequired, AudibleAlert.prompt, 0.4)
def calibration_incomplete_alert(CP: car.CarParams, sm: messaging.SubMaster, metric: bool) -> Alert: def calibration_incomplete_alert(CP: car.CarParams, sm: messaging.SubMaster, metric: bool) -> Alert:
@ -321,7 +320,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
"BRAKE!", "BRAKE!",
"Risk of Collision", "Risk of Collision",
AlertStatus.critical, AlertSize.full, AlertStatus.critical, AlertSize.full,
Priority.HIGHEST, VisualAlert.fcw, AudibleAlert.chimeWarningRepeatInfinite, 2.), Priority.HIGHEST, VisualAlert.fcw, AudibleAlert.warningSoft, 2.),
}, },
EventName.ldw: { EventName.ldw: {
@ -329,7 +328,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
"TAKE CONTROL", "TAKE CONTROL",
"Lane Departure Detected", "Lane Departure Detected",
AlertStatus.userPrompt, AlertSize.mid, AlertStatus.userPrompt, AlertSize.mid,
Priority.LOW, VisualAlert.ldw, AudibleAlert.chimePrompt, 3.), Priority.LOW, VisualAlert.ldw, AudibleAlert.prompt, 3.),
}, },
# ********** events only containing alerts that display while engaged ********** # ********** events only containing alerts that display while engaged **********
@ -360,7 +359,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
"Steering Temporarily Unavailable", "Steering Temporarily Unavailable",
"", "",
AlertStatus.userPrompt, AlertSize.small, AlertStatus.userPrompt, AlertSize.small,
Priority.LOW, VisualAlert.steerRequired, AudibleAlert.chimePrompt, 1.), Priority.LOW, VisualAlert.steerRequired, AudibleAlert.prompt, 1.),
}, },
EventName.preDriverDistracted: { EventName.preDriverDistracted: {
@ -376,7 +375,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
"KEEP EYES ON ROAD", "KEEP EYES ON ROAD",
"Driver Distracted", "Driver Distracted",
AlertStatus.userPrompt, AlertSize.mid, AlertStatus.userPrompt, AlertSize.mid,
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarning2RepeatInfinite, .1), Priority.MID, VisualAlert.steerRequired, AudibleAlert.prompt, .1),
}, },
EventName.driverDistracted: { EventName.driverDistracted: {
@ -384,7 +383,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
"DISENGAGE IMMEDIATELY", "DISENGAGE IMMEDIATELY",
"Driver Distracted", "Driver Distracted",
AlertStatus.critical, AlertSize.full, AlertStatus.critical, AlertSize.full,
Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeatInfinite, .1), Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.warningImmediate, .1),
}, },
EventName.preDriverUnresponsive: { EventName.preDriverUnresponsive: {
@ -400,7 +399,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
"TOUCH STEERING WHEEL", "TOUCH STEERING WHEEL",
"Driver Unresponsive", "Driver Unresponsive",
AlertStatus.userPrompt, AlertSize.mid, AlertStatus.userPrompt, AlertSize.mid,
Priority.MID, VisualAlert.steerRequired, AudibleAlert.chimeWarning2RepeatInfinite, .1), Priority.MID, VisualAlert.steerRequired, AudibleAlert.prompt, .1),
}, },
EventName.driverUnresponsive: { EventName.driverUnresponsive: {
@ -408,7 +407,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
"DISENGAGE IMMEDIATELY", "DISENGAGE IMMEDIATELY",
"Driver Unresponsive", "Driver Unresponsive",
AlertStatus.critical, AlertSize.full, AlertStatus.critical, AlertSize.full,
Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.chimeWarningRepeatInfinite, .1), Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.warningImmediate, .1),
}, },
EventName.manualRestart: { EventName.manualRestart: {
@ -452,7 +451,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
"Car Detected in Blindspot", "Car Detected in Blindspot",
"", "",
AlertStatus.userPrompt, AlertSize.small, AlertStatus.userPrompt, AlertSize.small,
Priority.LOW, VisualAlert.none, AudibleAlert.chimePrompt, .1), Priority.LOW, VisualAlert.none, AudibleAlert.prompt, .1),
}, },
EventName.laneChange: { EventName.laneChange: {
@ -468,7 +467,7 @@ 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.chimeWarning2RepeatInfinite, 1.), Priority.LOW, VisualAlert.steerRequired, AudibleAlert.promptRepeat, 1.),
}, },
# Thrown when the fan is driven at >50% but is not rotating # Thrown when the fan is driven at >50% but is not rotating
@ -496,44 +495,44 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
# ********** events that affect controls state transitions ********** # ********** events that affect controls state transitions **********
EventName.pcmEnable: { EventName.pcmEnable: {
ET.ENABLE: EngagementAlert(AudibleAlert.chimeEngage), ET.ENABLE: EngagementAlert(AudibleAlert.engage),
}, },
EventName.buttonEnable: { EventName.buttonEnable: {
ET.ENABLE: EngagementAlert(AudibleAlert.chimeEngage), ET.ENABLE: EngagementAlert(AudibleAlert.engage),
}, },
EventName.pcmDisable: { EventName.pcmDisable: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.chimeDisengage), ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
}, },
EventName.buttonCancel: { EventName.buttonCancel: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.chimeDisengage), ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
}, },
EventName.brakeHold: { EventName.brakeHold: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.chimeDisengage), ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
ET.NO_ENTRY: NoEntryAlert("Brake Hold Active"), ET.NO_ENTRY: NoEntryAlert("Brake Hold Active"),
}, },
EventName.parkBrake: { EventName.parkBrake: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.chimeDisengage), ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
ET.NO_ENTRY: NoEntryAlert("Park Brake Engaged"), ET.NO_ENTRY: NoEntryAlert("Park Brake Engaged"),
}, },
EventName.pedalPressed: { EventName.pedalPressed: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.chimeDisengage), ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
ET.NO_ENTRY: NoEntryAlert("Pedal Pressed During Attempt", ET.NO_ENTRY: NoEntryAlert("Pedal Pressed During Attempt",
visual_alert=VisualAlert.brakePressed), visual_alert=VisualAlert.brakePressed),
}, },
EventName.wrongCarMode: { EventName.wrongCarMode: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.chimeDisengage), ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
ET.NO_ENTRY: wrong_car_mode_alert, ET.NO_ENTRY: wrong_car_mode_alert,
}, },
EventName.wrongCruiseMode: { EventName.wrongCruiseMode: {
ET.USER_DISABLE: EngagementAlert(AudibleAlert.chimeDisengage), ET.USER_DISABLE: EngagementAlert(AudibleAlert.disengage),
ET.NO_ENTRY: NoEntryAlert("Enable Adaptive Cruise"), ET.NO_ENTRY: NoEntryAlert("Enable Adaptive Cruise"),
}, },
@ -627,14 +626,12 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
# ten times the regular interval, or the average interval is more than 10% too high. # ten times the regular interval, or the average interval is more than 10% too high.
EventName.commIssue: { EventName.commIssue: {
ET.SOFT_DISABLE: SoftDisableAlert("Communication Issue between Processes"), ET.SOFT_DISABLE: SoftDisableAlert("Communication Issue between Processes"),
ET.NO_ENTRY: NoEntryAlert("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 # Thrown when manager detects a service exited unexpectedly while driving
EventName.processNotRunning: { EventName.processNotRunning: {
ET.NO_ENTRY: NoEntryAlert("System Malfunction: Reboot Your Device", ET.NO_ENTRY: NoEntryAlert("System Malfunction: Reboot Your Device"),
audible_alert=AudibleAlert.chimeDisengage),
}, },
EventName.radarFault: { EventName.radarFault: {
@ -670,15 +667,13 @@ 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: NormalPermanentAlert("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),
}, },
EventName.highCpuUsage: { EventName.highCpuUsage: {
#ET.SOFT_DISABLE: SoftDisableAlert("System Malfunction: Reboot Your Device"), #ET.SOFT_DISABLE: SoftDisableAlert("System Malfunction: Reboot Your Device"),
#ET.PERMANENT: NormalPermanentAlert("System Malfunction", "Reboot your Device"), #ET.PERMANENT: NormalPermanentAlert("System Malfunction", "Reboot your Device"),
ET.NO_ENTRY: NoEntryAlert("System Malfunction: Reboot Your Device", ET.NO_ENTRY: NoEntryAlert("System Malfunction: Reboot Your Device"),
audible_alert=AudibleAlert.chimeDisengage),
}, },
EventName.accFaulted: { EventName.accFaulted: {
@ -782,7 +777,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
"openpilot Canceled", "openpilot Canceled",
"No close lead car", "No close lead car",
AlertStatus.normal, AlertSize.mid, AlertStatus.normal, AlertSize.mid,
Priority.HIGH, VisualAlert.none, AudibleAlert.chimeDisengage, 3.), Priority.HIGH, VisualAlert.none, AudibleAlert.disengage, 3.),
ET.NO_ENTRY: NoEntryAlert("No Close Lead Car"), ET.NO_ENTRY: NoEntryAlert("No Close Lead Car"),
}, },
@ -791,7 +786,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
"openpilot Canceled", "openpilot Canceled",
"Speed too low", "Speed too low",
AlertStatus.normal, AlertSize.mid, AlertStatus.normal, AlertSize.mid,
Priority.HIGH, VisualAlert.none, AudibleAlert.chimeDisengage, 3.), Priority.HIGH, VisualAlert.none, AudibleAlert.disengage, 3.),
}, },
# When the car is driving faster than most cars in the training data the model outputs can be unpredictable # When the car is driving faster than most cars in the training data the model outputs can be unpredictable
@ -800,7 +795,7 @@ EVENTS: Dict[int, Dict[str, Union[Alert, Callable[[Any, messaging.SubMaster, boo
"Speed Too High", "Speed Too High",
"Model uncertain at this speed", "Model uncertain at this speed",
AlertStatus.userPrompt, AlertSize.mid, AlertStatus.userPrompt, AlertSize.mid,
Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.chimeWarning2RepeatInfinite, 4.), Priority.HIGH, VisualAlert.steerRequired, AudibleAlert.promptRepeat, 4.),
ET.NO_ENTRY: NoEntryAlert("Slow down to engage"), ET.NO_ENTRY: NoEntryAlert("Slow down to engage"),
}, },

View File

@ -7,18 +7,31 @@ import time
from cereal import car, log from cereal import car, log
import cereal.messaging as messaging import cereal.messaging as messaging
from common.realtime import DT_CTRL
from selfdrive.car.honda.interface import CarInterface from selfdrive.car.honda.interface import CarInterface
from selfdrive.controls.lib.events import ET, EVENTS, Events from selfdrive.controls.lib.events import ET, EVENTS, Events
from selfdrive.controls.lib.alertmanager import AlertManager from selfdrive.controls.lib.alertmanager import AlertManager
EventName = car.CarEvent.EventName EventName = car.CarEvent.EventName
def cycle_alerts(duration=2000, is_metric=False): def cycle_alerts(duration=200, is_metric=False):
alerts = list(EVENTS.keys()) # all alerts
print(alerts) #alerts = list(EVENTS.keys())
alerts = [EventName.preDriverDistracted, EventName.promptDriverDistracted, EventName.driverDistracted] # this plays each type of audible alert
#alerts = [EventName.preLaneChangeLeft, EventName.preLaneChangeRight] alerts = [
(EventName.buttonEnable, ET.ENABLE),
(EventName.buttonCancel, ET.USER_DISABLE),
(EventName.wrongGear, ET.NO_ENTRY),
(EventName.vehicleModelInvalid, ET.SOFT_DISABLE),
(EventName.accFaulted, ET.IMMEDIATE_DISABLE),
# DM sequence
(EventName.preDriverDistracted, ET.WARNING),
(EventName.promptDriverDistracted, ET.WARNING),
(EventName.driverDistracted, ET.WARNING),
]
CP = CarInterface.get_params("HONDA CIVIC 2016") CP = CarInterface.get_params("HONDA CIVIC 2016")
sm = messaging.SubMaster(['deviceState', 'pandaStates', 'roadCameraState', 'modelV2', 'liveCalibration', sm = messaging.SubMaster(['deviceState', 'pandaStates', 'roadCameraState', 'modelV2', 'liveCalibration',
@ -30,43 +43,45 @@ def cycle_alerts(duration=2000, is_metric=False):
AM = AlertManager() AM = AlertManager()
frame = 0 frame = 0
idx, last_alert_millis = 0, 0 while True:
while 1:
if frame % duration == 0:
idx = (idx + 1) % len(alerts)
events.clear()
events.add(alerts[idx])
current_alert_types = [ET.PERMANENT, ET.USER_DISABLE, ET.IMMEDIATE_DISABLE, current_alert_types = [ET.PERMANENT, ET.USER_DISABLE, ET.IMMEDIATE_DISABLE,
ET.SOFT_DISABLE, ET.PRE_ENABLE, ET.NO_ENTRY, ET.SOFT_DISABLE, ET.PRE_ENABLE, ET.NO_ENTRY,
ET.ENABLE, ET.WARNING] ET.ENABLE, ET.WARNING]
a = events.create_alerts(current_alert_types, [CP, sm, is_metric])
AM.add_many(frame, a)
AM.process_alerts(frame)
dat = messaging.new_message() for alert, et in alerts:
dat.init('controlsState') events.clear()
dat.controlsState.alertText1 = AM.alert_text_1 events.add(alert)
dat.controlsState.alertText2 = AM.alert_text_2
dat.controlsState.alertSize = AM.alert_size
dat.controlsState.alertStatus = AM.alert_status
dat.controlsState.alertBlinkingRate = AM.alert_rate
dat.controlsState.alertType = AM.alert_type
dat.controlsState.alertSound = AM.audible_alert
pm.send('controlsState', dat)
dat = messaging.new_message() a = events.create_alerts([et, ], [CP, sm, is_metric])
dat.init('deviceState') AM.add_many(frame, a)
dat.deviceState.started = True AM.process_alerts(frame)
pm.send('deviceState', dat) print(AM.alert)
for _ in range(duration):
dat = messaging.new_message()
dat.init('controlsState')
dat.controlsState.enabled = True
dat = messaging.new_message('pandaStates', 1) dat.controlsState.alertText1 = AM.alert_text_1
dat.pandaStates[0].ignitionLine = True dat.controlsState.alertText2 = AM.alert_text_2
dat.pandaStates[0].pandaType = log.PandaState.PandaType.uno dat.controlsState.alertSize = AM.alert_size
pm.send('pandaStates', dat) dat.controlsState.alertStatus = AM.alert_status
dat.controlsState.alertBlinkingRate = AM.alert_rate
dat.controlsState.alertType = AM.alert_type
dat.controlsState.alertSound = AM.audible_alert
pm.send('controlsState', dat)
time.sleep(0.01) dat = messaging.new_message()
dat.init('deviceState')
dat.deviceState.started = True
pm.send('deviceState', dat)
dat = messaging.new_message('pandaStates', 1)
dat.pandaStates[0].ignitionLine = True
dat.pandaStates[0].pandaType = log.PandaState.PandaType.uno
pm.send('pandaStates', dat)
frame += 1
time.sleep(DT_CTRL)
if __name__ == '__main__': if __name__ == '__main__':
cycle_alerts() cycle_alerts()

View File

@ -31,17 +31,18 @@ BASE_CONFIG = [
AmpConfig("Enable PLL2", 0b1, 0x1A, 7, 0b10000000), AmpConfig("Enable PLL2", 0b1, 0x1A, 7, 0b10000000),
AmpConfig("DAI1: I2S mode", 0b00100, 0x14, 2, 0b01111100), AmpConfig("DAI1: I2S mode", 0b00100, 0x14, 2, 0b01111100),
AmpConfig("DAI2: I2S mode", 0b00100, 0x1C, 2, 0b01111100), AmpConfig("DAI2: I2S mode", 0b00100, 0x1C, 2, 0b01111100),
AmpConfig("Right speaker output volume", 0x1a, 0x3E, 0, 0b00011111), AmpConfig("Right speaker output volume", 0x1c, 0x3E, 0, 0b00011111),
AmpConfig("DAI1 Passband filtering: music mode", 0b1, 0x18, 7, 0b10000000), AmpConfig("DAI1 Passband filtering: music mode", 0b1, 0x18, 7, 0b10000000),
AmpConfig("DAI1 voice mode gain (DV1G)", 0b00, 0x2F, 4, 0b00110000), AmpConfig("DAI1 voice mode gain (DV1G)", 0b00, 0x2F, 4, 0b00110000),
AmpConfig("DAI1 attenuation (DV1)", 0x0, 0x2F, 0, 0b00001111), AmpConfig("DAI1 attenuation (DV1)", 0x0, 0x2F, 0, 0b00001111),
AmpConfig("DAI2 attenuation (DV2)", 0x0, 0x31, 0, 0b00001111), AmpConfig("DAI2 attenuation (DV2)", 0x0, 0x31, 0, 0b00001111),
AmpConfig("DAI2: DC blocking", 0b1, 0x20, 0, 0b00000001), AmpConfig("DAI2: DC blocking", 0b1, 0x20, 0, 0b00000001),
AmpConfig("DAI2: High sample rate", 0b0, 0x20, 3, 0b00001000), AmpConfig("DAI2: High sample rate", 0b0, 0x20, 3, 0b00001000),
AmpConfig("ALC enable", 0b0, 0x43, 7, 0b10000000), AmpConfig("ALC enable", 0b1, 0x43, 7, 0b10000000),
AmpConfig("ALC/excursion limiter release time", 0b101, 0x43, 4, 0b01110000), AmpConfig("ALC/excursion limiter release time", 0b101, 0x43, 4, 0b01110000),
AmpConfig("ALC multiband enable", 0b1, 0x43, 3, 0b00001000),
AmpConfig("DAI1 EQ enable", 0b0, 0x49, 0, 0b00000001), AmpConfig("DAI1 EQ enable", 0b0, 0x49, 0, 0b00000001),
AmpConfig("DAI2 EQ enable", 0b0, 0x49, 1, 0b00000010), AmpConfig("DAI2 EQ enable", 0b1, 0x49, 1, 0b00000010),
AmpConfig("DAI2 EQ clip detection disabled", 0b1, 0x32, 4, 0b00010000), AmpConfig("DAI2 EQ clip detection disabled", 0b1, 0x32, 4, 0b00010000),
AmpConfig("DAI2 EQ attenuation", 0x5, 0x32, 0, 0b00001111), AmpConfig("DAI2 EQ attenuation", 0x5, 0x32, 0, 0b00001111),
AmpConfig("Excursion limiter upper corner freq", 0b100, 0x41, 4, 0b01110000), AmpConfig("Excursion limiter upper corner freq", 0b100, 0x41, 4, 0b01110000),
@ -62,11 +63,11 @@ BASE_CONFIG = [
AmpConfig("Zero-crossing detection disabled", 0b0, 0x49, 5, 0b00100000), AmpConfig("Zero-crossing detection disabled", 0b0, 0x49, 5, 0b00100000),
] ]
BASE_CONFIG += configs_from_eq_params(0x84, EQParams(0x65C4, 0xC07C, 0x3D66, 0x07D9, 0x120F)) BASE_CONFIG += configs_from_eq_params(0x84, EQParams(0x274F, 0xC0FF, 0x3BF9, 0x0B3C, 0x1656))
BASE_CONFIG += configs_from_eq_params(0x8E, EQParams(0x1009, 0xC6BF, 0x2952, 0x1C97, 0x30DF)) BASE_CONFIG += configs_from_eq_params(0x8E, EQParams(0x1009, 0xC6BF, 0x2952, 0x1C97, 0x30DF))
BASE_CONFIG += configs_from_eq_params(0x98, EQParams(0x2822, 0xC1C7, 0x3B50, 0x0EF8, 0x180A)) BASE_CONFIG += configs_from_eq_params(0x98, EQParams(0x0F75, 0xCBE5, 0x0ED2, 0x2528, 0x3E42))
BASE_CONFIG += configs_from_eq_params(0xA2, EQParams(0x1009, 0xC5C2, 0x271F, 0x1A87, 0x32A6)) BASE_CONFIG += configs_from_eq_params(0xA2, EQParams(0x091F, 0x3D4C, 0xCE11, 0x1266, 0x2807))
BASE_CONFIG += configs_from_eq_params(0xAC, EQParams(0x2000, 0xCA1E, 0x4000, 0x2287, 0x0000)) BASE_CONFIG += configs_from_eq_params(0xAC, EQParams(0x0A9E, 0x3F20, 0xE573, 0x0A8B, 0x3A3B))
class Amplifier: class Amplifier:
AMP_I2C_BUS = 0 AMP_I2C_BUS = 0

View File

@ -9,8 +9,8 @@
class HardwareTici : public HardwareNone { class HardwareTici : public HardwareNone {
public: public:
static constexpr float MAX_VOLUME = 1.0; static constexpr float MAX_VOLUME = 0.9;
static constexpr float MIN_VOLUME = 0.4; static constexpr float MIN_VOLUME = 0.3;
static bool TICI() { return true; } static bool TICI() { return true; }
static std::string get_os_version() { static std::string get_os_version() {
return "AGNOS " + util::read_file("/VERSION"); return "AGNOS " + util::read_file("/VERSION");

View File

@ -1 +1 @@
e0926a8b9f7cffc35808109a710648a7f57c0b71 9cbef406393a83b35a8f25aa75099da8f8d68276

View File

@ -1,5 +1,9 @@
#include "selfdrive/ui/soundd/sound.h" #include "selfdrive/ui/soundd/sound.h"
#include <QAudio>
#include <QAudioDeviceInfo>
#include <QDebug>
#include "cereal/messaging/messaging.h" #include "cereal/messaging/messaging.h"
#include "selfdrive/common/util.h" #include "selfdrive/common/util.h"
@ -7,14 +11,15 @@
// TODO: detect when we can't display the UI // TODO: detect when we can't display the UI
Sound::Sound(QObject *parent) : sm({"carState", "controlsState", "deviceState"}) { Sound::Sound(QObject *parent) : sm({"carState", "controlsState", "deviceState"}) {
const QString sound_asset_path = Hardware::TICI() ? "../../assets/sounds_tici/" : "../../assets/sounds/"; qInfo() << "default audio device: " << QAudioDeviceInfo::defaultOutputDevice().deviceName();
for (auto &[alert, fn, loops] : sound_list) { for (auto &[alert, fn, loops] : sound_list) {
QSoundEffect *s = new QSoundEffect(this); QSoundEffect *s = new QSoundEffect(this);
QObject::connect(s, &QSoundEffect::statusChanged, [=]() { QObject::connect(s, &QSoundEffect::statusChanged, [=]() {
assert(s->status() != QSoundEffect::Error); assert(s->status() != QSoundEffect::Error);
}); });
s->setVolume(Hardware::MIN_VOLUME); s->setVolume(Hardware::MIN_VOLUME);
s->setSource(QUrl::fromLocalFile(sound_asset_path + fn)); s->setSource(QUrl::fromLocalFile("../../assets/sounds/" + fn));
sounds[alert] = {s, loops}; sounds[alert] = {s, loops};
} }
@ -42,8 +47,9 @@ void Sound::update() {
// scale volume with speed // scale volume with speed
if (sm.updated("carState")) { if (sm.updated("carState")) {
float volume = util::map_val(sm["carState"].getCarState().getVEgo(), 0.f, 20.f, float volume = std::clamp(sm["carState"].getCarState().getVEgo() / 29.f, 0.1f, 1.0f);
Hardware::MIN_VOLUME, Hardware::MAX_VOLUME); volume = QAudio::convertVolume(volume, QAudio::LogarithmicVolumeScale, QAudio::LinearVolumeScale);
volume = util::map_val(volume, 0.f, 1.f, Hardware::MIN_VOLUME, Hardware::MAX_VOLUME);
for (auto &[s, loops] : sounds) { for (auto &[s, loops] : sounds) {
s->setVolume(std::round(100 * volume) / 100); s->setVolume(std::round(100 * volume) / 100);
} }

View File

@ -7,14 +7,15 @@
const std::tuple<AudibleAlert, QString, int> sound_list[] = { const std::tuple<AudibleAlert, QString, int> sound_list[] = {
// AudibleAlert, file name, loop count // AudibleAlert, file name, loop count
{AudibleAlert::CHIME_DISENGAGE, "disengaged.wav", 0}, {AudibleAlert::ENGAGE, "engage.wav", 0},
{AudibleAlert::CHIME_ENGAGE, "engaged.wav", 0}, {AudibleAlert::DISENGAGE, "disengage.wav", 0},
{AudibleAlert::CHIME_WARNING1, "warning_1.wav", 0}, {AudibleAlert::REFUSE, "refuse.wav", 0},
{AudibleAlert::CHIME_WARNING_REPEAT, "warning_repeat.wav", 10},
{AudibleAlert::CHIME_WARNING_REPEAT_INFINITE, "warning_repeat.wav", QSoundEffect::Infinite}, {AudibleAlert::PROMPT, "prompt.wav", 0},
{AudibleAlert::CHIME_WARNING2_REPEAT_INFINITE, "warning_2.wav", QSoundEffect::Infinite}, {AudibleAlert::PROMPT_REPEAT, "prompt.wav", QSoundEffect::Infinite},
{AudibleAlert::CHIME_ERROR, "error.wav", 0},
{AudibleAlert::CHIME_PROMPT, "error.wav", 0}, {AudibleAlert::WARNING_SOFT, "warning_soft.wav", QSoundEffect::Infinite},
{AudibleAlert::WARNING_IMMEDIATE, "warning_immediate.wav", 10},
}; };
class Sound : public QObject { class Sound : public QObject {

View File

@ -15,14 +15,13 @@ AudibleAlert = car.CarControl.HUDControl.AudibleAlert
SOUNDS = { SOUNDS = {
# sound: total writes # sound: total writes
AudibleAlert.none: 0, AudibleAlert.none: 0,
AudibleAlert.chimeEngage: 173, AudibleAlert.engage: 197,
AudibleAlert.chimeDisengage: 173, AudibleAlert.disengage: 230,
AudibleAlert.chimeError: 173, AudibleAlert.refuse: 223,
AudibleAlert.chimePrompt: 173, AudibleAlert.prompt: 217,
AudibleAlert.chimeWarning1: 163, AudibleAlert.promptRepeat: 475,
AudibleAlert.chimeWarningRepeat: 468, AudibleAlert.warningSoft: 477,
AudibleAlert.chimeWarningRepeatInfinite: 468, AudibleAlert.warningImmediate: 468,
AudibleAlert.chimeWarning2RepeatInfinite: 470,
} }
def get_total_writes(): def get_total_writes():
@ -40,7 +39,7 @@ class TestSoundd(unittest.TestCase):
pm = messaging.PubMaster(['deviceState', 'controlsState']) pm = messaging.PubMaster(['deviceState', 'controlsState'])
# make sure they're all defined # make sure they're all defined
alert_sounds = {v: k for k, v in car.CarControl.HUDControl.AudibleAlert.schema.enumerants.items()} alert_sounds = {v: k for k, v in car.CarControl.HUDControl.AudibleAlert.schema.enumerants.items() if not k.endswith('DEPRECATED')}
diff = set(SOUNDS.keys()).symmetric_difference(alert_sounds.keys()) diff = set(SOUNDS.keys()).symmetric_difference(alert_sounds.keys())
assert len(diff) == 0, f"not all sounds defined in test: {diff}" assert len(diff) == 0, f"not all sounds defined in test: {diff}"
@ -65,7 +64,7 @@ class TestSoundd(unittest.TestCase):
pm.send('controlsState', msg) pm.send('controlsState', msg)
time.sleep(DT_CTRL) time.sleep(DT_CTRL)
tolerance = (expected_writes % 100) * 2 tolerance = expected_writes / 10
actual_writes = get_total_writes() - start_writes actual_writes = get_total_writes() - start_writes
assert abs(expected_writes - actual_writes) <= tolerance, f"{alert_sounds[sound]}: expected {expected_writes} writes, got {actual_writes}" assert abs(expected_writes - actual_writes) <= tolerance, f"{alert_sounds[sound]}: expected {expected_writes} writes, got {actual_writes}"

View File

@ -78,7 +78,7 @@ struct Alert {
// car is started, but controls is lagging or died // car is started, but controls is lagging or died
return {"TAKE CONTROL IMMEDIATELY", "Controls Unresponsive", return {"TAKE CONTROL IMMEDIATELY", "Controls Unresponsive",
"controlsUnresponsive", cereal::ControlsState::AlertSize::FULL, "controlsUnresponsive", cereal::ControlsState::AlertSize::FULL,
AudibleAlert::CHIME_WARNING_REPEAT}; AudibleAlert::WARNING_IMMEDIATE};
} }
} }
return {}; return {};