Practica Arduino con giroscopo L3GD20

¿Sabes qué es un giroscopio? Bueno, imagino que has escuchado de ellos, si tienes un Smartphone o una consola Wii sabes qué son. Qué pensabas que hacía que tu celular girara la pantalla cuando lo movías? o cuando rotabas tu cámara fotográfica y cambiaba la vista de la foto? o cuando juegas en el Wii y mueves los controles para poder rescatar a la princesa Peach en Mario Kart? o cuando... bueno ya me entendiste.

Básicamente podemos usar cualquier giroscopio pero esta vez usaremos el L3GD20 que tiene muy buena precisión y será muy fácil de programar con Arduino gracias a la librería que han creado para él.

Lo primero que te diré es que los giroscopios miden la velocidad angular, difícil? quiere decir que pueden medir la velocidad a la que gira un objeto en el espacio. Así como medirías una velocidad lineal en metros por segundo (m/s) ó en los carros en Kilómetros por hora (Km/h) pues en estos sensores obtienes medida de grados por segundo (°/s). ¿Grados? sí, de los grados que mides con un transportador.

Ahora yo te pregunto ¿has jugado al trompo o peonza? si eres muy joven puede que no sepas con qué es eso :S averígualo!. Pues te lo pregunto porque mucha de la física que se encuentra cuando sueltas el trompo y se mantiene girando se usa en el giroscopio, principalmente la inercia. La inercia es lo que hace que el trompo gire y que el giroscopio mida la velocidad de giro. Puedes leer más de este sorprendente efecto aqui.

También tendrás que saber que el L3GD20 es un giroscopio de tres ejes de gran precisión con regulador de voltaje incluido en la placa. La mayoría de estos sensores funcionan a 3.3V así que gracias al regulador lo puedes alimentar desde 2.5V a 5.5V. Que no se te ocurra colocarle un mayor voltaje al que te digo! o sino tendrás un agradable olor a semiconductor quemado :(

Cuando dice que es de tres ejes significa que el giro lo puedes medir en tres direcciones por separado: X, Y y Z que es la convención más común en física y matemática.

Para empezar con lo práctico necesitaremos varias cosas. Estás listo? Entonces ve marcando lo que ya tienes de esta lista:

1. El giroscopio L3GD20.

2. Un Arduino Uno con su cable USB.

3. Arduino IDE (el entorno de desarrollo).

4. Librería del sensor para Arduino, descárgala aqui!

5. Cablecitos de protoboard.

6. Muchas ganas de aprender :)

Para que no tengas problemas instalando la librería del sensor en Arduino te recomiendo que mires este rápido tutorial de cómo hacerlo.

Este sensor es digital y se comunica por medio de I2C/SPI, así lograrás una comunicación con sólo dos cables con el microcontrolador. Es por esto que las conexiones que tendrás que hacer son las siguientes:

Arduino --- L3GD20

SDA <-> SDA

SCL <-> SDA

5V <-> VIN

GND <-> GND

Una vez tengas esas conexiones vamos a hacer el programa. Para eso necesitas saber que vamos a hacer dos mediciones distintas del sensor con el programa. Sí, vamos a medir la velocida angular y los grados que se ha movido el giroscopio. Pero si el sensor sólo nos da valored de velocidad cómo medir los grados? bueno recordarás de física que realizas la integración de la velocidad angular obtienes el desplazamiento angular o los grados que se ha movido.

Por último te mostraré el código que va en tu Arduino para que se realicen los cálculos que te he dicho y el programa te muestre los valores de velocidad angular y posición en grados por cada eje.

/* Giroscopio L3GD20
* Este programa está diseñado para establecer comunicación
* con el giroscopio por medio de SPI y obtener los valores
* de aceleración angular. Con los valores obtenidos se realiza
* una corrección del offset, cálculo del nivel de ruido y la
* integración de la velocidad para obtener los grados.
*/

// Se incluyen las librerías necesarias
#include <Wire.h>
#include <L3G.h>

L3G gyro;  // Declaración del giroscopio

int sampleNum=500;  // Número de muestras para el promediar el offset

// Declaración de variables de offset y ruido
int dc_offsetX=0; // Offset en X
double noiseX=0;  // Nivel de ruido en X

int dc_offsetY=0;  // Offset en Y
double noiseY=0;  // Nivel de ruido en Y

int dc_offsetZ=0;  // Offset en Z
double noiseZ=0;  // Nivel de ruido en Z

// Declaración de variables para muestras de la velocidad
unsigned long time;
int sampleTime=10;
int rateX;  // Medición actual de velocidad X
int rateY;  // Medición actual de velocidad Y
int rateZ;  // Medición actual de velocidad Z

// Declaración de variables para medición del ángulo
int prev_rateX=0;  // Medición previa de velocidad X
double angleX=0;  // Valor del ángulo en Z

int prev_rateY=0;  // Medición previa de velocidad Y
double angleY=0;  // Valor del ángulo en Y

int prev_rateZ=0;  // Medición previa de velocidad Z
double angleZ=0;  // Valor del ángulo en Z

// Bloque de configuración
void setup() {
  Serial.begin(9600);  // Se abre la comunicación con el PC
  Wire.begin();  // Se abre la comunicación con el sensor

  // Si no hay respuesta del sensor se muestra un mensaje y
  // el programa se detiene
  if (!gyro.init())
  {
    Serial.println("Ha fallado la comunicacion con el sensor");
    while (1);
  }

  gyro.enableDefault();  // Si hay comunicación se configura
                         // por defecto el sensor
 
  calculoOffset();  // Función para calcular el offset de cada eje
}

// Bloque de Programa
void loop() {
  if(millis() - time > sampleTime)
  {
    time = millis(); // Tiempo de la próxima actualización
    gyro.read();  // Lectura de medición de velocidad
    
    // **********************************
    rateX=((int)gyro.g.x-dc_offsetX)/100;  // Calculo de la velocidad X en °/s

    // Sumatoria (integración) de la velocidad para el calculo de grados X
    angleX += ((double)(prev_rateX + rateX) * sampleTime) / 2000;
    
    prev_rateX = rateX;  // Se debe recordar una muestra previa de velocidad
    // Se coloca el ángulo recorrido en una escala de 0 a 360 grados
    if (angleX < 0){
      angleX += 360;
    }
    else if (angleX >= 360)
    {
      angleX -= 360;
    }
    
    // **********************************
    rateY=((int)gyro.g.y-dc_offsetY)/100;  // Calculo de la velocidad Y en °/s

    // Sumatoria (integración) de la velocidad para el calculo de grados Y
    angleY += ((double)(prev_rateY + rateY) * sampleTime) / 2000;
    
    prev_rateY = rateY;  // Se debe recordar una muestra previa de velocidad
    // Se coloca el ángulo recorrido en una escala de 0 a 360 grados
    if (angleY < 0){
      angleY += 360;
    }
    else if (angleY >= 360)
    {
      angleY -= 360;
    }   
    
    // **********************************
    rateZ=((int)gyro.g.z-dc_offsetZ)/100;  // Calculo de la velocidad Z en °/s

    // Sumatoria (integración) de la velocidad para el calculo de grados Z
    angleZ += ((double)(prev_rateZ + rateZ) * sampleTime) / 2000;
    
    prev_rateZ = rateZ;  // Se debe recordar una muestra previa de velocidad
    // Se coloca el ángulo recorrido en una escala de 0 a 360 grados
    if (angleZ < 0){
      angleZ += 360;
    }
    else if (angleZ >= 360)
    {
      angleZ -= 360;
    }

    // Impresión de los datos por consola
    Serial.print("AnguloZ: ");
    Serial.print(angleZ);
    Serial.print("\tVelZ: ");
    Serial.print(rateZ);
    
    Serial.print("\tAnguloY: ");
    Serial.print(angleY);
    Serial.print("\tVelY: ");
    Serial.println(rateY);
    
    Serial.print("\tAnguloX: ");
    Serial.print(angleX);
    Serial.print("\tVelX: ");
    Serial.println(rateX); 
  }
}

// Función del cálculo de Offset y nivel de ruido
void calculoOffset(){

  //**************************************
  // Promedio de muestras
  for(int n=0;n<sampleNum;n++){
    gyro.read();
    dc_offsetX+=(int)gyro.g.x;
  }
  dc_offsetX=dc_offsetX/sampleNum;

  // Calculo de nivel de ruido
  for(int n=0;n<sampleNum;n++){
    gyro.read();
    if((int)gyro.g.x-dc_offsetY>noiseX)
      noiseX=(int)gyro.g.x-dc_offsetX;
    else if((int)gyro.g.x-dc_offsetX<-noiseX)
      noiseX=-(int)gyro.g.x-dc_offsetX;
  }
  noiseX=noiseX/100;
   
  //**************************************
  // Promedio de muestras  
  for(int n=0;n<sampleNum;n++){
    gyro.read();
    dc_offsetY+=(int)gyro.g.y;
  }
  dc_offsetY=dc_offsetY/sampleNum;
  
  // Calculo de nivel de ruido
  for(int n=0;n<sampleNum;n++){
    gyro.read();
    if((int)gyro.g.y-dc_offsetY>noiseY)
      noiseY=(int)gyro.g.y-dc_offsetY;
    else if((int)gyro.g.y-dc_offsetY<-noiseY)
      noiseY=-(int)gyro.g.y-dc_offsetY;
  }
  noiseY=noiseY/100;
  
  //**************************************
  // Promedio de muestras  
  for(int n=0;n<sampleNum;n++){
    gyro.read();
    dc_offsetZ+=(int)gyro.g.z;
  }
  dc_offsetZ=dc_offsetZ/sampleNum;

  // Calculo de nivel de ruido
  for(int n=0;n<sampleNum;n++){
    gyro.read();
    if((int)gyro.g.z-dc_offsetZ>noiseZ)
      noiseZ=(int)gyro.g.z-dc_offsetZ;
    else if((int)gyro.g.z-dc_offsetZ<-noiseZ)
      noiseZ=-(int)gyro.g.z-dc_offsetZ;
  }
  noiseZ=noiseZ/100;
}

 

 

Related Articles

Este espacio lo he creado pensando en los entusiastas como tú, para compartir y centralizar documentación sobre temas que me apasionan: Arduino, impresoras 3D, Raspberry Pi, y mucho más.

Además, he querido fusionarlo con mi canal de YouTube, donde exploramos retro-informática, Raspberry Pi, consolas retro, electrónica y otras maravillas del mundo tecnológico. Este es tu sitio si disfrutas aprendiendo, creando y reviviendo lo mejor de la tecnología de ayer y hoy.

¡Bienvenido!