{"id":43471083,"url":"https://github.com/jctoledo/blackbox","last_synced_at":"2026-02-03T07:04:35.908Z","repository":{"id":331185846,"uuid":"1074384598","full_name":"jctoledo/blackbox","owner":"jctoledo","description":"ESP32 vehicle telemetry: GPS+IMU sensor fusion for real-time G-forces, speed \u0026 position. Built-in mobile dashboard. $50 DIY alternative to $1000+ track day loggers.","archived":false,"fork":false,"pushed_at":"2026-02-02T02:52:54.000Z","size":6602,"stargazers_count":3,"open_issues_count":13,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-02T04:42:08.857Z","etag":null,"topics":["ekf","embedded-rust","embedded-systems","esp32","extended-kalman-filter","gps","imu","motorsport","rust","sensor-fusion","trackday","vehicle-dynamics"],"latest_commit_sha":null,"homepage":"https://jctoledo.github.io/blackbox/","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jctoledo.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"docs/SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":null},"created_at":"2025-10-11T17:25:24.000Z","updated_at":"2026-01-24T16:03:19.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/jctoledo/blackbox","commit_stats":null,"previous_names":["jctoledo/blackbox"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/jctoledo/blackbox","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jctoledo%2Fblackbox","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jctoledo%2Fblackbox/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jctoledo%2Fblackbox/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jctoledo%2Fblackbox/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jctoledo","download_url":"https://codeload.github.com/jctoledo/blackbox/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jctoledo%2Fblackbox/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29036648,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-03T06:39:36.383Z","status":"ssl_error","status_checked_at":"2026-02-03T06:39:32.787Z","response_time":96,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ekf","embedded-rust","embedded-systems","esp32","extended-kalman-filter","gps","imu","motorsport","rust","sensor-fusion","trackday","vehicle-dynamics"],"created_at":"2026-02-03T07:04:35.404Z","updated_at":"2026-02-03T07:04:35.902Z","avatar_url":"https://github.com/jctoledo.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Blackbox - ESP32 Vehicle Telemetry System\n\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Rust](https://img.shields.io/badge/rust-1.75%2B-orange.svg)](https://www.rust-lang.org/)\n[![ESP32-C3](https://img.shields.io/badge/platform-ESP32--C3-blue.svg)](https://www.espressif.com/)\n\nReal-time GPS + IMU sensor fusion for vehicle dynamics. Track position, velocity, acceleration, and driving modes on $50 hardware. Built-in mobile dashboard with lap timer.\n\n**What you get:**\n- Live G-meter with mode detection (idle, accel, brake, corner)\n- Lap timer with delta-to-best display\n- 20-30 Hz telemetry streaming over WiFi\n- Works standalone — no phone app or internet needed\n\n**Documentation:** [Lap Timer Guide](docs/LAP_TIMER.md) · [Sensor Fusion Guide](docs/SENSOR_FUSION.md) · [Flash Partition](docs/PARTITION_SIZE_ISSUES.md)\n\n---\n\n## Quick Start\n\n### Option A: Flash from Browser (Easiest)\n\n1. Go to **https://jctoledo.github.io/blackbox/**\n2. Connect ESP32-C3 via USB\n3. Click **Connect Device** → select port → **Flash Firmware**\n\n*Requires Chrome, Edge, or Opera. Hold BOOT button if device isn't detected.*\n\n### Option B: Build from Source\n\n```bash\n# Install toolchain (one-time)\ncurl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh\ncargo install espup cargo-espflash\nespup install\n\n# Build and flash\nsource $HOME/export-esp.sh  # Required in every new terminal\ncd sensors/blackbox\ncargo run --release\n```\n\nFirst build takes 10-20 minutes. See [Build Guide](#building-from-source) for detailed instructions.\n\n### Use the Dashboard\n\n1. Power on device → creates WiFi network **\"Blackbox\"**\n2. Connect your phone (password: `blackbox123`)\n3. Open browser → go to `192.168.71.1`\n4. Drive!\n\n---\n\n## Hardware\n\n### Required Components (~$50-100)\n\n| Component | Price | Notes |\n|-----------|-------|-------|\n| ESP32-C3 DevKit | $5 | Any C3 dev board works |\n| WT901 IMU | $25 | 9-axis, configurable to 200Hz |\n| GPS Module | $15-75 | NEO-6M (budget) or NEO-M9N (recommended) |\n| Wires + USB | $5 | — |\n\n**GPS Choice:** NEO-M9N ($75) provides 25Hz updates and better accuracy. Worth it for serious use. NEO-6M ($15) works fine for learning.\n\n### Wiring\n\n```\nESP32-C3              WT901 IMU         GPS Module\n─────────             ─────────         ──────────\n3V3  ─────────────────► VCC\nGND  ─────────────────► GND\nGPIO19 (RX) ──────────► TX\nGPIO18 (TX) ──────────► RX\n3V3  ─────────────────────────────────► VCC\nGND  ─────────────────────────────────► GND\nGPIO4  (RX) ──────────────────────────► TX\nGPIO5  (TX) ──────────────────────────► RX\nGPIO8 ───► (Optional: WS2812 LED)\n```\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eIMU Configuration (optional)\u003c/b\u003e\u003c/summary\u003e\n\nThe WT901 ships at 10Hz. Firmware auto-detects baud rate, so **try it first without configuration**.\n\nCheck the diagnostics page — if IMU Rate shows ~10Hz instead of ~200Hz, configure it:\n\n```bash\n# Requires USB-serial adapter (~$5)\n# Connect: IMU TX→Adapter RX, IMU RX→Adapter TX, GND, 5V\ncd tools/python\npip install pyserial\npython3 configure_wt901.py /dev/ttyUSB0\n```\n\nSettings save to EEPROM — only needed once per IMU.\n\n\u003c/details\u003e\n\n---\n\n## Mobile Dashboard\n\nConnect to the device's WiFi and open `192.168.71.1` in any browser.\n\n### Features\n\n| Feature | Description |\n|---------|-------------|\n| G-Meter | Real-time lateral/longitudinal display with trail |\n| Speed | Current and max speed |\n| Mode Detection | IDLE, ACCEL, BRAKE, CORNER, or combined states |\n| Driving Presets | Track, Canyon, City, Highway, or Custom |\n| Lap Timer | Record tracks, time laps, see delta-to-best |\n| Recording | Capture sessions, export to CSV |\n| Diagnostics | Sensor rates, GPS quality, EKF health |\n\n### Controls\n\n| Action | Effect |\n|--------|--------|\n| Tap CLR | Reset max G values |\n| Tap max speed | Reset max speed |\n| Preset buttons | Switch driving profile |\n| REC button | Start/stop recording |\n\n---\n\n## Lap Timer\n\nRecord tracks anywhere and get real-time lap timing with delta display.\n\n**[Full Lap Timer Guide →](docs/LAP_TIMER.md)**\n\n### Quick Overview\n\n1. **Record a Track** — Tap lap timer card → **+** → drive one lap → **Stop**\n2. **Activate Track** — Tap saved track to enable timing\n3. **Drive** — Cross start line, timing begins automatically\n4. **Watch Delta** — Green = ahead, Red = behind your best\n\n### Delta Bar\n\n```\n    -2.3s                     2.3 seconds AHEAD of best\n◄████████████░░░░░░░░►        Green bar extends left\n\n    +1.5s                     1.5 seconds BEHIND best\n◄░░░░░░░░████████████►        Red bar extends right\n```\n\n- **Scale:** ±2 seconds = full bar. Number shows actual delta beyond ±2s.\n- **Trend arrows:** ▲ gaining time, ▼ losing time\n- **Glow effect:** Appears when delta exceeds 1 second\n\n### Features\n\n| Feature | Description |\n|---------|-------------|\n| Circuit \u0026 Stage | Loop tracks or point-to-point routes |\n| Session History | All lap times saved and grouped by date |\n| Track Auto-Detection | Notifies you when near a saved track |\n| Data Management | View storage, export CSV, delete sessions |\n\nSee the [full documentation](docs/LAP_TIMER.md) for details on recording, delta calculation, and troubleshooting.\n\n---\n\n## Calibration\n\nProper calibration is critical for accurate readings.\n\n1. Mount device rigidly in final position\n2. Park on level ground, engine **OFF**\n3. Power on and **don't touch anything** during yellow LED (~10 seconds)\n4. Wait for cyan pulse = ready\n\n**Signs of bad calibration:** Mode triggers incorrectly, G-meter not centered when parked, non-zero acceleration when stationary.\n\n**To recalibrate:** Tap CLR in dashboard while stationary with engine off.\n\n---\n\n## LED Status\n\n| Pattern | Meaning |\n|---------|---------|\n| Cyan pulse (2s) | GPS locked, operational |\n| Yellow fast blink | Waiting for GPS fix |\n| Yellow pulses | Calibration in progress |\n| Green blinks (boot) | WiFi ready |\n| Red blink | Error (check wiring) |\n\n---\n\n## Building from Source\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003ePrerequisites by Platform\u003c/b\u003e\u003c/summary\u003e\n\n**Ubuntu/Debian:**\n```bash\nsudo apt-get install -y git wget flex bison gperf python3 python3-pip \\\n  python3-venv cmake ninja-build ccache libffi-dev libssl-dev dfu-util libusb-1.0-0\n\ncurl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh\ncargo install espup cargo-espflash\nespup install\nrustup component add rust-src --toolchain esp\n```\n\n**macOS:**\n```bash\nbrew install cmake ninja dfu-util\ncurl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh\ncargo install espup cargo-espflash\nespup install\nrustup component add rust-src --toolchain esp\n```\n\n**Windows:**\n1. Install Visual Studio Build Tools, Python 3, Git\n2. Install Rust via rustup-init.exe\n3. Run: `cargo install espup cargo-espflash \u0026\u0026 espup install`\n\n\u003c/details\u003e\n\n### First Time Setup\n\nAfter cloning, run the partition setup script to configure paths for your machine:\n\n```bash\n./scripts/setup-partition.sh\n```\n\nThis is required because the ESP-IDF build system needs absolute paths. See [Flash Partition](docs/PARTITION_SIZE_ISSUES.md) for details.\n\n### Build Commands\n\n```bash\nsource $HOME/export-esp.sh  # Required in every new terminal!\ncd sensors/blackbox\n\ncargo check              # Quick syntax check\ncargo build --release    # Build firmware\ncargo run --release      # Build + flash + monitor\ncargo fmt                # Format code\ncargo clippy             # Lint\n```\n\n### GPS Configuration\n\n```bash\n# Default: NEO-6M at 5Hz\ncargo build --release\n\n# NEO-M9N at 25Hz\nexport GPS_MODEL=\"m9n\" GPS_RATE=\"25\"\ncargo build --release\n```\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eTroubleshooting Build Issues\u003c/b\u003e\u003c/summary\u003e\n\n**\"can't find crate for core\"**\n```bash\nsource $HOME/export-esp.sh\nrustup component add rust-src --toolchain esp\n```\n\n**\"linking with riscv32-esp-elf-gcc failed\"**\n```bash\nsource $HOME/export-esp.sh  # You forgot this\n```\n\n**Permission denied on serial port (Linux)**\n```bash\nsudo usermod -a -G dialout $USER\n# Log out and back in\n```\n\n**Build hangs**\n```bash\ncargo clean\nrm -rf ~/.espressif\nespup install\n```\n\n\u003c/details\u003e\n\n---\n\n## Configuration Reference\n\n### WiFi Modes\n\n**Access Point (default)** — Device creates its own network. Best for mobile use.\n```bash\ncargo build --release  # No config needed\n```\n\n**Station Mode** — Device joins your network. Enables UDP streaming to laptop.\n```bash\nexport WIFI_MODE=\"station\"\nexport WIFI_SSID=\"YourNetwork\"\nexport WIFI_PASSWORD=\"YourPassword\"\nexport UDP_SERVER=\"192.168.1.100:9000\"\ncargo build --release\n```\n\n### Mode Detection Thresholds\n\nConfigure via dashboard presets or custom sliders:\n\n| Preset | Accel | Brake | Lateral | Best For |\n|--------|-------|-------|---------|----------|\n| Track | 0.35g | 0.55g | 0.50g | Racing |\n| Canyon | 0.22g | 0.35g | 0.28g | Mountain roads |\n| City | 0.10g | 0.18g | 0.12g | Daily driving |\n| Highway | 0.12g | 0.22g | 0.14g | Cruising |\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eEKF Tuning (Advanced)\u003c/b\u003e\u003c/summary\u003e\n\nEdit `sensors/blackbox/src/ekf.rs`:\n\n```rust\nconst Q_ACC: f32 = 0.40;    // Process noise: acceleration\nconst Q_GYRO: f32 = 0.005;  // Process noise: gyro\nconst R_POS: f32 = 20.0;    // Measurement noise: GPS position\nconst R_VEL: f32 = 0.2;     // Measurement noise: GPS velocity\n```\n\nHigher Q = trust sensors more. Higher R = trust sensors less.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e\u003cb\u003eDiagnostics Metrics Explained\u003c/b\u003e\u003c/summary\u003e\n\n| Metric | Healthy | Meaning |\n|--------|---------|---------|\n| IMU Rate | 195-200 Hz | Accelerometer samples/sec |\n| GPS Rate | 5-25 Hz | Position fixes/sec |\n| Position σ | \u003c5m | EKF position uncertainty |\n| Velocity σ | \u003c0.5 m/s | EKF velocity uncertainty |\n| Bias X/Y | \u003c0.5 m/s² | Learned accelerometer bias |\n| HDOP | \u003c2.0 | GPS quality (lower = better) |\n\n**Troubleshooting:**\n- IMU 0 Hz → Check wiring, run configure_wt901.py\n- GPS 0 Hz → Check wiring, ensure sky view\n- High bias → Recalibrate (CLR button)\n\n\u003c/details\u003e\n\n---\n\n## Technical Overview\n\n**[Full Sensor Fusion Guide →](docs/SENSOR_FUSION.md)**\n\n### How Sensor Fusion Works\n\nThe system combines fast IMU (200Hz) with accurate GPS (5-25Hz):\n\n1. **Predict** — IMU accelerations update position/velocity 200×/sec\n2. **Correct** — GPS fixes correct drift 5-25×/sec\n3. **ZUPT** — When stopped, velocity forced to zero, biases learned\n\n**7-State Kalman Filter:** Position (x,y), heading, velocity (vx,vy), accelerometer biases (bax,bay)\n\n### Data Flow\n\n```\nGPS (5-25Hz) ──┐\n               ├──► EKF ──► Mode Classifier ──► Telemetry (20Hz)\nIMU (200Hz) ───┘\n```\n\nSee the [full sensor fusion documentation](docs/SENSOR_FUSION.md) for details on coordinate frames, ZUPT, EKF tuning, and diagnostics interpretation.\n\n### File Structure\n\n```\nblackbox/\n├── docs/                # Documentation\n│   ├── LAP_TIMER.md     # Lap timer user guide\n│   └── SENSOR_FUSION.md # EKF and sensor fusion details\n├── framework/           # Sensor fusion library (host-testable)\n│   └── src/\n│       ├── ekf.rs       # Extended Kalman Filter\n│       ├── transforms.rs # Coordinate math\n│       ├── mode.rs      # Mode detection\n│       └── fusion.rs    # GPS/IMU blending\n├── sensors/blackbox/    # ESP32 firmware\n│   └── src/\n│       ├── main.rs      # Main loop\n│       ├── websocket_server.rs  # Dashboard\n│       └── ...\n└── tools/\n    ├── dashboard-dev/   # Dashboard simulator\n    └── python/          # Receivers and tools\n```\n\n---\n\n## Python Tools\n\nStation mode only. Connect ESP32 and laptop to same network.\n\n```bash\ncd tools/python\npip install -r requirements.txt\n\n# Receive telemetry\npython3 udp_telemetry_server.py\n\n# Analyze CSV export\npython3 analyze_telemetry.py recorded_session.csv\n\n# Configure IMU\npython3 configure_wt901.py /dev/ttyUSB0\n```\n\n---\n\n## Future Enhancements\n\n- [ ] SD card logging\n- [ ] CAN bus integration\n- [ ] Bluetooth connectivity\n- [ ] Over-the-air updates\n- [x] ~~Mobile dashboard~~ ✓\n- [x] ~~High-rate GPS~~ ✓\n- [x] ~~Lap timer~~ ✓\n\n---\n\n## Contributing\n\nContributions welcome — bug fixes, new features, documentation improvements. Open an issue or PR on GitHub.\n\n## License\n\nMIT License — see [LICENSE](LICENSE).\n\n---\n\n**Questions?** Open an [issue](https://github.com/jctoledo/blackbox/issues).\n\n**Ready to build?** [Start with Quick Start ↑](#quick-start)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjctoledo%2Fblackbox","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjctoledo%2Fblackbox","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjctoledo%2Fblackbox/lists"}