modeld two-state; UI: immediate blank on ignition off; READY splash on wake

- modeld: simplified to 0fps (standstill or parked) or 20fps. Removed
  4/10fps reduced-rate path, republish caching, FPCC/liveCalibration
  reads, and ModelFps per-cycle param writes.
- ui.cc updateWakefulness: ignition on→off now resets interactive_timeout
  to 0 for immediate screen blank. Tap still wakes via existing handler.
- home.cc offroadTransition(false): reset ready->has_driven to false so
  the READY text appears on fresh ignition, not the textless post-drive
  splash.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-18 11:20:48 -05:00
parent ba4176ffd0
commit 4c8ef93b2b
3 changed files with 18 additions and 56 deletions
+7 -50
View File
@@ -169,7 +169,7 @@ def main(demo=False):
# messaging # messaging
pm = PubMaster(["modelV2", "cameraOdometry"]) pm = PubMaster(["modelV2", "cameraOdometry"])
sm = SubMaster(["deviceState", "carState", "roadCameraState", "liveCalibration", "driverMonitoringState", "navModel", "navInstruction", "carControl", "frogpilotCarControl", "liveTracks", "frogpilotPlan"]) sm = SubMaster(["deviceState", "carState", "roadCameraState", "liveCalibration", "driverMonitoringState", "navModel", "navInstruction", "carControl", "liveTracks", "frogpilotPlan"])
publish_state = PublishState() publish_state = PublishState()
params = Params() params = Params()
@@ -186,11 +186,6 @@ def main(demo=False):
model_standby = False model_standby = False
last_standby_ts_write = 0 last_standby_ts_write = 0
params_memory = Params("/dev/shm/params") params_memory = Params("/dev/shm/params")
# CLEARPILOT: cache last model output for republishing on skip cycles. Keeps downstream
# cameraOdometry/modelV2 rate constant at 20Hz so services.py freq checks never fail
# during reduced-rate mode. Content is stale but we only reduce rate when not engaged,
# so no one is actually using it for control.
last_model_output = None
nav_features = np.zeros(ModelConstants.NAV_FEATURE_LEN, dtype=np.float32) nav_features = np.zeros(ModelConstants.NAV_FEATURE_LEN, dtype=np.float32)
nav_instructions = np.zeros(ModelConstants.NAV_INSTRUCTION_LEN, dtype=np.float32) nav_instructions = np.zeros(ModelConstants.NAV_INSTRUCTION_LEN, dtype=np.float32)
buf_main, buf_extra = None, None buf_main, buf_extra = None, None
@@ -246,25 +241,18 @@ def main(demo=False):
sm.update(0) sm.update(0)
# CLEARPILOT: variable framerate — 4/10fps when not engaged, 20fps when engaged # CLEARPILOT: two-state modeld — 0fps at standstill or parked, 20fps otherwise.
# (or lane changing / calibrating). Downstream services get a constant publish rate
# via the republish-caching below — only the GPU inference is skipped, so no
# freq_ok cascade in consumers.
fpcc = sm['frogpilotCarControl']
lat_active = fpcc.latRequested
lane_changing = fpcc.noLatLaneChange
standstill = sm['carState'].standstill standstill = sm['carState'].standstill
calibrating = sm['liveCalibration'].calStatus != log.LiveCalibrationData.Status.calibrated parked = sm['carState'].gearShifter == car.CarState.GearShifter.park
full_rate = lat_active or lane_changing or calibrating should_standby = standstill or parked
# Standby transitions (standstill only, when not at full rate)
should_standby = standstill and not full_rate
if should_standby and not model_standby: if should_standby and not model_standby:
params_memory.put_bool("ModelStandby", True) params_memory.put_bool("ModelStandby", True)
params_memory.put("ModelFps", "0")
model_standby = True model_standby = True
cloudlog.warning("modeld: standby ON (standstill)") cloudlog.warning("modeld: standby ON")
elif not should_standby and model_standby: elif not should_standby and model_standby:
params_memory.put_bool("ModelStandby", False) params_memory.put_bool("ModelStandby", False)
params_memory.put("ModelFps", "20")
model_standby = False model_standby = False
run_count = 0 run_count = 0
frame_dropped_filter.x = 0. frame_dropped_filter.x = 0.
@@ -277,28 +265,6 @@ def main(demo=False):
last_vipc_frame_id = meta_main.frame_id last_vipc_frame_id = meta_main.frame_id
continue continue
# CLEARPILOT: reduced framerate: skip GPU inference on most frames but still
# republish cached output at full 20Hz so downstream services never see a rate
# drop (avoids freq_ok → valid cascade that causes "Communication Issue" false
# positives on engage). Daylight: skip 1/2 (compute at 10fps), night: skip 4/5
# (compute at 4fps). ModelStandbyTs still written for model_suppress window.
republish_only = False
if not full_rate:
is_daylight = params_memory.get_bool("IsDaylight")
skip_interval = 2 if is_daylight else 5
target_fps = b"10" if is_daylight else b"4"
if params_memory.get("ModelFps") != target_fps:
params_memory.put("ModelFps", target_fps.decode())
now = _time.monotonic()
if now - last_standby_ts_write > 1.0:
params_memory.put("ModelStandbyTs", str(now))
last_standby_ts_write = now
if run_count % skip_interval != 0:
republish_only = True
else:
if params_memory.get("ModelFps") != b"20":
params_memory.put("ModelFps", "20")
desire = DH.desire desire = DH.desire
is_rhd = sm["driverMonitoringState"].isRHD is_rhd = sm["driverMonitoringState"].isRHD
frame_id = sm["roadCameraState"].frameId frame_id = sm["roadCameraState"].frameId
@@ -370,21 +336,12 @@ def main(demo=False):
**({'radar_tracks': radar_tracks,} if DISABLE_RADAR else {}), **({'radar_tracks': radar_tracks,} if DISABLE_RADAR else {}),
} }
# CLEARPILOT: on republish cycles, skip the GPU inference and reuse the last
# model output. Publish rate stays at 20Hz, compute rate is reduced.
if republish_only and last_model_output is not None:
model_output = last_model_output
model_execution_time = 0.0
else:
mt1 = time.perf_counter() mt1 = time.perf_counter()
model_output = model.run(buf_main, buf_extra, model_transform_main, model_transform_extra, inputs, prepare_only) model_output = model.run(buf_main, buf_extra, model_transform_main, model_transform_extra, inputs, prepare_only)
mt2 = time.perf_counter() mt2 = time.perf_counter()
model_execution_time = mt2 - mt1 model_execution_time = mt2 - mt1
if model_output is not None: if model_output is not None:
# cache for next republish cycle
last_model_output = model_output
modelv2_send = messaging.new_message('modelV2') modelv2_send = messaging.new_message('modelV2')
posenet_send = messaging.new_message('cameraOdometry') posenet_send = messaging.new_message('cameraOdometry')
fill_model_msg(modelv2_send, model_output, publish_state, meta_main.frame_id, meta_extra.frame_id, frame_id, frame_drop_ratio, fill_model_msg(modelv2_send, model_output, publish_state, meta_main.frame_id, meta_extra.frame_id, frame_id, frame_drop_ratio,
+3 -1
View File
@@ -122,9 +122,11 @@ void HomeWindow::offroadTransition(bool offroad) {
slayout->setCurrentWidget(ready); slayout->setCurrentWidget(ready);
} else { } else {
// CLEARPILOT: start onroad in splash — updateState will switch to // CLEARPILOT: start onroad in splash — updateState will switch to
// camera view once the car shifts out of park // camera view once the car shifts out of park. Reset has_driven so
// fresh ignition shows the READY text (not the post-drive textless splash).
LOGW("CLP UI: onroad transition -> showing splash (parked)"); LOGW("CLP UI: onroad transition -> showing splash (parked)");
was_parked_onroad = true; was_parked_onroad = true;
ready->has_driven = false;
slayout->setCurrentWidget(ready); slayout->setCurrentWidget(ready);
} }
} }
+4 -1
View File
@@ -558,7 +558,10 @@ void Device::updateWakefulness(const UIState &s) {
} }
if (ignition_state_changed) { if (ignition_state_changed) {
if (ignition_on && s.scene.screen_brightness_onroad == 0 && !s.scene.standby_mode) { if (!ignition_on) {
// CLEARPILOT: ignition on→off blanks the screen immediately (tap still wakes).
resetInteractiveTimeout(0, 0);
} else if (s.scene.screen_brightness_onroad == 0 && !s.scene.standby_mode) {
resetInteractiveTimeout(0, 0); resetInteractiveTimeout(0, 0);
} else { } else {
resetInteractiveTimeout(s.scene.screen_timeout, s.scene.screen_timeout_onroad); resetInteractiveTimeout(s.scene.screen_timeout, s.scene.screen_timeout_onroad);