Source Listings

Full text of every standalone snippet this workshop runs, so nothing you're asked to run is hidden off-page. Each was written only to run in this workshop (not shipped as part of sunnypilot itself) and lives under snippets/ in this workshop's own directory.

process_inventory.py

Run with: python3 sunnypilot-architecture/snippets/process_inventory.py (no live publisher needed — this one only imports the process registry and evaluates its condition functions statically). Cited from Module 1; output on the Log page.

 1  # Standalone, self-contained snippet -- not part of manager.py.
 2  # Statically evaluates every registered process's condition function to see
 3  # which processes would run offroad vs onroad, without ever starting a process
 4  # or touching hardware.
 5  from cereal import car
 6  from openpilot.common.params import Params
 7  from openpilot.system.manager.process_config import managed_processes
 8
 9  params = Params()
10  CP = car.CarParams.new_message()
11
12  offroad = [n for n, p in managed_processes.items() if p.enabled and p.should_run(False, params, CP)]
13  onroad = [n for n, p in managed_processes.items() if p.enabled and p.should_run(True, params, CP)]
14
15  print(f'total registered: {len(managed_processes)}')
16  print(f'enabled on this machine: {sum(p.enabled for p in managed_processes.values())} / {len(managed_processes)}')
17  print(f'would run OFFROAD (started=False): {len(offroad)}')
18  print(sorted(offroad))
19  print()
20  print(f'would run ONROAD (started=True):  {len(onroad)}')
21  print(sorted(onroad))
22  print()
23  onroad_only = sorted(set(onroad) - set(offroad))
24  print(f'onroad-only ({len(onroad_only)}):', onroad_only)

dump_msgs.py

Run with: python3 sunnypilot-architecture/snippets/dump_msgs.py against a live publisher, e.g. ./tools/replay/replay --demo --no-vipc -c 3 -s 45 & in another terminal first. Cited from Module 2 and Module 3; output on the Log page.

 1  # Standalone, self-contained snippet -- not part of any daemon.
 2  # Subscribes to the live cereal pub/sub bus and prints a curated set of
 3  # fields from each message the moment it first arrives.
 4  #
 5  # Run against a live publisher, e.g. in another terminal:
 6  #   ./tools/replay/replay --demo --no-vipc
 7  # then, with the same venv active:
 8  #   python3 sunnypilot-architecture/snippets/dump_msgs.py
 9  import time
10  import cereal.messaging as messaging
11
12  sm = messaging.SubMaster(['carState', 'modelV2', 'longitudinalPlan', 'radarState', 'selfdriveState', 'carControl'])
13
14  deadline = time.monotonic() + 15
15  seen = set()
16  while time.monotonic() < deadline and len(seen) < 6:
17      sm.update(100)
18      for k in sm.data.keys():
19          if sm.updated[k] and k not in seen:
20              seen.add(k)
21              print(f"=== {k} (valid={sm.valid[k]}) ===")
22              if k == 'carState':
23                  cs = sm[k]
24                  print(f"  vEgo={cs.vEgo:.3f} m/s  gasPressed={cs.gasPressed}  "
25                        f"cruiseState.speed={cs.cruiseState.speed:.3f}  standstill={cs.standstill}")
26              elif k == 'carControl':
27                  cc = sm[k]
28                  print(f"  latActive={cc.latActive}  longActive={cc.longActive}  "
29                        f"cruiseControl.override={cc.cruiseControl.override}  "
30                        f"actuators.accel={cc.actuators.accel:.3f}  actuators.curvature={cc.actuators.curvature:.5f}")
31              elif k == 'selfdriveState':
32                  ss = sm[k]
33                  print(f"  state={ss.state}  enabled={ss.enabled}  active={ss.active}  "
34                        f"alertType={ss.alertType!r}")
35              elif k == 'modelV2':
36                  mv = sm[k]
37                  print(f"  frameId={mv.frameId}  laneLineProbs={[round(p, 3) for p in mv.laneLineProbs]}  "
38                        f"leadsV3[0].prob={mv.leadsV3[0].prob:.3f}  action.desiredAcceleration={mv.action.desiredAcceleration:.3f}")
39              elif k == 'longitudinalPlan':
40                  lp = sm[k]
41                  print(f"  longitudinalPlanSource={lp.longitudinalPlanSource}  aTarget={lp.aTarget:.3f}  "
42                        f"hasLead={lp.hasLead}  speeds[0]={lp.speeds[0]:.3f}  speeds[-1]={lp.speeds[-1]:.3f}")
43              elif k == 'radarState':
44                  rs = sm[k]
45                  print(f"  leadOne.status={rs.leadOne.status}  leadOne.dRel={rs.leadOne.dRel:.3f}")
46              print()
47
48  print("seen:", seen)

dump_state_transitions.py

Run with: python3 sunnypilot-architecture/snippets/dump_state_transitions.py against a live publisher played faster than real time, e.g. ./tools/replay/replay --demo --no-vipc -c 5 -x 3 --no-loop &. Cited from Module 4; output on the Log page.

 1  # Standalone, self-contained snippet -- not part of any daemon.
 2  # Watches selfdriveState.state over time and prints every transition,
 3  # together with the carState/carControl context that likely caused it.
 4  #
 5  # Run against a live publisher, e.g. in another terminal:
 6  #   ./tools/replay/replay --demo --no-vipc -x 3
 7  # then, with the same venv active:
 8  #   python3 sunnypilot-architecture/snippets/dump_state_transitions.py
 9  import time
10  import cereal.messaging as messaging
11
12  sm = messaging.SubMaster(['selfdriveState', 'carState', 'carControl'])
13
14  last_state = None
15  deadline = time.monotonic() + 45
16  transitions = 0
17  while time.monotonic() < deadline and transitions < 8:
18      sm.update(100)
19      if not sm.valid['selfdriveState']:
20          continue
21      state = str(sm['selfdriveState'].state)
22      if state != last_state:
23          transitions += 1
24          cs = sm['carState']
25          cc = sm['carControl']
26          print(f"[{transitions}] state -> {state}  "
27                f"(gasPressed={cs.gasPressed}, vEgo={cs.vEgo:.2f}, "
28                f"latActive={cc.latActive}, longActive={cc.longActive}, "
29                f"alertType={sm['selfdriveState'].alertType!r})")
30          last_state = state
31
32  print("done, transitions:", transitions)