TODOPIC

Mecatrónica => UAV => Mensaje iniciado por: elgarbe en 05 de Enero de 2014, 11:46:29

Título: Giroscopos - UAV's
Publicado por: elgarbe en 05 de Enero de 2014, 11:46:29
Los giróscopos son sensores que miden la velocidad angular a la que es sometido. Si bien existen sensores que miden en uno o dos ejes, hoy en día son muy comunes los giróscopos que miden en los tres ejes.
En mi caso estoy trabajando y mostraré resultados aquí del L3G4200D de ST. Lo tengo montado una plaquita que compre en dx.com. Si bien posee interfaz SPI, en la placa esta cableado el bus I2C, para facilitar la lectura de los 4 sensores de la IMU.
Esta (http://www.st.com/web/catalog/sense_power/FM89/SC1288/PF250373) es la página del producto. En ella podrán encontrar la hoja de datos así como algunas notas de aplicacion.

La gran mayoría de los sensores de tecnologia MEMS (en realidad la mayoria de todos los sensores) poseen 3 parámetros fundamentales:
El Offset (Zero rate level): Cuando el giróscopo esta en "quieto" debería entregar en su salida 0 °/seg. Sin embargo no es así y con el giróscopo en reposo siempre tendremos un valor distinto de 0. En la hoja de datos del L3G, en la Tabla 4, podemos ver que dependiendo de la sensibilidad elegida tenemos distintos Zero rate level, por ejemplo con un rango de 2000dps (°/seg) tenemos un offset típico de +-75dps. El valor de un sensor soldado en una placa y listo para usar es batanta fijo, no es que va a variar entre -75 y +75dps constantemente, sino que va a tomat un valor, digamos 15dps, y variará un poco alrededor de dicho valor.
Es muy importante determinar el offset de nuestro sensor para obtener una medicion correcta.
Sensivilidad (Sensitivity): Nos indica cuantos dps equivale cada bit del dato binario de salida. Por ejemplo, para un rango de 2000dps tenemos 0.07 dps/LSB. Esto significa que cuando la salida del sensor sea 1 representará 0.07 dps, cuando la salida sea 10 significará que el sensor está midiendo 0.7 dps. La sensibilidad es bastante fija y está muy cerca de lo que dice la hoja de datos. Se puede determinar prácticamente para mejorar la presicion de la medicion.
Rango(range): El rango es entre que valores el sensor puede medir. Por ejemplo, este sensor podee 3 rangos configurables: +-250dps, +-500dps y +-2000dps.

El offset y la sensivilidad son funcion de la temperatura y en aplicaciones de alta presicion se podría corregir con las variaciones de temperatura.

Otro dato importante es el ODR (Output Data Rate). Este sensor podemos elegir 100Hz (1 muestra cada 10mseg), 200Hz, 400Hz y 800Hz (1 medicion cada 1,25mseg). si no he leido mál a mayor ODR mayor nivel de ruido tendremos en la medicion.

Bien, con esto estamos mas o menos en condiciones de empezar a probar estos sensores. Para ello hay que tener un poco de idea de como funciona el bus I2C para entender mejor.

Edito: Un lugar con una excelente explicacion sobre la teoría de los Acelerómetros y gyróscopos. (http://www.starlino.com/imu_guide.html)

Título: Re: Giroscopos - UAV's
Publicado por: elgarbe en 05 de Enero de 2014, 11:46:57
I2C Muy básico

Informacion sobre I2C hay por todos lados, yo simplemente haré una reseña de lo que necesita saber alguien que no nunca leyó nada al respecto y quiere hacer andar estos sensores.

El bus I2C es un bus de 2 cables, SCL (Clock) y SDA (Datos). Generalmente hay un maestro que inicia las comunicaciones y varios esclavos con direcciones únicas. El bus es bidireccional, por lo que el maestro puede pedir datos al esclavo y el esclavo responde con ellos. Cada dispositivo posee una direccion de 7bits. Se agrega un bit más que indica si la accion a realizar es una lectura o una escritura. No voy a entrar en detalles con el tema de bit de start, bit de stop, ACK y demás yerbas, eso para mí esta oculto en el drive del I2C.
Cada driver (I2C) presentará una interfaz determinada que nos permitirá realizar una comunicacion en el bus. Por ejemplo, mi drive para el LPC1769 (Cortex M3) tiene las siguientes funciones:
Código: [Seleccionar]
void I2C1_IRQHandler( void );
void I2C1Init( void );
uint32_t I2CStart( uint32_t portNum );
uint32_t I2CStop( uint32_t portNum );
uint32_t I2CEngine( uint32_t portNum );

En mi caso la cosa es muy simple, tengo una funcion denominada I2C1Init, la cual inicializa y configura el bus I2C 1 de mi uC. La velocidad y demás parámetros estan en unos defines.
Despues tengo un I2C_IRQHandler, en donde estpa el corazón del drive, ya que la comunicacion en mi uC se realiza enteramente con interrupciones.
Luego tengo I2CStart e I2CStop, los cuales nunca usé
Finalmente tengo la más importante I2CEngine. Los drive para los PIC generalmente tienn funciones como i2c_read, i2cwrite, etc. La funcion I2CEngine que tiene mi drive se encarga de hacer la combinacion completa desde el Start al Stop, haciendo los read y write necesarios para obtener una comunicacion completa.
Entonces en mi codigo del giróscopo tengo una funcion que me permite escribir registos en él:
Código: [Seleccionar]
void L3G4200D_write(unsigned char reg_address, unsigned char value){

I2CWriteLength[PORT_USED] = 3;
I2CReadLength[PORT_USED] = 0;
I2CMasterBuffer[PORT_USED][0] = L3G4200D_WRITE_ADDR;
I2CMasterBuffer[PORT_USED][1] = reg_address;
I2CMasterBuffer[PORT_USED][2] = value;

I2CEngine( PORT_USED );
}
Si bien la el uso de I2CEngine no es muy intuitivo, una vez que le he agarrado la mano va como piña.
En este caso la secuencia sería, el master genera el CLK y pone la señal de START. Escribe la direccion del dispositivo con los 7bits + el bit de lectura/escritura. Si no me equivoco el master espera un ACK del escalvo. Luego el master escribe la direccion del registro (reg_address) y el valor que desea escribir y espera por el ACK del esclavo. Entonces con esta función se hace una transaccion completa I2C.

Tambien tengo una funcion para leer registros del giróscopo:
Código: [Seleccionar]
unsigned char L3G4200D_read(unsigned char reg){
// uint32_t result=0;
I2CWriteLength[PORT_USED] = 2;
I2CReadLength[PORT_USED] = 1;
I2CMasterBuffer[PORT_USED][0] = L3G4200D_WRITE_ADDR;
I2CMasterBuffer[PORT_USED][1] = reg;
I2CMasterBuffer[PORT_USED][2] = L3G4200D_READ_ADDR;

I2CEngine( PORT_USED );

return(I2CSlaveBuffer[PORT_USED][0]);
}
Como ven, para leer un registro, primero hay que hacer una operacion de escritura y pasar la direccion que queremos leer. Luego sigue una operacion de lectura. Aquí, I2CEngine hace todo de una.

Tambien tengo una funcion que me permite inicializar (configurar) el Giróscopo:
Código: [Seleccionar]
void L3G4200D_init(){

// L3G4200D_write(L3G4200D_CTRL_REG1, 0b00001111); // 100Hz, 12.5 CO, all axis enable
// L3G4200D_write(L3G4200D_CTRL_REG4, 0x20); // 0x00 250 dps, 0x10 500 dps, 0x20 2000dps

L3G4200D_write(L3G4200D_CTRL_REG2, 0b00011001); //
L3G4200D_write(L3G4200D_CTRL_REG3, 0x00); //
L3G4200D_write(L3G4200D_CTRL_REG4, 0b10110000); // 0x00 250 dps, 0x10 500 dps, 0x20 2000dps
L3G4200D_write(L3G4200D_CTRL_REG5, 0b00010011); //
L3G4200D_write(L3G4200D_CTRL_REG1, 0x0F); // 100Hz, 12.5 CO, all axis enable
}

Y finalmente la funcion que permite leer los datos "crudos" (RAW data) del gyroscopo:
Código: [Seleccionar]
void L3G4200D_read_data(){

// uint32_t result=0;
I2CWriteLength[PORT_USED] = 2;
I2CReadLength[PORT_USED] = 6;
I2CMasterBuffer[PORT_USED][0] = L3G4200D_WRITE_ADDR;
I2CMasterBuffer[PORT_USED][1] = (L3G4200D_DATA_ADDR | (1<<7));
I2CMasterBuffer[PORT_USED][2] = L3G4200D_READ_ADDR;

res_g=I2CEngine( PORT_USED );

gyro_X = make_word2(I2CSlaveBuffer[PORT_USED][1], I2CSlaveBuffer[PORT_USED][0]);
gyro_Y = make_word2(I2CSlaveBuffer[PORT_USED][3], I2CSlaveBuffer[PORT_USED][2]);
gyro_Z = make_word2(I2CSlaveBuffer[PORT_USED][5], I2CSlaveBuffer[PORT_USED][4]);
}
En esta funcion es muy importante el tipo de datos de gyro_X, Y y Z. Deben ser de 16bits con signo. Cada compilador posee un tipo de datos para ellos, en mi caso es signed short. Tambien es importante notar que hay que leer 2 direcciones para formar el dato de cada eje.

Para la configuracion inicial del gyro, lo podemos discutir y probar más adelante. Hay muchas opciones, algunas de las cuales no entiendo bien. En principio lo más importante a configurar es el rango (con él queda definida la sensibilidad), el ODR y el power mode.

Bueno, con esto tenemos una base para arrancar con las pruebas. Es importante que si alguien quiere hacer pruebas vea como funciona su drive para el bus I2C.

Bueno, en la próxima, Leyendo el registro who_am_I.

Saludos!
Título: Re: Giroscopos - UAV's
Publicado por: elgarbe en 10 de Enero de 2014, 22:21:07
Leyendo el registro who_am_I

Bueno, en este punto necesitaremos la hoja de datos para ver un poco las características de nuestro giro y su configuracion.
En mi caso uso el L3G4200D de ST.
Lo primero que hay que analizar es la tabla 4 (mecánical characteristics)

(http://imagizer.imageshack.us/v2/640x480q90/22/29d4.jpg) (https://imageshack.com/i/0m29d4j)

Como primer parámetro tenemos el Rango del gyro, podemos elegir entre +-250, +-500 y +-2000. A mayor rango, vamos a poder medir velocidades angulares mayores y además será menos sensible a velocidades más pequeñas. En mi caso elegiré 2000dps.
Una vez elegido el rango, la sensivilidad queda determinada. En mi caso 0.07 dps por cada bit en el dato de salida.
Luego tenemos el ODR, podemos elegir 100, 200, 400 u 800Hz. O sea, 1 muestra cada 10mseg hasta 1 muestra cada 1,25mseg. Aquí hay algo para investigar que aún no he hecho. Tengo entendido que a mayor ODR mas "ruidosa" será la señal de salida. En principio elegiría 100 o 200Hz.
El resto de los parámetros los podemos ver un poco más adelante.

Bien, en la Tabla18 tenemos un listado de todos los registros del gyro, los cuales debemos/podemos leer/escribir para hacerlo funcionar.
El primer registro que podemos utilizar para testeo es el Who_am_I en la direccion 0x0F cuyo valor por defecto es 211 decimal.
Luego tenemos 5 registros de control, los cuales debemos configurar para obtener la respuesta deseada del gyro
Luego tenemos los 6 registros con los datos crudos de cada eje.

Bueno, veamos un pequeño ejemplo para leer el registro Who_am_I y verificar el funcionamiento de la comunicacion:

Lamentablemente para muchos, mi placa de desarrollo es la LPCXpresso, por lo que el código que propongo es para ella. Es C, por lo que se podrá modificar facilmente a cualquier otro uC.

Bueno, este es mi archivo L3G4200D.h
Código: [Seleccionar]
#ifndef L3G4200D_H_
#define L3G4200D_H_

#include "i2c.h"

extern volatile uint8_t I2CMasterBuffer[I2C_PORT_NUM][BUFSIZE];
extern volatile uint8_t I2CSlaveBuffer[I2C_PORT_NUM][BUFSIZE];
extern volatile uint32_t I2CReadLength[I2C_PORT_NUM];
extern volatile uint32_t I2CWriteLength[I2C_PORT_NUM];

#define L3G4200D_READ_ADDR      0xD3
#define L3G4200D_WRITE_ADDR     0xD2
#define L3G4200D_DATA_ADDR 0x28

#define L3G4200D_WHO_AM_I       0x0F

#define L3G4200D_CTRL_REG1     0x20
#define L3G4200D_CTRL_REG2     0x21
#define L3G4200D_CTRL_REG3     0x22
#define L3G4200D_CTRL_REG4     0x23
#define L3G4200D_CTRL_REG5     0x24
#define L3G4200D_REFERENCE     0x25
#define L3G4200D_OUT_TEMP      0x26
#define L3G4200D_STATUS_REG    0x27

#define L3G4200D_OUT_X_L       0x28
#define L3G4200D_OUT_X_H       0x29
#define L3G4200D_OUT_Y_L       0x2A
#define L3G4200D_OUT_Y_H       0x2B
#define L3G4200D_OUT_Z_L       0x2C
#define L3G4200D_OUT_Z_H       0x2D

#define L3G4200D_FIFO_CTRL_REG 0x2E
#define L3G4200D_FIFO_SRC_REG  0x2F

#define L3G4200D_INT1_CFG      0x30
#define L3G4200D_INT1_SRC      0x31
#define L3G4200D_INT1_THS_XH   0x32
#define L3G4200D_INT1_THS_XL   0x33
#define L3G4200D_INT1_THS_YH   0x34
#define L3G4200D_INT1_THS_YL   0x35
#define L3G4200D_INT1_THS_ZH   0x36
#define L3G4200D_INT1_THS_ZL   0x37
#define L3G4200D_INT1_DURATION 0x38

#define PORT_USED 1

void L3G4200D_init();
unsigned char L3G4200D_read(unsigned char reg);
unsigned char L3G4200D_write(unsigned char reg_address, unsigned char value);

void L3G4200D_init(){

L3G4200D_write(L3G4200D_CTRL_REG1, 0b00001111); // 100Hz, 12.5 CO, all axis enable
L3G4200D_write(L3G4200D_CTRL_REG4, 0x20); // 0x00 250 dps, 0x10 500 dps, 0x20 2000dps
}

unsigned char L3G4200D_read(unsigned char reg){
I2CWriteLength[PORT_USED] = 2;
I2CReadLength[PORT_USED] = 1;
I2CMasterBuffer[PORT_USED][0] = L3G4200D_WRITE_ADDR;
I2CMasterBuffer[PORT_USED][1] = reg;
I2CMasterBuffer[PORT_USED][2] = L3G4200D_READ_ADDR;

I2CEngine( PORT_USED );

return(I2CSlaveBuffer[PORT_USED][0]);
}

unsigned char L3G4200D_write(unsigned char reg_address, unsigned char value){
I2CWriteLength[PORT_USED] = 3;
I2CReadLength[PORT_USED] = 0;
I2CMasterBuffer[PORT_USED][0] = L3G4200D_WRITE_ADDR;
I2CMasterBuffer[PORT_USED][1] = reg_address;
I2CMasterBuffer[PORT_USED][2] = value;

return(I2CEngine( PORT_USED ));
}

#endif /* L3G4200D_H_ */

Sé que en los .h van las definiciones y tendria que tener un L3G4200D.c, pero todavia me falta aprender algunas cosas sobre programar con varios .c, en especial con el alcance de las variables, etc.
Bueno, como ven al principio estan todos los define con las direcciones de cada registro. Luego tengo las funciones típicas necesarias para usar el gyro en esta aplicacion.

Mi main.c es este:
Código: [Seleccionar]
#ifdef __USE_CMSIS
#include "LPC17xx.h"
#endif

#include <cr_section_macros.h>
#include <NXP/crp.h>
#include "uart2.h"
#include <stdio.h>
#include "i2c.h"
#include "L3G4200D.h"


/*******************************************************************************
**   Main Function  main()
*******************************************************************************/
int main (void){
unsigned char who_am_I;

I2C1Init(); /* initialize I2c1 */
L3G4200D_init();
UART2_Init(56700); // Inicializo el UART a 56700

UART2_PrintString ("\r\nGiroscopo L3G4200D\r\n");
UART2_PrintString ("======== elgarbe ==========\r\n");

who_am_I=L3G4200D_read(L3G4200D_WHO_AM_I);

UART2_PrintString("\r\nEl registro who am I  contiene: ");
uart2_printUint32(who_am_I, 10);

while ( 1 ){
}
}

Simplemente se inicializa el I2C, luego se inicializa el gyro. Para ello solo hace falta escribir 2 registros. el REG1 configuramos 100Hz de ODR, 12.5 Hz de BW, habilitamos los tres ejes y ponemos el modo de energia en Normal. En el REG4 elegimos 2000dps

Finalmente inicializamos la UART, escribimos un mensaje para luego leer el registro who_am_I y mostrar su valor.

El terminal obtengo la siguiente salida
(http://imagizer.imageshack.us/v2/800x600q90/42/mz1l.jpg) (https://imageshack.com/i/16mz1lj)
Título: Re: Giroscopos - UAV's
Publicado por: elgarbe en 12 de Enero de 2014, 13:08:23
Leyendo los datos RAW

Bueno, ahora que ya estamos "hablando" con el gyro, denemos poder leer la informacion de los dps que está midiendo el gyro.

Para ello simplemente voy a agregar una funcion que me permita leer los 6 registros de datos y unir X_L xon X_H para obtener el dato completo del eje X (al igual que con los otros ejes).

Código: [Seleccionar]
short make_word(unsigned char HB, unsigned char LB){
   return ((HB << 8) | LB);
}

void L3G4200D_read_data(){

uint32_t result=0;
I2CWriteLength[PORT_USED] = 2;
I2CReadLength[PORT_USED] = 6;
I2CMasterBuffer[PORT_USED][0] = L3G4200D_WRITE_ADDR;
I2CMasterBuffer[PORT_USED][1] = (L3G4200D_DATA_ADDR | (1<<7));
I2CMasterBuffer[PORT_USED][2] = L3G4200D_READ_ADDR;

result=I2CEngine( PORT_USED );

gyro_X = make_word(I2CSlaveBuffer[PORT_USED][1], I2CSlaveBuffer[PORT_USED][0]);
gyro_Y = make_word(I2CSlaveBuffer[PORT_USED][3], I2CSlaveBuffer[PORT_USED][2]);
gyro_Z = make_word(I2CSlaveBuffer[PORT_USED][5], I2CSlaveBuffer[PORT_USED][4]);
}

Como se puede ver se leen 6 registros, a partir de la direccion L3G4200D_DATA_ADDR. Luego se arma el dato combinando de a dos los registros leídos para armar un short con signo (16 bits).

En el main tenemos:
Código: [Seleccionar]
/*
===============================================================================
 Name        : main.c
 Author      : $(author)
 Version     :
 Copyright   : $(copyright)
 Description : main definition
===============================================================================
*/

#ifdef __USE_CMSIS
#include "LPC17xx.h"
#endif

signed short gyro_X, gyro_Y, gyro_Z;
volatile uint32_t msTicks;

__INLINE static void delay_ms (uint32_t delayTicks) {
  uint32_t currentTicks;
  currentTicks = msTicks; // read current tick counter
  while ((msTicks - currentTicks) < delayTicks);
}

#include <cr_section_macros.h>
#include <NXP/crp.h>
#include "uart2.h"
#include <stdio.h>
#include "i2c.h"
#include "L3G4200D.h"

float x1,y1,z1;

void SysTick_Handler(void) {
msTicks++; /* increment counter necessary in Delay() */
}

/*******************************************************************************
**   Main Function  main()
*******************************************************************************/
int main (void){

//Configuro el SysTick para que interrumpa cada 1mseg
if (SysTick_Config(SystemCoreClock / 1000)) {
while (1);
}

I2C1Init(); // Inicializamos el bus I2C
L3G4200D_init(); // Inicializamos el Gyróscopo
UART2_Init(57600); // Inicializamos el UART a 57600

UART2_PrintString ("\r\nGiroscopo L3G4200D\r\n");
UART2_PrintString ("======== elgarbe ==========\r\n");

UART2_PrintString ("\r\nRAW X\tRAW Y\tRAW Z\r\n");

while ( 1 ){

L3G4200D_read_data();

uart2_printInt32(gyro_X, 10);
UART2_Sendchar('\t');
uart2_printInt32(gyro_Y, 10);
UART2_Sendchar('\t');
uart2_printInt32(gyro_Z, 10);
UART2_Sendchar('\r');
UART2_Sendchar('\n');

delay_ms(500);
}
}

Como se puede ver, tenemos 3 variables globales signed short para almacenar los datos del gyro.
Aquí estamos haciendo uso del SysTick timer de los Cortex M3. Está configurado para que interrumpa cada 1 mseg, lo usamos para crear la funcion delay_ms.
Como antes, inicializamos el bus I2C, el gyróscopo y la UART. Luego llamamos a la funcion read_data del L3G4200D e imprimimos en la UART el resultado.

Esta es una imagen de nuestra terminal:

(http://imagizer.imageshack.us/v2/800x600q90/163/rfh2.jpg) (https://imageshack.com/i/4jrfh2j)

Bien, esos son los datos crudos del gyro, no son dps. La primera observacion que podemos hacer es que no son 0 como uno esperaría obtener con el gyro sin mover, fijo en la mesa... En cambio obtenemos ciertos valores. Bueno, esos valores son el Zero Rate Level. Otra cosa que observamos es que dicho valor cambia constantemente. Por ejemplo en el eje X tenemos valores que van desde 7 a 18 "cuentas del ADC". Esto puede ser mucho o poco, aún no lo sabemos ya que no tenemos los datos en dps para compararlos con los 2000dps de alcance con el que tenemos configurado al gyro. Aunque si pensamos un poco, el gyro tiene un ADC de 16 y me parece que obtener una variacion de 7 a 18 cuentas en 65535 no parece ser mucho, me parece que es simplemente "ruido" en el ADC... pero de esto no estoy seguro. Algo que no entiendo, ya que nunca estudie, es el Rate Noise Density... quizá tenga que ver con esto... alguien esta leyendo este post y sabe al respecto puede desasnarme...

Bien, entonces el siguiente paso lógico sería convertir los datos RAW en dps.

Eso quedará para la próxima entrega.
Saludos!
Título: Re: Giroscopos - UAV's
Publicado por: elgarbe en 12 de Enero de 2014, 14:39:59
Eliminando Offset - obteniendo °/seg (dps)

Bueno, llegó el momento de que este bichito empiece a dar informacion que sirva para algo!

Como vimos en el post anterior, el gyróscopo no entrega 0 cuentas cuando está en reposo, sino que posee un Zero Rate Level. Es por ello que debemos realizar una funcion que obtenga el offset del Gyro para poder restarlo a cada medicion posterior y obtener una lectura correcta.
Mi funcion de obtener offset es la siguiente:

Código: [Seleccionar]
void L3G4200D_GetBiass(void){

int i;
for (i = 0; i < SAMPLESS_BIASS; i += 1) {
L3G4200D_read_data();
biass_X += gyro_X;
biass_Y += gyro_Y;
biass_Z += gyro_Z;
delay_ms(1);
}
biass_X /= SAMPLESS_BIASS;
biass_Y /= SAMPLESS_BIASS;
biass_Z /= SAMPLESS_BIASS;
}

Como pueden observar, simplemente tomo SAMPLESS_BIASS cantidad de muestras y hago un promedio de ellas. En este caso estoy tomando unas 600 muestras. Cuantas más muestras mejor.

Una vez que obtengo el Offset, lo siguiente es la conversion de LSB's o cuentas o datos RAW en dps. Para ello utilizamos la sensibilidad. En la tabla 4 antes vista, encontramos que para 2000dps de rango tenemos una sensibilidad de 70 mdps/LSB o 0.07 dps/LSB.
En definitiva los datos "correctos" o reales son (RAW - Offset) * Sensibilidad

Bien, mi main queda ahora de la siguiente forma:

Código: [Seleccionar]
/*
===============================================================================
 Name        : main.c
 Author      : $(author)
 Version     :
 Copyright   : $(copyright)
 Description : main definition
===============================================================================
*/

#ifdef __USE_CMSIS
#include "LPC17xx.h"
#endif

#define GYRO_X_SCALE 0.07 //Sensibilidad en cada eje
#define GYRO_Y_SCALE 0.07 //extraído del datasheet
#define GYRO_Z_SCALE 0.07

#define SAMPLESS_BIASS 600 //Número de muestras para calular biass

signed short gyro_X, gyro_Y, gyro_Z;
double biass_X, biass_Y, biass_Z;

volatile uint32_t msTicks;

__INLINE static void delay_ms (uint32_t delayTicks) {
  uint32_t currentTicks;
  currentTicks = msTicks; // read current tick counter
  while ((msTicks - currentTicks) < delayTicks);
}

#include <cr_section_macros.h>
#include <NXP/crp.h>
#include <math.h>
#include "uart2.h"
#include <stdio.h>
#include "i2c.h"
#include "L3G4200D.h"

void SysTick_Handler(void) {
msTicks++; /* increment counter necessary in Delay() */
}

/*******************************************************************************
**   Main Function  main()
*******************************************************************************/
int main (void){

double gx, gy, gz;

//Configuro el SysTick para que interrumpa cada 1mseg
if (SysTick_Config(SystemCoreClock / 1000)) {
while (1);
}

I2C1Init(); // Inicializamos el bus I2C
L3G4200D_init(); // Inicializamos el Gyróscopo
UART2_Init(57600); // Inicializamos el UART a 57600

UART2_PrintString ("\r\nGiroscopo L3G4200D\r\n");
UART2_PrintString ("======== elgarbe =========\r\n");

UART2_PrintString ("Obteniendo Offset...\r\n");

L3G4200D_GetBiass();

UART2_PrintString ("Offset X: ");
uart2_printDouble(biass_X, 4);
UART2_PrintString("\r\n");
UART2_PrintString ("Offset Y: ");
uart2_printDouble(biass_Y, 4);
UART2_PrintString("\r\n");
UART2_PrintString ("Offset Z: ");
uart2_printDouble(biass_Z, 4);
UART2_PrintString("\r\n");

UART2_PrintString ("\r\nRAW X\tRAW Y\tRAW Z\tdps X\tdps Y\tdps Z\r\n");

while ( 1 ){

L3G4200D_read_data();

gx=((float)gyro_X - biass_X);
gy=((float)gyro_Y - biass_Y);
gz=((float)gyro_Z - biass_Z);

uart2_printDouble(gx , 2);
UART2_Sendchar('\t');
uart2_printDouble(gy , 2);
UART2_Sendchar('\t');
uart2_printDouble(gz , 2);
UART2_Sendchar('\t');

gx *= GYRO_X_SCALE;
gy *= GYRO_Y_SCALE;
gz *= GYRO_Z_SCALE;

uart2_printDouble(gx, 3);
UART2_Sendchar('\t');
uart2_printDouble(gy, 3);
UART2_Sendchar('\t');
uart2_printDouble(gz, 3);
UART2_PrintString("\r\n");

delay_ms(500);
}
}

Bueno, básicamente, primero obtenemos el offset con la nueva funcion incorporada. Muestro esos datos.
Luego calculo los datos sin offset y los muestro. Finalmente multiplico por la sensibilidad y muestro los datos en °/seg
Esta es una captura de lo que obtengo:

(http://imagizer.imageshack.us/v2/800x600q90/24/vtff.jpg) (https://imageshack.com/i/0ovtffj)

De aquí podemos ver aunque hemos eliminado el offset, todavía tenemos datos distintos de cero, pero en este caso están mas cerca de 0. Tamien notamos que en el peor de los casos tenemos 0.564 dps en el eje X cuando deveríamos tener 0. Será mucho? Pues veamos, el rango del Gyro está en 2000 dps por lo que 0.564 representa el 0.028%!!!! A mí me parece que eso es más que suficiente!

Bien, veamos ahora que pasa si giramos el sensor en un sentido y lo dejamos quieto, pero inclinado:

(http://imagizer.imageshack.us/v2/800x600q90/845/jgho.jpg) (https://imageshack.com/i/nhjghoj)

Como se puede observar he girado el sensor "alrededor" del eje X y lo he hecho a una velocidad aproximada de 30°/seg. Cuando dejé de girar el sensor, el resultado vuelve a ser 0 ya que estoy midiendo la velocidad angular.

Bueno, ya estamos llegando al final, solo nos queda calcular el ángulo a partir de la velocidad...

Saludos!
Título: Re: Giroscopos - UAV's
Publicado por: elgarbe en 15 de Enero de 2014, 21:24:23
Integrando y obteniendo el ángulo de giro

Bien, ya estamos listos para poder obtener el tan preciado ángulo que ha girado la IMU. Para ello debemos integrar la velocidad angular que nos brinda el Gyróscopo en un tiempo de muestreo determinado.
La técnica es bien simple, tomo un tiempo de muestreo (20mseg en mi caso) y leo el sensor cada timeStep segundos. La integracion discreta se obtiene tomando el valor anterior del ángulo + el valor nuevo * el timeStep.

Entonces mi nuevo main es:

Código: [Seleccionar]
#ifdef __USE_CMSIS
#include "LPC17xx.h"
#endif

#define GYRO_X_SCALE 0.07 //Sensibilidad en cada eje
#define GYRO_Y_SCALE 0.07 //extraído del datasheet
#define GYRO_Z_SCALE 0.07

#define SAMPLESS_BIASS 600 //Número de muestras para calular biass

signed short gyro_X, gyro_Y, gyro_Z;
double biass_X, biass_Y, biass_Z;

volatile uint32_t msTicks;

__INLINE static void delay_ms (uint32_t delayTicks) {
  uint32_t currentTicks;
  currentTicks = msTicks; // read current tick counter
  while ((msTicks - currentTicks) < delayTicks);
}

#include <cr_section_macros.h>
#include <NXP/crp.h>
#include <math.h>
#include "uart2.h"
#include <stdio.h>
#include "i2c.h"
#include "L3G4200D.h"

int timeStep = 20; //Tiempo que tiene que durar el main


void SysTick_Handler(void) {
msTicks++; /* increment counter necessary in Delay() */
}

/*******************************************************************************
**   Main Function  main()
*******************************************************************************/
int main (void){
double gx=0.0, gy=0.0, gz=0.0;
uint32_t timer=0;
//Configuro el SysTick para que interrumpa cada 1useg
if (SysTick_Config(SystemCoreClock / 1000)) {
while (1);
}

I2C1Init(); // Inicializamos el bus I2C
L3G4200D_init(); // Inicializamos el Gyróscopo
UART2_Init(57600); // Inicializamos el UART a 57600

UART2_PrintString ("\r\nGiroscopo L3G4200D\r\n");
UART2_PrintString ("======== elgarbe =========\r\n");

UART2_PrintString ("Obteniendo Offset...\r\n");

L3G4200D_GetBiass();

UART2_PrintString ("Offset X: ");
uart2_printDouble(biass_X, 4);
UART2_PrintString("\r\n");
UART2_PrintString ("Offset Y: ");
uart2_printDouble(biass_Y, 4);
UART2_PrintString("\r\n");
UART2_PrintString ("Offset Z: ");
uart2_printDouble(biass_Z, 4);
UART2_PrintString("\r\n");

UART2_PrintString ("\r\n° X\t° Y\t° Z\r\n");


timer = msTicks; //get a start value to determine the time the loop takes

while ( 1 ){
L3G4200D_read_data();

gx += (((float)gyro_X - biass_X) * GYRO_X_SCALE) * timeStep/1000;
gy += (((float)gyro_Y - biass_Y) * GYRO_Y_SCALE) * timeStep/1000;
gz += (((float)gyro_Z - biass_Z) * GYRO_Z_SCALE) * timeStep/1000;

uart2_printDouble(gx, 3);
UART2_Sendchar(',');
uart2_printDouble(gy, 3);
UART2_Sendchar(',');
uart2_printDouble(gz, 3);
// UART2_Sendchar(',');
// uart2_printInt32(msTicks, 10);
UART2_PrintString("\r\n");

timer=msTicks-timer; // Obtengo cuánto tiempo pasó en el bucle
timer=timeStep-timer; // Obtengo lo que falta para llegar al timeStep
delay_ms(timer); // Espero hasta llegar al timeStep
timer=msTicks;
}
}

Como podemos ver simplemente hemos agregado la integracion discreta y al final del loop tenemos un par de instrucciones para calcular cuanto tiempo debo "perder" en mi bucle para llegar a los timeStep segundos.

Bueno, en el hyperterminal he logueado en un archivo los datos leidos del sensor para luego abrirlo con Excel y realizar el siguiente gráfico:

(http://imagizer.imageshack.us/v2/800x600q90/545/vzg8.jpg) (https://imageshack.com/i/f5vzg8j)

Como se puede observar, en la prueba he girado el sensor alrededor del eje X, primero 90° en un sentido, luego lo vuelvo a la posicion original luego lo giro en otro sentido y finalmente lo dejo quieto unos segundos.
El tiempo del eje horizontal es en segundos.
De este gráfico podemos ver 2 cosas cuando giro el sensor en un sentido hasta obtener máxima excursion, el ángulo no llega a 90°. Algirar en el otro sentido se pasa de 90°.
Finalmente podemos ver el tan odiado DRIFT. Cuando dejo el sensor quieto, debido al proceso de integracion, los datos no estan fijos, sino que el ángulo va creciendo en un sentido, es por ellos que los gyróscopos no suelen usarse solos para determinar la posicion del objeto que hemos rotado.
Para corregir el drift se utilizan los acelerómetros. Veremos su funcionamiento en el post dedicado a ellos.

Saludos!
Título: Re: Giroscopos - UAV's
Publicado por: PCCM en 15 de Enero de 2014, 23:39:34
Tengo entendido que el "Rate Noise Density"(Rn) como bien dices es el ruido del sensor.
Generalmente se denota el efecto del ruido por este parámetro o por el "Angular Random Walk".
La formula del Ruido del sensor está dada por: Ruido Sensor=(Rate Noise Density)*sqrt(Ancho de banda)
A más ancho de banda, más ruido se verá en el sensor.

Tal Rn se puede representar como la fluctuación de la medida del sensor. Para el caso de este sensor el  ruido del sensor será 0.03*sqrt(50)=0.212 dps, con la condición de que el ancho de banda sea de 50Hz como dice en el diagrama.

hay otros parámetros que también afectan al ruido total, pero para hallar el "ruido total"(RT) es:
RT=sqrt(Rn + .....), con este ejemplo y considerando solo el Rn, el RT dá aprox  0.46 dps.

Como dije otro parámetro común de encontrar en los gyros u otros sensores es en "Angular Random Walk"
Para convertir el "Rate Noise Density" a "Angular Random Walk"(ARW) solo se multiplica por 60.
Por ejemplo en este caso el Rn=0.03dps/sqrt(Hz)
entonces el ARW=0.03*60=1.8 grados/sqrt(hora), el ARW describe la desviación promedio cuando se integra la señal. Independientemente de otras características que contribuyen al error angular(como el factor escala o las bias).
El error incrementará a lo largo de la integración, por ejemplo para este caso dentro de una hora la desviación angular promedio será de 1.8*sqrt(1)=1.8 grados, después de 2 horas será 1.8*sqrt(2)= 2.54 grados.


Título: Re: Giroscopos - UAV's
Publicado por: PCCM en 16 de Enero de 2014, 00:01:22
Te resultaron esos valores debido al tiempo de integración que le colocaste(20 ms), el cual es demasiado como para calcular el ángulo con el giroscopo, si bajas la velocidad de muestreo solo para este ejemplo mejorará su comportamiento.

La velocidad de muestreo se puede aumentar a esos valores de 20ms o alrededor, cuando se tiene un algoritmo para corregir el angulo.
además recuerda corregir el factor escala.

Saludos
Título: Re: Giroscopos - UAV's
Publicado por: elgarbe en 16 de Enero de 2014, 00:12:01
Totalmente de acuerdo. Bajando el tiempo del lazo (tiempo de integracion) o mejorando el algoritmo de integracion se puede reducir y mucho la deriva.
La idea es mostrar que dicha deriva existe y que generalmente no se utiliza el giróscopo sin corregir con otro sensor debido a ello.
Puede ser que el corrimiento del cero se deba a que el sensor no esta perfectamente a 0° cuando está en reposo? deduzco que debe estar inlcinado unos 10° en el sentido del eje Y. por eso obtengo 20° de menos en un sentido y 20° de más en el otro.
Tambien tendría que trabajar en el factor de escala, por ahora y para estos ejemplos tomo el de la hoja de datos. Creo que lo ideal para el factor de escala sería hacerlo girar a velocidad constante y verificar con la lectura.
Todas esa mejoras y calibraciones harán que la deriva se reduzca, pero no desaparecerá....

Por cierto, como vienes con tu proyecto?

Saludos!
Título: Re: Giroscopos - UAV's
Publicado por: PCCM en 16 de Enero de 2014, 00:24:50
Ya que tu micro puede correr más rápido puedes mostrar los resultados a su máximo muestreo y ver como se comporta. yo no pude llegar ya que con toda la transmisión serial llegaba a 8ms.

a mediados de la prox. semana retomo el navegador inercial en el trabajo, ya que aún tengo problemas. Ahora estoy acabando otro proyecto, que me consume todo el tiempo.
Gracias por seguir compartiendo. Así animas a profundizase más en el tema.

saludos.
Título: Re: Giroscopos - UAV's
Publicado por: elgarbe en 16 de Enero de 2014, 09:25:45
Tengo entendido que el "Rate Noise Density"(Rn) como bien dices es el ruido del sensor.
Generalmente se denota el efecto del ruido por este parámetro o por el "Angular Random Walk".
La formula del Ruido del sensor está dada por: Ruido Sensor=(Rate Noise Density)*sqrt(Ancho de banda)
A más ancho de banda, más ruido se verá en el sensor.

Tal Rn se puede representar como la fluctuación de la medida del sensor. Para el caso de este sensor el  ruido del sensor será 0.03*sqrt(50)=0.212 dps, con la condición de que el ancho de banda sea de 50Hz como dice en el diagrama.

hay otros parámetros que también afectan al ruido total, pero para hallar el "ruido total"(RT) es:
RT=sqrt(Rn + .....), con este ejemplo y considerando solo el Rn, el RT dá aprox  0.46 dps.

Como dije otro parámetro común de encontrar en los gyros u otros sensores es en "Angular Random Walk"
Para convertir el "Rate Noise Density" a "Angular Random Walk"(ARW) solo se multiplica por 60.
Por ejemplo en este caso el Rn=0.03dps/sqrt(Hz)
entonces el ARW=0.03*60=1.8 grados/sqrt(hora), el ARW describe la desviación promedio cuando se integra la señal. Independientemente de otras características que contribuyen al error angular(como el factor escala o las bias).
El error incrementará a lo largo de la integración, por ejemplo para este caso dentro de una hora la desviación angular promedio será de 1.8*sqrt(1)=1.8 grados, después de 2 horas será 1.8*sqrt(2)= 2.54 grados.


Fantàstico, ahora entiendo un poco más el tema!
En este contexto, que sería el ancho de banda? por que es 50Hz en tu ejemplo? eso es otra cosa que siempre tuve como duda...

Saludos!
Título: Re: Giroscopos - UAV's
Publicado por: PCCM en 17 de Enero de 2014, 03:45:39
Le puse 50Hz ya que en la imagen que colocaste, en el "Test condition" del "Rate Noise density", dice que calcularon ese valor con esa condición.
El valor de 0.03 dps/sqrt(Hz) es un promedio del análisis del "Rn" en los 3 ejes y en todos los rangos.
Por ejemplo en un ejemplo de STMicroeletronics en la siguiente tabla se ve como obtuvieron el "Rn" para un gyro, realizandole 6 test, en todos los rangos con un ancho de banda de 12.5Hz.

(http://imageshack.com/a/img836/7373/ucc0.png)

El promedio de todos estos "Rn" es 0.029dps/sqrt(Hz) el cual es dato para el datasheet del sensor.

El ancho de banda es el rango de frecuencia en la cual el sensor va a obtener los datos, cuanto más ancho de banda el sensor será más sensible y por la formula anterior tendrá mas ruido, "sqrt" veces el ancho de banda, generalmente se define este valor para el filtro pasa bajos que incorpora los gyros digitales.Un mejor ejemplo está en la siguiente imagen del mpu6050.

(http://imageshack.com/a/img24/2971/toq7.png)

Para el caso de gyro se puede observar que se puede configurar varios anchos de banda desde 5Hz a 256Hz, para el filtro pasa bajos. Estos filtros tienen su demora de procesamiento como se describe en la parte derecha. y los cuales estos datos pueden ser muestreados optimamente a la frecuencia especificada más a la derecha.
Título: Re: Giroscopos - UAV's
Publicado por: elgarbe en 17 de Enero de 2014, 23:30:08
Ya que tu micro puede correr más rápido puedes mostrar los resultados a su máximo muestreo y ver como se comporta. yo no pude llegar ya que con toda la transmisión serial llegaba a 8ms.

a mediados de la prox. semana retomo el navegador inercial en el trabajo, ya que aún tengo problemas. Ahora estoy acabando otro proyecto, que me consume todo el tiempo.
Gracias por seguir compartiendo. Así animas a profundizase más en el tema.

saludos.

Bueno, siguiendo tu consejo he hecho la prueba. Mi tiempo de muestreo está en 5mseg. Para que te des una idea, la lectura del giro toma 846uSeg, el envío de los datos a 115200bps toma 1535uSeg.

El resultado es mucho mejor:

(http://imagizer.imageshack.us/v2/800x600q90/690/dx4j.jpg) (https://imageshack.com/i/j6dx4jj)

Notar que el experimento fue por 96seg. y ver lo planchado que esta al comienzo y al final...
Para tener una idea, en el segundo 62.082 es cuando el gyro quedó estable:
2,714   4,808   3,029   62,080
en el segundo 96.8 tengo:
4,085   4,999   3   96,800

son 1.3° para el eje X, 0.19° para el Y y 0.029 para el Z!!!!!!!!!!!!!!!!!!!!!!

Respecto al 1.3° del eje X te digo que otra cosa que noté es la variacion del Offset del gyro. Si obtengo 10 veces el offset obtengo valores distintos, similares, pero distintos. He visto proyectos en donde para sacar el offset toman 1000 muestras y obtienen 10 veces el offset y toman el promedio de las 10.

También probe, pero no documenté, una especie de filtro con la desviacion estándar. Lo que hacía es es tomar 600 mediciones y promediarlar. Luego tomaba 600 muestras y calculaba la desviacion estándar. Mi "filtro" era cualquier cosa por debajo de la desviacion estándar era considerado 0....

Tengo que reconocer que de ruido y sus filtros en sensores conozco poco y nada...

En fin, esa deriba que estoy obteniendo para mí es más que suficiente, pensar que no está corregida con ningun otro sensor... Tambien hay que tener en cuenta que 5mseg en el bucle principal es medio complicado, cuando se agrega el mantenimiento de la DCM y la lectura de los otros sensores no sé si se podrá llegar a ese tiempo... En breve espero poder probarlo y documentarlo...

Ahora lo que tendría que probar es pasar el I2C a 400KHz y tratar de aumentar el ODR para ver si se pueden achicar los tiempos...

Saludos!
Título: Re: Giroscopos - UAV's
Publicado por: elgarbe en 18 de Enero de 2014, 00:01:02
Bueno, una más antes de irme a dormir....

Probé el cálculo del Offset varias veces para obtener el promedio, esto es lo que obtuve:

(http://imagizer.imageshack.us/v2/800x600q90/32/ml98.jpg) (https://imageshack.com/i/0wml98j)

Los datos son estos:

Código: [Seleccionar]
Giroscopo L3G4200D
======== elgarbe =========
Obteniendo Offset,,,

Off X Off Y Off Z
14,7650 -6,6450 -16,9767
13,6813 -6,2011 -16,2850
16,4128 -6,9820 -16,1655
14,1807 -6,1783 -15,8136
12,0853 -6,1503 -15,4730
11,4201 -6,4936 -15,4841
14,6824 -7,7158 -17,5491
14,1978 -6,6879 -16,6009
11,2137 -6,3128 -15,8093
13,4737 -6,7789 -15,9997
14,6541 -7,7446 -17,3417
15,6844 -5,6879 -16,4706
15,7995 -6,9811 -17,2991
12,5280 -6,6216 -16,2238
15,0509 -7,4894 -17,0370
12,1918 -7,4025 -15,7367
10,7087 -5,5807 -15,0629
14,6795 -6,5976 -17,2384
17,5895 -6,3977 -17,2421
14,3876 -6,6740 -17,2337
17,1590 -6,1561 -17,3587
12,9019 -8,3619 -17,2173
16,6715 -5,5073 -16,5554
11,5845 -4,4708 -14,5943
14,3793 -5,1458 -14,9893
14,3073 -5,5852 -15,9983
15,4022 -5,8226 -15,3983
15,7257 -5,6230 -16,9540
17,4695 -6,1977 -17,3816
12,4408 -6,7937 -17,0023
15,8257 -5,3447 -16,0317
15,0364 -7,8256 -18,6051
15,1984 -5,7264 -16,8127
15,7703 -7,0829 -17,5664
12,4696 -6,8835 -16,2193
14,5774 -6,3431 -16,2870
13,7460 -6,8506 -17,4171
16,0412 -7,1298 -17,6457
13,0134 -7,0202 -17,0961
15,7667 -6,5450 -17,1052
15,2813 -6,0992 -17,0935
14,8471 -7,7768 -18,2035
12,7764 -6,0563 -16,0737
15,6930 -5,7568 -16,3551
15,7678 -6,5696 -16,6073
14,8113 -7,0726 -17,9110
13,0630 -8,0501 -17,9765
14,6934 -4,5884 -15,0300
12,2912 -6,6126 -16,9900
14,7655 -6,7760 -17,1867

14,3773 -6,5019 -16,6541

La última fila es el promedio de los 50 offset's.... en el gráfico puse una linea de tendencia Lineal con su ecuacion....
Conclusiones?

Saludos!
Título: Re: Giroscopos - UAV's
Publicado por: elgarbe en 18 de Enero de 2014, 15:52:40
Bueno, un experimento más.

Calculo el offset promediando 50 juegos de offset, cada uno de 600 muestras.

El resultado:

(http://imagizer.imageshack.us/v2/800x600q90/577/oq3n.jpg) (https://imageshack.com/i/g1oq3nj)

Luego tomo el promedio de esos 50 juegos de offset y ejecuto el algoritmo que integra la velocidad angular para obtener el ángulo en el que se encuentra el sensro y obtengo:

(http://imagizer.imageshack.us/v2/800x600q90/856/15b8.jpg) (https://imageshack.com/i/ns15b8j)


Como resultado se destaca:

En el segundo 97 tengo:
2,425   6,706   2,24   97

y al final, en el segundo 158 tengo:

4,408   6,913   1,369   158

Graficamente:

(http://imagizer.imageshack.us/v2/800x600q90/689/axia.jpg) (https://imageshack.com/i/j5axiaj)

En el eje X tengo algo raro, es como si fuese muy ruidoso y es el que más deriva tiene. Luego el eje Y tiene 0.2° en 1 minuto. El eje Z sufrió un pequeño codazo mío que hizo que el se gire un poco, por eso el salto en el valor. Pero en el gráfico se ve que es muy estable....

Alguna idea que pasará con el eje X???

Saludos!
Título: Re: Giroscopos - UAV's
Publicado por: PCCM en 20 de Enero de 2014, 03:32:54
Cuanto más muestras obtienes para obtener el offset menor es la variación en cada cálculo del offset, ya que se obtiene más datos del ruido involucrado. Yo hago algo parecido como tu pero en vez de calcular 50 veces el offset con 600 muestras, calculo el offset solo una vez con 3000 muestras.

Como analizaste en las graficas el calculo en el offset nunca va a ser constante, parece que es por la variación de la temperatura ya que es un factor importante en la suma del ruido.

Viendo en el datasheet del sensor que uso mpu6050, un dato nos da esta variación: "Sensitivity change vs Temperature" = +-0.02%/grados centigrados
lo cual nos dice que por cada variación de 1 grados centigrado tenemos una variación de +-2% de lo sensado.
En el sensor que uso en promedio en cada lectura la temperatura varia 0.19 miligrados. el cual parte de casi 26 grados hasta 32 grados después de varios segundos en el cual se estabiliza, pero siempre variando.

Puede ser que el mayor ruido que viste en el ejex, sea aleatorio, en mi caso cada vez que hago pruebas. a veces el ejex, ejey o ejez son más ruidosos.
Y las pruebas que estas haciendo es para movimientos lentos, podrías hacer pruebas para movimientos bruscos, ya que en el comportamiento real será asi. En las pruebas que hice cuando hago movimientos bruscos, el sensor se desvia demasiado en pocos segundos. por ejemplo de 0,0,0 a 66,4,88. o a otros valores pero el desvió es demasiado.


Título: Re: Giroscopos - UAV's
Publicado por: elgarbe en 20 de Enero de 2014, 21:54:36
Cuanto más muestras obtienes para obtener el offset menor es la variación en cada cálculo del offset, ya que se obtiene más datos del ruido involucrado. Yo hago algo parecido como tu pero en vez de calcular 50 veces el offset con 600 muestras, calculo el offset solo una vez con 3000 muestras.

Es cierto, no sé si tiene mucho sentido hacer promedio de medias...

Como analizaste en las graficas el calculo en el offset nunca va a ser constante, parece que es por la variación de la temperatura ya que es un factor importante en la suma del ruido.

Viendo en el datasheet del sensor que uso mpu6050, un dato nos da esta variación: "Sensitivity change vs Temperature" = +-0.02%/grados centigrados
lo cual nos dice que por cada variación de 1 grados centigrado tenemos una variación de +-2% de lo sensado.
En el sensor que uso en promedio en cada lectura la temperatura varia 0.19 miligrados. el cual parte de casi 26 grados hasta 32 grados después de varios segundos en el cual se estabiliza, pero siempre variando.

Puede ser que el mayor ruido que viste en el ejex, sea aleatorio, en mi caso cada vez que hago pruebas. a veces el ejex, ejey o ejez son más ruidosos.
Y las pruebas que estas haciendo es para movimientos lentos, podrías hacer pruebas para movimientos bruscos, ya que en el comportamiento real será asi. En las pruebas que hice cuando hago movimientos bruscos, el sensor se desvia demasiado en pocos segundos. por ejemplo de 0,0,0 a 66,4,88. o a otros valores pero el desvió es demasiado.

Voy a ver el tema de la temperatura. Quizá podría loguear un dia entero RAW data vs Temperatura y ver que obtengo.

Lo de los ejes es cierto, a veces esa deriva se ve en el eje X, a veces en el Y.

La deriva con el movimiento no sé bien a que responde, fijate en mis ejemplos que al finalizar y dejar el sensor en reposo aparecen unos grados de deriva, que no son por el offset ya que si ves cuanto se deriva cuando esta quieto en ese tiempo no da tanta driva....

Por cierto, tenes algo de filtro complementario para combinar los datos del gyro y del accel? en matlab?

Saludos!
Título: Re: Giroscopos - UAV's
Publicado por: PCCM en 21 de Enero de 2014, 02:08:02
No se puede ver bien la deriva que tienes cuando esta quieto al inicio. Pero se ve que son solo por 18 segundos.
pero cuando lo mueves y dejas de mover analizas la desviación después de 60 segundos.

El filtro complementario es en una sola linea:
Angulo_estimado=alpha*(Angulo_debido_gyro) + (1-alpha)*(Angulo_debido_acel)

donde alpha generalmente es un valor alto(0.98, 0.99, ..), este se comporta como filtro pasa bajos para el acelerometro y filtro pasa altos para el giroscopo.
ya que para tiempos pequeños es bueno el gyro, pero para largos tiempos se aprovecha el acelerometro para que lo corrija.

Como se ve el analisis solo es en frecuencia, y como sabrás el filtro complementario es un filtro kalman "reducido", en el filtro complementario no se considera el análisis estadístico del ruido en la salida y en el proceso. Lo problemático de kalman es hallar estos datos estadísticos(covarianza) y datos iniciales, ya que por ejemplo se puede hallar la covarianza del ruido a la salida, midiendo la diferencia entre el angulo calculado entre el giroscopo y acelerometro, pero la covarianza del ruido en el proceso generalmente se estima con las pruebas y error que se realizan.

Además si se quiere usar el filtro kalman eficientemente, no es suficiente usar tal filtro sino su variación: el filtro kalman extendido, ya que este ultimo se basa en la estimación del angulo para sistemas no lineales, los cuales son realmente como se comporta el gyro y acelerometro.

Pero no son los unicos , hay varios algoritmos , como el de Mahony, Madgwick, etc

En un post mio sobre "ayuda de acelerómetro" tenía el problema sobre estos estimadores. cuando implementes tu estimador de actitud(sea por filtro complementario o cualquier otro) prueba dejandolo quieto en la mesa y moviendolo de un lado a otro, supuestamente en cabeceo y banqueo debe permanecer en 0 grados pero aumenta debido a la acelereración provocada.

Saludos.
Título: Re: Giroscopos - UAV's
Publicado por: jonathanPIC888 en 25 de Enero de 2014, 16:16:10
Hola como están. Siguiendo sus consejos he implementado una librería para CCS del L3G4200D, con los siguientes resultados:

Eso es en reposo...

Código: [Seleccionar]
GYRO SCALED x:0.06,y:-0.10,z:0.02

GYRO RAW x:-010,y:0003,z:0005

GYRO SCALED x:0.00,y:-0.03,z:-0.04

GYRO RAW x:-010,y:0003,z:0005

GYRO SCALED x:0.06,y:-0.03,z:0.02

GYRO RAW x:-010,y:0003,z:0006

GYRO SCALED x:0.06,y:-0.03,z:-0.04

GYRO RAW x:-011,y:0002,z:0004

GYRO SCALED x:0.13,y:-0.10,z:-0.18

GYRO RAW x:-010,y:0003,z:0004

GYRO SCALED x:0.06,y:-0.10,z:-0.04

Giro completo en el eje Z....

Código: [Seleccionar]
GYRO SCALED x:0.20,y:0.10,z:-2.35

GYRO RAW x:-039,y:-437,z:-571

GYRO SCALED x:-11.97,y:-6.26,z:-363.62

GYRO RAW x:0005,y:0427,z:-921

GYRO SCALED x:-5.32,y:-9.20,z:-272.97

GYRO RAW x:-007,y:-008,z:0329

GYRO SCALED x:0.00,y:0.10,z:18.01

GYRO RAW x:-010,y:0005,z:0192

GYRO SCALED x:0.06,y:0.03,z:15.21

Los datos no me coinciden mucho con los de sus ejemplos...quizá sea por los tipos de datos...pero sinceramente no estoy muy seguro si las lecturas son correctas al 100%.

igual les dejo mi código de ejemplo y la librería:

Código: C
  1. // CCS library compilation [2014]
  2. // Driver para el giroscopio L3G4200D.
  3. // Programador: Moyano Jonathan
  4. // Compilador: CCS v4.140
  5. // Versión de la librería: v1.0 Revisión: 0.1
  6. // Fecha de modificación: Enero de 2014.
  7.  
  8. // Definición de macros y funciones
  9. #include <L3G4200D.h>  
  10.  
  11. // Desarrollo de las funciones de usuario.
  12.  
  13. void L3G4200D_write(int8 reg_address, int8 value){
  14.  
  15.    i2c_start();                       // Inicializa comunicación I2C, condición de start.
  16.    i2c_write(L3G4200D_WRITE_DEV_ADD); // Envíamos la dirección del dispositivo + comando para escritura.
  17.    i2c_write(reg_address);            // Indicamos que registro será escrito.
  18.    i2c_write(value);                  // Enviamos el nuevo valor al registro.
  19.    i2c_stop();                        // Condición de stop.
  20.  
  21. }
  22.  
  23. unsigned char L3G4200D_read(unsigned char reg){
  24.  
  25. unsigned char val = 0x00;  // Variable auxiliar.
  26.    
  27.    i2c_start();                       // Inicializa comunicación I2C, condición de start.
  28.    i2c_write(L3G4200D_WRITE_DEV_ADD); // Envíamos la dirección del dispositivo + comando para escritura.
  29.    i2c_write(reg);                    // Indicamos que registro será leído.
  30.    i2c_start();                       // Reiniciamos la comunicación.
  31.    i2c_write(L3G4200D_READ_DEV_ADD);  // Envíamos la dirección del dispositivo + comando para lectura.
  32.    val = i2c_read(0);                 // Leemos el registro.        
  33.    i2c_stop();                        // Condición de stop.
  34.    return(val);                       // Retornamos con el valor leído.
  35. }
  36.  
  37.  
  38. void L3G4200D_GetRawAxis(signed int16 *rx, signed int16 *ry, signed int16 *rz){
  39.  
  40. // Variables auxiliares.
  41. signed int16 ax=0x00;
  42. signed int16 ay=0x00;
  43. signed int16 az=0x00;
  44. int8  lsb,msb;
  45.  
  46.  msb=L3G4200D_read(L3G4200D_OUT_X_H);
  47.  lsb=L3G4200D_read(L3G4200D_OUT_X_L);
  48.    ax=make16(msb,lsb);
  49.  msb=L3G4200D_read(L3G4200D_OUT_Y_H);
  50.  lsb=L3G4200D_read(L3G4200D_OUT_Y_L);
  51.    ay=make16(msb,lsb);
  52.  msb=L3G4200D_read(L3G4200D_OUT_Z_H);
  53.  lsb=L3G4200D_read(L3G4200D_OUT_Z_L);
  54.    az=make16(msb,lsb);
  55.  
  56.   *rx=ax;
  57.   *ry=ay;
  58.   *rz=az;
  59. }
  60.  
  61. void L3G4200D_init(int16 rango){
  62.  
  63.   // Habilitamos los ejes X,Y,Z y encendemos el dispositivo.
  64.   L3G4200D_write(L3G4200D_CTRL_REG1,0b00001111);
  65.   // Configuración del registro CTRL_REG2.
  66.   L3G4200D_write(L3G4200D_CTRL_REG2,0b00011001);
  67.   // Configuramos el registro CTRL_REG3.
  68.   L3G4200D_write(L3G4200D_CTRL_REG3,0x00);
  69.   // Configuramos el registro CTRL_REG5.
  70.   L3G4200D_write(L3G4200D_CTRL_REG5,0b00010011);
  71.  
  72.   // Configuramos el rango.
  73.  
  74.   if(rango == 250){
  75.     L3G4200D_write(L3G4200D_CTRL_REG4,0x00); // 250  º/seg
  76.   }else if(rango == 500){
  77.     L3G4200D_write(L3G4200D_CTRL_REG4,0x10); // 500  º/seg
  78.   }else{
  79.     L3G4200D_write(L3G4200D_CTRL_REG4,0x20); // 2000 º/seg
  80.   }
  81.  
  82. }
  83.  
  84. int8 ReadWhoAmI(void){
  85.  
  86. // Variable auxiliar.
  87.  int8 value=0x00;
  88.   value=L3G4200D_read(L3G4200D_WHO_AM_I); // Leemos el registro.
  89.     return(value);                        // Retornamos con el valor.
  90. }
  91.  
  92. void L3G4200D_GetBiass(float *_bx, float *_by, float *_bz){
  93.  
  94. // Variable auxiliar.
  95. int16 i=0x00;
  96. signed int16 _x,_y,_z;
  97. float biass_X;
  98. float biass_Y;
  99. float biass_Z;
  100.  
  101.    // Obtenemos 600 muestras cada 1ms.
  102.    for (i =0; i<600; i += 1) {
  103.       L3G4200D_GetRawAxis(&_x,&_y,&_z);
  104.       biass_X += _x;
  105.       biass_Y += _y;
  106.       biass_Z += _z;
  107.       delay_ms(1);
  108.    }
  109.    
  110.    // Promediamos..
  111.    biass_X /= 600;
  112.    biass_Y /= 600;
  113.    biass_Z /= 600;
  114.    
  115.    // Retornamos los valores.
  116.    *_bx = biass_X;
  117.    *_by = biass_Y;
  118.    *_bz = biass_Z;
  119. }
  120.  
  121. void L3G4200D_GetScaledAxis(float *_sx, float *_sy, float *_sz, float biassX, float biassY, float biassZ, int16 rango){
  122.  
  123. signed int16 _x,_y,_z;
  124. float gx,gy,gz;
  125. float escala;
  126.  
  127.   // Adquirimos los datos crudos..
  128.   L3G4200D_GetRawAxis(&_x,&_y,&_z);
  129.   // A los datos crudos le resto el biass.
  130.    gx=((float)_x - biassX);
  131.    gy=((float)_y - biassY);
  132.    gz=((float)_z - biassZ);
  133.    
  134.  // La sensibilidad va a estar determinada por el rango...
  135.  
  136.    if(rango == 250){ escala = 0.00875;      // 250  º/seg
  137.   }else if(rango == 500){escala = 0.0175;   // 500  º/seg
  138.   }else{escala = 0.07;                      // 2000 º/seg
  139.   }
  140.  
  141.   // Determino los datos correctos, utilizando la fórmula: (RAW - Offset) * Sensibilidad
  142.    gx *= escala;
  143.    gy *= escala;
  144.    gz *= escala;
  145.    
  146.     // Retornamos con los datos.
  147.     *_sx = gx;
  148.     *_sy = gy;
  149.     *_sz = gz;
  150. }

encabezado...

Código: C
  1. // CCS library compilation [2014]
  2. // Driver para el giroscopio L3G4200D.
  3. // Programador: Moyano Jonathan
  4. // Compilador: CCS v4.140
  5. // Versión de la librería: v1.0 Revisión: 0.1
  6. // Fecha de modificación: Enero de 2014.
  7.  
  8. // Macros y definición de registros internos.
  9.  
  10. #define L3G4200D_WRITE_DEV_ADD  0xD0
  11. #define L3G4200D_READ_DEV_ADD   0xD1
  12.  
  13. #define L3G4200D_WHO_AM_I       0x0F
  14.  
  15. #define L3G4200D_CTRL_REG1      0x20
  16. #define L3G4200D_CTRL_REG2      0x21
  17. #define L3G4200D_CTRL_REG3      0x22
  18. #define L3G4200D_CTRL_REG4      0x23
  19. #define L3G4200D_CTRL_REG5      0x24
  20. #define L3G4200D_REFERENCE      0x25
  21. #define L3G4200D_OUT_TEMP       0x26
  22. #define L3G4200D_STATUS_REG     0x27
  23.  
  24. #define L3G4200D_OUT_X_L        0x28
  25. #define L3G4200D_OUT_X_H        0x29
  26. #define L3G4200D_OUT_Y_L        0x2A
  27. #define L3G4200D_OUT_Y_H        0x2B
  28. #define L3G4200D_OUT_Z_L        0x2C
  29. #define L3G4200D_OUT_Z_H        0x2D
  30.  
  31. #define L3G4200D_FIFO_CTRL_REG  0x2E
  32. #define L3G4200D_FIFO_SRC_REG   0x2F
  33.  
  34. #define L3G4200D_INT1_CFG       0x30
  35. #define L3G4200D_INT1_SRC       0x31
  36. #define L3G4200D_INT1_THS_XH    0x32
  37. #define L3G4200D_INT1_THS_XL    0x33
  38. #define L3G4200D_INT1_THS_YH    0x34
  39. #define L3G4200D_INT1_THS_YL    0x35
  40. #define L3G4200D_INT1_THS_ZH    0x36
  41. #define L3G4200D_INT1_THS_ZL    0x37
  42. #define L3G4200D_INT1_DURATION  0x38
  43.  
  44. // Definimos los pines utilizados para la comunicación (POR DEFECTO).
  45. #define _SDA PIN_B0
  46. #define _SCL PIN_B1
  47.  
  48. // Configuramos el puerto utilizado para la comunicación I2C a 400Khz.
  49. #use i2c(Master,Fast, SDA=_SDA, SCL=_SCL)  
  50.  
  51. // Escribe un registro del L3G4200D.
  52. void L3G4200D_write(int8 reg_address, int8 value);
  53. // Lee un registro del L3G4200D.
  54. unsigned char L3G4200D_read(unsigned char reg);
  55. // Lee los 3 ejes del giroscopio.
  56. void L3G4200D_GetRawAxis(signed int16 *rx, signed int16 *ry, signed int16 *rz);
  57. // Inicializa el L3G4200D y selecciona la escala de medida en º/seg.
  58. void L3G4200D_init(int16 rango);
  59. // Lee el registro Who i am ?
  60. int8 ReadWhoAmI(void);
  61. // Obtiene el offset del sensor.
  62. void L3G4200D_GetBiass(float *_bx, float *_by, float *_bz);
  63. // Obtiene los datos en grados/segundos.
  64. void L3G4200D_GetScaledAxis(float *_sx, float *_sy, float *_sz, float biassX, float biassY, float biassZ, int16 rango);

Otra consulta que tengo, para poder visualizar el ángulo en el que se encuentra el giróscopo, tengo que multiplicar por el tiempo de muestreo verdad ?
Título: Re: Giroscopos - UAV's
Publicado por: elgarbe en 25 de Enero de 2014, 18:33:13
Pero que buena codificacion!!!! Ojalá yo fuses tan prolijo con el código!!!!

En principio, si solo lees los datos raw y luego le sacas el offset y lo escalas lo que obtienes es la velocidad angular. Entonces, por más que des un giro completo los datos que mostrás pueden estar bien o no... depende de con que velocidad lo estés girando....

Para obtener el ángulo de giro debes hacer la integracion discreta, es mas o menos como vos dijiste, al angulo actual le sumas la velocidad leída x el tiempo de muestreo. Yo uso estas líneas:

      L3G4200D_read_data();

      gx += (((float)gyro_X - biass_X) * GYRO_X_SCALE) * timeStep/1000;
      gy += (((float)gyro_Y - biass_Y) * GYRO_Y_SCALE) * timeStep/1000;
      gz += (((float)gyro_Z - biass_Z) * GYRO_Z_SCALE) * timeStep/1000;

De alguna forma debes asegurar que el tiempo del bucle principal (si es que ahí haces la integracion) dure un tiempo conocido, en mi caso timeStep.

Si fueses tan amable, te pediría el main con el que obtuviste los datos que mostraste. La librería que pusiste va a mis favoritos y en caso de usar pic la usaré.

Seré curioso, que aplicacion estás trantado de desarrollar?

Saludos!!!
Título: Re: Giroscopos - UAV's
Publicado por: jonathanPIC888 en 25 de Enero de 2014, 19:04:02
Citar
Pero que buena codificacion!!!! Ojalá yo fuses tan prolijo con el código!!!!

Muchas gracias, igual me falta pulir algunas cosas de la programación.

Citar
En principio, si solo lees los datos raw y luego le sacas el offset y lo escalas lo que obtienes es la velocidad angular. Entonces, por más que des un giro completo los datos que mostrás pueden estar bien o no... depende de con que velocidad lo estés girando....

En mi caso lo estoy girando con la mano, tendría que utilizar algún sistema mecánico más estable para hacerlo girar a velocidades angulares constantes.

Citar
Para obtener el ángulo de giro debes hacer la integracion discreta, es mas o menos como vos dijiste, al angulo actual le sumas la velocidad leída x el tiempo de muestreo.

Voy a implementar una tarea con RTOS de CCS para que cada 50ms haga una lectura de los 3 ejes....ahora no entiendo lo siguiente:


* timeStep/1000; ----> por que es el tiempo de muestreo dividido 1000 ? Si uso el RTOS...el timeStep serian los 50ms que le indico para que realice la adquisición ?

El main que utilizo es el siguiente:

Código: C
  1. // Programa: Prueba del giroscopio L3G4200D.
  2. // Programador: Moyano Jonathan.
  3. // Fecha: Enero de 2014.
  4. // Versión: v1.0
  5. // Revisión: r0.1
  6. /////////////////////////////////////////////
  7.  
  8. // Incluimos plantilla.
  9. #include <Plantilla_UconnectME28.h>  // Drivers de periféricos.
  10.  
  11. // Variables globales.
  12. float _sx,_sy,_sz;
  13. float bx,by,bz;
  14. int8 data=0x00;
  15. signed int16 _rx,_ry,_rz;
  16.  
  17. void main ()
  18. {
  19.     // Inicializamos el sensor.
  20.     L3G4200D_init(2000);
  21.    
  22.     // Verificamos el funcionamiento de la comunicación.
  23.      data=ReadWhoAmI();
  24.       fprintf(DEBUG,"who am I:%u\r\n",data);
  25.        delay_ms(2000);
  26.        
  27.        // Determinamos el offset del sensor.
  28.        L3G4200D_GetBiass(&bx,&by,&bz);
  29.        fprintf(DEBUG,"Offset x:%f\r\n",bx);
  30.        fprintf(DEBUG,"Offset y:%f\r\n",by);
  31.        fprintf(DEBUG,"Offset z:%f\r\n",bz);
  32.        delay_ms(2000);
  33.  
  34.    
  35.     while(true){
  36.    
  37.          // Imprime los datos crudos del giróscopo.
  38.          L3G4200D_GetRawAxis(&_rx,&_ry,&_rz);
  39.          fprintf(DEBUG,"GYRO RAW x:%04ld,y:%04ld,z:%04ld\r\n\r\n",_rx,_ry,_rz);
  40.          
  41.          // Imprimimos la velocidad angular cada 50ms aprox.
  42.          L3G4200D_GetScaledAxis(&_sx,&_sy,&_sz,bx,by,bz,2000);
  43.          fprintf(DEBUG,"GYRO SCALED x:%f,y:%f,z:%f\r\n\r\n",_sx,_sy,_sz);
  44.          delay_ms(50);
  45.       }    
  46.                      
  47.    }

La librería la hice siguiendo tus consejos del acelerómetro y leyendo la hoja de datos del sensor. Vos podrías adaptarla perfectamente para trabajar con el LCP1769.

Con respecto a la aplicación, es para un sistema de navegación en un robot móvil. En estos momentos estoy tratando de entender la física y demás parámetros para poder
implementarlo con un PIC trabajando a 12mips a 48Mhz....o 16Mips a 64Mhz.
Ya tengo librerías desarrolladas para HCM5883L (magnetómetro), BMP085 (barómetro - falta función para determinar la altura con respecto a nivel del mar), ADXL345 (acelerómetro - falta función para escalar los datos y obtener la aceleración en Gs)..y algunas otras funciones más y dispositivos como el GPS que se irán integrando con el tiempo.


Título: Re: Giroscopos - UAV's
Publicado por: elgarbe en 26 de Enero de 2014, 00:52:03
* timeStep/1000; ----> por que es el tiempo de muestreo dividido 1000 ? Si uso el RTOS...el timeStep serian los 50ms que le indico para que realice la adquisición ?

En mi caso timeStep vale 20 (mseg). Lo divido por 1000 para que quede en segundos, ya que el sensor nos etrega rad/seg debemos multiplicar por el tiempo en segundos. Me explico?

Con respecto a la aplicación, es para un sistema de navegación en un robot móvil. En estos momentos estoy tratando de entender la física y demás parámetros para poder
implementarlo con un PIC trabajando a 12mips a 48Mhz....o 16Mips a 64Mhz.
Ya tengo librerías desarrolladas para HCM5883L (magnetómetro), BMP085 (barómetro - falta función para determinar la altura con respecto a nivel del mar), ADXL345 (acelerómetro - falta función para escalar los datos y obtener la aceleración en Gs)..y algunas otras funciones más y dispositivos como el GPS que se irán integrando con el tiempo.

Por los sesnores que tienes imagino que usas la GY-80. Yo estoy usando la misma. Tengo el barometro funcionando, pero aún no hice tiempo de postearlo. Fijate en este subforo que he escrito sobre el acelerómetro también.
Ahora estoy con el magnetómetro. Si quieres compartir tu código será bienvenido!

No me imagino la navegacion de un robot con acelerómetros, gyros y demás. Me gustaría saber más de tu desarrollo...

Saludos y estamos en contacto!


Título: Re: Giroscopos - UAV's
Publicado por: PCCM en 27 de Enero de 2014, 01:49:06
Hola Jonathan, dices que tienes librerías desarrolladas para el HMC5883L. Has hecho pruebas de como te da el azimut para ángulos de cabeceo o banqueo superiores a +-40 grados?, se que se puede solucionar con el giroscopo, pero con el magnetómetro solo?

Saludos, y excelente trabajo.
Título: Re: Giroscopos - UAV's
Publicado por: jonathanPIC888 en 27 de Enero de 2014, 15:13:40
Citar
En mi caso timeStep vale 20 (mseg). Lo divido por 1000 para que quede en segundos, ya que el sensor nos etrega rad/seg debemos multiplicar por el tiempo en segundos. Me explico?

Ok, ahora entiendo. Entonces si genero una tarea que se ejecute cada 50ms, mi timeStep sería 50ms/1000.

Citar
Tengo el barometro funcionando, pero aún no hice tiempo de postearlo. Fijate en este subforo que he escrito sobre el acelerómetro también.

Voy a postear la librería que tengo del acelerómetro, barómetro y magnetómetro dentro del foro de UAV.

Citar
No me imagino la navegacion de un robot con acelerómetros, gyros y demás. Me gustaría saber más de tu desarrollo...

Quiero darle a un robot, una posición X,Y dentro de una zona a campo abierto y que se guíe por IMU+GPS. Luego quiero darle la misma dirección X,Y dentro de una zona cerrada y que se guíe por radar + cámara + odometría. Es un proyecto ambicioso, pero por ahora estoy aprendiendo...no se nada sobre navegación ni tampoco mucho sobre sistemas
de control de lazo cerrado complejos...

Citar
Has hecho pruebas de como te da el azimut para ángulos de cabeceo o banqueo superiores a +-40 grados?, se que se puede solucionar con el giroscopo, pero con el magnetómetro solo?

Disculpá mi ignorancia, pero no entiendo tu pregunta  :(




Título: Re: Giroscopos - UAV's
Publicado por: elgarbe en 27 de Enero de 2014, 15:51:46
Quiero darle a un robot, una posición X,Y dentro de una zona a campo abierto y que se guíe por IMU+GPS. Luego quiero darle la misma dirección X,Y dentro de una zona cerrada y que se guíe por radar + cámara + odometría. Es un proyecto ambicioso, pero por ahora estoy aprendiendo...no se nada sobre navegación ni tampoco mucho sobre sistemas
de control de lazo cerrado complejos...

Ok, si queres te comento algo, no lo tomes 100% seguro ya que es mi conclusion de lo que vengo leyendo hace unos meses. Creo que no se puede o es muy dificil conocer la posicion de un objeto midiendo con acelerómetros, giróscopos y magnetómetros. Tengo entendido que podes obtener con cierta presicion la orientacion (léase, rotación) del objeto. Para obtener la posicion deberías integrar 2 veces la medicion del acelerómetro por ejemplo (verdad?) y tengo entendido que la primera integra aporta deriva y una segunda integral hace ilegible la medicion. Fijate en este video si no entendí mal:
El proyecto es muy, pero muy interesante! todo lo que quieras y puedas compartir será bienvenido ya que será de utilidad para el resto de los proyectos que pueden aparecer en este foro y sin duda me será de utilidad para mi controladora de vuelo.

Citar
Has hecho pruebas de como te da el azimut para ángulos de cabeceo o banqueo superiores a +-40 grados?, se que se puede solucionar con el giroscopo, pero con el magnetómetro solo?

Disculpá mi ignorancia, pero no entiendo tu pregunta  :(

Lo que pregunta es si has probado la medicion del ángulo (respecto del norte) pero inclinando tu magnetómetro. En la pràctica cuando inclinas el magnetómetro la lectura deja de ser correcta y el límite esta en los 40º aproximadamente. Para evitar ese error se suele compensar con acelerómetros. Compensar con magnetometro solo no sé si se podrá... imagino que conociendo el vector flujo magnetíco terrestre con presicion en el lugar de operacion (es un vector que no es paralelo a la tierra) y combinand la lectura de los tres ejes del magnetómetro se podría estimar... pero no sé... estoy lejos de eso por ahora!!!

Saludos!
Título: Re: Giroscopos - UAV's
Publicado por: jonathanPIC888 en 27 de Enero de 2014, 16:47:00
Citar
Tengo entendido que podes obtener con cierta presicion la orientacion (léase, rotación) del objeto. Para obtener la posicion deberías integrar 2 veces la medicion del acelerómetro por ejemplo (verdad?) y tengo entendido que la primera integra aporta deriva y una segunda integral hace ilegible la medicion.

Esto me lo comentaron tal cuál unos estudiantes de doctorado, que están preparando unos sistemas de guía de vuelo en el grupo de investigación de robótica de la UTN de Mendoza. Me dijeron que era complejo resolver la matemática necesaria para obtener un sistema que me entregara una posición confiable utilizando una unidad de medición inercial. Ellos tenían un proyecto similar al mio, pero no encontraron los sensores adecuados y solo resolvieron que el robot móvil se moviera dentro de un ambiente cerrado a una posición X,Y determinada por el usuario...no pudieron utilizar el GPS + IMU para orientarse..

Citar
El proyecto es muy, pero muy interesante! todo lo que quieras y puedas compartir será bienvenido ya que será de utilidad para el resto de los proyectos que pueden aparecer en este foro y sin duda me será de utilidad para mi controladora de vuelo.

Todavía estoy muy verder, me falta estudiar más conceptos...por ahora estoy resolviendo las librerías para los sensores y realizando pruebas básicas.

Citar
Lo que pregunta es si has probado la medicion del ángulo (respecto del norte) pero inclinando tu magnetómetro.

No, la lectura se volvía errática cuando lo inclinaba...me medía cualquier cosa...luego cuando lo coloco sobre la mesa y comienzo a girar se estabiliza por completo. En mi librería utilizo el ángulo de declinación terrestre para mejorar la lectura, según un tutorial de internet, pero nada más. Con respecto a la compensación por inclinación, en este post hay un enlace donde se explica como resolverlo con un acelerómetro ADXL345.

http://www.todopic.com.ar/foros/index.php?topic=41981.0 (http://www.todopic.com.ar/foros/index.php?topic=41981.0)


Título: Re: Giroscopos - UAV's
Publicado por: PCCM en 28 de Enero de 2014, 18:59:23
Para obtener su recorrido del sistema solo con los sensores inerciales es posible pero muy errático con el tiempo, he leido temas donde calculan el recorrido solo el acelerómetro  pero obtienen mucho error con el tiempo. es como si fuera el giroscopo solo intentando calcular angulos.

En las pruebas que hice solo de laboratorio, para recorridos moviendo en diagonal (50cm veritcal y 50cm horizontal) tuve recorrido del acelerometro de 45cm vertical y 40 horizontal., pero esas pruebas duraron solo unos segundos. ya me imagino para mas tiempo el error incrementará.