fix: fan 100% on overheat, FCW fps-aware, commIssue suppress, 10min shutdown

- Fan controller: allow full 100% fan when offroad temp >= 75°C (startup cooling)
- ModelFps memory param: modeld publishes actual FPS (20 or 4) so downstream
  consumers can adjust frame-rate-dependent logic
- Longitudinal planner: dynamically adjusts dt and v_desired_filter based on
  ModelFps; FCW crash_cnt threshold scales with FPS to maintain consistent
  0.15s trigger window at both 20fps and 4fps
- controlsd: suppress commIssue alerts for 2s after lateral control engages
  (FPS transition from 4->20 causes transient freq check failures)
- Shutdown timer: hardcoded to 10 minutes (was 45min via FrogPilot param),
  screen taps reset the countdown via ShutdownTouchReset memory param,
  removed Shutdown Timer UI selector from ClearPilot menu

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-16 16:29:42 -05:00
parent 2331aa00a0
commit 1eb8d41454
12 changed files with 62 additions and 38 deletions

View File

@@ -170,6 +170,8 @@ class Controls:
self.current_alert_types = [ET.PERMANENT]
self.logged_comm_issue = None
self.not_running_prev = None
self.last_lat_engage_ts = 0 # CLEARPILOT: timestamp of most recent lat engage transition
self.prev_lat_active = False
self.steer_limited = False
self.desired_curvature = 0.0
self.experimental_mode = False
@@ -455,7 +457,16 @@ class Controls:
standby_ts = float(self.params_memory.get("ModelStandbyTs") or "0")
except (ValueError, TypeError):
standby_ts = 0
model_suppress = (time.monotonic() - standby_ts) < 2.0
now = time.monotonic()
model_suppress = (now - standby_ts) < 2.0
# CLEARPILOT: detect lat engage rising edge and suppress commIssue for 2s after
# Model FPS jumps from 4 to 20 on engage, causing transient freq check failures
lat_active_now = self.CC.latActive
if lat_active_now and not self.prev_lat_active:
self.last_lat_engage_ts = now
self.prev_lat_active = lat_active_now
lat_engage_suppress = (now - self.last_lat_engage_ts) < 2.0
not_running = {p.name for p in self.sm['managerState'].processes if not p.running and p.shouldBeRunning}
if self.sm.recv_frame['managerState'] and (not_running - IGNORE_PROCESSES):
@@ -486,7 +497,7 @@ class Controls:
# generic catch-all. ideally, a more specific event should be added above instead
has_disable_events = self.events.contains(ET.NO_ENTRY) and (self.events.contains(ET.SOFT_DISABLE) or self.events.contains(ET.IMMEDIATE_DISABLE))
no_system_errors = (not has_disable_events) or (len(self.events) == num_events)
if (not self.sm.all_checks() or self.card.can_rcv_timeout) and no_system_errors and not model_suppress:
if (not self.sm.all_checks() or self.card.can_rcv_timeout) and no_system_errors and not model_suppress and not lat_engage_suppress:
if not self.sm.all_alive():
self.events.add(EventName.commIssue)
elif not self.sm.all_freq_ok():