Proyecto 20.3
Bluetooth RC Car v2
En el siguiente tutorial veremos cómo reciclar / reparar un viejo coche de radio control.
En esta ocasión se trata de un coche teledirigido que encontré en la calle, sin carrocería y sin mando a distancia. Como soy un poco Diógenes -y más cuando se trata de cacharros electrónicos- me lo lleve a casa y comprobé que los motores funcionaban correctamente. Es todo lo que necesito; del mando radiocontrol ya me ocupo yo.
Este coche ya lo he utilizado en proyectos anteriores. En uno de ellos lo hice funcionar con un mando por infrarrojos y en otro proyecto lo hice funcionar con un mando por radiofrecuencia.
En esta ocasión vamos a hacer dos importantes mejoras respecto a los tutoriales anteriores. Por un lado la parte del control remoto la implementaremos mediante bluetooth con un móvil Android y una aplicación diseñada a tal efecto, así nos ahorramos tener que hacer el mando a distancia. Además las comunicaciones por bluetooth tienen un alcance y fiabilidad muy buenas.
El otro cambio consiste en sustituir las cuatro pilas AA que alimentan el coche, por dos baterías de litio. Con este cambio dotamos al coche de más horas de autonomía -y diversión- además de ahorrarnos un dinero en pilas.
Para que nadie se pierda vamos a empezar de cero. Lo primero que hay que hacer es quitar las tapas y acceder al interior para retirar la electrónica ya que está diseñada para funcionar con su propio mando a distancia y como no lo tenemos no nos sirve.
En la esquina inferior derecha pueden verse dos parejas de transistores, seguramente un puente en H para el motor de tracción. El cable negro conectaba la antena con la tarjeta.
Dejaremos únicamente los dos motores de CC, uno montado en las ruedas delanteras para controlar la dirección y otro acoplado en las ruedas traseras para la tracción. Junto al eje trasero está el interruptor de encendido.
Como decía un poco más arriba, vamos a sustituir las cuatro pilas alcalinas AA que originalmente utiliza el coche, por baterías de litio 18650. Esta mejora se la debo a cierto robot hexápodo de cuyo nombre no quiero acordarme y gracias al cual tengo por casa unos cuantos módulos UBEC de sobra.
Para implementar este cambio necesitaremos un portapilas para dos baterías 18650, dos baterías de unos 2500 mAh y su correspondiente cargador. En mi caso sólo he adquirido el portapilas, ya que las baterías y el cargador los compré en su día para mi amigo Vorpal.
Para el que no los conozca, los módulos UBEC son reguladores de tensión que convierten los aproximadamente 8V del pack de dos baterías de litio 18650 en una tensión fija regulada de 5 ó 6 V seleccionable mediante un jumper.
Estos reguladores de tensión soportan corrientes de 3, 5, 7 amperios dependiendo del modelo y son ampliamente utilizados por makers para alimentar drones, servos, robots, etc.
El módulo UBEC lo ubicaremos en el lugar donde antes estaba la tarjeta que retiramos al principio. Las dos baterías de litio van donde antes estaba el portapilas para las cuatro pilas AA. El portapilas lo pegamos al chasis con un poco de silicona termofusible. En el frontal colocaremos la antena bluetooth.
En la tapa central haremos unos taladros para pasar los cables de los dos motores, la salida de 6V del UBEC para alimentar el servo y la alimentación del Arduino.
También he atornillados dos pequeños separadores hexagonales donde irá montado el servo para los motores.
Al retirar la electrónica del coche necesitaremos un driver para controlar los motores. De eso se encargará un archiconocido de los makers: el CI L293D. Este integrado se puede comprar ya montado en placa con los correspondientes conectores, lo que facilita mucho su uso.
En mi caso voy a reciclar un L293 que tenía por casa. Lo he montado en un zócalo y lo he soldado en una placa de islas junto con unos cables para facilitar las conexiones.
La parte de control se la dejamos a un Arduino NANO V3 que por su pequeño tamaño y bajo precio es ideal para este tipo de tareas. Para las comunicaciones utilizaremos un módulo bluetooth HC05. Por último necesitaremos una protoboard de las pequeñas para ayudarnos con las conexiones.
La siguiente imagen muestra el coche con los elementos principales montados.
Solo nos falta montar unos ledes delante y detrás para simular las luces cortas y de posición.
Para ello he utilizado una placa de islas donde he soldado los ledes con sus respectivas resistencias y el transistor que los alimenta.
Vista frontal. Los ledes blancos son las luces de cruce, los amarillos las de posición.
Vista trasera
Esquema
El esquema del coche no presenta mayores complicaciones.
Con dos baterías de litio 18650 conectadas en serie alimentamos el módulo UBEC y el Arduino a través de la entrada VIN. El UBEC entrega una tensión de 6V para los motores, tensión que llevaremos al pin 8 del L293D.
Con los 5V del regulador interno del Arduino alimentamos los ledes, las señales lógicas del L293D en el pin 16 (VCC) y la antena bluetooth. Los pines de comunicación TX y RX del módulo HC05 van cruzados con los del Arduino.
Para terminar, en el pin 12 del Arduino he conectado un zumbador que hará las veces de bocina o claxon. Como veis, nos está quedando un coche la mar de completo, mejor que el original :-)
Una vez terminado el montaje y las conexiones de los componentes, lo siguiente es configurar el módulo HC05 para que se vincule con el móvil y comunique correctamente.
Para configurar los módulos HC05 he seguido las indicaciones de este Instructable pero poniendo el módulo en modo AT como se explica en este vídeo
Para configurar los módulos necesitamos un Arduino UNO y cinco cables macho-hembra.
Hacia la mitad de esta página hay un archivo llamado at_mode.zip. Descárgalo, conecta Arduino al PC, seleccionar el puerto COM correspondiente y sube el sketch at_mode.ino
Desconecta Arduino del PC y conecta el módulo como se indica en el esquema.
3. Para poder comunicar con el módulo éste tiene que estar en modo AT Command. Este modo se indica con un parpadeo lento del led.
Para que el módulo entre en modo AT Command haced lo siguiente: con Arduino desconectado del PC presionar el pulsador de reset del módulo y sin soltar conecta Arduino al PC, después suelta el pulsador. El led parpadeará lentamente.
4. Ir al IDE de Arduino → Herramientas → Monitor Serie y configurar: Ambos NL & CR y velocidad 9600 baudio
5. Introduce los siguientes comandos:
AT+RMAAD (borra la configuración actual)
AT+ROLE=0 (configura el módulo como esclavo)
AT+ROLE? (para verificar rol)
+ROLE:0
AT+PSWD? (para verificar PIN, debe ser el mismo en ambos)
+PIN:"1234"
AT+UART=38400,0,0 (configura la velocidad a 38400)
AT+UART? (para verificar que la velocidad es correcta)
+UART:38400,0,0
6. Fin, el módulo está configurado. Desconecta Arduino del PC.
Sketch
Vamos a pasar a la parte del código.
El funcionamiento es muy sencillo, dependiendo del botón que pulsemos en la pantalla de nuestro móvil, la aplicación manda un mensaje por bluetooth correspondiente a una letra o comando. El receptor lo interpreta y actúa en consecuencia invocando a la función que corresponda.
Mira el Tutorial Oficial de la aplicación para obtener más información.
/* Bluetooth RC Car
version 1. On Change mode con buzzer
luces cortas, 4 luces de posicion y warning lights.
Basado en el original de Andi.co https://sites.google.com/site/bluetoothrccar/
Modificado por un servidor: Angel M. https://sites.google.com/site/angmuz/
*/
int motor1Pin1 = 10; // IN1 L293D IC
int motor1Pin2 = 9; // IN2 L293D IC
int enableM1 = 11; // EN1,2 L293D IC
int motor2Pin1 = 5; // IN3 L293D IC
int motor2Pin2 = 4; // IN4 L293D IC
int enableM2 = 6; // EN3,4 L293D IC
int front_leds = 3; // Luces frontales al pin 2
int rear_leds = 2; // Luces traseras al pin 3
int buzz = 12; // Buzzer al pin 12
char command = 'S';
void setup() {
// sets the pins as outputs:
pinMode(motor1Pin1, OUTPUT);
pinMode(motor1Pin2, OUTPUT);
pinMode(enableM1, OUTPUT);
pinMode(motor2Pin1, OUTPUT);
pinMode(motor2Pin2, OUTPUT);
pinMode(enableM2, OUTPUT);
pinMode(front_leds, OUTPUT);
pinMode(rear_leds, OUTPUT);
pinMode(buzz, OUTPUT);
Serial.begin(38400);
}
// Functions
// if the command is 'S' motors will turn off
void motorsOff(){
digitalWrite(enableM1, LOW);
digitalWrite(enableM2, LOW);
digitalWrite(motor1Pin1, LOW);
digitalWrite(motor1Pin2, LOW);
digitalWrite(motor2Pin1, LOW);
digitalWrite(motor2Pin2, LOW);
}
// if the command is 'F' car go forward
void goForward() {
digitalWrite(enableM1, LOW);
digitalWrite(enableM2, HIGH); // enable main motor
digitalWrite(motor1Pin1, LOW);
digitalWrite(motor1Pin2, LOW);
digitalWrite(motor2Pin1, HIGH);
digitalWrite(motor2Pin2, LOW);
}
// if the command is 'B' car go backward
void goBackward() {
digitalWrite(enableM1, LOW);
digitalWrite(enableM2, HIGH); //enable main motor
digitalWrite(motor1Pin1, LOW);
digitalWrite(motor1Pin2, LOW);
digitalWrite(motor2Pin1, LOW);
digitalWrite(motor2Pin2, HIGH);
}
// if the command is 'R' car turn right
void turnRight() {
digitalWrite(enableM1, HIGH);
digitalWrite(enableM2, LOW);
digitalWrite(motor1Pin1, LOW);
digitalWrite(motor1Pin2, HIGH);
digitalWrite(motor2Pin1, LOW);
digitalWrite(motor2Pin2, LOW);
}
// if the command is 'L' car turn left
void turnLeft() {
digitalWrite(enableM1, HIGH);
digitalWrite(enableM2, LOW);
digitalWrite(motor1Pin1, HIGH);
digitalWrite(motor1Pin2, LOW);
digitalWrite(motor2Pin1, LOW);
digitalWrite(motor2Pin2, LOW);
}
// if the command is 'I' car go forward right
void goForwardRight() {
digitalWrite(enableM1, HIGH);
digitalWrite(enableM2, HIGH);
digitalWrite(motor1Pin1, LOW);
digitalWrite(motor1Pin2, HIGH);
digitalWrite(motor2Pin1, HIGH);
digitalWrite(motor2Pin2, LOW);
}
// if the command is 'G' car go forward left
void goForwardLeft() {
digitalWrite(enableM1, HIGH);
digitalWrite(enableM2, HIGH);
digitalWrite(motor1Pin1, HIGH);
digitalWrite(motor1Pin2, LOW);
digitalWrite(motor2Pin1, HIGH);
digitalWrite(motor2Pin2, LOW);
}
// if the command is 'J' car go backward right
void goBackwardRight() {
digitalWrite(enableM1, HIGH);
digitalWrite(enableM2, HIGH);
digitalWrite(motor1Pin1, LOW);
digitalWrite(motor1Pin2, HIGH);
digitalWrite(motor2Pin1, LOW);
digitalWrite(motor2Pin2, HIGH);
}
// if the command is 'H' car go backward left
void goBackwardLeft() {
digitalWrite(enableM1, HIGH);
digitalWrite(enableM2, HIGH);
digitalWrite(motor1Pin1, HIGH);
digitalWrite(motor1Pin2, LOW);
digitalWrite(motor2Pin1, LOW);
digitalWrite(motor2Pin2, HIGH);
}
// if the command is 'U' the rear leds will turn ON
void ledsOn() {
digitalWrite(rear_leds, HIGH); // set leds ON
}
// if the command is 'u' the rear leds will turn OFF
void ledsOff() {
digitalWrite(rear_leds, LOW); // set leds OFF
}
// if the command is 'W' the front leds will turn ON
void cortasOn() {
digitalWrite(front_leds, HIGH); // set leds ON
}
// if the command is 'w' the front leds will turn OFF
void cortasOff() {
digitalWrite(front_leds, LOW); // set leds OFF
}
// if the command is 'X' the warning leds will turn ON for ten times
void warningOn() {
for (int i=0; i<10; i++)
{
digitalWrite(rear_leds, HIGH);
delay(500);
digitalWrite(rear_leds, LOW);
delay(500);
}
}
// if the command is 'x' the warning leds will turn OFF
void warningOff() {
digitalWrite(rear_leds, LOW); // set leds ON
}
// if the command is 'V' the buzzer will turn ON
void buzzOn() {
digitalWrite(buzz, HIGH); // set buzzer ON
}
// if the command is 'v' the buzzer will turn OFF
void buzzOff() {
digitalWrite(buzz, LOW); // set buzzer OFF
}
// if the command is 'D' all Off
void allOff(){
digitalWrite(rear_leds, LOW); // set leds OFF
digitalWrite(buzz, LOW); // set buzzer OFF
digitalWrite(front_leds, LOW); // set cortas OFF
digitalWrite(enableM1, LOW); // disable M1
digitalWrite(enableM2, LOW); // disable M2
digitalWrite(motor1Pin1, LOW); // set pin 2 on L293D low
digitalWrite(motor1Pin2, LOW); // set pin 7 on L293D low
digitalWrite(motor2Pin1, LOW); // set pin 10 on L293D low
digitalWrite(motor2Pin2, LOW); // set pin 15 on L293D low
}
void loop() {
//if some date is sent, reads it and saves in command
if(Serial.available() > 0){
command = Serial.read();
Serial.print(command);
switch(command){
case 'S':
motorsOff();
break;
case 'F':
goForward();
break;
case 'I':
goForwardRight();
break;
case 'G':
goForwardLeft();
break;
case 'B':
goBackward();
break;
case 'J':
goBackwardRight();
break;
case 'H':
goBackwardLeft();
break;
case 'R':
turnRight();
break;
case 'L':
turnLeft();
break;
case 'U':
ledsOn();
break;
case 'u':
ledsOff();
break;
case 'W':
cortasOn();
break;
case 'w':
cortasOff();
break;
case 'V':
buzzOn();
break;
case 'v':
buzzOff();
break;
case 'D':
allOff();
break;
case 'X':
warningOn();
break;
case 'x':
warningOff();
break;
}
}
}
También tenemos la posibilidad de variar la velocidad del coche mediante una barra de deslizamiento que hay en la parte superior izquierda de la pantalla.
Esta opción es muy útil para maniobrar en sitios pequeños. Para que funcione con nuestro coche debemos introducir una serie de nuevos comandos en el bucle switch / case que son 6, 7 ,8, 9 , q.
Estos comandos corresponden a distintas posiciones de la barra de velocidad que se traducen en pulsos PWM que enviaremos al driver L293D mediante Arduino para modificar la velocidad del motor de tracción, el motor de giro lo dejamos igual.
Añadiremos una nueva variable int spd donde almacenamos la velocidad y cambiamos el comando digitalWrite(enableM2, HIGH) por analogWrite(enableM2, spd) en las funciones para aplicar los pulsos PWM al driver.
A continuación el sketch
/* Bluetooth RC Car.
version 2. On Change con control de velocidad
Basado en el original de Andi.co https://sites.google.com/site/bluetoothrccar/
Modificado por un servidor: Angel M. https://sites.google.com/site/angmuz/
*/
int motor1Pin1 = 10; // IN1 L293D IC
int motor1Pin2 = 9; // IN2 L293D IC
int enableM1 = 11; // EN1,2 L293D IC
int motor2Pin1 = 5; // IN3 L293D IC
int motor2Pin2 = 4; // IN4 L293D IC
int enableM2 = 6; // EN3,4 L293D IC
int front_leds = 3; // Luces frontales al pin 2
int rear_leds = 2; // Luces traseras al pin 3
int buzz = 12; // Buzzer al pin 12
char command = 'S';
int spd = 0;
void setup() {
// sets the pins as outputs:
pinMode(motor1Pin1, OUTPUT);
pinMode(motor1Pin2, OUTPUT);
pinMode(enableM1, OUTPUT);
pinMode(motor2Pin1, OUTPUT);
pinMode(motor2Pin2, OUTPUT);
pinMode(enableM2, OUTPUT);
pinMode(front_leds, OUTPUT);
pinMode(rear_leds, OUTPUT);
pinMode(buzz, OUTPUT);
Serial.begin(38400);
}
// Functions
// if the command is 'S' motors will turn off
void motorsOff(){
digitalWrite(enableM1, LOW); // dir motor
digitalWrite(enableM2, LOW); // main motor
digitalWrite(motor1Pin1, LOW);
digitalWrite(motor1Pin2, LOW);
digitalWrite(motor2Pin1, LOW);
digitalWrite(motor2Pin2, LOW);
}
// if the command is 'F' car go forward
void goForward() {
digitalWrite(enableM1, LOW);
analogWrite(enableM2, spd);
digitalWrite(motor1Pin1, LOW);
digitalWrite(motor1Pin2, LOW);
digitalWrite(motor2Pin1, HIGH);
digitalWrite(motor2Pin2, LOW);
}
// if the command is 'B' car go backward
void goBackward() {
digitalWrite(enableM1, LOW);
analogWrite(enableM2, spd);
digitalWrite(motor1Pin1, LOW);
digitalWrite(motor1Pin2, LOW);
digitalWrite(motor2Pin1, LOW);
digitalWrite(motor2Pin2, HIGH);
}
// if the command is 'R' car turn right
void turnRight() {
digitalWrite(enableM1, HIGH);
digitalWrite(enableM2, LOW);
digitalWrite(motor1Pin1, LOW);
digitalWrite(motor1Pin2, HIGH);
digitalWrite(motor2Pin1, LOW);
digitalWrite(motor2Pin2, LOW);
}
// if the command is 'L' car turn left
void turnLeft() {
digitalWrite(enableM1, HIGH);
digitalWrite(enableM2, LOW);
digitalWrite(motor1Pin1, HIGH);
digitalWrite(motor1Pin2, LOW);
digitalWrite(motor2Pin1, LOW);
digitalWrite(motor2Pin2, LOW);
}
// if the command is 'I' car go forward right
void goForwardRight() {
digitalWrite(enableM1, HIGH);
analogWrite(enableM2, spd);
digitalWrite(motor1Pin1, LOW);
digitalWrite(motor1Pin2, HIGH);
digitalWrite(motor2Pin1, HIGH);
digitalWrite(motor2Pin2, LOW);
}
// if the command is 'G' car go forward left
void goForwardLeft() {
digitalWrite(enableM1, HIGH);
analogWrite(enableM2, spd);
digitalWrite(motor1Pin1, HIGH);
digitalWrite(motor1Pin2, LOW);
digitalWrite(motor2Pin1, HIGH);
digitalWrite(motor2Pin2, LOW);
}
// if the command is 'J' car go backward right
void goBackwardRight() {
digitalWrite(enableM1, HIGH);
analogWrite(enableM2, spd);
digitalWrite(motor1Pin1, LOW);
digitalWrite(motor1Pin2, HIGH);
digitalWrite(motor2Pin1, LOW);
digitalWrite(motor2Pin2, HIGH);
}
// if the command is 'H' car go backward left
void goBackwardLeft() {
digitalWrite(enableM1, HIGH);
analogWrite(enableM2, spd);
digitalWrite(motor1Pin1, HIGH);
digitalWrite(motor1Pin2, LOW);
digitalWrite(motor2Pin1, LOW);
digitalWrite(motor2Pin2, HIGH);
}
// if the command is 'U' the rear leds will turn ON
void ledsOn() {
digitalWrite(rear_leds, HIGH); // set leds ON
}
// if the command is 'u' the rear leds will turn OFF
void ledsOff() {
digitalWrite(rear_leds, LOW); // set leds OFF
}
// if the command is 'W' the front leds will turn ON
void cortasOn() {
digitalWrite(front_leds, HIGH); // set leds ON
}
// if the command is 'w' the front leds will turn OFF
void cortasOff() {
digitalWrite(front_leds, LOW); // set leds OFF
}
// if the command is 'X' the warning leds will turn ON for ten times
void warningOn() {
for (int i=0; i<10; i++)
{
digitalWrite(rear_leds, HIGH);
delay(500);
digitalWrite(rear_leds, LOW);
delay(500);
}
}
// if the command is 'x' the warning leds will turn OFF
void warningOff() {
digitalWrite(rear_leds, LOW); // set leds ON
}
// if the command is 'V' the buzzer will turn ON
void buzzOn() {
digitalWrite(buzz, HIGH); // set buzzer ON
}
// if the command is 'v' the buzzer will turn OFF
void buzzOff() {
digitalWrite(buzz, LOW); // set buzzer OFF
}
// if the command is 'D' all Off
void allOff(){
digitalWrite(rear_leds, LOW); // set leds OFF
digitalWrite(buzz, LOW); // set buzzer OFF
digitalWrite(front_leds, LOW); // set cortas OFF
digitalWrite(enableM1, LOW); // disable M1
digitalWrite(enableM2, LOW); // disable M2
digitalWrite(motor1Pin1, LOW); // set pin 2 on L293D low
digitalWrite(motor1Pin2, LOW); // set pin 7 on L293D low
digitalWrite(motor2Pin1, LOW); // set pin 10 on L293D low
digitalWrite(motor2Pin2, LOW); // set pin 15 on L293D low
}
void loop() {
//if some date is sent, reads it and saves in command
if(Serial.available() > 0){
command = Serial.read();
Serial.print(command);
switch(command){
case 'S':
motorsOff();
break;
case '6':
spd=150;
break;
case '7':
spd=175;
break;
case '8':
spd=200;
break;
case '9':
spd=225;
break;
case 'q':
spd=255;
break;
case 'F':
goForward();
break;
case 'I':
goForwardRight();
break;
case 'G':
goForwardLeft();
break;
case 'B':
goBackward();
break;
case 'J':
goBackwardRight();
break;
case 'H':
goBackwardLeft();
break;
case 'R':
turnRight();
break;
case 'L':
turnLeft();
break;
case 'U':
ledsOn();
break;
case 'u':
ledsOff();
break;
case 'W':
cortasOn();
break;
case 'w':
cortasOff();
break;
case 'V':
buzzOn();
break;
case 'v':
buzzOff();
break;
case 'D':
allOff();
break;
case 'X':
warningOn();
break;
case 'x':
warningOff();
break;
}
}
}
Aplicacion Bluetooth RC Car
Descarga la App Bluetoot RC CAR desde Play Store.
Sube el código al Arduino, abre la aplicación Bluetooth RC Car y clic en Settings .
Seleccionar Connect to car, en la lista de dispositivos, seleccionamos HC-05 y ponemos el PIN 1234.
Una vez el móvil se conecta por bluetooth, el icono rojo pasa a verde y al pulsar sobre los mandos, el coche actuará en consecuencia.
Si has cargado la versión 2 del sketch, debes seleccionar primero la velocidad con la barra deslizante y después accionar los mandos de control.
Para encender las luces y el claxon, tocar sobre los iconos de la parte superior de la pantalla.
Descarga el esquema y los sketch para Arduino aquí abajo.