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}