Files
clearpilot/selfdrive/clearpilot/bench_onroad.py
Brian Hanson 4b0d0bb708 bench mode, ClearPilot menu, status window, UI introspection RPC
Bench mode (--bench flag):
- bench_onroad.py publishes fake vehicle state as managed process
- manager blocks real car processes (pandad, thermald, controlsd, etc.)
- bench_cmd.py for setting params and querying UI state
- BLOCKER: UI segfaults (SIGSEGV) when OnroadWindow becomes visible
  without camera frames — need to make CameraWidget handle missing
  VisionIPC gracefully before bench drive mode works

ClearPilot menu:
- Replaced grid launcher with sidebar settings panel (ClearPilotPanel)
- Sidebar: Home, Dashcam, Debug
- Home panel: Status and System Settings buttons
- Debug panel: telemetry logging toggle (ParamControl)
- Tap from any view (splash, onroad) opens ClearPilotPanel
- Back button returns to splash/onroad

Status window:
- Live system stats refreshing every 1 second
- Storage, RAM, load, IP, WiFi, VPN, GPS, time, telemetry status
- Tap anywhere to close, returns to previous view
- Honors interactive timeout

UI introspection RPC:
- ZMQ REP server at ipc:///tmp/clearpilot_ui_rpc
- Dumps full widget tree with visibility, geometry, stacked indices
- bench_cmd dump queries it, detects crash loops via process uptime
- ui_dump.py standalone tool

Other:
- Telemetry toggle wired to TelemetryEnabled param with disk space guard
- Telemetry disabled on every manager start
- Blinking red circle on onroad UI when telemetry recording
- Fixed showDriverView overriding park/drive transitions every frame
- Fixed offroadTransition sidebar visibility race in MainWindow
- launch_openpilot.sh: cd to /data/openpilot, --bench flag support

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-13 02:33:33 +00:00

130 lines
4.3 KiB
Python

#!/usr/bin/env python3
"""
ClearPilot bench onroad simulator.
Publishes fake messages to make the UI go onroad and display
configurable vehicle state. Control values via params in /dev/shm/params:
BenchSpeed - vehicle speed in mph (default: 0)
BenchSpeedLimit - speed limit in mph (default: 0, 0=hidden)
BenchCruiseSpeed - cruise set speed in mph (default: 0, 0=not set)
BenchGear - P, D, R, N (default: P)
BenchEngaged - 0 or 1, cruise engaged (default: 0)
Usage:
su - comma -c "PYTHONPATH=/data/openpilot python3 -m selfdrive.clearpilot.bench_onroad"
To stop: Ctrl+C or kill the process. UI returns to offroad.
"""
import time
import cereal.messaging as messaging
from cereal import log, car
from openpilot.common.params import Params
MS_PER_MPH = 0.44704
def main():
params = Params()
params_mem = Params("/dev/shm/params")
# Set defaults
params_mem.put("BenchSpeed", "0")
params_mem.put("BenchSpeedLimit", "0")
params_mem.put("BenchCruiseSpeed", "0")
params_mem.put("BenchGear", "P")
params_mem.put("BenchEngaged", "0")
pm = messaging.PubMaster([
"deviceState", "pandaStates", "carState", "controlsState",
"driverMonitoringState", "liveCalibration",
])
print("Bench onroad simulator started")
print("Set values in /dev/shm/params/d/Bench*")
print(" BenchSpeed=0 BenchSpeedLimit=0 BenchCruiseSpeed=0 BenchGear=P BenchEngaged=0")
gear_map = {
"P": car.CarState.GearShifter.park,
"D": car.CarState.GearShifter.drive,
"R": car.CarState.GearShifter.reverse,
"N": car.CarState.GearShifter.neutral,
}
frame = 0
try:
while True:
# Read bench params
speed_mph = float((params_mem.get("BenchSpeed", encoding="utf-8") or "0").strip())
speed_limit_mph = float((params_mem.get("BenchSpeedLimit", encoding="utf-8") or "0").strip())
cruise_mph = float((params_mem.get("BenchCruiseSpeed", encoding="utf-8") or "0").strip())
gear_str = (params_mem.get("BenchGear", encoding="utf-8") or "P").strip().upper()
engaged = (params_mem.get("BenchEngaged", encoding="utf-8") or "0").strip() == "1"
speed_ms = speed_mph * MS_PER_MPH
gear = gear_map.get(gear_str, car.CarState.GearShifter.park)
# deviceState — 2 Hz
if frame % 5 == 0:
dat = messaging.new_message("deviceState")
dat.deviceState.started = True
dat.deviceState.freeSpacePercent = 80
dat.deviceState.memoryUsagePercent = 30
dat.deviceState.cpuTempC = [40.0] * 3
dat.deviceState.gpuTempC = [40.0] * 3
dat.deviceState.cpuUsagePercent = [20] * 8
dat.deviceState.networkType = log.DeviceState.NetworkType.cell4G
pm.send("deviceState", dat)
# pandaStates — 10 Hz
if frame % 1 == 0:
dat = messaging.new_message("pandaStates", 1)
dat.pandaStates[0].ignitionLine = True
dat.pandaStates[0].pandaType = log.PandaState.PandaType.tres
pm.send("pandaStates", dat)
# carState — 10 Hz
dat = messaging.new_message("carState")
cs = dat.carState
cs.vEgo = speed_ms
cs.vEgoCluster = speed_ms
cs.gearShifter = gear
cs.standstill = speed_ms < 0.1
cs.cruiseState.available = True
cs.cruiseState.enabled = engaged
cs.cruiseState.speed = cruise_mph * MS_PER_MPH if cruise_mph > 0 else 0
pm.send("carState", dat)
# controlsState — 10 Hz
dat = messaging.new_message("controlsState")
ctl = dat.controlsState
ctl.vCruise = cruise_mph * 1.60934 if cruise_mph > 0 else 255 # km/h or 255=not set
ctl.vCruiseCluster = ctl.vCruise
ctl.enabled = engaged
ctl.active = engaged
pm.send("controlsState", dat)
# driverMonitoringState — low freq
if frame % 10 == 0:
dat = messaging.new_message("driverMonitoringState")
dat.driverMonitoringState.isActiveMode = True
pm.send("driverMonitoringState", dat)
# liveCalibration — low freq
if frame % 50 == 0:
dat = messaging.new_message("liveCalibration")
dat.liveCalibration.calStatus = log.LiveCalibrationData.Status.calibrated
dat.liveCalibration.rpyCalib = [0.0, 0.0, 0.0]
pm.send("liveCalibration", dat)
frame += 1
time.sleep(0.1) # 10 Hz base loop
except KeyboardInterrupt:
print("\nBench simulator stopped")
if __name__ == "__main__":
main()