cubs2_dynamics
Aircraft dynamics modeling and analysis tools for Cubs2. This package provides pure analysis and modeling capabilities with no ROS dependencies, making it reusable in non-ROS contexts.
Features
Differentiable dynamics models - Using CasADi for automatic differentiation
Hierarchical model composition - Combine multiple models into integrated systems
Type-safe modeling - Structured dataclass-based state, input, and output definitions
Linearization - Compute linear approximations around operating points
Trim analysis - Find equilibrium flight conditions
Numerical integration - RK4 and other integrators with single-loop composition
SportCub model - Complete 6-DOF aircraft dynamics
Modules
Model Framework
The core modeling framework is provided by the Cyecca library:
ModelSX - Base class for dynamics models with symbolic differentiation (from
cyecca.dynamics)Integrators - Numerical integration schemes (RK4, Euler)
Linearization - Linearization utilities for nonlinear systems (from
cyecca.dynamics.linearize)
Aircraft Models
sportcub.py- Complete SportCub aircraft dynamics modelAerodynamics (lift, drag, moments)
Propulsion (thrust)
Ground contact dynamics
6-DOF rigid body equations
Analysis Tools
trim_fixed_wing.py- Compute trim conditions for steady flight
Hierarchical Model Composition
The framework supports composing multiple subsystem models into a single integrated model with a unified integration loop:
from cyecca.dynamics import ModelSX
from cubs2_dynamics.sportcub import sportcub
from cubs2_control.autolevel_controller import autolevel_controller
# Create submodels
aircraft = sportcub()
controller = autolevel_controller()
# Compose into parent system
parent = ModelSX.compose({
"plant": aircraft,
"controller": controller
})
# Connect signals between subsystems
parent.connect("controller.u.q", "plant.x.r") # Controller reads aircraft orientation
parent.connect("controller.u.omega", "plant.x.w") # Controller reads angular velocity
parent.connect("plant.u.ail", "controller.y.ail") # Aircraft gets aileron command
# Build integrated dynamics with single RK4 integrator
parent.build_composed(integrator="rk4")
# Simulate composed system (single integration step for all subsystems)
x_next = parent.f_step(x=x0_vec, u=u_vec, p=p_vec, dt=0.01)
# Access subsystem states with structured syntax
aircraft_pos = x0.plant.p # Aircraft position
controller_integral = x0.controller.i_p # Controller integral state
Key Features:
Single integration loop - All subsystems integrated together for numerical accuracy
Structured state access -
x.plant.p,x.controller.i_pinstead of index-based accessType-safe connections - String-based paths with compile-time validation
Automatic state composition - Parent state created by merging subsystem states
Examples
Simulate Aircraft Dynamics
from cubs2_dynamics.sportcub import SportCubModel
from cyecca.dynamics.integrators import rk4
import numpy as np
# Create model
model = SportCubModel()
# Initial state [x, y, z, vx, vy, vz, qw, qx, qy, qz, p, q, r]
x0 = model.get_initial_state()
# Control input [aileron, elevator, rudder, throttle]
u = np.array([0.0, 0.1, 0.0, 0.5])
# Time step
dt = 0.01
# Simulate one step
x_next = rk4(lambda x: model.dynamics(x, u), x0, dt)
Compute Trim Condition
from cubs2_dynamics.trim_fixed_wing import compute_trim
# Find trim for level flight at 20 m/s
trim_state, trim_control = compute_trim(
velocity=20.0,
altitude=100.0,
gamma=0.0 # level flight
)
Linearization
from cyecca.dynamics.linearize import linearize_dynamics
# Linearize around trim condition
A, B = linearize_dynamics(model, trim_state, trim_control)
Testing
# Run all dynamics tests
colcon test --packages-select cubs2_dynamics
colcon test-result --verbose
Tests cover:
Model consistency and Jacobian correctness
Integration accuracy
Trim computation
Linearization
Dependencies
Python Libraries:
numpy - Numerical arrays
scipy - Scientific computing
casadi - Automatic differentiation and optimization
cyecca - Dynamics modeling framework
Build Dependencies:
ament_cmake
ament_cmake_python
No ROS Dependencies
This package intentionally has no ROS runtime dependencies to keep the dynamics models reusable in:
Non-ROS simulation environments
MATLAB/Simulink integration
Standalone analysis scripts
Hardware-in-the-loop testing