Skip to content

Commit 1819afa

Browse files
TheButlahNoxime
andauthored
Implemented BMI160 acceleration (#172)
Co-authored-by: Aaro Perämaa <aaro.peramaa@gmail.com>
1 parent 7fb7acc commit 1819afa

File tree

2 files changed

+100
-11
lines changed

2 files changed

+100
-11
lines changed

firmware/src/imu/drivers/bmi160/math.rs

Lines changed: 96 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
const RAD_PER_DEG: f32 = 2. * core::f32::consts::PI / 360.;
1+
const RAD_PER_DEG: f32 = core::f32::consts::PI / 180.;
22
const DEG_PER_RAD: f32 = 1. / RAD_PER_DEG;
3+
const ACCEL_PER_G: f32 = 9.81;
4+
const G_PER_ACCEL: f32 = 1. / ACCEL_PER_G;
35

46
// TODO: This whole module needs unit tests
57

@@ -13,6 +15,7 @@ pub enum GyroFsr {
1315
D250,
1416
D125,
1517
}
18+
1619
#[allow(dead_code)]
1720
impl GyroFsr {
1821
/// The default FSR when the IMU is reset
@@ -85,16 +88,102 @@ impl GyroFsr {
8588
pub const fn rad_per_lsb(self) -> f32 {
8689
self.dps_per_lsb() * RAD_PER_DEG
8790
}
91+
92+
/// The bmi160 returns the data from the gyro as an `i16`, we must use the Full
93+
/// Scale Range to convert to a float rad/s
94+
pub const fn discrete_to_velocity(self, discrete: i16) -> f32 {
95+
discrete as f32 * self.rad_per_lsb()
96+
}
97+
}
98+
99+
/// The Full Scale Range of the accelerometer. For example, G2 means +/- 19.6 meters/sec^2
100+
#[derive(Eq, PartialEq, Copy, Clone, Debug)]
101+
#[allow(dead_code)]
102+
pub enum AccelFsr {
103+
G2,
104+
G4,
105+
G8,
106+
G16,
107+
}
108+
109+
#[allow(dead_code)]
110+
impl AccelFsr {
111+
/// The default FSR when the IMU is reset
112+
pub const DEFAULT: Self = Self::G2;
113+
pub const fn from_reg(v: u8) -> Result<Self, InvalidBitPattern> {
114+
Ok(match v {
115+
0b0011 => Self::G2,
116+
0b0101 => Self::G4,
117+
0b1000 => Self::G8,
118+
0b1100 => Self::G16,
119+
_ => return Err(InvalidBitPattern),
120+
})
121+
}
122+
123+
pub const fn to_reg(self) -> u8 {
124+
match self {
125+
Self::G2 => 0b0011,
126+
Self::G4 => 0b0101,
127+
Self::G8 => 0b1000,
128+
Self::G16 => 0b1100,
129+
}
130+
}
131+
132+
pub const fn as_u16(self) -> u16 {
133+
match self {
134+
Self::G2 => 2,
135+
Self::G4 => 4,
136+
Self::G8 => 8,
137+
Self::G16 => 16,
138+
}
139+
}
140+
141+
pub const fn from_u16(v: u16) -> Result<Self, InvalidNum> {
142+
// TODO: I'm not confident this is performant
143+
Ok(match v {
144+
v if v == Self::G2.as_u16() => Self::G2,
145+
v if v == Self::G4.as_u16() => Self::G4,
146+
v if v == Self::G8.as_u16() => Self::G8,
147+
v if v == Self::G16.as_u16() => Self::G16,
148+
_ => return Err(InvalidNum),
149+
})
150+
}
151+
152+
/// least signficant bits per g
153+
pub const fn lsb_per_g(self) -> f32 {
154+
let range: f32 = self.as_u16() as _;
155+
// Add 1 because there is MAX+1 numbers due to `0`
156+
const TMP: f32 = i16::MAX as f32 + 1.;
157+
TMP / range
158+
}
159+
160+
/// g per least significant bit
161+
pub const fn g_per_lsb(self) -> f32 {
162+
let range: f32 = self.as_u16() as _;
163+
// Add 1 because there is MAX+1 numbers due to `0`
164+
const TMP: f32 = 1. / (i16::MAX as f32 + 1.);
165+
range * TMP
166+
}
167+
168+
/// least significant bits per accel
169+
pub const fn lsb_per_accel(self) -> f32 {
170+
self.lsb_per_g() * ACCEL_PER_G
171+
}
172+
173+
/// g per least significant bit
174+
pub const fn accel_per_lsb(self) -> f32 {
175+
self.g_per_lsb() * G_PER_ACCEL
176+
}
177+
178+
/// The bmi160 returns the data from the accel as an `i16`, we must use the Full
179+
/// Scale Range to convert to a float m/s^2
180+
pub const fn discrete_to_accel(self, discrete: i16) -> f32 {
181+
discrete as f32 * self.accel_per_lsb()
182+
}
88183
}
89184

90185
#[derive(Debug)]
91186
pub struct InvalidBitPattern;
92187

93188
#[derive(Debug)]
94189
pub struct InvalidNum;
95-
96-
/// The bmi160 returns the data from the gyro as an `i16`, we must use the Full Scale Range to
97-
/// convert to a float.
98-
pub const fn discrete_to_radians(fsr: GyroFsr, discrete: i16) -> f32 {
99-
discrete as f32 * fsr.rad_per_lsb()
100-
}

firmware/src/imu/drivers/bmi160/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
mod math;
22

3-
use self::math::{discrete_to_radians, GyroFsr};
3+
use self::math::GyroFsr;
44
use crate::aliases::I2c;
55
use crate::imu::{FusedData, Imu, Quat};
66
use crate::utils::{self, nb2a};
@@ -86,9 +86,9 @@ impl<I: I2c> Bmi160<I> {
8686
// TODO: Implement sensor fusion and temperature compensation
8787
// TODO: This should be integrated to position, lol
8888
Ok(nalgebra::UnitQuaternion::from_euler_angles(
89-
discrete_to_radians(FSR, gyro_vel_euler.x),
90-
discrete_to_radians(FSR, gyro_vel_euler.y),
91-
discrete_to_radians(FSR, gyro_vel_euler.z),
89+
FSR.discrete_to_velocity(gyro_vel_euler.x),
90+
FSR.discrete_to_velocity(gyro_vel_euler.y),
91+
FSR.discrete_to_velocity(gyro_vel_euler.z),
9292
))
9393
}
9494
}

0 commit comments

Comments
 (0)