Il BNO055 è un System in Package (SiP), che integra un accelerometro triassiale a 14 bit, un giroscopio triassiale a 16 bit con una gamma di ±2000 gradi al secondo, un sensore geomagnetico triassiale e un microcontrollore M0+ a 32 bit con sistema Bosch Sensortec software sensor fusion, in un unico pacchetto.
Il BNO055 può emettere i seguenti dati del sensore:
- Orientamento assoluto (Vettore di Eulero, 100 Hz) Dati di orientamento a tre assi basati su una sfera a 360°
- Orientamento assoluto (Quatenrion, 100 Hz) Uscita quaternione a quattro punti per una manipolazione dei dati più accurata
- Angular Velocity Vector (100Hz) Tre assi di ‘velocità di rotazione’ in rad/s
- Acceleration Vector (100Hz) Tre assi di accelerazione (gravità + movimento lineare) in m/s^2
- Vettore di intensità del campo magnetico (20Hz) Rilevamento a tre assi del campo magnetico in micro Tesla (uT)
- Vettore di accelerazione lineare (100 Hz) Tre assi di dati di accelerazione lineare (accelerazione meno gravità) in m/s^2
- Vettore di gravità (100 Hz) Tre assi di accelerazione gravitazionale (meno qualsiasi movimento) in m/s^2
- Temperatura (1Hz) Temperatura ambiente in gradi centigradi
Pinout BNO055
Esistono molte versioni di moduli di questi sensori, io scelgo il più piccolo ed economico.
Ecco il modulo che uso Aliexpress
Tutti questi moduli avevano le stesse caratteristiche, ma per abilitarle devi fare diverse operazioni.
Questo è il clone che uso:
Ed ecco quello di Adafruit:
Il sensore supporta il livello logico 3.3v, ma il modulo può essere alimentato a 5v.
Può comunicare tramite i2c (opzione di default) e tramite UART, per attivare l’ultima modalità è necessario dissaldare PS1
.
PS1 | PS0 | Functionality |
---|---|---|
0 | 0 | Interfaccia I2C standard/veloce |
0 | 1 | HID su I2C |
1 | 0 | Interfaccia UART |
1 | 1 | Riservato |
In modalità i2c standard puoi selezionare 2 indirizzi, di default in questo modulo è attivo l’indirizzo 0x29, se metti a GND il pin ADD l’indirizzo diventa 0x28.
i2c configuration | ADD | I2C address |
---|---|---|
Slave | HIGH | 0x29 |
Slave | LOW (default) | 0x28 |
HID-I2C | 0x40 |
INT è configurato come pin di interruzione per segnalare un’interruzione all’host. Il trigger di interruzione è configurato come fronte di salita ed è agganciato al pin INT. Una volta che si verifica un’interruzione, il pin INT viene impostato su alto e rimarrà alto fino a quando non viene ripristinato dall’host .
Caratteristiche
Caratteristiche del magnetometro
Un magnetometro è un dispositivo che misura il campo magnetico o il momento del dipolo magnetico. Alcuni magnetometri misurano la direzione, la forza o il cambiamento relativo di un campo magnetico in una posizione particolare.
Scrivo alcuni esempi e informazioni aggiuntive sui magnetometri in questo articolo “Magnetometro GY-273 QMC5883L clone HMC5883L per Arduino, esp8266 e esp32“.
- Funzionalità flessibile
Campo magnetico tipico ±1300µT (asse x, y);
±2500µT (asse z)
Risoluzione del campo magnetico di ~0,3µT- Modalità operative :
- Bassa potenza
- Regolare
- Regolare potenziato
- Alta precisione
- Modalità di alimentazione :
- Normale
- Sonno
- Sospendere
- Forza
- Modalità operative :
Caratteristiche dell’accelerometro
Un accelerometro è uno strumento che misura la corretta accelerazione. L’accelerazione corretta è l’accelerazione (la velocità di variazione della velocità) di un corpo nel proprio frame di riposo istantaneo; questo è diverso dall’accelerazione di coordinate, che è l’accelerazione in un sistema di coordinate fisse.
Ho spiegato di cosa si tratta in dettaglio e scritto vari esempi pratici di applicazione su questo articolo “Accelerometro GY-291 ADXL345 i2c spi con interrupt per esp32, esp8266, stm32 e Arduino“.
- Funzionalità programmabile Intervalli
di accelerazione ±2g/±4g/±8g/±16g
Ampiezze di banda del filtro passa-basso 1kHz – <8Hz
Modalità operative:- Normale
- Sospendere
- Bassa potenza
- Pausa
- Sospensione profonda
- Controller di interrupt su chip
Generazione di segnali di interrupt attivati dal movimento per- rilevamento di qualsiasi movimento (pendenza).
- riconoscimento del movimento lento o assente
- rilevamento di g alto
Caratteristiche del giroscopio
Un giroscopio è un dispositivo utilizzato per misurare o mantenere l’orientamento e la velocità angolare. In origine era un filatoio o disco in cui l’asse di rotazione (asse di rotazione) è libero di assumere da solo qualsiasi orientamento.
- Funzionalità programmabile
Intervalli commutabili da ±125°/s a ±2000°/s
Ampiezze di banda del filtro passa-basso 523Hz – 12Hz
Modalità operative :- Normale
- Accensione rapida
- Sospensione profonda
- Sospendere
- Risparmio energetico avanzato
- Controller di interrupt su chip
Generazione di segnali di interrupt attivati dal movimento per- rilevamento di qualsiasi movimento (pendenza).
- alta percentuale
Cablaggio
Per un utilizzo di base di i2c è necessario collegare solo VCC, GND, SDA e SCL.
Arduino UNO
La versione Adafruit del sensore è ben documentata e supporta completamente il livello logico 5v.
La versione clone non era chiara se supportava completamente il livello logico 5v, ma sicuramente supportava l’alimentazione a 5v. provo a usarlo con Arduino UNO e funziona correttamente senza LLC.
Cablaggio esp32
esp32 funziona a 3.3v, quindi il cablaggio era senza dubbio.
E qui il clone.
Cablaggio esp8266
L’esp8266 come esp32 funziona a 3.3v, quindi il cablaggio è lineare.
E ora il clone.
Libreria di base
Adafruit (come al solito) offre una libreria bella e molto semplice da usare che necessita degli Adafruit Unified Sensors , ma non supporta gli interrupt, e può essere installata direttamente dal gestore della libreria Arduino.
È necessario installare la libreria Adafruit Unified Sensor come dipendenze.
Qui lo sketch di esempio che mostra tutti i valori che puoi prelevare dal sensore.
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BNO055.h>
#include <utility/imumaths.h>
/* This driver uses the Adafruit unified sensor library (Adafruit_Sensor),
which provides a common 'type' for sensor data and some helper functions.
To use this driver you will also need to download the Adafruit_Sensor
library and include it in your libraries folder.
You should also assign a unique ID to this sensor for use with
the Adafruit Sensor API so that you can identify this particular
sensor in any data logs, etc. To assign a unique ID, simply
provide an appropriate value in the constructor below (12345
is used by default in this example).
Connections
===========
Connect SCL to analog 5
Connect SDA to analog 4
Connect VDD to 3.3-5V DC
Connect GROUND to common ground
History
=======
2015/MAR/03 - First release (KTOWN)
*/
/* Set the delay between fresh samples */
uint16_t BNO055_SAMPLERATE_DELAY_MS = 100;
// Check I2C device address and correct line below (by default address is 0x29 or 0x28)
// id, address
Adafruit_BNO055 bno = Adafruit_BNO055(55, 0x28);
void setup(void)
{
Serial.begin(115200);
Serial.println("Orientation Sensor Test"); Serial.println("");
/* Initialise the sensor */
if (!bno.begin())
{
/* There was a problem detecting the BNO055 ... check your connections */
Serial.print("Ooops, no BNO055 detected ... Check your wiring or I2C ADDR!");
while (1);
}
delay(1000);
}
void loop(void)
{
//could add VECTOR_ACCELEROMETER, VECTOR_MAGNETOMETER,VECTOR_GRAVITY...
sensors_event_t orientationData , angVelocityData , linearAccelData, magnetometerData, accelerometerData, gravityData;
bno.getEvent(&orientationData, Adafruit_BNO055::VECTOR_EULER);
bno.getEvent(&angVelocityData, Adafruit_BNO055::VECTOR_GYROSCOPE);
bno.getEvent(&linearAccelData, Adafruit_BNO055::VECTOR_LINEARACCEL);
bno.getEvent(&magnetometerData, Adafruit_BNO055::VECTOR_MAGNETOMETER);
bno.getEvent(&accelerometerData, Adafruit_BNO055::VECTOR_ACCELEROMETER);
bno.getEvent(&gravityData, Adafruit_BNO055::VECTOR_GRAVITY);
printEvent(&orientationData);
printEvent(&angVelocityData);
printEvent(&linearAccelData);
printEvent(&magnetometerData);
printEvent(&accelerometerData);
printEvent(&gravityData);
int8_t boardTemp = bno.getTemp();
Serial.println();
Serial.print(F("temperature: "));
Serial.println(boardTemp);
uint8_t system, gyro, accel, mag = 0;
bno.getCalibration(&system, &gyro, &accel, &mag);
Serial.println();
Serial.print("Calibration: Sys=");
Serial.print(system);
Serial.print(" Gyro=");
Serial.print(gyro);
Serial.print(" Accel=");
Serial.print(accel);
Serial.print(" Mag=");
Serial.println(mag);
Serial.println("--");
delay(BNO055_SAMPLERATE_DELAY_MS);
}
void printEvent(sensors_event_t* event) {
double x = -1000000, y = -1000000 , z = -1000000; //dumb values, easy to spot problem
if (event->type == SENSOR_TYPE_ACCELEROMETER) {
Serial.print("Accl:");
x = event->acceleration.x;
y = event->acceleration.y;
z = event->acceleration.z;
}
else if (event->type == SENSOR_TYPE_ORIENTATION) {
Serial.print("Orient:");
x = event->orientation.x;
y = event->orientation.y;
z = event->orientation.z;
}
else if (event->type == SENSOR_TYPE_MAGNETIC_FIELD) {
Serial.print("Mag:");
x = event->magnetic.x;
y = event->magnetic.y;
z = event->magnetic.z;
}
else if (event->type == SENSOR_TYPE_GYROSCOPE) {
Serial.print("Gyro:");
x = event->gyro.x;
y = event->gyro.y;
z = event->gyro.z;
}
else if (event->type == SENSOR_TYPE_ROTATION_VECTOR) {
Serial.print("Rot:");
x = event->gyro.x;
y = event->gyro.y;
z = event->gyro.z;
}
else if (event->type == SENSOR_TYPE_LINEAR_ACCELERATION) {
Serial.print("Linear:");
x = event->acceleration.x;
y = event->acceleration.y;
z = event->acceleration.z;
}
else {
Serial.print("Unk:");
}
Serial.print("\tx= ");
Serial.print(x);
Serial.print(" |\ty= ");
Serial.print(y);
Serial.print(" |\tz= ");
Serial.println(z);
}
E qui l’uscita seriale.
temperature: 26
Calibration: Sys=0 Gyro=3 Accel=0 Mag=1
--
Orient: x= 12.75 | y= -33.44 | z= 30.75
Rot: x= -37.00 | y= -15.81 | z= -15.88
Linear: x= 0.30 | y= -0.06 | z= -0.25
Mag: x= 26.69 | y= -11.50 | z= -23.06
Accl: x= -5.10 | y= -4.24 | z= 6.77
Accl: x= -5.41 | y= -4.18 | z= 7.02
temperature: 26
Calibration: Sys=0 Gyro=3 Accel=0 Mag=1
--
Orient: x= 11.81 | y= -31.56 | z= 34.44
Rot: x= -21.81 | y= -14.81 | z= -19.62
Linear: x= -0.21 | y= -0.23 | z= -0.53
Mag: x= 27.75 | y= -9.75 | z= -24.25
Accl: x= -5.47 | y= -4.80 | z= 6.72
Accl: x= -5.10 | y= -4.77 | z= 6.88
temperature: 26
Calibration: Sys=0 Gyro=3 Accel=0 Mag=1
--
Orient: x= 12.69 | y= -29.25 | z= 38.69
Rot: x= -36.44 | y= -7.81 | z= -18.81
Linear: x= 0.08 | y= 0.13 | z= -0.35
Mag: x= 27.50 | y= -8.69 | z= -25.75
Accl: x= -4.52 | y= -5.23 | z= 6.08
Accl: x= -4.76 | y= -5.40 | z= 6.64
temperature: 26
Calibration: Sys=0 Gyro=3 Accel=0 Mag=1
--
Orient: x= 13.25 | y= -27.19 | z= 42.06
Rot: x= -21.94 | y= -8.81 | z= -14.63
Linear: x= 0.30 | y= 0.02 | z= -0.77
Mag: x= 28.25 | y= -4.19 | z= -26.87
Accl: x= -4.15 | y= -5.85 | z= 5.68
Accl: x= -4.45 | y= -5.87 | z= 6.46
temperature: 26
Costruttore
Nell’esempio è possibile identificare il costruttore per la connessione i2c.
Adafruit_BNO055 bno = Adafruit_BNO055(55, 0x28);
la dichiarazione completa è:
Adafruit_BNO055(int32_t sensorID = -1, uint8_t address = BNO055_ADDRESS_A, TwoWire *theWire = &Wire);
Il primo parametro è un’identificazione univoca arbitraria del sensore, il secondo è l’indirizzo, di default è BNO055_ADDRESS_A
o 0x28
, l’ultimo è la dichiarazione Wire
.
Begin
Nel metodo Begin puoi specificare con il tipo di operazione che vuoi gestire:
bool begin(adafruit_bno055_opmode_t mode = OPERATION_MODE_NDOF);
Ci sono molte opzioni e si spiegano da sole:
OPERATION_MODE_CONFIG = 0X00,
OPERATION_MODE_ACCONLY = 0X01,
OPERATION_MODE_MAGONLY = 0X02,
OPERATION_MODE_GYRONLY = 0X03,
OPERATION_MODE_ACCMAG = 0X04,
OPERATION_MODE_ACCGYRO = 0X05,
OPERATION_MODE_MAGGYRO = 0X06,
OPERATION_MODE_AMG = 0X07,
OPERATION_MODE_IMUPLUS = 0X08,
OPERATION_MODE_COMPASS = 0X09,
OPERATION_MODE_M4G = 0X0A,
OPERATION_MODE_NDOF_FMC_OFF = 0X0B,
OPERATION_MODE_NDOF = 0X0C
Qui la tabella che spiega cosa succede quando si seleziona un’opzione specifica.
Non-fusionmodes (generate solo da sensori)
Operating Mode | Accel | Magn | Gyro | Rel. orient. Fusion | Absol. orient. Fusion |
---|---|---|---|---|---|
CONFIGMODE | – | – | – | – | – |
ACCONLY | X | – | – | – | – |
MAGONLY | – | X | – | – | – |
GYROONLY | – | – | X | – | – |
ACCMAG | X | X | – | – | – |
ACCGYRO | X | – | X | – | – |
MAGGYRO | – | X | X | – | – |
AMG | X | X | X | – | – |
Fusion modes
Operating Mode | Accel | Magn | Gyro | Rel. orient. Fusion | Absol. orient. Fusion |
---|---|---|---|---|---|
IMU | X | – | X | X | – |
COMPASS | X | X | – | – | X |
M4G | X | X | X | – | |
NDOF_FMC_OFF | X | X | X | – | X |
NDOF | X | X | X | – | X |
Recuperare i dati
Quindi possiamo ottenere i dati in modo selettivo come nell’esempio.
//could add VECTOR_ACCELEROMETER, VECTOR_MAGNETOMETER,VECTOR_GRAVITY...
sensors_event_t orientationData , angVelocityData , linearAccelData, magnetometerData, accelerometerData, gravityData;
bno.getEvent(&orientationData, Adafruit_BNO055::VECTOR_EULER);
bno.getEvent(&angVelocityData, Adafruit_BNO055::VECTOR_GYROSCOPE);
bno.getEvent(&linearAccelData, Adafruit_BNO055::VECTOR_LINEARACCEL);
bno.getEvent(&magnetometerData, Adafruit_BNO055::VECTOR_MAGNETOMETER);
bno.getEvent(&accelerometerData, Adafruit_BNO055::VECTOR_ACCELEROMETER);
bno.getEvent(&gravityData, Adafruit_BNO055::VECTOR_GRAVITY);
Oppure puoi ottenere tutti i dati in un colpo solo in questo modo.
/* Get a new sensor event */
sensors_event_t event;
bno.getEvent(&event);
Tipo di eventi vettoriali
Dati di accelerazione
bno.getEvent(&accelerometerData, Adafruit_BNO055::VECTOR_ACCELEROMETER);
[...]
if (event->type == SENSOR_TYPE_ACCELEROMETER) {
Serial.print("Accl:");
x = event->acceleration.x;
y = event->acceleration.y;
z = event->acceleration.z;
}
In modalità non-fusion dati di accelerazione non compensati per ciascun asse X/Y/Z.
In modalità fusion , l’algoritmo di fusione emette i dati di accelerazione compensati dall’offset per ciascun asse X/Y/Z.
Accelerazione lineare
bno.getEvent(&linearAccelData, Adafruit_BNO055::VECTOR_LINEARACCEL);
[...]
else if (event->type == SENSOR_TYPE_LINEAR_ACCELERATION) {
Serial.print("Linear:");
x = event->acceleration.x;
y = event->acceleration.y;
z = event->acceleration.z;
}
L’uscita dell’accelerazione lineare è disponibile solo nelle modalità operative di fusione .
L’algoritmo di fusione emette dati di accelerazione lineare per ciascun asse x/y/z.
Intensità del campo magnetico
bno.getEvent(&magnetometerData, Adafruit_BNO055::VECTOR_MAGNETOMETER);
[...]
else if (event->type == SENSOR_TYPE_MAGNETIC_FIELD) {
Serial.print("Mag:");
x = event->magnetic.x;
y = event->magnetic.y;
z = event->magnetic.z;
}
In modalità non fusione, dati sull’intensità di campo non compensati per ciascun asse X/Y/Z.
In modalità fusione, l’algoritmo di fusione emette dati sull’intensità del campo magnetico compensati per ciascun asse X/Y/Z.
Orientamento (angoli di Eulero)
bno.getEvent(&orientationData, Adafruit_BNO055::VECTOR_EULER);
[...]
else if (event->type == SENSOR_TYPE_ORIENTATION) {
Serial.print("Orient:");
x = event->orientation.x;
y = event->orientation.y;
z = event->orientation.z;
}
L’output di orientamento è disponibile solo nelle modalità operative di fusione .
L’algoritmo di fusione emette dati sull’offset e sull’orientamento con compensazione dell’inclinazione nel formato degli angoli di Eulero per ciascuna direzione/rollio/inclinazione DOF. Fare riferimento alla tabella seguente per informazioni sui tipi di dati e la rappresentazione dell’unità per il formato dell’angolo di Eulero.
Vettore di gravità
bno.getEvent(&gravityData, Adafruit_BNO055::VECTOR_GRAVITY);
[...]
else if (event->type == SENSOR_TYPE_ROTATION_VECTOR) {
Serial.print("Rot:");
x = event->gyro.x;
y = event->gyro.y;
z = event->gyro.z;
}
L’uscita del vettore di gravità è disponibile solo nelle modalità operative di fusione .
L’algoritmo di fusione genera dati vettoriali di gravità per ciascun asse x/y/z.
Velocità angolare
bno.getEvent(&angVelocityData, Adafruit_BNO055::VECTOR_GYROSCOPE);
[...]
else if (event->type == SENSOR_TYPE_GYROSCOPE) {
Serial.print("Gyro:");
x = event->gyro.x;
y = event->gyro.y;
z = event->gyro.z;
}
In modalità non fusione, dati di velocità angolare (velocità di imbardata) non compensati per ciascun asse X/Y/Z.
In modalità fusione, l’algoritmo di fusione emette i dati di velocità angolare compensata (velocità di imbardata) per ciascun asse X/Y/Z.
Quaternione
La funzione .getQuat restituisce un Quaternion, con cui è spesso più facile e preciso lavorare rispetto agli angoli di Eulero quando si esegue la fusione del sensore o la manipolazione dei dati con i dati grezzi del sensore.
È possibile ottenere un campione di dati di quaternioni tramite il codice seguente:
imu::Quaternion quat = bno.getQuat();
/* Display the quat data */
Serial.print("qW: ");
Serial.print(quat.w(), 4);
Serial.print(" qX: ");
Serial.print(quat.y(), 4);
Serial.print(" qY: ");
Serial.print(quat.x(), 4);
Serial.print(" qZ: ");
Serial.print(quat.z(), 4);
Serial.println("");
Temperatura
L’helper .getTemp restituisce la temperatura ambiente attuale in gradi Celsius e può essere letta tramite la seguente chiamata di funzione:
/* Display the current temperature */
int8_t temp = bno.getTemp();
Serial.print("Current Temperature: ");
Serial.print(temp);
Serial.println(" C");
Serial.println("");
Risparmio energetico
Puoi anche entrare in modalità di sospensione e tornare alla normalità con questi comandi.
/* Power managments functions */
void enterSuspendMode();
void enterNormalMode();
Sposta il coniglietto 3d con WebGL e posizione assoluta
Un esempio molto interessante fornito con la libreria è leggere i dati seriali e convertirli in una rotazione 3D per farlo in modo semplice, utilizzando l’API Web Serial per il browser Chrome.
Quindi, prima, hai bisogno di Chrome.
Quindi devi abilitare l’API WebSerial e, per farlo, devi inserire l’URL nel browser, chrome://flags
quindi cercare (con Ctrl + f) le funzionalità della piattaforma Web sperimentale e abilitarlo.
Quindi carica l’esempio fornito nella libreria webserial_3d , caricalo e avvialo.
Ora apri questo nel browser questo URL:
https://adafruit.github.io/Adafruit_WebSerial_3DModelViewer/
Selezionare 9600 baud , fare clic su Connetti e selezionare la porta seriale del dispositivo corretta.
Il risultato è che puoi cambiare l’orientamento del coniglietto con il movimento di bno055.
Questa è una libreria fantastica, ma penso sia il caso di sperimentare anche una gestione più complessa del dispositivo con l’ausilio anche di interrupt, per fare questo faremo uso di un’altra libreria nel prossimo articolo.
Grazie
- BNO055 accelerometro, giroscopio, magnetometro con la semplice libreria Adafruit
- BNO055 per esp32, esp8266 e Arduino: cablaggio e libreria Bosch avanzata
- BNO055 per esp32, esp8266 e Arduino: caratteristiche, configurazione e rimappatura assi
- BNO055: modalità di alimentazione, accelerometro e interrupt di movimento
- BNO055 per esp32, esp8266 e Arduino: abilitare il pin INT e High G Interrupt dell’accelerometro
- BNO055 per esp32, esp8266 e Arduino: giroscopio ad alta velocità e interrupt per ogni movimento