Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 84 additions & 43 deletions crazyflow/dynamics/first_principles/__init__.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,31 @@
r"""Full rigid-body dynamics for a quadrotor.

This package implements Newton-Euler dynamics based on physical constants: mass, inertia, motor
This package implements Newton-Euler dynamics based on physical parameters: mass, inertia, motor
thrust and torque curves, arm length, and drag coefficients. The command interface is four motor
angular velocities in RPM. No data fitting is required; all parameters are measurable physical
quantities.
angular velocities in RPM. Mass and arm length are measured directly and the propeller inertia is
taken from CAD data. The thrust and torque curves are fitted to load cell data, and the inertia and
drag coefficients are identified from flight data.

Motor forces and torques are quadratic polynomials in RPM:
When rotor dynamics are modelled, the rotor speeds evolve as:

\[
f_{p,i} = k_0 + k_1 \Omega_i + k_2 \Omega_i^2, \qquad
\tau_{p,i} = m_0 + m_1 \Omega_i + m_2 \Omega_i^2.
\dot{\boldsymbol{\Omega}} = \begin{cases}
\hat{c}_\mathrm{v} (\boldsymbol{\Omega}_\mathrm{cmd} - \boldsymbol{\Omega})
+ \hat{c}_\mathrm{d} (\boldsymbol{\Omega}_\mathrm{cmd}^2 - \boldsymbol{\Omega}^2)
& \forall\, \boldsymbol{\Omega}_\mathrm{cmd} \geq \boldsymbol{\Omega}, \\
\check{c}_\mathrm{v} (\boldsymbol{\Omega}_\mathrm{cmd} - \boldsymbol{\Omega})
+ \check{c}_\mathrm{d} (\boldsymbol{\Omega}_\mathrm{cmd}^2 - \boldsymbol{\Omega}^2)
& \forall\, \boldsymbol{\Omega}_\mathrm{cmd} < \boldsymbol{\Omega}.
\end{cases}
\]

When rotor dynamics are modelled, each motor RPM evolves as:
Each motor produces a thrust and a drag torque, both quadratic polynomials of its rotor speed in
RPM:

\[
\dot{\Omega}_i = \begin{cases}
c_1 (\Omega_{\mathrm{cmd},i} - \Omega_i)
+ c_2 (\Omega_{\mathrm{cmd},i}^2 - \Omega_i^2)
& \Omega_{\mathrm{cmd},i} \geq \Omega_i \\[4pt]
c_3 (\Omega_{\mathrm{cmd},i} - \Omega_i)
+ c_4 (\Omega_{\mathrm{cmd},i}^2 - \Omega_i^2)
& \Omega_{\mathrm{cmd},i} < \Omega_i
\end{cases}
f_{\mathrm{m},i} = k_{\mathrm{f},0} + k_{\mathrm{f},1} \Omega_i + k_{\mathrm{f},2} \Omega_i^2,
\qquad
t_{\mathrm{m},i} = k_{\mathrm{t},0} + k_{\mathrm{t},1} \Omega_i + k_{\mathrm{t},2} \Omega_i^2.
\]

The rigid-body equations of motion are:
Expand All @@ -32,53 +35,91 @@
\dot{\mathbf{p}} &= \mathbf{v}, \\
\dot{\mathbf{q}} &= \tfrac{1}{2}
\mathbf{q} \otimes \begin{bmatrix} {}^{\mathcal{B}}\boldsymbol{\omega}\\0 \end{bmatrix}, \\
m\dot{\mathbf{v}} &= m\mathbf{g}
+ R\,{}^{\mathcal{B}}\mathbf{f}_t
+ R\,{}^{\mathcal{B}}\mathbf{f}_a, \\
m\dot{\mathbf{v}} &= \mathbf{f}_\Sigma, \\
\mathbf{J}\,{}^{\mathcal{B}}\dot{\boldsymbol{\omega}} &=
{}^{\mathcal{B}}\mathbf{t}_\Sigma
- {}^{\mathcal{B}}\boldsymbol{\omega}
\times \mathbf{J}\,{}^{\mathcal{B}}\boldsymbol{\omega},
\end{aligned}
\]

where \(R = {}^{\mathcal{I}}R_{\mathcal{B}}(\mathbf{q})\) is the rotation from body to world frame,
and the forces and torques are:
where the total force and torque are:

\[
\begin{aligned}
{}^{\mathcal{B}}\mathbf{f}_t &=
\mathbf{e}_z \textstyle\sum_{i=1}^{4} f_{p,i}, \\
{}^{\mathcal{B}}\mathbf{f}_a &= D_b\,R^{\top}\mathbf{v}, \\
{}^{\mathcal{B}}\mathbf{t}_\Sigma &=
{}^{\mathcal{B}}\mathbf{t}_t
+ {}^{\mathcal{B}}\mathbf{t}_d
+ {}^{\mathcal{B}}\mathbf{t}_i,
\mathbf{f}_\Sigma &= \mathbf{f}_\mathrm{g}
+ \mathbf{R}\,{}^{\mathcal{B}}\mathbf{f}_\mathrm{t}
+ \mathbf{R}\,{}^{\mathcal{B}}\mathbf{f}_\mathrm{a}, \\
{}^{\mathcal{B}}\mathbf{t}_\Sigma &= {}^{\mathcal{B}}\mathbf{t}_\mathrm{t}
+ {}^{\mathcal{B}}\mathbf{t}_\mathrm{d}
+ {}^{\mathcal{B}}\mathbf{t}_\mathrm{g}
+ {}^{\mathcal{B}}\mathbf{t}_\mathrm{r}.
\end{aligned}
\]

with:
The individual terms are defined as:

\[
\begin{aligned}
{}^{\mathcal{B}}\mathbf{t}_t &=
\frac{l}{\sqrt{2}}
\begin{bmatrix}1&0&0\\0&1&0\\0&0&0\end{bmatrix}
M\,\mathbf{f}_p, \\
{}^{\mathcal{B}}\mathbf{t}_d &=
\begin{bmatrix}0&0&0\\0&0&0\\0&0&1\end{bmatrix}
M\,\boldsymbol{\tau}_p, \\
{}^{\mathcal{B}}\mathbf{t}_i &= J_p
\begin{bmatrix}
-{}^{\mathcal{B}}\omega_y\;\mathbf{m}_z^{\top}\boldsymbol{\Omega} \\
-{}^{\mathcal{B}}\omega_x\;\mathbf{m}_z^{\top}\boldsymbol{\Omega} \\
\mathbf{m}_z^{\top}\dot{\boldsymbol{\Omega}}
\end{bmatrix},
\mathbf{f}_\mathrm{g} &= m\mathbf{g}, \\
{}^{\mathcal{B}}\mathbf{f}_\mathrm{t} &=
\mathbf{e}_\mathrm{z} \textstyle\sum_{i=1}^{4} f_{\mathrm{m},i}, \\
{}^{\mathcal{B}}\mathbf{f}_\mathrm{a} &= \mathbf{C}_\mathrm{a}\,{}^{\mathcal{B}}\mathbf{v}, \\
{}^{\mathcal{B}}\mathbf{t}_\mathrm{t} &=
l\,\mathrm{diag}(1, 1, 0)\,\mathbf{M}\,\mathbf{f}_\mathrm{m}, \\
{}^{\mathcal{B}}\mathbf{t}_\mathrm{d} &=
\mathrm{diag}(0, 0, 1)\,\mathbf{M}\,\mathbf{t}_\mathrm{m}, \\
{}^{\mathcal{B}}\mathbf{t}_\mathrm{g} &= J_\mathrm{p}
\left({}^{\mathcal{B}}\boldsymbol{\omega} \times \mathbf{e}_\mathrm{z}\right)
\mathbf{e}_\mathrm{z}^{\top} \mathbf{M}\,\boldsymbol{\Omega}, \\
{}^{\mathcal{B}}\mathbf{t}_\mathrm{r} &= J_\mathrm{p}\,\mathbf{e}_\mathrm{z}\,
\mathbf{e}_\mathrm{z}^{\top} \mathbf{M}\,\dot{\boldsymbol{\Omega}}.
\end{aligned}
\]

where \(D_b\) is the body-frame drag matrix, \(l\) is the motor arm length, \(J_p\) is the propeller
moment of inertia, \(M\) is the \(3\times 4\) mixing matrix, and \(\mathbf{m}_z\) is its last row.
The gyroscopic and reaction torques convert \(\boldsymbol{\Omega}\) and
\(\dot{\boldsymbol{\Omega}}\) to rad/s.

| Variable | Name | Description |
| --- | --- | --- |
| \(\boldsymbol{\Omega}\), \(\Omega_i\) | `rotor_vel` | Rotor speeds in RPM |
| \(\boldsymbol{\Omega}_\mathrm{cmd}\) | `cmd` | Commanded rotor speeds in RPM |
| \(\mathbf{f}_\mathrm{m}\), \(f_{\mathrm{m},i}\) | | Motor thrusts |
| \(\mathbf{t}_\mathrm{m}\), \(t_{\mathrm{m},i}\) | | Motor drag torques |
| \(\mathbf{p}\) | `pos` | Position in m |
| \(\mathbf{q}\) | `quat` | Orientation as a scalar-last quaternion |
| \(\mathbf{v}\) | `vel` | Velocity in m/s |
| \({}^{\mathcal{B}}\boldsymbol{\omega}\) | `ang_vel` | Angular velocity in rad/s |
| \(\mathbf{f}_\Sigma\) | | Total force |
| \({}^{\mathcal{B}}\mathbf{t}_\Sigma\) | | Total torque |
| \(\mathbf{f}_\mathrm{g}\) | | Gravitational force |
| \({}^{\mathcal{B}}\mathbf{f}_\mathrm{t}\) | | Thrust force |
| \({}^{\mathcal{B}}\mathbf{f}_\mathrm{a}\) | | Aerodynamic drag force |
| \({}^{\mathcal{B}}\mathbf{t}_\mathrm{t}\) | | Thrust torque |
| \({}^{\mathcal{B}}\mathbf{t}_\mathrm{d}\) | | Aerodynamic counter torque of the propellers |
| \({}^{\mathcal{B}}\mathbf{t}_\mathrm{g}\) | | Gyroscopic torque |
| \({}^{\mathcal{B}}\mathbf{t}_\mathrm{r}\) | | Reaction torque |
| \(\mathbf{R}\) | | Rotation from body to world frame |
| \(\mathbf{e}_\mathrm{z}\) | | Unit vector in z direction |
| \({}^{\mathcal{B}}(\cdot)\) | | Quantity in the body frame, world frame if unmarked |
| \(\otimes\) | | Quaternion product |
| \(\mathrm{diag}(\cdot)\) | | Diagonal matrix |

| Parameter | Name | Description |
| --- | --- | --- |
| \(\hat{c}_\mathrm{v}\) | `rotor_dyn_coef` | Viscous damping on spin-up, entry 0 |
| \(\hat{c}_\mathrm{d}\) | `rotor_dyn_coef` | Drag on spin-up, entry 1 |
| \(\check{c}_\mathrm{v}\) | `rotor_dyn_coef` | Viscous damping on spin-down, entry 2 |
| \(\check{c}_\mathrm{d}\) | `rotor_dyn_coef` | Drag on spin-down, entry 3 |
| \(k_{\mathrm{f},0}, k_{\mathrm{f},1}, k_{\mathrm{f},2}\) | `rpm2thrust` | Thrust curve |
| \(k_{\mathrm{t},0}, k_{\mathrm{t},1}, k_{\mathrm{t},2}\) | `rpm2torque` | Torque curve |
| \(m\) | `mass` | Mass in kg |
| \(\mathbf{J}\) | `J` | Inertia matrix in kg m² |
| \(\mathbf{g}\) | `gravity_vec` | Gravity vector in m/s² |
| \(l\) | `L` | Distance of the motors to the body axes in m |
| \(\mathbf{M}\) | `mixing_matrix` | Mixing matrix of motor placement and spin direction |
| \(J_\mathrm{p}\) | `prop_inertia` | Combined inertia of one propeller and its motor in kg m² |
| \(\mathbf{C}_\mathrm{a}\) | `drag_matrix` | Drag coefficients in matrix form in N/(m/s) |
"""

from crazyflow.dynamics.first_principles.dynamics import (
Expand Down
64 changes: 33 additions & 31 deletions crazyflow/dynamics/first_principles/dynamics.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
"""First-principles dynamics-based quadrotor dynamics.

This module implements full rigid-body dynamics for a quadrotor based on Newton-Euler equations. The
dynamics are parameterised with physical constants (mass, inertia, thrust and torque curves, motor
arm length, drag coefficients) and require no data fitting. Propeller gyroscopic effects are
included.
dynamics are parameterised with physical quantities (mass, inertia, thrust and torque curves, motor
arm length, drag coefficients). Propeller gyroscopic effects are included.

The command interface is four motor angular velocities in RPM.

Expand Down Expand Up @@ -79,20 +78,21 @@ def dynamics(
dist_t: Disturbance torque (Nm) in the world frame acting on the CoM.

mass: Mass of the drone (kg).
L: Distance from the CoM to the motors (m). Shared (1,) or one value per motor (4,).
prop_inertia: Inertia of the propellers in z direction (kg m^2). Shared (1,) or one value
per motor (4,).
L: Distance of the motors to the body axes (m). Shared (1,) or one value per motor (4,).
prop_inertia: Combined inertia of one propeller and its motor (kg m^2). Shared (1,) or one
value per motor (4,).
gravity_vec: Gravity vector (m/s^2). We assume the gravity vector points downwards, e.g.
[0, 0, -9.81].
J: Inertia matrix (kg m^2).
J_inv: Inverse inertia matrix (1/kg m^2).
rpm2thrust: Propeller force constants (N min^2). Shared (1, 3) or one curve per motor
(4, 3).
rpm2torque: Propeller torque constants (Nm min^2). Shared (1, 3) or one curve per motor
(4, 3).
mixing_matrix: Mixing matrix denoting the turn direction of the motors (4x3).
drag_matrix: Drag matrix containing the linear drag coefficients (3x3).
rotor_dyn_coef: Rotor dynamics coefficients. Shared (1, 4) or one set per motor (4, 4).
rpm2thrust: Thrust curve coefficients [k_f0, k_f1, k_f2] for rotor speeds in RPM. Shared
(1, 3) or one curve per motor (4, 3).
rpm2torque: Torque curve coefficients [k_t0, k_t1, k_t2] for rotor speeds in RPM. Shared
(1, 3) or one curve per motor (4, 3).
mixing_matrix: Mixing matrix of motor placement and spin direction (3x4).
drag_matrix: Drag coefficients in matrix form (N/(m/s), 3x3).
rotor_dyn_coef: Rotor dynamics coefficients, viscous damping and drag on spin-up followed by
viscous damping and drag on spin-down. Shared (1, 4) or one set per motor (4, 4).

Note:
All array parameters accept leading batch axes (N, M) to vary per world and per drone.
Expand Down Expand Up @@ -205,22 +205,24 @@ def symbolic_dynamics(
model_dist_f: If ``True``, a 3-D force disturbance is appended to ``X``.
model_dist_t: If ``True``, a 3-D torque disturbance is appended to ``X``.
mass: Drone mass in kg.
L: Distance from centre of mass to the motors in meters, shared ``(1,)`` or one value per
L: Distance of the motors to the body axes in meters, shared ``(1,)`` or one value per
motor ``(4,)``.
prop_inertia: Moment of inertia of the propellers about their spin axis in kg m², shared
``(1,)`` or one value per motor ``(4,)``.
prop_inertia: Combined inertia of one propeller and its motor in kg m², shared ``(1,)`` or
one value per motor ``(4,)``.
gravity_vec: Gravity vector, shape ``(3,)``.
J: Inertia matrix, shape ``(3, 3)``.
J_inv: Inverse inertia matrix, shape ``(3, 3)``.
rpm2thrust: Polynomial coefficients ``[a, b, c]`` for the thrust curve
``f = a + b * rpm + c * rpm²``, shared ``(1, 3)`` or one curve per motor ``(4, 3)``.
rpm2torque: Polynomial coefficients ``[a, b, c]`` for the drag-torque curve
``τ = a + b * rpm + c * rpm²``, shared ``(1, 3)`` or one curve per motor ``(4, 3)``.
mixing_matrix: Matrix of shape ``(3, 4)`` mapping per-motor forces to body torques.
rotor_dyn_coef: Four rotor dynamics coefficients ``[k_acc1, k_acc2, k_dec1, k_dec2]`` used
in the piecewise-linear spin-up/down model, shared ``(1, 4)`` or one set per motor
rpm2thrust: Thrust curve coefficients ``[k_f0, k_f1, k_f2]`` with
``f = k_f0 + k_f1 * rpm + k_f2 * rpm²``, shared ``(1, 3)`` or one curve per motor
``(4, 3)``.
rpm2torque: Torque curve coefficients ``[k_t0, k_t1, k_t2]`` with
``t = k_t0 + k_t1 * rpm + k_t2 * rpm²``, shared ``(1, 3)`` or one curve per motor
``(4, 3)``.
mixing_matrix: Mixing matrix of motor placement and spin direction, shape ``(3, 4)``.
rotor_dyn_coef: Rotor dynamics coefficients, viscous damping and drag on spin-up followed by
viscous damping and drag on spin-down, shared ``(1, 4)`` or one set per motor
``(4, 4)``.
drag_matrix: Diagonal ``(3, 3)`` matrix of linear drag coefficients.
drag_matrix: Drag coefficients in matrix form in N/(m/s), shape ``(3, 3)``.

Returns:
Tuple ``(X_dot, X, U, Y)`` of CasADi ``MX`` expressions:
Expand Down Expand Up @@ -319,25 +321,25 @@ class Params:
mass: Array = field(metadata={CORE_NDIM_KEY: 1}) # (1,)
"""Mass of the drone."""
L: Array = field(metadata={CORE_NDIM_KEY: 1}) # (1,)
"""Arm length of the drone. One shared value, or one value per motor with shape (4,)."""
"""Distance of the motors to the body axes. One shared value, or one per motor (4,)."""
prop_inertia: Array = field(metadata={CORE_NDIM_KEY: 1}) # (1,)
"""Inertia of the propellers. One shared value, or one value per motor with shape (4,)."""
"""Inertia of one propeller and its motor. One shared value, or one per motor (4,)."""
gravity_vec: Array = field(metadata={CORE_NDIM_KEY: 1}) # (3,)
"""Gravity vector of the drone."""
J: Array = field(metadata={CORE_NDIM_KEY: 2}) # (3, 3)
"""Inertia matrix of the drone."""
J_inv: Array = field(metadata={CORE_NDIM_KEY: 2}) # (3, 3)
"""Inverse of the inertia matrix of the drone."""
rpm2thrust: Array = field(metadata={CORE_NDIM_KEY: 2}) # (1, 3)
"""Force constants of the drone. One shared curve, or one curve per motor with shape (4, 3)."""
"""Thrust curve coefficients. One shared curve, or one curve per motor with shape (4, 3)."""
rpm2torque: Array = field(metadata={CORE_NDIM_KEY: 2}) # (1, 3)
"""Torque constants of the drone. One shared curve, or one curve per motor with shape (4, 3)."""
"""Torque curve coefficients. One shared curve, or one curve per motor with shape (4, 3)."""
mixing_matrix: Array = field(metadata={CORE_NDIM_KEY: 2}) # (3, 4)
"""Mixing matrix of the drone."""
"""Mixing matrix of motor placement and spin direction."""
drag_matrix: Array = field(metadata={CORE_NDIM_KEY: 2}) # (3, 3)
"""Drag matrix of the drone."""
"""Drag coefficients in matrix form."""
rotor_dyn_coef: Array = field(metadata={CORE_NDIM_KEY: 2}) # (1, 4)
"""Rotor speed dynamics coefficients of the drone. One shared set, or one per motor (4, 4)."""
"""Rotor dynamics coefficients. One shared set, or one per motor (4, 4)."""

@staticmethod
def create(drone: str, device: Device) -> Params:
Expand Down
4 changes: 2 additions & 2 deletions crazyflow/dynamics/first_principles/params.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
# ]
# thrust_min = 0.0 # N per motor
# thrust_max = 0.0 # N per motor
# L = 0.0 # m, CoM to motor distance
# L = 0.0 # m, distance of the motors to the body axes
# prop_inertia = 0.0 # kg m^2, zero drops the gyroscopic and reaction torque of the propellers
# rpm2thrust = [0.0, 0.0, 0.0] # N, polynomial in RPM by index
# rpm2torque = [0.0, 0.0, 0.0] # Nm, polynomial in RPM by index
Expand All @@ -22,7 +22,7 @@
# [-1.0, 1.0, 1.0, -1.0],
# [-1.0, 1.0, -1.0, 1.0]
# ]
# drag_matrix = [ # 1/s, zero disables drag
# drag_matrix = [ # N/(m/s), zero disables drag
# [0.0, 0.0, 0.0],
# [0.0, 0.0, 0.0],
# [0.0, 0.0, 0.0]
Expand Down
44 changes: 33 additions & 11 deletions crazyflow/dynamics/so_rpy/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,51 @@
\[
\begin{aligned}
\dot{\mathbf{p}} &= \mathbf{v}, \\
m\dot{\mathbf{v}} &= m\mathbf{g}
+ (c_{\mathrm{acc}} + c_f F_{\mathrm{cmd}})\,R\,\mathbf{e}_z, \\
\ddot{\boldsymbol{\psi}} &=
c_{\psi}\,\boldsymbol{\psi}
+ c_{\dot{\psi}}\,\dot{\boldsymbol{\psi}}
+ c_u\,\mathbf{u}_{\mathrm{rpy}},
m\dot{\mathbf{v}} &= \mathbf{f}_\mathrm{g}
+ \mathbf{R}\,\mathbf{e}_\mathrm{z}
(c_\mathrm{acc} + c_\mathrm{f} f_{\Sigma,\mathrm{cmd}}), \\
\ddot{\boldsymbol{\Psi}} &=
\boldsymbol{c}_{\boldsymbol{\Psi},1}\,\boldsymbol{\Psi}
+ \boldsymbol{c}_{\boldsymbol{\Psi},2}\,\dot{\boldsymbol{\Psi}}
+ \boldsymbol{c}_{\boldsymbol{\Psi},3}\,\boldsymbol{\Psi}_\mathrm{cmd},
\end{aligned}
\]

The vector \(\boldsymbol{\psi} = [\phi,\theta,\psi]^{\top}\) holds the roll, pitch, and yaw angles
with rates \(\dot{\boldsymbol{\psi}}\). The coefficients \(c_{\psi}\), \(c_{\dot{\psi}}\), and
\(c_u\) are identified from flight data.
where \(\mathbf{f}_\mathrm{g} = m\mathbf{g}\).

!!! note
This is the native Euler-angle form, matching
[symbolic_dynamics_euler][crazyflow.dynamics.so_rpy.symbolic_dynamics_euler]. The simulation
does not integrate this state directly. It shares the common ``[pos, quat, vel, ang_vel]`` state
with the other models and advances the orientation from the body angular velocity
\({}^{\mathcal{B}}\boldsymbol{\omega}\), converting \(\ddot{\boldsymbol{\psi}} \leftrightarrow
\({}^{\mathcal{B}}\boldsymbol{\omega}\), converting \(\ddot{\boldsymbol{\Psi}} \leftrightarrow
{}^{\mathcal{B}}\dot{\boldsymbol{\omega}}\) through the kinematic Jacobian at every step.
Integrating from \({}^{\mathcal{B}}\boldsymbol{\omega}\) rather than \(\dot{\boldsymbol{\psi}}\)
Integrating from \({}^{\mathcal{B}}\boldsymbol{\omega}\) rather than \(\dot{\boldsymbol{\Psi}}\)
makes the discrete trajectory differ slightly from integrating the Euler state directly. The
difference, however, is negligible at our default frequency of 500 Hz.

| Variable | Name | Description |
| --- | --- | --- |
| \(\mathbf{p}\) | `pos` | Position in m |
| \(\mathbf{v}\) | `vel` | Velocity in m/s |
| \(\boldsymbol{\Psi} = [\phi,\theta,\psi]^{\top}\) | | Roll, pitch, and yaw in rad, from `quat` |
| \(\dot{\boldsymbol{\Psi}}\) | | Roll, pitch, and yaw rates in rad/s, from `ang_vel` |
| \(\boldsymbol{\Psi}_\mathrm{cmd}\) | `cmd[:3]` | Commanded roll, pitch, and yaw in rad |
| \(f_{\Sigma,\mathrm{cmd}}\) | `cmd[3]` | Commanded collective thrust in N |
| \(\mathbf{f}_\mathrm{g}\) | | Gravitational force |
| \(\mathbf{R}\) | | Rotation from body to world frame |
| \(\mathbf{e}_\mathrm{z}\) | | Unit vector in z direction |
| \({}^{\mathcal{B}}(\cdot)\) | | Quantity in the body frame, world frame if unmarked |

| Parameter | Name | Description |
| --- | --- | --- |
| \(m\) | `mass` | Mass in kg |
| \(\mathbf{g}\) | `gravity_vec` | Gravity vector in m/s² |
| \(c_\mathrm{acc}\) | `acc_coef` | Thrust offset |
| \(c_\mathrm{f}\) | `cmd_f_coef` | Thrust scaling coefficient |
| \(\boldsymbol{c}_{\boldsymbol{\Psi},1}\) | `rpy_coef` | Rotational dynamics coefficients |
| \(\boldsymbol{c}_{\boldsymbol{\Psi},2}\) | `rpy_rates_coef` | Rotational dynamics coefficients |
| \(\boldsymbol{c}_{\boldsymbol{\Psi},3}\) | `cmd_rpy_coef` | Rotational dynamics coefficients |
"""

from crazyflow.dynamics.so_rpy.dynamics import (
Expand Down
Loading
Loading