park mode: pause self-driving processes, keep car ECU heartbeat
When the car is in park (ignition still on), pause everything that
isn't strictly needed and keep controlsd in a minimal-cycle keepalive
mode so the car's steering ECU keeps seeing the LFA/LKAS CAN-FD
messages and stays in tester mode (no steering fault on shift to drive).
controlsd:
- Detects park gear, writes ParkMode to /dev/shm/params.
- park_mode_tick(): publishes a do-nothing CarControl through
self.card (CarController.update unconditionally appends the
steering messages every cycle, which is the actual heartbeat).
Still runs clearpilot_state_control so the LFA/debug button +
ScreenDisplayMode keep working in park.
- After park→drive, stay in keepalive-tick mode until SubMaster
reports all services healthy (an 8s hard cap as safety net).
Avoids the burst of commIssue alerts that would otherwise fire
while modeld/plannerd/paramsd/torqued/dmonitoringd/calibrationd/
frogpilot_process spin back up from cold.
manager / process_config:
- New gating helpers _park_mode(), only_onroad_active,
driverview_active, always_run_unless_parked.
- Re-gated to only_onroad_active: modeld, sensord, soundd, locationd,
calibrationd, torqued, paramsd, plannerd, radard, speed_logicd.
- Re-gated to driverview_active: dmonitoringmodeld, dmonitoringd.
- frogpilot_process → always_run_unless_parked (preserves offroad
behavior, only pauses when ignition+parked).
- controlsd stays plain only_onroad — it's the writer + heartbeat.
- ParkMode registered in params.cc, defaulted to "0" in manager_init.
thermald + fan_controller (broken-tree rule, ported):
- thermald subscribes to carState; passes standstill, is_parked,
cruise_engaged into fan_controller.update.
- New fan range rules:
parked → 0-100% (no floor, full cooling)
cruise on → 30-100%
standstill → 10-100%
moving → 30-100%
ignition off → 0-30% (existing)
dashcamd: already park-aware via gear-driven trip lifecycle — no
change needed.
Verified: build clean. Launched on bench: park mode kicks in on
startup (gearShifter=unknown initially → eventually park),
modeld/plannerd/paramsd/torqued/calibrationd/frogpilot_process
correctly disappear from the manager process list, gpsd/dashcamd/
ui/controlsd/pandad stay alive, ParkMode=1 in /dev/shm/params.
This commit is contained in:
@@ -78,8 +78,19 @@ class Controls:
|
||||
|
||||
self.params_memory.put_bool("CPTLkasButtonAction", False)
|
||||
self.params_memory.put_int("ScreenDisplayMode", 0)
|
||||
self.params_memory.put_bool("ParkMode", False)
|
||||
# CLEARPILOT: edge tracking for park→drive auto-wake of screen
|
||||
self.was_driving_gear = False
|
||||
# CLEARPILOT: park-mode bookkeeping. While ParkMode is true, controlsd
|
||||
# only does a minimal tick (carControl heartbeat through card so the
|
||||
# hyundai CAN-FD steering messages keep the car ECU's tester mode alive)
|
||||
# and writes ParkMode so manager pauses modeld/locationd/etc. After
|
||||
# exiting park, stay in keepalive-tick mode until SubMaster reports
|
||||
# everything healthy again, with an 8-second hard cap so we never get
|
||||
# stuck if some service is permanently broken.
|
||||
self.park_mode = False
|
||||
self.park_exit_frame = -1
|
||||
self.PARK_GRACE_MAX_FRAMES = int(8.0 / DT_CTRL)
|
||||
|
||||
self.radarless_model = self.params.get("Model", encoding='utf-8') in RADARLESS_MODELS
|
||||
|
||||
@@ -237,6 +248,16 @@ class Controls:
|
||||
CS = self.data_sample()
|
||||
cloudlog.timestamp("Data sampled")
|
||||
|
||||
# CLEARPILOT: park mode — short-circuit to a minimal tick (just publish
|
||||
# the carControl heartbeat to keep the car's ECU in tester mode). Also
|
||||
# covers the post-park grace window so commIssue events don't flash
|
||||
# while modeld / locationd / paramsd / etc. spin back up.
|
||||
self._update_park_mode(CS)
|
||||
if self.park_mode or self._in_park_exit_grace():
|
||||
self._park_mode_tick(CS)
|
||||
self.CS_prev = CS
|
||||
return
|
||||
|
||||
self.update_events(CS)
|
||||
self.update_frogpilot_events(CS)
|
||||
self.update_clearpilot_events(CS)
|
||||
@@ -1238,6 +1259,38 @@ class Controls:
|
||||
if (len(CS.buttonEvents) > 0):
|
||||
print (CS.buttonEvents)
|
||||
|
||||
def _update_park_mode(self, CS):
|
||||
# CLEARPILOT: track the gear-park flag and write ParkMode for manager.
|
||||
# On park→drive transition, capture the frame so the grace window starts.
|
||||
in_park = CS.gearShifter == GearShifter.park
|
||||
if in_park != self.park_mode:
|
||||
self.park_mode = in_park
|
||||
self.params_memory.put_bool("ParkMode", in_park)
|
||||
if not in_park:
|
||||
self.park_exit_frame = self.sm.frame
|
||||
|
||||
def _in_park_exit_grace(self):
|
||||
# CLEARPILOT: after exiting park, keep doing the minimal tick until the
|
||||
# restarting modeld/locationd/etc. are publishing again, so they don't
|
||||
# trip a burst of commIssue alerts. Exit grace as soon as SubMaster
|
||||
# reports everything healthy; otherwise hold for up to 8 seconds as a
|
||||
# safety cap (avoids getting stuck if a service is permanently broken).
|
||||
if self.park_exit_frame < 0:
|
||||
return False
|
||||
if (self.sm.frame - self.park_exit_frame) >= self.PARK_GRACE_MAX_FRAMES:
|
||||
return False
|
||||
return not (self.sm.all_checks() and not self.card.can_rcv_timeout)
|
||||
|
||||
def _park_mode_tick(self, CS):
|
||||
# CLEARPILOT: minimal-cycle keepalive. Publishes a do-nothing carControl
|
||||
# via card → CarController.update → sendcan, which sends the LFA/LKAS
|
||||
# CAN-FD messages every cycle. Those send unconditionally regardless of
|
||||
# CC.enabled / latActive, so the car's steering ECU keeps seeing the
|
||||
# heartbeat and stays in tester mode.
|
||||
CC = car.CarControl.new_message()
|
||||
self.clearpilot_state_control(CC, CS)
|
||||
self.card.controls_update(CC, self.frogpilot_variables)
|
||||
|
||||
def clearpilot_state_control(self, CC, CS):
|
||||
# CLEARPILOT: pure UI plumbing — does not modify CC/actuators. Maintains
|
||||
# ScreenDisplayMode (5-state machine driven by the LFA/debug button + gear
|
||||
|
||||
Reference in New Issue
Block a user