Skip to content

Hardware

Single-device architecture: a rooted Pixel 10 in cabin is the entire compute stack. CAN telemetry comes from an AiM MXP dash logger, not straight off the BMW PT-CAN.

┌───────────────────────────────────────────────────────────────────┐
│                           CAR                                      │
│                                                                    │
│   BMW E46 M3 ─────► AiM MXP ─────► CANable 2.0 ─USB-C OTG─► Pixel │
│   (MSS54HP DME)     (SmartyCam)    RH-02 PRO                  10   │
│                     v3.0 protocol  SLCAN @ 1 Mbit/s                │
│                                                                    │
│   Pixel 10 (Termux + KernelSU)                                     │
│     ├─ Python bridge :8765 (Flask + SQLite)                        │
│     ├─ LocalLLM APK :8080 (Gemma 4 E2B via LiteRT-LM)              │
│     └─ Chrome PWA (or any laptop via `adb reverse`)                │
└───────────────────────────────────────────────────────────────────┘

Phone

Item Detail
Device Pixel 10 (codename frankel)
Root KernelSU
Shell Termux + Termux:API (for fullscreen + storage access)
SoC Tensor G5
Storage path /data/data/com.termux/files/home/pitwall/

/dev/ttyACM* is chmod 666'd on bridge start so Termux can open the CANable without su per frame — see deploy/phone/70-start-bridge.sh.

CAN adapter — Jhoinrch CANable 2.0 RH-02 PRO

Spec Value
Transport USB-C OTG → /dev/ttyACM0
Protocol SLCAN (ASCII), single-channel
Bitrate 1 000 000 bit/s (matches AiM MXP SmartyCam output)
Frame format mixed standard (0x4xx) + extended IDs
python-can --can-interface slcan --can-channel /dev/ttyACM0 --can-bitrate 1000000

Dash logger — AiM MXP

The Pixel never touches the native BMW PT-CAN. The AiM MXP sits in the middle: it ingests BMW DME/DSC (CANBUS1) plus TrailBrake TPMS (CANBUS2) and re-broadcasts a fixed protocol on its SmartyCam output port. The CANable listens to that output bus.

Spec Value
Make / Model AiM MXP
Output port SmartyCam
Protocol AiM MXP SmartyCam Enhanced CAN Protocol v3.0
Software RaceStudio3 v3.83.00
Total frames 20 (5 standard 0x420–0x424 + 15 extended 0x450–0x45E)
Total channels 66
Input — CANBUS1 BMW DME / DSC (BMW_MINI protocol, 500 Kbit/s, receive only)
Input — CANBUS2 TrailBrake TPMS

Source spec PDF: .context/CANable2_Pixel10_Developer_Integration_Spec_v3.0.pdf. On-bus frame layouts live in data/dbc/pitwall.dbc; the wrapping facts (wiring, bitrate, broadcast rates, sign-recovery, known-broken channels) live in data/cars/bmw_e46_m3.yaml.

Known-broken channels (from live capture)

Gear position is not exposed by MSS54HP on any diagnostic path. MXP slots at 0x420[4-5] and 0x450[2-3] read either 0 or 0xCFFE padding (PDF says 0; live capture shows 0xCFFE). Coaches derive gear from RPM / wheel-speed ratio rather than trusting these slots — see methods.gear_position in the car YAML.

Test vehicle

Spec Value
Make BMW
Model M3
Chassis E46
Year 2003
Engine S54B32
ECU MSS54HP DME

Field-test target

May 23, 2026 — Sonoma Raceway. Track JSON: data/tracks/sonoma.json.

Audio

Pixel Earbuds (Bluetooth, passive isolation). The PWA's CoachVoiceButton uses the Web Speech API for STT and speechSynthesis for TTS; both run inside Chrome on the same phone — no separate audio service.