buenas,
Puedes utilizar la misma filosofia del headtrack para FPV, se lee un sensor (o valor) y se emite en ppm a traves del cable trainer de la emisora, es algo bastante sencillo de hacer y con una buena temporizacion puedes alcanzar esa precision en canales que por lo general no se usan (revisate los post relaccionados en
http://www.aeromodelismovirtual.com), como puede ser el 7 u el 8, con esto no dependes de los valores de la emisora, sino de la temporizacion y modulacion de un circuito conectado a la emisora a traves, como te he dicho, el conector de trainer.
Espero os sirva de ayuda, os dejo algo de codigo que hice en su dia (con el giroscopo creo que no funcionaba correctamente porque necesitaba mas velocidad para calcular con mas precision el angulo de giro, al utilizar la integral rectangular o trapezoidal de la señal discreta... creo recordar...)para simular un headtrack sin brujula, pero con giroscopo para calcular el giro de la cabeza, la funcion esencial es la del timer 2 que es la que genera el tren de pulsos PPM en los canales 6 y 7 de la emisora.
// PIC16F876A
#include "Y:\headtrack\headtrack.h"
#include "y:\headtrack\lib_int_eeprom.c"
#include "float.h"
#include <stdlib.h>
// Definicion de posiciones de memoria para los valores de calibracion
// Canales ADC
#define canal_giro 0
#define canal_incl 1
// Pendientes
#define D_ANGULO1 0X00
#define D_ANGULO2 0X02
#define D_INCLINACION1 0X04
#define D_INCLINACION2 0X06
// Ceros
#define D_CANGULO 0X08
#define D_CINCLINACION 0X0A
// Factor de multiplicacion-division
#define factor 1000000
// recorrido servo en us
#define lim_sup_servo 2500
#define lim_inf_servo 300
// Frecuencia de oscilacion del led T_led*20ms
#define T_led 50
// Numero de cuentas con las que se realizara el filtrado software
#define max_filtrado 1
// Periodo de muestreo (en segundos)
#define muestreo 0.02
//define sensisibilidad del gyro (en milivoltios) mV/º/s
#define sensibilidad 0.67
// definde el angulo maximo de variacion
#define max_angulo 180
//Define el numero maximo de cuentas del ADC
#define adc 1024
//variables para calculo angulo de movimiento
int16 gyro[2]; // Lecturas del ADC
signed int16 c_angulo=0,c_inclinacion=0,aux;
float p_inclinacion,aux2;
int16 inclinacion1,inclinacion2,angulo,inclinacion;
int i=0;
int led=0;
int16 aux3;
int16 aux4;
//Valores de calibracion por defecto
#rom 0x2100 = {0xA7,0x02,0x89,0x01,0xB0,0x02,0x7F,0x010,0x18,0x00,0x17,0x00,0xFF,0xFF,0xFF,0xFF}
#rom 0x21E8 = {'H','e','a','d','T','r','a','c','k',' ','b','y',' ','X','e','R','e','X',' ','V','2','.','0'}
int calcula_angulo (void) //devuelve la variacion de angulo del giroscopo
{
float rectangulo,triangulo,area,MSB;
int angle;
MSB= 5/adc; //5000 milivoltios entre cuentas de ADC valor del escalon
// Calculando area inferior rectangulo
rectangulo = (gyro[0]*muestreo)*MSB; //area del rectangulo
//Calculando area superior triangulo
triangulo = (((gyro[0]-gyro[1])/muestreo)/2)*MSB; //area del triangulo
//calculando area total
area = rectangulo + triangulo;
//calculando angulo de variacion mV/s / mV/º/s
angle = area/sensibilidad;
return (angle);
}
/**************************************************************************/
void cero (void)
{
//giroscopo
c_angulo = (max_angulo * (((lim_sup_servo-lim_inf_servo)/2) - angulo))/(lim_sup_servo-lim_inf_servo);
// Inclinacion
set_adc_channel(canal_incl); // recogemos valor inclinacion
delay_ms(10);
c_inclinacion = read_adc(ADC_START_AND_READ)-512;
write_int16_eeprom(D_CANGULO, c_angulo);
write_int16_eeprom(D_CINCLINACION, c_inclinacion);
//señal de que hemos hecho 0
output_bit(pin_a2,1);
delay_ms(100);
output_bit(pin_a2,0);
}
/**************************************************************************/
void channell(void)
{
output_bit(Pin_A5,0);
delay_us(400);
output_bit(Pin_A5,1);
delay_us(900);
output_bit(Pin_A5,0);
}
/**************************************************************************/
void parpadea (int i)
{
output_bit(pin_a2,1);
delay_ms(i);
output_bit(pin_a2,0);
delay_ms(i);
output_bit(pin_a2,1);
}
/**************************************************************************/
void calibracion(void)
{
disable_interrupts (GLOBAL);
//Calibracion punto 1 de inclinacion
parpadea(500);
while(input(Pin_a3));
output_bit(pin_a2,0);
set_adc_channel(canal_incl);
delay_ms(10);
inclinacion1 = read_adc(ADC_START_AND_READ);
delay_ms(1000);
//Calibracion punto 2 de inclinacion
parpadea(500);
while(input(Pin_a3));
output_bit(pin_a2,0);
set_adc_channel(canal_incl);
delay_ms(10);
inclinacion2 = read_adc(ADC_START_AND_READ);
delay_ms(1000);
//Preparacion para guardar la pendiente de inclinacion
if (inclinacion1 < inclinacion2)
{
aux = inclinacion1;
inclinacion1 =inclinacion2;
inclinacion2 = aux;
}
write_int16_eeprom(D_INCLINACION1, inclinacion1);
write_int16_eeprom(D_INCLINACION2, inclinacion2);
while(1) //proceso de calibracion terminado hay que apagar.
{
parpadea(200);
}
}
/**************************************************************************/
void restaura_cal(void)
{
//restaurando giroscopo
c_angulo = read_int16_eeprom(D_CANGULO);
//restaurando inclinacion
inclinAcion1 = read_int16_eeprom(D_INCLINACION1);
inclinacion2 = read_int16_eeprom(D_INCLINACION2);
p_inclinacion = ((((lim_sup_servo - lim_inf_servo) * factor)/(inclinacion1-inclinacion2)));
c_inclinacion = read_int16_eeprom(D_CINCLINACION) ;
}
/**************************************************************************/
#int_RDA //comunicaciones con exterior
RDA_isr()
{
}
/**************************************************************************/
#int_TIMER2 //Pulsos de salida
void TIMER2_isr(void)
{
int x;
// recogiendo valor del giroscopo
gyro[0]=gyro[1];
set_adc_channel(canal_giro); // recogemos valor inclinacion
delay_us(500);
gyro[1] = read_adc(ADC_START_AND_READ);
//secuencia de temporizacion para Slave emisora PPM
for (x=0;x<5;x++)
channell();
//Canal 6: EJE X DEL INCLINOMETRO
delay_us(400);
output_bit(Pin_A5,1);
delay_us(angulo);
output_bit(Pin_A5,0);
//Canal 7: EJE Y DEL INCLINOMETRO
delay_us(400);
output_bit(Pin_A5,1);
delay_us(inclinacion);
output_bit(Pin_A5,0);
//Pulso de sincronizacion
delay_us(350);
output_bit(Pin_A5,1);
if (i>T_led)
{
i=0;
led= !led;
output_bit(pin_a2,led);
}
else
i++;
}
/**************************************************************************/
void main()
{
int cal;
int16 filtro_angulo[max_filtrado];
int16 filtro_inclinacion[max_filtrado];
int32 valor_filtrado;
setup_adc_ports(AN0_AN1_AN3);
setup_adc(ADC_OFF);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DIV_BY_16,249,10);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
enable_interrupts(INT_RDA);
enable_interrupts(INT_TIMER2);
enable_interrupts(GLOBAL);
if (!input(Pin_A3)) //hemos pulsado en arranque calibracion?
{
while (!input(Pin_A3)); // esperamos a soltar el boton
calibracion();
}
enable_interrupts(GLOBAL);
restaura_cal();
for (cal=0;cal<max_filtrado;cal++)
{
filtro_angulo[cal]=0;
filtro_inclinacion[cal]=0;
}
// TODO: USER CODE!!
while (1)
{
delay_ms(10);
if (!input(pin_a3))/// si pulsamos boton entramos en cero
{
cal=0;
while(!cal) // esperamos a dejar de pulsar el boton
{
delay_ms(100);
cal = input(pin_A3);
}
cero(); //hacemos cero
}
// Giroscopo
aux = angulo + (((lim_sup_servo-lim_inf_servo)/(max_angulo/2))* (calcula_angulo() + c_angulo));
for (cal=0;cal<max_filtrado;cal++)
{
filtro_angulo[cal]=filtro_angulo[cal+1];
valor_filtrado = filtro_angulo[cal] + valor_filtrado;
}
filtro_angulo[max_filtrado-1]=aux;
valor_filtrado= (valor_filtrado + filtro_inclinacion[max_filtrado-1])/ max_filtrado;
if (valor_filtrado > lim_sup_servo)
angulo = lim_sup_servo;
else if (valor_filtrado < lim_inf_servo)
angulo = lim_inf_servo ;
else
angulo = valor_filtrado;
// inclinacion
set_adc_channel(canal_incl);
delay_us(100);
aux4 = read_adc() - (c_inclinacion + inclinacion2);
aux2= (aux4 * p_inclinacion);
aux3= aux2/factor;
aux = lim_inf_servo+aux3;
for (cal=0;cal<max_filtrado;cal++)
{
filtro_inclinacion[cal]=filtro_inclinacion[cal+1];
valor_filtrado = filtro_inclinacion[cal] + valor_filtrado;
}
filtro_inclinacion[max_filtrado-1]=aux;
valor_filtrado= (valor_filtrado + filtro_inclinacion[max_filtrado-1])/ max_filtrado;
if (valor_filtrado > lim_sup_servo)
inclinacion = lim_sup_servo;
else if (valor_filtrado < lim_inf_servo)
inclinacion = lim_inf_servo ;
else
inclinacion = valor_filtrado;
}
}
Saludos.