lunes, 8 de noviembre de 2010

Radio control Memo car

XD antes que nada, tremendo el título del artículo. Este proyecto trata de manejar nuestro coche radio control, mediante un PC. con las teclas AWSD por ejemplo y poder memorizar el camino que hemos hecho.

Lo primero es el material del que disponemos. Utilizaremos un coche de juguete tyco, aunque cualquiera nos vale ya que no vamos a tocar el coche para nada, simplemente puentearemos el mando para poder manejarlo con arduino.



El coche va sin su carcasa, no es que esté roto... , y el mando ya en su acabado final con sus cables de conexión a la placa de control.

La placa de control:

Para poder comunicar el arduino con el mando he construido un pekeño shield que ahora explicaré su funcionamiento.



El circuito es bastante simple, se compone de 4 transistores BC337 con los cuales conmuto el circuito entre la tierra y las conexiones del mando. Con 4 pines de arduino controlaré digitalmente si acciono cada uno de los interruptores del mando.
Cabe destacar que este coche es digital, no tiene aceleración gradual ni giro gradual, todas sus acciones son binarias.

PD: yo no sabía como funcionaba un transistor como este pero es bastante fácil, tienen 3 patas, las de los lados las conectas al circuito y la del medio al arduino, y si el arduino mete voltaje por ahi, el circuito se abre. Es como un interruptor pero en lugar de botón para encender o apagar, se le manda una señal por la pata del medio.




El montaje del sistema es facil y rápido.

El mando y sus conexiones:

Llevó su tiempo buscar los puntos donde le hacía cosquillas al mando pero al final gracias a Isra en gran parte encontramos el funcionamiento básico del mando y como puentearlo:



Como vemos en las imágenes, hemos tenido que abrir el mando y acceder por la parte posterior a las soldaduras. En la foto de la derecha, los cables rojo y negro de arriba izquierda, son los conectores para girar el coche, los de arriba derecha es el acelerador y la marcha atrás. Y abajo donde coincide con el cable azul, es la tierra, que es muy importante que la tierra del mando esté conectada a la tierra de arduino.

La programación de Arduino:

En arduino simplemente tendremos un programa que dado un numero que nos viene por serie, hace una acción u otra por los pines de control.

const int ledPin = 9; // the pin that the LED is attached to

void setup()
{
// initialize the serial communication:
Serial.begin(9600);
// initialize the ledPin as an output:
pinMode(2, OUTPUT); //up
pinMode(3, OUTPUT); //down
pinMode(4, OUTPUT); //right
pinMode(5, OUTPUT); //left
digitalWrite(2, B0);
digitalWrite(3, B0);
digitalWrite(4, B0);
digitalWrite(5, B0);
}

void loop() {
byte val;
int WEST = 8;
int SOUTH = 4;
int EAST = 2;
int NORTH = 1;

if (Serial.available()) {
val = Serial.read();
(val & NORTH)?digitalWrite(2, B1):digitalWrite(2, B0);
(val & EAST)?digitalWrite(3, B1):digitalWrite(3, B0);
(val & SOUTH)?digitalWrite(4, B1):digitalWrite(4, B0);
(val & WEST)?digitalWrite(5, B1):digitalWrite(5, B0);
}
}


La programación de Processing:

Processing es el que tiene la miga, este se encarga de enviarle a arduino las teclas que estámos pulsando, para que arduino mueva el coche. Pero además llevará un sistema de log de teclas que irá guardando en un fichero para poder reproducir la secuencia programada.

Teclas:
ASDW : teclas de dirección
R: Empezar a grabar camino
P: Reproducir secuencia grabada (la secuencia se reproducirá en bucle infinito)
U: Stop, tanto para grabar como para reproducir



final static int NORTH = 2;
final static int EAST = 4;
final static int SOUTH = 1;
final static int WEST = 8;
final static int TURBO = 16;

boolean record = false;
boolean play = false;
int result;
import processing.serial.*;
Serial port;
PrintWriter output;
String[] lines;
int index = 0;

void all(int colori){
izq(colori);
der(colori);
arr(colori);
aba(colori);
}

void izq(int colori){
fill(colori);
rect(10,50,30,40);
}
void der(int colori){
fill(colori);
rect(80,50,30,40);
}
void arr(int colori){
fill(colori);
rect(40,10,40,40);
}
void aba(int colori){
fill(colori);
rect(40,90,40,40);
}
void setup() {
size(400,200);
frameRate(30);
result = 0;
port = new Serial(this, Serial.list()[0], 9600);
background(0);
all(33);
}
void draw() {
if (record) {
output.println(result);
output.flush();
}
if (play) {
if (index <>
result = int(lines[index]);
index = index + 1;
} else index = 0;
}
switch(result) {
case NORTH:
port.write(NORTH);
arr(255);
aba(33);
break;
case TURBO|NORTH:
port.write(SOUTH|NORTH);
arr(150);
aba(33);
break;
case TURBO|NORTH|WEST:
port.write(SOUTH|NORTH|WEST);
arr(150);
der(33);
izq(150);
aba(33);
break;
case TURBO|NORTH|EAST:
port.write(SOUTH|NORTH|EAST);
arr(150);
der(150);
izq(33);
aba(33);
break;
case EAST:
port.write(EAST);
der(255);
izq(33);
break;
case SOUTH:
port.write(SOUTH);
aba(255);
arr(33);
break;
case WEST:
port.write(WEST);
izq(255);
der(33);
break;
case NORTH|EAST:
port.write(NORTH|EAST);
arr(255);
der(255);
izq(33);
aba(33);
break;
case NORTH|WEST:
arr(255);
der(33);
izq(255);
aba(33);
port.write(NORTH|WEST);
break;
case SOUTH|EAST:
arr(33);
der(255);
izq(33);
aba(255);
port.write(SOUTH|EAST);
break;
case SOUTH|WEST:
arr(33);
der(33);
izq(255);
aba(255);
port.write(SOUTH|WEST);
break;
default:
port.write(0);
all(33);
break;
}

}
void keyPressed(){
switch(key) {
case('w'):case('W'):result |=NORTH;break;
case('d'):case('D'):result |=EAST;break;
case('s'):case('S'):result |=SOUTH;break;
case('a'):case('A'):result |=WEST;break;
case('t'):case('T'):result |=TURBO;break;
case('r'):case('R'):
output = createWriter("save.txt");
record = true;
play = false;
break;
case('u'):case('U'):record = false; play = false;break;
case('p'):case('P'):
play = true;
record = false;
output.flush();
output.close();
lines = loadStrings("save.txt");
index = 0;
break;
}
}
void keyReleased(){
switch(key) {
case('w'):case('W'):result ^=NORTH;break;
case('d'):case('D'):result ^=EAST;break;
case('s'):case('S'):result ^=SOUTH;break;
case('a'):case('A'):result ^=WEST;break;
case('t'):case('T'):result ^=TURBO;break;
}
}

Video: