Skip to main content

mpu6050_dmp/
accel.rs

1//! Accelerometer Data Processing
2//!
3//! The MPU6050's accelerometer measures linear acceleration along three axes:
4//! - X: Forward/backward motion
5//! - Y: Left/right motion
6//! - Z: Up/down motion (including gravity)
7//!
8//! Raw readings are in ADC units and must be scaled according to the
9//! configured full-scale range to get actual g-force values.
10
11/// Raw acceleration readings from the sensor's ADC.
12///
13/// This structure represents:
14/// - Raw sensor readings (when reading acceleration)
15/// - Calibration offsets (when used for calibration)
16/// - Values are in ADC units (-32768 to +32767)
17/// - Must be scaled by full-scale range for g-force values
18#[derive(Copy, Clone, Debug, PartialEq, Eq)]
19#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
20#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
21#[cfg_attr(feature = "postcard-experimental", derive(postcard::experimental::max_size::MaxSize))]
22pub struct Accel {
23    pub(crate) x: i16,
24    pub(crate) y: i16,
25    pub(crate) z: i16,
26}
27
28impl Accel {
29    pub const fn new(x: i16, y: i16, z: i16) -> Self {
30        Self { x, y, z }
31    }
32
33    /// Converts raw sensor bytes into acceleration values.
34    ///
35    /// The MPU6050 provides 16-bit acceleration values as:
36    /// - 2 bytes per axis (high byte, low byte)
37    /// - Big-endian byte order
38    /// - Signed integers (-32768 to +32767)
39    pub const fn from_bytes(data: [u8; 6]) -> Self {
40        let x = [data[0], data[1]];
41        let y = [data[2], data[3]];
42        let z = [data[4], data[5]];
43        Self {
44            x: i16::from_be_bytes(x),
45            y: i16::from_be_bytes(y),
46            z: i16::from_be_bytes(z),
47        }
48    }
49
50    pub const fn to_bytes(&self) -> [u8; 6] {
51        let x = self.x.to_be_bytes();
52        let y = self.y.to_be_bytes();
53        let z = self.z.to_be_bytes();
54        [x[0], x[1], y[0], y[1], z[0], z[1]]
55    }
56
57    pub const fn x(&self) -> i16 {
58        self.x
59    }
60
61    pub const fn y(&self) -> i16 {
62        self.y
63    }
64
65    pub const fn z(&self) -> i16 {
66        self.z
67    }
68
69    /// Converts raw ADC values to g-force units.
70    ///
71    /// The conversion process:
72    /// 1. Takes raw ADC values (-32768 to +32767)
73    /// 2. Divides by scale factor based on full-scale range
74    /// 3. Results in g-force values (e.g., ±2g, ±4g, etc.)
75    pub const fn scaled(&self, scale: AccelFullScale) -> AccelF32 {
76        AccelF32 {
77            x: scale.scale_value(self.x),
78            y: scale.scale_value(self.y),
79            z: scale.scale_value(self.z),
80        }
81    }
82}
83
84/// Full-scale range settings for the accelerometer.
85///
86/// Each setting provides different sensitivity:
87/// - G2: ±2g range (most sensitive, best for small movements)
88/// - G4: ±4g range
89/// - G8: ±8g range
90/// - G16: ±16g range (least sensitive, best for high-impact movements)
91///
92/// The range affects:
93/// - Sensitivity (LSB/g) - higher range = lower sensitivity
94/// - Resolution - lower range = better resolution
95/// - Maximum measurable acceleration
96#[derive(Copy, Clone, Debug)]
97#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
98#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
99#[cfg_attr(feature = "postcard-experimental", derive(postcard::experimental::max_size::MaxSize))]
100pub enum AccelFullScale {
101    /// ±2g range (16384 LSB/g)
102    G2 = 0,
103    /// ±4g range (8192 LSB/g)
104    G4 = 1,
105    /// ±8g range (4096 LSB/g)
106    G8 = 2,
107    /// ±16g range (2048 LSB/g)
108    G16 = 3,
109}
110
111impl AccelFullScale {
112    pub const fn scale(self) -> f32 {
113        match self {
114            Self::G2 => 16384.0,
115            Self::G4 => 8192.0,
116            Self::G8 => 4096.0,
117            Self::G16 => 2048.0,
118        }
119    }
120
121    pub const fn scale_value(self, value: i16) -> f32 {
122        (value as f32) / self.scale()
123    }
124}
125
126/// Acceleration values in g-force units.
127///
128/// This structure holds accelerometer data after conversion from
129/// raw ADC values to actual g-forces. Values typically range:
130/// - ±2g in G2 mode
131/// - ±4g in G4 mode
132/// - ±8g in G8 mode
133/// - ±16g in G16 mode
134///
135/// Note: The Z axis will read ~1g when stationary due to gravity
136#[derive(Debug, Clone, Copy)]
137#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
138#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
139#[cfg_attr(feature = "postcard-experimental", derive(postcard::experimental::max_size::MaxSize))]
140pub struct AccelF32 {
141    /// X-axis acceleration in g-force
142    x: f32,
143    /// Y-axis acceleration in g-force  
144    y: f32,
145    /// Z-axis acceleration in g-force
146    z: f32,
147}
148
149impl AccelF32 {
150    pub const fn new(x: f32, y: f32, z: f32) -> Self {
151        Self { x, y, z }
152    }
153
154    pub const fn x(&self) -> f32 {
155        self.x
156    }
157
158    pub const fn y(&self) -> f32 {
159        self.y
160    }
161
162    pub const fn z(&self) -> f32 {
163        self.z
164    }
165}