miércoles, 28 de septiembre de 2011

Robot SigueLíneas (IV): Resultados

Y aquí os dejo un vídeo de este robot moviéndose a lo largo de la línea del panel que venía con el Lego(C) Mindstorms.



Va bastante lento. El que se mueva más rápido iba a necesitar de más labores de programación y tampoco estaba por la labor. Con hacer un seguidor de líneas utilizando dos sensores ya me daba por satisfecho.

En el vídeo se puede ver como comienza a girar el robot. Cuando uno de los sensores se acerca a la línea negra. Cuando la línea está entre los dos sensores el robot sigue recto.

El cable conectado al arduino,se utiliza para darle energía y para enviar la información al Matlab, que la lee a través del puerto serie. Matlab envía las órdenes utilizando el bluetooth, que milagrosamente ahora funciona.

Me gustaría como mejora, ponerle un portapilas al arduino para no tener cables. Enviar la información a través de un emisor rf a otro arduino, este sí, conectado por usb a un Matlab y que este envíe las órdenes por bluetooth al bloque.

Robot SigueLíneas (III): Matlab

Aquí adjunto el código para mover todo con matlab.

umbral = 150;
potenciaAdelante = 5;
potenciaGiro = 3 * potenciaAdelante;

COM_CloseNXT all
hNXT = COM_OpenNXT('bluetooth.ini');
COM_SetDefaultNXT(hNXT);

placa = serial( 'COM4' , 'BaudRate', 9600 );
fopen( placa );

try
i = 1;

mi = NXTMotor('A');
md = NXTMotor('B');


while (i < 10000)
loQueRecibo = fscanf( placa );
loQueRecibo = sscanf(loQueRecibo,'%d');

a = size(loQueRecibo);

if(a(1) == 2)

loQueRecibo;

valorIzquierda = loQueRecibo(1);
valorDerecha = loQueRecibo(2);

if( (valorIzquierda < umbral) && (valorDerecha > umbral) )
display('Me muevo hacia la izquierda.');
mi.Stop('off');
mi.SendToNXT();

md.Power = potenciaGiro;
md.SendToNXT();
elseif( (valorDerecha < umbral) && (valorIzquierda > umbral) )
display('Me muevo hacia la derecha.');

md.Stop('off');
md.SendToNXT();

mi.Power = potenciaGiro;
mi.SendToNXT();
elseif( (valorDerecha > umbral) && (valorIzquierda > umbral) )
display('Me muevo hacia adelante como los de alicante.');

mi.Power = potenciaAdelante;
mi.SendToNXT();

md.Power = potenciaAdelante;
md.SendToNXT();
else
md.Stop('off');
mi.Stop('off');

loQueRecibo

%pause;
end

i = i + 1;
end % compruebo que he recibido dos
end

catch err
loQueRecibo
display('LEÑO GORDO')

err

try
mi.Stop('off');
md.Stop('off');
catch err1
end

fclose( placa );
COM_CloseNXT(hNXT);
end % try-catch

mi.Stop('off');
md.Stop('off');

fclose( placa );
COM_CloseNXT(hNXT);


He utilizado la la última versión estable de laRWHT toolbox. Ahora está orientada a objetos y utiliza una aplicación en nxc para un, según ellos, mejor control de los motores.

Robot SigueLíneas (II): Parte Arduino leyendo un sensor óptico QRD1114

El montaje es bastante sencillo. Habría que repetirlo dos veces, para tener un sensor a cada lado de la línea.





En las entradas analógicas 0 y 5 del arduino recogemos la información del sensor.

El código del arduino es el siguiente

int pinIzquierdo = 0;
int pinDerecho = 5;

void setup(){
Serial.begin(9600);

pinMode( pinIzquierdo , INPUT );
pinMode( pinDerecho , INPUT );
}//setup

void loop(){
delay(500);

Serial.print( analogRead ( pinIzquierdo ) );
Serial.print( " " );
Serial.print( analogRead ( pinDerecho ) );
Serial.println();
Serial.flush();
}//loop


Y aquí está la salida que se muestra por el monitor serie.

A la izquierda de cuando detecta blanco por ambos lados. En el centro cuando detecta blanco a un lado y negro al otro. Y a la izquierda viceversa.

Robot Sigue Líneas (I): Introducción

Hoy voy exponer un pequeño proyecto que es bastante típico dentro del mundo de la construcción de robots: un seguidor de líneas.

Cierto es que ya había construido un robot de características similares en un par de ocasiones. Pero en ambos casos sólo tenía un sensor para leer la línea. Ahora, voy a tener dos. Además de que no puse ningún vídeo.

No me he comprado ningún sensor de lego nuevo. Vamos a hacerlo con estos dos pequeños sensores (QRD1114), un arduino y un lego.



Estos sensores tienen aquí una hoja de especificaciones muy bien explicada para gente experta. Como soy un poco más mundano, lo voy a explicar para zotes como yo. Es un sensor análogico que mide la cantidad de luz reflejada por una superficie. De este modo, una superficie negra no refleja la misma luz que una blanca, permitiendo diferenciar el color de la superficie.

Lo que pretendo construir es un vehículo que tenga incrustado el arduino conectado a los dos sensores. Este arduino enviará la lectura de los sensores a Matlab a través de un cable usb. Matlab la interpretará y moverá los motores del vehículo acorde a través de la conexión bluetooth.





Lo ideal sería prescindir del cable usb y enviar la información a Matlab a través de un emisor rf, como ya hice con anterioridad. Pero es que de momento, tampoco sé alimentar al arduino con otra cosa que no sea un cable usb.

sábado, 9 de abril de 2011

Comunicación i2c con Arduino

El i2c es un bus serie para la transmisión de datos. Aquí seguro que lo explican mucho mejor que yo. Pero como pequeño resumen, el bus i2c tiene dos líneas importantes SDA para datos y SCL para la señal del reloj.

Las placas Arduino tienen soporte para este protocolo en los pines analógicos 4 y 5 y se proporciona una librería, Wire, para trabajar.

Así que lo que voy a explicar a continuación es un pequeño ejemplo de como dos placas Arduino se pueden comunicar a través de i2c.

El escenario será el habitual. Un Arduino hará de maestro y enviará al Arduino esclavo si se ha pulsado un botón para que ilumine un led y otro.

Aquí va el código para el maestro
#include 

int pinBotonRojo = 2;
int pinBotonVerde = 3;

int rojo = 1;
int verde = 2;
int azul = 3;
int nada = 4;

void setup(){
Wire.begin();
Serial.begin(9600);

pinMode( pinBotonRojo , INPUT );
pinMode( pinBotonVerde , INPUT );
}//setup

void loop(){

Wire.beginTransmission(4);

int valorBotonRojo = digitalRead ( pinBotonRojo );
int valorBotonVerde = digitalRead ( pinBotonVerde );

if ( (valorBotonRojo == HIGH) && (valorBotonVerde == HIGH) ){
Wire.send(nada);
Serial.println("Envío -> nada");
}else if ( (valorBotonRojo == HIGH) && (valorBotonVerde == LOW) ){
Wire.send(rojo);
Serial.println("Envío -> rojo");
}else if ( (valorBotonRojo == LOW) && (valorBotonVerde == HIGH) ){
Wire.send(verde);
Serial.println("Envío -> verde");
}else if ( (valorBotonRojo == LOW) && (valorBotonVerde == LOW) ){
Wire.send(azul);
Serial.println("Envío -> azul");
}

Wire.endTransmission();

delay(500);
}//loop


Y aquí va el código para el esclavo
#include 

int pinLedRojo = 2;
int pinLedVerde = 3;

int rojo = 1;
int verde = 2;
int azul = 3;
int nada = 4;

void setup() {
Wire.begin(4);
Wire.onReceive(receiveEvent);
Serial.begin(9600);
pinMode( pinLedRojo , OUTPUT );
pinMode( pinLedVerde , OUTPUT );
}

void loop(){}

void receiveEvent(int howMany) {
int recibo = Wire.receive();
Serial.print("Recibo : ");
Serial.println(recibo);
Serial.print("howMany : ");
Serial.println(howMany);

if( recibo == nada ){
digitalWrite( pinLedRojo , HIGH );
digitalWrite( pinLedVerde , HIGH );
}else if ( recibo == rojo ){
digitalWrite( pinLedRojo , HIGH );
digitalWrite( pinLedVerde , LOW );
}else if ( recibo == verde ){
digitalWrite( pinLedRojo , LOW );
digitalWrite( pinLedVerde , HIGH );
}else if ( recibo == azul ){
digitalWrite( pinLedRojo , LOW );
digitalWrite( pinLedVerde , LOW );
}
}//receiveEvent


Aquí hay una foto del montaje final.



Y aquí un pequeño video para los incrédulos.



Como se puede ver es bastante sencillo utilizar el i2c del Arduino. Por lo menos para comunicar dos Arduinos.

El paso siguiente será conectar un Lego(c) NXT con un Arduino usando i2c. De este modo podré usar un Arduino como sensor para el NXT.

jueves, 24 de marzo de 2011

Emisor Receptor RF con Arduino (III): Conclusiones

Los tutoriales que encontré por internet trataban el tema a tan bajo nivel que se me hacía imposible seguirlos. Esta librería te abstrae completamente de todo y sólo te tienes que preocupar practicamente de la función enviar mensaje y recibir mensaje. Te lo dan todo hecho. Aunque esto, para gente que le guste trastear más, pueda ser un inconveniente. Yo, sólo puedo decir cosas buenas de VirtualDrive para Arduino.

He probado el alcance, y a unos tres metros, que es lo máximo que me dan los cables usb, funciona igual de bien. No estoy usando antenas de ningún tipo. Debería buscar como alimentar al Arduino con una base de pilas. De este modo no estaría limitado al cable conectado al ordenador.

Lo siguiente que voy a intentar hacer en esta línea, es conectar el Arduino emisor al ordenador que leerá órdenes de un joystick, y un Arduino receptor al Lego(C) Mindstorms y tratar de manejarlo remotamente, al más puro estilo coche teledirigido.

Emisor Receptor RF con Arduino (II): Primer intento

He estado buscando por internet tutoriales sobre el tema y de todo lo que he encontrado, lo que más esperanzas me ha generado, ha sido VirtualWire para Arduino.

Como dicen los creadores, y yo traduzco, "VirtualWire es una librería para Arduino que permite enviar mensajes cortos, sin direccionamiento, retransmisión o confirmación, como un UDP inalámbrico, utilizando ASK"

VirtualWire is an Arduino library that provides features to send short messages, without
addressing, retransmit or acknowledgment, a bit like UDP over wireless, using ASK
(amplitude shift keying).


El enlace anterior apunta a un documento donde está explicada perfectamente toda la librería. Lo cierto es que la API que proporcionan es bastante limpia y parece sencilla. Así que manos a la obra.

Lo primero que vamos a programar es la parte emisora y el código que he escrito es el siguiente. Es realmente sencillo. Lee cada medio segundo el estado de los botones y lo envía.

#include 

int pinRojo = 2;
int pinVerde = 3;
// me he dado cuenta de que no hace falta
// configurarlo para salida o entrada
int pinTx = 4;

void setup(){
pinMode(pinRojo,INPUT);
pinMode(pinVerde,INPUT);

vw_set_tx_pin(pinTx);
vw_setup(2000);

Serial.begin(9600);
}//setup

void loop(){
delay(500);

int estadoRojo = digitalRead(pinRojo);
int estadoVerde = digitalRead(pinVerde);

char *mensaje = "VACIO";

if ( (estadoRojo == HIGH ) && (estadoVerde == HIGH) ){
mensaje = "A"; // rojo + verde = azul
}else if ( (estadoRojo == LOW) && (estadoVerde == LOW) ){
mensaje = "N"; // nada
}else if ( (estadoRojo == HIGH) && (estadoVerde == LOW) ){
mensaje = "R"; // rojo
}else if ( (estadoRojo == LOW) && (estadoVerde == HIGH) ){
mensaje = "V"; //verde
}

Serial.print("Enviado -> ");
Serial.println( mensaje );

vw_send( (uint8_t *) mensaje , strlen(mensaje) );
}//loop


Y aquí se puede ver el circuito que he montado para el emisor. Está hecho con Fritzing. Como no tenía un componente para el emisor, he dejado el cableado suelto y he añadido las patillas.



Y ahora, vamos a por la parte receptora. También sencilla, cada vez que recibe un mensaje, lo compara y enciende el LED correspondiente.

#include 

int pinRojo = 2;
int pinVerde = 3;
int pinRx = 4;

void setup(){
pinMode(pinRojo,OUTPUT);
pinMode(pinVerde,OUTPUT);

Serial.begin(9600);

vw_set_rx_pin(pinRx);
vw_setup(2000);
vw_rx_start();
}//setup

void loop(){
// esto es un poco engañoso porque sólo voy
// a recibir cosas de tamaño 0
uint8_t mensaje[VW_MAX_MESSAGE_LEN];
uint8_t longitud = VW_MAX_MESSAGE_LEN;

if (vw_get_message( mensaje , &longitud ) ){
Serial.print("Recibido -> ");
Serial.println( mensaje[0] );

if( mensaje[0] == 'A' ){
digitalWrite( pinRojo , HIGH );
digitalWrite( pinVerde , HIGH );
}else if( mensaje[0] == 'R' ){
digitalWrite( pinRojo , HIGH );
digitalWrite( pinVerde , LOW );
}else if( mensaje[0] == 'V' ){
digitalWrite( pinRojo , LOW );
digitalWrite( pinVerde , HIGH );
}else if( mensaje[0] == 'N' ){
digitalWrite( pinRojo , LOW );
digitalWrite( pinVerde , LOW );
}// if de caso de mensaje
}//if de he recibido un mensaje
}//loop


Y aquí se puede ver el circuito que he montado para el receptor. Está hecho con Fritzing. Como no tenía un componente para el receptor, he dejado el cableado suelto y he añadido las patillas.



Y me ha funcionado todo, más o menos a la primera, y no me lo creo todavía. He conseguido exactamente lo que pretendía en un principio. Aquí os dejo un video de esta maravilla funcionando.

Emisor Receptor RF con Arduino (I): Introducción

Durante un arrebato consumista estas navidades, hice un pedido a una tienda de electrónica de un montón de cachirulos. Una de las cosas que pedí, fueron un par de módulos emisor y receptor de radiofrecuencia.

Y como el pedido me vino muy bien, rápido y no tengo ninguna queja, os he enlazado los productos a la tienda.

Lo que pretendo conseguir es conectar un Arduino a un emisor, y otro Arduino al receptor, y tratar que se comuniquen entre si utilizando la magia de las ondas.

Aprovecho para contar, que en mi arrebato consumista navideño, cayó un Arduino Uno. Para que juege con el Arduino Duemilanove que ya tenía, que estaba muy sólo ultimamente.

¿Cómo voy a probar que mis dos Arduinos se llevan bien, y hablan entre si? El Arduino emisor leerá los valores de dos botones, y el Arduino receptor encenderá un par de leds según el botón pulsado.

lunes, 21 de febrero de 2011

Vehículos dirigidos (III): Resultados

Una vez que tenemos los valores de los sensores del mando en matlab lo único que queda es programación.

Aquí mi mayor problema ha sido que no he sido capaz de encontrar una explicación lógica a los valores que leía del mando, por lo que mi calibrado y mi código es un tanto artesanal.

Yo esperaba que dejando el mando en reposo, y moviendo sólo un eje, sólo obtendría valores distintos para ese valor. Nada más lejos de la realidad. Los valores que recibía del mando variaban todos.



Así que como ya he comentado el convertir los valores que leía en movimientos se ha hecho de manera artesanal.

Aquí os dejo dos vídeos, en el primero se maneja el vehículo con el joystick y en el segundo con el acelerómetro.




martes, 1 de febrero de 2011

Vehículos dirigidos (II): Conectando nunchuck + wiichuck + arduino + matlab

El objetivo es enviar los valores de los sensores del mando nunchuck al arduino.


Lo que aparentemente parecía muy fácil ya que hay cienes y cienes de tutoriales y librerías, no resultó tan fácil. Aquí os resumiré los pasos que he ido siguiendo y como conseguí que todo funcionara.

En primer lugar nos descargamos de aquí la librería nunchuck_funcs.h. Esta librería nos ofrece una interfaz muy sencilla para obtener los valores del mando.

// returns zbutton state: 1=pressed, 0=notpressed
static int nunchuck_zbutton()

// returns zbutton state: 1=pressed, 0=notpressed
static int nunchuck_cbutton()

// returns value of x-axis joystick
static int nunchuck_joyx()

// returns value of y-axis joystick
static int nunchuck_joyy()

// returns value of x-axis accelerometer
static int nunchuck_accelx()

// returns value of y-axis accelerometer
static int nunchuck_accely()

// returns value of z-axis accelerometer
static int nunchuck_accelz()


Quizás otro día explique como está construida esta librería por dentro e incluso que haga yo una, pero de momento me supera por todos lados.

Con esta interfaz tan sencilla, sólo nos queda escribir un pequeño código para arduino que recupere los valores.

#include
#include "nunchuck_funcs.h"

int loop_cnt=0;

int accx,accy,accz,zbut,cbut,jx,jy;

void setup(){
pinMode(10, OUTPUT); // LEYENDO INFORMACIÓN DEL MANDO
pinMode(11, OUTPUT); // ENVIANDO AL PUERTO SERIE
pinMode(12, OUTPUT); // ESPERANDO

digitalWrite(10,LOW);
digitalWrite(11,LOW);
digitalWrite(12,LOW);

Serial.begin(9600);
nunchuck_setpowerpins();
nunchuck_init();
}

/*
se queda iluminado durante x tiempo y sólo está a bajo nivel
cuando está recibiendo información
*/

void loop(){
digitalWrite(10,HIGH);

nunchuck_get_data();

accx = nunchuck_accelx();
accy = nunchuck_accely();
accz = nunchuck_accelz();

zbut = nunchuck_zbutton();
cbut = nunchuck_cbutton();

jx = nunchuck_joyx();
jy = nunchuck_joyy();

digitalWrite(10,LOW);

digitalWrite(11,HIGH);
Serial.print( accx );
Serial.print(" ");
Serial.print( accy );
Serial.print(" ");
Serial.print( accz );
Serial.print(" ");
Serial.print( zbut );
Serial.print(" ");
Serial.print( cbut );
Serial.print(" ");
Serial.print( jx );
Serial.print(" ");
Serial.println( jy );
Serial.flush();
digitalWrite(11,LOW);

digitalWrite(12,HIGH);
delay(250);
digitalWrite(12,LOW);

}//loop


El utilizar los pines con los leds, sólo tiene la función de depurar la aplicación. Como se puede ver lo único que se hace es leer los valores y escribirles separados al puerto serie. Para probarlo, podemos arrancar el monitor serie del entorno Arduino.


Se ve como si movemos el mando, pues los valores se van cambiando y así se recogen, separados por espacios.

Si queremos leer con matlab el valor de un puerto serie, hay que utilizar el siguiente código. Que nos deja los valores en un array llamado loQueRecibo. Habrá mejores y peores maneras, pero mis conocimientos de matlab, no dan para más

Cosas importantes, el nombre del puerto USB al que está conectado el arduino y la velocidad de conexión.

placa = serial( 'COM16' , 'BaudRate', 9600 );
fopen( placa );
loQueRecibo = fscanf( placa );
loQueRecibo = sscanf(loQueRecibo,'%d');


De este modo tenemos en el array loQueRecibo, los valores que se recogen del nunchuck y que se pueden ver en el pantallazo del monitor serie.

Vehículos dirigidos (I): Introducción

Hace mucho, mucho tiempo en una galaxia muy, muy ... ¡no!, espera, no era así. Pues eso, que hace mucho tiempo que no escribo nada en mi blog. Esto no quiere decir que haya estado sin hacer nada. He trasteado y mucho, pero no he obtenido los resultados que yo esperaba.

Para empezar jugué mucho con mi off-roader, le monté y desmonté e hice cajas y cajas de cambios, pero eso es otra historia. Y luego también hice muchas cosas con el arduino, y me compré un montón e componentes, pero eso es otra historia. La historia que os contaré hoy, trata sobre un nunchuck, un wiichuck, un arduino y un lego. Que si bien eran cada uno hijos de su padre y de su madre, hablaban usando un usb, bluetooth y un matlab.

Hay infinidad de videos en youtube que muestran coches manejados con mandos de la wii, o aparatos más extraños. En esta serie de entradas os voy a contar mis experiencias construyendo alguno de estos vehículos.

Espero que a alguien le sirva de ayuda. Empecemos.