Über den Beitrag
Nachdem ich im letzten Beitrag die BNO08x-Module behandelt habe, wende ich mich in diesem Beitrag dem kleinen Bruder, nämlich dem BNO055, zu. Ich gehe zunächst auf die Eigenschaften des BNO055 ein und zeige dann, wie ihr ihn mithilfe der beliebten Bibliothek Adafruit BNO055 ansteuert. Da die Adafruit-Bibliothek nur einen Teil des Funktionsumfanges des BNO055 implementiert hat, stelle ich als Alternative die vollständigere Bibliothek DFRobot_BNO055 vor. Das komplette Potenzial hebt die Bibliothek BNO055, die vom Hersteller selbst stammt. Der Preis dafür ist ein höherer Aufwand bei der Einarbeitung. Nach dem Studium dieses Artikels sollte es jedoch schneller gehen.
Das erwartet euch im einzelnen:
- BNO055 vs. BNO08x
- BNO055-Module
- Eigenschaften des BNO055
- Ansteuerung mit der Adafruit-Bibliothek
- Ansteuerung mit der DFRobot-Bibliothek
- Ansteuerung mit der Bosch-Bibliothek
BNO055 vs. BNO08x
Laut Adafruit basieren der BNO055 und die BNO08x-Vertreter auf derselben Hardware. Der entscheidende Unterschied liegt in der Firmware, die auf dem internen Mikrocontroller ausgeführt wird. Die Firmwareversionen bedingen zwei wesentliche Unterschiede:
- Zum einen sind die Vertreter der BNO08x-Familie in der Lage, komplexe Bewegungsmuster wie Schrittfolgen oder Schüttelbewegungen selbstständig zu erkennen.
- Zum anderen verfolgen beide Sensorreihen grundlegend unterschiedliche Kommunikationskonzepte: Beim BNO055 werden die Sensordaten direkt aus Registern gelesen. Bei den BNO08x-Modulen hingegen erfolgt die Kommunikation ausschließlich über die SH-2-Software, die als API zwischen Mikrocontroller und Sensor fungiert.
Die BNO08x-Module bieten damit zwar eine höhere Funktionalität, verlangen aber auch eine entsprechend leistungsfähigere Ansteuerung. Die Bibliotheken für den BNO055 laufen hingegen problemlos auf vergleichsweise kleineren Mikrocontrollern wie dem ATmega328P (z. B. Arduino UNO R3, „Classic“ Nano oder Pro Mini).
BNO055-Module
Ich betrachte in diesem Beitrag ausschließlich BNO055-Module. Hier ein paar gängige Vertreter:


- Beim linken Modul wird der externe Quarz separat mitgeliefert. Ihr lötet ihn unterhalb „COM3“ ein. Auf den anderen Modulen sind die Quarze schon verfügbar.
- Vom linken Modul gibt es Versionen, bei denen die Lötbrücken S0 und S1 (= PS0/PS1, Protocol Select) nicht wie oben abgebildet verlötet sind (auf GND gezogen). Um das I²C-Protokoll einzustellen, müsst ihr das nachholen. Beim mittleren Modul gibt es dazu keine Einstellmöglichkeit. Beim Adafruit-Modul sind PS0/PS1 auf GND gezogen.
- Der I²C-Adresspin ist bei den No-Name-Modulen auf HIGH gezogen (Adresse 0x29), wohingegen auf dem Adafruit-Modul ein Pull-Down-Widerstand zum Einsatz kommt (Adresse 0x28). Ihr wechselt die Adresse über den Address-Pin (I2C-SEL auf dem linken Board). Beim Adafruit-Modul könnt ihr alternativ die Lötbrücke auf der Rückseite des Moduls schließen.
- Nur das Adafruit-Modul ist 5V-tolerant. Es besitzt einen Spannungsregler und Levelshifter.
- Das Adafruit-Modul verfügt über die praktischen STEMMA-QT-Anschlüsse (kompatibel mit Qwiic).
Die preislichen Unterschiede sind erheblich. Bezahlt man für die No-Name-Module unter 10 Euro, so sind es für das Adafruit-Modul 30 bis 40 Euro. Auch von DFRobot gibt es ein hochwertiges Modul in ähnlicher Preislage. Qualität und Entwicklungskosten haben ihren Preis.
Eigenschaften des BNO055
Das Datenblatt und weitere Dokumente könnt ihr hier herunterladen.
Datenausgabe
Der BNO055 erlaubt euch die Ausgabe der folgenden Messwerte:
- Beschleunigung (Acceleration Vector): Beschleunigung des Moduls, inklusive der Schwerkraft
- max. Datenrate: 100 Hz, Einheit: m/s² oder mg (= Milli-g, nicht etwa Milligramm)
- Lineare Beschleunigung (Linear Acceleration Vector): Beschleunigung des Moduls, exklusive der Schwerkraft
- max. Datenrate: 100 Hz, Einheit: m/s² oder mg
- Schwerkraft (Gravity Vector): Nur die auf das Modul wirkende Erdbeschleunigung
- max. Datenrate: 100 Hz, Einheit: m/s² oder mg
- Winkelgeschwindigkeit (Angular Velocity Vector)
- max. Datenrate: 100 Hz, Einheit: rad/s oder °/s
- Magnetfeldstärke (Magnetic Field Strength Vector)
- max. Datenrate: 20 Hz, Einheit: µTesla
- Absolute Orientierung (Absolute Orientation)
- Als Quaternion
- max. Datenrate: 100 Hz, Einheit: ohne
- Als Euler-Winkel
- max. Datenrate: 100 Hz, Einheit: ° oder rad
- Als Quaternion
- Temperatur
- max. Datenrate: 1 Hz, Einheit: °C oder °F
Euler-Winkel beschreiben die absolute Ausrichtung im Raum über den Yaw- (auch: Heading), den Pitch- und den Rollwinkel, zu deutsch: Gier-, Nick- und Rollwinkel. Quaternionen sind mathematische Konstrukte, die gewisse Probleme der Euler-Winkel, wie etwa den Gimbal-Lock, umgehen.
Fusion und Non-Fusion-Modi
Das Magnetometer, das Gyroskop und das Magnetometer sind die eigentlichen Sensoren des BNO055. Das Tolle am BNO055 ist, dass er diese Daten kombinieren kann, um daraus die absolute Ausrichtung im Raum zu berechnen oder um die Erdbeschleunigung (Gravity) von der durch Bewegung wirkenden Beschleunigung (Linear Acceleration) zu trennen. Die Kombinationswerte erhaltet ihr in den sogenannten Fusion-Modi. Wollt ihr einfach nur die blanken Sensordaten, könnt ihr die Non-Fusion-Modi verwenden. Hier die Übersicht über alle Modi:

Die Non-Fusion-Modi sollten selbsterklärend sein. Einige Bemerkungen zu den Fusion Modes:
- IMU (Inertial Measurement Unit): Accelerometer und Gyroskop, also die „echten“ IMUs.
- Schnell, aber nur relative Orientierung.
- COMPASS: Nutzt die x- und die y-Achse des Magnetometers und das Accelerometer, um die Lage des Magnetometers zu bestimmen.
- Absolute Orientierung, aber Qualität kann durch störende Magnetfelder beeinträchtigt werden.
- M4G (Magnet for Gyroscope): Accelerometer und Magnetometer; ohne Kalibrierung des Magnetometers.
- Wie IMU, aber mit Magnetometer anstelle des Gyroskops. Absolute Orientierung, geringerer Strombedarf als IMU aber dafür anfällig gegenüber störenden Magnetfeldern.
- NDOF (Nine Degrees of Freedom): Alle Sensoren, mit schneller Kalibrierung des Magnetometers.
- Die akkurateste und schnellste Methode, aber mit höchstem Stromverbrauch.
- NDOF_FMC_OFF (NDOF – Fast Magnetometer Calibration Off): Wie NDOF, aber mit langsamer Kalibrierung des Magnetometers.
- Etwas geringerer Stromverbrauch als NDOF.
NDOF ist bei Nutzung der Adafruit-Bibliothek der voreingestellte Modus.
Elektrische Eckdaten
- Spannungsversorgung: 2.4 – 3.6 Volt (Adafruit-Modul: auch 5 Volt möglich)
- Typische Startzeiten:
- Reset: 650 ms
- Kaltstart: 400 ms
- Stromverbrauch (selbst ermittelt im NDOF-Modus):
- Normal Mode: 12.9 mA
- Suspend Mode: 1.2 mA
- Low-Power-Mode: 12.9 mA (aktive Phase) / 1.9 mA (Stromsparphase)
- Der Low-Power-Mode ist in der Adafruit-Bibliothek nicht implementiert (Stand Feb. 2026)
Eigenschaften der Sensoren
Die Sensoren haben ein breites Spektrum an möglichen Einstellungen:
- Accelerometer:
- Range: ± 2 g, ± 4 g, ± 8 g, ± 16 g
- Bandbreite: 7.81 Hz, 15.63 Hz, 31.25 Hz, 62.5 Hz, 125 Hz, 250 Hz, 500 Hz, 1000 Hz
- Betriebsmodi: Normal, Suspend, Low Power 1, Low Power 2, Standby, Deep Suspend
- Gyroskop:
- Range: ± 125 °/s, ± 250 °/s, ± 500 °/s, ± 1000 °/s, ± 2000 °/s
- Bandbreite: 12 Hz, 23 Hz, 32 Hz, 47 Hz, 64 Hz, 116 Hz, 230 Hz, 523 Hz
- Betriebsmodi: Normal, Fast Power Up, Deep Suspend, Suspend, Advanced Powersave
- Magnetometer:
- Range (typische Werte): ± 1300 µT, ± 2500 µT
- Datenrate: 2 Hz, 6 Hz, 8 Hz, 10 Hz, 15 Hz, 20 Hz, 25 Hz, 30 Hz
- Betriebsmodi: Low Power, Regular, Enhanced Regular, High Accuracy
- Power Modi: Normal, Sleep, Suspend, Force Mode
Im Low-Power-Mode des Accelerometers schläft der Sensor für eine einstellbare Zeit zwischen den Messungen (0.5–1000 Millisekunden). Das Gyroskop besitzt eine ähnliche Funktion für den Advanced Powersave Mode (2–20 Millisekunden).
Zu beachten: Alle diese individuellen Sensoreinstellungen stehen nur in den Non-Fusion-Modi zur Verfügung. In den Fusion Modes werden die Einstellungen automatisch vorgenommen. Die Adafruit-Bibliothek hat diese Einstellungen gar nicht implementiert.
Kommunikation
Die Kommunikation mit dem Mikrocontroller ist per I²C oder UART möglich. Allerdings habe ich keine Arduino- bzw. C++-Bibliothek gefunden, die die Ansteuerung per UART implementiert hat. Bezüglich I²C ist einschränkend zu bemerken, dass es mit bestimmten Mikrocontrollern oder I²C-Multiplexern Probleme geben kann (siehe hier auf den Adafruit-Seiten). Der maximale I²C-Takt ist 400 kHz.
Kalibrierung
In den Fusion-Modi kalibriert sich der BNO055 selbst, und das während des laufenden Betriebs. Der Kalibrierstatus der Sensoren wird auf einer Skala von 0 bis 3 bewertet. Je höher der Wert, desto besser die Kalibrierung und desto verlässlicher sind die Messwerte.
Bei der Kalibrierung erkennt der BNO055 Abweichungen der Soll- zu den Ist-Werten. Beispielsweise sollte das Gyroskop in Ruhelage für alle drei Achsen null ausgeben. Aber wie kann das Modul wissen, dass es sich in Ruhelage befindet? Die Antwort lautet: Wenn das Accelerometer und das Magnetometer konstante Werte liefern. Wie die Kalibrierung genau funktioniert, ist allerdings das Betriebsgeheimnis des Herstellers.
Die aus der Kalibrierung resultierenden Offsets werden in den zuständigen Offset-Registern gespeichert. Sie können dort ausgelesen und beim nächsten Start zurückgeschrieben werden, damit ihr nicht noch einmal auf die Kalibrierung warten müsst.
Außer dem Kalibrierstatus der Sensoren gibt es noch einen Systemkalibrierstatus. Dieser bezieht sich auf die Sensorfusion und ist deswegen spezifisch für den Betriebsmodus.
Interrupts
Über die Interrupts des BNO055 könnte ich problemlos einen eigenen Artikel schreiben. Stattdessen müsst ihr euch mit einem kurzen Überblick zufriedengeben. Durch die Beispielsketche werden die Dinge sicherlich noch klarer. Ansonsten schaut bitte ins Datenblatt, Kapitel 3.8.
Accelerometer-Interrupts
Für das Accelerometer könnt ihr (wenn auch nicht mit der Adafruit-Bibliothek) folgende Interrupts einstellen:
- Slow/No-Motion: Der Slow-Motion-Interrupt wird ausgelöst, wenn an mindestens einer der aktivierten Achsen eine bestimmte Steigung der Beschleunigung für eine bestimmte Anzahl an Messwerten (max. 64) überschritten wird. Der No-Motion-Interrupt wird ausgelöst, wenn an keiner der aktivierten Achsen eine Steigung der Beschleunigung oberhalb eines einstellbaren Limits über eine einstellbare Zeit (max. 336 Sekunden) hinweg registriert wird.
- Any Motion: Der Any-Motion-Interrupt ist dem Slow-Motion-Interrupt sehr ähnlich, jedoch ist er zur Detektion von kurzen Steigungsänderungen der Beschleunigung zwischen zwei Messpunkten konzipiert. Um Fehlmessungen zu vermeiden, könnt ihr festlegen, dass bis zu vier Messungen in Folge oberhalb des eingestellten Limits liegen müssen. Für weitere Details schaut bitte ins Datenblatt (Kapitel 3.8.2.2 und 3.8.2.3).
- High G: Bei diesem Interrupt ist nicht die Steigung der Beschleunigung, sondern das Überschreiten eines absoluten Beschleunigungswertes eines der beiden Auslöskriterien. Das andere Kriterium ist die einstellbare Mindestdauer der Überschreitung.
Gyroskop-Interrupts
Die Interrupts des Gyroskops sind:
- Any Motion: Der Any-Motion-Interrupt des Gyroskops funktioniert wie der Any-Motion-Interrupt des Accelerometers, nur ist hier die Steigung der Winkelgeschwindigkeit das Auslösekriterium.
- High Rate: Der High-Rate-Interrupt entspricht dem High-G-Interrupt des Accelerometers. Er wird ausgelöst, wenn ein bestimmter absoluter Wert der Winkelgeschwindigkeit für eine bestimmte Zeit überschritten wird.
Anschluss an den Mikrocontroller
Unten seht ihr ein Schaltungsbeispiel für die Ansteuerung des BNO055. Ich habe einen klassischen Arduino Nano verwendet, um zwei Dinge zu verdeutlichen: Zum einen ist bei 5-Volt-Boards ein Levelshifter Pflicht. Zum anderen möchte ich hervorheben, dass sich der BNO055 – anders als die BNO08x-Familie – auch problemlos mit einem (vergleichsweise!) kleinen Mikrocontroller betreiben lässt.

Den Interrupt-, den Boot- und den Reset-Pin habe ich unverbunden gelassen. Der Boot-Pin ist nur relevant, wenn ihr neue Firmware aufspielen wollt. Damit habe ich mich nicht beschäftigt. Den Reset-Pin könnt ihr anschließen, wenn ihr Hardware-Resets ausführen wollt. Der Anschluss ist Active-LOW. Zu den Interrupts kommen wir später.
Ansteuerung mit der Adafruit-Bibliothek
Wie schon angedeutet: Die Adafruit-Bibliothek glänzt nicht durch Vollständigkeit. Unter anderem sind Interrupts und die individuellen Sensoroptionen für die Non-Fusion-Modes nicht implementiert. Allerdings wird das viele User wahrscheinlich nicht stören, weil sie einfach nur die Sensor- und Sensorfusiondaten abrufen wollen und sich nicht mit komplexen Details oder gar dem Datenblatt beschäftigen möchten.
Eine Besonderheit der Adafruit-Bibliothek ist, dass sie zusätzlich die Bibliothek Adafruit_Sensor benötigt. Diese abstrahiert Sensoren und bietet einen gewissen Komfort. Gleichwohl entfernt ihr euch damit etwas weiter von der Hardware.
Einstieg: read_all_data.ino
Wir beginnen mit dem Bibliotheks-Beispielsketch „read_all_data.ino“. Ich habe nur zwei Anpassungen vorgenommen. Zum einen habe ich die Datenrate angepasst, weil mir die Ausgabe zu hektisch war. Zum anderen habe ich in setup() die Zeile bno.setExtCrystalUse(true); eingefügt, welche – wie der Funktionsname vermuten lässt – die Verwendung des externen Oszillators einstellt.
#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 = 1000;
// Check I2C device address and correct line below (by default address is 0x29 or 0x28)
// id, address
Adafruit_BNO055 bno = Adafruit_BNO055(55, 0x28, &Wire);
void setup(void)
{
Serial.begin(115200);
while (!Serial) delay(10); // wait for serial port to open!
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);
}
bno.setExtCrystalUse(true); // this line is not in the original example sketch
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 if (event->type == SENSOR_TYPE_GRAVITY) {
Serial.print("Gravity:");
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);
}
Hier die Ausgabe des Sketches auf dem seriellen Monitor:

Erklärungen zum read_all_data.ino
Ich werde nicht jede Zeile durchgehen. Vieles sollte selbsterklärend sein.
Mit Adafruit_BNO055 bno = Adafruit_BNO055(55, 0x28, &Wire) erzeugt ihr euer BNO055-Objekt. Ihr übergebt eine Sensor-ID, die I²C-Adresse und das TwoWire-Objekt (als Referenz). Die Sensor-ID ist ein Feature der Adafruit-Sensor-Bibliothek und frei wählbar (Datentyp: int32_t).
Mit bno.begin() initialisiert ihr euer Modul. Der Rückgabewert (bool) verrät euch, ob die Initialisierung erfolgreich war.
Die Messdaten des BNO055 werden in Strukturen vom Typ sensors_event_t gespeichert. Die Definition der Struktur findet ihr in Adafruit_Sensor.h. Ihr ruft die Messwerte mit getEvent(&xxxxxData, Adafruit_BNO055::VECTOR_XXXXX) ab, wobei xxxxx bzw. XXXXX für den jeweiligen Sensor oder die Sensorfusion steht. Eine Ausnahme ist die Temperatur, die ihr mit bno.getTemp() abfragt.
Die Messdaten gebt ihr mit printEvent(&xxxxxData) aus. Die Funktion erkennt anhand des übergebenen Event-Typs, von welchem Sensor die Daten stammen bzw. ob es sich um berechnete Sensorfusionswerte handelt. Da das Event als Referenz an printEvent() übergeben wird, müsst ihr, wenn ihr auf die jeweiligen Achsenwerte zugreifen wollt, den Pfeil- anstelle des Punktoperators verwenden. Also zum Beispiel z = event->orientation.z.
Übrigens sind die „Events“ hier ein Konzept der Adafruit_Sensor-Bibliothek. Das hat nichts mit dem Event-Konzept zu tun, das ihr vielleicht vom BNO08x her kennt.
Kalibrierung
Der Sketch gibt neben den Messdaten auch den Kalibrierstatus aus. Wenn ihr den BNO055 neu startet oder resettet, dann werdet ihr sehen, dass zunächst alle Kalibrierstatuswerte null sind. Der Kalibrierstatus des Gyroskops wechselt rasch auf 3. Für die Kalibrierung des Magnetometers muss man den BNO055 ein wenig um die Achsen drehen. Im NDOF-Modus geht das schnell, in den anderen Modi dauert es etwas. Am längsten dauert die Kalibrierung des Accelerometers. Das Datenblatt empfiehlt, den BNO055 in 6 verschiedenen Ausrichtungen für ein paar Sekunden still zu platzieren.
Weitere Einstellungen und Funktionen
Die Adafruit-Bibliothek bietet weitere Einstellungsoptionen und Funktionen, für die es zum Teil eigene Beispielsketche gibt.
Einstellen des Fusion- oder Non-Fusion-Modus
Beim Sketch read_all_data.ino greift die Voreinstellung, nämlich der NDOF-Modus. Es gibt zwei Wege, den Modus zu ändern. Ihr übergebt den Modus an:
- die Funktion
begin() - oder an
setMode()
Den Namen des Parameters für den von euch gewählten Modus könnt ihr der Tabelle weiter oben entnehmen.
Abfragen und Setzen der Kalibrierwerte
Wie ihr gesehen habt, nimmt die Kalibrierung eine gewisse Zeit in Anspruch. Um bei einem Reset oder Neustart Zeit zu sparen, könnt ihr die Offsets mit getSensorOffsets() abfragen, im EEPROM (falls verfügbar) speichern und nach dem Reset oder Neustart mit setSensorOffsets() wieder zurückschreiben. In diesem Zusammenhang ist auch die Funktion isFullyCalibrated() sehr nützlich. Sie prüft modusabhängig, ob die verwendeten Sensoren den Kalibrierstatus 3 haben.
Ich gehe nicht näher darauf ein, da es dazu den Beispielsketch restore_offsets.ino gibt, der den Gebrauch dieser Funktionen veranschaulicht.
System Status / Sensor-Informationen
Der Beispielsketch sensor_api.ino liefert euch einige Informationen über den Sensor aus der Adafruit Sensor Bibliothek wie etwa den Sensornamen und die von euch vergebene ID. Überdies liefert der Sketch Informationen über den Systemstatus, das Ergebnis des Selbsttests und eventuelle Systemfehler:

Der „System Status“ ist der Inhalt des Systemstatusregisters. Wie die Zahl zu interpretieren ist, findet ihr im Datenblatt in Kapitel 4.3.58.
Die Angabe „Self Test“ ist der Inhalt des Self-Test-Registers (siehe Kapitel 4.3.55). Dabei bedeutet eine 1 Erfolg, eine 0 bedeutet Fehler.
- Bit0 steht für das Accelerometer
- Bit1 steht für das Magnetometer
- Bit3 steht für das Gyroskop
- Bit4 steht für den Mikrocontroller des BNO055
Beispiel: Self-Test-Register ist 0xF = 0b1111 ⇒ alles ist i.O.
Der „System Error“ ist der Inhalt des System Error Registers. Die „Übersetzung“ findet ihr im Datenblatt in Kapitel 4.3.59. Erhaltet ihr 0x0, dann ist alles OK.
Achsenzuordnung ändern
Um die Zuordnung der Achsen zu ändern, also etwa die x- mit der z-Achse zu tauschen, steht euch die Funktion setAxisRemap(REMAP_CONFIG_Px) zur Verfügung. Dabei ist x ein Zahl zwischen 0 und 7 und steht für eine bestimmte Einbausituation des Sensors. Ihr findet dazu schematische Darstellungen im Datenblatt in Kapitel 3.4.
Falls euch die Varianten nicht ausreichen, dann könnt ihr den passenden Parameter für setAxisMap() auch selbst erstellen. Dazu schauen wir uns das Register AXIS_MAP_CONFIG an, welches durch die Funktion beschrieben wird:

Der Reset-Wert ist 0b100100 = 0x24. Um die z-Achse zur x-Achse zu machen, schreibt ihr 0b00 (repräsentiert die x-Achse) in die Bits 4 und 5. Damit die x-Achse zur z-Achse wird, schreibt ihr 0xb10 (repräsentiert die z-Achse) in die Bits 0 und 1. Der Registerinhalt ist dann 0b000110 = 0x6, also würde euer Funktionsaufruf setAxisRemap(0x6) lauten. Ich habe festgestellt, dass setAxisRemap() nicht an jeder beliebigen Stelle aufgerufen werden darf. Verwendet Funktion am besten direkt nach bno.begin().
Achsenvorzeichen ändern
Vielleicht habt ihr den BNO055 so eingebaut, dass die z-Achse nach unten zeigt? Je nachdem, ob ihr ihn um die x- oder die y-Achse gedreht habt, ist dann das Vorzeichen der z- und der x-Achse oder der z- und der y-Achse umgedreht. Die Vorzeichen könnt ihr mit setAxisSign(REMAP_SIGN_Px) leicht ändern. Dabei stehen P0 bis P7 wieder für die eben genannten Einbausituationen.
Alternativ errechnet ihr den Parameter selbst. Die Funktion beschreibt das AXIS_MAP_SIGN-Register:

Der Default-Wert ist 0. Um das z-Achsen-Vorzeichen umzudrehen, muss Bit0 eins sein, also setAxisSign(0x1). Wenn ihr die z- und die x-Achse drehen wollt, dann schreibt ihr 0b101 = 0x5 in das Register, also setAxisSign(0x5). Nehmt auch diese Einstellung am besten direkt nach bno.begin() vor.
Raw Data
Wenn ihr das Adafruit Unified Sensor-System nicht verwenden möchtet, dann könnt ihr die sogenannten Rohdaten-Hilfsfunktionen verwenden. Ein Grund dafür könnte sein, dass ihr direkt auf die Rohdaten des Beschleunigungsmessers, Magnetometers oder Gyroskops zugreifen möchtet, bevor diese von den Sensorfusionsalgorithmen verarbeitet werden. Wie das geht, zeigt der Beispielsketch rawdata.ino. Weitere Informationen findet ihr hier auf den Adafruit-Seiten.
Suspend-Modus
Wenn ihr Strom sparen wollt, dann bringt euch enterSuspendMode() in den Suspend-Modus. Dabei werden sowohl die Sensoren als auch der Mikrocontroller in den Schlafmodus versetzt. Mit enterNormalModus() kommt ihr wieder zurück in den normalen Modus. Wie schon erwähnt, ist der Low-Power-Modus leider nicht implementiert, obwohl dieser eigentlich sehr sinnvoll ist. Im Low-Power-Modus geht der BNO055 nach einer gewissen Zeit ohne Aktivität (Voreinstellung ist 5 Sekunden) in einen energiesparenden Zustand, in dem lediglich das Accelerometer aktiv ist. Registriert das Accelerometer Aktivität, geht der BNO055 bis zur nächsten aktivitätslosen Phase wieder in den normalen Modus.
Ansteuerung mit der DFRobot-Bibliothek
Die Adafruit-Bibliothek wird die Bedürfnisse vieler User wahrscheinlich befriedigen. Wie auch immer, sie deckt das Potenzial des BNO055 nicht voll ab. Sehr viel vollständiger, aber dafür auch komplexer, ist die Bibliothek DFRobot_BNO055.
Leider könnt ihr die Bibliothek nicht über den Bibliotheks-Manager der Arduino-IDE installieren. Stattdessen folgt dem obigen Link, klickt auf den grünen Button „<> Code“, dann „Download ZIP“. Speichert die Datei und entzippt sie in eurem Ordner Arduino/libraries. Ihr solltet dann einen Unterordner „DFRobot_BNO055-master“ sehen, in dem sich die Bibliotheksdateien befinden. Danach findet ihr die Beispielsketche über die Arduino IDE unter Datei → Beispiele → DFRobot_BNO055-master.
Einstieg – readData.ino
/*!
* read_data.ino
*
* Download this demo to test read data from bno055
* Data will print on your serial monitor
*
* Product: http://www.dfrobot.com.cn/goods-1860.html
* Copyright [DFRobot](http://www.dfrobot.com), 2016
* Copyright GNU Lesser General Public License
*
* version V1.0
* date 07/03/2019
*/
#include "DFRobot_BNO055.h"
#include "Wire.h"
typedef DFRobot_BNO055_IIC BNO; // ******** use abbreviations instead of full names ********
BNO bno(&Wire, 0x28); // input TwoWire interface and IIC address
// show last sensor operate status
void printLastOperateStatus(BNO::eStatus_t eStatus)
{
switch(eStatus) {
case BNO::eStatusOK: Serial.println("everything ok"); break;
case BNO::eStatusErr: Serial.println("unknow error"); break;
case BNO::eStatusErrDeviceNotDetect: Serial.println("device not detected"); break;
case BNO::eStatusErrDeviceReadyTimeOut: Serial.println("device ready time out"); break;
case BNO::eStatusErrDeviceStatus: Serial.println("device internal status error"); break;
default: Serial.println("unknow status"); break;
}
}
void setup()
{
Serial.begin(115200);
bno.reset(); // resets the BNO055
while(bno.begin() != BNO::eStatusOK) {
Serial.println("bno begin failed");
printLastOperateStatus(bno.lastOperateStatus);
delay(2000);
}
Serial.println("bno begin success");
}
#define printAxisData(sAxis) \
Serial.print(" x: "); \
Serial.print(sAxis.x); \
Serial.print(" y: "); \
Serial.print(sAxis.y); \
Serial.print(" z: "); \
Serial.println(sAxis.z)
void loop()
{
BNO::sAxisAnalog_t sAccAnalog, sMagAnalog, sGyrAnalog, sLiaAnalog, sGrvAnalog;
BNO::sEulAnalog_t sEulAnalog;
BNO::sQuaAnalog_t sQuaAnalog;
sAccAnalog = bno.getAxis(BNO::eAxisAcc); // read acceleration
sMagAnalog = bno.getAxis(BNO::eAxisMag); // read geomagnetic
sGyrAnalog = bno.getAxis(BNO::eAxisGyr); // read gyroscope
sLiaAnalog = bno.getAxis(BNO::eAxisLia); // read linear acceleration
sGrvAnalog = bno.getAxis(BNO::eAxisGrv); // read gravity vector
sEulAnalog = bno.getEul(); // read euler angle
sQuaAnalog = bno.getQua(); // read quaternion
Serial.println();
Serial.println("======== analog data print start ========");
Serial.print("acc analog: (unit mg) "); printAxisData(sAccAnalog);
Serial.print("mag analog: (unit ut) "); printAxisData(sMagAnalog);
Serial.print("gyr analog: (unit dps) "); printAxisData(sGyrAnalog);
Serial.print("lia analog: (unit mg) "); printAxisData(sLiaAnalog);
Serial.print("grv analog: (unit mg) "); printAxisData(sGrvAnalog);
Serial.print("eul analog: (unit degree) "); Serial.print(" head: "); Serial.print(sEulAnalog.head); Serial.print(" roll: "); Serial.print(sEulAnalog.roll); Serial.print(" pitch: "); Serial.println(sEulAnalog.pitch);
Serial.print("qua analog: (no unit) "); Serial.print(" w: "); Serial.print(sQuaAnalog.w); printAxisData(sQuaAnalog);
Serial.println("======== analog data print end ========");
delay(1000);
}
Die Zeile typedef DFRobot_BNO055_IIC BNO; dient lediglich der Bequemlichkeit. Sie ermöglicht es, „BNO“ anstelle des langen Bibliotheksnamens „DFRobot_BNO055_IIC“ zu verwenden. Mit BNO bno(&Wire, 0x28); erzeugt ihr euer BNO055-Objekt und übergebt ihm das I²C-Objekt Wire und die I²C-Adresse.
while(bno.begin() != BNO::eStatusOK) versucht, den BNO055 zu initialisieren, bis er zurückmeldet, dass alles OK ist. Für Anfänger ist die Schreibweise mit dem doppelten Doppelpunkt vielleicht nicht so geläufig. eStatusOK ist im Enum eStatus_t in DFRobot_BNO055.h definiert. Da die Enum-Definition innerhalb der Klasse erfolgt, müsst ihr den Klassennamen mit dem doppelten Doppelpunkt voranstellen. Der Nachteil ist Schreibarbeit, der Vorteil ist Schutz vor Namenskollisionen.
Die Messwerte werden in Strukturen vom Typ sAxisAnalog_t, sEulAnalog_t und sQuaAnalog_t gespeichert. Auch diese Definitionen findet ihr in DFRobot_BNO055.h. x-, y- und z-Werte werden mit getAxis() abgefragt. Da die Funktion für verschiedene Messwerte zuständig ist, müsst ihr noch den Typ übergeben, also z. B. BNO::eAxisAcc für das Accelerometer. getEul() und getQua() hingegen sind eindeutig.
Will man eine Ausgabefunktion für die Messwerte schreiben, ergibt sich hier auch das Problem, dass sie unterschiedliche Wertetypen (sAccAnalog, sMagAnalog etc.) entgegennehmen muss. In readData.ino wird das Problem mit einem #define-Makro (Probleme damit? Siehe hier) gelöst.
Der Rest sollte klar sein, oder? Hier noch die Ausgabe:

Sketche um Funktionen erweitern
Falls ihr die Beispielsketche um Funktionen erweitern wollt, die in Beispielsketchen nicht beschrieben sind, dann kommt ihr nicht umhin, ein wenig in DFRobot_BNO055.h zu wühlen. Zum einen braucht ihr die Funktionsnamen, zum anderen braucht ihr in vielen Fällen den Datentyp, der übergeben oder zurückgegeben wird.
In der folgenden, modifizierten Version des Sketches readData.ino zeige ich das am Beispiel des Kalibrierstatus. Die Funktion ist getCalStatus() und der Rückgabewert ist eine Struktur vom Typ sRegCalibState.
/*!
* read_data.ino
*
* Download this demo to test read data from bno055
* Data will print on your serial monitor
*
* Product: http://www.dfrobot.com.cn/goods-1860.html
* Copyright [DFRobot](http://www.dfrobot.com), 2016
* Copyright GNU Lesser General Public License
*
* version V1.0
* date 07/03/2019
* modified by Wolfgang Ewald 07/02/2026
*/
#include "DFRobot_BNO055.h"
#include "Wire.h"
typedef DFRobot_BNO055_IIC BNO; // ******** use abbreviations instead of full names ********
BNO bno(&Wire, 0x28); // input TwoWire interface and IIC address
// show last sensor operate status
void printLastOperateStatus(BNO::eStatus_t eStatus)
{
switch(eStatus) {
case BNO::eStatusOK: Serial.println("everything ok"); break;
case BNO::eStatusErr: Serial.println("unknow error"); break;
case BNO::eStatusErrDeviceNotDetect: Serial.println("device not detected"); break;
case BNO::eStatusErrDeviceReadyTimeOut: Serial.println("device ready time out"); break;
case BNO::eStatusErrDeviceStatus: Serial.println("device internal status error"); break;
default: Serial.println("unknow status"); break;
}
}
void setup()
{
Serial.begin(115200);
bno.reset();
delay(1000); // give time to reset and avoid "device not detected"
while(bno.begin() != BNO::eStatusOK) {
Serial.println("bno begin failed");
printLastOperateStatus(bno.lastOperateStatus);
delay(2000);
}
Serial.println("bno begin success");
}
#define printAxisData(sAxis) \
Serial.print(" x: "); \
Serial.print(sAxis.x); \
Serial.print(" y: "); \
Serial.print(sAxis.y); \
Serial.print(" z: "); \
Serial.println(sAxis.z)
void loop()
{
BNO::sAxisAnalog_t sAccAnalog, sMagAnalog, sGyrAnalog, sLiaAnalog, sGrvAnalog;
BNO::sEulAnalog_t sEulAnalog;
BNO::sQuaAnalog_t sQuaAnalog;
BNO::sRegCalibState_t sCalibState;
sAccAnalog = bno.getAxis(BNO::eAxisAcc); // read acceleration
sMagAnalog = bno.getAxis(BNO::eAxisMag); // read geomagnetic
sGyrAnalog = bno.getAxis(BNO::eAxisGyr); // read gyroscope
sLiaAnalog = bno.getAxis(BNO::eAxisLia); // read linear acceleration
sGrvAnalog = bno.getAxis(BNO::eAxisGrv); // read gravity vector
sEulAnalog = bno.getEul(); // read euler angle
sQuaAnalog = bno.getQua(); // read quaternion
sCalibState = bno.getCalStatus(); // read calibration status
Serial.println();
Serial.println("======== analog data print start ========");
Serial.print("acc analog: (unit mg) "); printAxisData(sAccAnalog);
Serial.print("mag analog: (unit ut) "); printAxisData(sMagAnalog);
Serial.print("gyr analog: (unit dps) "); printAxisData(sGyrAnalog);
Serial.print("lia analog: (unit mg) "); printAxisData(sLiaAnalog);
Serial.print("grv analog: (unit mg) "); printAxisData(sGrvAnalog);
Serial.print("eul analog: (unit degree) "); Serial.print(" head: "); Serial.print(sEulAnalog.head); Serial.print(" roll: "); Serial.print(sEulAnalog.roll); Serial.print(" pitch: "); Serial.println(sEulAnalog.pitch);
Serial.print("qua analog: (no unit) "); Serial.print(" w: "); Serial.print(sQuaAnalog.w); printAxisData(sQuaAnalog);
Serial.print("Calibration Status: ");
Serial.print(" SYS: "); Serial.print(sCalibState.SYS);
Serial.print(" ACC: "); Serial.print(sCalibState.ACC);
Serial.print(" GYR: "); Serial.print(sCalibState.GYR);
Serial.print(" MAG: "); Serial.println(sCalibState.MAG);
Serial.println("======== analog data printend ========");
delay(1000);
}
Hier die Ausgabe dazu:

Erweiterte Konfiguration
Der Beispielsketch config.ino bzw. meine leicht modifizierte Version config_mod.ino zeigen, wie ihr einige individuelle Einstellungen für die Achsen vornehmt und wie ihr Offsets manuell setzt. Die möglichen Einstellparameter findet ihr in DFRobot_BNO055.h.
Auch wenn ich mich wiederhole: Diese Einstellungen lassen sich nur in den Nicht-Fusion-Modi vornehmen. Die Originalversion des Beispielsketches stellt den NDOF-Modus ein, was veränderte Einstellungen wirkungslos macht.
/*!
* config.ino
*
* Download this demo to test config to bno055
* Data will print on your serial monitor
*
* Product: http://www.dfrobot.com.cn/goods-1860.html
* Copyright [DFRobot](http://www.dfrobot.com), 2016
* Copyright GNU Lesser General Public License
*
* version V1.0
* date 07/03/2019
* modified by Wolfgang Ewald 12/02/2026
*/
#include "DFRobot_BNO055.h"
#include "Wire.h"
typedef DFRobot_BNO055_IIC BNO; // ******** use abbreviations instead of full names ********
BNO bno(&Wire, 0x28); // input TwoWire interface and IIC address
// show last sensor operate status
void printLastOperateStatus(BNO::eStatus_t eStatus)
{
switch(eStatus) {
case BNO::eStatusOK: Serial.println("everything ok"); break;
case BNO::eStatusErr: Serial.println("unknow error"); break;
case BNO::eStatusErrDeviceNotDetect: Serial.println("device not detected"); break;
case BNO::eStatusErrDeviceReadyTimeOut: Serial.println("device ready time out"); break;
case BNO::eStatusErrDeviceStatus: Serial.println("device internal status error"); break;
default: Serial.println("unknow status"); break;
}
}
void setup()
{
Serial.begin(115200);
bno.reset();
while(bno.begin() != BNO::eStatusOK) {
Serial.println("bno begin faild");
printLastOperateStatus(bno.lastOperateStatus);
delay(2000);
}
Serial.println("bno begin success");
bno.setPowerMode(BNO::ePowerModeNormal); // set to normal power mode
bno.setOprMode(BNO::eOprModeConfig); // must set sensor to config-mode before configure
bno.setAccPowerMode(BNO::eAccPowerModeNormal); // set acc to normal power mode
bno.setGyrPowerMode(BNO::eGyrPowerModeNormal); // set gyr to normal power mode
bno.setMagPowerMode(BNO::eMagPowerModeForce); // set mag to force power mode
// accelerometer normal configure
bno.setAccRange(BNO::eAccRange_2G); // set range to 2g
bno.setAccBandWidth(BNO::eAccBandWidth_62_5); // set band width 62.5HZ
bno.setAccPowerMode(BNO::eAccPowerModeNormal); // set accelerometer power mode
// magnetometer normal configure
bno.setMagDataRate(BNO::eMagDataRate_20); // set output data rate 20HZ
bno.setMagPowerMode(BNO::eMagPowerModeForce); // set power mode
bno.setMagOprMode(BNO::eMagOprModeRegular); // set operate mode
// gyroscope normal configure
bno.setGyrRange(BNO::eGyrRange_125); // set range
bno.setGyrBandWidth(BNO::eGyrBandWidth_32); // set band width
bno.setGyrPowerMode(BNO::eGyrPowerModeNormal); // set power mode
BNO::sAxisAnalog_t sOffsetAcc; // unit mg, members can't out of acc range
BNO::sAxisAnalog_t sOffsetMag; // unit ut, members can't out of mag range
BNO::sAxisAnalog_t sOffsetGyr; // unit dps, members can't out of gyr range
sOffsetAcc.x = 1;
sOffsetAcc.y = 1;
sOffsetAcc.z = 1;
sOffsetMag.x = 1;
sOffsetMag.y = 1;
sOffsetMag.z = 1;
sOffsetGyr.x = 1;
sOffsetGyr.y = 1;
sOffsetGyr.z = 1;
bno.setAxisOffset(BNO::eAxisAcc, sOffsetAcc); // set offset
bno.setAxisOffset(BNO::eAxisMag, sOffsetMag);
bno.setAxisOffset(BNO::eAxisGyr, sOffsetGyr);
bno.setOprMode(BNO::eOprModeAMG); // shift a non-fusion mode
}
#define printAxisData(sAxis) \
Serial.print(" x: "); \
Serial.print(sAxis.x); \
Serial.print(" y: "); \
Serial.print(sAxis.y); \
Serial.print(" z: "); \
Serial.println(sAxis.z)
void loop()
{
BNO::sAxisAnalog_t sAccAnalog, sMagAnalog, sGyrAnalog;
sAccAnalog = bno.getAxis(BNO::eAxisAcc);
sMagAnalog = bno.getAxis(BNO::eAxisMag);
sGyrAnalog = bno.getAxis(BNO::eAxisGyr);
Serial.println();
Serial.println("======== analog data print start ========");
Serial.print("acc analog: (unit mg) "); printAxisData(sAccAnalog);
Serial.print("mag analog: (unit ut) "); printAxisData(sMagAnalog);
Serial.print("gyr analog: (unit dps) "); printAxisData(sGyrAnalog);
Serial.println("======== analog data print end ========");
delay(1000);
}
Interrupts
Die Interrupts des BNO055 sind ein ziemlich komplexes Thema. Hier zunächst der von mir geringfügig modifizierte Beispielsketch interrupt.ino:
/*!
* interrupt.ino
*
* Download this demo to test bno055 interrupt
* Connect bno055 int pin to arduino pin 2
* If there occurs interrupt, it will printr on you serial monitor, more detail please reference comment
*
* Product: http://www.dfrobot.com.cn/goods-1860.html
* Copyright [DFRobot](http://www.dfrobot.com), 2016
* Copyright GNU Lesser General Public License
*
* version V1.0
* date 07/03/2019
*/
#include "DFRobot_BNO055.h"
#include "Wire.h"
typedef DFRobot_BNO055_IIC BNO; // ******** use abbreviations instead of full names ********
BNO bno(&Wire, 0x28); // input TwoWire interface and IIC address
// show last sensor operate status
void printLastOperateStatus(BNO::eStatus_t eStatus)
{
switch(eStatus) {
case BNO::eStatusOK: Serial.println("everything ok"); break;
case BNO::eStatusErr: Serial.println("unknow error"); break;
case BNO::eStatusErrDeviceNotDetect: Serial.println("device not detected"); break;
case BNO::eStatusErrDeviceReadyTimeOut: Serial.println("device ready time out"); break;
case BNO::eStatusErrDeviceStatus: Serial.println("device internal status error"); break;
default: Serial.println("unknow status"); break;
}
}
bool intFlag = false;
void intHandle()
{
intFlag = true;
}
void setup()
{
Serial.begin(115200);
bno.reset();
while(bno.begin() != BNO::eStatusOK) {
Serial.println("bno begin faild");
printLastOperateStatus(bno.lastOperateStatus);
delay(2000);
}
Serial.println("bno begin success");
bno.setOprMode(BNO::eOprModeConfig); // set to config mode
bno.setIntMaskEnable(BNO::eIntAll); // set interrupt mask enable, signal to int pin when interrupt
// bno.setIntMaskDisable(BNO::eIntAccAm | BNO::eIntAccNm); // set interrupt mask disable, no signal to int pin when interrupt
bno.setIntEnable(BNO::eIntAll); // set interrupt enable
// bno.setIntDisable(BNO::eIntAccAm | BNO::eIntAccNm); // set interrupt disable
bno.setAccIntEnable(BNO::eAccIntSetAll); // set accelerometer interrupt enable
// bno.setAccIntDisable(BNO::eAccIntSetAmnmXAxis | BNO::eAccIntSetHgXAxis); // set accelerometer interrupt disable
/* accelerometer any motion threshold to set, unit mg, value is dependent on accelerometer range selected,
* case 2g, no more than 1991
* case 4g, no more than 3985
* case 8g, no more than 7968
* case 16g, no more than 15937
* attenion: The set value will be slightly biased according to datasheet
* tips: default accelerometer range is 4g
*/
// how to trig this: still --> fast move
bno.setAccAmThres(100);
// any motion interrupt triggers if duration consecutive data points are above the any motion interrupt
// threshold define in any motion threshold
bno.setAccIntAmDur(1);
// set high-g duration, value from 2ms to 512ms
bno.setAccHighGDuration(80);
/*
* accelerometer high-g threshold to set, unit mg, value is dependent on accelerometer range selected,
* case 2g, no more than 1991
* case 4g, no more than 3985
* case 8g, no more than 7968
* case 16g, no more than 15937
* Attenion: The set value will be slightly biased according to datasheet
*/
// how to trig this: still --> (very) fast move
bno.setAccHighGThres(650); // comment Wolfgang: due to a bug the effective value is double the parameter.
// accelerometer (no motion) / (slow motion) settings, 2nd parameter unit seconds, no more than 336
bno.setAccNmSet(BNO::eAccNmSmnmNm, 4); // better name would be setAccNmSmSet() for no and slow motion
/*
* accelerometer no motion threshold to set, unit mg, value is dependent on accelerometer range selected,
* case 2g, no more than 1991
* case 4g, no more than 3985
* case 8g, no more than 7968
* case 16g, no more than 15937
* Attenion: The set value will be slightly biased according to datasheet
*/
// hot to trig this: any motion --> still --> still
bno.setAccNmThres(100);
bno.setGyrIntEnable((BNO::eGyrIntSet_t) (BNO::eGyrIntSetHrXAxis | BNO::eGyrIntSetHrYAxis | BNO::eGyrIntSetHrZAxis)); // set gyroscope interrupt enable, in most cases, this is enough.
// bno.setGyrIntEnable(BNO::eGyrIntSetAmYAxis | BNO::eGyrIntSetAmYAxis | BNO::eGyrIntSetAmZAxis); // set gyroscope interrupt enable
// bno.setGyrIntDisable(BNO::eGyrIntSetHrXAxis | BNO::eGyrIntSetAmXAxis); // set gyroscope interrupt disable
/*
* 2nd parameter, high rate threshold to set, unit degree/seconds, value is dependent on gyroscope range selected,
* case 2000, no more than 1937
* case 1000, no more than 968
* case 500, no more than 484
* case 250, no more than 242
* case 125, no more than 121
* Attenion: The set value will be slightly biased according to datasheet
* 3rd parameter, high rate duration to set, unit ms, duration from 2.5ms to 640ms
* Attenion: The set value will be slightly biased according to datasheet
*/
// how to trigger this: still --> fast tilt
bno.setGyrHrSet(BNO::eSingleAxisX, 300, 80);
bno.setGyrHrSet(BNO::eSingleAxisY, 300, 80);
bno.setGyrHrSet(BNO::eSingleAxisZ, 300, 80);
/*
* gyroscope any motion threshold to set, unit mg, value is dependent on accelerometer range selected,
* case 2000, no more than 128
* case 1000, no more than 64
* case 500, no more than 32
* case 250, no more than 16
* case 125, no more than 8
* Attenion: The set value will be slightly biased according to datasheet
* tips: default range is 2000
*/
// how to trigger this: still --> fast tilt
bno.setGyrAmThres(20);
bno.setOprMode(BNO::eOprModeNdof); // configure done
attachInterrupt(digitalPinToInterrupt(2), intHandle, RISING); // attach interrupt
bno.getIntState(); // clear unexpected interrupt
intFlag = false;
}
void loop()
{
if(intFlag) {
intFlag = false;
uint8_t intSta = bno.getIntState(); // interrupt auto clear after read
Serial.println("interrupt detected");
if(intSta & BNO::eIntAccAm)
Serial.println("accelerometer any motion detected");
if(intSta & BNO::eIntAccNm)
Serial.println("accelerometer no motion detected");
if(intSta & BNO::eIntAccHighG)
Serial.println("acceleromter high-g detected");
if(intSta & BNO::eIntGyrHighRate)
Serial.println("gyroscope high rate detected");
if(intSta & BNO::eIntGyrAm)
Serial.println("gyroscope any motion detected");
}
}
Ich empfehle, den Sketch hochzuladen und ein wenig mit dem Modul herumzuspielen. So oder ähnlich könnte die Ausgabe aussehen:

Um Interrupts zu konfigurieren, müsst ihr den BNO055 zunächst in den Konfigurationsmodus versetzen.
Aktivierung
Mit setIntMaskEnable() und setIntMaskDisable() solltet ihr einstellen können, welche Interrupts an den Interruptpin weitergegeben werden. Ich habe allerdings die Erfahrung gemacht, dass alle aktivierten Interrupts an den Pin weitergeleitet werden, sofern mindestens ein Interrupt für den Interruptpin eingestellt ist. Auch wenn kein Interrupt an den Interruptpin weitergegeben wird, werden die aktivierten Interrupts immer noch ausgelöst, allerdings werden lediglich die entsprechenden Interruptflags gesetzt.
Die eigentliche (De-)Aktivierung der Interrupts erfolgt mit der Funktion setIntEnable() bzw. setIntDisable(), was einwandfrei funktioniert. Die möglichen Parameter sind:
- eIntGyrAm: Any Motion für das Gyroskop
- eIntGyrHighRate: High Rate für das Gyroskop
- eIntAccHighG: High G für das Accelerometer
- eIntAccAm: Any Motion für das Accelerometer
- eIntAccNm: No Motion für das Accelerometer
- eIntAll: Alle Interrupts
Die Parameter können über das logische Oder (|) auch kombiniert werden.
Mithilfe von setAccIntEnable() bzw. bno.setAccIntDisable() legt ihr fest, welche Achsen die Interrupts auslösen. Entsprechende Funktionen stehen auch für das Gyroskop zur Verfügung.
Ihr könnt entweder den No-Motion- oder den Slow-Motion-Interrupt einstellen, nicht beide. Das macht ihr mit der Funktion setAccNmSet(), der ihr entweder eAccNmSmnmNm oder eAccNmSmnmSm übergebt.
Interruptbedingungen
Interrupts werden ausgelöst, wenn Messwerte oder Steigungen der Messwerte Grenzwerte für eine bestimmte Zeit oder eine bestimmte Anzahl an Messwerten über- oder unterschreiten. Die Parameter der folgenden Funktionen legen fest:
setAccAmThres(): Limit für die Steigung der Beschleunigungswerte. Der Wert ist eigentlich rangeabhängig, aber die Bibliothek skaliert ihn im Hintergrund.setAccHighGThres(): Limit für die Steigung der Winkelgeschwindigkeiten. Auch dieser Wert ist eigentlich rangeabhängig. Die Bibliothek skaliert das Limit im Hintergrund, allerdings ist da noch ein Bug. Um ihn auszugleichen, übergebt den gewünschten Wert geteilt durch 2.setAccNmThres(): Das ist das Steigungslimit für den No-/Slow-Motion-Interrupt. Was die Sache kompliziert macht, ist, dass die Zeit zwischen zwei Messpunkten von der Bandbreite abhängt.setGyrAmThres(): Ist das Pendant zusetAccAmThres().setAccNmSet(): Die Funktion kennen wir von oben. Ihr zweiter Parameter hat je nach Einstellung zwei unterschiedliche Bedeutungen:- No-Motion-Mode: Zeit in Sekunden, die das Limit unterschritten werden muss (max. 336).
- Slow-Motion-Mode: Anzahl der Steigungswerte, die überschritten werden müssen. Das ist in der Bibliothek (derzeit) allerdings nicht richtig implementiert.
setGyrHrSet(): Parameter 1 legt die Achse fest, Parameter 2 ist das Limit als absoluter Wert, Parameter 3 ist die Dauer in Millisekunden.setAccIntAmDur(): Mindestanzahl der aufeinanderfolgenden Datenpunkte, die das Limit überschreiten, bevor der Interrupt ausgelöst wird.setAccHighGDuration(): Dauer der Überschreitung des Limits in Millisekunden, bevor ein Interrupt ausgelöst wird.
Na, seid ihr verwirrt? Ich war es jedenfalls. Ich habe selten so einen Mischmasch von Parametern zur Interrupteinstellung gesehen. Die Bibliothek kann da nichts für.
Low-Power-Mode
Kommen wir zu etwas Einfacherem, dem Low-Power-Mode. Das ist derselbe Sketch wie readData_mod.ino, allerdings erweitert um die Zeilen 32 bis 37.
#include "DFRobot_BNO055.h"
#include "Wire.h"
typedef DFRobot_BNO055_IIC BNO; // ******** use abbreviations instead of full names ********
BNO bno(&Wire, 0x28); // input TwoWire interface and IIC address
// show last sensor operate status
void printLastOperateStatus(BNO::eStatus_t eStatus)
{
switch(eStatus) {
case BNO::eStatusOK: Serial.println("everything ok"); break;
case BNO::eStatusErr: Serial.println("unknow error"); break;
case BNO::eStatusErrDeviceNotDetect: Serial.println("device not detected"); break;
case BNO::eStatusErrDeviceReadyTimeOut: Serial.println("device ready time out"); break;
case BNO::eStatusErrDeviceStatus: Serial.println("device internal status error"); break;
default: Serial.println("unknow status"); break;
}
}
void setup()
{
Serial.begin(115200);
bno.reset();
delay(1000);
while(bno.begin() != BNO::eStatusOK) {
Serial.println("bno begin faild");
printLastOperateStatus(bno.lastOperateStatus);
delay(2000);
}
Serial.println("bno begin success");
bno.setOprMode(BNO::eOprModeConfig);
// bno.setAccAmThres(500); // relvant for wakeup
// bno.setAccIntAmDur(1); // relevant for wakeup
// bno.setAccNmThres(100); // relevant for entering low power mode
// bno.setAccNmSet(BNO::eAccNmSmnmNm, 4); // relevant for entering low power mode
bno.setPowerMode(BNO::ePowerModeLowPower);
bno.setOprMode(BNO::eOprModeNdof);
}
#define printAxisData(sAxis) \
Serial.print(" x: "); \
Serial.print(sAxis.x); \
Serial.print(" y: "); \
Serial.print(sAxis.y); \
Serial.print(" z: "); \
Serial.println(sAxis.z)
void loop()
{
BNO::sAxisAnalog_t sAccAnalog, sMagAnalog, sGyrAnalog, sLiaAnalog, sGrvAnalog;
BNO::sEulAnalog_t sEulAnalog;
BNO::sQuaAnalog_t sQuaAnalog;
BNO::sRegCalibState_t sCalibState;
sAccAnalog = bno.getAxis(BNO::eAxisAcc); // read acceleration
sMagAnalog = bno.getAxis(BNO::eAxisMag); // read geomagnetic
sGyrAnalog = bno.getAxis(BNO::eAxisGyr); // read gyroscope
sLiaAnalog = bno.getAxis(BNO::eAxisLia); // read linear acceleration
sGrvAnalog = bno.getAxis(BNO::eAxisGrv); // read gravity vector
sEulAnalog = bno.getEul(); // read euler angle
sQuaAnalog = bno.getQua(); // read quaternion
sCalibState = bno.getCalStatus(); // read calibration status
Serial.println();
Serial.println("======== analog data print start ========");
Serial.print("acc analog: (unit mg) "); printAxisData(sAccAnalog);
Serial.print("mag analog: (unit ut) "); printAxisData(sMagAnalog);
Serial.print("gyr analog: (unit dps) "); printAxisData(sGyrAnalog);
Serial.print("lia analog: (unit mg) "); printAxisData(sLiaAnalog);
Serial.print("grv analog: (unit mg) "); printAxisData(sGrvAnalog);
Serial.print("eul analog: (unit degree) "); Serial.print(" head: "); Serial.print(sEulAnalog.head); Serial.print(" roll: "); Serial.print(sEulAnalog.roll); Serial.print(" pitch: "); Serial.println(sEulAnalog.pitch);
Serial.print("qua analog: (no unit) "); Serial.print(" w: "); Serial.print(sQuaAnalog.w); printAxisData(sQuaAnalog);
Serial.print("Calibration Status: ");
Serial.print(" SYS: "); Serial.print(sCalibState.SYS);
Serial.print(" ACC: "); Serial.print(sCalibState.ACC);
Serial.print(" GYR: "); Serial.print(sCalibState.GYR);
Serial.print(" MAG: "); Serial.println(sCalibState.MAG);
Serial.println("======== analog data printend ========");
delay(1000);
}
Nach ein paar Sekunden Laufzeit seht ihr, dass die Ausgabewerte eingefroren sind. Das zeigt euch, dass sich der BNO055 im Low-Power-Modus befindet. Wackelt ihr ein wenig am Modul, dann wacht es wieder auf. Die Bedingungen für das Einschlafen und Aufwachen sind dieselben wie für den No-Motion- und den Any-Motion-Interrupt. Um das zu testen, könnt ihr die Zeilen 33 bis 36 entkommentieren und mit den Parametern spielen.
Weiteres
Das Achsen-Remapping und die Einstellung der Achsen-Vorzeichen nehmt ihr mit setAxisMapConfig() und setAxisMapSign() vor. Die Parameter lauten eMapSign_Px bzw. eMapConfig_Px mit x = 0 bis 7. P0 bis P7 entsprechen, wie schon bei der Adafruit-Bibliothek erwähnt, bestimmten Einbausituationen des BNO055, die in Abschnitt 3.4 des Datenblatts beschrieben werden.
Was die Bibliothek anscheinend nicht implementiert hat, ist die Einstellung der Schlafzeiten für das Accelerometer und das Gyroskop im sensorspezifischen Low-Power-Mode bzw. Advanced-Power-Mode.
Ansteuerung mit der Bosch-Bibliothek
Zum Schluss möchte ich noch auf die Bibliothek BNO055 vom Sensorhersteller Bosch eingehen. Ihr findet sie hier auf GitHub. In der Arduino-IDE könnt ihr sie über den Bibliotheksmanager installieren.
Die Bibliothek ist im C-Stil geschrieben und deswegen für viele vielleicht etwas gewöhnungsbedürftig. So erzeugt ihr beispielsweise kein BNO055-Objekt, da die Bibliothek keine Klasse enthält. Entsprechend ruft ihr die Funktionen nicht wie gewohnt über objectname.function_name() auf, sondern nur über den Funktionsnamen wie etwa bno055_read_accel_xyz().
Ein weiteres Merkmal der Bibliothek ist, dass ihr nicht darum herumkommt, in das Datenblatt und in die Bibliotheksdateien zu schauen. So müsst ihr etwa, wenn ihr die Limits für die Interrupts festlegen wollt, erst einmal den Funktionsnamen heraussuchen, da es wenig Beispielsketche gibt. Dann müsst ihr noch die Bedeutung der zu übergebenden Parameter herausfinden.
Das klingt alles etwas abschreckend, aber der Vorteil dieser Bibliothek ist ihre Vollständigkeit. Ihr habt damit die absolute Kontrolle. Und Raketenwissenschaft ist die Bedienung auch nicht, sie erfordert nur ein wenig mehr Einarbeitung und Nachschlagen. Meine Beispielsketche geben vielleicht ein bisschen Starthilfe.
Messdaten auslesen und Einstellungen vornehmen
Die Bibliothek hat nur einen Beispielsketch, der das Auslesen von Messwerten veranschaulicht, nämlich Euler_Streaming.ino. Da er lediglich Euler-Winkel liefert, habe ich ihn um die anderen Messwerte und den Kalibrierstatus erweitert.
Außerdem zeige ich euch beispielhaft, wie ihr verschiedene Einstellungen vornehmt. Weitere Funktionen zur Konfiguration und die zugehörigen Parameter müsst ihr euch selbst aus BNO055.h heraussuchen.
#include "BNO055_support.h" //Contains the bridge code between the API and Arduino
#include <Wire.h>
//The device address is set to BNO055_I2C_ADDR2 in this example. You can change this in the BNO055.h file in the code segment shown below.
// /* bno055 I2C Address */
// #define BNO055_I2C_ADDR1 0x28
// #define BNO055_I2C_ADDR2 0x29
// #define BNO055_I2C_ADDR BNO055_I2C_ADDR2
//This structure contains the details of the BNO055 device that is connected. (Updated after initialization)
struct bno055_t myBNO;
// Structures to hold the measured/calculated data
struct bno055_accel myAccelData;
struct bno055_gyro myGyroData;
struct bno055_mag myMagData;
struct bno055_euler myEulerData;
struct bno055_quaternion myQuaternionData;
struct bno055_linear_accel myLinearAccelData;
struct bno055_gravity myGravityData;
BNO055_S16 myTemperatureData; // BNO055_S16 = short int
int factor = 1.0; // for calculation measured values from raw data
void setup() {
//Initialize I2C communication
Wire.begin();
//Initialization of the BNO055
BNO_Init(&myBNO); // Assigning the structure to hold information about the device
/* Some config examples. After initiation you are in config mode, for later changes go
into config mode before. If you apply changes, you need to repower the BNO055 or do
a reset. */
bno055_set_reset_sys(1); delay(800); // force reset a give rest time
/* Some examples of config options */
// bno055_set_operation_mode(OPERATION_MODE_CONFIG); // change to config mode
// bno055_set_powermode(POWER_MODE_LOW_POWER); // Altern.: POWER_MODE_SUSPEND / POWER_MODE_LOW_POWER
// bno055_set_axis_remap_value(REMAP_Y_Z); // swap y and z axis
// bno055_set_x_remap_sign(1); // set negative sign for x-axis
// bno055_set_accel_range(ACCEL_RANGE_2G); // not available in fusion modes
// bno055_set_gyro_range(GYRO_RANGE_125rps); // you also need to change the factor below; not available in fusion modes
bno055_set_operation_mode(OPERATION_MODE_NDOF); // set NDoF mode
delay(1);
//Initialize the Serial Port to view information on the Serial Monitor
Serial.begin(115200);
}
template <typename T>
void printXYZ(const T *xyzData, float factor) {
Serial.print(" x: "); Serial.print((float)xyzData->x / factor);
Serial.print(" y: "); Serial.print((float)xyzData->y / factor);
Serial.print(" z: "); Serial.println((float)xyzData->z / factor);
}
void printCalib() {
unsigned char sysCalib=99, accelCalib=99, gyroCalib=99, magCalib=99;
bno055_get_syscalib_status(&sysCalib);
bno055_get_accelcalib_status(&accelCalib);
bno055_get_gyrocalib_status(&gyroCalib);
bno055_get_magcalib_status(&magCalib);
Serial.print("Calibration: ");
Serial.print("SYS: "); Serial.print(sysCalib);
Serial.print(" ACC: "); Serial.print(accelCalib);
Serial.print(" GYR: "); Serial.print(gyroCalib);
Serial.print(" MAG: "); Serial.println(magCalib);
}
void loop() {
bno055_read_accel_xyz(&myAccelData);
bno055_read_gyro_xyz(&myGyroData);
bno055_read_mag_xyz(&myMagData);
bno055_read_gravity_xyz(&myGravityData);
bno055_read_linear_accel_xyz(&myLinearAccelData);
bno055_read_euler_hrp(&myEulerData);
bno055_read_quaternion_wxyz(&myQuaternionData);
bno055_read_temperature_data(&myTemperatureData);
Serial.print("Acceleration: "); printXYZ(&myAccelData, 1.0);
Serial.print("Gyroscope: "); printXYZ(&myGyroData, 16.0);
Serial.print("Magnetometer: "); printXYZ(&myMagData, 16.0);
Serial.print("Gravity: "); printXYZ(&myGravityData, 1.0);
Serial.print("Lin. Acceleration: "); printXYZ(&myLinearAccelData, 1.0);
Serial.print("Euler Angles: ");
Serial.print(" head: "); Serial.print((float)myEulerData.h / 16.0);
Serial.print(" roll: "); Serial.print((float)myEulerData.r / 16.0);
Serial.print(" pitch: "); Serial.println((float)myEulerData.p / 16.0);
Serial.print("Quaternion: "); Serial.print(" w: "); Serial.print((float)myQuaternionData.w / 16384.0);
printXYZ(&myQuaternionData, 16384.0);
Serial.print("Temperature: "); Serial.println(myTemperatureData);
printCalib();
Serial.println(); //Extra line to differentiate between packets
delay(1000);
}
So sieht dann die Ausgabe im seriellen Monitor aus:

Ich möchte den Sketch nicht Zeile für Zeile durchgehen, aber trotzdem einige Hinweise geben, die über die Kommentare im Sketch hinausgehen:
- Da es keine Klasse mit Konstruktor gibt, könnt ihr keine I²C-Adresse übergeben. Änderungen müsst ihr direkt in BNO055.h vornehmen.
- Die Struktur myBNO enthält Geräteinformationen (siehe Beispielsketch Basic.ino) und wird für die Init-Funktion benötigt.
- Die Messwerte werden in Strukturen gespeichert. Ihr übergebt diese Strukturen den zuständigen Funktionen als Referenz.
- Die Messwerte kommen als Rohdaten zurück, die noch mit individuellen Faktoren umgerechnet werden müssen. Wichtig ist, dass der Faktor für die Gyroskopwerte rangeabhängig ist.
- Der Ausgabefunktion für die Messwerte,
printXYZ(), werden unterschiedliche Datentypen übergeben. In vorherigen Sketchen haben wir das Problem mit einem#define-Makro umschifft. Stattdessen habe ich mich hier für eine Lösung mittels Template entschieden.
Interrupts
Als hoffentlich nützliche Ergänzung zu den spärlichen Beispielsketchen der Bibliothek habe ich noch einen Sketch geschrieben, der euch die Verwendung von Interrupts näherbringen soll. Dabei habe ich mich auf den Any-Motion- und den No-(/Slow-)Motion-Interrupt beschränkt. Wenn ihr weitere Interrupts einrichten wollt, dann müsst ihr euch die entsprechenden Funktionen aus BNO055.h heraussuchen.
Hier zunächst der Sketch:
#include "BNO055_support.h" //Contains the bridge code between the API and Arduino
#include <Wire.h>
#define FUNC_ENABLE 1 // enable functions
#define FUNC_DISABLE 0 // disable functions
#define NO_MOTION_ENABLE 1
#define SLOW_MOTION_ENABLE 0
//This structure contains the details of the BNO055 device that is connected. (Updated after initialization)
struct bno055_t myBNO;
int intPin = 2; // interrupt pin
unsigned char intSta = 0; // interupt status register
volatile bool intFlag = false; // interrupt flag
void intHandle() {
intFlag = true;
}
void setup() {
//Initialize I2C communication
Wire.begin();
pinMode(intPin, INPUT);
//Initialization of the BNO055
BNO_Init(&myBNO); //Assigning the structure to hold information about the device
/* Some config examples. After iniitiation you are in config mode, for later changes go
into config mode before. If you apply changes, you need to repower the BNO055 or do
a reset. */
bno055_set_reset_sys(true); delay(800); // force reset
bno055_set_operation_mode(OPERATION_MODE_CONFIG); // change to config mode
bno055_set_intmsk_accel_anymotion(FUNC_ENABLE); // any motion interrupt propagated to interrupt pin
bno055_set_intmsk_accel_nomotion(FUNC_ENABLE); // no motion interrupt propagated to interrupt pin
bno055_set_accel_slow_no_motion_enable(NO_MOTION_ENABLE); // Alternative: SLOW_MOTION_ENABLE
bno055_set_int_accel_anymotion(FUNC_ENABLE); // enable any motion interrupt
bno055_set_int_accel_nomotion(FUNC_ENABLE); // enable no/slow motion interrupt
/* activate axes for any motion / no (or slow) motion interrupt*/
bno055_set_accel_an_nm_axis_enable(BNO055_ACCEL_AM_NM_X_AXIS, FUNC_ENABLE);
bno055_set_accel_an_nm_axis_enable(BNO055_ACCEL_AM_NM_Y_AXIS, FUNC_ENABLE);
bno055_set_accel_an_nm_axis_enable(BNO055_ACCEL_AM_NM_Z_AXIS, FUNC_ENABLE);
bno055_set_accel_anymotion_threshold(40); // in 4g range 1 LSB = 7.81 mg
bno055_set_accel_anymotion_duration(1); // parameter (max 3) = no samples above limit + 1
bno055_set_accel_slow_no_threshold(10); // in 4g range 1 LSB = 7.81 mg
/* Parameter x (max. 63) for bno055_set_accel_slow_no_duration(x)
In no motion mode:
x < 16 => duration[s] = x + 1
15 < x < 22 => duration[s] = 40 + (x - 16) * 8
31 < x < 64 => duration[s] = 88 + (x - 32) * 8
In slow motion mode:
number of samples above limit = x + 1
*/
bno055_set_accel_slow_no_duration(5); // interrupt after 6s of no motion
attachInterrupt(digitalPinToInterrupt(intPin), intHandle, RISING); // attach interrupt
bno055_read_register(BNO055_INT_STA_ADDR, &intSta, sizeof(intSta)); // clear unexpected interrupt
intFlag = false;
bno055_set_reset_int(true);
bno055_set_operation_mode(OPERATION_MODE_NDOF); // set NDoF mode,
delay(1);
//Initialize the Serial Port to view information on the Serial Monitor
Serial.begin(115200);
}
void loop() {
if(intFlag) {
intFlag = false;
/* read interrupt state register and clear it */
bno055_read_register(BNO055_INT_STA_ADDR, &intSta, sizeof(intSta));
bno055_set_reset_int(true); // set interrupt pin low again
Serial.println("interrupt detected");
if(intSta & BNO055_INT_STAT_ACC_AM__MSK) // is any motion triggered?
Serial.println("accelerometer any motion detected");
if(intSta & BNO055_INT_STAT_ACC_NM__MSK) // is no motion triggered?
Serial.println("accelerometer no motion detected");
}
}
Und so könnte eine Ausgabe aussehen:

Wer den Interrupt-Sketch für die DFRobot-Bibliothek durchgearbeitet hat, wird in diesem Sketch vieles wiedererkennen.
Auch hier ergänze ich die Kommentare im Sketch nur durch ein paar zusätzliche Erklärungen:
- Zunächst legt ihr fest, welche Interrupts an den Interruptpin weitergeleitet werden.
- Mit der Funktion
bno055_set_accel_slow_no_motion_enable();entscheidet ihr euch für den No-Motion- oder den Slow-Motion-Interrupt. - Die Limits (Thresholds) werden so, wie ihr sie übergebt, in die entsprechenden Register eingetragen. Um herauszubekommen, was der Wert bedeutet, müsst ihr im Datenblatt den Wert für das LSB (least significant bit) heraussuchen. Der Wert für das LSB ändert sich mit der Range.
- Die Duration für den No-Motion-Interrupt hat drei Bereiche mit unterschiedlichen Berechnungsformeln. Dabei ist der Bereich 22 bis 31 nicht definiert.
- Welcher Interrupt ausgelöst wurde, wird durch Anwendung der Interruptmaske auf den Inhalt des Interruptregisters ermittelt.
- Das Löschen des Interruptregisters und das Zurücksetzen des Interruptpins sind zwei separate Schritte.
So, alles andere müsst ihr euch selbst zusammensuchen!

Hallo Wolfgang, es wird ja langsam öde, immer nur „Danke für Deine prima Doku“ zu schreiben.
Daher diesmal nur ein einfaches „Danke“ … muss reichen!
;O))
Ne, im ernst: Bin natürlich wieder total begeistert über Deine beispiellose Fachlektüre.
Immer wieder gerne, weiter so!
Viele Grüße und schönen Sonntag, auch wenn’s auf dem Rest dieses Planeten wegen der vielen Kriegstreibereien sehr unschön ist.
– Harry
Hallo Harry, ich freue mich immer über positive Rückmeldungen – vielen Dank dafür.
Und ja, die Welt ist schon verrückt. Die Menschheit lernt anscheinend nichts dazu. Da bleibt uns nur, zumindest in unserem Umfeld Gutes zu tun.
Dir auch einen schönen Sonntag,
Wolfgang