MPU6050 – Ein Sensor, der Bewegung „fühlt“

Habt ihr euch jemals gefragt, wie euer Smartphone weiß, ob ihr es dreht oder ob es sich bewegt?

Das Geheimnis liegt in einem kleinen, aber leistungsstarken Bauteil: einer sogenannten IMU (Inertial Measurement Unit). Eine IMU ist ein Sensor, der Bewegungen und Lageveränderungen erkennt. Sie kombiniert meist einen Beschleunigungssensor (Accelerometer) und ein Gyroskop, manchmal auch ein Magnetometer. Damit kann sie z. B. Neigungen, Drehungen oder Erschütterungen messen – ideal für Smartphones, Drohnen oder DIY-Projekte mit Mikrocontrollern.

Ein besonders beliebter Vertreter dieser Sensorfamilie ist der MPU6050. Er vereint ein 3-Achsen-Gyroskop und einen 3-Achsen-Beschleunigungssensor in einem einzigen Chip – perfekt für Projekte mit Arduino, ESP32 oder Raspberry Pi.

In diesem Beitrag zeige ich euch, wie ihr den MPU6050, der in diesem Beitrag auf dem GY-521 Modul integriert ist, auslesen könnt, welche Daten er liefert und wie ihr ihn in euren eigenen Projekten einsetzen könnt.
Nicht ganz unbekannt, da ich dieses Modul schon im Projekt Der sich selbst ausbalancierende 2Rad Arduino eingesetzt hatte.

Was macht der MPU6050 Chip?

  • Er kann Bewegung (Beschleunigung) und Drehung (Rotation) messen.
  • Er merkt, ob er nach links, rechts, oben oder unten bewegt wird.
  • Er kann erkennen, wie schnell sich etwas dreht – wie bei einem Kreisel!

Warum ist das interessant?
Mit diesem Sensor kann man spannende Dinge machen, zum Beispiel:

  • Einen Schrittzähler bauen, der die Bewegungen zählt.
  • Einen Controller für ein Spiel bauen, um mit der Handbewegung zu steuern.
  • Einen Roboter entwickeln, der merkt, wenn er umfällt und sich wieder ausrichtet.
  • Als Drohnenstabilisierung, hält die Fluglage stabil.
  • Ein Zweirad Fahrzeug das sich selbst ausbalanciert.

Aber wie genau funktioniert er?
Der MPU6050 enthält kleine mechanische Teile, die sich bewegen, wenn der Sensor in Bewegung ist. Diese Bewegungen werden dann in Zahlen umgewandelt – und damit könnt ihr in eurem Programm arbeiten. Obwohl diese mechanischen Teile mikroskopisch klein sind, sind sie fundamental für die Funktionsweise des Sensors. Sie sind jedoch sicher im Chipgehäuse integriert und nicht direkt von außen sichtbar oder zugänglich. Man spricht hier vom Mikro-Elektro-Mechanische Systeme (MEMS).

Hier der Versuch das mal bildlich darzustellen:

Beschleunigungssensor: Misst die Beschleunigung, indem er die Verschiebung einer kleinen Masse (Prüfmasse) gegenüber dem festen Rahmen des Sensors erfasst. Diese Verschiebung, verursacht durch Trägheitskräfte, wird in ein elektrisches Signal umgewandelt.

Gyroskop: Erfasst die Dreh-Rate (Winkelgeschwindigkeit) oft über den Coriolis-Effekt, der auf schwingende oder rotierende mikromechanische Elemente wirkt. Die durch die Drehung verursachten winzigen Auslenkungen oder Frequenzänderungen werden gemessen.

Welche Messungen sind möglich

Beschleunigungsmessung (Accelerometer)

  • Misst die Bewegung in drei Achsen (X, Y, Z)
  • Erkennt Neigung und Schwankungen
  • Kann für Schrittzähler, Balance-Systeme oder Erdbebenmessungen genutzt werden

Drehgeschwindigkeit (Gyroskop)

  • Misst die Rotationsgeschwindigkeit um die drei Achsen (X, Y, Z)
  • Wird für Kreiselsysteme, Robotersteuerung und Flugstabilisierung verwendet

Temperaturmessung zur Kalibrierung

  • Der MPU6050 hat einen integrierten Temperatursensor
  • Durch Temperaturschwankungen wird die Genauigkeit der Bewegungserfassung beeinflusst. Erhaltene Werte durch regelmäßige Messung dient zur Kalibrierung für genauere Bewegungsverfolgung.
  • Kann aber auch nur zur Überwachung der Umgebungstemperatur genutzt werden

Kombinierte Messungen
Durch die Kombination von Beschleunigung und Gyroskop kann man relative Bewegungen und Lageänderungen berechnen. Diese Technik wird beispielsweise auch zum erkennen von Vibration und Ruhestellung verwendet.

Eine absolute Orientierung ist aber nicht möglich. Damit das funktioniert, muss man die Sensoren mit einem Magnetometer kombinieren, so wie es im LSM9DS1 von Adafruit der Fall ist.
Der Arduino Nano 33 BLE Sense Rev2 hat auch eine 9-Achsen-IMU, die aus dem BMI270 (Gyroskop & Beschleunigungssensor) und dem BMM150 (Magnetometer) besteht.


Ausrichtung
Wie sollte das Modul angebracht werden?
Empfohlene Ausrichtung, wenn möglich, flach auf einer Oberfläche liegend, wie aufgedruckte Achsen.


Dann sollte das Modul folgende Werte anzeigen:

Bewegungssensor (Beschleunigungssensor / Accelerometer)

Er misst, wie stark und in welche Richtung das Modul bewegt oder geneigt wird.

  • Die Bewegungen werden in drei Richtungen gemessen:
    • X = links/rechts
    • Y = vor/zurück
    • Z = oben/unten

Wenn du den Sensor ruhig auf den Tisch legst, zeigt der Z-Wert trotzdem einen Wert – nämlich die Gravitationskraft von 1g, was der Erdbeschleunigung von etwa 9,81 m/sentspricht.

Drehsensor (Gyroskop)

Er merkt, wie schnell sich das Modul um eine Achse dreht – wie ein Kreisel!

  • Auch hier gibt es X, Y und Z – aber diesmal bedeuten sie:
    • X = Drehen um die linke/rechte Achse (Kopf nicken)
    • Y = Drehen um die vordere/hintere Achse (Kopf schief legen)
    • Z = Drehen um die senkrechte Achse (Kopf schütteln / drehen)

Diese Werte zeigen nicht, wie weit sich das Modul gedreht hat – sondern wie schnell es sich gerade dreht.


Erstellung der Testumgebung:
Erste Werte aus der Testumgebung und anschließend Kalibrierung

Da ja der Bewegungssensor sowie auch das Gyroskop X, Y und Z Werte ausgibt, also ein 3-Achsen für Beschleunigungsmessung + 3-Achsen für Drehgeschwindigkeitsmessung, müssen 6 Achsen-Werte auslesbar sein und auf Glaubwürdigkeit geprüft werden.

Hardware:
Arduino R4 Wifi (Mit ESP32-S3 mini)
GY-521(MPU6050) Datenblatt

Verdrahtung:
Das mir vorliegende Modul MPU6050 kommuniziert per I2C (Adresse 0x68) und ist 3,3 V und auch 5 V Tolerant.

MPU6050 VCC → Arduino 3.3V oder 5V (beides kompatibel)
MPU6050 GND → Arduino GND
MPU6050 SCL → Arduino SCL oder auch Pin A5
MPU6050 SDA → Arduino SDA oder auch Pin A4
(Optional AD0 = High, dann I2C Adresse 0x69)

Als erstes schau ich mal, ob überhaupt die 6 Achsen-Werte mit einem Arduino und dem MPU6050 ausgelesen werden.

Arduino-Code zum Auslesen der 6 Achsen:

  1. Öffne die Arduino IDE 2.x.
  2. Installiere die Bibliothek „Adafruit MPU6050“:
    • Gehe zu „Sketch“ → „Bibliothek einbinden“ → „Bibliotheken verwalten“
    → Suche nach „MPU6050“ und installiere die von „Adafruit“
  • Unter Beispiele ist nun das Sketch basic_readings zu finden.
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>

Adafruit_MPU6050 mpu;

const int numSamples = 500;

float ax_sum = 0, ay_sum = 0, az_sum = 0;
float gx_sum = 0, gy_sum = 0, gz_sum = 0;

void setup(void) {
  Serial.begin(115200);
  while (!Serial) delay(10);

  if (!mpu.begin()) {
    Serial.println("MPU6050 nicht gefunden!");
    while (1) delay(10);
  }

  Serial.println("Starte Kalibrierung... Bitte Sensor ruhig liegen lassen.");
  delay(2000);

  for (int i = 0; i < numSamples; i++) {
    sensors_event_t a, g, temp;
    mpu.getEvent(&a, &g, &temp);

    ax_sum += a.acceleration.x;
    ay_sum += a.acceleration.y;
    az_sum += a.acceleration.z;

    gx_sum += g.gyro.x;
    gy_sum += g.gyro.y;
    gz_sum += g.gyro.z;

    delay(5);
  }

  float ax_offset = ax_sum / numSamples;
  float ay_offset = ay_sum / numSamples;
  float az_offset = az_sum / numSamples - 9.81; // 1g = 9.81 m/s²

  float gx_offset = gx_sum / numSamples;
  float gy_offset = gy_sum / numSamples;
  float gz_offset = gz_sum / numSamples;

  Serial.println("\n// === KALIBRIERUNGSERGEBNISSE ===");
  Serial.println("// Diese Werte kannst du in deinem Sketch als Offset verwenden:");
  Serial.print("const float AX_OFFSET = "); Serial.print(ax_offset, 4); Serial.println(";");
  Serial.print("const float AY_OFFSET = "); Serial.print(ay_offset, 4); Serial.println(";");
  Serial.print("const float AZ_OFFSET = "); Serial.print(az_offset, 4); Serial.println(";");
  Serial.print("const float GX_OFFSET = "); Serial.print(gx_offset, 4); Serial.println(";");
  Serial.print("const float GY_OFFSET = "); Serial.print(gy_offset, 4); Serial.println(";");
  Serial.print("const float GZ_OFFSET = "); Serial.print(gz_offset, 4); Serial.println(";");

  Serial.println("\nStarte Testausgabe mit korrigierten Werten...\n");
  delay(3000);
}

void loop() {
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);

  // === HIER DEINE OFFSETS EINTRAGEN (nach Kalibrierung) ===
  const float AX_OFFSET = 0.0;
  const float AY_OFFSET = 0.0;
  const float AZ_OFFSET = 0.0;
  const float GX_OFFSET = 0.0;
  const float GY_OFFSET = 0.0;
  const float GZ_OFFSET = 0.0;

  float ax_corr = a.acceleration.x - AX_OFFSET;
  float ay_corr = a.acceleration.y - AY_OFFSET;
  float az_corr = a.acceleration.z - AZ_OFFSET;

  float gx_corr = g.gyro.x - GX_OFFSET;
  float gy_corr = g.gyro.y - GY_OFFSET;
  float gz_corr = g.gyro.z - GZ_OFFSET;

  Serial.print("aX: "); Serial.print(ax_corr, 3);
  Serial.print(" | aY: "); Serial.print(ay_corr, 3);
  Serial.print(" | aZ: "); Serial.print(az_corr, 3);
  Serial.print(" || gX: "); Serial.print(gx_corr, 3);
  Serial.print(" | gY: "); Serial.print(gy_corr, 3);
  Serial.print(" | gZ: "); Serial.println(gz_corr, 3);

  delay(500);
}

Was du bekommst (wenn alles geklappt hat):

  • aX, aY, aZ: Beschleunigung in X, Y, Z (in Rohwerten)
  • gX, gY, gZ: Winkelgeschwindigkeit (Gyro) in X, Y, Z (ebenfalls Rohwerte)
  • Sowie die Raumtemperatur

Was direkt auffällt ist (abgesehen, das Ende Juni25 es wirklich sehr warm ist) das es keine exakten Null Werte gibt und das die Erdbeschleunigung etwas zu hoch ist. (aZ-Wert = Erdbeschleunigung: 1g (etwa 9,81 m/s2)


Die Kalibrierung des MPU6050

Die Messwerte des MPU6050 sind für viele Anwendungen erstaunlich gut – vor allem, wenn man bedenkt, wie günstig und kompakt das Modul ist.
Je nach Aufgabe die das Modul zu erfüllen hat, sollte jedoch eine Kalibrierung durchgeführt werden.

Die Stärken des MPU6050:

  • Gute Auflösung: 16-bit ADC für Beschleunigung und Gyro.
  • Schnelle Abtastrate: Bis zu 1 kHz möglich.
  • Integrierter DMP (Digital Motion Processor): Kann komplexe Berechnungen wie Quaternionen oder Neigungswinkel übernehmen (wenn du ihn nutzt).

Die Schwächen:

  • Drift beim Gyroskop: Über längere Zeit summieren sich kleine Fehler → Winkelabweichung.
    Selbst im Ruhezustand liefert das Gyro kleine Werte ≠ 0 → diese müssen als Offset abgezogen werden.
  • Rauschen beim Beschleunigungssensor: Besonders bei kleinen Bewegungen.
    Auch im Ruhezustand (z. B. liegend auf dem Tisch) zeigt der Sensor nicht exakt 0 g auf X/Y und 1 g auf Z.
  • Temperaturabhängigkeit: Die Sensorwerte können sich bei Temperaturänderungen leicht verschieben.

Die Kalibrierung des MPU6050 ist somit ein entscheidender Schritt, um präzisere und stabilere Messwerte zu erhalten – besonders wenn du Neigungswinkel oder Bewegungen über längere Zeit messen willst. Kalibriere den Sensor in der Umgebungstemperatur, in der er später auch betrieben wird.

Vorgehen zur manuellen Kalibrierung

Schritt 1: Sensor sollte ruhig aufliegen

Lege den MPU6050 flach und absolut ruhig auf eine ebene Fläche. Am besten keine Bewegung während der Kalibrierung!

Schritt 2: Mittelwerte berechnen

Hier ein Beispielcode, der den Mittelwerte für Gyro und Acc mit 500 Messungen berechnet:

#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>

Adafruit_MPU6050 mpu;

const int numSamples = 500; //500 Messungen

float ax_sum = 0, ay_sum = 0, az_sum = 0;
float gx_sum = 0, gy_sum = 0, gz_sum = 0;

void setup(void) {
  Serial.begin(115200);
  while (!Serial) delay(10);

  if (!mpu.begin()) {
    Serial.println("MPU6050 nicht gefunden!");
    while (1) delay(10);
  }

  Serial.println("Starte Kalibrierung... Bitte Sensor ruhig liegen lassen.");
  delay(2000);

  for (int i = 0; i < numSamples; i++) {
    sensors_event_t a, g, temp;
    mpu.getEvent(&a, &g, &temp);

    ax_sum += a.acceleration.x;
    ay_sum += a.acceleration.y;
    az_sum += a.acceleration.z;

    gx_sum += g.gyro.x;
    gy_sum += g.gyro.y;
    gz_sum += g.gyro.z;

    delay(5);
  }

  float ax_offset = ax_sum / numSamples;
  float ay_offset = ay_sum / numSamples;
  float az_offset = az_sum / numSamples - 9.81; // 1g = 9.81 m/s²

  float gx_offset = gx_sum / numSamples;
  float gy_offset = gy_sum / numSamples;
  float gz_offset = gz_sum / numSamples;

  Serial.println("\n// === KALIBRIERUNGSERGEBNISSE ===");
  Serial.println("// Diese Werte kannst du in deinem Sketch als Offset verwenden:");
  Serial.print("const float AX_OFFSET = "); Serial.print(ax_offset, 4); Serial.println(";");
  Serial.print("const float AY_OFFSET = "); Serial.print(ay_offset, 4); Serial.println(";");
  Serial.print("const float AZ_OFFSET = "); Serial.print(az_offset, 4); Serial.println(";");
  Serial.print("const float GX_OFFSET = "); Serial.print(gx_offset, 4); Serial.println(";");
  Serial.print("const float GY_OFFSET = "); Serial.print(gy_offset, 4); Serial.println(";");
  Serial.print("const float GZ_OFFSET = "); Serial.print(gz_offset, 4); Serial.println(";");

  Serial.println("\nStarte Testausgabe mit korrigierten Werten...\n");
  delay(3000);
}

void loop() {
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);

  // === HIER DEINE OFFSETS EINTRAGEN (nach Kalibrierung) ===
const float AX_OFFSET = 0.0;
const float AY_OFFSET = 0.0;
const float AZ_OFFSET = 0.0;
const float GX_OFFSET = 0.0;
const float GY_OFFSET = 0.0;
const float GZ_OFFSET = 0.0;

  float ax_corr = a.acceleration.x - AX_OFFSET;
  float ay_corr = a.acceleration.y - AY_OFFSET;
  float az_corr = a.acceleration.z - AZ_OFFSET;

  float gx_corr = g.gyro.x - GX_OFFSET;
  float gy_corr = g.gyro.y - GY_OFFSET;
  float gz_corr = g.gyro.z - GZ_OFFSET;

  Serial.print("aX: "); Serial.print(ax_corr, 3);
  Serial.print(" | aY: "); Serial.print(ay_corr, 3);
  Serial.print(" | aZ: "); Serial.print(az_corr, 3);
  Serial.print(" || gX: "); Serial.print(gx_corr, 3);
  Serial.print(" | gY: "); Serial.print(gy_corr, 3);
  Serial.print(" | gZ: "); Serial.println(gz_corr, 3);

  delay(500);
}

Erste Ausgabe im Seriellen Monitor:

Werte aus dem Seriellen Monitor übernehmen und in den Sketch ab Zeile 65 eintragen und wieder hochladen.

Die zweite Ausgabe sollte dann in etwa so aussehen:

Ergebnis: Das sind doch Werte mit denen man arbeiten kann.
Die Restabweichungen sind im Bereich des natürlichen Rauschens und der mechanischen Toleranz des MPU6050. Für Anwendungen wie Neigungsmessung, Schrittzähler oder Balancing-Tacker ist das mehr als ausreichend genau.
Wenn Langzeitmessungen geplant werden, sollte darüber hinaus eine Funktion, die die Offsets in Abhängigkeit der Temperatur anpasst, erweitert werden.


Kleine Wasserwaage:
Neigungsmessung mit Accelerometer (Beschleunigungsmessung) an einem Arduino R4 Wifi

Nach diesen Vorbereitungen nun eine Art Wasserwaage zu erstellen.
Dazu benötigen wir nur das auslesen der X-Achse. Die LED Matrix des Arduino soll deutlich zeigen wenn das Werkstück gerade ist.

Quellcode:

#include <Wire.h>
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Arduino_LED_Matrix.h>

Adafruit_MPU6050 mpu;
ArduinoLEDMatrix matrix;

// === Deine Offset Werte hier eintragen ===
const float AX_OFFSET = -0.1467;
const float AY_OFFSET = 0.2289;
const float AZ_OFFSET = 0.3203;

// === Gleitender Mittelwert für Roll-Wert ===
#define NUM_SAMPLES 10
float rollBuffer[NUM_SAMPLES];
int bufferIndex = 0;

// Funktion zur Glättung des Roll-Werts
float getSmoothedRoll(float newRoll) {
  rollBuffer[bufferIndex] = newRoll;
  bufferIndex = (bufferIndex + 1) % NUM_SAMPLES;

  float sum = 0;
  for (int i = 0; i < NUM_SAMPLES; i++) {
    sum += rollBuffer[i];
  }
  return sum / NUM_SAMPLES;
}

void setup() {
  Serial.begin(115200);
  while (!Serial) delay(10);

  if (!mpu.begin()) {
    Serial.println("MPU6050 nicht gefunden!");
    while (1) delay(10);
  }

  matrix.begin();
  Serial.println("Wasserwaage (Roll) gestartet...");
}

void loop() {
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);

  // === Kalibrierte Beschleunigungswerte berechnen ===
  float accX = a.acceleration.x - AX_OFFSET;
  float accY = a.acceleration.y - AY_OFFSET;
  float accZ = a.acceleration.z - AZ_OFFSET;

  // === Roll-Winkel berechnen (Rotation um Y-Achse) ===
  float rawRoll = atan2(accY, sqrt(accX * accX + accZ * accZ)) * 180 / PI;
  float roll = getSmoothedRoll(rawRoll);

  // === LED-Matrix vorbereiten ===
  uint8_t frame[8][12] = {0};

  // Roll-Wert auf horizontale Matrixbreite (0–11) abbilden
  int x = map(roll, -5, 5, 0, 11);
  x = constrain(x, 0, 11);
  int y = 4; // Mittlere Zeile bleibt konstant

  frame[y][x] = 1; // Hauptpunkt setzen

  // === Kreis um Mittelpunkt bei fast waagerechter Lage ===
  if (roll >= -0.5 && roll <= 0.5) {
    if (x > 0) frame[y][x - 1] = 1;
    if (x < 11) frame[y][x + 1] = 1;
    if (y > 0) frame[y - 1][x] = 1;
    if (y < 7) frame[y + 1][x] = 1;
  }

  // === Zusätzliche Punkte bei starker Neigung ===
  if (roll > 0.5 && x < 10) {
    frame[y][x + 2] = 1;
  } else if (roll < -0.5 && x > 1) {
    frame[y][x - 2] = 1;
  }

  // === Matrix anzeigen ===
  matrix.loadPixels((uint8_t*)frame, sizeof(frame));

  // === Serielle Ausgabe zur Kontrolle ===
  Serial.print("Roll (geglättet): ");
  Serial.println(roll, 2);

  delay(100);
}



Zweiter Aufbau:

Hier jetzt ein Balance-Tracker mit Accelerometer, der mit den X- und Y-Werten den grafischen Nullpunkt sucht und anzeigt. Die LED-Matrix des Arduino zeigt visuell, ob das Werkstück im Gleichgewicht ist.

  • X-Achse: Verläuft horizontal (links/rechts).
  • Y-Achse: Verläuft vertikal (vorne/hinten).

Wie visualisiert die LED-Matrix das Gleichgewicht?

Die LED-Matrix stellt das Gleichgewicht durch eine Kombination aus fixiertem Punkt, wachsenden Balken und einem umkreisten Nullpunkt dar:

Fixierter Mittelpunkt:

  • Der zentrale Punkt bleibt immer sichtbar und repräsentiert die perfekte Balance.
  • Er dient als visuelle Referenz, um zu erkennen, wie das Werkstück geneigt ist.

Dynamische Balken:

  • Wenn das Werkstück geneigt wird, verlängern sich Balken in entgegengesetzter Richtung der Neigung.
  • Je stärker die Neigung, desto länger der Balken.
  • Dadurch sieht der Nutzer direkt, wo noch eine Korrektur nötig ist.

Umkreisung des Nullpunkts:

  • Wenn Pitch und Roll zwischen 0 und 0.5 liegen, erscheint ein Kreis um den Punkt.
  • Dieser zeigt visuell an, dass das Objekt nahezu ausbalanciert ist.
  • Er erleichtert die Feineinstellung und hilft bei der letzten Korrektur.
  • Exakte Messwerte sind im Seriellen Monitor zu sehen

Quellcode:

#include <Wire.h>
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Arduino_LED_Matrix.h>

Adafruit_MPU6050 mpu;
ArduinoLEDMatrix matrix;

// === Deine Offset Werte hier eintragen ===
const float AX_OFFSET = -0.1467;
const float AY_OFFSET = 0.2289;
const float AZ_OFFSET = 0.3203;
const float GX_OFFSET = 0.1779;
const float GY_OFFSET = 0.0222;
const float GZ_OFFSET = 0.0117;

// === Gleitende Mittelwerte ===
#define NUM_SAMPLES 10
float pitchBuffer[NUM_SAMPLES];
float rollBuffer[NUM_SAMPLES];
int bufferIndex = 0;

// Glättung für Pitch
float getSmoothedPitch(float newPitch) {
  pitchBuffer[bufferIndex] = newPitch;
  float sum = 0;
  for (int i = 0; i < NUM_SAMPLES; i++) sum += pitchBuffer[i];
  return sum / NUM_SAMPLES;
}

// Glättung für Roll
float getSmoothedRoll(float newRoll) {
  rollBuffer[bufferIndex] = newRoll;
  float sum = 0;
  for (int i = 0; i < NUM_SAMPLES; i++) sum += rollBuffer[i];
  return sum / NUM_SAMPLES;
}

void setup() {
  Serial.begin(115200);
  while (!Serial) delay(10);

  if (!mpu.begin()) {
    Serial.println("MPU6050 nicht gefunden!");
    while (1) delay(10);
  }

  matrix.begin();
  Serial.println("2D-Wasserwaage mit dynamischen Balken gestartet...");
}

void loop() {
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);

  // === Kalibrierte Beschleunigungswerte ===
  float accX = a.acceleration.x - AX_OFFSET;
  float accY = a.acceleration.y - AY_OFFSET;
  float accZ = a.acceleration.z - AZ_OFFSET;

  // === Pitch & Roll berechnen ===
  float rawPitch = atan2(accX, sqrt(accY * accY + accZ * accZ)) * 180 / PI;
  float rawRoll  = atan2(accY, sqrt(accX * accX + accZ * accZ)) * 180 / PI;

  // Pitch invertieren für korrekte Anzeige
  rawPitch = -rawPitch;

  // === Glätten ===
  float pitch = getSmoothedPitch(rawPitch);
  float roll  = getSmoothedRoll(rawRoll);
  bufferIndex = (bufferIndex + 1) % NUM_SAMPLES;

  // === LED-Matrix vorbereiten ===
  uint8_t frame[8][12] = {0};

  // Mittelpunkt der Matrix
  int centerX = 5;
  int centerY = 3;
  frame[centerY][centerX] = 1;

  // === Kreis um Mittelpunkt bei fast waagerechter Lage ===
  if (abs(pitch) <= 0.5 && abs(roll) <= 0.5) {
    if (centerX > 0) frame[centerY][centerX - 1] = 1;
    if (centerX < 11) frame[centerY][centerX + 1] = 1;
    if (centerY > 0) frame[centerY - 1][centerX] = 1;
    if (centerY < 7) frame[centerY + 1][centerX] = 1;
  }

  // === Dynamische Balkenlängen berechnen ===
  int rollLength = constrain(abs(roll) / 2, 1, 6);   // max. 6 LEDs
  int pitchLength = constrain(abs(pitch) / 2, 1, 6); // max. 6 LEDs

  // === Roll-Balken (horizontal) ===
  if (roll > 0) {
    for (int i = 1; i <= rollLength && centerX + i < 12; i++) {
      frame[centerY][centerX + i] = 1; // nach rechts
    }
  } else {
    for (int i = 1; i <= rollLength && centerX - i >= 0; i++) {
      frame[centerY][centerX - i] = 1; // nach links
    }
  }

  // === Pitch-Balken (vertikal) ===
  if (pitch > 0) {
    for (int i = 1; i <= pitchLength && centerY + i < 8; i++) {
      frame[centerY + i][centerX] = 1; // nach unten
    }
  } else {
    for (int i = 1; i <= pitchLength && centerY - i >= 0; i++) {
      frame[centerY - i][centerX] = 1; // nach oben
    }
  }

  // === Matrix anzeigen ===
  matrix.loadPixels((uint8_t*)frame, sizeof(frame));

  // === Serielle Ausgabe zur Kontrolle ===
  Serial.print("Pitch: ");
  Serial.print(pitch, 2);
  Serial.print(" | Roll: ");
  Serial.println(roll, 2);

  delay(100);
}


Dritter Aufbau:

Da du bereits zwei Messungen mit dem Accelerometer getestet hast, nun eine praktische Anwendung mit dem Gyroskop.

Echtzeit-Drehungsanzeige im Seriellen Plotter

Hier werden diese drei Achsen deutlich im Plotter angezeigt:

  • X = Drehen um die linke/rechte Achse (Kopf nicken)
  • Y = Drehen um die vordere/hintere Achse (Kopf schief legen)
  • Z = Drehen um die senkrechte Achse (Kopf schütteln / drehen)

Hier ein einfacher Sketch, der die Gyroskop-Werte (Drehgeschwindigkeit) ausliest und im seriellen Plotter darstellt:

#include <Wire.h>
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>

Adafruit_MPU6050 mpu;

void setup() {
  Serial.begin(115200);
  while (!Serial);

  mpu.begin();
  mpu.setAccelerometerRange(MPU6050_RANGE_8_G);
  mpu.setGyroRange(MPU6050_RANGE_500_DEG);
  mpu.setFilterBandwidth(MPU6050_BAND_21_HZ);

  // WICHTIG: Diese Zeile muss die erste Ausgabe sein!
  Serial.println("x\ty\tz");
}

void loop() {
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);

  Serial.print(g.gyro.x);
  Serial.print("\t");
  Serial.print(g.gyro.y);
  Serial.print("\t");
  Serial.println(g.gyro.z);

  delay(50);
}


Aufbau mit X, Y und Z-Werten ist das balancierende 2 Rad Fahrzeug:


Quelle und Datenblatt des Herstellers:
GY-521_Datenblatt

Youtube Video:



Weiterführender Artikel zum Thema:

Wer weitere Details zu diesem Modul erfahren und ohne Bibliothek weitere Optionen entdecken möchte, sollte unbedingt mal bei Wolles Elektonikkiste vorbeischauen.

,
Datenschutz-Übersicht

Diese Website verwendet Cookies, damit wir dir die bestmögliche Benutzerkomfort bieten können. Cookie-Informationen werden in deinem Browser gespeichert und führen Funktionen aus, wie das Wiedererkennen von dir, wenn du auf unsere Website zurückkehrst und hilft uns zu verstehen, welche Abschnitte der Website für dich am interessantesten und nützlichsten sind.