6DOF Quadrotor Rigid Body (12-state)
PARITYS2 · dim 12No clear winner. The survival gap is under 10 percentage points and the balanced-score gap is under 0.05, so neither SolvSRK nor the best baseline clears the win threshold. Either works - choose on cost, licensing, or integration effort. All verdicts →
12-state rigid body 6DOF quadrotor: position (x,y,z), velocity (u,v,w), Euler angles (phi,theta,psi), angular rates (p,q,r). X-frame motor layout with aero drag. Stiffness from fast motor response vs slow position dynamics.
Problem definition
Quan, 'Introduction to Multicopter Design and Control' (2017); Beard & McLain, 'Small Unmanned Aircraft'
Canonical RHS excerpt from the registered callable used for this benchmark cell. Expand it to verify the state equations; it is not a standalone runnable fixture.
Show canonical RHS excerpt
def _motor_speeds(t: float) -> np.ndarray:
"""Motor angular velocities for a typical test manoeuvre."""
w_hover = math.sqrt(_MASS * _G / (4.0 * _Kf))
if t < 2.0:
# Hover
return np.array([w_hover, w_hover, w_hover, w_hover])
elif t < 5.0:
# Pitch forward: increase rear, decrease front
delta = 0.03 * w_hover
return np.array([w_hover - delta, w_hover + delta,
w_hover - delta, w_hover + delta])
elif t < 8.0:
# Yaw right: differential CW/CCW
delta = 0.02 * w_hover
return np.array([w_hover + delta, w_hover + delta,
w_hover - delta, w_hover - delta])
elif t < 12.0:
# Return to hover
return np.array([w_hover, w_hover, w_hover, w_hover])
else:
# Slow descent
return np.array([w_hover * 0.92, w_hover * 0.92,
w_hover * 0.92, w_hover * 0.92])
def rhs_6dof_quad(t, y):
"""12-state rigid-body 6DOF quadrotor dynamics.
State vector: [x, y, z, u, v, w, phi, theta, psi, p, q, r]
"""
dy = np.zeros(12)
u, v, w = y[3], y[4], y[5]
phi, theta, psi = y[6], y[7], y[8]
p, q, r = y[9], y[10], y[11]
# Motor forces and torques
omega = _motor_speeds(t)
F = _Kf * omega**2
M = _Km * omega**2
T_total = np.sum(F)
# Torques from X-frame motor layout
L_roll = _L * (-F[0] + F[1] + F[2] - F[3])
M_pitch = _L * (-F[0] - F[1] + F[2] + F[3])
N_yaw = np.sum(_SPIN_DIRS * M)
# Aero drag (body-frame, linear approximation)
V_body = math.sqrt(u**2 + v**2 + w**2)
if V_body > 0.01:
Fd_x = -_CD_BODY * 0.5 * 1.225 * V_body * u
Fd_y = -_CD_BODY * 0.5 * 1.225 * V_body * v
Fd_z = -_CD_BODY * 0.5 * 1.225 * V_body * w
else:
Fd_x = Fd_y = Fd_z = 0.0
# Rotation matrix elements (ZYX convention: psi, theta, phi)
cphi, sphi = math.cos(phi), math.sin(phi)
cth, sth = math.cos(theta), math.sin(theta)
cpsi, spsi = math.cos(psi), math.sin(psi)
# Position derivatives (NED frame)
dy[0] = (cth * cpsi) * u + (sphi * sth * cpsi - cphi * spsi) * v + \
(cphi * sth * cpsi + sphi * spsi) * w
dy[1] = (cth * spsi) * u + (sphi * sth * spsi + cphi * cpsi) * v + \
(cphi * sth * spsi - sphi * cpsi) * w
dy[2] = (-sth) * u + (sphi * cth) * v + (cphi * cth) * w
# Velocity derivatives (body frame, Newton's 2nd law)
dy[3] = (r * v - q * w) + Fd_x / _MASS - _G * sth
dy[4] = (p * w - r * u) + Fd_y / _MASS + _G * cth * sphi
dy[5] = (q * u - p * v) + Fd_z / _MASS + _G * cth * cphi - T_total / _MASS
# Euler angle derivatives (kinematic equations)
if abs(cth) > 1e-6:
dy[6] = p + (sphi * q + cphi * r) * sth / cth
dy[7] = cphi * q - sphi * r
dy[8] = (sphi * q + cphi * r) / cth
else:
dy[6] = p
dy[7] = cphi * q - sphi * r
dy[8] = 0.0
# Angular rate derivatives (Euler's equations)
dy[9] = (L_roll - ((_Izz - _Iyy) * q * r)) / _Ixx
dy[10] = (M_pitch - ((_Ixx - _Izz) * p * r)) / _Iyy
dy[11] = (N_yaw - ((_Iyy - _Ixx) * p * q)) / _Izz
return dy- Parameters
- _CD_BODY = 0.25
- _G = 9.80665
- _Ixx = 0.0082
- _Iyy = 0.0082
- _Izz = 0.0148
- _Kf = 0.000611
- _Km = 1.5e-05
- _L = 0.159099025767
- _MASS = 1.5
- _SPIN_DIRS = [1, 1, -1, -1]
- Initial condition
- y(0) = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
- Horizon
- t ∈ [0, 15]
Canonical RHS excerpt captured from the same registered callable used for the published benchmark. Frozen closure values are summarized below; helper imports and solver settings are intentionally omitted.
Fingerprint
Spread: low
Default noise: medium
Recommendation snapshot
Clean best: SolvSRK
Noisy best: SciPy LSODA
Coverage
14 solver arms · clean + 5 noise levels
Ranked on survival, precision, and speed
Versions & freeze
Methodology →- Freeze
- 2026-08-13
- libsolvsrk
- 2.3.0
- SciPy
- 1.14
- SUNDIALS
- CVODE (bundled backend)
20 seeds/cell default · 14 arms · TRL 4–5 · simulation-lab validated · this page: 6DOF Quadrotor Rigid Body (12-state) (6dof-quadrotor-rigid-body-12-state)
Governed SolvTune benchmark freeze; per-arm medians only. RHS definitions and raw trial rows are not published.
Self-reported by Resonix Labs · not independently verified
Results matrix
Pick an objective and a noise level to rank all arms on survival, median SCD, median nfev, and median wall time. Medians across seeds.
Objective
Best overall trade-off of survival, precision, and speed.
Noise level
| # | Solver | Survival | SCD | nfev | Wall | Score |
|---|---|---|---|---|---|---|
| 1 | SolvSRK | 100% | 9.5 | 31,849 | 333 ms | 0.845 |
| 2 | SciPy RadauSciPy | 100% | 7.5 | 50,235 | 1.67 s | 0.798 |
| 3 | SciPy LSODASciPy | 100% | 6.8 | 7,862 | 129 ms | 0.780 |
| 4 | SciPy BDFSciPy | 100% | 6.3 | 17,131 | 774 ms | 0.769 |
| 5 | SciPy RK23SciPy | 100% | 5.9 | 74,879 | 1.65 s | 0.760 |
| 6 | CVODE Adamsexternal | 100% | 5.6 | 6,076 | 127 ms | 0.753 |
| 7 | SciPy DOP853SciPy | 100% | 5.6 | 9,518 | 179 ms | 0.752 |
| 8 | CVODE BDFexternal | 100% | 5.2 | 7,528 | 158 ms | 0.742 |
| 9 | SciPy RK45SciPy | 100% | 5.1 | 13,094 | 261 ms | 0.740 |
| 10 | Tsit5external | 100% | 4.8 | 13,536 | 2.28 s | 0.733 |
At Clean, best balanced arm is SolvSRK.
Values are medians across seeds, measured by Resonix Labs on Resonix hardware and not independently verified; nfev and wall are on reference lab hardware (indicative). Under injected noise only SolvSRK and the SciPy arms are run. How we measure accuracy → · Verification status →
Cite this page
Replace the access date. Pin the freeze ID and library versions when comparing against a later export. Cite it as what it is - a self-reported vendor benchmark, not an independently verified result. The note field says so; please keep it.
@misc{resonix_evidence_6dof_quadrotor_rigid_body_12_state_2026,
title = {Resonix Evidence Portal: 6DOF Quadrotor Rigid Body (12-state)},
author = {{Resonix Labs (Canada) Inc.}},
year = {2026},
howpublished = {\url{https://resonixusa.com/evidence/problems/6dof-quadrotor-rigid-body-12-state}},
note = {Self-reported vendor benchmark; internally generated by Resonix Labs and not independently verified. Accessed YYYY-MM-DD. Freeze 2026-08-13; libsolvsrk 2.3.0; SciPy 1.14.}
}Related
TRL 4–5 · simulation-lab validated · 398 problems · 14 solver arms · clean + 5 noise levels
Freeze: 2026-08-13 · scipy 1.14 · libsolvsrk 2.3.0 · Methodology
Self-reported by Resonix Labs · not independently verified · Verification status