From adcffad2769a8898242aacd343512e6b5b6878c6 Mon Sep 17 00:00:00 2001 From: Brian Hanson Date: Wed, 15 Apr 2026 03:49:02 +0000 Subject: [PATCH] feat: speed limit ding sound when cruise warning sign appears Plays a ding via soundd when the cruise warning sign becomes visible (cruise set speed out of range vs speed limit) or when the speed limit changes while the warning sign is already showing. Max 1 ding per 30s. Ding is mixed independently into soundd output at max volume without interrupting alert sounds. bench_cmd ding available for manual trigger. Co-Authored-By: Claude Opus 4.6 (1M context) --- common/params.cc | 1 + selfdrive/clearpilot/bench_cmd.py | 5 +++ selfdrive/clearpilot/sounds/ding.wav | Bin 0 -> 62772 bytes selfdrive/clearpilot/speed_logic.py | 39 ++++++++++++++++-------- selfdrive/manager/manager.py | 1 + selfdrive/ui/soundd.py | 44 ++++++++++++++++++++++++++- 6 files changed, 76 insertions(+), 14 deletions(-) create mode 100644 selfdrive/clearpilot/sounds/ding.wav diff --git a/common/params.cc b/common/params.cc index e692693..9da6281 100755 --- a/common/params.cc +++ b/common/params.cc @@ -260,6 +260,7 @@ std::unordered_map keys = { {"ClearpilotSpeedUnit", PERSISTENT}, {"ClearpilotCruiseWarning", PERSISTENT}, {"ClearpilotCruiseWarningSpeed", PERSISTENT}, + {"ClearpilotPlayDing", PERSISTENT}, // {"SpeedLimitLatDesired", PERSISTENT}, // {"SpeedLimitVTSC", PERSISTENT}, diff --git a/selfdrive/clearpilot/bench_cmd.py b/selfdrive/clearpilot/bench_cmd.py index 839ad03..cb90f6c 100644 --- a/selfdrive/clearpilot/bench_cmd.py +++ b/selfdrive/clearpilot/bench_cmd.py @@ -9,6 +9,7 @@ Usage: python3 -m selfdrive.clearpilot.bench_cmd cruise 55 python3 -m selfdrive.clearpilot.bench_cmd cruiseactive 0|1|2 (0=disabled, 1=active, 2=paused) python3 -m selfdrive.clearpilot.bench_cmd engaged 1 + python3 -m selfdrive.clearpilot.bench_cmd ding (trigger speed limit ding sound) python3 -m selfdrive.clearpilot.bench_cmd debugbutton (simulate LKAS debug button press) python3 -m selfdrive.clearpilot.bench_cmd dump python3 -m selfdrive.clearpilot.bench_cmd wait_ready @@ -108,6 +109,10 @@ def main(): elif cmd == "wait_ready": wait_ready() + elif cmd == "ding": + params.put("ClearpilotPlayDing", "1") + print("Ding triggered") + elif cmd == "debugbutton": # Simulate LKAS debug button — same state machine as controlsd.clearpilot_state_control() current = params.get_int("ScreenDisplayMode") diff --git a/selfdrive/clearpilot/sounds/ding.wav b/selfdrive/clearpilot/sounds/ding.wav new file mode 100644 index 0000000000000000000000000000000000000000..374f2d49c8707612abf40332f2bff93997961084 GIT binary patch literal 62772 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 0 else "0") @@ -59,7 +56,6 @@ class SpeedState: self.params_memory.put("ClearpilotIsMetric", "1" if is_metric else "0") # Cruise warning logic - # Only evaluate when speed limit >= 20 and cruise is active (not paused, not disabled) warning = "" warning_speed = "" cruise_engaged = cruise_active and not cruise_standstill @@ -75,3 +71,20 @@ class SpeedState: self.params_memory.put("ClearpilotCruiseWarning", warning) self.params_memory.put("ClearpilotCruiseWarningSpeed", warning_speed) + + # Ding logic: play when warning sign appears or speed limit changes while visible + should_ding = False + if warning: + if not self.prev_warning: + # Warning sign just appeared + should_ding = True + elif speed_limit_int != self.prev_warning_speed_limit: + # Speed limit changed while warning sign is visible + should_ding = True + + if should_ding and now - self.last_ding_time >= 30: + self.params_memory.put("ClearpilotPlayDing", "1") + self.last_ding_time = now + + self.prev_warning = warning + self.prev_warning_speed_limit = speed_limit_int if warning else 0 diff --git a/selfdrive/manager/manager.py b/selfdrive/manager/manager.py index 5646886..359c9b5 100755 --- a/selfdrive/manager/manager.py +++ b/selfdrive/manager/manager.py @@ -97,6 +97,7 @@ def manager_init(frogpilot_functions) -> None: params_memory.put("ClearpilotSpeedUnit", "mph") params_memory.put("ClearpilotCruiseWarning", "") params_memory.put("ClearpilotCruiseWarningSpeed", "") + params_memory.put("ClearpilotPlayDing", "0") params.clear_all(ParamKeyType.CLEAR_ON_ONROAD_TRANSITION) params.clear_all(ParamKeyType.CLEAR_ON_OFFROAD_TRANSITION) if is_release_branch(): diff --git a/selfdrive/ui/soundd.py b/selfdrive/ui/soundd.py index 69263b7..e8768f8 100755 --- a/selfdrive/ui/soundd.py +++ b/selfdrive/ui/soundd.py @@ -93,6 +93,27 @@ class Soundd: self.spl_filter_weighted = FirstOrderFilter(0, 2.5, FILTER_DT, initialized=False) + # ClearPilot ding (plays independently of alerts) + self.ding_sound = None + self.ding_frame = 0 + self.ding_playing = False + self.ding_check_counter = 0 + self._load_ding() + + def _load_ding(self): + ding_path = BASEDIR + "/selfdrive/clearpilot/sounds/ding.wav" + try: + wavefile = wave.open(ding_path, 'r') + assert wavefile.getnchannels() == 1 + assert wavefile.getsampwidth() == 2 + assert wavefile.getframerate() == SAMPLE_RATE + length = wavefile.getnframes() + self.ding_sound = np.frombuffer(wavefile.readframes(length), dtype=np.int16).astype(np.float32) / (2**16/2) + cloudlog.info(f"ClearPilot ding loaded: {length} frames") + except Exception as e: + cloudlog.error(f"Failed to load ding sound: {e}") + self.ding_sound = None + def load_sounds(self): self.loaded_sounds: dict[int, np.ndarray] = {} @@ -137,7 +158,20 @@ class Soundd: written_frames += frames_to_write self.current_sound_frame += frames_to_write - return ret * self.current_volume + ret = ret * self.current_volume + + # Mix in ClearPilot ding (independent of alerts, always max volume) + if self.ding_playing and self.ding_sound is not None: + ding_remaining = len(self.ding_sound) - self.ding_frame + if ding_remaining > 0: + frames_to_write = min(ding_remaining, frames) + ret[:frames_to_write] += self.ding_sound[self.ding_frame:self.ding_frame + frames_to_write] * MAX_VOLUME + self.ding_frame += frames_to_write + else: + self.ding_playing = False + self.ding_frame = 0 + + return ret def callback(self, data_out: np.ndarray, frames: int, time, status) -> None: if status: @@ -197,6 +231,14 @@ class Soundd: self.get_audible_alert(sm) + # ClearPilot: check for ding trigger at ~2Hz + self.ding_check_counter += 1 + if self.ding_check_counter % 10 == 0 and self.ding_sound is not None: + if self.params_memory.get("ClearpilotPlayDing") == b"1": + self.params_memory.put("ClearpilotPlayDing", "0") + self.ding_playing = True + self.ding_frame = 0 + rk.keep_time() assert stream.active