Proyecto 15 - Coche Radiocontrol
5 de abril de 2015
En este proyecto vamos a hacer un coche de radio control.
Partiendo de un coche de radio control averiado, le cambiaremos la electrónica por un CI L293D, básicamente un driver para motores y con un mando por infrarrojos haremos el control remoto.
Proyecto 15a - Motor Test
En primer lugar vamos a probar los motores del coche. Montamos el circuito del esquema y con un código sencillo comprobamos que los motores funcionan y se mueven como queremos.
Creamos funciones para cada uno de los movimientos, que luego invocaremos según corresponda.
Esquema
Sketch
//M1 motor de giro
//M2 motor traccion
int enableM1 = 11;
int in1Pin = 10;
int in2Pin = 9;
int enableM2 = 6;
int in4Pin = 5;
int in3Pin = 4;
int speed = 255;
void setup()
{
pinMode(in1Pin, OUTPUT);
pinMode(in2Pin, OUTPUT);
pinMode(enableM1, OUTPUT);
pinMode(in3Pin, OUTPUT);
pinMode(in4Pin, OUTPUT);
pinMode(enableM2, OUTPUT);
}
void loop()
{
boolean FW = 0;
boolean BW = 1;
goForward(speed, FW); // Go Forward straight
turnRight(speed, BW); // Go Forward and turn Right
turnRightBK(speed, BW); // Go Backward and turn Right
goBackward(speed, BW); // Go Backward straight
goForward(speed, FW); // Go Forward straight
turnLeft(speed, FW); // Go Forward and turn Left
turnLeftBK(speed, FW); // GO Backward and turn Left
delay(3000);
}
//Turn Left and go Forward
void turnLeft(int speed, boolean FW)
{
//Motor1
boolean reverse1 = FW;
analogWrite(enableM1, speed);
digitalWrite(in1Pin, !reverse1);
digitalWrite(in2Pin, reverse1);
//Motor2
boolean reverse2 = FW;
analogWrite(enableM2, speed);
digitalWrite(in3Pin, !reverse2);
digitalWrite(in4Pin, reverse2);
delay(1500);
analogWrite(enableM1, 0);
analogWrite(enableM2, 0);
}
//Turn Right and go Forward
void turnRight(int speed, boolean BW)
{
//Motor1
boolean reverse1 = BW;
analogWrite(enableM1, speed);
digitalWrite(in1Pin, !reverse1);
digitalWrite(in2Pin, reverse1);
//Motor2
boolean reverse2 = !BW;
analogWrite(enableM2, speed);
digitalWrite(in3Pin, !reverse2);
digitalWrite(in4Pin, reverse2);
delay(1500);
analogWrite(enableM1, 0);
analogWrite(enableM2, 0);
}
//Funcion Go Forward
void goForward(int speed, boolean FW)
{
//Motor1 inhabilitado, para que vaya recto
analogWrite(enableM1, 0);
//Motor2
boolean reverse2 = FW;
analogWrite(enableM2, speed);
digitalWrite(in3Pin, !reverse2);
digitalWrite(in4Pin, reverse2);
delay(1500);
analogWrite(enableM2, 0);
}
//Funcion Go Backward
void goBackward(int speed, boolean BW)
{
//Motor1 inhabilitado, para que vaya recto
analogWrite(enableM1, 0);
//Motor2
boolean reverse2 = BW;
analogWrite(enableM2, speed);
digitalWrite(in3Pin, !reverse2);
digitalWrite(in4Pin, reverse2);
delay(1500);
analogWrite(enableM1, 0);
analogWrite(enableM2, 0);
}
//Turn Left and go Backward
void turnLeftBK(int speed, boolean FW)
{
//Motor1 Giro
boolean reverse1 = FW;
analogWrite(enableM1, speed);
digitalWrite(in1Pin, !reverse1);
digitalWrite(in2Pin, reverse1);
//Motor2 Traccion
boolean reverse2 = !FW;
analogWrite(enableM2, speed);
digitalWrite(in3Pin, !reverse2);
digitalWrite(in4Pin, reverse2);
delay(1500);
analogWrite(enableM1, 0);
analogWrite(enableM2, 0);
}
//Turn Right and go Backward
void turnRightBK(int speed, boolean BW)
{
//Motor1 giro
boolean reverse1 = BW;
analogWrite(enableM1, speed);
digitalWrite(in1Pin, !reverse1);
digitalWrite(in2Pin, reverse1);
//Motor2 traccion
boolean reverse2 = BW;
analogWrite(enableM2, speed);
digitalWrite(in3Pin, !reverse2);
digitalWrite(in4Pin, reverse2);
delay(1500);
analogWrite(enableM1, 0);
analogWrite(enableM2, 0);
}
Proyecto 15b - Mando a Distancia por Infrarrojos
A continuación vamos a hacer el control remoto por infrarrojos.
Este tutorial lo he sacado de la web tronixstuff. Mira el original aquí.
Para ello necesitamos un mando por infrarrojos y un receptor. El mando puede ser uno que tengamos por casa y como receptor utilizamos el TSOP31238, funciona a 38KHz y se puede adquirir por menos de 1€.
En mi caso he utilizado el mando de un antiguo reproductor de CD Philips. También vale un mando universal.
Lo primero es verificar que el receptor funciona correctamente, para ello mediante un sencillo sketch veremos en el monitor serial los distintos códigos hexadecimales asociados a cada botón.
Aquí podemos descargar la librería necesaria para que funcione el receptor:
Esquema
Sketch
// example 32.1 - IR receiver code repeater
// http://tronixstuff.com/tutorials > chapter 32
// based on code by Ken Shirriff - http://arcfn.com
#include <IRremote.h> // use the library
int receiver = 11; // pin 1 of IR receiver to Arduino digital pin 11
IRrecv irrecv(receiver); // create instance of 'irrecv'
decode_results results;
void setup()
{
Serial.begin(9600); // for serial monitor output
irrecv.enableIRIn(); // Start the receiver
}
void loop()
{
if (irrecv.decode(&results)) // have we received an IR signal?
{
Serial.println(results.value, HEX); // display it on serial monitor in hexadecimal
irrecv.resume(); // receive the next value
} // Your loop can do other things while waiting for an IR command
}
Una vez cargado el sketch, abrir el monitor serial y comenzar a pulsar botones, a cada pulsación le corresponde un código en hexadecimal.
Indicar que cada mando es diferente, el aquí usado tiene la particularidad de que el mismo botón tiene dos códigos que se repiten secuencialmente.
Apuntad en un papel el código correspondiente a cada botón, lo necesitaremos para programar las funciones.
Dependiendo del mando utilizado habrá que modificar el sketch para adaptarlo a nuestras necesidades, como veremos más adelante.
Proyecto 15c - Creando un Control Remoto por Infrarrojos
En este proyecto haremos un mando a distancia con el que controlaremos los pines digitales del Arduino.
Mediante una estructura switch-case asociamos cada código a una acción, en este caso encender un led.
Este ejemplo servirá de base para controlar un coche teledirigido.
Esquema
Sketch
int receiverpin = 11;
#include <IRremote.h>
IRrecv irrecv(receiverpin);
decode_results results;
void setup()
{
pinMode(2, OUTPUT);
pinMode(4, OUTPUT);
pinMode(6, OUTPUT);
irrecv.enableIRIn();
}
void ledUno() // enciende el led 1 tres segundos
{
digitalWrite(2, HIGH);
delay(3000);
digitalWrite(2, LOW);
}
void ledDos() // enciende el led 2 tres segundos
{
digitalWrite(4, HIGH);
delay(3000);
digitalWrite(4, LOW);
}
void ledTres() // enciende el led 3 tres segundos
{
digitalWrite(6, HIGH);
delay(3000);
digitalWrite(6, LOW);
}
void translateIR()
{
switch(results.value)
{
case 0xD02: ledUno(); break;
case 0xD05: ledDos(); break;
case 0xD06: ledTres(); break;
}
}
void loop()
{
if (irrecv.decode(&results))
{
translateIR();
irrecv.resume();
}
}
Proyecto 15d - RC Car
Vamos a agrupar lo aprendido hasta aquí, para hacer nuestro propio coche de radiocontrol.
Esquema
En el circuito definitivo he empleado el L293D y un arduino Nano, versión en miniatura y más barata que el arduino UNO.
Debido a su reducido tamaño y coste, arduino Nano es ideal para trabajar de forma permanente in situ en proyectos ya testeados.
En la foto podéis ver el resultado final del coche.
Sketch
//RC car with IR Remote Control
//M1 motor de giro
//M2 motor traccion
int receiverpin = 11;
#include <IRremote.h>
IRrecv irrecv(receiverpin); // create instance of 'irrecv'
decode_results results;
int enableM1 = 5;
int in1Pin = 10;
int in2Pin = 9;
int enableM2 = 6;
int in4Pin = 13;
int in3Pin = 4;
int speed = 255;
int duration = 500;
void setup()
{
pinMode(in1Pin, OUTPUT);
pinMode(in2Pin, OUTPUT);
pinMode(enableM1, OUTPUT);
pinMode(in3Pin, OUTPUT);
pinMode(in4Pin, OUTPUT);
pinMode(enableM2, OUTPUT);
irrecv.enableIRIn();
}
//Turn Left and go Forward
void turnLeft(int speed)
{
//Motor1
boolean FW = 0;
boolean reverse1 = FW;
analogWrite(enableM1, speed);
digitalWrite(in1Pin, !reverse1);
digitalWrite(in2Pin, reverse1);
//Motor2
boolean reverse2 = FW;
analogWrite(enableM2, speed);
digitalWrite(in3Pin, !reverse2);
digitalWrite(in4Pin, reverse2);
delay(duration);
analogWrite(enableM1, 0);
analogWrite(enableM2, 0);
}
//Turn Right and go Forward
void turnRight(int speed)
{
//Motor1
boolean BW = 1;
boolean reverse1 = BW;
analogWrite(enableM1, speed);
digitalWrite(in1Pin, !reverse1);
digitalWrite(in2Pin, reverse1);
//Motor2
boolean reverse2 = !BW;
analogWrite(enableM2, speed);
digitalWrite(in3Pin, !reverse2);
digitalWrite(in4Pin, reverse2);
delay(duration);
analogWrite(enableM1, 0);
analogWrite(enableM2, 0);
}
//Funcion Go Forward
void goForward(int speed)
{
//Motor1 inhabilitado, para que vaya recto
boolean FW = 0;
analogWrite(enableM1, 0);
//Motor2
boolean reverse2 = FW;
analogWrite(enableM2, speed);
digitalWrite(in3Pin, !reverse2);
digitalWrite(in4Pin, reverse2);
delay(duration);
analogWrite(enableM2, 0);
}
//Funcion Go Backward
void goBackward(int speed)
{
//Motor1 inhabilitado, para que vaya recto
boolean BW = 1;
analogWrite(enableM1, 0);
//Motor2
boolean reverse2 = BW;
analogWrite(enableM2, speed);
digitalWrite(in3Pin, !reverse2);
digitalWrite(in4Pin, reverse2);
delay(duration);
analogWrite(enableM1, 0);
analogWrite(enableM2, 0);
}
//Turn Left and go Backward
void turnLeftBK(int speed)
{
//Motor1 Giro
boolean FW = 0;
boolean reverse1 = FW;
analogWrite(enableM1, speed);
digitalWrite(in1Pin, !reverse1);
digitalWrite(in2Pin, reverse1);
//Motor2 Traccion
boolean reverse2 = !FW;
analogWrite(enableM2, speed);
digitalWrite(in3Pin, !reverse2);
digitalWrite(in4Pin, reverse2);
delay(duration);
analogWrite(enableM1, 0);
analogWrite(enableM2, 0);
}
//Turn Right and go Backward
void turnRightBK(int speed)
{
//Motor1 giro
boolean BW = 1;
boolean reverse1 = BW;
analogWrite(enableM1, speed);
digitalWrite(in1Pin, !reverse1);
digitalWrite(in2Pin, reverse1);
//Motor2 traccion
boolean reverse2 = BW;
analogWrite(enableM2, speed);
digitalWrite(in3Pin, !reverse2);
digitalWrite(in4Pin, reverse2);
delay(duration);
analogWrite(enableM1, 0);
analogWrite(enableM2, 0);
}
void translateIR()
{
switch(results.value)
{
speed = 255;
case 0xD02: goForward(speed); break; // Go Forward straight
case 0x502: goForward(speed); break; // Go Forward straight
case 0xD08: goBackward(speed); break; // Go Backward straight
case 0x508: goBackward(speed); break; // Go Backward straight
case 0xD06: turnRight(speed); break; // Go Forward and turn Right
case 0x506: turnRight(speed); break; // Go Forward and turn Right
case 0xD04: turnLeft(speed); break; // Go Forward and turn Left
case 0x504: turnLeft(speed); break; // Go Forward and turn Left
case 0xD07: turnLeftBK(speed); break; // GO Backward and turn Left
case 0x507: turnLeftBK(speed); break; // GO Backward and turn Left
case 0xD09: turnRightBK(speed); break; // Go Backward and turn Right
case 0x509: turnRightBK(speed); break; // Go Backward and turn Right
}
}
void loop()
{
if (irrecv.decode(&results))
{
translateIR();
irrecv.resume(); // receive the next value
}
}
Aquí debajo hay una versión modificada del código anterior.
Se trata de un modo de funcionamiento continuo para las funciones de avanzar, retroceder y girar, de esa forma el manejo del coche resulta más cómodo al no tener que mantener constantemente pulsado el botón correspondiente.
Al disponer del botones de sobra, se han mantenido también las funciones originales con delay para maniobras que necesiten de movimientos más precisos.