Dynamics
LAV2 provides a unified dynamics parameter and interface framework for aerial and amphibious platforms. The current implementation organizes the stack around a shared parameter object plus modality-specific models so the local MuJoCo runner and the GPU/task backends stay aligned on the same physical constants and interface assumptions. That implementation split is primarily about software structure and numerical modeling, not a claim that rotor and contact dynamics are physically fully decoupled; coupling effects such as lift influencing ground-contact forces are not yet modeled explicitly.
Vehicle Parameters
VehicleParams is the primary parameter surface for the platform. It groups the vehicle description into:
- environment parameters
- body parameters
- propeller parameters
- track parameters
- PX4-aligned parameters
Some of those values are direct configuration inputs, while others are derived in __post_init__, such as thrust and torque coefficients, default initial RPM, and hover throttle related terms. In practice, this means VehicleParams defines both the raw platform constants and the quantities that downstream dynamics and controllers actually consume.
When you need mass, inertia, simulation timing, rotor coefficients, or track geometry, start from VehicleParams rather than scattering literals across the stack.
At the module structure level, concrete dynamics implementations are organized under the common interface DynamicsBase, so rotor, track, and parallel backend variants share the same high-level lifecycle and parameter ownership pattern.
Timing: sim_dt And step_dt
The timing fields are especially important once the same dynamics are used outside the local single-rate simulator. sim_dt is the actuator and physics integration step, while step_dt is the controller update step.
These values become distinct in frameworks with decimation, such as Isaac Lab, where the physics engine may step faster than the control policy or command update loop. The same separation is also important when higher-level and lower-level policies run asynchronously. Keeping both fields in VehicleParams avoids hiding those rate assumptions inside individual modules.
Rotor Dynamics
RotorDynamics converts per-rotor RPM commands into an 8-element output vector:
- first 4 entries: thrusts
- last 4 entries: reaction torques
Its update rule follows the standard rotor-model structure. The commanded rotor speed is first filtered and rate-limited instead of being applied instantaneously. Thrust and reaction torque are then computed from rotor speed and motor acceleration:
Here, \(\omega_i\) is the rotor speed, \(f_i\) is thrust, \(\tau_i\) is reaction torque, \(c_T\) and \(c_M\) are the thrust and torque coefficients, \(J_m\) is motor inertia, and \(d_i \in \{+1, -1\}\) encodes the rotor spin direction. The filtered update uses separate rise and fall time constants together with explicit clipping on the RPM change rate.
For this model to be meaningful, it needs to stay aligned with the real platform parameters, especially:
- initial rotor speed
- motor inertia and time constants
- thrust and torque coefficients
- maximum RPM
- rotor spin directions
Track Dynamics
TrackDynamics models left and right track commands and returns a (2, n_w, 2) array:
- axis 0: left and right track sides
- axis 1: wheel/contact points along each side
- axis 2: planar force components
(Fx, Fy)
At the current stage, the practical point for users is that this module turns left and right track commands plus planar body motion into distributed driving forces at the track contact points, and that output is what the local simulation uses to apply track-side propulsion effects.
State And Command Conventions
The local runner uses compact state slices that match the controller contracts:
- rotor mode dynamics consume motor RPM commands with shape
(4,) - track mode dynamics consume left/right commands with shape
(2,) - track slip computation reads body-frame
[u, v, r]
On the controller side, flight state/target vectors use 12 channels ordered as:
[x, y, z, vx, vy, vz, roll, pitch, yaw, wx, wy, wz]
Track state/target vectors use 6 channels ordered as:
[x, y, yaw, u, v, r]
Understanding these layouts makes it much easier to follow the local simulator and the task wrappers.
Parallel Backend Parity
The Torch implementations under lav2/dynamics/torch/ mirror the NumPy API so large-scale parallel training can reuse the same dynamics logic. The same rule should apply to any future backend implementation in other compute frameworks, such as JAX or Warp.
When a dynamics module is added under the NumPy path, parallel backends should add a same-named counterpart under their own framework directory and preserve behavioral consistency except for the leading environment dimension. In other words, batched implementations may add an extra env axis, but the underlying state, command, and output semantics should stay the same.
API Cross-References
- Shared parameters: VehicleParams
- Rotor model: RotorDynamics
- Track model: TrackDynamics
- Torch rotor model: lav2.dynamics.torch.rotor
- Torch track model: lav2.dynamics.torch.track