embedded_flight_control/attitude/
multi_copter.rs1use super::AttitudeController;
2use crate::PID;
3use embedded_flight_core::MotorOutput;
4use nalgebra::Vector3;
5
6pub struct MultiCopterAttitudeController {
23 pub roll_rate: PID,
25 pub pitch_rate: PID,
26 pub yaw_rate: PID,
27 pub attitude_controller: AttitudeController,
28}
29
30impl Default for MultiCopterAttitudeController {
31 fn default() -> Self {
32 const AC_ATC_MULTI_RATE_RP_P: f32 = 0.135;
33 const AC_ATC_MULTI_RATE_RP_I: f32 = 0.135;
34 const AC_ATC_MULTI_RATE_RP_D: f32 = 0.0036;
35 const AC_ATC_MULTI_RATE_RP_IMAX: f32 = 0.5;
36 const AC_ATC_MULTI_RATE_RP_FILT_HZ: f32 = 20.;
37 const AC_ATC_MULTI_RATE_YAW_P: f32 = 0.180;
38 const AC_ATC_MULTI_RATE_YAW_I: f32 = 0.018;
39 const AC_ATC_MULTI_RATE_YAW_D: f32 = 0.;
40 const AC_ATC_MULTI_RATE_YAW_IMAX: f32 = 0.5;
41 const AC_ATC_MULTI_RATE_YAW_FILT_HZ: f32 = 2.5;
42
43 let dt = 0.0025;
45
46 Self {
47 roll_rate: PID::new(
48 AC_ATC_MULTI_RATE_RP_P,
49 AC_ATC_MULTI_RATE_RP_I,
50 AC_ATC_MULTI_RATE_RP_D,
51 0.,
52 AC_ATC_MULTI_RATE_RP_IMAX,
53 AC_ATC_MULTI_RATE_RP_FILT_HZ,
54 0.,
55 AC_ATC_MULTI_RATE_RP_FILT_HZ,
56 dt,
57 ),
58 pitch_rate: PID::new(
59 AC_ATC_MULTI_RATE_RP_P,
60 AC_ATC_MULTI_RATE_RP_I,
61 AC_ATC_MULTI_RATE_RP_D,
62 0.,
63 AC_ATC_MULTI_RATE_RP_IMAX,
64 AC_ATC_MULTI_RATE_RP_FILT_HZ,
65 0.,
66 AC_ATC_MULTI_RATE_RP_FILT_HZ,
67 dt,
68 ),
69 yaw_rate: PID::new(
70 AC_ATC_MULTI_RATE_YAW_P,
71 AC_ATC_MULTI_RATE_YAW_I,
72 AC_ATC_MULTI_RATE_YAW_D,
73 0.,
74 AC_ATC_MULTI_RATE_YAW_IMAX,
75 AC_ATC_MULTI_RATE_RP_FILT_HZ,
76 AC_ATC_MULTI_RATE_YAW_FILT_HZ,
77 0.,
78 dt,
79 ),
80 attitude_controller: Default::default(),
81 }
82 }
83}
84
85impl MultiCopterAttitudeController {
86 pub fn motor_output(&mut self, gyro: Vector3<f32>, now_ms: u32) -> MotorOutput<f32> {
88 self.motor_output_with_limit(gyro, now_ms, [false; 3])
89 }
90
91 pub fn motor_output_with_limit(
93 &mut self,
94 gyro: Vector3<f32>,
95 now_ms: u32,
96 limit: [bool; 3],
97 ) -> MotorOutput<f32> {
98 self.update_throttle_rpy_mix();
101
102 self.attitude_controller.ang_vel_body += self.attitude_controller.sysid_ang_vel_body;
103
104 let roll = self.roll_rate.update(
105 self.attitude_controller.ang_vel_body[0],
106 gyro[0],
107 limit[0],
108 now_ms,
109 ) + self.attitude_controller.actuator_sysid[0];
110 let pitch = self.roll_rate.update(
111 self.attitude_controller.ang_vel_body[1],
112 gyro[1],
113 limit[1],
114 now_ms,
115 ) + self.attitude_controller.actuator_sysid[1];
116 let yaw = self.roll_rate.update(
117 self.attitude_controller.ang_vel_body[2],
118 gyro[2],
119 limit[2],
120 now_ms,
121 ) + self.attitude_controller.actuator_sysid[2];
122
123 let roll_ff = self.roll_rate.feed_forward();
124 let pitch_ff = self.pitch_rate.feed_forward();
125 let yaw_ff = self.yaw_rate.feed_forward() * self.attitude_controller.feed_forward_scalar;
126
127 self.attitude_controller.sysid_ang_vel_body = Vector3::zeros();
128 self.attitude_controller.actuator_sysid = Vector3::zeros();
129
130 MotorOutput::new(
133 Vector3::new(roll, pitch, yaw),
134 Vector3::new(roll_ff, pitch_ff, yaw_ff),
135 )
136 }
137
138 pub fn update_throttle_rpy_mix(&mut self) {
140 if self.attitude_controller.throttle_rpy_mix
142 < self.attitude_controller.throttle_rpy_mix_desired
143 {
144 self.attitude_controller.throttle_rpy_mix += (2. * self.attitude_controller.dt).min(
146 self.attitude_controller.throttle_rpy_mix_desired
147 - self.attitude_controller.throttle_rpy_mix,
148 );
149 } else if self.attitude_controller.throttle_rpy_mix
150 > self.attitude_controller.throttle_rpy_mix_desired
151 {
152 self.attitude_controller.throttle_rpy_mix -= (0.5 * self.attitude_controller.dt).min(
154 self.attitude_controller.throttle_rpy_mix
155 - self.attitude_controller.throttle_rpy_mix_desired,
156 );
157 }
158
159 self.attitude_controller.throttle_rpy_mix = self
160 .attitude_controller
161 .throttle_rpy_mix
162 .max(0.1)
163 .min(self.attitude_controller.attitude_control_max);
164 }
165}
166
167#[cfg(test)]
168mod tests {
169 use nalgebra::{Quaternion, Vector3};
170
171 use super::MultiCopterAttitudeController;
172
173 #[test]
174 fn f() {}
175}