Es gibt nur wenige Module auf dem Markt, die in den letzten Monaten so einen Hype ausgelöst haben wie das MPU-6050 Modul. Die zwei in eins Platine vereint dabei gleich zwei beliebte Sensor-Eigenschaften: Das Modul kann gleichzeitig als Gyroskop, als auch als Beschleunigungssensor eingesetzt werden.
Wie das? Der Sensor umfasst ein 3-Achsen-Gyroskop und einen 3-Achsen-Beschleunigungssensor auf ein und demselben Chip. Dadurch können alle (!) Sensorwerte zeitgleich abgerufen werden. So ist man als Bastler immer über die aktuelle Sensorposition bestens informiert. Diese Eigenschaft ist besonders für den Modellbau sehr interessant, vornehmlich bei balancierenden Chassis oder Drohnen.
Zudem kann über einen weiteren Master I2C Bus auf externe Magnetometer oder andere Sensoren zurückgreifen, sodass auch diese Sensordaten vollumfänglich erfasst werden können.
Die Sensordaten des MPU-6050 (GY-521) im Schnellüberblick:
- Chipsatz: MPU-6050 (auch als GY-521 bekannt)
- Spannungsversorgung: 3.3 - 5V DC
- Freiheitsgerade: 6*
- Schnittstelle: I2C
- Pinabstand: 2.54 mm
Kommen wir nun zum spannenden Teil: der Praxis. Damit Ihr Euch einen schönen Überblick über die nützlichen Funktionen des MPU-6050 Moduls verschaffen könnt, haben wir für euch einen Beispiel-Schaltplan entwickelt. Dabei wird das MPU-6050 Modul von einem Funduino UNO R3 ausgelesen und die erfassten Daten ausgewertet.
Wir interessieren uns hierbei primär für die Sensordaten des Gyroskops. Dabei möchten wir die Werte der X-, Y- und Z-Achse auslesen und feststellen, ob eine Veränderung der Sensor-Lageposition stattgefunden hat. Die Veränderung der Lageposition soll uns mit farbigen LEDs dargestellt werden.
So weit, so gut: aber wie setzen wir das um?
Der Programmcode des MPU-6050 Moduls
Jetzt gehts ans Eingemachte: na ja, so halb. Denn erstmal müssen wir uns die passende Bibliothek für das MPU6050 Modul herunterladen und in unsere Arduino IDE einbinden. Die Bibliothek trägt den Namen "<MPU6050_tockn.h>" und kann direkt über die Bibliotheksverwaltung der Arduino IDE gefunden und installiert werden.
Nach diesem ersten Schritt beginnen wir mit dem eigentlichen Code. Zunächst legen wir die LED-Anschlüsse für unsere LEDs fest, die uns als Indikatoren für die Achspotition dienen sollen. Anschließend legen wir jeweils zwei Variablen für die Achspotition der drei Achsen fest.
Sicherlich stellt Ihr Euch die Frage, warum wir gleich zwei Variablen pro Achse benötigen. Da wir feststellen möchten, ob sich die Position der jeweiligen Achse verändert hat, müssen wir zunächst einmal feststellen, welchen Wert der Sensor für die aktuelle Position erfasst hat. Diesen Sensorwert des MPU-6050 sichern wir uns für einen kurzen Zeitraum in der ersten Variable.
In der zweiten Variablen wird der Wert der Achsposition wenig später erneut gespeichert. Wir können die beiden erfassten Messwerte nun miteinander vergleichen. Insofern eine Abweichnung der Position um ein zuvor definiertes Mindestmaß erfasst worden ist (in unserem Codebeispiel +-3), können davon ausgehen, dass der Sensor die Position verändert hat. In diesem Fall schalten wir die zugeordnete LED ein.
Besonders schön: die erfassten Messdaten lassen sich gut im seriellen Plotter der Arduino IDE anzeigen.
// Dieser Sketch vergleicht die Winkel der X/Y/Z Achsen mit den vorangegangenen Werten.
// Sind sie um +/-3° unterschiedlich, schaltet der Sketch LEDs. (jew.1 für POS oder für NEG)
// Achtung: Es sind nicht die absoluten Werte sondern RELATIVE Werte gegenüber der vorherigen Messung
#include <MPU6050_tockn.h> // Bibliotheken einbinden
#include <Wire.h> // <-
MPU6050 mpu6050(Wire, 0.1, 0.1); // Dämpfung der Werte. Je kleiner (Richtung"0"), um so nervöser die Werte-
// je größer (Richtung"1") um so träger die Werte
const int ledXpos =2; //***
const int ledXneg =3; // *
const int ledYpos =4; // * Festlegen der LED-Anschlüsse
const int ledYneg =5; // *
const int ledZpos =6; // *
const int ledZneg =7; //***
int xJetztPos; // Variable AKTUELLE X-Pos
int yJetztPos; // Variable AKTUELLE Y-Pos
int zJetztPos; // Variable AKTUELLE Z-Pos
int xVorPos; // Variable VORHERIGE X-Pos
int yVorPos; // Variable VORHERIGE Y-Pos
int zVorPos; // Variable VORHERIGE Z-Pos
int unterschied = 3;
void setup() { // Beginn Setup-Funktion
Serial.begin(115200); // Öffne serielle Übertragung (115200Baud) !!! Am Monitor ebenfalls einstellen !!!
pinMode(ledXpos, OUTPUT); //***
pinMode(ledXneg, OUTPUT); // *
pinMode(ledYpos, OUTPUT); // * Festlegen dass LED-Anschlüsse Ausgänge sind
pinMode(ledYneg, OUTPUT); // *
pinMode(ledZpos, OUTPUT); // *
pinMode(ledZneg, OUTPUT); //***
Wire.begin(); // Beginn I2C Protokoll
mpu6050.begin(); // Start des Gyros
mpu6050.calcGyroOffsets(); // Gyro kalkuliert seine Offsets !!! Währenddessen ruhig liegen lassen !!!
// Benutze mpu6050.calcGyroOffsets(true), um es im seriellen Monitor zu verfolgen.
delay(1000); // Darauf warten wir...
}
void loop() { // Anfang der Loop-Schleife
mpu6050.update(); // Erzeuge neuen Datensatz im Gyro
xJetztPos=(mpu6050.getGyroAngleX()); // Fordere neuen Datensatz vom Gyro an, schreibe in X Variable
yJetztPos=(mpu6050.getGyroAngleY()); // Fordere neuen Datensatz vom Gyro an, schreibe in Y Variable
zJetztPos=(mpu6050.getGyroAngleZ()); // Fordere neuen Datensatz vom Gyro an, schreibe in Z Variable
if (xJetztPos < xVorPos-(unterschied)) // Vergleiche alten Datensatz mit neuem. Unterschied < -3 ?
{digitalWrite(ledXpos, LOW); digitalWrite(ledXneg, HIGH);} // Dann schalte LEDs entsprechend
else if (xJetztPos > xVorPos+(unterschied)) // Vergleiche alten Datensatz mit neuem. Unterschied < +3 ?
{digitalWrite(ledXpos, HIGH); digitalWrite(ledXneg, LOW);} // Dann schalte LEDs entsprechend
else // Oder eben alle X LEDs aus...
{digitalWrite(ledXpos, LOW); digitalWrite(ledXneg, LOW);} // Dann schalte LEDs entsprechend
if (yJetztPos < yVorPos-(unterschied)) // Vergleiche alten Datensatz mit neuem. Unterschied < -3 ?
{digitalWrite(ledYpos, LOW); digitalWrite(ledYneg, HIGH);} // Dann schalte LEDs entsprechend
else if (yJetztPos > yVorPos+(unterschied)) // Vergleiche alten Datensatz mit neuem. Unterschied < +3 ?
{digitalWrite(ledYpos, HIGH); digitalWrite(ledYneg, LOW);} // Dann schalte LEDs entsprechend
else // Oder eben alle Y LEDs aus...
{digitalWrite(ledYpos, LOW); digitalWrite(ledYneg, LOW);} // Dann schalte LEDs entsprechend
if (zJetztPos < zVorPos-(unterschied)) // Vergleiche alten Datensatz mit neuem. Unterschied < -3 ?
{digitalWrite(ledZpos, LOW); digitalWrite(ledZneg, HIGH);} // Dann schalte LEDs entsprechend
else if (zJetztPos > zVorPos+(unterschied)) // Vergleiche alten Datensatz mit neuem. Unterschied < +3 ?
{digitalWrite(ledZpos, HIGH); digitalWrite(ledZneg, LOW);} // Dann schalte LEDs entsprechend
else // Oder eben alle Z LEDs aus...
{digitalWrite(ledZpos, LOW); digitalWrite(ledZneg, LOW);} // Dann schalte LEDs entsprechend
xVorPos=xJetztPos; // Aktualisiere den (bisher) alten Datensatz
yVorPos=yJetztPos; // Aktualisiere den (bisher) alten Datensatz
zVorPos=zJetztPos; // Aktualisiere den (bisher) alten Datensatz
// Dann kann im nächsten Durchlauf wieder gegen "vorher" verglichen werden
Serial.print(xJetztPos); // >> serieller Plotter<< gerechte Schreibweise [gib X aus]
Serial.print(" ");Serial.print(yJetztPos); // (" ") = (\t) = Neue Farbe [gib Y aus]
Serial.print(" ");Serial.println(zJetztPos); // (" ") = (\t) = Neue Farbe [gib Z aus]
delay(15); // (minimale Verzögerung beruhigt die serielle Ausgabe)
} // Ende der Loop-Schleife
// Experimentiere ruhig ein wenig mit der Dämpfung in der dritten Programmzeile
//-> MPU6050 mpu6050(Wire, 0.3, 0.3);
// oder mit dem delay() zum Schluss. Beobachte danach die Werte im >>seriellen PLOTTER <<