#!/usr/bin/env python3 """ CLEARPILOT: minimal controlsd variant that runs while ignition is on but the car is in Park. Keeps CAN parsing and carState publishing alive (so thermald can see gearShifter and decide when to swap us out for the full controlsd), but skips all of the heavy onroad work — no model, no planner, no lateral or longitudinal control, no actuator commands. Manager swaps between this and the full controlsd via predicate flips: - this runs when: ignition AND not started - full runs when: started (which requires ignition AND not_parked) The two are mutually exclusive — only one publishes carState at a time. """ from types import SimpleNamespace from openpilot.common.realtime import Priority, config_realtime_process from openpilot.selfdrive.car.card import CarD def _make_default_frogpilot_variables() -> SimpleNamespace: """Safe defaults for fields read inside CarInterface.update / CarState.update. We're not actuating anything here; these only need to keep the update path from raising AttributeError. False/0 across the board is the safe baseline.""" fv = SimpleNamespace() fv.conditional_experimental_mode = False fv.experimental_mode_via_distance = False fv.traffic_mode = False fv.sport_plus = False fv.long_pitch = False fv.no_lat_lane_change = False return fv def main(): config_realtime_process(4, Priority.CTRL_HIGH) # CarD's __init__ blocks until it sees CAN + a pandaState, then calls get_car # to fingerprint and write CarParams. Same path the full controlsd takes. card = CarD() card.initialize() fv = _make_default_frogpilot_variables() # state_update drains CAN, parses carState, publishes carState/carOutput/carParams. # Internally blocks via drain_sock_raw(wait_for_one=True), so the loop is # naturally paced by CAN traffic — no extra sleep needed. while True: card.state_update(fv) if __name__ == "__main__": main()