Architecture
Cubs2 follows a layered architecture separating dynamics, control, and ROS integration.
System Overview
┌─────────────────────────────────────────────┐
│ cubs2_bringup (Launch) │
└──────────────┬──────────────────────────────┘
│
┌──────────────┴──────────────────────────────┐
│ │
│ cubs2_simulation (ROS2 Runtime) │
│ ┌───────────────────────────────────────┐ │
│ │ cubs2_control (Controllers) │ │
│ │ ┌────────────────────────────────┐ │ │
│ │ │ cubs2_dynamics (Physics) │ │ │
│ │ │ ┌─────────────────────────┐ │ │ │
│ │ │ │ cyecca (Core Models) │ │ │ │
│ │ │ └─────────────────────────┘ │ │ │
│ │ └────────────────────────────────┘ │ │
│ └───────────────────────────────────────┘ │
└──────────────────────────────────────────────┘
Layer Responsibilities
Cyecca Layer
Location: External library (pip install cyecca)
Responsibilities:
Core ModelSX framework
Symbolic differentiation (CasADi)
Numerical integrators
Linearization tools
Generic dynamics utilities
Dependencies: numpy, scipy, casadi
ROS: None
cubs2_dynamics
Responsibilities:
Aircraft-specific models (SportCub)
Trim computation
Aerodynamic coefficients
Ground contact dynamics
Dependencies: cyecca, numpy, scipy, casadi
ROS: None
cubs2_control
Responsibilities:
Attitude controllers
PID controllers
Closed-loop compositions
Control algorithms
Dependencies: cubs2_dynamics, cyecca
ROS: None
cubs2_simulation
Responsibilities:
ROS2 node implementation
Message publishing/subscribing
Real-time scheduling
TF broadcasting
Gamepad integration
Dependencies: cubs2_dynamics, cubs2_control, cubs2_msgs
ROS: rclpy, geometry_msgs, sensor_msgs
cubs2_planning
Responsibilities:
Dubins path planning
Racecourse navigation
Waypoint generation
Path visualization
Dependencies: cubs2_msgs
ROS: rclpy, nav_msgs, visualization_msgs
cubs2_rviz
Responsibilities:
Custom RViz panels
Video streaming
HUD display
Joystick widget
Simulation controls
Dependencies: cubs2_msgs, Qt5, GStreamer
ROS: rclcpp, rviz_common, pluginlib
cubs2_bringup
Responsibilities:
System launch files
Parameter configuration
Node orchestration
Dependencies: All other cubs2 packages
ROS: launch, launch_ros
Data Flow
Simulation Loop
┌─────────────────┐
│ User Input │ (/joy, /control)
└────────┬────────┘
│
v
┌─────────────────┐
│ Controller │ (cubs2_control)
└────────┬────────┘
│
v
┌─────────────────┐
│ Dynamics │ (cubs2_dynamics)
└────────┬────────┘
│
v
┌─────────────────┐
│ Integration │ (RK4)
└────────┬────────┘
│
v
┌─────────────────┐
│ State Update │
└────────┬────────┘
│
v
┌─────────────────┐
│ ROS Messages │ (/pose, /velocity, /imu)
└─────────────────┘
Message Types
Custom Messages
cubs2_msgs/AircraftControl- Control surface commands
Standard Messages
geometry_msgs/PoseStamped- Position and orientationgeometry_msgs/TwistStamped- Velocitiessensor_msgs/Imu- IMU measurementsnav_msgs/Path- Planned trajectoryvisualization_msgs/MarkerArray- Visual markers
Hierarchical Composition
ModelSX Framework
Cubs2 uses Cyecca’s ModelSX for hierarchical model composition:
# Create submodels
aircraft = sportcub()
controller = autolevel_controller()
# Compose
system = ModelSX.compose({
"plant": aircraft,
"controller": controller
})
# Connect signals
system.connect("controller.u.q", "plant.x.r")
system.connect("plant.u.ail", "controller.y.ail")
# Build with single integrator
system.build_composed(integrator="rk4")
Benefits:
Single integration loop (numerical accuracy)
Type-safe state access (
x.plant.pnotx[0:3])Reusable subsystems
Clear signal flow
Plugin Architecture
RViz Panels
Panels use Qt5 and RViz2 API:
class MyPanel : public rviz_common::Panel {
Q_OBJECT
public:
MyPanel(QWidget* parent = nullptr);
private:
rclcpp::Node::SharedPtr node_;
rclcpp::Publisher<...>::SharedPtr pub_;
};
PLUGINLIB_EXPORT_CLASS(cubs2::MyPanel, rviz_common::Panel)
Design Principles
Separation of Concerns
Dynamics ≠ ROS
Control ≠ ROS
Only runtime nodes use ROS
Benefit: Reusable in non-ROS contexts (MATLAB, hardware)
Composition over Inheritance
Build systems from subsystems
Connect via explicit signals
Avoid deep inheritance hierarchies
Type Safety
Dataclass-based state definitions
Named fields instead of indices
Compile-time validation
Testing
Unit tests for each layer
Integration tests for compositions
Hardware-in-loop tests
Performance Considerations
Simulation Speed
Factors affecting real-time performance:
Integration timestep (smaller = slower)
Model complexity
Visualization overhead
Python vs compiled code
Optimization Strategies:
JIT compilation (CasADi)
Vectorized operations (NumPy)
Reduced visualization rate
C++ critical paths
Memory
CasADi symbolic expressions cached
ROS messages zero-copy when possible
Preallocated state vectors
Extensibility
Adding Aircraft
Create new module in
cubs2_dynamicsInherit from or use ModelSX pattern
Define state/input/output dataclasses
Implement dynamics equations
Adding Controller
Create module in
cubs2_controlFollow ModelSX pattern for composition
Add unit tests
Document tuning parameters
Adding RViz Panel
Create header in
cubs2_rviz/includeImplement in
cubs2_rviz/srcRegister in
plugin_description.xmlUpdate RViz config
See Also
Contributing - Development guidelines
Testing - Testing procedures