feat: ramp-up delay on lat engagement to prevent commIssue flash
Some checks failed
prebuilt / build prebuilt (push) Has been cancelled
badges / create badges (push) Has been cancelled

Decouples "tell modeld to go fast" from "steering actually active":
- New LatRequested memory param — controlsd writes when lat would be active
- modeld reads LatRequested (not carControl.latActive) for FPS decision,
  so it switches to 20fps immediately on engage request
- controlsd delays CC.latActive becoming true by 250ms (5 frames @ 20fps)
  after LatRequested goes true, giving downstream services
  (longitudinalPlan, liveCalibration, etc.) time to stabilize at the new rate

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-16 16:46:37 -05:00
parent 1eb8d41454
commit 2d819c784b
6 changed files with 20 additions and 5 deletions

Binary file not shown.

View File

@@ -172,6 +172,8 @@ class Controls:
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.lat_requested_ts = 0 # CLEARPILOT: timestamp when lat was first requested (for ramp-up delay)
self.prev_lat_requested = False
self.steer_limited = False
self.desired_curvature = 0.0
self.experimental_mode = False
@@ -695,8 +697,17 @@ class Controls:
# Check which actuators can be enabled
standstill = CS.vEgo <= max(self.CP.minSteerSpeed, MIN_LATERAL_CONTROL_SPEED) or CS.standstill
CC.latActive = (self.active or self.FPCC.alwaysOnLateral) and self.speed_check and not CS.steerFaultTemporary and not CS.steerFaultPermanent and \
(not standstill or self.joystick_mode)
lat_requested = (self.active or self.FPCC.alwaysOnLateral) and self.speed_check and not CS.steerFaultTemporary and not CS.steerFaultPermanent and \
(not standstill or self.joystick_mode)
# CLEARPILOT: tell modeld early so it can ramp to 20fps, then delay latActive by
# 250ms (5 frames at 20fps) so downstream services stabilize before steering engages.
self.params_memory.put_bool("LatRequested", lat_requested)
now_ts = time.monotonic()
if lat_requested and not self.prev_lat_requested:
self.lat_requested_ts = now_ts
self.prev_lat_requested = lat_requested
CC.latActive = lat_requested and (now_ts - self.lat_requested_ts) >= 0.25
CC.longActive = self.enabled and not self.events.contains(ET.OVERRIDE_LONGITUDINAL) and self.CP.openpilotLongitudinalControl
actuators = CC.actuators

View File

@@ -89,6 +89,7 @@ def manager_init(frogpilot_functions) -> None:
params_memory.put("VpnEnabled", "1")
params_memory.put("DashcamFrames", "0")
params_memory.put("DashcamState", "stopped")
params_memory.put("LatRequested", "0")
params_memory.put("ModelFps", "20")
params_memory.put("ModelStandby", "0")
params_memory.put("ShutdownTouchReset", "0")

View File

@@ -242,10 +242,12 @@ def main(demo=False):
sm.update(0)
# CLEARPILOT: power saving — three modes based on driving state
# Full 20fps: lat active or lane changing
# Reduced 4fps: not lat active, not standstill (driving without cruise)
# Full 20fps: lat requested or lane changing
# Reduced 4fps: not lat requested, not standstill (driving without cruise)
# Standby 0fps: standstill
lat_active = sm['carControl'].latActive
# Uses LatRequested (not carControl.latActive) so modeld ramps to 20fps BEFORE
# controlsd actually engages steering — gives downstream services time to stabilize.
lat_active = params_memory.get_bool("LatRequested")
lane_changing = params_memory.get_bool("no_lat_lane_change")
standstill = sm['carState'].standstill
calibrating = sm['liveCalibration'].calStatus != log.LiveCalibrationData.Status.calibrated

Binary file not shown.