usar-arduino-con-los-imu-de-9dof-mpu-9150-y-mpu-9250

Usar Arduino con los IMU de 9DOF MPU-9150 y MPU-9250

¿Qué es un IMU MPU-9150 o MPU-9250?

Los sensores MPU-9150 y MPU-9250 son IMU de 9DOF nueva generación fabricado por Invensense. Ambos dispositivos forman parte de la misma familia de componentes, siendo el MPU-9250 el modelo actual y recomendado por el fabricante.

Internamente, el MPU-9250 incorpora en un mismo integrado una IMU MPU-6500, que a su vez está formado por acelerómetro de 3DOF y un giroscopio de 3DOF, y un magnetómetro AK8963 de 3DOF fabricado por Asahi Kasei Microdevices Corporation. Por su parte, el MPU-9150 está formado por una IMU MPU-6050 y un magnetómetro AK8975.

La comunicación en ambos modelos puede realizarse tanto por bus SPI como por bus I2C, por lo que es sencillo obtener los datos medidos. La tensión de alimentación es de bajo voltaje entre 2.4 a 3.6V.

Frecuentemente se encuentran integrados en módulos que incorporan la electrónica necesaria para conectarla de forma sencilla a un Arduino. En la mayoría de los módulos, esto incluye un regulador de voltaje que permite alimentar directamente a 5V.

Es un sensor consume 3.5mA, con todos los sensores y el DMP activados. Dispone de un sensor de temperatura embebido, un reloj de alta precisión e interrupciones programables. También puede conectarse con otros dispositivos I2C.

Dispone de conversores analógicos digitales (ADC) de 16bits. El rango del acelerómetro puede ser ajustado a ±2g, ±4g, ±8g, y ±16g, el del giroscopio a ±250, ±500, ±1000, and ±2000°/sec, y el del magnetómetro hasta ±4800µT.

El MPU-9250 incorpora un procesador interno (DMP Digital Motion Processor) que ejecuta complejos algoritmos de MotionFusion para combinar las mediciones de los sensores internos, evitando tener que realizar los filtros de forma exterior.

El MPU-9250 es un IMU de nueva generación, que proporciona resultados superiores a otros IMUs como el MPU-6050. Al incorporar un magnetómetro, el MPU-9250 elimina la deriva (drift) que puede aparecer en otros IMUs al cabo de unas horas de uso.

Pese a su precio superior, usaremos el MPU-9250 cuando necesitemos un IMU de características superiores, por ejemplo, en vehículos o robots que requieren precisión durante tiempos prolongados.

Precio

El MPU-9250 es un sensor con una gran relación entre calidad y precio. Podemos encontrarlo por unos 3.60€, en vendedores internacionales de AliExpress o eBay.

arduino-mpu6050-componente-1

Lógicamente, su precio es muy superior a los IMUs de 6DOF. Sin embargo, es uno de los IMUs de 9DOF más baratos.

Además, frente a otros IMUs de 9DOF dispone la ventaja de disponer de los tres sensores (acelerómetro, giroscopio y magnetómetro) en el mismo integrado, por lo que su DMP puede realizar cálculos y correcciones con las mediciones de los tres sensores de forma simultánea.

En los restantes IMUs de 9DOF estos cálculos deben realizarse de forma externa, lo que supone una pérdida de precisión y rendimiento.

Esquema de montaje

La conexión es sencilla, simplemente alimentamos el módulo desde Arduino mediante GND y 5V y conectamos el pin SDA y SCL de Arduino con los pines correspondientes del sensor.

arduino-mpu6050-esquema-1

Mientras que la conexión vista desde el lado de Arduino quedaría así.

arduino-mpu6050-conexion-1

En Arduino Uno, Nano y Mini Pro, SDA es el pin A4 y el SCK el pin A5. Para otros modelos de Arduino consultar el esquema patillaje correspondiente.

Verificar que vuestra placa es compatible con 5V antes de conectarla a Arduino. Si no, tendréis que usar un adaptador de nivel lógico.

Ejemplos de código

El siguiente ejemplo emplea el bus I2C para realizar la lectura de los valores RAW del MPU-9250.

//GND - GND
//VCC - VCC
//SDA - Pin A4
//SCL - Pin A5

#include <Wire.h>


#define    MPU9250_ADDRESS            0x68

#define    MAG_ADDRESS                0x0C


#define    GYRO_FULL_SCALE_250_DPS    0x00  

#define    GYRO_FULL_SCALE_500_DPS    0x08

#define    GYRO_FULL_SCALE_1000_DPS   0x10

#define    GYRO_FULL_SCALE_2000_DPS   0x18


#define    ACC_FULL_SCALE_2_G        0x00  

#define    ACC_FULL_SCALE_4_G        0x08

#define    ACC_FULL_SCALE_8_G        0x10

#define    ACC_FULL_SCALE_16_G       0x18

//Funcion auxiliar lectura
void I2Cread(uint8_t Address, uint8_t Register, uint8_t Nbytes, uint8_t* Data)
{
  Wire.beginTransmission(Address);
  Wire.write(Register);
  Wire.endTransmission();

  Wire.requestFrom(Address, Nbytes);
  uint8_t index = 0;
  while (Wire.available())
    Data[index++] = Wire.read();
}

// Funcion auxiliar de escritura
void I2CwriteByte(uint8_t Address, uint8_t Register, uint8_t Data)
{
  Wire.beginTransmission(Address);
  Wire.write(Register);
  Wire.write(Data);
  Wire.endTransmission();
}

void setup()
{
  Wire.begin();
  Serial.begin(115200);

  // Configurar acelerometro
  I2CwriteByte(MPU9250_ADDRESS, 28, ACC_FULL_SCALE_16_G);
  // Configurar giroscopio
  I2CwriteByte(MPU9250_ADDRESS, 27, GYRO_FULL_SCALE_2000_DPS);
  // Configurar magnetometro
  I2CwriteByte(MPU9250_ADDRESS, 0x37, 0x02);
  I2CwriteByte(MAG_ADDRESS, 0x0A, 0x01);
}

void loop()
{
  // ---  Lectura acelerometro y giroscopio --- 
  uint8_t Buf[14];
  I2Cread(MPU9250_ADDRESS, 0x3B, 14, Buf);

  // Convertir registros acelerometro
  int16_t ax = -(Buf[0] << 8 | Buf[1]);
  int16_t ay = -(Buf[2] << 8 | Buf[3]);
  int16_t az = Buf[4] << 8 | Buf[5];

  // Convertir registros giroscopio
  int16_t gx = -(Buf[8] << 8 | Buf[9]);
  int16_t gy = -(Buf[10] << 8 | Buf[11]);
  int16_t gz = Buf[12] << 8 | Buf[13];

  // ---  Lectura del magnetometro --- 
  uint8_t ST1;
  do
  {
    I2Cread(MAG_ADDRESS, 0x02, 1, &ST1);
  } while (!(ST1 & 0x01));

  uint8_t Mag[7];
  I2Cread(MAG_ADDRESS, 0x03, 7, Mag);

  // Convertir registros magnetometro
  int16_t mx = -(Mag[3] << 8 | Mag[2]);
  int16_t my = -(Mag[1] << 8 | Mag[0]);
  int16_t mz = -(Mag[5] << 8 | Mag[4]);

  // --- Mostrar valores ---

  // Acelerometro
  Serial.print(ax, DEC);
  Serial.print("\t");
  Serial.print(ay, DEC);
  Serial.print("\t");
  Serial.print(az, DEC);
  Serial.print("\t");

  // Giroscopio
  Serial.print(gx, DEC);
  Serial.print("\t");
  Serial.print(gy, DEC);
  Serial.print("\t");
  Serial.print(gz, DEC);
  Serial.print("\t");

  // Magnetometro
  Serial.print(mx + 200, DEC);
  Serial.print("\t");
  Serial.print(my - 70, DEC);
  Serial.print("\t");
  Serial.print(mz - 700, DEC);
  Serial.print("\t");
  
  // Fin medicion
  Serial.println("");
  
  delay(10);    
}

Ejemplo con RTIMULIB-Arduino

Otra opción para la lectura del sensor es emplear la librería RTIMULIB-Arduino, que permite crear un sistema AHRS ((Attitude Heading Reference Systems) y funciona con una gran variedad de sensores. Vimos como emplear esta librería en esta entrada.

Descarga el código

Todo el código de esta entrada está disponible para su descarga en Github. github-full