From 5b67d4798b0605dced9777934a306bed8428b116 Mon Sep 17 00:00:00 2001 From: Brian Hanson Date: Fri, 17 Apr 2026 16:28:55 -0500 Subject: [PATCH] fix: update services.py rates to match new thermald/gpsd publish rates MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root cause of "TAKE CONTROL IMMEDIATELY / Communication Issue Between Processes" during driving: our 4Hz thermald and 2Hz gpsd changes pushed deviceState, managerState, and gpsLocation above their declared rate ceilings in cereal/services.py. SubMaster's freq_ok check requires observed rate within [0.8*min, 1.2*max]; publishing faster than max also fails the check — which trips all_freq_ok(), raises EventName.commIssue, and fires the banner. - deviceState: 2Hz → 4Hz (matches thermald DT_TRML=0.25) - gpsLocation: 1Hz → 2Hz (matches gpsd 2Hz polling) - managerState: 2Hz → 4Hz (gated on deviceState arrival, inherits rate) Also: - Re-enabled dashcamd in process_config.py (was disabled for the diagnostic test — dashcamd was innocent). - Added a CLAUDE.md section documenting this class of bug so the next rate change updates services.py too. Co-Authored-By: Claude Opus 4.6 (1M context) --- CLAUDE.md | 25 +++++++++++++++++++++++++ cereal/services.py | 6 +++--- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 2cd4057..0dabec2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -84,6 +84,31 @@ ls /data/log2/current/ cat /data/log2/current/gpsd.log ``` +### Changing a Service's Publish Rate + +SubMaster's `freq_ok` check requires observed rate to fall within +`[0.8 × min_freq, 1.2 × max_freq]` of the value declared in +`cereal/services.py`. Publishing *faster* than declared fails the check +just as surely as publishing too slowly — it trips `all_freq_ok()` → +`EventName.commIssue` → "TAKE CONTROL IMMEDIATELY / Communication Issue +Between Processes". + +If you change how often a process publishes, you **must** update the rate +in `cereal/services.py` to match. Example (real bug we hit): + +- Bumped thermald from 2Hz → 4Hz (DT_TRML 0.5→0.25) for faster fan control +- Bumped gpsd from 1Hz → 2Hz +- manager publishes `managerState` gated by `sm.update()` returning on + `deviceState`, so it picks up thermald's rate automatically + +`services.py` still declared `deviceState` and `managerState` as 2Hz +(ceiling 2.4Hz) and `gpsLocation` as 1Hz (ceiling 1.2Hz), so controlsd +fired `commIssue` on every cycle the moment any of these arrived at the +new faster rate. + +Fix: update the second tuple element (Hz) in `cereal/services.py` for the +affected service. Cereal will use the updated rate for all consumers. + ### Adding New Params The params system uses a C++ whitelist. Adding a new param name in `manager.py` alone will crash with `UnknownKeyName`. You must: diff --git a/cereal/services.py b/cereal/services.py index 3e0aaee..0e5e680 100755 --- a/cereal/services.py +++ b/cereal/services.py @@ -30,7 +30,7 @@ services: dict[str, tuple] = { "temperatureSensor": (True, 2., 200), "temperatureSensor2": (True, 2., 200), "gpsNMEA": (True, 9.), - "deviceState": (True, 2., 1), + "deviceState": (True, 4., 1), # CLEARPILOT: 4Hz (was 2Hz) — thermald DT_TRML=0.25 "can": (True, 100., 1223), # decimation gives ~5 msgs in a full segment "controlsState": (True, 100., 10), "pandaStates": (True, 10., 1), @@ -50,7 +50,7 @@ services: dict[str, tuple] = { "longitudinalPlan": (True, 20., 5), "procLog": (True, 0.5, 15), "gpsLocationExternal": (True, 10., 10), - "gpsLocation": (True, 1., 1), + "gpsLocation": (True, 2., 1), # CLEARPILOT: 2Hz (was 1Hz) — gpsd polls at 2Hz "ubloxGnss": (True, 10.), "qcomGnss": (True, 2.), "gnssMeasurements": (True, 10., 10), @@ -70,7 +70,7 @@ services: dict[str, tuple] = { "wideRoadEncodeIdx": (False, 20., 1), "wideRoadCameraState": (True, 20., 20), "modelV2": (True, 20., 40), - "managerState": (True, 2., 1), + "managerState": (True, 4., 1), # CLEARPILOT: 4Hz (was 2Hz) — gated by deviceState arrival "uploaderState": (True, 0., 1), "navInstruction": (True, 1., 10), "navRoute": (True, 0.),