domingo, 15 de octubre de 2017

Tutorial #23 ESP8266 – Obtener Inclinación con MPU6050 (GY-521)

En el tutorial de hoy explico como hacer un dispositivo de IOT (internet de las cosas) que nos permite obtener la inclinación en X, Y y Z (roll, pitch y yaw). Para esto voy a explicar cómo conectar un MPU6050, que es un IMU (Unidad de Medición Inercial) a un ESP8266 y a partir de un filtro complementario obtener dichos ángulos.



MPU6050:

#include <Wire.h>
 
//Direccion I2C de la IMU
#define MPU 0x68
 
//Ratios de conversion
#define A_R 16384.0 // 32768/2
#define G_R 131.0 // 32768/250
 
//Conversion de radianes a grados 180/PI
#define RAD_A_DEG = 57.295779
 
//MPU-6050 da los valores en enteros de 16 bits
//Valores RAW
int16_t AcX, AcY, AcZ, GyX, GyY, GyZ;
 
//Angulos
float Acc[2];
float Gy[3];
float Angle[3];

String valores;

long tiempo_prev;
float dt;

void setup()
{
Wire.begin(4,5); // D2(GPIO4)=SDA / D1(GPIO5)=SCL
Wire.beginTransmission(MPU);
Wire.write(0x6B);
Wire.write(0);
Wire.endTransmission(true);
Serial.begin(115200);
}

void loop()
{
   //Leer los valores del Acelerometro de la IMU
   Wire.beginTransmission(MPU);
   Wire.write(0x3B); //Pedir el registro 0x3B - corresponde al AcX
   Wire.endTransmission(false);
   Wire.requestFrom(MPU,6,true);   //A partir del 0x3B, se piden 6 registros
   AcX=Wire.read()<<8|Wire.read(); //Cada valor ocupa 2 registros
   AcY=Wire.read()<<8|Wire.read();
   AcZ=Wire.read()<<8|Wire.read();
 
   //A partir de los valores del acelerometro, se calculan los angulos Y, X
   //respectivamente, con la formula de la tangente.
   Acc[1] = atan(-1*(AcX/A_R)/sqrt(pow((AcY/A_R),2) + pow((AcZ/A_R),2)))*RAD_TO_DEG;
   Acc[0] = atan((AcY/A_R)/sqrt(pow((AcX/A_R),2) + pow((AcZ/A_R),2)))*RAD_TO_DEG;
 
   //Leer los valores del Giroscopio
   Wire.beginTransmission(MPU);
   Wire.write(0x43);
   Wire.endTransmission(false);
   Wire.requestFrom(MPU,6,true);   //A partir del 0x43, se piden 6 registros
   GyX=Wire.read()<<8|Wire.read(); //Cada valor ocupa 2 registros
   GyY=Wire.read()<<8|Wire.read();
   GyZ=Wire.read()<<8|Wire.read();
 
   //Calculo del angulo del Giroscopio
   Gy[0] = GyX/G_R;
   Gy[1] = GyY/G_R;
   Gy[2] = GyZ/G_R;

   dt = (millis() - tiempo_prev) / 1000.0;
   tiempo_prev = millis();
 
   //Aplicar el Filtro Complementario
   Angle[0] = 0.98 *(Angle[0]+Gy[0]*dt) + 0.02*Acc[0];
   Angle[1] = 0.98 *(Angle[1]+Gy[1]*dt) + 0.02*Acc[1];

   //Integración respecto del tiempo paras calcular el YAW
   Angle[2] = Angle[2]+Gy[2]*dt;
 
   //Mostrar los valores por consola
   valores = "90, " +String(Angle[0]) + "," + String(Angle[1]) + "," + String(Angle[2]) + ", -90";
   Serial.println(valores);
   
   delay(10);
}

Enlaces:
https://www.luisllamas.es/arduino-orientacion-imu-mpu-6050/
https://www.luisllamas.es/como-usar-un-acelerometro-arduino/
https://www.luisllamas.es/como-usar-un-giroscopio-arduino/
https://www.luisllamas.es/medir-la-inclinacion-imu-arduino-filtro-complementario/
https://robologs.net/2014/10/15/tutorial-de-arduino-y-mpu-6050/
http://www.naylampmechatronics.com/blog/45_Tutorial-MPU6050-Acelerómetro-y-Giroscopio.html

Librerías:
https://github.com/jrowberg/i2cdevlib/tree/master/Arduino/MPU6050
https://github.com/jrowberg/i2cdevlib/tree/master/Arduino/I2Cdev

Mapa de Registros del MPU6050:
https://www.invensense.com/wp-content/uploads/2015/02/MPU-6000-Register-Map1.pdf

14 comentarios:

  1. hola: necesito urgentemente saber como hacer que el sensor active una led cuando llegue a cierta inclinación (es para mi cohete) el único inconveniente es que se prácticamente 0 sobre arduino y aprender lo necesario para ello me costaría meses, aparte de que nadie me puede enseñar y no tengo tiempo, no se como añadir los códigos para que funcione o simplemente se le añade la librería y ya esta. Si me pudieran ayudar me seria muy útil, gracias.

    ResponderEliminar
  2. Buenas, que le pasa a la z cuando lo muestra en consola? Tiene valores de 1400 o mas grandes. Lo pregunto por que a mi me pasa lo mismo. El resto de valores TAMBIEN me aparecen demasiado grandes, pero con el tiempo se centran. Pero la Z nunca se centra...

    Por cierto el codigo no compila, declaras RAD_A_DEG, pero despues accedes a RAD_TO_DEG ...

    Estoy utilizando tu codigo en micropython. Crees que podria haber alguna diferencia substancial? (La sintaxis la cambie y todo me corre perfecto, solo ese problema con los valores grandisimos (no entre -90 y +90

    ResponderEliminar
  3. Buenas noches, antes que nada felicitaciones por la explicación. Mi problema es que utilizo ESP3226 en lugar de ESP8266. El código está cargado, pero cuando abro el monitor serial, los ángulos no se muestran y obtengo solo NaN. No se muestran ángulos en el trazador serial. ¿Puedes resolver este problema? Gracias de antemano!
    Adjunte la dirección de correo electrónico: alessio.scalese@gmail.com

    ResponderEliminar
    Respuestas
    1. Debes usar "GPIO21" y "GPIO22" estos son para la comunicación I2C sin embargo de debe hacer un ajuste en el eje Z pues no ajusta adecuadamente

      Eliminar
    2. Hola, ¿alguien ha logrado hacer el ajuste correctamente en el eje Z y puede compartir? Gracias

      Eliminar
    3. Hola, espero que ya lo tengas resuelto, pero por las dudas te paso lo que tenes que modificar. Yo estoy usando una ESP32 y los puertos de SDA y SCL son GPIO21 y GPIO22.
      En la línea 35 tenes que modificar esto:
      Wire.begin(21,22); // D21(GPIO21)=SDA / D22(GPIO22)=SCL

      PD: Muchas gracias Ing. Alejandro Alomar por el tutorial.

      Saludos!

      Eliminar
  4. como hacer este proyecto con Arduino UNO?

    ResponderEliminar
  5. Exactamente de la misma manera. Saludos.

    ResponderEliminar
  6. Exactamente de la misma manera. Saludos.

    ResponderEliminar
  7. Enhorabueno por el tutorial, está muy interesante y gracias por el aporte. Tengo una pregunta. Los ángulos medidos van desde 90 a -90. Me gustaría saber qué parte del código debo corregir para que los ángulos vayan desde 180 a -180. Muchas gracias de antemano

    ResponderEliminar
    Respuestas

    1. Perdón por algunos, error tipográfico. Soy de Brasil.
      Hola, creo que este problema está en un error en el código. En la línea 11, se crea un valor RAD_A_DEG, sin embargo, a continuación se usa un valor RAD_TO_DEGREE. Cuando uso los mismos dos, funcionó según lo deseado.

      Eliminar
  8. antes de agregar el filtro complementario los valores que se calcularon con Gy[0] = GyX/G_R; Gy[1] = GyY/G_R; Gy[2] = GyZ/G_R; corresponden al offset?

    ResponderEliminar
  9. como puedo configurar el MPU6050 para detectar el movimiento de un objeto en X, Y y Z. y a su vez active un led ya sea que haya movimiento en X o en Y o en Z.

    ResponderEliminar
  10. Hola, tengo una pregunta, al momento de conectar los pines y cargar el programa, el sensor se inicia pero no arroja ningun valor, los pines están bien conectados no entiendo por qué no los arroja

    ResponderEliminar