MPU6050

Es gibt viele Anwendungen, in denen Kenntnisse über die Neigung des Geräts von Bedeutung sind. In vielen Fällen können einfache Beschleunigungssensoren genügend Informationen liefern, da der Beschleunigungsvektor gleich der Erdbeschleunigung ist. In einigen Anwendungen kann die Neigung des Geräts nicht alleine über dessen Beschleunigungsvektor bestimmt werden. Beispielsweise kann es passieren, dass sich die Bewegungsrichtung oder die Bewegungsgeschwindigkeit des Geräts ändern.
Der Bau von kleinen Quadrocoptern hat sich in den letzten Jahren zu einem Trend entwickelt. Diese Fluggeräte benötigen für ihre Stabilisierung Informationen über ihre Neigung. Ständige Änderungen der Fluggeschwindigkeit, Flugrichtung und externe Einflüsse, wie z.B. Wind, beeinflussen die Ausgabewerte der Beschleunigungssensoren.
Für diese Zwecke wurde das sogenannte Gyroskop entwickelt. Gyroskope messen die Drehgeschwindigkeit eines Geräts. Diese Drehgeschwindigkeit misst ein Gyroskop unabhängig von dessen Linearbeschleunigung und ist dadurch geeignet zur Bestimmung der Neigung eines bewegten Geräts.
Mit dem MPU6050 existiert ein sehr mächtiges Gyroskop, in dem gleichzeitig ein Beschleunigungssensor und ein Thermometer eingebaut ist. Der MPU6050 hat einen eigenständigen Chip, auf dem eigene Algorithmen installiert werden können, welche die Rohdaten verarbeiten und die Ergebnisse in Register zum Auslesen abspeichern können. Der Chip wird über einen I2C-Bus angesteuert. Über einen weiteren I2C-Bus kann ein weiterer Sensor angeschlossen werden.
Die Möglichkeiten dieses Sensors sind enorm. Man könnte ein ganzes Buch über den MPU6050 verfassen. In diesem Tutorial werde ich lediglich zeigen, wie man die Rohdaten ausliest und auf der Konsole anzeigen lässt. Wenn ich mal mehr Zeit habe, werde ich ggf. weitere Tutorial über speziellere Aspekte des MPU6050 schreiben.
Es wird der I2C-Bus verwendet. Dieser benötigt auf eurem System ggf. eine besondere Einrichtung, sofern diese noch nicht erfolgt ist. Informationen dazu habe ich hier geschrieben.

Inhalt


Material

  • MPU6050
  • Diverse Kabel
  • Steckbrett

Aufbau

Den MPU6050 gibt es in verschiedenen Varianten zu kaufen. Dies ist der Aufbau meines MPU6050:

MPU6050
Wie immer dienen die Anschlüsse VCC und GND der Stromversorgung. Der MPU6050 benötigt eine Spannung von 3,3V. Über SCL und SDA erfolgt die I2C-Kommunikation mit dem Raspberry Pi. Ein weiterer Sensor kann über einen I2C-Bus mit den Anschlüssen XCL und XDA angesteuert werden. Jedes Gerät, dass über einen I2C-Bus angesteuert wird, hat eine feste Device-ID. Der MPU6050 hat die 0x68 als ID. Sollten zwei MPU6050 angeschlossen werden, haben beide die gleiche ID, wodurch eine Unterscheidung nicht mehr möglich ist. Mit einer Spannung an AD0 kann die Device-ID des MPU6050 auf 0x69 geändert werden. Dadurch ist es möglich, ohne weitere Hardware zwei MPU6050 anzuschließen. Ein Interrupt-Flag in einem Statusregister kann über INT gesetzt werden. Dies kann wichtig für Algorithmen sein, die direkt auf dem Chip gespeichert sind.

Der Aufbau für die Benutzung des MPU6050 ist sehr simpel:

Gesamtaufbau
Für die Kommunikation über den I2C-Bus ist es wichtig, dass die Anschlüssen SCL und SDA des Raspberry Pi verwendet werden und nicht wie sonst üblich irgendwelche beliebigen GPIO-Pins. Ich habe AD0 noch an GND angeschlossen, was man sich aber auch sparen kann, wenn man möchte.

Programm

Es müssen im Programmcode dieses mal, anders als sonst üblich, keine Anschlüsse initialisiert werden. Es kann mit einer Lesefunktion begonnen werden. Die Register im MPU6050 sind 8-Bit groß. Folglich müssen die Register byteweise ausgelesen werden:
int read_byte(int fd, char adr) {
    return wiringPiI2CReadReg8(fd , adr);
}
Hierbei ist fd der Filehandler des Geräts nach dem Setup und adr die Adresse des Registers.

Da die Sensordaten als 16-Bit Wörter vorliegen, sollte man eine Funktion schreiben, welche die Register byteweise ausliest und zu einem vorzeichenbehafteten 16-Bit-Wert zusammensetzt.
int read_word(int fd, char adr) {
    int word = read_byte(fd, adr)<<8|read_byte(fd,adr+1);

    // Zweierkomplement des 16-Bit Worts berechnen
    if(word >= 0x8000) {
        word = -(0xFFFF - word + 1);
    }

    return word;
}
In der main-Funktion können jetzt die Sensordaten in einer Programmschleife ausgelesen und ausgegeben werden:
// Device ID
#define MPU 0x68

// Command
#define WAKE_UP 0

// Registeradressen
#define ACCEL_XOUT_H 0x3B
#define ACCEL_XOUT_L 0x3C
#define ACCEL_YOUT_H 0x3D
#define ACCEL_YOUT_L 0x3E
#define ACCEL_ZOUT_H 0x3F
#define ACCEL_ZOUT_L 0x40
#define TEMP_OUT_H 0x41
#define TEMP_OUT_L 0x42
#define GYRO_XOUT_H 0x43
#define GYRO_XOUT_L 0x44
#define GYRO_YOUT_H 0x45
#define GYRO_YOUT_L 0x46
#define GYRO_ZOUT_H 0x47
#define GYRO_ZOUT_L 0x48
#define PWR_MGMT_1 0x6B

int main() {
    // Erzeugung des Filehandlers
    int fd = wiringPiI2CSetup(MPU);

    // fd == -1 wenn Device ID nicht bekannt
    if(fd == -1) {
        return 0;
    }

    int AcX, AcY, AcZ, Tmp, GyX, GyY, GyZ;
    double dAcX, dAcY, dAcZ, dTmp, dGyX, dGyY, dGyZ;

    // Diese Anweisung aktiviert den MPU6050
    wiringPiI2CWriteReg16(fd, PWR_MGMT_1, WAKE_UP);

    while(true) {
        // Rohdaten auslesen
        AcX = read_word(fd, ACCEL_XOUT_H);
        AcY = read_word(fd, ACCEL_YOUT_H);
        AcZ = read_word(fd, ACCEL_ZOUT_H);
        Tmp = read_word(fd, TEMP_OUT_H);
        GyX = read_word(fd, GYRO_XOUT_H);
        GyY = read_word(fd, GYRO_YOUT_H);
        GyZ = read_word(fd, GYRO_ZOUT_H);

        // Umrechnung der Rohdaten nach g
        dAcX = AcX/16384.0;
        dAcY = AcY/16384.0;
        dAcZ = AcZ/16384.0;

        // Umrechnung der Rohdaten nach °/s
        dGyX = GyX/131.0;
        dGyY = GyY/131.0;
        dGyZ = GyZ/131.0;

        // Umrechnung der Rohdaten nach °C
        dTmp = Tmp/340.00+36.53;

        std::cout << "MPU6050" << std::endl;
        std::cout << "Ac: x = " << dAcX << "  y = " << dAcY << "  z = " << dAcZ << std::endl;
        std::cout << "Temp: " << dTmp << std::endl;
        std::cout << "Gy: x = " << dGyX << "  y = " << dGyY << "  z = " << dGyZ << std::endl;
        std::cout << std::endl;

        delay(1000);
    }

    return 0;
}
Die Formeln für die Umrechnung der Rohdaten in physikalische Einheiten kommen aus dem Datenblatt. Diese sind u.a. abhängig von den Einstellungen des MPU6050. So kann das Gyroskop auf eines der Intervalle +/-250 °/s, +/-500 °/s, +/-1000 °/s oder +/-2000 °/s eingestellt werden. Je kleiner das Intervall, desto genauer können die Werte auf 16 Bit dargestellt werden. Es wirkt so, als würden sich die Werte ständig ändern, ohne dass man den Sensor bewegt. Dies kann auf dem ersten Blick verwirren. Tatsächlich ändern sich die Werte nicht großartig. Mit 16 Bit langen Wörtern können die Sensordaten mit einer sehr hohen Genauigkeit abgebildet werden. Dadurch werden auch extrem kleine Änderungen sichtbar.

Leider kann ich in einem Tutorial nicht das gesamte Potential des MPU6050 präsentieren, welches wirklich enorm ist. Es existieren umfangreiche Bibliotheken, welche viele Funktionen für die Benutzung des Sensors bereitstellen. Mit mehr Zeit werde ich weitere Tutorials zum MPU6050 schreiben, welche auf speziellere Funktionen eingehen.

Ich hoffe dieses Tutorial hat euch bei der Verwendung des MPU6050 weitergeholfen oder euch seinen Nutzen näher gebracht und euch zum Kauf angeregt. Für weitere Informationen zum Sensor siehe:

Keine Kommentare:

Kommentar veröffentlichen

Hinweis: Nur ein Mitglied dieses Blogs kann Kommentare posten.