locationd: ignore GPS as Kalman input; expand park-cached-output to onroad consumers

locationd: ignore gpsLocation observations entirely (clearpilot_disable_gps
const at the top of handle_gps; falls through to determine_gps_mode's
no-GPS path). gpsd.py keeps publishing real GPS for UI / dashcam / clock
/ night-mode — only locationd ignores it. The previous gpsd.py path was
hard-coding vNED=[0,0,0] while the car was moving 28 m/s, feeding the
Kalman contradictory GPS-vs-IMU velocity observations that propagated into
latcontrol_torque through liveLocationKalman.angularVelocityCalibrated and
caused a real "drift right on straight roads" symptom.

controlsd: short-circuit state_control() while parked. Skips LaC/LoC PID,
MPC, model_v2 reads, lane-change logic — all wasted work when the car
isn't moving. Returns the same enabled=False/latActive=False/longActive=False
CC the original code would have produced, so publish_logs runs unchanged
and card.controls_update keeps the sendcan / tester-present heartbeat
flowing at 100Hz. controlsd CPU dropped from ~59% to ~3% in park.

controlsd: also wire self.FPCC.noLatLaneChange = True/False in the
existing lane-change suppression branch. The Hyundai carcontroller already
reads off frogpilot_variables.no_lat_lane_change for the no-steer signal,
but the UI's distinctive yellow CHANGE_LANE_PATH_COLOR (onroad.cc:901)
reads from frogpilotCarControl.NoLatLaneChange — which nobody was setting,
so the yellow line never appeared during lane-change suppression.

plannerd: skip longitudinal_planner.update + publish + publish_ui_plan
while parked. Downstream controlsd already short-circuits in park, so
longitudinalPlan / uiPlan staleness is fine.

frogpilot_process: same idea — skip frogpilot_planner.update + publish
while parked.

dmonitoringmodeld: mirror the cached-output trick from modeld. Add carState
to the SubMaster, cache the last (model_output, dsp_execution_time) tuple,
and serve it on every frame while gear is in park instead of running DSP
inference on the driver camera.

Together with the existing modeld park-cached-output, the heavy onroad
processing pipeline (modeld → plannerd → controlsd → carcontroller) now
all idles in park and only fires when the car leaves park.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-26 12:12:38 -05:00
parent dc7e0a2db7
commit cea422b075
5 changed files with 48 additions and 5 deletions
+21
View File
@@ -665,6 +665,25 @@ class Controls:
def state_control(self, CS):
"""Given the state, this function returns a CarControl packet"""
# CLEARPILOT: short-circuit while parked. Skip LaC/LoC PID, MPC, model_v2
# reads, lane-change logic — none of it matters when the car isn't moving.
# publish_logs still runs and still triggers carcontroller.apply via
# card.controls_update, so the sendcan heartbeats / tester-present messages
# keep flowing at 100Hz and the car doesn't fault. Saves ~30% controlsd CPU
# in park.
if CS.gearShifter == car.CarState.GearShifter.park:
CC = car.CarControl.new_message()
CC.enabled = False
CC.latActive = False
CC.longActive = False
CC.actuators.longControlState = self.LoC.long_control_state
self.LaC.reset()
self.LoC.reset(v_pid=CS.vEgo)
self.frogpilot_variables.no_lat_lane_change = False
self.FPCC.noLatLaneChange = False
lac_log = log.ControlsState.LateralDebugState.new_message()
return CC, lac_log
# Update VehicleModel
lp = self.sm['liveParameters']
x = max(lp.stiffnessFactor, 0.1)
@@ -705,8 +724,10 @@ class Controls:
if model_v2.meta.laneChangeState == LaneChangeState.laneChangeStarting and clearpilot_disable_lat_on_lane_change:
CC.latActive = False
self.frogpilot_variables.no_lat_lane_change = True
self.FPCC.noLatLaneChange = True
else:
self.frogpilot_variables.no_lat_lane_change = False
self.FPCC.noLatLaneChange = False
if CS.leftBlinker or CS.rightBlinker:
self.last_blinker_frame = self.sm.frame