Skip to content

Commit 6f5805f

Browse files
committed
Add IMU HAL interface to decouple App from Adafruit BNO055
Signed-off-by: Javier Balloffet <javier.balloffet@gmail.com>
1 parent 3da85f7 commit 6f5805f

5 files changed

Lines changed: 190 additions & 43 deletions

File tree

andino_firmware/include/andino/app/app.h

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,11 @@
2929
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3030
#pragma once
3131

32-
#include <Adafruit_BNO055.h>
33-
3432
#include "andino/app/constants.h"
3533
#include "andino/app/pid.h"
3634
#include "andino/app/shell.h"
3735
#include "andino/drivers/encoder.h"
36+
#include "andino/drivers/imu.h"
3837
#include "andino/drivers/motor.h"
3938
#include "andino/hal/clock.h"
4039
#include "andino/hal/digital_out.h"
@@ -62,20 +61,17 @@ class App {
6261
* @param left_encoder_b The left encoder channel B interrupt input.
6362
* @param right_encoder_a The right encoder channel A interrupt input.
6463
* @param right_encoder_b The right encoder channel B interrupt input.
65-
* @param bno055_imu The Adafruit BNO055 IMU sensor.
6664
*/
6765
App(const Clock& clock, SerialStream& serial_stream, DigitalOut& left_motor_enable,
6866
PwmOut& left_motor_forward, PwmOut& left_motor_backward, DigitalOut& right_motor_enable,
6967
PwmOut& right_motor_forward, PwmOut& right_motor_backward, InterruptIn& left_encoder_a,
70-
InterruptIn& left_encoder_b, InterruptIn& right_encoder_a, InterruptIn& right_encoder_b,
71-
Adafruit_BNO055& bno055_imu)
68+
InterruptIn& left_encoder_b, InterruptIn& right_encoder_a, InterruptIn& right_encoder_b)
7269
: clock_(clock),
7370
serial_stream_(serial_stream),
7471
left_motor_(&left_motor_enable, &left_motor_forward, &left_motor_backward),
7572
right_motor_(&right_motor_enable, &right_motor_forward, &right_motor_backward),
7673
left_encoder_(&left_encoder_a, &left_encoder_b),
7774
right_encoder_(&right_encoder_a, &right_encoder_b),
78-
bno055_imu_(bno055_imu),
7975
left_pid_controller_(Constants::kPidKp, Constants::kPidKd, Constants::kPidKi,
8076
Constants::kPidKo, -Constants::kPwmMax, Constants::kPwmMax),
8177
right_pid_controller_(Constants::kPidKp, Constants::kPidKd, Constants::kPidKi,
@@ -147,7 +143,8 @@ class App {
147143
/// Right wheel encoder.
148144
Encoder right_encoder_;
149145

150-
Adafruit_BNO055& bno055_imu_;
146+
/// IMU sensor.
147+
Imu imu_;
151148

152149
/// PID controllers (one per wheel).
153150
Pid left_pid_controller_;
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
// BSD 3-Clause License
2+
//
3+
// Copyright (c) 2026, Ekumen Inc.
4+
// All rights reserved.
5+
//
6+
// Redistribution and use in source and binary forms, with or without
7+
// modification, are permitted provided that the following conditions are met:
8+
//
9+
// 1. Redistributions of source code must retain the above copyright notice, this
10+
// list of conditions and the following disclaimer.
11+
//
12+
// 2. Redistributions in binary form must reproduce the above copyright notice,
13+
// this list of conditions and the following disclaimer in the documentation
14+
// and/or other materials provided with the distribution.
15+
//
16+
// 3. Neither the name of the copyright holder nor the names of its
17+
// contributors may be used to endorse or promote products derived from
18+
// this software without specific prior written permission.
19+
//
20+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23+
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24+
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25+
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26+
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27+
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28+
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29+
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30+
#pragma once
31+
32+
namespace andino {
33+
34+
/// @brief This class allows to use an IMU sensor by configuring it and then getting its
35+
/// orientation, angular velocity and linear acceleration readings. It is backed by an Adafruit
36+
/// BNO055 sensor.
37+
class Imu {
38+
public:
39+
/// @brief Absolute orientation as a quaternion.
40+
struct Orientation {
41+
/// @brief Constructs a zeroed-out Orientation.
42+
Orientation() = default;
43+
44+
/// @brief Constructs an Orientation from its components.
45+
Orientation(double orientation_x, double orientation_y, double orientation_z,
46+
double orientation_w)
47+
: x(orientation_x), y(orientation_y), z(orientation_z), w(orientation_w) {
48+
}
49+
50+
/// Quaternion x component.
51+
double x{0.0};
52+
/// Quaternion y component.
53+
double y{0.0};
54+
/// Quaternion z component.
55+
double z{0.0};
56+
/// Quaternion w component.
57+
double w{0.0};
58+
};
59+
60+
/// @brief A 3-axis vector reading (e.g. angular velocity or linear acceleration).
61+
struct Vector3 {
62+
/// @brief Constructs a zeroed-out Vector3.
63+
Vector3() = default;
64+
65+
/// @brief Constructs a Vector3 from its components.
66+
Vector3(double vector_x, double vector_y, double vector_z)
67+
: x(vector_x), y(vector_y), z(vector_z) {
68+
}
69+
70+
/// X axis component.
71+
double x{0.0};
72+
/// Y axis component.
73+
double y{0.0};
74+
/// Z axis component.
75+
double z{0.0};
76+
};
77+
78+
/// @brief Initializes the IMU sensor.
79+
///
80+
/// @return True if the IMU sensor was successfully initialized, false otherwise.
81+
bool begin() const;
82+
83+
/// @brief Gets the absolute orientation.
84+
///
85+
/// @return Absolute orientation as a quaternion.
86+
Orientation get_orientation() const;
87+
88+
/// @brief Gets the angular velocity.
89+
///
90+
/// @return Angular velocity vector [rad/s].
91+
Vector3 get_angular_velocity() const;
92+
93+
/// @brief Gets the linear acceleration.
94+
///
95+
/// @return Linear acceleration vector [m/s^2].
96+
Vector3 get_linear_acceleration() const;
97+
};
98+
99+
} // namespace andino

andino_firmware/src/app/app.cpp

Lines changed: 17 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,7 @@
6666

6767
#include <stdio.h>
6868

69-
#include <Adafruit_BNO055.h>
70-
#include <Adafruit_Sensor.h>
7169
#include <Arduino.h>
72-
#include <Wire.h>
73-
#include <utility/imumaths.h>
7470

7571
#include "andino/app/commands.h"
7672
#include "andino/app/constants.h"
@@ -108,10 +104,7 @@ void App::setup() {
108104
shell_.register_command(Commands::kReadEncodersAndImu, cmd_read_encoders_and_imu_cb, this);
109105

110106
// Initialize IMU sensor.
111-
if (bno055_imu_.begin()) {
112-
bno055_imu_.setExtCrystalUse(true);
113-
is_imu_connected = true;
114-
}
107+
is_imu_connected = imu_.begin();
115108
}
116109

117110
void App::loop() {
@@ -272,40 +265,33 @@ void App::cmd_read_encoders_and_imu_cb(void* context, int, char**) {
272265
Serial.print(app->right_encoder_.read());
273266
Serial.print(" ");
274267

275-
// Retrieve absolute orientation (quaternion). See
276-
// https://learn.adafruit.com/adafruit-bno055-absolute-orientation-sensor/overview for further
277-
// information.
278-
imu::Quaternion orientation = app->bno055_imu_.getQuat();
279-
Serial.print(orientation.x(), 4);
268+
// Retrieve absolute orientation (quaternion).
269+
Imu::Orientation orientation = app->imu_.get_orientation();
270+
Serial.print(orientation.x, 4);
280271
Serial.print(" ");
281-
Serial.print(orientation.y(), 4);
272+
Serial.print(orientation.y, 4);
282273
Serial.print(" ");
283-
Serial.print(orientation.z(), 4);
274+
Serial.print(orientation.z, 4);
284275
Serial.print(" ");
285-
Serial.print(orientation.w(), 4);
276+
Serial.print(orientation.w, 4);
286277
Serial.print(" ");
287278

288-
// Retrieve angular velocity (rad/s). See
289-
// https://learn.adafruit.com/adafruit-bno055-absolute-orientation-sensor/overview for further
290-
// information.
291-
imu::Vector<3> angular_velocity = app->bno055_imu_.getVector(Adafruit_BNO055::VECTOR_GYROSCOPE);
292-
Serial.print(angular_velocity.x());
279+
// Retrieve angular velocity (rad/s).
280+
Imu::Vector3 angular_velocity = app->imu_.get_angular_velocity();
281+
Serial.print(angular_velocity.x);
293282
Serial.print(" ");
294-
Serial.print(angular_velocity.y());
283+
Serial.print(angular_velocity.y);
295284
Serial.print(" ");
296-
Serial.print(angular_velocity.z());
285+
Serial.print(angular_velocity.z);
297286
Serial.print(" ");
298287

299-
// Retrieve linear acceleration (m/s^2). See
300-
// https://learn.adafruit.com/adafruit-bno055-absolute-orientation-sensor/overview for further
301-
// information.
302-
imu::Vector<3> linear_acceleration =
303-
app->bno055_imu_.getVector(Adafruit_BNO055::VECTOR_LINEARACCEL);
304-
Serial.print(linear_acceleration.x());
288+
// Retrieve linear acceleration (m/s^2).
289+
Imu::Vector3 linear_acceleration = app->imu_.get_linear_acceleration();
290+
Serial.print(linear_acceleration.x);
305291
Serial.print(" ");
306-
Serial.print(linear_acceleration.y());
292+
Serial.print(linear_acceleration.y);
307293
Serial.print(" ");
308-
Serial.print(linear_acceleration.z());
294+
Serial.print(linear_acceleration.z);
309295
}
310296

311297
void App::adjust_motors_speed() {
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
// BSD 3-Clause License
2+
//
3+
// Copyright (c) 2026, Ekumen Inc.
4+
// All rights reserved.
5+
//
6+
// Redistribution and use in source and binary forms, with or without
7+
// modification, are permitted provided that the following conditions are met:
8+
//
9+
// 1. Redistributions of source code must retain the above copyright notice, this
10+
// list of conditions and the following disclaimer.
11+
//
12+
// 2. Redistributions in binary form must reproduce the above copyright notice,
13+
// this list of conditions and the following disclaimer in the documentation
14+
// and/or other materials provided with the distribution.
15+
//
16+
// 3. Neither the name of the copyright holder nor the names of its
17+
// contributors may be used to endorse or promote products derived from
18+
// this software without specific prior written permission.
19+
//
20+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23+
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24+
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25+
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26+
// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27+
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28+
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29+
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30+
#include "andino/drivers/imu.h"
31+
32+
#include <Adafruit_BNO055.h>
33+
#include <Wire.h>
34+
35+
/// Adafruit BNO055 IMU sensor instance.
36+
static Adafruit_BNO055 g_bno055_imu(55, BNO055_ADDRESS_A, &Wire);
37+
38+
namespace andino {
39+
40+
bool Imu::begin() const {
41+
if (!g_bno055_imu.begin()) {
42+
return false;
43+
}
44+
g_bno055_imu.setExtCrystalUse(true);
45+
return true;
46+
}
47+
48+
Imu::Orientation Imu::get_orientation() const {
49+
// See https://learn.adafruit.com/adafruit-bno055-absolute-orientation-sensor/overview for
50+
// further information.
51+
imu::Quaternion orientation = g_bno055_imu.getQuat();
52+
return Orientation{orientation.x(), orientation.y(), orientation.z(), orientation.w()};
53+
}
54+
55+
Imu::Vector3 Imu::get_angular_velocity() const {
56+
// See https://learn.adafruit.com/adafruit-bno055-absolute-orientation-sensor/overview for
57+
// further information.
58+
imu::Vector<3> angular_velocity = g_bno055_imu.getVector(Adafruit_BNO055::VECTOR_GYROSCOPE);
59+
return Vector3{angular_velocity.x(), angular_velocity.y(), angular_velocity.z()};
60+
}
61+
62+
Imu::Vector3 Imu::get_linear_acceleration() const {
63+
// See https://learn.adafruit.com/adafruit-bno055-absolute-orientation-sensor/overview for
64+
// further information.
65+
imu::Vector<3> linear_acceleration = g_bno055_imu.getVector(Adafruit_BNO055::VECTOR_LINEARACCEL);
66+
return Vector3{linear_acceleration.x(), linear_acceleration.y(), linear_acceleration.z()};
67+
}
68+
69+
} // namespace andino

andino_firmware/src/main.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,6 @@
2727
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
2828
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2929
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30-
#include <Adafruit_BNO055.h>
31-
#include <Wire.h>
32-
3330
#include "andino/app/app.h"
3431
#include "andino/app/hw.h"
3532
#include "andino/bsp/clock_arduino.h"
@@ -51,13 +48,12 @@ static andino::InterruptInArduino left_encoder_a(andino::Hw::kLeftEncoderChannel
5148
static andino::InterruptInArduino left_encoder_b(andino::Hw::kLeftEncoderChannelBGpioPin);
5249
static andino::InterruptInArduino right_encoder_a(andino::Hw::kRightEncoderChannelAGpioPin);
5350
static andino::InterruptInArduino right_encoder_b(andino::Hw::kRightEncoderChannelBGpioPin);
54-
static Adafruit_BNO055 bno055_imu(55, BNO055_ADDRESS_A, &Wire);
5551

5652
// Main application.
5753
static andino::App app(sys_clock, serial_stream, left_motor_enable, left_motor_forward,
5854
left_motor_backward, right_motor_enable, right_motor_forward,
5955
right_motor_backward, left_encoder_a, left_encoder_b, right_encoder_a,
60-
right_encoder_b, bno055_imu);
56+
right_encoder_b);
6157

6258
/// @brief Application entry point.
6359
///

0 commit comments

Comments
 (0)