API guide¶
How to do the common jobs with the driver: start the hub, enable reports, read them, stop, and handle errors.
Every snippet on this page is compiled by the host CI from
tests/docs/api_tasks.cpp, with Imu standing for BNO085<MyI2c>. The
API reference lists every member.
The shape of the API¶
One BNO085<Comm> object per sensor. Its calls fall into four groups; the port's GetInterfaceType() decides
which groups work:
| Group | Calls | Interface |
|---|---|---|
| SH-2 session | Begin(), Close(), Update() |
I2C, SPI, UART |
| Reports | EnableSensor(), DisableSensor(), SetCallback(), HasNewData(), GetLatest() |
I2C, SPI, UART |
| UART-RVC | BeginRvc(), ServiceRvc(), SetRvcCallback(), CloseRvc() |
UARTRVC (UART-RVC mode) |
| Firmware update | EnterBootloader(), Dfu(), DfuFromMemory(), RunDfuFromMemory(), ExitBootloaderAndReboot() |
I2C, SPI, UART (Firmware update) |
| Pins and state | HardwareReset(), SetBootPin(), SetWakePin(), SelectInterface(), GetState(), GetLastError() |
any |
Calls that can fail return bool (or an SH-2 status int for firmware updates) and never throw. After a
false, GetLastError() holds the reason as an SH2_ERR_* code.
Start the hub¶
bool start_imu(Imu& imu) {
imu.HardwareReset(); // optional: NRST low 2 ms, then 94 ms for the hub to boot
if (!imu.Begin()) {
std::printf("Begin failed: %d\n", imu.GetLastError()); // SH2_ERR_* (sh2_err.h)
return false;
}
return imu.GetState() == BNO085DriverState::Sh2Active;
}
Begin() opens your port, starts the CEVA SH-2 library, waits up to 200 ms for the hub's reset message and sends
a reinitialise command. Calling it again while the session is open returns true and does nothing.
Enable reports¶
bool enable_reports(Imu& imu) {
bool ok = true;
ok &= imu.EnableSensor(BNO085Sensor::GameRotationVector, 5); // 200 Hz, no magnetometer
ok &= imu.EnableSensor(BNO085Sensor::LinearAcceleration, 10); // 100 Hz
ok &= imu.EnableSensor(BNO085Sensor::Gyroscope, 10); // 100 Hz
ok &= imu.EnableSensor(BNO085Sensor::StepCounter, 0); // on change
ok &= imu.EnableSensor(BNO085Sensor::TapDetector, 0); // on change
return ok;
}
EnableSensor(sensor, interval_ms, sensitivity) takes the report period in milliseconds; 0 suits on-change
reports such as the step counter. The hub picks a rate between 0.9 and 2.1 times the one you ask for, and not every
report can run at its maximum at once. The driver remembers each interval and re-sends it when the hub reports a
reset. Configuration lists the report types and their maximum rates.
Read reports with a callback¶
void use_callbacks(Imu& imu) {
imu.SetCallback([](const SensorEvent& e) {
switch (e.sensor) {
case BNO085Sensor::GameRotationVector:
std::printf("q %.3f %.3f %.3f %.3f\n", e.rotation.w, e.rotation.x, e.rotation.y,
e.rotation.z);
break;
case BNO085Sensor::StepCounter:
std::printf("steps %u\n", static_cast<unsigned>(e.stepCount));
break;
case BNO085Sensor::TapDetector:
std::printf("%s tap\n", e.tap.doubleTap ? "double" : "single");
break;
default:
break;
}
});
for (;;) {
imu.Update(); // the callback runs from here, on this thread
}
}
The callback runs inside Update(), on the thread that calls it, once per report. Keep it short: copy the data
out. SensorEvent is one struct for every report type; the fields that matter depend on e.sensor:
| Report | Field | Unit |
|---|---|---|
Rotation vectors (RotationVector, GameRotationVector, GeomagneticRotationVector, ARVRStabilized*) |
rotation (w, x, y, z, accuracy) |
unit quaternion |
GyroIntegratedRV |
rotation, angularVelocity |
quaternion, rad/s |
Accelerometer, LinearAcceleration, Gravity |
vector |
m/s² |
Gyroscope / GyroUncalibrated |
vector (+ bias) |
rad/s |
Magnetometer / MagneticFieldUncalibrated |
vector (+ bias) |
µT |
RawAccelerometer, RawGyroscope, RawMagnetometer |
raw |
ADC counts |
Pressure, AmbientLight, Humidity, Proximity, Temperature |
scalar |
hPa, lux, %, cm, °C |
StepCounter |
stepCount, latencyUs |
steps, µs |
TapDetector |
tap (doubleTap, direction) |
|
StabilityClassifier, PersonalActivityClassifier |
classification, activity |
|
| Gesture detectors (shake, flip, pickup, tilt, ...) | detected, eventFlags |
Read reports by polling¶
void poll(Imu& imu) {
imu.Update();
if (imu.HasNewData(BNO085Sensor::LinearAcceleration)) {
const SensorEvent e = imu.GetLatest(BNO085Sensor::LinearAcceleration); // clears the flag
std::printf("a %.2f %.2f %.2f m/s^2 (accuracy %u)\n", e.vector.x, e.vector.y, e.vector.z,
static_cast<unsigned>(e.vector.accuracy));
}
}
HasNewData() is set when a report arrives and cleared by GetLatest(). The callback does not clear it, so you can
mix both styles. Outside an SH-2 session HasNewData() returns false and GetLatest() a default event.
Stop reports and close¶
void stop(Imu& imu) {
imu.DisableSensor(BNO085Sensor::Gyroscope); // report interval 0: the hub stops it
imu.Close(); // sh2_close(), then the port's Close()
}
The destructor closes an open SH-2 or RVC session too. Close the session before you power the sensor down.
Handle errors¶
const char* sh2_error_name(int code) {
switch (code) {
case SH2_OK:
return "ok";
case SH2_ERR:
return "general error (transport did not open, hub did not answer)";
case SH2_ERR_BAD_PARAM:
return "bad parameter, or a call for the wrong interface type";
case SH2_ERR_OP_IN_PROGRESS:
return "wrong driver state (not started, or another mode is active)";
case SH2_ERR_IO:
return "bus error";
case SH2_ERR_HUB:
return "the hub reported an error";
case SH2_ERR_TIMEOUT:
return "the hub did not answer in time";
default:
return "unknown";
}
}
bool enable_or_report(Imu& imu) {
if (!imu.EnableSensor(BNO085Sensor::RotationVector, 10)) {
std::printf("EnableSensor: %s\n", sh2_error_name(imu.GetLastError()));
return false;
}
return true;
}
| Signal | Meaning | Where to look |
|---|---|---|
Begin() is false, SH2_ERR |
The port's Open() failed, or the SH-2 library could not start |
Bus pins, address, power |
SH2_ERR_TIMEOUT |
The hub did not answer a command in time | H_INTN wiring, Read() contract, PS0/PS1 straps |
SH2_ERR_BAD_PARAM |
Wrong interface for the call (SH-2 call on UART-RVC, or the reverse), or a bad DFU image | GetInterfaceType() |
SH2_ERR_OP_IN_PROGRESS |
Wrong state: reports before Begin(), a call during a firmware update |
GetState() |
BNO08X_ERR_SH2_SESSION_IN_USE (-100) |
Begin() refused: another BNO085 object holds the one SH-2 session of the process |
Close() the other object first (Architecture) |
accuracy 0 or 1 |
Calibration not settled yet | Move the device; keep it away from magnetic fields |
| Reports stop, then resume | The hub reset; the driver re-enabled your reports | Supply, NRST, ESD |
Troubleshooting maps symptoms to causes.
Control pins¶
HardwareReset(lowMs) holds NRST active for lowMs (default 2 ms) and then waits RESET_STARTUP_MS (94 ms, the
start-up time of datasheet figure 6-8). SetBootPin(true)
asserts BOOTN (low) for the bootloader; SetWakePin(true) asserts WAKE in SPI mode. Each forwards to your port's
GpioSet(), so a pin the board does not wire is a no-op. All four return false when the port's GpioSet()
reports a GPIO error (Porting). Hardware has the levels.