Skip to content

drone_models

drone-models: quadrotor dynamics models for estimation, control, and simulation.

This package provides numeric and symbolic quadrotor dynamics models at multiple fidelity levels. Models are pure functions compatible with any Array API backend (NumPy, JAX, PyTorch, etc.) and with CasADi for symbolic computation.

Use parametrize to bind a dynamics function to a named drone configuration, and available_models to enumerate all registered models.

available_models module-attribute

parametrize(fn, drone_model, xp=None, device=None)

Parametrize a dynamics function with the default dynamics parameters for a drone model.

Parameters:

Name Type Description Default
fn Callable[P, R]

The dynamics function to parametrize.

required
drone_model str

The drone model to use.

required
xp ModuleType | None

The array API module to use. If not provided, numpy is used.

None
device str | None

The device to use. If none, the device is inferred from the xp module.

None
Example
from drone_models.core import parametrize
from drone_models.first_principles import dynamics

dynamics_fn = parametrize(dynamics, drone_model="cf2x_L250")
pos_dot, quat_dot, vel_dot, ang_vel_dot, rotor_vel_dot = dynamics_fn(
    pos=pos, quat=quat, vel=vel, ang_vel=ang_vel, cmd=cmd, rotor_vel=rotor_vel
)

Returns:

Type Description
Callable[P, R]

The parametrized dynamics function with all keyword argument only parameters filled in.

Source code in drone_models/core.py
def parametrize(
    fn: Callable[P, R], drone_model: str, xp: ModuleType | None = None, device: str | None = None
) -> Callable[P, R]:
    """Parametrize a dynamics function with the default dynamics parameters for a drone model.

    Args:
        fn: The dynamics function to parametrize.
        drone_model: The drone model to use.
        xp: The array API module to use. If not provided, numpy is used.
        device: The device to use. If none, the device is inferred from the xp module.

    Example:
        ```{ .python notest }
        from drone_models.core import parametrize
        from drone_models.first_principles import dynamics

        dynamics_fn = parametrize(dynamics, drone_model="cf2x_L250")
        pos_dot, quat_dot, vel_dot, ang_vel_dot, rotor_vel_dot = dynamics_fn(
            pos=pos, quat=quat, vel=vel, ang_vel=ang_vel, cmd=cmd, rotor_vel=rotor_vel
        )
        ```

    Returns:
        The parametrized dynamics function with all keyword argument only parameters filled in.
    """
    try:
        xp = np if xp is None else xp
        physics = fn.__module__.split(".")[-2]
        sig = inspect.signature(fn)
        kwonly_params = [
            name
            for name, param in sig.parameters.items()
            if param.kind == inspect.Parameter.KEYWORD_ONLY
        ]
        params = load_params(physics, drone_model, xp=xp)
        params = {k: xp.asarray(v, device=device) for k, v in params.items() if k in kwonly_params}
    except KeyError as e:
        raise KeyError(
            f"Model `{physics}` does not exist in the parameter registry for drone `{drone_model}`"
        ) from e
    except ValueError as e:
        raise ValueError(f"Drone model `{drone_model}` not supported for `{physics}`") from e
    return partial(fn, **params)

model_features(model)

Return the feature flags declared by a dynamics function.

Feature flags are set by the supports decorator on each dynamics function and describe which optional inputs the model accepts.

Parameters:

Name Type Description Default
model Callable

A dynamics function, or a functools.partial wrapping one (as returned by parametrize).

required

Returns:

Type Description
dict[str, bool]

A dict of feature names to booleans. Currently contains: - "rotor_dynamics": True if the model accepts and integrates rotor_vel, False if passing rotor_vel raises a ValueError.

Example
from drone_models import model_features
from drone_models.first_principles import dynamics

model_features(dynamics)  # {'rotor_dynamics': True}
Source code in drone_models/__init__.py
def model_features(model: Callable) -> dict[str, bool]:
    """Return the feature flags declared by a dynamics function.

    Feature flags are set by the [supports][drone_models.core.supports] decorator on each
    dynamics function and describe which optional inputs the model accepts.

    Args:
        model: A dynamics function, or a ``functools.partial`` wrapping one (as
            returned by [parametrize][drone_models.parametrize]).

    Returns:
        A dict of feature names to booleans. Currently contains:
            - ``"rotor_dynamics"``: ``True`` if the model accepts and integrates
              ``rotor_vel``, ``False`` if passing ``rotor_vel`` raises a
              ``ValueError``.

    Example:
        ```python
        from drone_models import model_features
        from drone_models.first_principles import dynamics

        model_features(dynamics)  # {'rotor_dynamics': True}
        ```
    """
    if hasattr(model, "func"):  # Is a partial function
        return model_features(model.func)
    return getattr(model, "__drone_model_features__")

Submodules

Models

Module Description
first_principles Full physics model
so_rpy_rotor_drag Fitted model with rotor dynamics and drag
so_rpy_rotor Fitted model with rotor dynamics
so_rpy Simplest fitted model

Core

Module Description
core load_params, supports decorator, internal parametrize
drones available_drones tuple
symbols CasADi symbolic utilities
transform Motor/PWM/rotor conversion utilities

Utilities

Module Description
utils.rotation Quaternion/Euler/angular velocity conversions
utils.data_utils preprocessing, derivatives_svf
utils.identification sys_id_translation, sys_id_rotation