modeld: cached-output standby while gear is in park

Narrow re-introduction of the power-save mode: when carState reports
gearShifter == park, serve the last rendered model_output instead of
running GPU inference. First cycle (or before carState is flowing)
still runs one real inference so we have something to cache and serve.
Out-of-park returns to per-frame inference immediately.

Avoids the pitfall of the earlier variable-rate path: this doesn't
change the publish rate on modelV2/cameraOdometry (we still publish
every frame), so downstream freq_ok / valid checks in calibrationd /
locationd / paramsd stay happy. Only the GPU inference is skipped.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-23 10:49:44 -05:00
parent 2ce6e8fe0c
commit f896dfe25a
+13
View File
@@ -183,6 +183,10 @@ def main(demo=False):
model_transform_main = np.zeros((3, 3), dtype=np.float32)
model_transform_extra = np.zeros((3, 3), dtype=np.float32)
live_calib_seen = False
# CLEARPILOT: cache last model output to serve while gear is in park — saves
# GPU inference cost while still giving downstream a constant publish rate so
# freq_ok / valid checks don't cascade.
last_model_output = None
nav_features = np.zeros(ModelConstants.NAV_FEATURE_LEN, dtype=np.float32)
nav_instructions = np.zeros(ModelConstants.NAV_INSTRUCTION_LEN, dtype=np.float32)
buf_main, buf_extra = None, None
@@ -314,12 +318,21 @@ def main(demo=False):
**({'radar_tracks': radar_tracks,} if DISABLE_RADAR else {}),
}
# CLEARPILOT: in park, serve the cached last model output instead of running
# GPU inference. First cycle (no cache yet) still runs once so we have
# something to serve. Out-of-park resumes fresh inference every frame.
parked = sm['carState'].gearShifter == car.CarState.GearShifter.park
if parked and last_model_output is not None:
model_output = last_model_output
model_execution_time = 0.0
else:
mt1 = time.perf_counter()
model_output = model.run(buf_main, buf_extra, model_transform_main, model_transform_extra, inputs, prepare_only)
mt2 = time.perf_counter()
model_execution_time = mt2 - mt1
if model_output is not None:
last_model_output = model_output
modelv2_send = messaging.new_message('modelV2')
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,