# esp32_BNO08x: README

Loading...
Searching...
No Matches
README

Table of Contents.

1. About
2. Getting Started
   - Wiring
   - Adding to Project
   - Menuconfig
   - Examples
3. Unit Tests
   - Running Tests
   - Adding Tests
4. Documentation
5. Program Flowcharts
6. Acknowledgements
7. License
8. Contact

## About

esp32_BNO08x is a C++ component for esp-idf v5.x, serving as a driver for both BNO080 and BNO085 IMUs.

Originally based on the SparkFun BNO080 Arduino Library, it has since diverged significantly in implementation, taking a multi-tasked approach to avoid wasting CPU time polling the HINT pin of the IMU. Currently, only SPI is supported. There are no plans to support I2C due to unpredictable behavior caused by an esp32 I2C driver silicon bug. UART support may be implemented in the future.

NOTE: If you are here because this most recent update broke your code:
You can still use the old version on the `no_sh2_HAL` branch of this repo. It will no longer receive support. It's highly recommended you update your code base to this version as it uses the official Hillcrest Labs sh2 HAL lib to handle sh2 SHTP communication with the IMU, instead of my own implementation. It is better tested and more reliable at the cost of slightly more overhead.

(back to top)

## Getting Started

### Wiring

The default wiring is depicted below, it can be changed at driver initialization (see example section).

If your ESP does not have the GPIO pin numbers depicted below, you must change the default GPIO settings in menuconfig. See the Menuconfig section.

(back to top)

### Adding to Project

1. Create a "components" directory in the root workspace directory of your esp-idf project if it does not exist already.

   In workspace directory:

   mkdir components

2. Cd into the components directory and clone the esp32_BNO08x repo.

   cd components
   git clone https://github.com/myles-parfeniuk/esp32_BNO08x.git
3. Ensure you clean your esp-idf project before rebuilding.
   Within esp-idf enabled terminal:
   idf.py fullclean

(back to top)

### Menuconfig

This library provides a menuconfig menu configured in Kconfig.projbuild. It contains settings to control the default GPIO and a few other things.

To access the menu:

1. Within esp-idf enabled terminal, execute the menuconfig command:
   idf.py menuconfig
2. Scroll down to the esp_BNO08x menu and enter it, if you're using vsCode you may have to use the "j" and "k" keys instead of the arrow keys.

3. Modify whatever settings you'd like from the sub menus.

   - The GPIO Configuration menu allows for the default GPIO pins to be modified.
   - The SPI Configuration menu allows for the default host peripheral, SCLK frequency, and SPI queue size to be modified.
   - The Tasks menu allows for the stack size of the three tasks utilized by this library to be modified.
   - The Callbacks menu allows for the size of the callback queue and maximum amount of callbacks to be modified.
   - The Timeouts menu allows the length of various timeouts/delays to be set.
   - The Logging menu allows for the enabling and disabling of serial log/print statements for production code.

   (back to top)

### Examples

There are two ways data returned from the BNO08x can be accessed with this library:

1. Polling Method with `data_available()` Function:
   - See the Polling Example below.
2. Callback Registration with `register_cb()` Function:
   - See the Call-Back Function Example below.

#### Polling Example

#include <stdio.h>
#include "BNO08x.hpp"
static const constexpr char *TAG = "Main";
extern "C" void app_main(void)
{
static BNO08x imu;
// if a custom wiring scheme is desired instead of default:
/*
bno08x_config_t imu_config; //create config struct
imu_config.io_mosi = GPIO_NUM_X; //assign pin
imu_config.io_miso = GPIO_NUM_X; //assign pin
//etc...
BNO08x imu(imu_config); //pass config to BNO08x constructor
*/
// initialize imu
if (!imu.initialize())
{
ESP_LOGE(TAG, "Init failure, returning from main.");
return;
}
// enable game rotation vector and calibrated gyro reports
imu.rpt.rv_game.enable(100000UL); // 100,000us == 100ms report interval
imu.rpt.cal_gyro.enable(100000UL); // 100,000us == 100ms report interval
while (1)
{
// block until new report is detected
if (imu.data_available())
{
// check for game rotation vector report
if (imu.rpt.rv_game.has_new_data())
{
// get absolute heading in degrees
bno08x_euler_angle_t euler = imu.rpt.rv_game.get_euler();
// display heading
ESP_LOGI(TAG, "Euler Angle: x (roll): %.2f y (pitch): %.2f z (yaw): %.2f", euler.x, euler.y, euler.z);
}
// check for cal gyro report
if (imu.rpt.cal_gyro.has_new_data())
{
// get angular velocity in rad/s
bno08x_gyro_t velocity = imu.rpt.cal_gyro.get();
// display velocity
ESP_LOGW(TAG, "Velocity: x: %.2f y: %.2f z: %.2f", velocity.x, velocity.y, velocity.z);
}
}
}
}
BNO08x.hpp
BNO08x
BNO08x IMU driver class.
Definition BNO08x.hpp:33
BNO08x::data_available
bool data_available()
Polls for new data/report to become available.
Definition BNO08x.cpp:1582
BNO08x::rpt
bno08x_reports_t rpt
Definition BNO08x.hpp:128
BNO08x::initialize
bool initialize()
Initializes BNO08x sensor.
Definition BNO08x.cpp:81
BNO08xRptCalGyro::get
bno08x_gyro_t get()
Grabs most recent gyroscope data (velocity), units are in rad/s.
Definition BNO08xRptCalGyro.cpp:45
BNO08xRptCalGyro::enable
bool enable(uint32_t time_between_reports, sh2_SensorConfig_t sensor_cfg=BNO08xPrivateTypes::default_sensor_cfg) override
Enables calibrated gyro reports such that the BNO08x begins sending them.
Definition BNO08xRptCalGyro.cpp:35
BNO08xRpt::has_new_data
bool has_new_data()
Checks if a new report has been received since the last time this function was called.
Definition BNO08xRpt.cpp:134
BNO08xRptRVGeneric::enable
bool enable(uint32_t time_between_reports, sh2_SensorConfig_t sensor_cfg=BNO08xPrivateTypes::default_sensor_cfg) override
Enables a rotation vector report such that the BNO08x begins it.
Definition BNO08xRptRVGeneric.cpp:17
BNO08xRptRVGeneric::get_euler
bno08x_euler_angle_t get_euler(bool in_degrees=true)
Grabs most recent rotation vector data in form of an euler angle, units are in degrees or rads.
Definition BNO08xRptRVGeneric.cpp:50
BNO08x::bno08x_reports_t::rv_game
BNO08xRptGameRV rv_game
Definition BNO08x.hpp:82
BNO08x::bno08x_reports_t::cal_gyro
BNO08xRptCalGyro cal_gyro
Definition BNO08x.hpp:79
bno08x_euler_angle_t
Struct to represent euler angle (units in degrees or rads)
Definition BNO08xGlobalTypes.hpp:214
bno08x_euler_angle_t::y
float y
Definition BNO08xGlobalTypes.hpp:216
bno08x_euler_angle_t::z
float z
Definition BNO08xGlobalTypes.hpp:217
bno08x_euler_angle_t::x
float x
Definition BNO08xGlobalTypes.hpp:215
bno08x_gyro_t
Struct to represent gyro data (units in rad/s)
Definition BNO08xGlobalTypes.hpp:353
bno08x_gyro_t::x
float x
Definition BNO08xGlobalTypes.hpp:354
bno08x_gyro_t::y
float y
Definition BNO08xGlobalTypes.hpp:355
bno08x_gyro_t::z
float z
Definition BNO08xGlobalTypes.hpp:356

- Initialize the IMU and enable desired reports.
- Use the `data_available()` function to poll for new data, similar to the SparkFun library.
- Behavior: It is a blocking function that returns `true` when new data is received or `false` if a timeout occurs.
- Check for report flavor received if desired, with `has_new_data()`

#### Call-Back Function Example

#include <stdio.h>
#include "BNO08x.hpp"
static const constexpr char *TAG = "Main";
extern "C" void app_main(void)
{
static BNO08x imu;
// if a custom wiring scheme is desired instead of default:
/*
bno08x_config_t imu_config; //create config struct
imu_config.io_mosi = GPIO_NUM_X; //assign pin
imu_config.io_miso = GPIO_NUM_X; //assign pin
//etc...
BNO08x imu(imu_config); //pass config to BNO08x constructor
*/
// initialize imu
if (!imu.initialize())
{
ESP_LOGE(TAG, "Init failure, returning from main.");
return;
}
// enable game rotation vector and calibrated gyro reports
imu.rpt.rv_game.enable(100000UL); // 100,000us == 100ms report interval
imu.rpt.cal_gyro.enable(100000UL); // 100,000us == 100ms report interval
// There are 3 different flavors of callbacks available:
// 1) register a callback to execute when new data is received for any report
imu.register_cb([&imu]()
{
// check for game rotation vector report
if (imu.rpt.rv_game.has_new_data())
{
// get absolute heading in degrees
bno08x_euler_angle_t euler = imu.rpt.rv_game.get_euler();
// display heading
ESP_LOGI(TAG, "Euler Angle: x (roll): %.2f y (pitch): %.2f z (yaw): %.2f", euler.x, euler.y, euler.z);
}
});
// 2) register a callback that is only executed for a specific report
imu.rpt.cal_gyro.register_cb([&imu]()
{
// get angular velocity in rad/s
bno08x_gyro_t velocity = imu.rpt.cal_gyro.get();
// display velocity
ESP_LOGI(TAG, "Velocity: x: %.2f y: %.2f z: %.2f", velocity.x, velocity.y, velocity.z);
});
// 3) register a callback this passed report ID of report that asserted callback
imu.register_cb([](uint8_t rpt_ID)
{
switch (rpt_ID)
{
case SH2_GAME_ROTATION_VECTOR:
ESP_LOGW(TAG, "Game RV report RX");
break;
case SH2_CAL_GYRO:
ESP_LOGW(TAG, "Cal Gyro report RX");
break;
default:
break;
}
});
while (1)
{
vTaskDelay(10000UL / portTICK_PERIOD_MS); // delay here is irrelevant, we just don't want to trip cpu watchdog
}
}
BNO08x::register_cb
bool register_cb(std::function< void(void)> cb_fxn)
Registers a callback to execute when new data from a report is received.
Definition BNO08x.cpp:1600
BNO08xRpt::register_cb
bool register_cb(std::function< void(void)> cb_fxn)
Registers a callback to execute when new data from a specific report is received.
Definition BNO08xRpt.cpp:118

- Register callback functions that automatically execute upon receiving new data.
- Behavior: The registered callback will be invoked whenever new data is available.
- It is possible to register a callback to one report, or all reports.

(back to top)

## Unit Tests

A basic unit testing suite is included with this library, but it is very rudimentary.
It can be used to verify some of the basic features of a BNO08x device and this library.

(back to top)

### Running Tests

1. Create a project and add the component as described in the getting started guide.

2. Open the outermost CMakeLists.txt file in the project root directory, as depicted below.

3. Modify the file by adding "set(TEST_COMPONENTS "esp32_BNO08x" CACHE STRING "Components to test.")" as depicted below:

   # For more information about build system see
   # https://docs.espressif.com/projects/esp-idf/en/latest/api-guides/build-system.html
   # The following five lines of boilerplate have to be in your project's
   # CMakeLists in this exact order for cmake to work correctly
   cmake_minimum_required(VERSION 3.16)
   set(TEST_COMPONENTS "esp32_BNO08x" CACHE STRING "Components to test.")
   include($ENV{IDF_PATH}/tools/cmake/project.cmake)
   project(your_project_name)

4. Include the test suite in your main file and launch into the test suite:

   #include <stdio.h>
   #include "BNO08xTestSuite.hpp"
   extern "C" void app_main(void)
   {
   BNO08xTestSuite::run_all_tests();
   }
   BNO08xTestSuite.hpp
   BNO08xTestSuite::run_all_tests
   static void run_all_tests()
   Definition BNO08xTestSuite.hpp:33
5. Ensure you run `idf.py fullclean` or delete your build directory before building for the first time after modifying the CMakeLists.txt file in step 3.

(back to top)

### Adding Tests

Tests are implemented with the unity unit testing component.

To add a test, create a new .cpp file, or modify one of the existing ones in `esp32_BNO08x/test/`. Follow the existing test structure as an example, use the `TEST_CASE(){}` macro, then add a function to the `esp32BNO08x/include/BNO08xTestSuite.hpp` file to run your test(s).

Any tests added will automatically be detected at build time.

(back to top)

## Documentation

API documentation generated with doxygen can be found in the documentation directory of the master branch.

(back to top)

## Program Flowcharts

The following charts illustrate the program flow this library implements to deal with handling reports from the IMU in a multi-tasked manner. These are here to aid development for anyone looking to modify, fork, or contribute.
Sh2 HAL lib handles all communication with the IMU through callbacks which can be viewed in `BNO08xSH2HAL.hpp`.

(back to top)

## Acknowledgements

Special thanks to Anton Babiy, aka hwBirdy007 for helping with debugging SPI.
https://github.com/hwBirdy007

(back to top)

## License

Distributed under the MIT License. See `LICENSE.md` for more information.

(back to top)

## Contact

Myles Parfeniuk - myles.nosp@m..par.nosp@m.fenyu.nosp@m.k@gm.nosp@m.ail.c.nosp@m.om

Project Link: https://github.com/myles-parfeniuk/esp32_BNO08x.git

(back to top)