Autor Tema: Leyendo señales del receptor de RC  (Leído 20826 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado elgarbe

  • Moderador Local
  • PIC24H
  • *****
  • Mensajes: 2178
Leyendo señales del receptor de RC
« en: 23 de Enero de 2014, 20:33:18 »
Bueno, mientras voy definiendo algunas cosas más sobre los sensores y voy estudiando los siguientes pasos voy a tomarme un descanso para avanzar sobre otro punto importante del UAV: La lectura de las señales del receptor de radio control.
Cuando uno piensa en un UAV en el 90% de los casos piensa en un modelo (quad, avion, "rover" o auto, etc.) que se comanda con un típico radio control. El radiocontrol nos permite la comunicacion en un sentido con el UAV para comandarlo. Uno piensa en un radio control porque ya está todo desarrollado, tenemos radios de 4 canales, de 6, 7 12 y hasta 14 canales, programables, con fail safe y un sin numero de funciones a un precio bastante aseccible. Aunque la idea de desarrollar un enlace en RF bidireccional que convine comando, telemetría, video, sonido, etc. no es mala... solo que llevaría mucho tiempo y podríamos dejarlo para una segunda etapa.
Bien, definiendo entonces el camino del radio control, en el UAV tendremos un receptor. En mi caso estoy usando una vieja radio futaba de 4 canales, transmite en 72Mhz y tiene un alcance que aún no he probado pero me han dicho que ronda los 800mts.
El receptor recibe una trama PPM que representa el tiempo entre un pulso y otro de cada canal. Para entender bien esta parte recomiendo estos enlaces:
http://blog.deinventos.com/modificacion-de-un-receptor-de-35mhz-y-decodificacion-de-la-senal-ppm-sum/
http://www.pabr.org/pxarc/1.1/doc/pxarc.en.html Figura 6
http://nicisdigital.wordpress.com/2011/05/21/rc-receiver-interface/
http://picmania.garcia-cuervo.net/proyectos_rcrx_pic.php
http://www.e-radiocontrol.com.ar

como resumen de esos tres links surge que tenemos 3 alternativas:
  • Conectar cada salida del receptor a una entrada del uC y leer la señal del canal directamente
  • Abrir nuestro receptor y buscar la señal PPM para entrar en una sola entrada del uC
  • Hacer una OR con las señales de cada canal del receptor y entrar por una sola entrada del uC

Por lo que he visto en los proyectos generalmente eligen conectar cada salida de cada canal del receptor a una entrada del uC y leer los canales de forma independiente. Como opcional, si el RX posee una salida PCM o PPM, ofrecen una entrada para conectar dicha señal y ahorrar cablerío.

En principio yo no he decidido cuál adoptaré, como primer medida veamos un poco las señales en mi receptor:


El integrado más grande es un BU4015, el cual se encarga de decodificar la trama PPM. Por lo tanto en uno de sus pines deberíamos tener la trama PPM....

Bien, primero veamos y analicemos un poco las señales de cada canal del receptor:



Aquí vemos la señal de cada uno de los primeros 5 canales del receptor. El canal 3 que corresponde al motor vemos que tiene un pulso más chico, mientras que los demas canales tienen el mismo ancho de pulso. Esto es porque tengo el stick del acelerador del radio control en 0.
Como primer medida vemos que el período de la señal de cada canal es de 17.98mseg, en teoría deberían ser 20mseg.
Luego podemos ver que estoy apuntando a la onda del canal 3 y abajo puedo leer Width 1.045mseg. El resto de los canales está en 1.5mses aproximadamente, con todos los stick en el centro, pero el trim esta levemente corrido. En teoría el ancho del pulso debería variar entre 1 y 2mseg, siendo el punto medio o la posicion central del stick 1.5mseg.



Bien en esta otra foto he encontrado la señal PPM. Como pueden ver tenemos un ciclo completo "metido" en el tiempo en que el canal está activado. Al final de la trama tenemos un pulso adicional con un tiempo muerto de unos 10mseg hasta retomar el ciclo nuevamente.



Aquí podemos ver las mediciones de ancho de pulso del canal 3.



Finalmente el ancho del pulso del canal 4.

Creo que para hacer el proyecto lo más universal posible, lo ideal es cablear cada salida del receptor a una entrada del uC y leer cada pulso de cada canal por separado. En mi uC tengo decenas de pines GPIO para utilizar y la mayoría tiene interrupt on change... utilizaré P0.19 a P0.22 ya que son cuatro I/O que tengo en un conector de mi placa base para la LPCXpresso.

Una cosa importante es el tema de la standarizacion. Tengo entendido que no todos los receptores/transmisores son iguales, que hay pequeñas diferencias en los tiempos correspondientes al 0% y 100% del mando del transmisor, así como la frecuncia y el duty cicle. Por lo tanto sería bueno hacer una rutina de calibracion obteniendo dichos resultados.

Bueno, por ahora eso es todo, queda planteado el problema. Para la próxima veremos alguna implementacion.

Saludos!
« Última modificación: 24 de Enero de 2014, 17:19:02 por elgarbe »
-
Leonardo Garberoglio

Desconectado rivale

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1707
Re: Leyendo señales del receptor de RC
« Respuesta #1 en: 24 de Enero de 2014, 13:00:20 »
Hola elgarbe, muy buena tu explicación ((:-)), nunca he usado radio controles de ese tipo

por curiosidad, porque deicidiste usar RC para tu UAV, y no algun control por RF o bluetooth?
"Nada es imposible, no si puedes imaginarlo"

Desconectado AngelGris

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2480
Re: Leyendo señales del receptor de RC
« Respuesta #2 en: 24 de Enero de 2014, 13:55:28 »
  También puedes hallar muy buena información acerca de radio control en www.e-radiocontrol.com.ar
De vez en cuando la vida
nos besa en la boca
y a colores se despliega
como un atlas

Desconectado elgarbe

  • Moderador Local
  • PIC24H
  • *****
  • Mensajes: 2178
Re: Leyendo señales del receptor de RC
« Respuesta #3 en: 24 de Enero de 2014, 17:18:39 »
  También puedes hallar muy buena información acerca de radio control en www.e-radiocontrol.com.ar

Angel, si si, esa es una muy pero muy buena página y he sacado mucha info de ahí, hay diseño de circuitos muy completos, estudio de los RC etapa por etapa, etc. Ya agrego la referencia al principio.

Gracias!
-
Leonardo Garberoglio

Desconectado elgarbe

  • Moderador Local
  • PIC24H
  • *****
  • Mensajes: 2178
Re: Leyendo señales del receptor de RC
« Respuesta #4 en: 24 de Enero de 2014, 17:32:19 »
Hola elgarbe, muy buena tu explicación ((:-)), nunca he usado radio controles de ese tipo

por curiosidad, porque deicidiste usar RC para tu UAV, y no algun control por RF o bluetooth?

Hola, bluetooth es la opción más simple debido a los modulos BT-232. El tema es que el alcance es muy limitado. No más de 100mts, verdad?
En cuanto a RF están los módulos de APPCON que Norberto testeo en su momento y los tengo en mi lista de ToDo. No lo descarto para nada, el tema es que en este momento creo que me llevaría demasiado tiempo, crear un protocolo de comunicación, comprar y testear equipos... por ahora prefiero avanzar con un sistema que ya está funcionando, el RC que tengo en uso para aeromodelismo...

El tema del enlace con el UAV es digno de estudio. Normalmente hay 2 enlaces con el avion y hay una mezcla de señales. Se utilizan RC con sistemas LRS (Long range systems en 433MHz) para el comando del avion, cámara de a bordo, etc. Luego un enlace de audio y video para poder volar en primera persona. En el mismo enlace de video se monta una señal proveniente del OSD (On Screen Display) el cual superpone en la imagen de video la telemetría. Con canales adicionales del RC se suele manejar distintos menús del OSD. El tema es que si por algún problema perdes la cámara, la cual genera la señal de sincronismo de video, perdés la telemetría.
Lo ideal sería tener el enlace de video (en 1.2GHz) solo para video y un enlace adicional para el comando del UAV y la telemetría. Este enlace debería ser bidireccional y podrían ser módulos de RF. Las posibilidades son infinitas y se puede elegir la que uno mas le guste, cada una tiene pros y contras. El problema del enlace RF es que es menos universal para los que usan un UAV como hobby ya que todos usan RC para sus aviones/quadcopter/helicoptero....
También he visto que se puede hacer una especie de radio modem con el canal de sonido del transmisor de video para enviar la telemetría a tierra.

Saludos!
« Última modificación: 24 de Enero de 2014, 17:37:05 por elgarbe »
-
Leonardo Garberoglio

Desconectado rivale

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1707
Re: Leyendo señales del receptor de RC
« Respuesta #5 en: 24 de Enero de 2014, 17:50:23 »

Hola, bluetooth es la opción más simple debido a los modulos BT-232. El tema es que el alcance es muy limitado. No más de 100mts, verdad?


Tienes toda la razón, el bluetooth no tiene un alcance que sea de utilidad para esto, aunque sería entretenido mover el UAV desde el celular :mrgreen:



El tema del enlace con el UAV es digno de estudio. Normalmente hay 2 enlaces con el avion y hay una mezcla de señales. Se utilizan RC con sistemas LRS (Long range systems en 433MHz) para el comando del avion, cámara de a bordo, etc. Luego un enlace de audio y video para poder volar en primera persona. En el mismo enlace de video se monta una señal proveniente del OSD (On Screen Display) el cual superpone en la imagen de video la telemetría. Con canales adicionales del RC se suele manejar distintos menús del OSD. El tema es que si por algún problema perdes la cámara, la cual genera la señal de sincronismo de video, perdés la telemetría.
Lo ideal sería tener el enlace de video (en 1.2GHz) solo para video y un enlace adicional para el comando del UAV y la telemetría. Este enlace debería ser bidireccional y podrían ser módulos de RF. Las posibilidades son infinitas y se puede elegir la que uno mas le guste, cada una tiene pros y contras. El problema del enlace RF es que es menos universal para los que usan un UAV como hobby ya que todos usan RC para sus aviones/quadcopter/helicoptero....
También he visto que se puede hacer una especie de radio modem con el canal de sonido del transmisor de video para enviar la telemetría a tierra.

Saludos!

Solo era una duda, quería saber si tenias como requerimiento el uso de RC para el control del UAV. Como mencionas lo ideal es tener una comunicación bidireccional con el UAV, para poder montarle instrumentos o sensores y así poder tener acceso a ellos, creo que para esto sería mejor RF.


Sigo de cerca el post para aprender sobre RC ((:-))
"Nada es imposible, no si puedes imaginarlo"

Desconectado PCCM

  • PIC16
  • ***
  • Mensajes: 109
Re: Leyendo señales del receptor de RC
« Respuesta #6 en: 27 de Enero de 2014, 02:14:34 »
Tengo dudas del porque la necesidad de leer las señales del receptor. Si lo puedes conmutar con un multiplexor.
Osea bien los motores hacen caso a la señal del receptor(caso control manual) o bien al microcontrolador(caso control automático).

Por ejemplo el que utilizan en el ardupilot:

https://www.fairchildsemi.com/ds/74/74ACT157.pdf

Saludos.

Desconectado elgarbe

  • Moderador Local
  • PIC24H
  • *****
  • Mensajes: 2178
Re: Leyendo señales del receptor de RC
« Respuesta #7 en: 27 de Enero de 2014, 07:16:41 »
Tengo dudas del porque la necesidad de leer las señales del receptor. Si lo puedes conmutar con un multiplexor.
Osea bien los motores hacen caso a la señal del receptor(caso control manual) o bien al microcontrolador(caso control automático).

Por ejemplo el que utilizan en el ardupilot:

https://www.fairchildsemi.com/ds/74/74ACT157.pdf

Saludos.

En el caso de un avion, el cual puedes volar con el RC de forma tradicional puedes usar los multiplexores. Pero está el caso de los quadcopteros y hexacópteros, los cuales no puedes volar sin asistencia. Por eso la controladora debe poder leer los datos del Rx y transformalas en ordenes para los motores.
Tambien suele utilizarce en aviones para tener un vuelo manual "asisitido". Por ejemplo, limitando los ángulos de vuelo, velocidades, etc. para evitar entrar en perdida a baja altura u otros posibles incidentes.

Saludos!
-
Leonardo Garberoglio

Desconectado elgarbe

  • Moderador Local
  • PIC24H
  • *****
  • Mensajes: 2178
Re: Leyendo señales del receptor de RC
« Respuesta #8 en: 29 de Enero de 2014, 19:18:19 »
Bueno, hoy tengo ganas de avanzar un poco por este lado, así que veamos un poco la lectura de la señal del receptor.
El  otro día estaba pensando y finalmente me decidí por tomar la señal PPM dentro del receptor de RC y luego decodificarla usando una sola entrada Input Capture.

Entonces me decidí a soldar los cables en el interior del receptor:



como ven he soldado un cable en línea negativo (verde), otro en el naranja (positivo) y otro en el pin 1 (clock) del registro de desplazamiento. Es ese registro el que se encarga de decodificar la señal PPM en cada canal PWM (cable amarillo). Entonces desde mi placa de desarrollo para la LPC1769 alimento el módulo y la señal PPM ingresará al pin P0.4 (CAP2.0).
Los ARM cortex M3 tienen 4 timer de 32 bits, cada uno con dos input capture. Acá podría usar una entrada común y su interrupcion on change, pero eso requerirá un poco más de software, en cambio si usamos el input capture, todo lo relacionado a almacenar el valor del timer en el registro CAPTURE, generar interrupcion, etc, lo hace el hardware dedicado.
Bueno, para saber como configurar el timer debemos saber con que señales esperamos encontrarnos. Dijimos que la señal PPM codifica el tiempo en ON del PWM de cada canal uno destras del otro. Esperamos encontrar entonces (como vimos en el post anterior) un tren de pulso VARIABLES, y el período de cada pulso (tiempo ON + Tiempo OFF) es el tiempo ON del PWM de cada canal. El tiempo Off del PWM de cada canal es 20mseg (la frecuencia de trabajo del PWM es 50Hz) menos el tiempo ON. Veamos entonces entre que valores varía el tiempo ON de cada canal:



Aquí vemos que con el TRIM en 0 y el Stick del TX en 0 el tiempo ON del PWM (en este caso el canal 3) es de prácticamente 1ms.



Aquí vemos que con el TRIM en al máximo y el Stick del TX en el máximo el tiempo ON del PWM (en este caso el canal 3) es de prácticamente 2ms.

Bien, el timer 2 que quiero usar con la Input Captura 2, canal 0 es de 32 bits. Si el micro corre a 100MHz (puedo llegar a 120, pero voy a 100  :mrgreen:) y configuro como entrada del timer la señal CoreClock tendremo un Tick cada 10nseg. con 32 bits puedo contar hasta 4.294.967.296 o lo que es lo mismo, 42.9 segundos, con una presicion de 10nseg!!!!! Bue, no pongo prescaler ni nada y contaremos decenas de nsegundos. La idea es que cada flanco de subida de la señal PPM me dispare una Input Capture, voy almacenando el Tiempo actual y el previo, de modo tal de poder medir cuantas decenas de ns pasa entre cada Rising edge de la señal PPM.
Como hago para sincronizar el comienzo del canal 1? buscando el pulso final, el cual es mucho más largo. Cuando lo encuentro, inicializo un contador y a aprtir de alli, voy llevando la cuenta de los pulsos de cada canal.
Lo bueno de esto es que trabaja de fondo, con interrupcion, por lo que lo dejo midiendo los pulsos del Rx y cuando deseo saber el contenido actual, de forma asíncrona llamo a una funcion que me devuelve el array con los 4 valores de los 4 canales.
Este driver está tomado de una de las páginas que puse en el primer post y fue modificada para mi necesida.

Bien, mi Rx.h es el siguiente:

Código: [Seleccionar]
#ifndef RX_H_
#define RX_H_

#include "LPC17xx.h"

#define RX_CHANNELS 4


/* defines */
#define RX_SUCCESS     (0x00)
#define RX_NO_PACKET   (0x01)

/* typedefs */

/* functions */
void rx_init(uint8_t irq_priority);
uint8_t rx_get_packet(uint32_t packet[RX_CHANNELS]);

#endif /* RX_H_ */

Aquí, como punto importante es definir el número de canales de nuestro Rx.

Luego mi Rx.c es el siguiente:

Código: [Seleccionar]
/*
 * RX.c
 *
 *  Created on: 28/01/2014
 *      Author: elgarbe
 */


/*****************************************************************************
                                Copyright 2011
                             All Rights Reserved

 Information:
   File Name  :  rx.c
   Author(s)  :  Nic McDonald
   Project    :  Quadrotor
   Hardware   :  LPCXpresso LPC1768
   Purpose    :  RC Receiver Interface

******************************************************************************
 Modification History:
   Revision   Date         Author    Description of Revision
   1.00       05/19/2011   NGM       initial

******************************************************************************
 Theory of Operation:
   This modules implements an RC receiver interface.  It expects the input
   signal to have all channels combined into one signal and each pulse must be
   separated.
   Ex:
      ____
   __|    |___________________________ channel 1
             __
   _________|  |______________________ channel 2
                  ___
   ______________|   |________________ channel 3
      ____   __   ___
   __|    |_|  |_|   |________________ all channels


   This implementation utilizes TIMER2 to measure PWM signals.

******************************************************************************
Esta explicación es para el caso de hacer una OR con cada salida del Rx. En mi caso
extraigo la señal PPM del Rx y por lo tanto tengo que leer solamente flancos de subida,
ya que cada pulso termina donde comienza el siguiente, no hay un tiempo muerto entre
pulso y pulso

*****************************************************************************/

#include "rx.h"

/****************************************************************************/
/*                              Local Defines                               */
/****************************************************************************/
#define TICKS_PER_US (100) //A 100MHz el Tick es de 10ns x 100 = 1useg
#define TICKS_PER_MS (TICKS_PER_US*1000)


/****************************************************************************/
/*                             Private Variables                            */
/****************************************************************************/
static uint32_t pulses[RX_CHANNELS]; //Matriz para guardarel tiempo de cada pulso de cada canal
static uint8_t packet_available; //Bandera para indicar que ya recibimos RX_CHANNELS pulsos


/****************************************************************************/
/*                      Private Function Declarations                       */
/****************************************************************************/
static inline void cap2_0_interrupts_on(void);
static inline void cap2_0_interrupts_off(void);


/****************************************************************************/
/*                             Public Functions                             */
/****************************************************************************/
// This functions initializes TIMER2 as the receiver interface.
//   Assumes system clock is 100 MHz.
void rx_init(uint8_t irq_priority) {
    uint32_t ch;

    // clear the pulses array
    for (ch=0; ch<RX_CHANNELS; ch++)
        pulses[ch] = 0;

    // start with no packets available
    packet_available = 0;

    // give power to TIMER2
    LPC_SC->PCONP |= (1 << 22);

    // set peripheral clock selection for timer 2
    LPC_SC->PCLKSEL1 &= ~(3 << 12); //Borramos bits
    LPC_SC->PCLKSEL1 |=  (1 << 12); // set to "01" = Core Clock (100 MHz)

    // set the pin functions to CAP2.0 for P0.4
    LPC_PINCON->PINSEL0 &= ~(3 << 8); //Borramos bits. Seteamos a 11 en los bits 8 y 9
    LPC_PINCON->PINSEL0 |=  (3 << 8); //para elejir CAP2.0 como funcion del puerto P0.4

    // set the clock source for TIMER2 to PCLK
    LPC_TIM2->CTCR = 0; // this is the default

    // set the prescaler
    LPC_TIM2->PR = 0; // TC increments on every PCLK

    // enable and reset the the counters
    LPC_TIM2->TCR = 0x00000003;
    LPC_TIM2->TCR = 0x00000001;

    // set captures to occur on rising edges
    LPC_TIM2->CCR = 0x00000001; //Capture only on Rising edge. Sin interrupciones

    // Habilito la interrupcion en la Input Capture
    cap2_0_interrupts_on();

    // Registramos la interrupcion del Timer2
    NVIC_EnableIRQ(TIMER2_IRQn);

    // Fijamos la prioridad de la interrupcion
    NVIC_SetPriority(TIMER2_IRQn, irq_priority); // '0' es la mayor
}

//  If a packet has arrived since the last call, 'packet' is filled with
//  the contents of the packet and RX_SUCCESS is returned.  If no packet
//  is available, RX_NO_PACKET is returned.
//  The size of 'packet' must be at least RX_CHANNELS.
//  This is NOT thread safe.
uint8_t rx_get_packet(uint32_t packet[RX_CHANNELS]) {
    uint32_t avail, ch;

    // turn off timer2 capture interrupts while accessing packet_available
    cap2_0_interrupts_off();
    avail = packet_available; // grab current value
    packet_available = 0; // set to zero
    cap2_0_interrupts_on(); // Vuelvo a encender la Interrupcion

    // check if a packet is available
    if (avail) {
        // copy packet
        for (ch=0; ch<RX_CHANNELS; ch++)
            packet[ch] = pulses[ch];

        // set as success
        return RX_SUCCESS;
    }
    else {
        // set as failure
        return RX_NO_PACKET;
    }
}


/****************************************************************************/
/*                             Private Functions                            */
/****************************************************************************/
static inline void cap2_0_interrupts_on(void) {
    LPC_TIM2->CCR |= 0x00000004;
}

static inline void cap2_0_interrupts_off(void) {
    LPC_TIM2->CCR &= ~0x00000004;
}


/****************************************************************************/
/*                           Interrupt Functions                            */
/****************************************************************************/
void TIMER2_IRQHandler(void) {
    // persistent local variables
    static uint32_t tmp_pulses[RX_CHANNELS];
    static uint32_t prev_ticks = 0;
    static uint32_t current_pulse = 0;

    // local variables
    uint32_t curr_ticks, nanos;
//    uint32_t rising_edge;
    uint32_t c;

//    // check that this interrupt is from CAP2.0
    if((LPC_TIM2->IR & 0x0000003F) == 0x00000010){

    // compute delta time (each tick is 10ns)
    curr_ticks  = LPC_TIM2->CR0;
    nanos = (curr_ticks - prev_ticks) * 10;

    //Si el tiempo del pulso supera los 3mseg es que estamos en el pulso de sincronismo
if (nanos > 3000000){
current_pulse = 0;
    }
    else {
        // store this sample
        tmp_pulses[current_pulse] = nanos;

        // advance to next pulse
        current_pulse++;

        // check for end of packet
        if (current_pulse == RX_CHANNELS) {
            // wrap pointer
            current_pulse = 0;

            // copy out packet
            for (c=0; c<RX_CHANNELS; c++)
                pulses[c] = tmp_pulses[c];

            // signal available packet
            packet_available = 1;
        }
    }

    // clear the interrupt
    LPC_TIM2->IR |= 0x00000010;

    // save current as previous for next event
    prev_ticks = curr_ticks;
    }
}

He dejado parte de la explicación del código original para referencia.

Mi main.c es este:

Código: [Seleccionar]


/*
===============================================================================
 Name        : main.c
 Author      : elgarbe
 Description : Esta práctica es para mostrar un conteo binario con led externos (P2.0..7)
 a una frecuencia establecida por el timer. Hace uso de la librería CMSIS
===============================================================================
*/

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

#include <cr_section_macros.h>
#include <NXP/crp.h>
#include "RX.h"
#include "uart2.h"

__CRP const unsigned int CRP_WORD = CRP_NO_CRP ;

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

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

int main(void) {
uint32_t rx_values[RX_CHANNELS];
uint8_t hay_datos = 0;
uint8_t canal=0;

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

rx_init(0); //Inicializo el Timer2 para que lea la señal PPM
UART2_Init(115200); // Inicializamos el UART a 115200

UART2_PrintString ("\r\nLeyendo Rx\r\n");
UART2_PrintString ("===== elgarbe =====\r\n");

while(1) {
hay_datos = rx_get_packet(rx_values); //Verifico si hay datos nuevo provenientes del Tx
if(hay_datos == RX_SUCCESS){ //esto es asincrónico, verifico cuando quiero saber
       for (canal=0; canal<RX_CHANNELS; canal++){ //Pero la int por input capture
uart2_printUint32(rx_values[canal], 10); //esta constantemente leyendo los datos
UART2_Sendchar(','); //de la señal PPM del Rx
       }
UART2_PrintString("\r\n");
}
delay_ms(250);
}
return 0 ;
}

Bien, veamos una captura del hyperterminal cuando muevo el stick del canal 1:



Como ven el canal 1 varía desde 1.5mseg en reposo hasta 1.93 con el stick en un extremo y 1.03 con el stick en otro extremo.

Bueno, por ahora un tema menos, ya podemos recibir comandos con el RC!!!

Saludos!
-
Leonardo Garberoglio

Desconectado AngelGris

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2480
Re: Leyendo señales del receptor de RC
« Respuesta #9 en: 29 de Enero de 2014, 20:20:38 »
  En su momento había hecho con un 16f628 un decodificador de señal PPM (es el que figura en el sitio e-radiocontrol) y funcionaba muy bien. La prueba la realicé tomando la salida de trainer de transmisor RC. Si tu equipo posee dicha salida puedes aprovecharla para no estar trabajando sobre la plaque del recetor.
De vez en cuando la vida
nos besa en la boca
y a colores se despliega
como un atlas

Desconectado elgarbe

  • Moderador Local
  • PIC24H
  • *****
  • Mensajes: 2178
Re: Leyendo señales del receptor de RC
« Respuesta #10 en: 29 de Enero de 2014, 21:15:09 »
  En su momento había hecho con un 16f628 un decodificador de señal PPM (es el que figura en el sitio e-radiocontrol) y funcionaba muy bien. La prueba la realicé tomando la salida de trainer de transmisor RC. Si tu equipo posee dicha salida puedes aprovecharla para no estar trabajando sobre la plaque del recetor.

Es buena idea! lo voy a tener en cuenta para las próximas pruebas.

Saludos y gracias!
-
Leonardo Garberoglio

Desconectado pajaro

  • PIC24H
  • ******
  • Mensajes: 1121
Re: Leyendo señales del receptor de RC
« Respuesta #11 en: 05 de Marzo de 2014, 19:33:28 »
Hola compañeros

yo tengo la idea de hacer lo del ppm como dice AngelGris con un uC
tanto en la codificacion como en la descodificacion pero en base
de un 18F2550 si este finde le saco tiempo lo intentare simular.

un saludo.

Desconectado elgarbe

  • Moderador Local
  • PIC24H
  • *****
  • Mensajes: 2178
Re: Leyendo señales del receptor de RC
« Respuesta #12 en: 10 de Marzo de 2014, 21:21:54 »
Hola, lo ideal sería hacerlo con el micro más chico posible en la parte del decodificador, la que va en el avion. Incluso estaría bueno programar un Fail Safe. Si se detecta que las señales que llegan por el receptor son erroneas (debido a perdida de señal) activar una salida de fail safe. Los sistemas de estabilizacion usan dicha señal para tomar control del avion, estabilizarlo y tratar de volverlo al punto de salida...

Saludos!
-
Leonardo Garberoglio

Desconectado AngelGris

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2480
Re: Leyendo señales del receptor de RC
« Respuesta #13 en: 10 de Marzo de 2014, 23:17:44 »
  Cuando recién comencé a programar en C los PIC lo hacía con CCS y había hecho un programa para receptor de RC con un 16F628A. Que tenía una especie de FailSafe.
Básicamente el funcionamiento era el siguiente... si se encendía el receptor con RA3 en 0 se leían las posiciones de los Stick y se grababan en la EEPROM del PIC.
Si se cortaba la señal de entrada por un tiempo predeterminado, se leía la memoria y las salidas se colocaban en la posición pregrabada. Si reaparecía la señal de entrada salía del modo FailSafe.

Este es el programa... pero hace tanto que no agarro CCS que ni entiendo lo que hice  :mrgreen:

Código: C
  1. #include "16f628a.h"
  2. #use delay (clock=4000000)
  3. #use fast_io (all)
  4. #byte CMCON=0x1F
  5. #byte PORTB=0x6
  6. #byte PORTA=0x5
  7.  
  8. int8    Canales;
  9. int8    Contador;
  10. int8    ContadorFail;
  11. int8    ContadorRetorno;
  12. int8    ContadorCanales;
  13. int8    Salidas;
  14. int16   Duracion[9];
  15. int16   RetardoFinal;
  16. int1    FailSafe;
  17. int1    EstadoAnterior;
  18. int1    SalirFailSafe;
  19. int1    Programado;
  20. int1    DejarDeContar;
  21.  
  22. #int_timer2
  23. void timer2interrupt()
  24. {
  25.         if ((ContadorFail >= 20) && (!FailSafe))
  26.         {
  27.                 FailSafe = True;
  28.                 EstadoAnterior = CMCON,7;
  29.         }
  30.         else
  31.                 ContadorFail++;
  32.         output_b (0);
  33.         Salidas = 1;
  34.         Canales = 1;
  35.         set_timer2 (0);
  36.         clear_interrupt (int_timer2);
  37. }
  38.  
  39. int CuentaCanales()
  40. {
  41.         int8    Canales;
  42.         int8    CantidadTramas;
  43.         CantidadTramas = 0;
  44.         ContadorFail = 0;
  45.         Canales = 0;
  46.         while (true)
  47.         {
  48.                 while (bit_test (CMCON,7) == 0)
  49.                 {
  50.                         if (CantidadTramas ==3) break;
  51.                 }
  52.                 if (CantidadTramas ==3) break;
  53.                 if (Salidas == 1) CantidadTramas++;
  54.                 OutPut_b (Salidas);
  55.                 if (CantidadTramas == 2) Canales++;
  56.                 set_timer2 (0);
  57.                 ContadorFail = 0;
  58.                 shift_left (&Salidas,1,0);
  59.                 while (bit_test (CMCON,7) == 1)
  60.                 {
  61.                 }
  62.         }      
  63.         return (canales);
  64. }
  65.  
  66.  
  67. void LeerTiempos(int CantidadCanales)
  68. {
  69.         int8    Canales;
  70.         int8    CantidadTramas;
  71.         CantidadTramas = 0;
  72.         ContadorFail = 0;
  73.         Canales = 0;
  74.         while (true)
  75.         {
  76.                 while (bit_test (CMCON,7) == 0)
  77.                 {
  78.                         if (CantidadTramas ==3) break;
  79.                 }
  80.                 if (CantidadTramas ==3) break;
  81.                 if (Salidas == 1) CantidadTramas++;
  82.                 OutPut_b (Salidas);
  83.                 if (CantidadTramas == 2)
  84.                 {
  85.                         Duracion[Canales] = get_timer1();
  86.                         Canales++;
  87.                 }
  88.                 set_timer1 (0);
  89.                 set_timer2 (0);
  90.                 ContadorFail = 0;
  91.                 if (Canales == CantidadCanales) break;
  92.                 shift_left (&Salidas,1,0);
  93.                 while (bit_test (CMCON,7) == 1)
  94.                 {
  95.                 }
  96.         }      
  97. }
  98.  
  99. void LeerMemoria()
  100. {
  101.         int8    Contador;
  102.         int8    Nibble;
  103.         int8    Data[2];
  104.         int8    Direccion;
  105.         Direccion = 0;
  106.         for (Contador = 1; Contador < 9; Contador++)
  107.         {
  108.                 for (Nibble = 0; Nibble < 2; Nibble++)
  109.                 {
  110.                         Data[Nibble] = read_eeprom (Direccion);
  111.                         Direccion++;
  112.                 }
  113.                 Duracion[Contador] = make16 (Data[1],Data[0]);
  114.         }
  115. }
  116.  
  117. void EscribirMemoria(int CantidadCanales)
  118. {
  119.         int8    Contador;
  120.         int8    Nibble;
  121.         int8    Data;
  122.         int8    Direccion;
  123.         Direccion = 0;
  124.         for (Contador = 1; Contador < CantidadCanales; Contador++)
  125.         {
  126.                 for (Nibble = 0; Nibble < 2; Nibble++)
  127.                 {
  128.                         if (Nibble == 0) Data = make8 (Duracion[Contador],0);
  129.                         if (Nibble == 1) Data = make8 (Duracion[Contador],1);
  130.                         write_eeprom (Direccion,Data);
  131.                         Direccion++;
  132.                 }
  133.         }
  134.         for (Contador = CantidadCanales; Contador < 9; Contador++)
  135.         {
  136.                 Duracion[Contador] = 0;
  137.                 for (Nibble = 0; Nibble < 2; Nibble++)
  138.                 {
  139.                         if (Nibble == 0) Data = make8 (Duracion[Contador],0);
  140.                         if (Nibble == 1) Data = make8 (Duracion[Contador],1);
  141.                         write_eeprom (Direccion,Data);
  142.                         Direccion++;
  143.                 }
  144.         }
  145. }
  146.  
  147. void SetDefault(int CantidadCanales)
  148. {
  149.         int8    Contador;
  150.         for (Contador = 1; Contador < CantidadCanales; Contador++)
  151.         {
  152.                 Duracion[Contador] = 1500;
  153.         }
  154.         EscribirMemoria (CantidadCanales);
  155. }
  156.  
  157. void main ()
  158. {
  159.         Contador = 0;
  160.         ContadorFail = 0;
  161.         ContadorRetorno = 0;
  162.         ContadorCanales = 0;
  163.         Salidas = 1;
  164.         FailSafe = false;
  165.         Programado = false;
  166.         DejarDeContar = false;
  167.         set_tris_a (0b00011111);
  168.         set_tris_b (0);
  169.         output_b (0);
  170.         setup_timer_2 (T2_DIV_BY_16,12,16);
  171.         clear_interrupt (int_timer2);
  172.         if (bit_test (porta,0) == 0)
  173.                 setup_comparator (nc_nc_a1_a2|cp2_invert);
  174.         else
  175.                 setup_comparator (nc_nc_a1_a2);
  176.         set_timer2 (0);
  177.         setup_timer_1 (T1_INTERNAL | T1_DIV_BY_1);
  178.         set_timer1 (0);
  179.         enable_interrupts (int_timer2);
  180.         enable_interrupts (global);
  181.        
  182.         ContadorCanales = CuentaCanales();
  183.  
  184.         if (bit_test(PORTA,4) == 1) SetDefault(ContadorCanales);
  185.         if (bit_test(PORTA,4) == 0) LeerMemoria();
  186.  
  187.         while (true)
  188.         {
  189.                 while ((bit_test (PORTA,3) == 0) && (!Programado))
  190.                 {
  191.                         LeerTiempos (ContadorCanales);
  192.                         EscribirMemoria (ContadorCanales);
  193.                         Programado = true;
  194.                 }
  195.                 while (!FailSafe)
  196.                 {
  197.                         ContadorFail = 0;
  198.                         ContadorRetorno = 0;
  199.                         SalirFailSafe = False;
  200.                         while (bit_test(CMCON,7) == 0)
  201.                         {
  202.                                 if (FailSafe) break;
  203.                         }
  204.                         output_b (Salidas);
  205.                         set_timer2 (0);
  206.                         Canales++;
  207.                         if (Canales < ContadorCanales) shift_left (&Salidas,1,0);
  208.                         else
  209.                                 Salidas = 0;
  210.                         while (bit_test (CMCON,7) ==1)
  211.                         {
  212.                                 if (FailSafe) break;
  213.                         }
  214.                         if ((bit_test(PORTA,3) == 0) && (!Programado)) break;
  215.                 }
  216.                 while (FailSafe)
  217.                 {
  218.                         RetardoFinal = 0;
  219.                         for (Contador = 1; Contador < ContadorCanales; Contador++)
  220.                         {
  221.                                 OutPut_b (Salidas);
  222.                                 set_timer2 (0);
  223.                                 delay_us (Duracion[Contador]-70);
  224.                                 shift_left (&Salidas,1,0);
  225.                                 RetardoFinal = RetardoFinal + Duracion[Contador] + 100;
  226.                         }
  227.                         OutPut_b (0);
  228.                         delay_us (20000 - RetardoFinal);
  229.                         if (SalirFailSafe)
  230.                         {
  231.                                 ContadorRetorno++;
  232.                                 if (ContadorRetorno >= 125)
  233.                                 {
  234.                                         FailSafe = False;
  235.                                         break;
  236.                                 }
  237.                         }
  238.                         if (bit_test (CMCON,7) != EstadoAnterior)
  239.                         {
  240.                                 SalirFailSafe = True;
  241.                         }
  242.                 }
  243.         }
  244. }
De vez en cuando la vida
nos besa en la boca
y a colores se despliega
como un atlas

Desconectado elgarbe

  • Moderador Local
  • PIC24H
  • *****
  • Mensajes: 2178
Re: Leyendo señales del receptor de RC
« Respuesta #14 en: 10 de Marzo de 2014, 23:43:05 »
Muy bueno!!!

pregunta: la parte de RF la tenias hecha tmb?

Sds!
-
Leonardo Garberoglio