Skip to content

uzh-rpg/LAFR

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

𝗟𝗔𝗙𝗥: Learning Agile Quadrotor Flight in the Real World

Yunfan Ren  ·  Zhiyuan Zhu  ·  Jiaxu Xing  ·  Davide Scaramuzza

Robotics and Perception Group, University of Zürich

Robotics: Science and Systems (RSS) 2026

Project Page arXiv YouTube License: GPLv3

A self-adaptive framework that learns agile quadrotor flight directly in the real world — without precise system identification, without offline Sim2Real transfer, and without conservative safety margins. The system evolves a base policy from a peak speed of 2.0 m/s to 7.3 m/s within roughly 100 seconds of physical flight time.

Motion-aware Event Suppression for Event Cameras

🌐   Project Page: rpg.ifi.uzh.ch/lafr

📄 Citation

If you find our work and/or code useful, please cite our paper:

@inproceedings{ren2026agile,
  title  = {Learning Agile Quadrotor Flight in the Real World},
  author = {Ren, Yunfan and Zhu, Zhiyuan and Xing, Jiaxu and Scaramuzza, Davide},
  booktitle = {Robotics: Science and Systems (RSS)},
  year   = {2026}
}

📃 Abstract

We present LAFR, a self-adaptive learning framework that achieves agile quadrotor flight directly in the real world, eliminating the need for precise system identification, offline Sim2Real transfer, and conservative safety margins. The framework chains three load-bearing contributions: (1) a hybrid quadrotor ODE in which rigid-body dynamics and a learned residual share a single continuous-time integrator, integrated by a Lie-group RK4 scheme on SO(3) so ω-residuals propagate into translational state within a single step; (2) a consistent-IO residual MLP trained AD-through-integrator with spectral-norm regularization, whose loss runs the integrator inside the optimization and minimizes the geodesic distance to the measured next state; and (3) Adaptive Temporal Scaling (ATS) via closed-loop sensitivity in β = 1/α, with a smooth quadratic barrier and an SO(3) geodesic component in the tracking-error metric. Together these implement RASH-BPTT (Real-world Anchored Short-horizon Backpropagation Through Time) for in-flight policy updates.

🛠 Installation

The code has been tested on:

Ubuntu: 22.04 / 24.04 LTS
Python: 3.11 (conda env recommended)
CUDA: 12 / 13 (GPU), or CPU
GPU: RTX 4090 / 5090 (Blackwell)

📦 Setup

Clone the repo and set up the conda environment. We recommend Mambaforge because it resolves the JAX/CUDA stack in seconds where stock conda can take minutes:

git clone https://github.com/uzh-rpg/LAFR.git
cd LAFR
mamba create -n lafr python=3.11 -y
mamba activate lafr

GPU host (CUDA 13 / Blackwell):

pip install --upgrade "jax[cuda13]"

GPU host (CUDA 12):

pip install --upgrade "jax[cuda12]"

CPU-only:

pip install --upgrade "jax[cpu]"

Then install LAFR:

pip install -e ".[dev]"
export XLA_PYTHON_CLIENT_PREALLOCATE=false

📖 Quick-Start

LAFR has a single entry point that chains base-policy training and online learning end-to-end:

$ python -m lafr.online_learning.run_pipeline --cfg lafr/cfg/online.yaml

Each invocation:

  1. Trains a base tracking policy from lafr/cfg/base.yaml (~22 s on an RTX 5090, 2048 envs × 500 epochs by default) and saves it under outputs/tracking/v*/policy_params.
  2. Runs the online residual-learning + ATS loop, writing versioned policies, datasets, ATS diagnostics, metrics, and a Rerun recording to outputs/online_learning/v*/.

Useful flags:

Flag Effect
--base-policy-dir <path> Reuse an existing checkpoint, skipping base-policy training
--skip-base-training Require an existing base policy; do not retrain
--base-cfg <path> / --base-log-dir <path> Override the base-training config or output dir
--iterations N / --policy-epochs N Override defaults from online.yaml
--smoke Shrink both stages to a few epochs for a quick CPU sanity check (used by CI)
--no-record-rerun Disable the bundled Rerun .rrd recording

📂 Visualization

The pipeline writes a Rerun recording to the run dir. Activate the conda env (so the bundled rerun viewer is on PATH) and open the recording on the host:

conda activate lafr
rerun outputs/online_learning/<run_dir>/online_learning.rrd

The bundled blueprint sets sim_time as the default timeline and pre-lays out a 3D spatial view plus five time-series panels:

Path Description
world/drone_model Per-step body-frame RGB triad (red/green/blue = body x/y/z)
world/drone_trail Short rolling tail of the drone position
world/reference Figure-8 reference path
world/reference_target Current reference target
world/wind Subtle drifting arrow grid showing the applied wind acceleration
world/policy_version Rasterized "policy vN alpha=…" label, world-space geometry
timeseries/speed Speed [m/s] over the rollout
timeseries/omega 3-axis body rate cmd + feedback, Y range pinned to ±7 rad/s
timeseries/thrust Commanded total thrust
timeseries/tracking_error Position error norm
timeseries/time_scale Reference time scale α

⚙️ Core Library

The core library is the lafr/ package. For more on each sub-module see its own README.md (where present).

Component Summary
algos/ BPTT trainer + ATS closed-loop sensitivity step (paper Eq. 8–11)
cfg/ base.yaml (base-policy training) + online.yaml (online pipeline)
envs/ JAX state-based trajectory-tracking environment + wrappers
modules/ Policy MLP and residual MLP (paper Eq. 5)
objects/ quadrotor.py (high-level), quadrotor_dynamics.py (Lie-group RK4 primitive), reference trajectories
online_learning/ The pipeline as a sub-package:run_pipeline.py (entry point) + cli.py / tui.py / rerun_logging.py / io.py / env_setup.py / pipeline.py
scripts/ train_base_policy implementation, called by run_pipeline
tests/ Env-level pytest sanity + bit-exact consistency test

The repository also ships tools/diff_run.py, an Orbax-aware bit-exact diff used by the pytest consistency check.

🔬 Reproducibility & tests

# Quick CPU end-to-end smoke run (the CI bar):
$ JAX_PLATFORMS=cpu python -m lafr.online_learning.run_pipeline --smoke \
    --seed 42 --no-record-rerun \
    --output-dir outputs/_baseline_online \
    --base-log-dir outputs/_baseline_tracking

# Verify the pipeline output is bit-exact against a saved baseline:
$ LAFR_BASELINE_DIR=outputs JAX_PLATFORMS=cpu pytest -q lafr/tests

tools/diff_run.py compares two run directories Orbax-aware (it loads each checkpoint and compares the deserialized tensors, since Orbax's on-disk layout drifts across saves while the underlying floats are deterministic).

🙏 Acknowledgements

This work was developed at the Robotics and Perception Group, University of Zürich. The Python-only differentiable simulator is built on JAX and Flax; the visualizer is Rerun. We thank the authors of flightning for open-sourcing their differentiable quadrotor simulator, which provided the foundation of this codebase, and the authors of learning_on_the_fly for this README template. We also acknowledge the use of Claude (Anthropic) and Codex (OpenAI) as coding assistants during the refactoring and cleanup of this codebase.

About

No description, website, or topics provided.

Resources

License

Stars

9 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages