Back to Projects

DroneGym — Founders Inc

An RL training gym for autonomous FPV drones, built in one night — configure any airframe, train a policy on camera-only observations, then fly it.

🏆 Winner — beat 127 other teams  |  Invited to keep building at Founders Inc

PythonNumPyGymnasiumStable-Baselines3 (PPO)FastAPI

Overview

DroneGym started as a fix for a teammate's gripe from the Anduril AI Grand Prix, where their drone simulations kept stalling because they rendered full camera images pixel by pixel. That felt like solving a much bigger problem than the task needed, so DroneGym fakes what the camera sees with simple geometry instead of rendering anything at all. Describe a drone's hardware and it trains a flight AI to chase a target in about five minutes on a laptop, no GPU required, then you can watch it fly. Built overnight.

How It Works

  • Hand-written NumPy quadrotor sim runs at 250 Hz under a 50 Hz policy (action repeat 5)
  • "Fake CV" is pure pinhole geometry returning [bbox_x, bbox_y, bbox_size, visible] — zero pixels rendered, and a drop-in swap point for a real detector later
  • Stable-Baselines3 PPO, MlpPolicy [64,64], 16 vectorized envs, 4-frame stack → 48 observation dims
  • Curriculum promotes difficulty 0→3 on a rolling success rate
  • Two scenarios: static target, and intercept — a constant-velocity crossing target, framed as counter-UAS

Tech Stack

  • Physics: NumPy, 250 Hz rigid-body integration
  • Training: Gymnasium env, Stable-Baselines3 PPO
  • Serving: FastAPI ground station backend, canvas frontend

My Contributions

Six-person team, 9 of 30 commits mine, with exclusive ownership of physics.py and config.py.

  • Wrote the entire 250 Hz rigid-body integrator: quaternion math, Newton-Euler with gyroscopic coupling J⁻¹(τ − ω×Jω), first-order motor lag, linear drag, semi-implicit Euler, per-step quaternion renormalization
  • Built DroneConfig and the hardware→physics derivation — KV × voltage → RPM → thrust via ct·ρ·(rpm/60)²·D⁴, frame size → arm length → inertia tensor — the piece that lets one policy architecture fly five wildly different airframes
  • Wrote randomize_config() for sim-to-real domain randomization, randomized spawn states, and the derive_params/make_state adapter
  • Added the --scenario/--target-speed training flags
  • Wrote a physics-research literature review comparing six open-source drone simulators against ~20 papers to justify each design choice

Challenges

  • Hover-centered action space: a fresh Gaussian policy outputs ≈0 mean, which under a naive thrust map commands ~5× hover on step one. Fixed by analytically inverting the physics mapping so a[0] == 0 is exact hover.
  • Non-Markov observation: get_bbox returns zeros both when the target is behind the camera and when it's off-frame, so a single frame can't tell the policy which way to yaw to reacquire — hence the mandatory 4-frame stack.

Project Media

DroneGym ground station UI showing WORLD, FPV CAMERA, and ATTITUDE panels with a loaded flight replay
The ground station — world view, FPV camera feed, and attitude readout replaying a captured flight.

Demo video — a trained policy flying the intercept scenario.

Links

Tools & Methods

PythonNumPyGymnasiumStable-Baselines3PPOFastAPI

Built at Founders Inc Hack Night.