Skip to content
ruhalisPublic

About

L2F-faithful quadrotor dynamics and RAPTOR-contract environments for Isaac Lab 3.0 on Newton

Topics

Resources

Stars

7 stars

Watchers

0 watching

Forks

Repository files navigation

Isaac-L2F

Python 3.12 Isaac Lab 3.0.0 License: MIT

L2F-faithful quadrotor dynamics and RAPTOR-contract environments for NVIDIA Isaac Lab 3.0 on Newton (MJWarp).

RAPTOR flying a figure-eight in Isaac-L2F
The RAPTOR foundation policy flying a 6 s figure-eight in Isaac-L2F-Hover-Direct on Newton/MJWarp, replayed in Isaac Sim. Yellow: reference, cyan: flown path.

L2F ("Learning to Fly in Seconds", rl-tools) is the fastest quadrotor dynamics simulator and the training ground of the RAPTOR foundation policy. It has no rendering and no collisions. Isaac Lab has GPU rendering, collisions and obstacle scenes, but its own multirotor support is PhysX-only and uses a different motor model. Isaac-L2F brings L2F's exact motor and wrench model and the RAPTOR observation/action contract into Isaac Lab, so that policies trained in L2F fly in Isaac Lab zero-shot, and vision policies can be trained on top of the same dynamics.

The contract

Everything in this package is written to one contract, the one RAPTOR and L2F use:

Frames body FLU (x forward, y left, z up), world z-up
Observation (22) position − p_ref (3, world) · rotation matrix row-major (9) · linear velocity − v_ref (3, world) · angular velocity (3, body) · previous action (4, raw)
Action (4) per-motor, normalised to [-1, 1], order front-right, back-right, back-left, front-left
Rate 100 Hz (dt = 0.01 s), one RK4 step per control step
Quaternion (w, x, y, z), body-to-world

The reference (p_ref, v_ref) is an input with neutral defaults (origin, zero velocity); a static setpoint has v_ref = 0. The previous action is the raw, unclamped action passed to the last step, as the l2f oracle keeps it. Trajectory references, position-error clamps, observation delays and noise schedules are downstream wrappers, not variants of the contract.

What is here

isaac_l2f.dynamics is a pure-PyTorch, batched, device-agnostic port of the L2F model:

  • parameter JSON schema (same keys as L2F / RAPTOR), load, save, stack, select
  • first-order motor lag with separate rising and falling time constants
  • thrust polynomial c0 + c1 u + c2 u², rotor drag torque, arm moments
  • RK4 step, post-integration, observation, reward, termination, initial-state sampling
  • the RAPTOR domain-randomisation sampler (thrust-to-weight, torque-to-inertia, mass, size, time constants, torque constant, disturbance magnitude)
  • rotor_wrench(params, u, effectiveness) returning the body-frame force and torque, which is what the Isaac Lab environment injects through the wrench composer; the optional per-rotor effectiveness [N, 4] scales a rotor's thrust and with it its reaction torque and arm moment (the hook fault schedules drive from downstream)
  • world-frame disturbance force and body-frame disturbance torque on the state

isaac_l2f.policy is the policy protocol every env runs: reset(mask) / step(obs) -> action. The policy owns its recurrent state and re-seeds the masked envs from its own h0; the hidden size comes from the artefact. Loaders exist for TorchScript (a scripted module with forward(obs, hidden) -> (action, hidden), an h0 buffer and a hidden_size attribute; feed-forward policies use size 0) and ONNX (inputs obs, hidden; outputs action, hidden_out; needs the onnx extra).

Upstream quirks are reproduced on purpose, not fixed: J and J_inv are stored independently and used as loaded, the orientation cost is 2·acos(1 − |q_z|), and the initial attitude angle ignores max_angle. Golden tests check every step against the l2f pip package.

import torch
from isaac_l2f.dynamics import load_registry, sample_initial_state, step, student_observation

params = load_registry("crazyflie").expand(1024)
gen = torch.Generator().manual_seed(0)
state = sample_initial_state(params, 1024, gen)
action = torch.zeros(1024, 4)
state = step(params, state, action)
obs = student_observation(params, state)   # [1024, 22], reference = origin / zero velocity

from isaac_l2f.policy import load_torchscript

policy = load_torchscript("student.pt")     # hidden size read from the artefact
action = policy.step(obs)                   # raw action; the env clamps
policy.reset(mask=torch.tensor([True] + [False] * 1023))   # re-seed env 0 only

Install

Development (any platform, no GPU needed for the dynamics core and its tests):

uv sync
uv run pytest -q

With Isaac Lab 3.0 (Linux, NVIDIA GPU, Python 3.12). Isaac Lab ships as one distribution on NVIDIA's package index with Newton included. The primary path is kit-less: Newton physics and the Newton Warp renderer run without Isaac Sim:

uv sync --extra isaac

The optional Kit path installs full Isaac Sim 6.2 as the RTX render path for scripts/render_flight.py and for USD/GUI work; physics is still Newton. The two extras are mutually exclusive (Isaac Sim pins numpy 2.3.1 and packaging 26.0, the kit-less split takes the latest), so switching is one sync either way:

UV_HTTP_TIMEOUT=1800 uv sync --extra isaacsim   # extension-cache wheels are multi-GB; uv's 30 s default times out

Training uses physics=newton_mjwarp; kit-less rendering is Newton's (renderer=newton_renderer, --viz newton_gl). NVIDIA's index is a regular extra index here (unsafe-best-match), as in NVIDIA's own pip instructions, because Isaac Sim pins NVIDIA-built transitive packages that exist only there. Isaac Sim 6.2 also pins urllib3==2.7.0 against Isaac Lab 3.0.0's urllib3>=2.8.0, so pyproject.toml overrides it to urllib3>=2.8.0 until NVIDIA aligns the two.

Two Linux-only rules that follow from the split lock:

  • Pass the same extra to every uv run on that machine (uv run --extra isaacsim python ..., uv run --extra isaac isaaclab train ...) or use uv run --no-sync. A bare uv run re-syncs to the default extra set, which is a different resolver split (both Linux splits pin torch==2.11.0 through Isaac Lab, the Kit split also numpy==2.3.1; macOS takes the latest), so it silently moves the venv off Isaac Lab's and Isaac Sim's pins.
  • Anything that imports isaacsim needs NVIDIA's EULA accepted non-interactively: OMNI_KIT_ACCEPT_EULA=YES. Export it in your shell profile on the box if you accept it.

Acknowledgements

Dynamics model and parameter format from rl-tools/l2f (MIT) and the RAPTOR pre-training code in rl-tools.

Citing

Please cite L2F (RA-L 2024), whose dynamics this package ports, and RAPTOR (Science Robotics 2026) if you fly the foundation policy; "Cite this repository" in the sidebar gives this package.

License

MIT, see LICENSE.

About

L2F-faithful quadrotor dynamics and RAPTOR-contract environments for Isaac Lab 3.0 on Newton

Topics

Resources

Stars

7 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages