Problema obteniendo angulos con Giroscopio (SOLUCIONADO)

Actualmente tengo un problema en la interpretación de la información que entrega el sensor ya que deseo obtener datos de inclinacion en grados ( datasheet anexo – IDG500 - http://www.tiendaderobotica.com/tienda/download/Datasheet_IDG500.pdf - ) ya que no son coherentes los datos entregados, luego de consultar fuentes me topé con este post en el foro (http://arduino.cc/forum/index.php/topic,58048.0.html ) de la comunidad arduino donde explican el manejo del sensor, pero no tuve éxito reproduciendo los pasos sugeridos por el autor, así que procedí a intentar con un método propio, siguiendo estos pasos:

Aref: 3.3V
Resolucion ADC: 1023
Sensibilidad sensor: 9.1 mV / º / Seg

Procedimiento:

9.1 mV / ( 3.3 V / 1023 ) = 2.821

Cada º / Seg equivale a 2.821 unidades del ADC, por lo tanto una unidad del ADC equivale a 0.354 º / Seg

Luego de calcular el tiempo de ejecución de las instrucciones requeridas en dicho proceso llegue a la conclusión que es aproximadamente un milisegundo asi que partiendo de la formula de velocidad angular procedo a multiplicar el valor en velocidad por la unidad de tiempo calculada.

Esta es la línea de código empleada para dicho proceso: (anexo programa completo -- Gyro_con_LCD – Arduino V1.0)

if (TGX > (CGX+2)) // Giroscopio X antihorario
{
T = TGX - CGX;
T = T * 0.354;
T = T * 0.001;
GX = GX - T;
lcd.setCursor(4,0);
lcd.print(" ");
lcd.setCursor(4,0);
lcd.print(GX);
}

if (TGX < (CGX-2)) // Giroscopio X horario
{
T = CGX - TGX;
T = T * 0.354;
T = T * 0.001;
GX = GX + T;
lcd.setCursor(4,0);
lcd.print(" ");
lcd.setCursor(4,0);
lcd.print(GX);
}

El problema radica en que el resultado final no me entrega un valor coherente en grados, por ejemplo para 90º el valor entregado es aproximadamente 4 y para 180º es aproximadamente 8; también presenta un desajuste gradual siempre que se rota el sensor hacia uno de los sentidos, incrementando el valor de error cada vez que se gira en un sentido definido ( en este caso es el anti horario ), por ejemplo:

Valor inicial en cero: 0
…. Luego de unos movimientos
Valor en cero: -0.9
…. Luego de unos movimientos
Valor en cero: -1.45

Y asi sigue creciendo progresivamente el error cada vez que se hace una rotación en uno de los sentidos, por lo tanto me gustaría corregirlo porque si se usa este sensor como un punto de referencia para estabilizar la plataforma del cuadricoptero, llegaría el momento en que esta ya no seria paralela con respecto al plano terrestre.

#include <LiquidCrystal.h>
LiquidCrystal lcd(9,8,7,6,5,4);

int CGX = 0;    // Variables giroscopio
int CGY = 0;
int TGX = 0;
int TGY = 0;
float GX = 0;
float GY = 0;
float T = 0;

int CAX = 0;    // Variables Acelerometro
int CAY = 0;
int CAZ = 0;
int TAX = 0;
int TAY = 0;
int TAZ = 0;
float AX = 0;
float AY = 0;
float AZ = 0;
float t = 0;



void setup() 
{ 
  pinMode(3,INPUT);
  lcd.begin(16, 2);
  analogReference(EXTERNAL);  
}

void loop() 
{ 
  TGX = analogRead (A1);            // Lectura de valor de sensores
  TGY = analogRead (A0);
  TAX = analogRead (A4);
  TAY = analogRead (A3);
  TAZ = analogRead (A2);
  
/* --------------------------------------------------------------------------------------------------------------*/

  if (CGX==0 && CGY==0)              // Definir punto de referencia en los giroscopio
  { lcd.print("Definir CEROS");
CEROS:
    if(digitalRead(3)==HIGH)        // Boton para cargar el punto de referencia
    { CGX = analogRead(A1);
      CGY = analogRead(A0);  }
    else  
    { goto CEROS;  }
    if (CGX!=0 && CGY!=0)           // Cargar interfaz de visualizacion
    { lcd.clear();
      lcd.setCursor(0,0);
      lcd.print("G-X:     Y:");
      lcd.setCursor(0,1);
      lcd.print("A-X    Y    Z");  }  }
      
/* --------------------------------------------------------------------------------------------------------------*/

  if (TGX > (CGX+1))                // Giroscopio X antihorario
  { T = ((TGX - CGX) * 0.354) * 0.001;
    GX = GX - T;
    lcd.setCursor(4,0);
    lcd.print("     ");
    lcd.setCursor(4,0);
    lcd.print(GX);  }

  if (TGX < (CGX-1))                // Giroscopio X horario
  { T = ((CGX - TGX) * 0.354) * 0.001;
    GX = GX + T;
    lcd.setCursor(4,0);
    lcd.print("     ");
    lcd.setCursor(4,0);
    lcd.print(GX);  }  
  
  if (TGY > (CGY+2))                // Giroscopio Y antihorario
  { T = ((TGY - CGY) * 2.821) * 0.001;
    GY = GY - T;
    lcd.setCursor(11,0);
    lcd.print("     ");
    lcd.setCursor(11,0);
    lcd.print(GY);  }

  if (TGY < (CGY-2))                // Giroscopio Y horario
  { T = ((CGY - TGY) * 2.821) * 0.001;
    GY = GY + T;
    lcd.setCursor(11,0);
    lcd.print("     ");
    lcd.setCursor(11,0);
    lcd.print(GY);  }
    
/* --------------------------------------------------------------------------------------------------------------*/
  
}

Tienes un error de concepto.

con un giroscopio no puedes medir la inclinación de grados respecto del suelo, esto lo puedes hacer con un acelerómetro.

Con un giroscopio lo que mides es la velocidad de giro, esto es, la aceleración angular, obtienes salida dependiendo de la velocidad de giro en cada eje.

con un acelerómetro mides el ángulo respecto del suelo midiendo la aceleración de la gravedad en cada eje, siempre y cuando el sensor esté quieto, porque si está en movimiento te dara una lectura errónea.

por ejemplo, pones el sensor a 45º respecto del suelo, y en ese momento subes y bajas el sensor en vertical y veras que esa medida de 45º varía .

lo dicho, que el sensor que tienes mide velocidad de angulo de giro, y no aceleración

Un saludo

Sin ser ningun entendido te dire por lo que he leido otras veces , aparte de lo que te ha dicho Srdongato muy acertadamente , el giroscopio tiene un efecto de drifting por el que va sumando un error al girar.

La mejor manera de tomar la medida , sobre todo si va estar en movimiento es combinando giroscopio mas acelerometro o sea un IMU y luego pasando las medidas por un filtro por software ( PID , Kalman )

Listo, ya esta solucionado, definitivamente el error era usar el sensor erroneo.

Adjunto el codigo final que he usado para la integracion de mi sensor con una LCD 2*16, el siguiente paso es hacer un PID con ese sensor :smiley:

Gracias por la ayuda.

#include <LiquidCrystal.h>
LiquidCrystal lcd(9,8,5,4,3,2);

// Variables giroscopio
int CGX = 0;    
int CGY = 0;
int TGX = 0;
int TGY = 0;
float GX = 0;
float GY = 0;
float T = 0;

// Variables Acelerometro
int CAX = 514;    // 514 (Valores funcionales)    -    513 (Valores Teoricos)
int CAY = 510;    // 510                          -    513
int CAZ = 523;    // 523                          -    560
int TAX = 0;
int TAY = 0;
int TAZ = 0;
float AX = 0;
float AY = 0;
float AZ = 0;
float VECTOR = 0;
float ANGULO = 0;

boolean estado = LOW;

void setup() 
{ 
  pinMode(7,INPUT);
  pinMode(6,INPUT);
  lcd.begin(16, 2);
  analogReference(EXTERNAL);  
  delay(100);
}

void loop() 
{ 
  TGX = analogRead (A1);            // Lectura de valor de sensores
  TGY = analogRead (A0);
  TAX = analogRead (A4);
  TAY = analogRead (A3);
  TAZ = analogRead (A2);
  
/* --------------------------------------------------------------------------------------------------------------*/
// Arranque
/* --------------------------------------------------------------------------------------------------------------*/


  if (CGX==0 && CGY==0)              // Definir punto de referencia en los giroscopio
  { lcd.print(" Presiona START");
CEROS:
    if(digitalRead(6)==LOW)        // Boton para cargar el punto de referencia
    { CGX = analogRead(A1);
      CGY = analogRead(A0);  }
    else  
    { goto CEROS;  }
    if (CGX!=0 && CGY!=0)           // Cargar interfaz de visualizacion
    { lcd.clear();
      //lcd.print("G-X:     Y:");
      lcd.print("  Angulo ");
      lcd.setCursor(0,1);
      lcd.print("A-X    Y    Z");  }  }
      
/* --------------------------------------------------------------------------------------------------------------*/
// Giroscopio
/* --------------------------------------------------------------------------------------------------------------*/
/*
  if (TGX > (CGX+1))                // Giroscopio X antihorario
  { T = ((TGX - CGX) * 0.354) * 0.001;
    GX = GX - T;
    lcd.setCursor(4,0);
    lcd.print("     ");
    lcd.setCursor(4,0);
    lcd.print(GX);  }

  if (TGX < (CGX-1))                // Giroscopio X horario
  { T = ((CGX - TGX) * 0.354) * 0.001;
    GX = GX + T;
    lcd.setCursor(4,0);
    lcd.print("     ");
    lcd.setCursor(4,0);
    lcd.print(GX);  }  
  
  if (TGY > (CGY+2))                // Giroscopio Y antihorario
  { T = ((TGY - CGY) * 2.821) * 0.001;
    GY = GY - T;
    lcd.setCursor(11,0);
    lcd.print("     ");
    lcd.setCursor(11,0);
    lcd.print(GY);  }

  if (TGY < (CGY-2))                // Giroscopio Y horario
  { T = ((CGY - TGY) * 2.821) * 0.001;
    GY = GY + T;
    lcd.setCursor(11,0);
    lcd.print("     ");
    lcd.setCursor(11,0);
    lcd.print(GY);  }
*/    
/* --------------------------------------------------------------------------------------------------------------*/
// Acelerometro
/* --------------------------------------------------------------------------------------------------------------*/

    AX = TAX - CAX;
    AY = TAY - CAY;
    AZ = TAZ - CAZ;
    VECTOR = sqrt( sq(AX) + sq(AY) + sq(AZ) ); 
    VECTOR = acos(AZ / VECTOR);
    ANGULO = (180 * VECTOR) / PI;
    lcd.setCursor(9,0);
    lcd.print(ANGULO);
    lcd.print("  ");  
    

/* --------------------------------------------------------------------------------------------------------------*/
// Valores del ADC
/* --------------------------------------------------------------------------------------------------------------*/
/*      
      lcd.setCursor(4,0);
      lcd.print(TGX);
      lcd.setCursor(11,0);
      lcd.print(TGY);              */
      lcd.setCursor(3,1);
      lcd.print(TAX);
      lcd.setCursor(8,1);
      lcd.print(TAY);
      lcd.setCursor(13,1);
      lcd.print(TAZ);