En la entrada anterior vimos cómo hacer una radio RC casera con Arduino, sin embargo, en esta entrada nos vamos a centrar en el receptor de nuestro sistema radio control casero. Es decir, vamos a hacer la parte del sistema que se encarga de recibir los datos y actuar en consecuencia. Esta va a ser una entrada muy cortita.

Generalmente los receptores RC comerciales todas las salidas son señales PWM, que mueven principalmente servos y ESC (Electronic Speed Controller). Sin embargo, al programar nosotros el receptor, podemos hacer que este tenga las salidas que a nosotros nos hagan falta. Por ejemplo, poniendo salidas digitales o lo que nosotros queramos.

Los Servos

De momento, vamos a centrarnos en cómo mover los servos que podamos conectar a nuestro receptor, ya que las salidas digitales son muy comunes y no tienen nada en especial. Para ello vamos a usar la librería Servo de Arduino, que nos aísla de todos los cálculos de tiempos de la señal PWM. Aunque, nunca está de más conocer como funcionan las cosas, aunque luego usemos librerías.

¿Cómo funciona el protocolo de los Servos?

Los servos se controlar mediante una señal PWM (Pulse Width Modulated). Es decir, una señal cuadrada periódica en la que la anchura de la parte positiva, va cambiando. Los servos necesitan una señal con periodo de 20 milisegundos, pero lo que de verdad configura la posición del servo es la anchura del pulso: 1500 us es para la posición central, 1000 us para los giros en contra de las agujas del reloj, y 2000 us a favor.

Diagrama de funcionamientos del protocolo

Protocolo de los servos

Aunque hay muchos tipos de servos, todos funcionan generalmente con el mismo protocolo, lo que cambia es la fuerza que tienen, y los voltajes y corrientes que necesitan. Además, la conexión siempre suele ser la misma:

Color Función
Rojo Alimentación (5V)
Marrón Tierra (GND)
Amarillo Señal PWM

¿Qué servo elegir?

Hay multitud de servos, cada uno con una características concretas. Seguramente si estás leyendo esto aún no tienes un servo, o no tienes muy claro la diferencia entre ellos, así que sigue leyendo!

Uno de los factores más importantes es la fuerza que tiene, ya que dependiendo de la aplicación, puede ser que compres un servo que no es capaz de mover la pieza que necesitas mover. Luego, el resto del sistema, tendrá que ser diseñado alrededor del servo que elijas ganador.

SG90 MG995 DS3218
servo sg90 servo mg995 servo ds3218
Par (Kg.cm) 1.8-2.5 8.5-10 18-20
Velocidad (s/60º) 0.1 0.2-0.16 0.14-0.16
Peso (g) 9 55 60
Mejor oferta (€) SG90 MG995 DS3218

Manejando servos con Arduino

Una vez que tenemos nuestro servo elegido solo nos queda conectar a nuestro Arduino para poder moverlo. Arduino implementa la función analogWrite  para hacer salidas de PWM, sin embargo, esta función no podemos utilizarla para nuestras funciones, ya que tiene una frecuencia mayor a los 50Hz que utilizan los servos. La frecuencia que genera el analogWrite  depende del procesador que estemos usando, podes ver exactamente la frecuencia en su página de ayuda.

En nuestro caso, para generar la señal PWM de 50Hz podemos hacer uso de la librería Servo, Solo necesitamos instalar la librería y ponernos manos a la obra. Además, como estamos orientados a hacer un receptor de RC, primero vamos a recibir los datos que generamos en el post anterior, dónde nos fabricábamos una radio RC con Arduino.

Si quieres aprender como mover servos y adaptar este código a un ATmega328p sin Arduino, mira esta entrada!

Recibiendo los datos del nRF24

Como este paso ya lo vimos en el post anterior, no va a cambiar demasiado. Inicializamos el módulo, y configuramos la dirección de lectura, a la misma que configuramos en el transmisor. Además, es muy importante, usar la misma estructura del mensaje, para que los datos se coloquen donde queremos.

En el siguiente código ya serviría para recibir los datos de los 4 ADCs:

#include <nRF24L01.h>
#include <printf.h>
#include <RF24.h>
#include <RF24_config.h>

// RF24
#define CE_PIN 9
#define CSN_PIN 10

RF24 radio(CE_PIN, CSN_PIN);

const uint64_t pipe_tx = 0xAABBCCDD01LL;

void setup() {
 
  radio.begin();
 
  // Configuramos la recepcion
  radio.openReadingPipe(1, pipe_tx);
  radio.setDataRate(RF24_1MBPS);
  radio.setPALevel(RF24_PA_MAX);
  radio.setAutoAck(false);
  radio.setCRCLength(RF24_CRC_8); 
  radio.startListening();
  
  radio.powerUp();
}

// Misma estructura en envio y recepcion
struct msg_{
  uint16_t adc1;
  uint16_t adc2;
  uint16_t adc3;
  uint16_t adc4;
} mensaje;

void loop() {
  // Si hay mensaje lo guardamos.
  while(radio.available()){
    radio.read(&mensaje, sizeof(mensaje));   

    // Hacemos cosas con ese nuevo mensaje 
  }
  
}

¿Cómo usar la librería Servo de Arduino?

Una vez que tenemos los datos recibidos, es muy sencillo usar la librería Servo de Arduino. Esta librería se encarga de preocuparse de todo el protocolo, así que simplemente tenemos que decirle en qué pin está el Servo, y luego ir escribiéndole los valores que queremos.

// Incluimos la nueva librería
#include <Servo.h>

//...

Servo servo1;
Servo servo2;
Servo servo3;
Servo servo4;

void setup(){
  // Inicializamos la radio
  // ...

  // Los ponemos en los pines que queramos
  // que sean PWM!
  servo1.attach(5);
  servo2.attach(...);
  servo3.attach(...);
  servo4.attach(...);
}

void loop(){

  // Si hay datos
  servo1.write(...);
  servo2.write(...);
  servo3.write(...);
  servo4.write(...);
}

Lo que es importante  de tener en cuenta aquí son básicamente 2 funciones:

  • attach(): Que configura el pin al que está conectada la señal del Servo. Hay que tener en cuenta que ese pin tiene que tener capacidad de PWM!!!
  • write(): La cual pone el servo en una posición entre 0 y 180 grados. Es decir, a esta función hay que pasarle valores entre 0 y 180.

Todo junto: recepción nRF24 y Servos

Una función importante a tener en cuenta antes de unir todo, es la función map() esta función se encarga de “mapear” un valor de entrada entre dos rangos, y transformarlo a otro valor en otro rango. Aunque parece un poco lioso es muy fácil, vereis.

En el mando de RC había un paso que era ver que valores nos devolvía el ADC para cada canal. Es decir, si nos centramos en el canal 1, si tenemos que leemos el valor mínimo en 100, y el máximo en 850, pero necesitamos que cuando recibamos un 100, el servo se ponga en la posición 0, y cuando tenemos el 850, queremos que sea posición 180, entonces tenemos que “mapear” del 100 al 0 y del 850 and 180. Y además, los valores intermedios que se calculen automaticamente.

Para ello tenemos la función map()Si, para el caso anterior hacemos: int adc1_conv = map(adc1,100,850,0,180); entonces en adc1_conv tendremos ya el valor del adc1 convertido al rango que queremos. Y si ahora lo ponemos todo junto en el código:

#include <Servo.h>

#include <nRF24L01.h>
#include <printf.h>
#include <RF24.h>
#include <RF24_config.h>

// RF24
#define CE_PIN 9
#define CSN_PIN 10

RF24 radio(CE_PIN, CSN_PIN);

const uint64_t pipe_tx = 0xAABBCCDD01LL;

Servo servo1;
Servo servo2;
Servo servo3;
Servo servo4;

void setup() {
 
  radio.begin();
 
  // Configuramos la recepcion
  radio.openReadingPipe(1, pipe_tx);
  radio.setDataRate(RF24_1MBPS);
  radio.setPALevel(RF24_PA_MAX);
  radio.setAutoAck(false);
  radio.setCRCLength(RF24_CRC_8); 
  radio.startListening();
  
  radio.powerUp();

  servo1.attach(5);
  servo2.attach(...);
  servo3.attach(...);
  servo4.attach(...);
}

// Misma estructura en envio y recepcion
struct msg_{
  uint16_t adc1;
  uint16_t adc2;
  uint16_t adc3;
  uint16_t adc4;
} mensaje;

void loop() {
  // Si hay mensaje lo guardamos.
  while(radio.available()){
    radio.read(&mensaje, sizeof(mensaje));   

    // Hacemos cosas con ese nuevo mensaje 
    servo1.write(map(mensaje.adc1, 100,850, 0, 180));
    servo2.write(...);
    servo3.write(...);
    servo4.write(...);
  }
  
}

Y con esto tendríamos todo!! Hemos visto como recibir datos del nRF24 y además usar la librería Servo. Si esto lo juntamos con la Radio RC casera  ya podemos controlar cualquier robot que queramos!

Si quieres estar al tanto de todos los proyectos no dudes en seguirme en youtube!


Gluón

Teleco con ganas de aprender más y compartirlo. Viajero empedernido y amante de la fotografía y la tecnología. Espero dejar mi granito de arena y que este pueda servir de ayuda.