Show HN: Open-Source AI Racing Harness
Source: Hacker News
# Overview
Today we're open‑sourcing a practice rig for **[Anduril's AI Grand Prix](https://www.theaigrandprix.com/)** (a $500 K autonomous drone‑race competition) so contestants and anyone else curious can start writing autopilot code against a working stack now, before the official Virtual Qualifier 1 simulator drops:
- Repository:
- Runs on macOS and Linux (WSL should work too)
- Setup: `uv sync` + a 5‑minute Betaflight build

---
## The Elodin Journey
The path here was longer than we expected. I came into this from the games side. One of my earlier jobs was working on **The Sims 4**, which (whatever else you think of it) does a serious amount of simulation under the hood: emergent behavior, deterministic‑ish replay, content pipelines, an editor good enough to ship to gamers (i.e. non‑engineers). That polish and joy of use was missing in aerospace tooling, where most teams I talked to were stitching together MATLAB/Simulink + Gazebo + a home‑grown Python harness and praying it held together.
We started **Elodin** a few years ago thinking we could close some of that gap, and it turned out to be a much bigger job than any of us understood at the time. Most of the last couple of years we have been sitting next to customers (drone, satellite, missiles, etc.), grounding the simulator in real flight data, finding the missing 20 % of features that turn a demo into something a flight‑software team relies on, and slowly converging on a stack that gets a useful sim up in hours instead of weeks.

*Traditional quadcopter simulation development in [MathWorks Simulink](https://www.mathworks.com/videos/programming-drones-with-simulink-1513024653640.html)*
What we ended up with, roughly, is:
- A **Rust ECS** + JIT‑compiled physics core (**nox**) with Python bindings
- A 3‑D editor that connects to a time‑series telemetry DB (`elodin-db`) over TCP and live‑binds GLB models, plots, and camera feeds to ECS components
- A small process runner (**s10**) so the same Python entry point can spawn whatever else the sim needs (flight controller, render server, external estimator)
The interesting bit is that the physics is plain JAX‑style code, `@el.map` functions over typed components, so things like Monte‑Carlo runs, GPU acceleration, and bit‑for‑bit deterministic replays fall out naturally. The engine and editor live at under the Apache‑2.0 license.
---
## The Challenge
When the AI Grand Prix was announced earlier this year it landed almost exactly on top of the workflow we'd been refining:
- Physics at one cadence
- A real flight controller at its native PID rate
- An FPV camera on top
- A single contestant‑authored Python function in the middle
Standing up a race‑from‑scratch program is itself a big undertaking, and as the expected drop date for the official Virtual Qualifier 1 simulator came and went we figured the friendliest thing to do was publish the representative rig we had been building internally, so other teams can start iterating now rather than wait for the starting gunshot in silence.

Concretely, the practice rig wires three things together with one post‑step callback:
1. **Elodin** runs the 6‑DOF rigid‑body physics, motor dynamics, drag, ground constraint, multi‑rate IMU/baro/mag sensors, and a GPU‑rendered 640 × 360 forward camera tilted +20° to match the published **[VADR‑TS‑002 spec](https://www.theaigrandprix.com/wp-content/uploads/2026/05/260508_Technical_Spec_0002.pdf)**.
2. **Betaflight** runs as its real SITL build (master, with `ENABLE_SIMULATOR_GYROPID_SYNC` so its PID loop blocks on each FDM packet) and handles RC, mixing, and PID exactly the way it does on a real airframe.
3. An ~80‑line bridge serializes FDM/RC/PWM packets over UDP and steps both sides in lockstep at 1 kHz, so when you tune a controller against this rig you're tuning against the same Betaflight that will run on the metal.
Contestants only edit `solver/`, which holds a single `autopilot(update: SensorUpdate) -> RCCommand` function. It gets called every tick with:
- Body‑frame IMU
- World pose
- Baro, mag
- An optional fresh RGBA camera frame
No GPS, no depth, no motor RPM – matching the official sim's published telemetry contract. We ship a deliberately unimpressive baseline solver (a small altitude/position PID over a hard‑coded gate list) so you have something that takes off and clears gates on day one.

### Caveats
- On the wire we use Betaflight's UDP packets rather than MAVLink, so anything you build here will need a thin shim to talk to the real qualifier sim once it ships.
- We currently expose ENU world state to the solver where the spec says NED.
- Atmospheric effects are a single drag coefficient (no turbulence, no ground effect, no battery sag).
- The spec has a small internal inconsistency around the camera FoV (it states VFoV = 90° but its own intrinsics imply VFoV ≈ 58.72° and HFoV = 90°). We follow the intrinsics, on the bet that the official sim's renderer will too.
- The repo’s `ARCHITECTURE.md` contains a long “Opportunities for improvement” section that is essentially our todo list – PRs are welcome.
---
## The Result
To try it out you need:
- `uv`
- `git` + `git lfs`
- A C toolchain (`build-essential` + `clang-18` on Ubuntu, Xcode CLT on macOS)
Then run:
```bash
bash scripts/install_elodin.sh # installs the Elodin CLI + DB
uv sync
git submodule update --init --recursive
You’ll have a fully functional practice rig ready for you to write and test your own autopilot logic against a realistic Betaflight‑backed simulation. Happy racing! 🚁
```bash
ursive --depth 1 betaflight
bash scripts/build_betaflight.sh
elodin editor sim/main.py
You should see SUCCESS: SITL integration working! Drone took off! and a [RACE] summary in the terminal.
The editor opens to a chase‑cam and FPV viewport you can scrub on the timeline.
The whole schematic is plain KDL embedded in sim/main.py, so changing the layout is straightforward. See the KDL API spec here:

We’d love to hear from people who have built sims for hard‑real‑time control, anyone planning to enter the AGP (or already in it), and anyone with opinions on the ergonomics of solver/api.py or on lockstep flight‑controller integration in general.
We’re also interested in where this approach falls apart:
- where game‑engine intuitions stop helping,
- where Python‑as‑the‑glue hits a wall,
- where deterministic replay leaks too much abstraction.
Happy to go deep on any layer of the stack in the comments.
Thanks for reading; hopefully you find it a useful primer for the competition.
Good luck, see you out there!