AdSense

Samstag, 31. August 2013

Beschleunigungssensor MPU-6050 mit ATMega 16A auslesen

(English version) Der Beschleunigungssensor MPU-6050 ist ziemlich vielseitig, klein und billig. Er kann mit bis zu 6 V betrieben werden und liefert Beschleunigungswerte und sogar Gyroskopwerte (also Drehung in Grad pro Sekunde). So ein Sensor ist also das ideale Kernstück für einen Quadrocopter.

In diesem Post möchte ich nun auch das Auslesen mit einem ATMega zeigen, da sich der Post mit dem Raspberry PI ziemlich großer Beliebtheit erfreut (http://physudo.blogspot.de/2013/07/beschleunigungssensor-mpu-6050-mit.html). Für I2C benutze ich am ATMega diese Implementierung: http://physudo.blogspot.de/2013/07/atmega-ic-master.html.

Zuerst einmal habe ich mir zwei Funktionen gebastelt, die entweder ein Register auslesen oder in ein Register reinschreiben:

void TWIM_WriteRegister(char reg, char value)
{
    TWIM_Start(addr, TWIM_WRITE); // set device address and write mode
    TWIM_Write(reg);
    TWIM_Write(value);
    TWIM_Stop();
}

char TWIM_ReadRegister(char reg)
{
    TWIM_Start(addr, TWIM_WRITE);
    TWIM_Write(reg);
    TWIM_Stop();

    TWIM_Start(addr, TWIM_READ); // set device address and read mode
    char ret = TWIM_ReadNack();
    TWIM_Stop();
    return ret;
}


Als nächstes möchte ich die Beschleunigung bzw. die Werte des Gyrometers auslesen. Zu beachten ist, dass zuerst der Sleep Mode deaktiviert werden muss, das geschieht mit TWIM_WriteRegister(107, 0). Zum auslesen der Werte habe ich mir wieder 2 Funktionen gebaut:

double MPU6050_ReadAccel(int axis)//x = 0; y = 1; z = 2
{
  char reg = axis * 2 + 59;
  char AFS_SEL = TWIM_ReadRegister(28);
  double factor = 1<<AFS_SEL;
  factor = 16384/factor;
  int val = 0;
  double double_val = 0;
  char ret = 0;

  ret = TWIM_ReadRegister(reg);
  val = ret << 8;

  ret = TWIM_ReadRegister(reg+1);  
  val += ret;

  if (val & 1<<15)
  val -= 1<<16;


   
  double_val = val;
 
  double_val = double_val / factor;

  return double_val;
}

double MPU6050_ReadGyro(int axis)//x = 0; y = 1; z = 2
{
  char reg = axis * 2 + 67;
  char FS_SEL = TWIM_ReadRegister(27);
  double factor = 1<<FS_SEL;
  factor = 131/factor;
  int val = 0;
  double double_val = 0;
  char ret = 0;

  ret = TWIM_ReadRegister(reg);
  val = ret << 8;

  ret = TWIM_ReadRegister(reg+1);  
  val += ret;

  if (val & 1<<15)
  val -= 1<<16;


  double_val = val;

  double_val = double_val / factor;

  return double_val;
}


Die Werte sind in Grad / Sekunde für das Gyrometer und in Einheiten von g für den Beschleunigungsmesser, mehr dazu gibt es auch in der Register Map, besonders bei der Erklärung von FS_SEL und AFS_SEL: http://www.invensense.com/mems/gyro/documents/RM-MPU-6000A.pdf

6 Kommentare:

  1. Vielen Dank für das Blog Post, es hat mir geholfen erste Versuche mit dem MP6050 zu machen.

    Ein paar Anmerkungen:
    - Damit ReadGyro und ReadAccel funktionieren muss der MP6050 zunächst aus dem Sleep Mode geweckt werden:

    TWIM_WriteRegister(107,0);

    - Die Verwendung von "double" als Datentyp ist unnötiger Overkill, gerade auf dem AVR. Die Quelldaten besitzen nur eine Genauigkeit on 16bit. Die 23 Bit Mantisse von single-float reicht aus.

    AntwortenLöschen
    Antworten
    1. Danke für die Anmerkung mit dem Sleep Mode, das habe ich nur in dem anderen Post mit dem Raspberry PI drin, werde es aber hier gleich mal ergänzen.

      Löschen
  2. Hallo,

    der Code kann so nicht funktionieren, da double_val ausgegeben wird, das Ergebnis der Rechnung aber in val gespeichert wird (double_val wird nach der Initialisierung mit 0 nicht mehr benutzt).

    AntwortenLöschen
    Antworten
    1. Anscheinend haben mir meine Augen einen Streich gespielt. Die Zeile double_val = val hat entweder gefehlt oder ich habe sie schlicht und ergreifend übersehen. Sorry!

      Löschen
    2. Nein, ich hab es korrigiert :-) du hast es also schon richtig gesehen, die Zeile hat gefehlt, danke für den Hinweis!

      Löschen
    3. So schnell kann man an seinem Verstand zweifeln! :-)

      Übrigens gibt Atmel Studio 6.1 beim Kompilieren beider 16Bit-Bitverschiebungen Warnungen aus: "left shift count >= width of type [enabled by default]"

      Mit folgendem Code klappt es auch ohne Warnung:

      signed int val = 0;
      ...
      ret = TWIM_ReadRegister(reg);
      val = ret << 8;

      ret = TWIM_ReadRegister(reg+1);
      val |= ret;

      val enthält dann gleich den signed Wert aus High- und Lowbyte.

      Großes Kompliment für deine Seite. Die Anmerkungen zum MPU-6050 haben mir wirklich weiter geholfen! :-)

      Löschen