rinku404/bno085

1.1.1

Latest
uploaded 5 hours ago
BNO085 9-axis IMU driver for ESP-IDF using CEVA's SH2 sensor hub protocol

Readme

# BNO085 IMU Driver for ESP-IDF

ESP-IDF component for the Bosch BNO085 9-axis IMU over I2C using CEVA's SH2 sensor hub protocol.

## Features

- 35+ sensors (orientation, raw IMU, environmental, activity detection, gesture detection)
- Multiple rotation vector types (standard, game, geomagnetic, AR/VR optimized, 1kHz gyro-integrated)
- Up to 8 concurrent sensors on the same I2C bus (configurable)
- Flexible I2C addressing (0x28 or 0x29 via AD0 pin)
- Multiplexer support for 8+ sensors
- Handle-based API with callback-based data delivery
- Full sensor decoding into named fields

## Hardware Setup

### Wiring Example (Heltec LoRa V3)

| BNO085 Pin | ESP32-S3 Pin | Signal       | Notes           |
|------------|--------------|--------------|-----------------|
| SDA        | GPIO 6       | I2C SDA      | Pull-up enabled |
| SCL        | GPIO 7       | I2C SCL      | Pull-up enabled |
| INT (H_INTN)| GPIO 5      | Interrupt    | Active-low      |
| RST (NRST) | GPIO 4       | Reset        | Active-low      |
| AD0        | GND          | Slave addr   | I2C addr 0x28   |
| VCC        | 3.3V         | Power        |                 |
| GND        | GND          | Ground       |                 |

**Important**: PS0 and PS1 must be tied to GND for I2C mode.

### I2C Address Selection

The BNO085 has an AD0 pin that selects the I2C address:
- AD0 = GND (0V) → I2C address 0x28
- AD0 = 3.3V → I2C address 0x29

Create the I2C device handle with the correct address matching your AD0 pin configuration.

### Multiple Sensors

Use an I2C multiplexer (e.g., TCA9548A) to connect multiple BNO085 sensors on different channels. Initialize one handle per sensor and select the multiplexer channel before calling `bno085_service()` on each handle.

## Installation

### From ESP-IDF Component Registry

```bash
idf.py add-dependency bno085
```

### From Git (Development)

```bash
git clone --recursive https://github.com/<your-username>/bno085.git components/bno085
```

## Quick Start

```c
#include "bno085.h"
#include "driver/i2c_master.h"
#include "freertos/task.h"

static void sensor_callback(bno085_handle_t handle,
                           const bno085_sensor_value_t *value,
                           void *user_context)
{
    if (value->sensor_id == BNO085_SENSOR_ROTATION_VECTOR) {
        printf("Quaternion: i=%.4f, j=%.4f, k=%.4f, real=%.4f\n",
               value->data.rotation_vector.i,
               value->data.rotation_vector.j,
               value->data.rotation_vector.k,
               value->data.rotation_vector.real);
    }
}

void app_main(void)
{
    // Set up I2C
    i2c_master_bus_config_t bus_config = {
        .i2c_port = I2C_NUM_0,
        .sda_io_num = GPIO_NUM_6,
        .scl_io_num = GPIO_NUM_7,
        .clk_source = I2C_CLK_SRC_DEFAULT,
        .glitch_ignore_cnt = 7,
    };
    i2c_master_bus_handle_t bus_handle;
    i2c_new_master_bus(&bus_config, &bus_handle);

    i2c_device_config_t dev_config = {
        .dev_addr_length = I2C_ADDR_BIT_LEN_7,
        .device_address = 0x28,  // AD0 = GND
        .scl_speed_hz = 400000,
    };
    i2c_master_dev_handle_t i2c_dev;
    i2c_master_bus_add_device(bus_handle, &dev_config, &i2c_dev);

    // Initialize BNO085
    bno085_config_t config;
    bno085_config_default(&config);

    bno085_handle_t bno085;
    bno085_init(&config, i2c_dev, GPIO_NUM_5, GPIO_NUM_4, &bno085);

    // Register callback
    bno085_register_sensor_callback(bno085, sensor_callback, NULL);

    // Enable sensors
    bno085_enable_sensor(bno085, BNO085_SENSOR_ROTATION_VECTOR, 100000);  // 10Hz
    bno085_enable_sensor(bno085, BNO085_SENSOR_ACCELEROMETER, 100000);    // 10Hz

    // Service loop
    while (1) {
        bno085_service(bno085);
        vTaskDelay(pdMS_TO_TICKS(10));
    }
}
```

## API Reference

### Initialization

```c
esp_err_t bno085_init(const bno085_config_t *config,
                      i2c_master_dev_handle_t i2c_dev,
                      gpio_num_t int_pin,
                      gpio_num_t reset_pin,
                      bno085_handle_t *out_handle);
```

Initialize the BNO085. Only one instance per chip due to SH2 library limitations.

### Service Loop

```c
void bno085_service(bno085_handle_t handle);
```

Call periodically (10ms recommended) to read sensor data and dispatch callbacks.

### Cleanup

```c
void bno085_deinit(bno085_handle_t handle);
```

Close the device and free resources.

### Callbacks

```c
esp_err_t bno085_register_sensor_callback(bno085_handle_t handle,
                                          bno085_sensor_callback_t callback,
                                          void *user_context);
```

Register a callback function. Replaces any previous callback.

### Sensor Control

```c
esp_err_t bno085_enable_sensor(bno085_handle_t handle,
                               uint8_t sensor_id,
                               uint32_t report_interval_us);

esp_err_t bno085_disable_sensor(bno085_handle_t handle,
                                uint8_t sensor_id);
```

Enable/disable sensors with specified reporting interval in microseconds:
- 10000 = 10ms (100Hz)
- 100000 = 100ms (10Hz)
- 1000000 = 1000ms (1Hz)

### Configuration

```c
typedef struct {
    uint32_t i2c_timeout_ms;        // I2C operation timeout (default: 100ms)
    uint8_t  reset_retry_count;     // Soft-reset retries (default: 5)
    uint32_t reset_retry_delay_ms;  // Delay between retries (default: 30ms)
    uint32_t reset_settle_delay_ms; // Delay after reset (default: 300ms)
} bno085_config_t;

void bno085_config_default(bno085_config_t *config);
```

## Available Sensors

### Orientation Sensors

| Sensor ID | Constant | Output | Use Case |
|-----------|----------|--------|----------|
| 0x05 | `BNO085_SENSOR_ROTATION_VECTOR` | Quaternion | Most accurate, AR/VR, drones |
| 0x08 | `BNO085_SENSOR_GAME_ROTATION_VECTOR` | Quaternion | Games (no mag yaw drift) |
| 0x09 | `BNO085_SENSOR_GEOMAGNETIC_ROTATION_VECTOR` | Quaternion | Low power, stationary devices |
| 0x28 | `BNO085_SENSOR_AR_VR_STABILIZED_RV` | Quaternion | High-quality AR/VR |
| 0x2A | `BNO085_SENSOR_GYRO_INTEGRATED_RV` | Quaternion | Head tracking (1kHz) |

### Raw IMU Data

| Sensor ID | Constant | Output | Range |
|-----------|----------|--------|-------|
| 0x01 | `BNO085_SENSOR_ACCELEROMETER` | x, y, z (m/s²) | ±8g |
| 0x02 | `BNO085_SENSOR_GYROSCOPE_CALIBRATED` | x, y, z (rad/s) | Calibrated |
| 0x03 | `BNO085_SENSOR_MAGNETIC_FIELD_CALIBRATED` | x, y, z (µT) | Calibrated |
| 0x04 | `BNO085_SENSOR_LINEAR_ACCELERATION` | x, y, z (m/s²) | Gravity removed |
| 0x06 | `BNO085_SENSOR_GRAVITY` | x, y, z (m/s²) | Gravity vector only |
| 0x07 | `BNO085_SENSOR_GYROSCOPE_UNCALIBRATED` | x, y, z + bias | Raw with bias |
| 0x0F | `BNO085_SENSOR_MAGNETIC_FIELD_UNCALIBRATED` | x, y, z + bias | Raw with bias |
| 0x14 | `BNO085_SENSOR_RAW_ACCELEROMETER` | x, y, z | ADC counts |
| 0x15 | `BNO085_SENSOR_RAW_GYROSCOPE` | x, y, z | ADC counts |
| 0x16 | `BNO085_SENSOR_RAW_MAGNETOMETER` | x, y, z | ADC counts |

### Motion Detection & Activity

| Sensor ID | Constant | Description |
|-----------|----------|-------------|
| 0x10 | `BNO085_SENSOR_TAP_DETECTOR` | Single/double tap detection |
| 0x11 | `BNO085_SENSOR_STEP_COUNTER` | Step count since reset |
| 0x12 | `BNO085_SENSOR_SIGNIFICANT_MOTION` | Significant motion event |
| 0x13 | `BNO085_SENSOR_STABILITY_CLASSIFIER` | Device stability state |
| 0x18 | `BNO085_SENSOR_STEP_DETECTOR` | Step event trigger |
| 0x19 | `BNO085_SENSOR_SHAKE_DETECTOR` | Shake/vibration detection |
| 0x1A | `BNO085_SENSOR_FLIP_DETECTOR` | Device flip motion |
| 0x1B | `BNO085_SENSOR_PICKUP_DETECTOR` | Device pickup detection |
| 0x1E | `BNO085_SENSOR_PERSONAL_ACTIVITY_CLASSIFIER` | Activity type (walk, run, vehicle, etc.) |
| 0x1F | `BNO085_SENSOR_SLEEP_DETECTOR` | Sleep state detection |
| 0x20 | `BNO085_SENSOR_TILT_DETECTOR` | Tilt change detection |
| 0x21 | `BNO085_SENSOR_POCKET_DETECTOR` | In-pocket detection |
| 0x22 | `BNO085_SENSOR_CIRCLE_DETECTOR` | Circular motion detection |

### Environmental Sensors

| Sensor ID | Constant | Output | Units |
|-----------|----------|--------|-------|
| 0x0A | `BNO085_SENSOR_PRESSURE` | Atmospheric pressure | Pa |
| 0x0B | `BNO085_SENSOR_AMBIENT_LIGHT` | Light intensity | lux |
| 0x0C | `BNO085_SENSOR_HUMIDITY` | Relative humidity | % |
| 0x0E | `BNO085_SENSOR_TEMPERATURE` | Ambient temperature | °C |

## Usage Examples

### Get Orientation Only

```c
void sensor_callback(bno085_handle_t handle,
                    const bno085_sensor_value_t *value,
                    void *user_context)
{
    if (value->sensor_id == BNO085_SENSOR_ROTATION_VECTOR) {
        printf("Q: i=%f, j=%f, k=%f, real=%f, acc=%f rad\n",
               value->data.rotation_vector.i,
               value->data.rotation_vector.j,
               value->data.rotation_vector.k,
               value->data.rotation_vector.real,
               value->data.rotation_vector.accuracy_rad);
    }
}

bno085_register_sensor_callback(bno085, sensor_callback, NULL);
bno085_enable_sensor(bno085, BNO085_SENSOR_ROTATION_VECTOR, 100000);
```

### Get All IMU Data

```c
bno085_register_sensor_callback(bno085, sensor_callback, NULL);
bno085_enable_sensor(bno085, BNO085_SENSOR_ACCELEROMETER, 50000);
bno085_enable_sensor(bno085, BNO085_SENSOR_GYROSCOPE_CALIBRATED, 50000);
bno085_enable_sensor(bno085, BNO085_SENSOR_MAGNETIC_FIELD_CALIBRATED, 50000);
bno085_enable_sensor(bno085, BNO085_SENSOR_LINEAR_ACCELERATION, 50000);
```

### Activity Detection (Fitness Tracker)

```c
bno085_enable_sensor(bno085, BNO085_SENSOR_STEP_COUNTER, 500000);
bno085_enable_sensor(bno085, BNO085_SENSOR_PERSONAL_ACTIVITY_CLASSIFIER, 1000000);
bno085_enable_sensor(bno085, BNO085_SENSOR_SIGNIFICANT_MOTION, 1000000);
```

### Motion + Orientation (Robot/Drone)

```c
bno085_enable_sensor(bno085, BNO085_SENSOR_ROTATION_VECTOR, 50000);  // 20Hz
bno085_enable_sensor(bno085, BNO085_SENSOR_LINEAR_ACCELERATION, 50000);
bno085_enable_sensor(bno085, BNO085_SENSOR_GYROSCOPE_CALIBRATED, 50000);
```

### Game Controller

```c
bno085_register_sensor_callback(bno085, sensor_callback, NULL);
bno085_enable_sensor(bno085, BNO085_SENSOR_GAME_ROTATION_VECTOR, 10000);  // 100Hz
```

## Sensor Data Structure

The callback receives `bno085_sensor_value_t` with:
- `sensor_id`: Which sensor sent this data
- `status`: Accuracy/reliability (0=unreliable, 1=low, 2=medium, 3=high)
- `timestamp_us`: Timestamp in microseconds
- `data`: Union with decoded sensor data

Access the appropriate data field based on sensor_id:

```c
if (value->sensor_id == BNO085_SENSOR_ACCELEROMETER) {
    float x = value->data.accelerometer.x;
    float y = value->data.accelerometer.y;
    float z = value->data.accelerometer.z;
}

if (value->sensor_id == BNO085_SENSOR_ROTATION_VECTOR) {
    float i = value->data.rotation_vector.i;
    float j = value->data.rotation_vector.j;
    float k = value->data.rotation_vector.k;
    float real = value->data.rotation_vector.real;
    float accuracy = value->data.rotation_vector.accuracy_rad;
}

if (value->sensor_id == BNO085_SENSOR_STEP_COUNTER) {
    uint32_t steps = value->data.step_counter.count;
}
```

## Limitations

- Up to `CONFIG_BNO085_MAX_INSTANCES` concurrent sensors (default 2, configurable to 1-8)
- Only one active BNO085 per I2C bus without a multiplexer
- The underlying SH2 library is not thread-safe for init/deinit; call from a single task

## Example Project

See `examples/basic_read/` for a complete working example.

## License

Apache-2.0. Includes CEVA SH2 library (also Apache-2.0). See `LICENSE` for details.

Links

Supports all targets

To add this component to your project, run:

idf.py add-dependency "rinku404/bno085^1.1.1"

download archive

Stats

  • Archive size
    Archive size ~ 75.26 KB
  • Downloaded in total
    Downloaded in total 0 times
  • Downloaded this version
    This version: 0 times

Badge

rinku404/bno085 version: 1.1.1
|