Bewegungssensor
#BMI270 – 6-Achsen Bewegungssensor (IMU)
Hochpräzise Inertial Measurement Unit (IMU) mit 3-Achsen-Beschleunigungssensor und 3-Achsen-Gyroskop.
- BMI270 – 6-Achsen Bewegungssensor (IMU)
- Übersicht
- Technische Daten
- Pinbelegung & Anschluss
- Funktionsweise
- Beispielcode
- Achsenorientierung
- Tipps & häufige Fehler
- Weiterführende Links
#Übersicht
Der BMI270 von Bosch ist ein moderner 6-Achsen Bewegungssensor, der speziell für Wearables und IoT-Anwendungen entwickelt wurde. Er kombiniert einen Beschleunigungssensor und ein Gyroskop in einem kompakten Gehäuse. Der Sensor eignet sich hervorragend für Bewegungserkennung, Schrittzählung, Gestenerkennung, Lagebestimmung und Navigationssysteme. Er bietet integrierte Features wie Step Counter, Gesture Detection und Activity Recognition.
#Technische Daten
| Eigenschaft | Wert |
|---|---|
| Beschleunigungsmessbereich | ±2g, ±4g, ±8g, ±16g (wählbar) |
| Beschleunigungsauflösung | 16 Bit |
| Gyroskop-Messbereich | ±125, ±250, ±500, ±1000, ±2000 °/s |
| Gyroskop-Auflösung | 16 Bit |
| Versorgungsspannung | 1.71 V bis 3.6 V |
| Stromverbrauch | 685 µA (volle Leistung) |
| Protokoll | I²C / SPI |
| I²C-Adresse | 0x68 |
| I²C-Taktfrequenz | bis 1 MHz |
| Betriebstemperatur | -40 °C bis +85 °C |
#Pinbelegung & Anschluss
#Anschlussschema (I²C)
| Sensor-Pin | ESP32-C6 Pin | Beschreibung |
|---|---|---|
| VCC | 3.3V | Versorgung |
| GND | GND | Masse |
| SDA | GPIO22 | I²C Daten |
| SCL | GPIO23 | I²C Takt |
| INT1 | (optional) | Interrupt 1 |
| INT2 | (optional) | Interrupt 2 |
#Hinweise zur Verdrahtung
- I²C-Adresse: SDO an GND = 0x68, SDO an VCC = 0x69
- Pull-up-Widerstände: Viele Breakout-Boards haben bereits Pull-ups integriert
- Interrupt-Pins: Optional für ereignisgesteuerte Anwendungen (Bewegungserkennung, Schritterkennung)
#Funktionsweise
Der BMI270 kombiniert zwei MEMS-Sensoren:
-
Beschleunigungssensor: Misst lineare Beschleunigung in drei Achsen (X, Y, Z). Basiert auf kapazitiver Messung einer beweglichen Masse. Erfasst auch die Erdbeschleunigung zur Lagebestimmung.
-
Gyroskop: Misst Winkelgeschwindigkeit (Drehrate) in drei Achsen. Nutzt den Coriolis-Effekt zur Erfassung von Rotationsbewegungen.
Integrierte Features:
- Step Counter (Schrittzähler)
- Step Detector (Schritterkennung)
- Significant Motion Detection
- Any Motion / No Motion Detection
- Wrist Gesture Recognition (für Wearables)
#Beispielcode
#MicroPython
from machine import I2C, Pin
from time import sleep_ms
import struct
class BMI270:
# Register
CHIP_ID = 0x00
ERR_REG = 0x02
STATUS = 0x03
ACC_X_LSB = 0x0C
GYR_X_LSB = 0x12
INTERNAL_STATUS = 0x21
ACC_CONF = 0x40
ACC_RANGE = 0x41
GYR_CONF = 0x42
GYR_RANGE = 0x43
CMD = 0x7E
PWR_CONF = 0x7C
PWR_CTRL = 0x7D
INIT_CTRL = 0x59
INIT_DATA = 0x5E
# Chip ID
BMI270_CHIP_ID = 0x24
def __init__(self, i2c, addr=0x68):
self.i2c = i2c
self.addr = addr
# Chip ID prüfen
chip_id = self._read_byte(self.CHIP_ID)
if chip_id != self.BMI270_CHIP_ID:
raise RuntimeError(f"BMI270 nicht gefunden. Chip ID: {hex(chip_id)}")
self._init_sensor()
# Skalierungsfaktoren (Standardeinstellungen)
self.acc_scale = 2.0 / 32768.0 # ±2g
self.gyr_scale = 500.0 / 32768.0 # ±500°/s
def _read_byte(self, reg):
return self.i2c.readfrom_mem(self.addr, reg, 1)[0]
def _write_byte(self, reg, val):
self.i2c.writeto_mem(self.addr, reg, bytes([val]))
def _read_bytes(self, reg, length):
return self.i2c.readfrom_mem(self.addr, reg, length)
def _init_sensor(self):
# Soft Reset
self._write_byte(self.CMD, 0xB6)
sleep_ms(100)
# Power Configuration: Advanced Power Save deaktivieren
self._write_byte(self.PWR_CONF, 0x00)
sleep_ms(50)
# Initialisierung vorbereiten
self._write_byte(self.INIT_CTRL, 0x00)
sleep_ms(10)
# Config-Datei laden (vereinfacht - minimale Konfiguration)
# Für volle Funktionalität muss die Bosch Config-Datei geladen werden
self._load_config_file()
# Initialisierung starten
self._write_byte(self.INIT_CTRL, 0x01)
sleep_ms(150)
# Status prüfen
status = self._read_byte(self.INTERNAL_STATUS)
if (status & 0x01) != 0x01:
print(f"Warnung: Initialisierungsstatus = {hex(status)}")
# Accelerometer konfigurieren: ODR 100Hz, Normal Mode
self._write_byte(self.ACC_CONF, 0xA8)
# Accelerometer Range: ±2g
self._write_byte(self.ACC_RANGE, 0x00)
# Gyroskop konfigurieren: ODR 100Hz, Normal Mode
self._write_byte(self.GYR_CONF, 0xA9)
# Gyroskop Range: ±500°/s
self._write_byte(self.GYR_RANGE, 0x02)
# Sensoren einschalten
self._write_byte(self.PWR_CTRL, 0x0E) # Acc + Gyr + Temp enable
sleep_ms(100)
def _load_config_file(self):
# Minimale Initialisierung ohne externe Config-Datei
# Für erweiterte Features (Step Counter etc.) wird die
# vollständige Bosch Config-Datei benötigt
pass
def read_accel(self):
"""Liest Beschleunigungswerte in g."""
data = self._read_bytes(self.ACC_X_LSB, 6)
x = struct.unpack('<h', data[0:2])[0] * self.acc_scale
y = struct.unpack('<h', data[2:4])[0] * self.acc_scale
z = struct.unpack('<h', data[4:6])[0] * self.acc_scale
return x, y, z
def read_gyro(self):
"""Liest Gyroskopwerte in °/s."""
data = self._read_bytes(self.GYR_X_LSB, 6)
x = struct.unpack('<h', data[0:2])[0] * self.gyr_scale
y = struct.unpack('<h', data[2:4])[0] * self.gyr_scale
z = struct.unpack('<h', data[4:6])[0] * self.gyr_scale
return x, y, z
def read_all(self):
"""Liest alle Sensorwerte auf einmal."""
data = self._read_bytes(self.ACC_X_LSB, 12)
ax = struct.unpack('<h', data[0:2])[0] * self.acc_scale
ay = struct.unpack('<h', data[2:4])[0] * self.acc_scale
az = struct.unpack('<h', data[4:6])[0] * self.acc_scale
gx = struct.unpack('<h', data[6:8])[0] * self.gyr_scale
gy = struct.unpack('<h', data[8:10])[0] * self.gyr_scale
gz = struct.unpack('<h', data[10:12])[0] * self.gyr_scale
return (ax, ay, az), (gx, gy, gz)
def set_acc_range(self, range_g):
"""Setzt den Beschleunigungsmessbereich (2, 4, 8 oder 16 g)."""
ranges = {2: 0x00, 4: 0x01, 8: 0x02, 16: 0x03}
if range_g not in ranges:
raise ValueError("Gültige Werte: 2, 4, 8, 16")
self._write_byte(self.ACC_RANGE, ranges[range_g])
self.acc_scale = range_g / 32768.0
def set_gyr_range(self, range_dps):
"""Setzt den Gyroskop-Messbereich (125, 250, 500, 1000, 2000 °/s)."""
ranges = {2000: 0x00, 1000: 0x01, 500: 0x02, 250: 0x03, 125: 0x04}
if range_dps not in ranges:
raise ValueError("Gültige Werte: 125, 250, 500, 1000, 2000")
self._write_byte(self.GYR_RANGE, ranges[range_dps])
self.gyr_scale = range_dps / 32768.0
# Hauptprogramm
i2c = I2C(0, scl=Pin(23), sda=Pin(22), freq=400000)
# I²C-Scan zur Überprüfung
devices = i2c.scan()
print(f"Gefundene I²C-Geräte: {[hex(d) for d in devices]}")
# Sensor initialisieren
try:
imu = BMI270(i2c)
print("BMI270 erfolgreich initialisiert!")
except RuntimeError as e:
print(f"Fehler: {e}")
raise SystemExit
# Messwerte ausgeben
while True:
accel, gyro = imu.read_all()
print(f"Beschleunigung: X={accel[0]:+.2f}g Y={accel[1]:+.2f}g Z={accel[2]:+.2f}g")
print(f"Gyroskop: X={gyro[0]:+.1f}°/s Y={gyro[1]:+.1f}°/s Z={gyro[2]:+.1f}°/s")
# Lage erkennen (vereinfacht)
if abs(accel[2]) > 0.8:
if accel[2] > 0:
print(" -> Lage: Flach (Oberseite oben)")
else:
print(" -> Lage: Flach (Unterseite oben)")
elif abs(accel[0]) > 0.8:
print(" -> Lage: Aufrecht (X-Achse)")
elif abs(accel[1]) > 0.8:
print(" -> Lage: Aufrecht (Y-Achse)")
print("-" * 50)
sleep_ms(500)
#C (Arduino Framework)
#include <Wire.h>
#include <BMI270_Sensor.h>
// I²C-Pins für das Lernboard
#define I2C_SDA 22
#define I2C_SCL 23
// I²C-Adresse des Sensors
#define BMI270_ADDR 0x68
BMI270Class BMI270;
void setup() {
Serial.begin(115200););
while (!Serial) delay(10););
// I²C mit den Board-spezifischen Pins initialisieren
Wire.begin(I2C_SDA, I2C_SCL);
Serial.println("BMI270 Test - Lernboard");
// Sensor initialisieren
if (!BMI270.begin()) {
Serial.println("BMI270 nicht gefunden!");
Serial.println("Verkabelung prüfen.");
while (1) delay(10);) delay(10););
}
Serial.println("BMI270 gefunden!");
Serial.println();
}
void loop() {
float ax, ay, az; // Beschleunigung
float gx, gy, gz; // Gyroskop
// Sensordaten abrufen
BMI270.readAcceleration(ax, ay, az);
BMI270.readGyroscope(gx, gy, gz);
// Beschleunigung ausgeben
Serial.print("Beschleunigung: ");
Serial.print("X="); Serial.print(ax, 2); Serial.print("g ");); Serial.print("g ");
Serial.print("Y="); Serial.print(ay, 2); Serial.print("g ");); Serial.print("g ");
Serial.print("Z="); Serial.print(az, 2); Serial.println("g");); Serial.println("g");
// Gyroskop ausgeben
Serial.print("Gyroskop: ");
Serial.print("X="); Serial.print(gx, 1); Serial.print("°/s ");); Serial.print("°/s ");
Serial.print("Y="); Serial.print(gy, 1); Serial.print("°/s ");); Serial.print("°/s ");
Serial.print("Z="); Serial.print(gz, 1); Serial.println("°/s");); Serial.println("°/s");
// Lage erkennen (vereinfacht)
Serial.print(" -> Lage: ");
if (abs(az) > 0.8) {) {
if (az > 0) {) {
Serial.println("Flach (Oberseite oben)");
} else {
Serial.println("Flach (Unterseite oben)");
}
} else if (abs(ax) > 0.8) {) {
Serial.println("Aufrecht (X-Achse)");
} else if (abs(ay) > 0.8) {) {
Serial.println("Aufrecht (Y-Achse)");
} else {
Serial.println("Geneigt");
}
Serial.println("--------------------------------------------------");
delay(500););
}
Benötigte Bibliothek für Arduino:
Bibliotheksname: BMI270_Sensor
Installation: Arduino IDE -> Bibliotheken verwalten -> "BMI270" suchen -> Installieren
Alternative: Bosch-Sensortec BMI270-API von GitHub
#Achsenorientierung
Die Achsen des BMI270 sind wie folgt definiert (Blick auf die Oberseite des Chips):
+Y
^
|
|
+X <---+---> -X
|
|
v
-Y
+Z zeigt aus der Chipoberfläche heraus
-Z zeigt in die Chipoberfläche hinein
Bei flacher Lage (Oberseite oben) zeigt der Z-Wert ca. +1g (Erdbeschleunigung).
#Tipps & häufige Fehler
-
Sensor wird nicht erkannt: Mit einem I²C-Scanner überprüfen, ob der Sensor auf Adresse 0x68 antwortet. Falls der SDO-Pin auf VCC liegt, ist die Adresse 0x69.
-
Initialisierung schlägt fehl: Der BMI270 benötigt eine spezielle Initialisierungssequenz mit Config-Datei. Bei Verwendung von Bibliotheken wird dies automatisch erledigt.
-
Drift beim Gyroskop: Gyroskope haben einen natürlichen Drift. Für präzise Winkelmessungen sollte ein Sensor-Fusion-Algorithmus (z.B. Madgwick, Mahony) verwendet werden.
-
Beschleunigungswerte nicht bei 0: Im Ruhezustand misst der Beschleunigungssensor die Erdbeschleunigung (ca. 1g auf der Z-Achse bei flacher Lage).
-
Verwechslung mit BMI160: Der BMI270 ist der Nachfolger des BMI160 mit verbesserter Genauigkeit und zusätzlichen Features. Die Register sind teilweise unterschiedlich.
-
Messbereich wählen: Für ruhige Anwendungen (z.B. Lagebestimmung) kleinere Messbereiche wählen (±2g, ±125°/s) für höhere Auflösung. Für schnelle Bewegungen größere Bereiche.