firmware: recover slow BNO086 startup
This commit is contained in:
@@ -7,6 +7,7 @@
|
|||||||
- Prevented echoed or oversized RS485 frames from starving the XIAO sensor loop.
|
- Prevented echoed or oversized RS485 frames from starving the XIAO sensor loop.
|
||||||
- Silently discard malformed partial RS485 echoes instead of emitting recursive `invalid_json` responses.
|
- Silently discard malformed partial RS485 echoes instead of emitting recursive `invalid_json` responses.
|
||||||
- Replaced sensor auto-detection with the verified installation settings: BNO086 address `0x4B` and MAX-M10S UART at 38400 baud.
|
- Replaced sensor auto-detection with the verified installation settings: BNO086 address `0x4B` and MAX-M10S UART at 38400 baud.
|
||||||
|
- Added fixed-address BNO086 power-up retries, runtime recovery, and report restoration after sensor resets.
|
||||||
|
|
||||||
## Unreleased
|
## Unreleased
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ This Arduino sketch reads a BNO086 IMU and MAX-M10S GPS and publishes versioned,
|
|||||||
Power both sensors from 3.3V with shared ground. Required Arduino libraries are Adafruit BNO08x, TinyGPSPlus, and ArduinoJson 6.x. Enable **USB CDC On Boot** for diagnostics. GPS uses hardware UART0 at the verified 38400 baud; RS485 uses hardware UART1.
|
Power both sensors from 3.3V with shared ground. Required Arduino libraries are Adafruit BNO08x, TinyGPSPlus, and ArduinoJson 6.x. Enable **USB CDC On Boot** for diagnostics. GPS uses hardware UART0 at the verified 38400 baud; RS485 uses hardware UART1.
|
||||||
|
|
||||||
The BNO086 uses the verified `0x4B` I2C address on D7/D8. If initialization fails, verify 3.3V/GND, SDA/SCL wiring, and the breakout's PS0/PS1 configuration.
|
The BNO086 uses the verified `0x4B` I2C address on D7/D8. If initialization fails, verify 3.3V/GND, SDA/SCL wiring, and the breakout's PS0/PS1 configuration.
|
||||||
|
Firmware retries the fixed address during power-up and periodically retries afterward, so a slow BNO086 power-up does not require cycling the XIAO. If the BNO086 resets at runtime, rotation-vector reporting is enabled again automatically.
|
||||||
|
|
||||||
The node sends `sensor_status` at 115200 baud every 200 ms. See `docs/SENSOR_NODE_PROTOCOL.md`. The initial firmware is transmit-only; add a dashboard receiver after bench-testing the node, RS485 polarity, and sensor axes.
|
The node sends `sensor_status` at 115200 baud every 200 ms. See `docs/SENSOR_NODE_PROTOCOL.md`. The initial firmware is transmit-only; add a dashboard receiver after bench-testing the node, RS485 polarity, and sensor axes.
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,14 @@ namespace {
|
|||||||
Adafruit_BNO08x bno086(-1);
|
Adafruit_BNO08x bno086(-1);
|
||||||
sh2_SensorValue_t value;
|
sh2_SensorValue_t value;
|
||||||
bool initialized = false;
|
bool initialized = false;
|
||||||
|
unsigned long lastInitAttemptMs = 0;
|
||||||
float radiansToDegrees(float r) { return r * 180.0f / PI; }
|
float radiansToDegrees(float r) { return r * 180.0f / PI; }
|
||||||
|
bool tryInitImu() {
|
||||||
|
lastInitAttemptMs = millis();
|
||||||
|
initialized = bno086.begin_I2C(BNO086_I2C_ADDRESS, &Wire);
|
||||||
|
if (initialized) initialized = bno086.enableReport(SH2_ROTATION_VECTOR, IMU_REPORT_INTERVAL_US);
|
||||||
|
return initialized;
|
||||||
|
}
|
||||||
void updateEuler(ImuState& s) {
|
void updateEuler(ImuState& s) {
|
||||||
float sinr = 2 * (s.real * s.i + s.j * s.k);
|
float sinr = 2 * (s.real * s.i + s.j * s.k);
|
||||||
float cosr = 1 - 2 * (s.i * s.i + s.j * s.j);
|
float cosr = 1 - 2 * (s.i * s.i + s.j * s.j);
|
||||||
@@ -27,13 +34,29 @@ bool initImu() {
|
|||||||
delay(100);
|
delay(100);
|
||||||
Serial.print("Starting BNO086 at 0x");
|
Serial.print("Starting BNO086 at 0x");
|
||||||
Serial.println(BNO086_I2C_ADDRESS, HEX);
|
Serial.println(BNO086_I2C_ADDRESS, HEX);
|
||||||
initialized = bno086.begin_I2C(BNO086_I2C_ADDRESS, &Wire);
|
for (int attempt = 1; attempt <= BNO086_INIT_ATTEMPTS; attempt++) {
|
||||||
if (initialized) initialized = bno086.enableReport(SH2_ROTATION_VECTOR, IMU_REPORT_INTERVAL_US);
|
if (tryInitImu()) return true;
|
||||||
return initialized;
|
Serial.print("BNO086 init attempt failed: ");
|
||||||
|
Serial.println(attempt);
|
||||||
|
delay(BNO086_INIT_RETRY_DELAY_MS);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void maintainImu(ImuState& s) {
|
||||||
|
if (initialized || millis() - lastInitAttemptMs < BNO086_RUNTIME_RETRY_MS) return;
|
||||||
|
Serial.println("Retrying BNO086 initialization");
|
||||||
|
s.online = tryInitImu();
|
||||||
|
if (s.online) Serial.println("BNO086 recovered");
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateImu(ImuState& s) {
|
void updateImu(ImuState& s) {
|
||||||
s.online = initialized;
|
s.online = initialized;
|
||||||
|
if (initialized && bno086.wasReset()) {
|
||||||
|
initialized = bno086.enableReport(SH2_ROTATION_VECTOR, IMU_REPORT_INTERVAL_US);
|
||||||
|
s.online = initialized;
|
||||||
|
if (!initialized) return;
|
||||||
|
}
|
||||||
if (!initialized || !bno086.getSensorEvent(&value) || value.sensorId != SH2_ROTATION_VECTOR) return;
|
if (!initialized || !bno086.getSensorEvent(&value) || value.sensorId != SH2_ROTATION_VECTOR) return;
|
||||||
s.i = value.un.rotationVector.i; s.j = value.un.rotationVector.j;
|
s.i = value.un.rotationVector.i; s.j = value.un.rotationVector.j;
|
||||||
s.k = value.un.rotationVector.k; s.real = value.un.rotationVector.real;
|
s.k = value.un.rotationVector.k; s.real = value.un.rotationVector.real;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "sensor_state.h"
|
#include "sensor_state.h"
|
||||||
bool initImu();
|
bool initImu();
|
||||||
|
void maintainImu(ImuState& state);
|
||||||
void updateImu(ImuState& state);
|
void updateImu(ImuState& state);
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,9 @@
|
|||||||
#define GPS_TX_PIN D10
|
#define GPS_TX_PIN D10
|
||||||
#define BNO086_I2C_ADDRESS 0x4B
|
#define BNO086_I2C_ADDRESS 0x4B
|
||||||
#define BNO086_I2C_CLOCK_HZ 100000
|
#define BNO086_I2C_CLOCK_HZ 100000
|
||||||
|
#define BNO086_INIT_ATTEMPTS 8
|
||||||
|
#define BNO086_INIT_RETRY_DELAY_MS 250
|
||||||
|
#define BNO086_RUNTIME_RETRY_MS 5000
|
||||||
#define GPS_BAUD 38400
|
#define GPS_BAUD 38400
|
||||||
#define RS485_BAUD 115200
|
#define RS485_BAUD 115200
|
||||||
#define IMU_REPORT_INTERVAL_US 20000
|
#define IMU_REPORT_INTERVAL_US 20000
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ void setup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
updateGps(gpsSerial, gpsState); updateImu(imuState);
|
updateGps(gpsSerial, gpsState); maintainImu(imuState); updateImu(imuState);
|
||||||
pollRs485Commands(rs485Serial, imuState);
|
pollRs485Commands(rs485Serial, imuState);
|
||||||
String calibrationResult;
|
String calibrationResult;
|
||||||
if (updateLevelCalibration(imuState, calibrationResult)) {
|
if (updateLevelCalibration(imuState, calibrationResult)) {
|
||||||
|
|||||||
@@ -35,6 +35,9 @@ def test_imu_uses_verified_i2c_address():
|
|||||||
imu = source("imu.cpp")
|
imu = source("imu.cpp")
|
||||||
assert "BNO086_I2C_ADDRESS 0x4B" in config
|
assert "BNO086_I2C_ADDRESS 0x4B" in config
|
||||||
assert "findBnoAddress" not in imu
|
assert "findBnoAddress" not in imu
|
||||||
|
assert "BNO086_INIT_ATTEMPTS" in imu
|
||||||
|
assert "BNO086_RUNTIME_RETRY_MS" in imu
|
||||||
|
assert "bno086.wasReset()" in imu
|
||||||
|
|
||||||
def test_gps_uses_verified_uart_baud():
|
def test_gps_uses_verified_uart_baud():
|
||||||
config = source("sensor_node_config.h")
|
config = source("sensor_node_config.h")
|
||||||
|
|||||||
Reference in New Issue
Block a user