Me había prometido que este 2013 iba a escribir una entrada mínimo cada mes. Está ya bien entrado el año y de momento sólo hay una. Hoy voy a intentar ponerle remedio presentando un juguete nuevo que tengo desde hace poco más de un año y que entre pitos y flautas, no he podido exprimir todo lo que me gustaría. Estoy hablando de la RaspberryPi.
Hablar de la RaspberryPi daría para muchos blogs. Yo me voy a centrar hoy en hacer una pequeña prueba de lo que es capaz su GPIO (General Purpose Input/Output), http://elinux.org/RPi_Low-level_peripherals.
Resumiendo mucho y salvando las distancias, son 26 pines digitales para conectar cualquier cosa que nos interese. Algo parecido a un Arduino, repito, salvando las distancias. Es muy importante recalcar que son digitales, cosa que me acabo de dar cuenta, así que todos mis planes para conectar algo analógico, de momento, quedan relegados a un segundo plano.
Hoy os voy a contar mis aventuras y desventuras intentando conectar un acelerómetro de tres ejes al arduino.
El acelerómetro en cuestión es este.
Conectarlo al Arduino Uno, es muy sencillo. Lo que más me ha costado ha sido la soldadura de los pines, pero todo mejora con la práctica. Lo podéis ver en el siguiente esquema de Fritzing.
A continuación va el sketch que he escrito para el Arduino Uno. Como hago habitualmente, recojo los valores de la salida X,Y,Z y la envío por el puerto serie.
int pinX = A0; // a este pin analógico va conectada la patilla X
int pinY = A1; // a este pin analógico va conectada la patilla Y
int pinZ = A2; // a este pin analógico va conectada la patilla Z
int valorX = 0; // de aquí leo el valor de la patilla X
int valorY = 0; // de aquí leo el valor de la patilla Y
int valorZ = 0; // de aquí leo el valor de la patilla Z
void setup(){
// configuro las patillas como entrada
pinMode(pinX,INPUT);
pinMode(pinY,INPUT);
pinMode(pinZ,INPUT);
//configuro la velocidad de escritura del puerto serie
Serial.begin(9600);
}//setup
void loop(){
delay(100); // pongo un pequeño retraso
// leo los valores
valorX = analogRead( pinX );
valorY = analogRead( pinY );
valorZ = analogRead( pinZ );
// los escribo al puerto serie de la forma -> por ejemplo -> // 123 123 123
Serial.print( valorX );
Serial.print(" ");
Serial.print( valorY );
Serial.print(" ");
Serial.print( valorZ );
Serial.print(" ");
Serial.println();
Serial.flush();
}//loop
La salida del puerto serie es la siguiente tras hacer algunos giros.
Como la salida no es muy espectacular, voy a aprovechar la salida por el puerto serie para mostar unas gráficas con Matlab. La salida es la siguiente.
Cuando la gráfica está en reposo el sensor no registra aceleración.
En este video de bastante mala calidad todo sea dicho, se puede ver el sensor en movimiento. Sólo me centro en el eje X
Si el "mando" queda quieto, la gráfica es una constante. Si giramos hacia un lado vemos que crece o decrece según el sentido del giro.
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.
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.
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.
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;
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.
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;
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.
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( 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.