Skip to content

Domain Randomization

This page explains domain randomization as a simulation-side capability of the LAV2 stack itself. The focus is vehicle intrinsic randomization rather than terrain generation or generic scene variation: under one task definition, different environment instances carry different yet physically plausible platform parameters, actuator responses, and controller settings.

The distinction matters in this repository. Scene-side variation is usually owned by terrain configuration or task events, while the randomization discussed here sits closer to the platform model. The mechanism changes what the simulated vehicle is, not only what the vehicle is asked to do. For the transfer-side motivation behind this choice, see Real2Sim; the discussion below concentrates on how the mechanism is represented and executed inside the simulation stack.

flowchart TD
  A[Nominal platform definition] --> B[VehicleParams]
  B --> C[Controller-side parameters]
  B --> D[Actuator and plant-side parameters]
  C --> E[Array API controllers]
  D --> F[Mixer and rotor dynamics]
  E --> G[Task backend reset hooks]
  F --> G
  G --> H[Per-env sampled runtime state]
  H --> I[Parallel training environments]

Design Boundary

LAV2 keeps the nominal platform description centered on VehicleParams. Domain randomization is layered on top of that nominal model instead of being defined as a separate parameter system. In practice, the repository still has one authoritative description of mass properties, actuator constants, timing assumptions, and PX4-aligned limits, while the training backends perturb selected subsets of those quantities at runtime.

The current implementation follows a consistent pattern: shared components own their nominal parameters and expose typed randomization APIs, while task backends decide when those APIs are invoked. This keeps randomization attached to the model that consumes it instead of introducing a second parameter definition in task code.

This repository therefore treats domain randomization as a property of the simulation components themselves. The key question is whether the affected controller or dynamics module can preserve a coherent interface after the perturbation has been applied. That design choice is also why the implementation currently lives around controllers, mixer logic, and rotor dynamics instead of being hidden entirely inside task code.

Parameter Surfaces

The first parameter surface is the controller side. The batched FlightController exposes FlightController.randomize, allowing the per-environment PID gains and controller limits to be resampled at reset. Conceptually, this differs from plant randomization. It changes the control law that interprets the same target and state signals, so it models uncertainty in the inner-loop controller configuration rather than uncertainty in the platform physics alone.

The second parameter surface is the actuator and allocation path. Mixer supports Mixer.randomize, which perturbs the parameters that govern thrust allocation and normalized-throttle interpretation. Because the mixer rebuilds its allocation matrix and thrust-related caches after sampling, the effect is not a superficial output disturbance; it changes how demanded wrench is mapped into rotor commands.

The third parameter surface is the rotor model itself. RotorDynamics exposes RotorDynamics.randomize, which perturbs quantities such as thrust and torque coefficients, rate limits, motor inertia, and rise or fall time constants. This is an important distinction from simpler perturbation schemes that only scale final thrust. In LAV2, the randomized rotor model can also change actuator response dynamics, which is usually closer to the kinds of mismatch that appear when moving from simulator assumptions to a real propulsion chain.

The fourth surface is AerodynamicEffects. Its drag, ground-effect, wall-effect, and prescribed-force settings can be sampled per environment through AerodynamicEffects.randomize. Aerodynamic coefficient ranges describe physical model parameters, while effect-scale ranges describe the strength of an enabled effect.

Isaac Lab ground tasks also randomize selected actuator-response, contact, mass, and inertia properties at reset. The task configuration is the entry point for the supported ranges, while the shared ground-drive adapter owns its runtime actuator parameters.

Taken together, these surfaces define the current scope of intrinsic randomization in LAV2. The repository does not yet treat all physically meaningful quantities as randomized objects uniformly across all backends. Center-of-mass offset and non-Isaac ground plants remain architectural extensions rather than one common runtime layer.

Runtime Topology

The runtime topology is intentionally stratified. The nominal vehicle description remains centralized, while sampled values are owned by the controller or dynamics component that consumes them. This split preserves one model vocabulary while allowing environment instances to differ at episode boundaries.

flowchart LR
  A[VehicleParams] --> B[FlightController]
  A --> C[Mixer]
  A --> D[RotorDynamics]
  B --> E[control_action or rotor_commands]
  C --> E
  D --> E
  E --> F[Task reset event]
  F --> G[randomize controller]
  F --> H[randomize mixer]
  F --> I[randomize rotor]
  G --> J[Per-env batched tensors]
  H --> J
  I --> J

What matters here is that orchestration does not invent a separate parameter language. Backends provide lifecycle hooks, while controller and plant modules own the meaning of each sampled parameter. This keeps task code thin and avoids coupling task semantics to component-specific bookkeeping.

It also clarifies why LAV2 prefers reset-time randomization. Once an episode begins, the control and dynamics modules should behave as one coherent sampled system. If parameters were resampled arbitrarily during the episode, the simulator would no longer represent a single uncertain platform instance but a time-varying plant definition. That may be useful in some research settings, but it is not the modeling assumption currently encoded in the stack.

Backend Integration

The training-oriented backends in LAV2 all use this same logic, but they do not wire it in identical ways. In Isaac Lab, lav2.tasks.isaaclab.locomotion.aerial.base.mdp.events provides the explicit event helpers that find the relevant action term, locate the attached runtime component, and invoke the component-level randomization method. The default wiring is then assembled in lav2.tasks.isaaclab.locomotion.aerial.base.base_env_cfg, where reset events specify practical parameter ranges for controller, mixer, and rotor perturbations.

Ground-task randomization is wired through the Isaac Lab environment configuration and reset integration. See lav2/tasks/isaaclab/locomotion/ground/ for task-specific configuration and GroundDriveActuatorAdapter for the shared actuator surface.

The mjlab path mirrors that structure closely. lav2.tasks.mjlab.locomotion.aerial.base.mdp.events exposes the same kind of event-layer indirection, and lav2.tasks.mjlab.locomotion.aerial.base.base_env_cfg binds those events into the manager-based environment configuration. This structural similarity is valuable because it preserves the same mental model across backends even when the surrounding environment framework differs.

Genesis Forge uses its own lifecycle integration, while the underlying randomized objects remain the same: controller, mixer, rotor, and aerodynamic modules expose the shared API surfaces.

Taken together, these integrations show the design intent clearly. Domain randomization in LAV2 is not supposed to be a backend-specific trick. The backend chooses the injection point, but the randomized semantics belong to the shared control and dynamics components. That is what keeps the implementation portable across Isaac Lab, mjlab, and future backends.

Aerodynamic Randomization

Aerodynamic randomization is opt-in. Enable the relevant capability in AerodynamicEffectsCfg and register a reset hook that calls AerodynamicEffects.randomize. The base task configs do not register such a hook, so existing task physics remains unchanged.

The following mapping keeps 60 percent of episodes at exactly zero wall effect and samples a weak version for the remainder:

randomization: AerodynamicRandomization = {
    "effect_probabilities": {"wall_effect": 0.4},
    "effect_scale_ranges": {"wall_effect": (0.1, 0.5)},
    "parameter_ranges": {
        "wall_effect_a1": (0.10, 0.21),
        "wall_effect_b1": (0.25, 0.45),
        "wall_effect_a2": (0.02, 0.06),
        "wall_effect_b2": (0.45, 0.65),
    },
}

The supported coefficient and effect names are defined by AerodynamicRandomization. Probabilities select how often an effect is present, parameter ranges perturb the physical model, and effect-scale ranges adjust its strength. Use physically valid, non-negative ranges and keep the exponential wall-model bases in (0, 1].

Backend-specific reset integrations consume the same AerodynamicRandomization mapping.

Whether sampled aerodynamic parameters are observable is a task-design choice. The present wall model uses an analytic plane; finite surfaces and geometry-aware masking remain scene-level work. Keep the randomized wall term weak until those geometry limitations and vehicle-specific coefficients have been validated.

Modeling Implications

The current implementation already reflects a more serious modeling stance than the simplest “multiply thrust by noise” baseline used in some projects. Once actuator time constants, thrust coefficients, limits, and controller gains can vary independently across environments, the policy is no longer trained against one frozen inner-loop stack. Instead, it is exposed to a family of related closed-loop systems that differ in physically meaningful ways.

That said, the present boundary is still narrower than a fully general domain-randomization engine. The repository does not yet provide a unified operation model covering relative scaling, additive perturbation, and absolute sampling for all parameter classes, nor does it expose one common targeting language across body, actuator, and controller objects. Those are sensible future directions, but the current documentation should describe what exists today without pretending those abstractions are already complete.

It is also important to keep controller-side and plant-side uncertainty conceptually separate. Randomizing controller gains addresses robustness to inner-loop configuration drift, while randomizing mixer and rotor parameters addresses robustness to actuation and plant mismatch. Combining them may be useful, but they answer different failure modes and should remain distinguishable in both code and documentation.

Future Extension

The most natural extension path is to make the new Isaac ground surfaces portable. Mass properties, center-of-mass offset, and track-side actuation parameters still need one shared runtime pattern across Isaac Lab, mjlab, and Genesis Forge.

Another important direction is to unify observability of sampled parameters. The ground action term exposes its samples, but the stack does not yet provide one cross-component intrinsics record that can be logged, replayed, or conditionally exposed to the policy.

These extensions should be understood as design continuation, not as a need to replace the current structure. The present implementation already establishes the right ownership pattern: nominal values remain centralized, runtime modules own sampled execution state, and task backends trigger randomization through reset-oriented hooks.

Aerodynamic uncertainty follows the same ownership rule but should keep its physical terms separate. The diagonal drag coefficients, ground-effect coefficient \(\kappa_g\), and wall-effect coefficients \((a_1,b_1,a_2,b_2)\) represent different mechanisms and are sampled independently. The surface plane and distance describe environment state. Because the ground and wall parameters are empirical and airframe-dependent, a sound range starts from system identification and then adds bounded uncertainty; coefficients normally stay fixed within an episode, while a time-varying external force or moving surface remains part of the scenario dynamics. Fixed linear body drag, rotor-speed-dependent blade drag, and quadratic relative-airspeed drag are different model families with different coefficient units, so their ranges are configured separately. Downwash coefficients can be introduced together with an identified vehicle and multi-vehicle wake model.

API Cross-References