# ClearPilot — CLAUDE.md ## Project Overview ClearPilot is a custom fork of **FrogPilot** (itself a fork of comma.ai's openpilot), based on a 2024 release. It is purpose-built for Brian Hanson's **Hyundai Tucson** (HDA2 equipped). The vehicle's HDA2 system has specific quirks around how it synchronizes driving state with openpilot that require careful handling. ### Key Customizations in This Fork - **UI changes** to the onroad driving interface - **Lane change behavior**: brief disengage when turn signal is active during lane changes - **Lateral control disabled**: the car's own radar cruise control handles lateral; openpilot handles longitudinal only - **Driver monitoring timeouts**: modified safety timeouts for the driver monitoring system - **Custom driving models**: `duck-amigo.thneed`, `farmville.onnx`, `wd-40.thneed` in `selfdrive/clearpilot/models/` - **ClearPilot service**: Node.js service at `selfdrive/clearpilot/` with behavior scripts for lane change and longitudinal control ### Short-Term Goals - ~~Fix the dashcam/screen recorder feature~~ (done — see Dashcam section below) - Fix GPS tracking feature - Add a safe-speed-exceeded chime - Implement interactions for the "debug function button" ## Working Rules ### CRITICAL: Change Control This is self-driving software. All changes must be deliberate and well-understood. - **NEVER make changes outside of what is explicitly requested** - **Always explain proposed changes first** — describe the change, the logic, and the architecture; let Brian review and approve before writing any code - **Brian is an expert on this software** — do not override his judgment or assume responsibility for changes he doesn't understand - **Every line must be understood** — work slowly and deliberately - **Test everything thoroughly** — Brian must always be in the loop - **Do not refactor, clean up, or "improve" code beyond the specific request** ### File Ownership We operate as `root` on this device, but openpilot runs as the `comma` user (uid=1000, gid=1000). After any code changes that touch multiple files or before testing: ```bash chown -R comma:comma /data/openpilot ``` ### Git - Remote: `git@git.internal.hanson.xyz:brianhansonxyz/comma.git` - Branch: `clearpilot` - Large model files are tracked in git (intentional — this is a backup) ### Samba Share - Share name: `openpilot` (e.g. `\\comma-3889765b\openpilot`) - Path: `/data/openpilot` - Username: `comma` - Password: `i-like-to-drive-cars` - Runs as `comma:comma` via force user/group — files created over SMB are owned correctly - Enabled at boot (`smbd` + `nmbd`) ### Testing Changes To restart the full openpilot stack after making changes: ```bash # Fix ownership first (we edit as root, openpilot runs as comma) chown -R comma:comma /data/openpilot # Kill existing stack — use pgrep/kill to avoid pkill matching our own shell kill $(pgrep -f 'python.*manager') 2>/dev/null; sleep 2 # Must use a login shell as comma — sudo -u won't set up the right Python/env su - comma -c "bash /data/openpilot/launch_openpilot.sh" ``` Note: `pkill -f manager` or `pkill -f launch_openpilot` will match the invoking shell's own command line and kill the launch process itself. Use `pgrep`+`kill` or run the kill as a separate step before launching. **Adding new params**: The params system uses a C++ whitelist. Adding a new param name in `manager.py` alone will crash with `UnknownKeyName`. You must also register the key in `common/params.cc` in the key list (alphabetically, with `PERSISTENT` or `CLEAR_ON_*` flag), then rebuild. The rebuild will recompile `params.cc` -> `libcommon.a` and re-link all binaries that use it. The `prebuilt` marker file skips compilation. It is **recreated automatically** after each successful build, so you must remove it every time you want to recompile: ```bash rm -f /data/openpilot/prebuilt ``` ## Dashcam / Screen Recorder ### Architecture The dashcam is the FrogPilot `ScreenRecorder` — it captures the onroad UI screen (with overlays) and encodes to MP4 using the Qualcomm OMX H.264 hardware encoder. - **Codec**: H.264 AVC (hardware accelerated via `OMX.qcom.video.encoder.avc`) - **Resolution**: 1440x720 (downscaled from 2160x1080) - **Bitrate**: 2 Mbps - **Container**: MP4 - **Segment length**: 3 minutes per file - **Save path**: `/data/media/0/videos/YYYYMMDD-HHMMSS.mp4` ### Changes Made (2026-04-11) 1. **Disabled comma training data video** (`selfdrive/manager/process_config.py`): commented out `encoderd` and `stream_encoderd`. CAN/sensor logs (`rlog`/`qlog`) are still recorded by `loggerd`. 2. **Re-enabled screen recorder** (`selfdrive/ui/qt/onroad.cc`): uncommented the `QTimer` that feeds frames to the encoder at UI_FREQ rate. 3. **Auto-start recording** (`selfdrive/frogpilot/screenrecorder/screenrecorder.cc`): modified `update_screen()` to automatically start recording when the car is on (`scene.started`) and stop when off. No button press needed. 4. **Hidden UI elements**: the record button is constructed but never made visible or added to layout. Recording is invisible to the driver. 5. **Debug flag** (`ScreenRecorderDebug` param): when set to `"1"`, recording starts even without a car connected. Used for bench testing. Read via `scene.screen_recorder_debug` in `ui.h`/`ui.cc`. 6. **Deleter updated** (`system/loggerd/deleter.py`): free space threshold raised from 5 GB to 9 GB. Oldest videos in `/data/media/0/videos/` are deleted first before falling back to log segments. ### Key Files | File | Role | |------|------| | `selfdrive/frogpilot/screenrecorder/screenrecorder.cc` | Screen capture and auto-start/stop logic | | `selfdrive/frogpilot/screenrecorder/omx_encoder.cc` | OMX H.264 hardware encoder wrapper | | `selfdrive/ui/qt/onroad.cc` | Timer that drives frame capture | | `selfdrive/ui/ui.h` | `screen_recorder_debug` scene flag | | `selfdrive/ui/ui.cc` | Reads `ScreenRecorderDebug` param | | `selfdrive/manager/manager.py` | Default params | | `selfdrive/manager/process_config.py` | encoderd disabled here | | `system/loggerd/deleter.py` | Storage rotation (9 GB threshold, videos + logs) | ## Device: comma 3x ### Hardware - Qualcomm Snapdragon SoC (aarch64) - Serial: comma-3889765b - Connects to the car via comma panda (CAN bus interface) ### Operating System - **Ubuntu 20.04.6 LTS (Focal Fossa)** on aarch64 - **Kernel**: 4.9.103+ (custom comma.ai PREEMPT build, Feb 2024) — very old, vendor-patched Qualcomm kernel - **AGNOS version**: 9.7 (comma's custom OS layer on top of Ubuntu) - **Display server**: Weston (Wayland compositor) on tty1 - **SELinux**: mounted (enforcement status varies) ### Users - `comma` (uid=1000) — the user openpilot runs as; member of root, sudo, disk, gpu, gpio groups - `root` — what we SSH in as; files must be chowned back to comma before running openpilot ### Filesystem / Mount Quirks | Mount | Device | Type | Notes | |-------------|-------------|---------|-------| | `/` | /dev/sda7 | ext4 | Root filesystem, read-write | | `/data` | /dev/sda12 | ext4 | **Persistent**. Openpilot lives here. Survives reboots. | | `/home` | overlay | overlayfs | **VOLATILE** — upperdir on tmpfs, changes lost on reboot | | `/tmp` | tmpfs | tmpfs | Volatile, 150 MB | | `/var` | tmpfs | tmpfs | Volatile, 128 MB (fstab) / 1.5 GB (actual) | | `/systemrw` | /dev/sda10 | ext4 | Writable system overlay, noexec | | `/persist` | /dev/sda2 | ext4 | Persistent config/certs, noexec | | `/cache` | /dev/sda11 | ext4 | Android-style cache partition | | `/dsp` | /dev/sde26 | ext4 | **Read-only** Qualcomm DSP firmware | | `/firmware` | /dev/sde4 | vfat | **Read-only** firmware blobs | | `/data/media`| NVMe | auto | 69 GB dashcam video storage | ### Unusual Packages / Services - `vnstat` — network traffic monitor - `cdsprpcd`, `qseecomd` — Qualcomm DSP and secure execution daemons - `tftp_server` — TFTP server running (Qualcomm firmware access) - armhf multiarch libraries present (32-bit binary support) - Reverse SSH tunnel running via screen (`/data/brian/reverse_ssh.sh`) - `phantom_touch_logger.py`, `power_drop_monitor.py` — comma hardware monitors ### Large Files on Device - `/data/media` — ~69 GB (dashcam video segments) - `/data/scons_cache` — ~1.9 GB (build cache) - `/data/safe_staging` — ~1.5 GB (OTA update staging) - Model files in repo: ~238 MB total (see models section below) ## Boot Sequence ``` Power On -> systemd: comma.service (runs as comma user) -> /usr/comma/comma.sh (waits for Weston, handles factory reset) -> /data/continue.sh (exec bridge to openpilot) -> /data/openpilot/launch_openpilot.sh -> Sources launch_env.sh (thread counts, AGNOS_VERSION) -> Runs agnos_init (marks boot slot, GPU perms, checks OS update) -> Sets PYTHONPATH, symlinks /data/pythonpath -> Runs build.py if no `prebuilt` marker -> Launches selfdrive/manager/manager.py -> manager_init() sets default params -> ensure_running() loop starts all managed processes ``` ## Openpilot Architecture ### Process Manager `selfdrive/manager/manager.py` orchestrates all processes defined in `selfdrive/manager/process_config.py`. ### Always-Running Processes (offroad + onroad) - `thermald` — thermal management, high CPU (~5.6%) - `pandad` — panda CAN bus interface - `ui` — Qt-based onroad/offroad UI - `deleter` — storage cleanup - `statsd`, `timed`, `logmessaged`, `tombstoned` — telemetry/logging - `manage_athenad` — comma cloud connectivity ### Onroad-Only Processes (when driving) - `controlsd` — main vehicle control loop - `plannerd` — path planning - `radard` — radar processing - `modeld` — driving model inference - `dmonitoringmodeld` — driver monitoring model - `locationd` — positioning/localization - `calibrationd` — camera calibration - `paramsd`, `torqued` — parameter estimation - `sensord` — IMU/sensor data - `soundd` — alert sounds - `camerad` — camera capture - `loggerd`, `encoderd` — video logging/encoding - `boardd` — board communication ### GPS - `ubloxd` + `pigeond` for u-blox GPS hardware - `qcomgpsd`, `ugpsd`, `navd` currently **commented out** in process_config ### FrogPilot Additions - `selfdrive/frogpilot/frogpilot_process.py` — FrogPilot main process - `selfdrive/frogpilot/controls/` — custom planner, control libraries - `selfdrive/frogpilot/fleetmanager/` — fleet management web UI - `selfdrive/frogpilot/screenrecorder/` — C++ OMX-based screen recorder (dashcam) - `selfdrive/frogpilot/ui/qt/` — custom UI widgets and settings panels - `selfdrive/frogpilot/assets/` — custom assets ### ClearPilot Additions - `selfdrive/clearpilot/clearpilot.js` — Node.js service - `selfdrive/clearpilot/behavior/` — lane change, longitudinal control mode scripts - `selfdrive/clearpilot/models/` — custom driving models (duck-amigo, farmville, wd-40) - `selfdrive/clearpilot/manager/api.js` — manager API - `selfdrive/clearpilot/theme/`, `selfdrive/clearpilot/resource/` — theming and assets ### Car Interface (Hyundai) - `selfdrive/car/hyundai/interface.py` — main car interface - `selfdrive/car/hyundai/carcontroller.py` — actuator commands - `selfdrive/car/hyundai/carstate.py` — vehicle state parsing - `selfdrive/car/hyundai/radar_interface.py` — radar data - `selfdrive/car/hyundai/hyundaicanfd.py` — CAN-FD message definitions (HDA2 uses CAN-FD) - `selfdrive/car/hyundai/values.py`, `fingerprints.py` — car-specific constants ### UI Code - `selfdrive/ui/` — Qt/C++ based - `selfdrive/ui/qt/onroad.cc` — main driving screen (contains uiDebug publish, screen recorder integration) - `selfdrive/ui/qt/home.cc` — home/offroad screen - `selfdrive/ui/qt/sidebar.cc` — sidebar - `selfdrive/ui/ui.cc`, `ui.h` — UI state management ### Key Dependencies - **Python 3.11** with: numpy, casadi, onnx/onnxruntime, pycapnp, pyzmq, sentry-sdk, sympy, Cython - **capnp (Cap'n Proto)** — IPC message serialization between all processes - **ZeroMQ** — IPC transport layer - **Qt 5** — UI framework - **OpenMAX (OMX)** — hardware video encoding (screen recorder) - **SCons** — build system for native C++ components