rust_gnc/control/mixer.rs
1//! # Motor Mixing
2//!
3//! This module implements the "Mixer" logic, which maps normalized control
4//! signals from the PID controllers to individual motor output levels.
5//!
6//! This module defines the interface for mapping control demands (Roll, Pitch, Yaw, Throttle)
7//! to physical actuator outputs.
8
9/// Common interface for different airframe geometries.
10pub trait Mixer {
11 /// The specific signal type produced by this mixer (e.g., 4 signals for a quad).
12 type Output;
13
14 /// Maps normalized control demands [-1.0, 1.0] and throttle [0.0, 1.0] to motor signals.
15 fn mix(&self, roll: f32, pitch: f32, yaw: f32, throttle: f32) -> Self::Output;
16}
17
18/// A collection of normalized pulse-width modulation (PWM) signals for
19/// a quadcopter's Electronic Speed Controllers (ESCs).
20///
21/// Range: 0.0 (Stopped) to 1.0 (Full Power).
22#[derive(Debug, PartialEq, Clone, Copy, Default)]
23pub struct QuadMotorSignals {
24 /// Signal for the Front-Left motor.
25 pub front_left: f32,
26 /// Signal for the Front-Right motor.
27 pub front_right: f32,
28 /// Signal for the Rear-Left motor.
29 pub rear_left: f32,
30 /// Signal for the Rear-Right motor.
31 pub rear_right: f32,
32}
33
34/// A stateless utility for calculating motor power distribution.
35pub struct QuadXMixer;
36
37impl Mixer for QuadXMixer {
38 type Output = QuadMotorSignals;
39
40 /// Mixes axis control signals and throttle into individual motor outputs.
41 ///
42 /// This follows the standard Quad-X mixing matrix. The signs (+/-) for each
43 /// component are determined by the motor's position relative to the
44 /// center of mass and its rotational direction.
45 ///
46 /// ### Parameters
47 /// * `roll` - Normalized roll correction [-1.0, 1.0].
48 /// * `pitch` - Normalized pitch correction [-1.0, 1.0].
49 /// * `yaw` - Normalized yaw correction [-1.0, 1.0].
50 /// * `throttle` - Base power level [0.0, 1.0].
51 ///
52 /// ### Returns
53 /// A `MotorSignals` struct with values clamped to the safe operating range [0.0, 1.0].
54 fn mix(&self, roll: f32, pitch: f32, yaw: f32, throttle: f32) -> Self::Output {
55 // Mixing Matrix Calculation:
56 // FL = Throttle + Roll + Pitch - Yaw
57 // FR = Throttle - Roll + Pitch + Yaw
58 // RL = Throttle + Roll - Pitch + Yaw
59 // RR = Throttle - Roll - Pitch - Yaw
60
61 let fl = throttle - roll - pitch - yaw;
62 let fr = throttle + roll - pitch + yaw;
63 let rl = throttle - roll + pitch + yaw;
64 let rr = throttle + roll + pitch - yaw;
65
66 QuadMotorSignals {
67 front_left: fl.clamp(0.0, 1.0),
68 front_right: fr.clamp(0.0, 1.0),
69 rear_left: rl.clamp(0.0, 1.0),
70 rear_right: rr.clamp(0.0, 1.0),
71 }
72 }
73}