Mide el movimiento como un dron: MPU-6500 + Arduino UNO

Mide el movimiento como un dron: MPU-6500 + Arduino UNO

0 comments

Introducción

¿Cómo sabe un teléfono que lo giraste, o cómo logra un dron mantenerse nivelado en el aire?

En esta práctica utilizaremos el módulo MPU-6500, un sensor de movimiento de 6 ejes, junto con un Arduino UNO.

El MPU-6500 combina en un solo chip un acelerómetro de 3 ejes y un giroscopio de 3 ejes, además de un sensor de temperatura. Se comunica por I2C, por lo que solo necesita dos cables de datos.

Es muy útil para proyectos de robótica, drones, robots autobalanceados, detección de inclinación, estabilizadores y control por movimiento.

Durante esta práctica aprenderemos a identificar sus pines, conectarlo correctamente al Arduino UNO, leer sus datos y convertirlos en aceleración (g), velocidad angular (°/s) y temperatura (°C).

¿Qué es el MPU-6500?

El MPU-6500 es un sensor inercial (IMU) fabricado por InvenSense (TDK). Integra en un mismo encapsulado un acelerómetro MEMS, un giroscopio MEMS y convertidores analógico-digitales de 16 bits.

El acelerómetro mide la aceleración en tres ejes (X, Y y Z), incluida la gravedad, por lo que también sirve para saber qué tan inclinado está el sensor. El giroscopio mide qué tan rápido gira el sensor alrededor de cada eje, en grados por segundo.

A diferencia de un sensor analógico, el MPU-6500 entrega sus datos ya digitalizados: Arduino los solicita por I2C y recibe números enteros que debemos convertir a unidades reales.

Módulo acelerómetro y giroscopio MPU-6500

Módulo acelerómetro y giroscopio MPU-6500.

Características principales

Característica Valor
Modelo MPU-6500
Ejes 6 (acelerómetro de 3 ejes + giroscopio de 3 ejes)
Resolución ADC de 16 bits
Rango del acelerómetro ±2 g, ±4 g, ±8 g y ±16 g (configurable)
Rango del giroscopio ±250, ±500, ±1000 y ±2000 °/s (configurable)
Sensor de temperatura Integrado
Comunicación I2C (hasta 400 kHz) y SPI
Dirección I2C 0x68 (AD0 a GND) o 0x69 (AD0 a VCC)
Registro WHO_AM_I 0x70
Voltaje del chip (hoja de datos) 1.71 a 3.6 V
Voltaje de trabajo del módulo 2.4 a 3.3 V
Alimentación del módulo 5 V
Pines 10 (incluye tira de pines de 2.54 mm)

Los valores del chip corresponden a la hoja de datos del MPU-6500 y los del módulo a la ficha del producto en Tecneu.

¿Cómo funciona?

El funcionamiento puede dividirse en varios pasos:

  1. El acelerómetro detecta la fuerza que actúa sobre estructuras microscópicas dentro del chip, incluida la gravedad.
  2. El giroscopio detecta la rotación gracias al efecto de Coriolis sobre otras estructuras en vibración.
  3. Los convertidores internos transforman esas señales en números de 16 bits.
  4. El chip guarda los resultados en registros internos.
  5. Arduino pide esos registros mediante el bus I2C.
  6. El programa une cada pareja de bytes en un número con signo.
  7. Finalmente, divide cada valor entre la sensibilidad del sensor para obtener g, °/s o °C.

Con el rango por defecto, el acelerómetro entrega 16384 unidades por cada g y el giroscopio 131 unidades por cada grado por segundo. Por ejemplo, un sensor quieto sobre la mesa debería leer cerca de 16384 en el eje Z, es decir, 1 g.

Material necesario

  • Arduino UNO.
  • Módulo MPU-6500.
  • Protoboard.
  • Cables Dupont.
  • Cable USB para Arduino UNO.

Tabla de conexiones

MPU-6500 Arduino UNO Función
VCC 5V Alimentación
GND GND Tierra
SCL A5 Reloj I2C
SDA A4 Datos I2C
AD0 GND (opcional) Selecciona la dirección I2C 0x68
Demás pines Sin conectar No se usan en esta práctica (INT, XDA, XCL, etc.)

En el Arduino UNO, los pines del bus I2C son A4 (SDA) y A5 (SCL). El módulo se alimenta con 5 V, como indica su ficha técnica: la placa reduce ese voltaje al que necesita el chip (2.4 a 3.3 V).

Nota: el módulo tiene 10 pines, pero en esta práctica solo usamos VCC, GND, SCL y SDA. Verifica la serigrafía de tu placa antes de conectar, ya que invertir la alimentación puede dañar el sensor. Si dejas AD0 sin conectar o lo llevas a GND, la dirección es 0x68.


Conexión física del módulo MPU-6500 a la protoboard y al Arduino UNO.


Otra vista del montaje físico de las conexiones.


Diagrama de conexión del MPU-6500 con Arduino UNO: VCC a 5V, GND a GND, SCL a A5 y SDA a A4.

⚠️ Recomendación para la alimentación

El chip MPU-6500 trabaja con 3.3 V, pero este módulo incluye la electrónica necesaria para alimentarse con 5 V, por eso conectamos VCC al pin de 5V del Arduino.

Aun así, el Arduino UNO trabaja con señales de 5 V en SDA y SCL, mientras que el chip es de 3.3 V. Para pruebas es una conexión muy común y suele funcionar, pero en un montaje definitivo conviene usar un convertidor de nivel lógico entre el Arduino y el módulo.

¿Por qué usamos I2C y los pines A4 y A5?

I2C es un bus de comunicación que utiliza solo dos cables: uno de datos (SDA) y uno de reloj (SCL). Varios dispositivos pueden compartir esos mismos cables, siempre que cada uno tenga una dirección distinta.

En el Arduino UNO, el hardware I2C está en los pines A4 (SDA) y A5 (SCL), por eso no podemos elegir otros pines. La librería Wire, incluida en el IDE de Arduino, se encarga de la comunicación.

La dirección del MPU-6500 es 0x68 si el pin AD0 está a GND y 0x69 si está a VCC. Así podemos conectar dos sensores al mismo bus.

El código

Ahora podemos utilizar un programa para leer el sensor y mostrar la aceleración, la velocidad angular y la temperatura en el Monitor Serial. No necesita librerías externas, solo Wire.

// ==========================================
// ACELEROMETRO Y GIROSCOPIO MPU-6500
// ARDUINO UNO (I2C)
// ==========================================

#include <Wire.h>

const byte MPU_ADDR = 0x68;   // AD0 a GND = 0x68, AD0 a VCC = 0x69

// Registros del MPU-6500
const byte REG_WHO_AM_I = 0x75;
const byte REG_PWR_MGMT_1 = 0x6B;
const byte REG_ACCEL_XOUT_H = 0x3B;

// Sensibilidad con la configuracion por defecto
const float SENS_ACEL = 16384.0;   // LSB por g        (rango +-2 g)
const float SENS_GIRO = 131.0;     // LSB por grado/s  (rango +-250 grados/s)

void escribirRegistro(byte registro, byte valor) {
  Wire.beginTransmission(MPU_ADDR);
  Wire.write(registro);
  Wire.write(valor);
  Wire.endTransmission();
}

byte leerRegistro(byte registro) {
  Wire.beginTransmission(MPU_ADDR);
  Wire.write(registro);
  Wire.endTransmission(false);
  Wire.requestFrom(MPU_ADDR, (byte)1);
  return Wire.read();
}

// Lee dos bytes (alto y bajo) y los une en un entero con signo
int16_t leer16() {
  uint8_t alto = Wire.read();
  uint8_t bajo = Wire.read();
  return (int16_t)((alto << 8) | bajo);
}

void setup() {

  Serial.begin(9600);
  Wire.begin();

  Serial.println("================================");
  Serial.println(" MPU-6500");
  Serial.println(" ACELEROMETRO + GIROSCOPIO");
  Serial.println("================================");

  // Comprobar que el sensor responde
  byte id = leerRegistro(REG_WHO_AM_I);
  Serial.print("WHO_AM_I: 0x");
  Serial.println(id, HEX);

  if (id != 0x70) {
    Serial.println("Aviso: se esperaba 0x70 para un MPU-6500. Revisa conexiones o el modelo del modulo.");
  }

  // Sacar el sensor del modo de bajo consumo (sleep)
  escribirRegistro(REG_PWR_MGMT_1, 0x00);
  delay(100);
}

void loop() {

  // Pedir 14 bytes desde ACCEL_XOUT_H:
  // acelerometro (6), temperatura (2) y giroscopio (6)
  Wire.beginTransmission(MPU_ADDR);
  Wire.write(REG_ACCEL_XOUT_H);
  Wire.endTransmission(false);
  Wire.requestFrom(MPU_ADDR, (uint8_t)14);

  if (Wire.available() < 14) {
    Serial.println("Error: el sensor no responde");
    delay(1000);
    return;
  }

  int16_t ax = leer16();
  int16_t ay = leer16();
  int16_t az = leer16();
  int16_t temp = leer16();
  int16_t gx = leer16();
  int16_t gy = leer16();
  int16_t gz = leer16();

  // Convertir las lecturas crudas a unidades reales
  float axg = ax / SENS_ACEL;
  float ayg = ay / SENS_ACEL;
  float azg = az / SENS_ACEL;

  float gxd = gx / SENS_GIRO;
  float gyd = gy / SENS_GIRO;
  float gzd = gz / SENS_GIRO;

  float temperatura = temp / 333.87 + 21.0;

  Serial.print("Acel (g): ");
  Serial.print(axg, 2);
  Serial.print(" | ");
  Serial.print(ayg, 2);
  Serial.print(" | ");
  Serial.print(azg, 2);

  Serial.print("   Giro (grados/s): ");
  Serial.print(gxd, 1);
  Serial.print(" | ");
  Serial.print(gyd, 1);
  Serial.print(" | ");
  Serial.print(gzd, 1);

  Serial.print("   Temp: ");
  Serial.print(temperatura, 1);
  Serial.println(" C");

  delay(500);
}

¿Qué hace el programa?

Primero incluimos la librería Wire y definimos la dirección I2C del sensor:

#include <Wire.h>

const byte MPU_ADDR = 0x68;

Después definimos la sensibilidad del acelerómetro y del giroscopio con la configuración por defecto. Con ellas convertiremos los números del sensor a unidades reales:

const float SENS_ACEL = 16384.0;   // LSB por g
const float SENS_GIRO = 131.0;     // LSB por grado/s

En el setup() leemos el registro WHO_AM_I. Un MPU-6500 responde 0x70; si recibimos otro valor, el programa avisa que algo no coincide (cableado, dirección o modelo del módulo):

byte id = leerRegistro(REG_WHO_AM_I);

El sensor arranca en modo de bajo consumo (sleep), así que escribimos 0 en el registro PWR_MGMT_1 para despertarlo:

escribirRegistro(REG_PWR_MGMT_1, 0x00);

En el loop() pedimos 14 bytes seguidos a partir del registro 0x3B. Contienen, en este orden, el acelerómetro (X, Y, Z), la temperatura y el giroscopio (X, Y, Z), con 2 bytes por cada valor:

Wire.requestFrom(MPU_ADDR, (uint8_t)14);

La función leer16() une el byte alto y el bajo en un número con signo:

int16_t leer16() {
  uint8_t alto = Wire.read();
  uint8_t bajo = Wire.read();
  return (int16_t)((alto << 8) | bajo);
}

Finalmente dividimos entre la sensibilidad para obtener las unidades reales. La temperatura usa la fórmula de la hoja de datos del MPU-6500:

float axg = ax / SENS_ACEL;
float gxd = gx / SENS_GIRO;
float temperatura = temp / 333.87 + 21.0;

La temperatura corresponde al chip, no al ambiente, y sirve sobre todo para compensar errores del sensor. Suele marcar unos grados más que el aire que lo rodea.

Prueba en el Monitor Serial

Después de cargar el programa en el Arduino UNO, abrimos el Monitor Serial y seleccionamos:

9600 baudios


Monitor Serial mostrando la aceleración, el giroscopio y la temperatura.

Al iniciar deberías ver el valor del registro WHO_AM_I y después una línea nueva cada medio segundo, similar a esta:

WHO_AM_I: 0x70
Acel (g): 0.01 | -0.02 | 1.00   Giro (grados/s): -0.8 | 0.4 | 0.2   Temp: 27.3 C

Los valores reales dependerán de la posición del sensor y de las condiciones de la prueba.

Realizando la prueba

Para comprobar el funcionamiento, coloca el módulo sobre la mesa y observa los valores. Después inclínalo y gíralo con cuidado:

  • Con el sensor quieto y horizontal, el acelerómetro debe marcar cerca de 1 g en un eje (normalmente Z) y cerca de 0 en los otros dos.
  • Al inclinar el módulo, la gravedad se reparte entre los ejes y los valores cambian.
  • Al girarlo, el giroscopio debe mostrar valores altos mientras se mueve y regresar cerca de 0 cuando se detiene.

Esta tabla muestra los valores aproximados del acelerómetro según la posición:

Posición del módulo Ax Ay Az
Horizontal, componentes hacia arriba ≈ 0 g ≈ 0 g ≈ +1 g
Horizontal, componentes hacia abajo ≈ 0 g ≈ 0 g ≈ −1 g
Apoyado sobre un lado largo ≈ 0 g ≈ ±1 g ≈ 0 g
Apoyado sobre un lado corto ≈ ±1 g ≈ 0 g ≈ 0 g

Los signos dependen de cómo marque tu módulo la orientación de los ejes (normalmente se dibujan en la placa), por lo que pueden ser contrarios a los de la tabla.

¿Por qué la medición puede variar?

Es importante entender que el sensor no es un instrumento de laboratorio.

La medición puede verse afectada por diferentes factores:

  • Error de cero (offset): con el sensor quieto, el giroscopio rara vez marca exactamente 0.
  • Vibraciones de la mesa, del motor o de las manos.
  • Ruido eléctrico y cables largos en el bus I2C.
  • Cambios de temperatura, que desplazan las lecturas.
  • Alimentación inestable.
  • El acelerómetro mide también las aceleraciones del movimiento, no solo la gravedad, por lo que la inclinación calculada es fiable solo con el sensor casi quieto.

Importante: el giroscopio entrega velocidad de giro, no ángulo. Para obtener el ángulo hay que acumular (integrar) las lecturas en el tiempo, y los pequeños errores se acumulan y producen una deriva. Por eso en proyectos reales se combinan acelerómetro y giroscopio con un filtro.

Mejora: calcular la inclinación

Con los valores del acelerómetro podemos calcular qué tan inclinado está el módulo. Agrega estas líneas en el loop(), después de convertir axg, ayg y azg:

// Calculo de inclinacion a partir del acelerometro
// (agregar despues de convertir axg, ayg y azg a g)

float roll  = atan2(ayg, azg) * 180.0 / PI;
float pitch = atan2(-axg, sqrt(ayg * ayg + azg * azg)) * 180.0 / PI;

Serial.print("Roll: ");
Serial.print(roll, 1);
Serial.print(" | Pitch: ");
Serial.println(pitch, 1);

Roll es la inclinación alrededor del eje X y pitch alrededor del eje Y. Con el módulo horizontal, ambos deben estar cerca de 0°.

Calibración del giroscopio

Una forma sencilla de reducir el error de cero es medir el giroscopio con el sensor completamente quieto y restar ese promedio a las lecturas. Agrega esta función al programa:

// Calibracion del giroscopio: se ejecuta una sola vez, con el sensor quieto
float offsetGx = 0, offsetGy = 0, offsetGz = 0;

void calibrarGiroscopio() {

  const int MUESTRAS = 200;
  long sumaX = 0, sumaY = 0, sumaZ = 0;

  for (int i = 0; i < MUESTRAS; i++) {

    Wire.beginTransmission(MPU_ADDR);
    Wire.write(0x43);                       // GYRO_XOUT_H
    Wire.endTransmission(false);
    Wire.requestFrom(MPU_ADDR, (uint8_t)6);

    sumaX += leer16();
    sumaY += leer16();
    sumaZ += leer16();
    delay(5);
  }

  offsetGx = sumaX / (float)MUESTRAS / SENS_GIRO;
  offsetGy = sumaY / (float)MUESTRAS / SENS_GIRO;
  offsetGz = sumaZ / (float)MUESTRAS / SENS_GIRO;
}

Después llámala en el setup(), al final, con el módulo inmóvil sobre la mesa:

calibrarGiroscopio();

Y en el loop() reemplaza las tres líneas de conversión del giroscopio por estas:

float gxd = gx / SENS_GIRO - offsetGx;
float gyd = gy / SENS_GIRO - offsetGy;
float gzd = gz / SENS_GIRO - offsetGz;

Con esto, el giroscopio debe marcar valores mucho más cercanos a 0 cuando el sensor está quieto.

Ventajas del MPU-6500

  • 6 ejes en un solo chip: acelerómetro y giroscopio en un mismo módulo.
  • Salida digital de 16 bits: buena resolución sin convertidores externos.
  • Rangos configurables: se adapta a movimientos suaves o violentos.
  • Solo dos cables de datos: comunicación I2C sencilla.
  • Sensor de temperatura integrado.
  • Tamaño compacto: fácil de integrar en robots y prototipos.

Aplicaciones

Este sensor puede utilizarse en diferentes proyectos electrónicos y de robótica:

  • Robots autobalanceados.
  • Drones y cuadricópteros.
  • Estabilizadores y gimbals.
  • Detección de inclinación y caídas.
  • Control por movimiento y gestos.
  • Podómetros y dispositivos portátiles.
  • Medición de vibraciones.
  • Proyectos educativos.

MPU-6500 vs. MPU-6050

Característica MPU-6500 MPU-6050
Ejes 6 (acelerómetro + giroscopio) 6 (acelerómetro + giroscopio)
Resolución 16 bits 16 bits
Comunicación I2C y SPI I2C
Dirección I2C 0x68 / 0x69 0x68 / 0x69
Registro WHO_AM_I 0x70 0x68
Fórmula de temperatura temp / 333.87 + 21 temp / 340 + 36.53
Voltaje del chip (hoja de datos) 1.71 – 3.6 V 2.375 – 3.46 V

Ambos se leen de forma muy parecida, pero no son idénticos. Por eso conviene revisar el registro WHO_AM_I: algunos módulos se venden con un nombre y llevan otro chip.

Conclusión

En esta práctica aprendimos a utilizar el módulo MPU-6500 con un Arduino UNO.

Aprendimos que este sensor combina un acelerómetro y un giroscopio de 3 ejes, se comunica por I2C y entrega números de 16 bits que debemos convertir a g, °/s y °C usando la sensibilidad del sensor.

También aprendimos a realizar las conexiones básicas:

MPU-6500          ARDUINO UNO

VCC  ───────────→ 5V
GND  ───────────→ GND
SCL  ───────────→ A5
SDA  ───────────→ A4

Finalmente utilizamos Arduino para leer los registros del sensor, convertirlos a unidades reales y visualizarlos en el Monitor Serial.

Este proyecto representa una base muy útil para desarrollar sistemas más avanzados. Por ejemplo, podemos construir un nivel digital, un robot que se mantenga en equilibrio o un sistema que detecte cuando un objeto se mueve o se cae.

El siguiente paso recomendado sería calibrar el giroscopio y combinar acelerómetro y giroscopio con un filtro complementario para obtener ángulos más estables.

Productos relacionados

Estos son los productos utilizados en esta práctica y puedes consultarlos directamente en Tecneu:

Productos utilizados en esta práctica

Tarjeta de desarrollo Arduino UNO R3 DIP con cable USB

Arduino UNO

Placa de desarrollo utilizada para leer los datos del sensor por I2C y calcular las unidades reales.

Comprar Arduino UNO en Tecneu

Módulo acelerómetro y giroscopio MPU-6500

Módulo MPU-6500

Sensor de movimiento de 6 ejes con acelerómetro y giroscopio, comunicación I2C y sensor de temperatura.

Comprar MPU-6500 en Tecneu

Comentarios 

No comments

Dejar un comentario
Tu correo no será publicado, los campos requeridos estan marcados con *
Artículos relacionados
Suscríbete
Suscríbete a nuestro boletín y recibe las últimas ofertas y novedades.