Manufactura industrial
Internet industrial de las cosas | Materiales industriales | Mantenimiento y reparación de equipos | Programación industrial |
home  MfgRobots >> Manufactura industrial >  >> Manufacturing Technology >> Proceso de manufactura

Domina el MPU6050: Tutorial acelerómetro y giroscopio para Arduino

En este tutorial aprenderemos a usar el sensor MPU6050 Acelerómetro y Giroscopio con Arduino. Primero explico cómo funciona el MPU6050 y cómo leer sus datos, luego haremos dos ejemplos prácticos.

Puedes ver el vídeo o leer el tutorial escrito.

Resumen

En el primer ejemplo, usando el entorno Processing, haremos una visualización 3D de la orientación del sensor. En el segundo, una plataforma autoestabilizada simple / DIY Gimbal. Basándonos en la orientación del MPU6050 y sus datos fusionados (acelerómetro + giroscopio), controlamos tres servos que mantienen la plataforma nivelada.

Cómo funciona

El MPU6050 IMU integra en un solo chip: acelerómetro 3 ejes y giroscopio 3 ejes.

El giroscopio mide velocidad rotacional (tasa de cambio de posición angular en el tiempo) en ejes X, Y, Z. Usa tecnología MEMS y efecto Coriolis (detalles en mi tutorial Cómo funcionan sensores MEMS). Salidas en grados/segundo; para obtener posición angular integramos la velocidad angular.

Domina el MPU6050: Tutorial acelerómetro y giroscopio para Arduino

El acelerómetro MPU6050 mide aceleración igual que el ADXL345 (explicado en vídeo anterior). Mide aceleración gravitatoria en 3 ejes; con trigonometría calculamos el ángulo de inclinación del sensor.

Si fusionamos (combinamos) datos de acelerómetro y giroscopio, obtenemos información muy precisa sobre la orientación del sensor.

El MPU6050 IMU también se llama dispositivo de seguimiento de movimiento 6 ejes o 6 DoF (6 Grados de Libertad), por sus 6 salidas (3 acelerómetro + 3 giroscopio).

Arduino y MPU6050

Veamos cómo conectar y leer datos del MPU6050 con Arduino. Usamos protocolo I2C: solo 2 hilos para comunicación + 2 para alimentación.

Domina el MPU6050: Tutorial acelerómetro y giroscopio para Arduino

Componentes necesarios:

  • IMU MPU6050 …………………………..…. Amazon / Banggood / AliExpress
  • Placa Arduino ………………………….…..
  • Protoboard y cables jumpers …………

Código Arduino MPU6050

Código para leer datos del MPU6050. Descripción detallada debajo.

/* Arduino y MPU6050 Acelerómetro y Giroscopio por Dejan, https://howtomechatronics.com */
#include <Wire.h>
const int MPU = 0x68; // Dirección I2C MPU6050
float AccX, AccY, AccZ;
float GyroX, GyroY, GyroZ;
float accAngleX, accAngleY, gyroAngleX, gyroAngleY, gyroAngleZ;
float roll, pitch, yaw;
float AccErrorX, AccErrorY, GyroErrorX, GyroErrorY, GyroErrorZ;
float elapsedTime, currentTime, previousTime;
int c = 0;

void setup() {
  Serial.begin(19200);
  Wire.begin(); // Inicializa comunicación I2C
  Wire.beginTransmission(MPU); // Inicia comunicación con MPU6050
  Wire.write(0x6B); // Registro 6B (PWR_MGMT_1)
  Wire.write(0x00); // Reset - pone 0 en registro 6B
  Wire.endTransmission(true);
  /*
  // Configurar sensibilidad acelerómetro - Rango completa (default ±2g)
  Wire.beginTransmission(MPU);
  Wire.write(0x1C); // Registro ACCEL_CONFIG (1C hex)
  Wire.write(0x10); // Bits 00010000 (±8g rango completo)
  Wire.endTransmission(true);
  // Configurar sensibilidad giroscopio - Rango completa (default ±250°/s)
  Wire.beginTransmission(MPU);
  Wire.write(0x1B); // Registro GYRO_CONFIG (1B hex)
  Wire.write(0x10); // Bits 00010000 (1000°/s rango completo)
  Wire.endTransmission(true);
  delay(20);
  */
  // Llama a esta función si necesitas valores de error IMU para tu módulo
  calculate_IMU_error();
  delay(20);
}

void loop() {
  // === Leer datos acelerómetro ===
  Wire.beginTransmission(MPU);
  Wire.write(0x3B); // Registro inicial 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU, 6, true); // Lee 6 registros (2 por eje)
  // Rango ±2g: dividir valores raw por 16384 (según datasheet)
  AccX = (Wire.read() << 8 | Wire.read()) / 16384.0; // X
  AccY = (Wire.read() << 8 | Wire.read()) / 16384.0; // Y
  AccZ = (Wire.read() << 8 | Wire.read()) / 16384.0; // Z

  // Calcular Roll y Pitch desde datos acelerómetro
  accAngleX = (atan(AccY / sqrt(pow(AccX, 2) + pow(AccZ, 2))) * 180 / PI) - 0.58; // AccErrorX ~(0.58)
  accAngleY = (atan(-1 * AccX / sqrt(pow(AccY, 2) + pow(AccZ, 2))) * 180 / PI) + 1.58; // AccErrorY ~(-1.58)

  // === Leer datos giroscopio ===
  previousTime = currentTime;
  currentTime = millis();
  elapsedTime = (currentTime - previousTime) / 1000.0; // Segundos

  Wire.beginTransmission(MPU);
  Wire.write(0x43); // Registro inicial giroscopio 0x43
  Wire.endTransmission(false);
  Wire.requestFrom(MPU, 6, true); // Lee 6 registros
  // Rango 250°/s: dividir raw por 131.0 (datasheet)
  GyroX = (Wire.read() << 8 | Wire.read()) / 131.0;
  GyroY = (Wire.read() << 8 | Wire.read()) / 131.0;
  GyroZ = (Wire.read() << 8 | Wire.read()) / 131.0;

  // Corregir salidas con errores calculados
  GyroX = GyroX + 0.56;  // GyroErrorX ~(-0.56)
  GyroY = GyroY - 2;     // GyroErrorY ~(2)
  GyroZ = GyroZ + 0.79;  // GyroErrorZ ~(-0.8)

  // Raw en °/s → multiplicar por segundos para obtener ángulo en grados
  gyroAngleX = gyroAngleX + GyroX * elapsedTime;
  gyroAngleY = gyroAngleY + GyroY * elapsedTime;
  yaw = yaw + GyroZ * elapsedTime;

  // Filtro complementario - combinar ángulos acelerómetro y giroscopio
  roll = 0.96 * gyroAngleX + 0.04 * accAngleX;
  pitch = 0.96 * gyroAngleY + 0.04 * accAngleY;

  // Imprimir en monitor serial
  Serial.print(roll); Serial.print("/");
  Serial.print(pitch); Serial.print("/");
  Serial.println(yaw);
}

void calculate_IMU_error() {
  // Llamar en setup para calcular errores acelerómetro y giroscopio.
  // Imprime valores de error usados en ecuaciones anteriores.
  // Nota: colocar IMU en posición plana para valores correctos.

  // Leer acelerómetro 200 veces
  while (c < 200) {
    Wire.beginTransmission(MPU);
    Wire.write(0x3B);
    Wire.endTransmission(false);
    Wire.requestFrom(MPU, 6, true);
    AccX = (Wire.read() << 8 | Wire.read()) / 16384.0;
    AccY = (Wire.read() << 8 | Wire.read()) / 16384.0;
    AccZ = (Wire.read() << 8 | Wire.read()) / 16384.0;
    // Sumar lecturas
    AccErrorX = AccErrorX + ((atan((AccY) / sqrt(pow((AccX), 2) + pow((AccZ), 2))) * 180 / PI));
    AccErrorY = AccErrorY + ((atan(-1 * (AccX) / sqrt(pow((AccY), 2) + pow((AccZ), 2))) * 180 / PI));
    c++;
  }
  // Promedio error
  AccErrorX = AccErrorX / 200;
  AccErrorY = AccErrorY / 200;
  c = 0;

  // Leer giroscopio 200 veces
  while (c < 200) {
    Wire.beginTransmission(MPU);
    Wire.write(0x43);
    Wire.endTransmission(false);
    Wire.requestFrom(MPU, 6, true);
    GyroX = Wire.read() << 8 | Wire.read();
    GyroY = Wire.read() << 8 | Wire.read();
    GyroZ = Wire.read() << 8 | Wire.read();
    // Sumar lecturas
    GyroErrorX = GyroErrorX + (GyroX / 131.0);
    GyroErrorY = GyroErrorY + (GyroY / 131.0);
    GyroErrorZ = GyroErrorZ + (GyroZ / 131.0);
    c++;
  }
  // Promedio error
  GyroErrorX = GyroErrorX / 200;
  GyroErrorY = GyroErrorY / 200;
  GyroErrorZ = GyroErrorZ / 200;

  // Imprimir errores en Serial Monitor
  Serial.print("AccErrorX: "); Serial.println(AccErrorX);
  Serial.print("AccErrorY: "); Serial.println(AccErrorY);
  Serial.print("GyroErrorX: "); Serial.println(GyroErrorX);
  Serial.print("GyroErrorY: "); Serial.println(GyroErrorY);
  Serial.print("GyroErrorZ: "); Serial.println(GyroErrorZ);
}

Descripción del código: Incluimos Wire.h para I2C y definimos variables para almacenar datos.

En setup(): inicializamos Wire y reseteamos sensor via registro gestión de potencia. En datasheet vemos dirección del registro.

Domina el MPU6050: Tutorial acelerómetro y giroscopio para Arduino

Opcionalmente, podemos seleccionar rango completo (Full-Scale Range) para acelerómetro y giroscopio via registros de configuración. Usaremos default ±2g (acel) y ±250°/s (gyro), así que dejo comentado.

// Configure Accelerometer Sensitivity - Full Scale Range (default +/- 2g)
Wire.beginTransmission(MPU);
Wire.write(0x1C); //Talk to the ACCEL_CONFIG register (1C hex)
Wire.write(0x10); //Set the register bits as 00010000 (+/- 8g full scale range)
Wire.endTransmission(true);
// Configure Gyro Sensitivity - Full Scale Range (default +/- 250deg/s)
Wire.beginTransmission(MPU);
Wire.write(0x1B); // Talk to the GYRO_CONFIG register (1B hex)
Wire.write(0x10); // Set the register bits as 00010000 (1000deg/s full scale)
Wire.endTransmission(true);
*/

En loop() leemos acelerómetro. Datos de cada eje en 2 bytes/registros; direcciones en datasheet.

Domina el MPU6050: Tutorial acelerómetro y giroscopio para Arduino

Para leer todos, empezamos en primer registro y con requestFrom() pedimos 6 registros (X, Y, Z). Leemos cada registro, combinamos apropiadamente (complemento a dos) para valores correctos.

// === Read acceleromter data ===
Wire.beginTransmission(MPU);
Wire.write(0x3B); // Start with register 0x3B (ACCEL_XOUT_H)
Wire.endTransmission(false);
Wire.requestFrom(MPU, 6, true); // Read 6 registers total
//For a range of +-2g, we need to divide the raw values by 16384, according to the datasheet
AccX = (Wire.read() << 8 | Wire.read()) / 16384.0; // X-axis value
AccY = (Wire.read() << 8 | Wire.read()) / 16384.0; // Y-axis value
AccZ = (Wire.read() << 8 | Wire.read()) / 16384.0; // Z-axis value

Para obtener valores -1g a +1g (aptos para calcular ángulos), dividimos por la sensibilidad seleccionada.

Domina el MPU6050: Tutorial acelerómetro y giroscopio para Arduino

Con estas fórmulas calculamos roll y pitch desde datos acelerómetro:

// Calculating Roll and Pitch from the accelerometer data
accAngleX = (atan(AccY / sqrt(pow(AccX, 2) + pow(AccZ, 2))) * 180 / PI) - 0.58; // AccErrorX ~(0.58)
accAngleY = (atan(-1 * AccX / sqrt(pow(AccY, 2) + pow(AccZ, 2))) * 180 / PI) + 1.58; // AccErrorY ~(-1.58)

Luego leemos giroscopio mismo método.

Domina el MPU6050: Tutorial acelerómetro y giroscopio para Arduino

Leemos 6 registros giroscopio, combinamos datos y dividimos por sensibilidad para obtener °/s.

// === Read gyroscope data ===
previousTime = currentTime;
currentTime = millis();
elapsedTime = (currentTime - previousTime) / 1000;
Wire.beginTransmission(MPU);
Wire.write(0x43); // Gyro data first register address 0x43
Wire.endTransmission(false);
Wire.requestFrom(MPU, 6, true);
GyroX = (Wire.read() << 8 | Wire.read()) / 131.0;
GyroY = (Wire.read() << 8 | Wire.read()) / 131.0;
GyroZ = (Wire.read() << 8 | Wire.read()) / 131.0;
Domina el MPU6050: Tutorial acelerómetro y giroscopio para Arduino

Corrijo salidas con pequeños errores calculados (explico cómo obtenerlos). Salidas en °/s → multiplicar por tiempo para obtener grados. Tiempo capturado cada iteración con millis().

// Correct the outputs with the calculated error values
GyroX = GyroX + 0.56; // GyroErrorX ~(-0.56)
GyroY = GyroY - 2;    // GyroErrorY ~(2)
GyroZ = GyroZ + 0.79; // GyroErrorZ ~ (-0.8)
// Currently the raw values are in degrees per seconds, deg/s, so we need to multiply by sendonds (s) to get the angle in degrees
gyroAngleX = gyroAngleX + GyroX * elapsedTime; // deg/s * s = deg
gyroAngleY = gyroAngleY + GyroY * elapsedTime;
yaw = yaw + GyroZ * elapsedTime;

Finalmente, fusionamos acelerómetro y giroscopio con filtro complementario. Tomamos 96% giroscopio (muy preciso, no sufre fuerzas externas) y 4% acelerómetro (elimina deriva giroscopio a largo plazo).

// Complementary filter - combine acceleromter and gyro angle values
roll = 0.96 * gyroAngleX + 0.04 * accAngleX;
pitch = 0.96 * gyroAngleY + 0.04 * accAngleY;

No podemos calcular Yaw desde acelerómetro → no aplicamos filtro complementario en Yaw.

Antes de ver resultados, explico cómo obtener valores de corrección de error. Llamamos a calculate_IMU_error() en setup() con sensor en posición plana quieta. Hacemos 200 lecturas por eje, sumamos y dividimos entre 200. En posición plana, salida esperada = 0. Así obtenemos error promedio del sensor.

void calculate_IMU_error() {
  // We can call this funtion in the setup section to calculate the accelerometer and gyro data error.
  // From here we will get the error values used in the above equations printed on the Serial Monitor.
  // Note that we should place the IMU flat in order to get the proper values, so that we then can the correct values
  // Read accelerometer values 200 times
  while (c < 200) {
    Wire.beginTransmission(MPU);
    Wire.write(0x3B);
    Wire.endTransmission(false);
    Wire.requestFrom(MPU, 6, true);
    AccX = (Wire.read() << 8 | Wire.read()) / 16384.0 ;
    AccY = (Wire.read() << 8 | Wire.read()) / 16384.0 ;
    AccZ = (Wire.read() << 8 | Wire.read()) / 16384.0 ;
    // Sum all readings
    AccErrorX = AccErrorX + ((atan((AccY) / sqrt(pow((AccX), 2) + pow((AccZ), 2))) * 180 / PI));
    AccErrorY = AccErrorY + ((atan(-1 * (AccX) / sqrt(pow((AccY), 2) + pow((AccZ), 2))) * 180 / PI));
    c++;
  }
  //Divide the sum by 200 to get the error value
  AccErrorX = AccErrorX / 200;
  AccErrorY = AccErrorY / 200;
  c = 0;
  // Read gyro values 200 times
  while (c < 200) {
    Wire.beginTransmission(MPU);
    Wire.write(0x43);
    Wire.endTransmission(false);
    Wire.requestFrom(MPU, 6, true);
    GyroX = Wire.read() << 8 | Wire.read();
    GyroY = Wire.read() << 8 | Wire.read();
    GyroZ = Wire.read() << 8 | Wire.read();
    // Sum all readings
    GyroErrorX = GyroErrorX + (GyroX / 131.0);
    GyroErrorY = GyroErrorY + (GyroY / 131.0);
    GyroErrorZ = GyroErrorZ + (GyroZ / 131.0);
    c++;
  }
  //Divide the sum by 200 to get the error value
  GyroErrorX = GyroErrorX / 200;
  GyroErrorY = GyroErrorY / 200;
  GyroErrorZ = GyroErrorZ / 200;
  // Print the error values on the Serial Monitor
  Serial.print("AccErrorX: "); Serial.println(AccErrorX);
  Serial.print("AccErrorY: "); Serial.println(AccErrorY);
  Serial.print("GyroErrorX: "); Serial.println(GyroErrorX);
  Serial.print("GyroErrorY: "); Serial.println(GyroErrorY);
  Serial.print("GyroErrorZ: "); Serial.println(GyroErrorZ);
}

Imprimimos valores en monitor serial y los implementamos en el código (roll, pitch y 3 ejes giroscopio).

Domina el MPU6050: Tutorial acelerómetro y giroscopio para Arduino

Finalmente, Serial.print muestra Roll, Pitch, Yaw para verificar funcionamiento.

MPU6050 Seguimiento orientación – Visualización 3D

Para visualización 3D, recibimos datos que Arduino envía por puerto serial en entorno Processing. Código completo Processing:

/* Arduino y MPU6050 IMU - Visualización 3D por Dejan, https://howtomechatronics.com */
import processing.serial.*;
import java.awt.event.KeyEvent;
import java.io.IOException;

Serial myPort;
String data="";
float roll, pitch, yaw;

void setup() {
  size(2560, 1440, P3D);
  myPort = new Serial(this, "COM7", 19200); // Comunicación serial
  myPort.bufferUntil('\n');
}

void draw() {
  translate(width/2, height/2, 0);
  background(233);
  textSize(22);
  text("Roll: " + int(roll) + " Pitch: " + int(pitch), -100, 265);
  // Rotar objeto
  rotateX(radians(-pitch));
  rotateZ(radians(roll));
  rotateY(radians(yaw));
  // Objeto 3D
  textSize(30);
  fill(0, 76, 153);
  box(386, 40, 200); // Dibujar caja
  textSize(25);
  fill(255, 255, 255);
  text("www.HowToMechatronics.com", -183, 10, 101);
}

// Leer datos del Puerto Serial
void serialEvent(Serial myPort) {
  data = myPort.readStringUntil('\n');
  if (data != null) {
    data = trim(data);
    // Separar string en "/"
    String items[] = split(data, '/');
    if (items.length > 1) {
      roll = float(items[0]);
      pitch = float(items[1]);
      yaw = float(items[2]);
    }
  }
}

Leemos datos entrantes de Arduino y los ponemos en variables Roll, Pitch, Yaw. En draw() usamos estos valores para rotar objeto 3D (caja con color y texto).

Al ejecutar, vemos que el objeto 3D sigue la orientación del sensor con buena precisión y respuesta.

Domina el MPU6050: Tutorial acelerómetro y giroscopio para Arduino

Inconveniente: Yaw deriva con el tiempo (no podemos usar filtro complementario). Para mejorar, hace falta sensor adicional: magnetómetro (corrección deriva Yaw giroscopio). Pero el MPU6050 tiene Digital Motion Processor (DMP) para cálculos onboard y eliminar deriva Yaw.

Domina el MPU6050: Tutorial acelerómetro y giroscopio para Arduino

Mismo ejemplo 3D con DMP: seguimiento preciso sin deriva Yaw. Procesador onboard también calcula y salida Cuaterniones (representan orientaciones/rotaciones 3D sin bloqueo Gimbal que ocurre con ángulos Euler).

Domina el MPU6050: Tutorial acelerómetro y giroscopio para Arduino

Obtener estos datos es más complejo: hace falta cable extra a pin digital Arduino (pin interrupción para leer este tipo de datos del MPU6050).

Domina el MPU6050: Tutorial acelerómetro y giroscopio para Arduino

Código más complejo → usamos librería i2cdevlib de Jeff Rowberg (descargable de GitHub). Incluiré enlace en artículo web.

Instalada librería, abrimos ejemplo MPU6050_DMP6. Bien comentado línea a línea.

Domina el MPU6050: Tutorial acelerómetro y giroscopio para Arduino

Podemos seleccionar salida: cuaterniones, ángulos Euler, yaw/pitch/roll, valores aceleración, cuaterniones para visualización 3D. Librería incluye sketch Processing para visualización 3D. Lo modifiqué para forma caja como ejemplo anterior. Código Processing para MPU6050_DMP6 con salida "OUTPUT_TEAPOT":

/* Arduino y MPU6050 IMU - Visualización 3D por Dejan, https://howtomechatronics.com */
import processing.serial.*;
import java.awt.event.KeyEvent;
import java.io.IOException;

Serial myPort;
String data="";
float roll, pitch, yaw;

void setup() {
  size(2560, 1440, P3D);
  myPort = new Serial(this, "COM7", 19200);
  myPort.bufferUntil('\n');
}

void draw() {
  translate(width/2, height/2, 0);
  background(233);
  textSize(22);
  text("Roll: " + int(roll) + " Pitch: " + int(pitch), -100, 265);
  rotateX(radians(-pitch));
  rotateZ(radians(roll));
  rotateY(radians(yaw));
  textSize(30);
  fill(0, 76, 153);
  box(386, 40, 200);
  textSize(25);
  fill(255, 255, 255);
  text("www.HowToMechatronics.com", -183, 10, 101);
}

void serialEvent(Serial myPort) {
  data = myPort.readStringUntil('\n');
  if (data != null) {
    data = trim(data);
    String items[] = split(data, '/');
    if (items.length > 1) {
      roll = float(items[0]);
      pitch = float(items[1]);
      yaw = float(items[2]);
    }
  }
}

Con serialEvent() recibimos cuaterniones del Arduino, y en draw() los usamos para rotar objeto 3D. Al ejecutar, vemos lo buenos que son los cuaterniones para rotar objetos en 3D.

Para no sobrecargar este tutorial, el segundo ejemplo (DIY Arduino Gimbal / Plataforma autoestabilizada) está en artículo separado.

Domina el MPU6050: Tutorial acelerómetro y giroscopio para Arduino

¡Pregunta en comentarios y revisa mi Colección de Proyectos Arduino!

Proceso de manufactura

  1. Crea un Cerrojo RFID Seguro con Arduino – Guía Paso a Paso
  2. Crea Animaciones y Juegos en LCD 16×2 con Arduino UNO
  3. Control Preciso de Servo con Arduino y MPU6050 (SG90 / MG996R)
  4. Control Arduino UNO desde Python 3 – Envío de Comandos y Demo LED
  5. Construye una Radio FM Compacta con Arduino Nano y RDA5807M
  6. Cálculo de ángulos de inclinación con MPU6050 y Arduino Nano usando Visuino
  7. Proyecto Sensor de Huella Dactilar con Arduino Nano – Tutorial Paso a Paso
  8. Construye un Mini Piano con Arduino UNO – Tutorial Paso a Paso
  9. Construye un Portátil Raspberry Pi 3 y Arduino: Guía Paso a Paso
  10. Reconocimiento de Gestos con ESP32 y Acelerómetro Arduino 101 - Tutorial DIY Fácil
  11. Tutorial Arduino para Principiantes 01: Inicia tu Primer Proyecto