Skip to main content

sensor_fusion/
sensor_fusion.rs

1use vqm::{Quaternion, Quaternionf32, Vector3};
2
3/// Common interface for the sensor fusion filters (Madgwick, Mahony, complementary).
4/// ```
5/// use vqm::{Vector3f32,Quaternionf32};
6/// use sensor_fusion::{MadgwickFilterf32, SensorFusion};
7///
8/// let mut madgwick_filter = MadgwickFilterf32::default();
9///
10/// let delta_t: f32 = 0.0;
11/// let acc = Vector3f32::default();
12/// let gyro_rps = Vector3f32::default();
13///
14/// let orientation = madgwick_filter.fuse_acc_gyro(acc, gyro_rps, delta_t);
15/// assert!(orientation.is_near_one(1.2e-4));
16/// ```
17pub trait SensorFusion<T> {
18    fn set_gains(&mut self, gain0: T, gain1: T);
19    fn gains(&self) -> (T, T);
20
21    fn requires_initialization() -> bool;
22
23    fn fuse_acc_gyro(&mut self, acc: Vector3<T>, gyro_rps: Vector3<T>, delta_t: T) -> Quaternion<T>;
24    fn fuse_acc_gyro_mag(&mut self, acc: Vector3<T>, gyro: Vector3<T>, mag: Vector3<T>, delta_t: T) -> Quaternion<T>;
25    fn correct_yaw_with_gain(&mut self, yaw_radians: T, gain: T, delta_t: T) -> Quaternion<T>;
26}
27
28/// Trait to allow sensor fusion filters to be used with method-call syntax, ie:<br>
29/// `let orientation = (acc, gyro_rps).fuse_acc_gyro_using(&mut madgwick, dt);`
30/// ```
31/// use vqm::{Vector3f32, Quaternionf32};
32/// use sensor_fusion::{MadgwickFilterf32, SensorFusion, FuseAccGyro};
33///
34/// let mut madgwick_filter = MadgwickFilterf32::default();
35///
36/// let delta_t: f32 = 0.0;
37/// let acc = Vector3f32::default();
38/// let gyro_rps = Vector3f32::default();
39///
40/// let orientation = (acc, gyro_rps).fuse_acc_gyro_using(&mut madgwick_filter, delta_t);
41/// assert!(orientation.is_near_one(1.2e-4));
42/// ```
43pub trait FuseAccGyro<T> {
44    fn fuse_acc_gyro_using<F: SensorFusion<T>>(self, filter: &mut F, delta_t: T) -> Quaternion<T>;
45}
46
47impl<T> FuseAccGyro<T> for (Vector3<T>, Vector3<T>) {
48    fn fuse_acc_gyro_using<F: SensorFusion<T>>(self, filter: &mut F, delta_t: T) -> Quaternion<T> {
49        let (acc, gyro) = self;
50        filter.fuse_acc_gyro(acc, gyro, delta_t)
51    }
52}
53
54/// Trait to allow sensor fusion filters to be used with method-call syntax, ie:<br>
55/// `let orientation = (acc, gyro_rps).fuse_acc_gyro_using(&mut madgwick, dt);`
56/// ```
57/// use vqm::{Vector3f32,Quaternionf32};
58/// use sensor_fusion::{MadgwickFilterf32,SensorFusion,FuseAccGyroMag};
59/// let mut madgwick_filter = MadgwickFilterf32::default();
60/// let dt: f32 = 0.0;
61/// let acc = Vector3f32::default();
62/// let gyro_rps = Vector3f32::default();
63/// let mag = Vector3f32::default();
64/// let orientation = (acc, gyro_rps, mag).fuse_acc_gyro_mag_using(&mut madgwick_filter, dt);
65/// assert!(orientation.is_near_one(1.2e-4));
66/// ```
67pub trait FuseAccGyroMag<T> {
68    fn fuse_acc_gyro_mag_using<F: SensorFusion<T>>(self, sensor_fusion_filter: &mut F, delta_t: T) -> Quaternion<T>;
69}
70
71impl<T> FuseAccGyroMag<T> for (Vector3<T>, Vector3<T>, Vector3<T>) {
72    fn fuse_acc_gyro_mag_using<F: SensorFusion<T>>(self, sensor_fusion_filter: &mut F, delta_t: T) -> Quaternion<T> {
73        let (acc, gyro, mag) = self;
74        sensor_fusion_filter.fuse_acc_gyro_mag(acc, gyro, mag, delta_t)
75    }
76}
77
78/*
79/// Calculate quaternion derivative (dq/dt aka q_dot) from angular rate <https://ahrs.readthedocs.io/en/latest/filters/angular.html#quaternion-derivative>
80pub fn q_dot<T>(q: Quaternion<T>, gyro_rps: Vector3<T>) -> Quaternion<T>
81where
82    T: Copy + One + Neg<Output = T> + Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Div<Output = T>,
83{
84    let half = T::one() / (T::one() + T::one());
85    Quaternion {
86        w: (-q.x * gyro_rps.x - q.y * gyro_rps.y - q.z * gyro_rps.z) * half,
87        x: (q.w * gyro_rps.x + q.y * gyro_rps.z - q.z * gyro_rps.y) * half,
88        y: (q.w * gyro_rps.y - q.x * gyro_rps.z + q.z * gyro_rps.x) * half,
89        z: (q.w * gyro_rps.z + q.x * gyro_rps.y - q.y * gyro_rps.x) * half,
90    }
91}*/
92
93#[cfg(any(debug_assertions, test))]
94mod tests {
95    #![allow(clippy::wildcard_imports)]
96    use super::*;
97    use vqm::Vector3f32;
98
99    #[allow(unused)]
100    struct TestStruct;
101
102    impl SensorFusion<f32> for TestStruct {
103        fn set_gains(&mut self, _gain0: f32, _gain1: f32) {}
104        fn gains(&self) -> (f32, f32) {
105            (0.0, 0.0)
106        }
107
108        fn requires_initialization() -> bool {
109            true
110        }
111        fn fuse_acc_gyro(&mut self, _acc: Vector3f32, _gyro_rps: Vector3f32, _delta_t: f32) -> Quaternionf32 {
112            Quaternionf32::default()
113        }
114        fn fuse_acc_gyro_mag(
115            &mut self,
116            acc: Vector3f32,
117            gyro_rps: Vector3f32,
118            _mag: Vector3f32,
119            delta_t: f32,
120        ) -> Quaternionf32 {
121            self.fuse_acc_gyro(acc, gyro_rps, delta_t)
122        }
123        fn correct_yaw_with_gain(&mut self, _yaw_radians: f32, _gain: f32, _delta_t: f32) -> Quaternionf32 {
124            Quaternionf32::default()
125        }
126    }
127
128    #[test]
129    fn sensor_fusion() {
130        let mut test_struct: TestStruct = TestStruct {};
131        _ = TestStruct::requires_initialization();
132        //assert_eq!(TestStruct::requires_initialization(), true);
133
134        test_struct.set_gains(0.0, 0.0);
135
136        let delta_t: f32 = 0.0;
137        let acc = Vector3f32::default();
138        let gyro_rps = Vector3f32::default();
139
140        let orientation = test_struct.fuse_acc_gyro(acc, gyro_rps, delta_t);
141        assert_eq!(orientation, Quaternion::default());
142    }
143
144    #[test]
145    fn fuse_using() {
146        use crate::MadgwickFilterf32;
147
148        let mut madgwick_filter = MadgwickFilterf32::default();
149        let requires_initialization = MadgwickFilterf32::requires_initialization();
150        assert!(requires_initialization);
151
152        madgwick_filter.set_beta(1.0);
153
154        let delta_t: f32 = 0.0;
155        let acc = Vector3f32::default();
156        let gyro_rps = Vector3f32::default();
157
158        //let orientation = madgwick_filter.fuse_acc_gyro(acc, gyro_rps, delta_t);
159        let orientation = (acc, gyro_rps).fuse_acc_gyro_using(&mut madgwick_filter, delta_t);
160        //assert_eq!(orientation, Quaternion { w: 1.0, x: 0.0, y: 0.0, z: 0.0 });
161        assert!(orientation.is_near_one(1.2e-4));
162    }
163}