En el tutorial anterior vimos como hacer un sencillo conjunto emisor-receptor de 2.4GHz con el módulo NRF24L01.
A continuación vamos a profundizar un poco más en el mundillo inalámbrico, haciendo un coche de radiocontrol y el correspondiente mando de control remoto.
El coche es el mismo que he utilizado en proyectos anteriores. Básicamente se trata de un chasis con dos motores, uno de tracción acoplado a las ruedas traseras y otro de giro en las ruedas delanteras.
Con un driver L293D alimentamos los motores, el módulo NRF24L01 será el encargado de las comunicaciones. El control de ambos dispositivos lo implementaremos con un Arduino NANO v3.
Como se aprecia en el esquema, he añadido cuatro leds de color rojo que harán la función de luces de posición y otros dos leds blancos que simulan las luces frontales o cortas como decimos por aquí. Además de un zumbador piezoeléctrico a modo de claxon.
El zumbador y las luces de posición están conectados a los pines analógicos A0 y A1 ya que no quedan pines digitales disponibles. Los pines analógicos se pueden utilizar como E/S digitales si hace falta. Solo hay que definirlos como tales en el setup del sketch.
El circuito dispone de dos alimentaciones, una de 5V con un USB Power Bank, para el Arduino, los leds y el L293D. Y otra alimentación de 6V con 4 pilas AA para los motores.
El transmisor consiste en una botonera con seis pulsadores para las funciones de avanzar, retroceder, girar a derecha e izquierda, encender y apagar las luces y tocar la bocina.
La botonera se conecta a un Arduino NANO v3, que por su reducido tamaño es ideal para hacer el control remoto. Conectamos también un módulo NRF24L01 que hará las veces de transmisor. Con una pila de 9V y un interruptor alimentamos el mando.
A continuación una imagen con el mando desde diferentes ángulos.
Vamos a pasar a la parte del código.
El funcionamiento es muy sencillo, dependiendo del pulsador que accionemos en el mando, el transmisor manda un mensaje por radio, que consiste en un número. El receptor lo interpreta y actúa en consecuencia invocando a la función que corresponda.
Para que el código compile correctamente son necesarias las librerías SPI y RF24. Ambas están disponibles para descargar al final de la página.
/*
Wireless Remote Controlled Car
w NRF24L01 2.4GHz Transceiver
Sketch para el emisor
Angel M. https://sites.google.com/site/angmuz/
*/
#include <nRF24L01.h>
#include <RF24.h>
#include <RF24_config.h>
#include <SPI.h>
int msg[1] ; // Array a transmitir
RF24 radio(9,10); // Creamos un objeto radio del tipo RF2$
const uint64_t pipe = 0xE8E8F0F0E1LL; // Usamos este canal
void setup(void){
pinMode(2, INPUT); // SW1
pinMode(3, INPUT); // SW2
pinMode(4, INPUT); // SW3
pinMode(5, INPUT); // SW4
pinMode(6, INPUT); // SW5
pinMode(7, INPUT); // SW6
Serial.begin(9600);
radio.begin();
radio.openWritingPipe(pipe);} // Abrir para escribir
void loop(void){
// SW6 buzz On
if (digitalRead(7)==HIGH)
{
msg[0] = 11;
radio.write(msg, 1);
}
// SW6 buzz Off
if (digitalRead(7)==LOW)
{
msg[0] = 12;
radio.write(msg, 1);
}
// SW1 go Forward
if (digitalRead(2)==HIGH)
{
msg[0] = 1;
}
// SW2 turn Left
if (digitalRead(3)==HIGH)
{
msg[0] = 3;
}
// SW3 turn Right
if (digitalRead(4)==HIGH)
{
msg[0] = 5;
}
// SW4 go Backward
if (digitalRead(5)==HIGH)
{
msg[0] = 7;
}
// Motor stop
if (digitalRead(2)==LOW && digitalRead(3)==LOW && digitalRead(4)==LOW && digitalRead(5)==LOW)
{
msg[0] = 2;
}
// SW5 lights On/Off
if (digitalRead(6)==HIGH)
{
msg[0] = 9;
}
radio.write(msg, 1);
// for debounce SW5
if (msg[0] == 9){
delay(100);
}
}
/*
Wireless Remote Controlled Car
w NRF24L01 2.4GHz Transceiver
Sketch para el receptor
Angel M. https://sites.google.com/site/angmuz/
*/
#include <nRF24L01.h>
#include <RF24.h>
#include <RF24_config.h>
#include <SPI.h>
int msg[1];
int command = 0;
RF24 radio(9,10);
const uint64_t pipe = 0xE8E8F0F0E1LL;
int in1Pin = 8; // pin 2 on L293D IC
int in2Pin = 7; // pin 7 on L293D IC
int enableM1 = 6; // pin 1 on L293D IC
int in4Pin = 5; // pin 15 on L293D IC
int in3Pin = 4; // pin 10 on L293D IC
int enableM2 = 3; // pin 9 on L293D IC
int ledsPosicion = 15; // Leds posicion al pin 15 (A1)
int cortas = 2; // luces cortas al pin 2
int buzz = 14; // Buzzer al pin 14 (A0)
boolean luces=0;
void setup(void) {
// sets the pins as outputs:
pinMode(in1Pin, OUTPUT);
pinMode(in2Pin, OUTPUT);
pinMode(enableM1, OUTPUT);
pinMode(in3Pin, OUTPUT);
pinMode(in4Pin, OUTPUT);
pinMode(enableM2, OUTPUT);
pinMode(buzz, OUTPUT);
pinMode(ledsPosicion, OUTPUT);
pinMode(cortas, OUTPUT);
//Serial.begin(9600);
radio.begin();
radio.openReadingPipe(1,pipe);
radio.startListening();
}
void loop(void){
if (radio.available())
{
int done = radio.read(msg, 1);
command = msg[0];
switch(command){
case 1:
goForward();
break;
case 3:
goForwardLeft();
break;
case 5:
goForwardRight();
break;
case 7:
goBackward();
break;
case 2:
motorStop();
break;
case 9:
lucesOnOff();
break;
case 11:
digitalWrite(buzz, HIGH);
break;
case 12:
digitalWrite(buzz, LOW);
break;
}
}
}
// Funciones
// if the command is '1' the car go forward
void goForward() {
//Motor1 inhabilitado, para que vaya recto
digitalWrite(enableM1, LOW);
digitalWrite(in1Pin, LOW);
digitalWrite(in2Pin, LOW);
//Motor2 traccion
digitalWrite(enableM2, HIGH);
digitalWrite(in3Pin, HIGH);
digitalWrite(in4Pin, LOW);
}
// if the command is '7' the car go backward
void goBackward() {
//Motor1 giro inhabilitado, para que vaya recto
digitalWrite(enableM1, LOW);
digitalWrite(in1Pin, LOW);
digitalWrite(in2Pin, LOW);
//Motor2 traccion
digitalWrite(enableM2, HIGH);
digitalWrite(in3Pin, LOW);
digitalWrite(in4Pin, HIGH);
}
// if the command is '5' the car go forward right
void goForwardRight() {
//Motor1 giro
digitalWrite(enableM1, HIGH);
digitalWrite(in1Pin, LOW);
digitalWrite(in2Pin, HIGH);
//Motor2 traccion
digitalWrite(enableM2, HIGH);
digitalWrite(in3Pin, HIGH);
digitalWrite(in4Pin, LOW);
}
// if the command is '3' the car go forward left
void goForwardLeft() {
//Motor1 giro
digitalWrite(enableM1, HIGH);
digitalWrite(in1Pin, HIGH);
digitalWrite(in2Pin, LOW);
//Motor2 traccion
digitalWrite(enableM2, HIGH);
digitalWrite(in3Pin, HIGH);
digitalWrite(in4Pin, LOW);
}
// if the command is 2 car stop
void motorStop() {
//Motor1 giro
digitalWrite(enableM1, LOW);
digitalWrite(in1Pin, LOW);
digitalWrite(in2Pin, LOW);
//Motor2 traccion
digitalWrite(enableM2, LOW);
digitalWrite(in3Pin, LOW);
digitalWrite(in4Pin, LOW);
}
void lucesOnOff() {
if (luces==0){
digitalWrite(cortas, HIGH);
digitalWrite(ledsPosicion, HIGH);
}
if (luces==1) {
digitalWrite(cortas, LOW);
digitalWrite(ledsPosicion, LOW);
}
luces=!luces;
}
Durante el desarrollo de este tutorial surgieron algunos problemas, tanto a nivel de hardware como de software. Un módulo NRF24L01 defectuoso me hizo perder muchas horas investigando por qué no funcionaba el transmisor, hasta que lo cambié por otro. Los condensadores utilizados para evitar el debounce de los pulsadores también han dado guerra, pues su valor debe ser el apropiado; menos de 100nF puede ocasionar un mal funcionamiento del transmisor.
En cuanto al software, es cuestión de empezar por un sketch sencillo e ir añadiendo funciones hasta que todos los movimientos, los leds y el zumbador funcionen correctamente.
Con esto quiero decir que no os desaniméis si vuestros proyectos no salen a la primera, rara vez lo hacen. Descomponed el problema en otros más sencillos, probadlos por separado y luego unidlo todo.
Descarga el proyecto en un .zip aquí abajo. Incluye esquemas, código y librerías.