¿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; }