Búsqueda personalizada

23 septiembre 2006

Version 1.1 control Linksys - Arduino

Mas proyectos en: http://eduardomarin.es/node/2


GUÍA: CONTROL ARDUINO - LINKSYS WRT45GL




En las siguientes líneas intento exponer con cierto detalle cómo conseguir una comunicación entre el router Linksys WRT45GL y la placa Arduino a través de una conexión sobre puerto serie, todo ello controlado desde un pc con conexión wifi sobre el router Linksys.

INTRODUCCIÓN

El propósito de la conexión entre estos dos dispositivos nos permite, en cierto modo, ampliar los límites tanto de la placa Arduino como del router Linksys. En combinación mútua, sus posiblidades abarcan, desde una relativa ampliación de memoria de Arduino, como una adquisición de datos de forma remota usando como puente el router Linksys. Podemos, así, mover brazos de robot (que portan webcams), hacer lecturas de diferentes tipos de sensores (temperatura, presión, movimiento), etc; todo ello a través de una red de conexión, ya sea local mediante ethernet o wifi, o a través de WLAN.
PARTICULARIZANDO...

Para mostrar la idea atrás esbozada, vamos a realizar el montaje para poder controlar hasta 12 leds, y llevar a cabo una lectura de un NTC (resistencia variable con la temperatura).
Implementaremos una interfaz gráfica, sobre HTML para hacerlo más intuitivo y atractivo.
La conexión con el router se basará en la comunicación sobre el puerto serie. Este aspecto requiere llevar a cabo una modificación física del router, pues no viene con dicho puerto implantado de fábrica, aunque sí su circuitería impresa.


COMPONENTES

Como decíamos, usaremos una placa Arduino, un router Linksys WRT45GL, una termorresistencia (NTC), dos conectores DB-9 (hembra y macho), un conector para cable plano de 10 pines con cable, y una resistencia de 330 ohm.



PROCESO








En primer lugar, instalaremos el puerto serie en el router.
Para ello, debemos abrir el aparato sin romperlo :-P . Desenrroscamos las antenas, ponemos el router boca abajo y empujamos hacia afuera, sobre las dos patas delanteras. En ese momento, el router pierde toda garantía, de lo cual, yo no me hago responsable :-)
Una vez abierto, debemos buscar dos puertos serigrafiados en la placa, fijándonos en el que tiene 10 perforaciones. Ese es el nuestro. Insertamos el conector de cable plano y soldamos con cuidado. En este momento es donde debemos identificar cada uno de los pines, para llevarlos al conector DB-9.









El router, al usar como sistema embebido Linux, en concreto ejecuta como intérprete de órdenes busybox, el cual mantiene las antiguas callout para comunicarse sobre el puerto serie. Más tarde estas salidas fueron sustituidas por las ttyS0 y ttyS1. No es nuestro caso. Así pues, cuando trabajemos con el puerto serie, debemos prestar atención a cua0 y cua1. Pero para ser más precisos, tan sólo nos fijaremos en cua1, pues, por algún motivo que no entiendo, el device cua0 no está operativo (is busy). Volviendo al puerto, debemos fijarnos en los pines 3, 5, 9 y 10, que son, tx, rx, gnd y gnd respectivamente (el puerto 1, 2, 4, y 6 son Vcc, Vcc, tx y rx de cua0, respectivamente).
Finalmente, y una vez hecha la identificación de los tres pines (gnd, tx, rx), soldamos, del cable plano, los tres cables al conector DB-9. La elección de los tres pines en el conector es a gusto de cada cual, pues no podremos usar ese conector para comunicarnos con un dispositivo corriente mediante puerto serie. Para ello deberíamos trabajar la señal para convertirla al estándar 232 (estamos trabajando en ttl).
Para fijar el conector, podemos realizar una apertura en la carcasa y así no tener que trastear demasiado con el router.










El siguiente paso sería comprobar que las conexiones las hemos realizado correctamente. Para ello, podemos hacer uso de Arduino, monitorizando lo que ocurre en el puerto serie. Así pues, conectamos al puerto serie y entramos mediante SSH (usando Putty por ejemplo) y lanzamos, o bien el entorno de desarrollo de Arduino, o bien un terminal para ver comunicación en COMx.

Desde la consola SSH, y una vez logeados en el router, probamos a enviar un cierto mensaje hacia Arduino. Ésto se lleva a cabo de la siguiente manera: la comunicación en Linux a través del puerto serie se lleva a cabo como una escritura en un fichero cualquiera, salvo que, en este caso, se trata del archivo de dispositivo localizado en /dev/cua/1. Así pues, si tecleamos echo Hola Mundo! > /dev/cua/1, el terminal del ordenador nos mostraría el mensaje por pantalla (siempre y cuando se encuentre a 9600 bps).

¿Cuál es el siguiente paso? El siguiente paso se va a dar sobre la programación de Arduino. Para ello debemos, en primer lugar, señalar la estructura de los diferentes módulos que van a componer la comunicación.
Por un lado, un código en Arduino se encargará de recibir datos codificados (made in yo) y generar las diferentes señales.
En el router, shell scripts (cgi) se encargarán de enviar y recibir datos y lanzar páginas HTML al navegador.
Por último, para hacer presentable la información, se crea la página Web que hará de interfaz al usuario.

Así pues, comencemos con el código en Arduino.

CÓDIGO EN ARDUINO


La idea es, básicamente, dejar la programación más compleja al router, que dispone de un sistema operativo empotrado, con más capacidad de memoria, y liberar a Arduino de esa carga, para, tan sólo, responder a códigos básicos que debe traducir, interpretar y generar las diferentes señales.


Así, podemos ver que tenemos 12 puertos digitales (0 y 1 reservadas para RX y TX), y 5 analógicas. Los digitales vamos a tomarlos sólo como salidas. De esta forma, cuando desde el router queramos activar una señal, sería lógico indicar, tanto que vamos a activar, como el número de puerto de que se trate. Con esta regla, podemos determinar que para activar un determinado puerto, debemos escribir echo H03 > /dev/cua/1. Es decir, para referirnos a la activación de un puerto usaremos "Hx", siendo x el número de puerto (3 <= x <= 13). De la misma forma, para desactivar o pasar a un estado Low "Lx". Finalmente, los puertos analógicos sólo serán de lectura, así pues, los nombraremos como "Ax" (0 <= x <= 5). El código debe leer iterativamente del puerto serie en busca de un byte "H", "L" ó "A", y, o bien activar o desactivar el puerto o bien leer el puerto. Todo ello se detalla en el siguiente código:
/* Adquisición de datos y control de salidas para 

linksys WRT45GL a través de puerto serie */



//Definimos las variables necesarias

int i,valor,valoraux,digito,pin;

byte dato,decenas,unidades;



void setup(){

for (i=2;i<=13;i++){
pinMode(i,OUTPUT);
}
Serial.begin(9600);
}

void loop(){
//A la hora de codificar cada una de las salidas digitales
//mediante el router, estableceremos como norma, codificar
//el estado HIGH para el pin 2 como: "H02". Y para un estado
//LOW: "L02". Para referirnos a las entradas analógicas, 
//lo indicaremos anteponiendo la A:  "A5".
//Dado que la comunicación serie, se lleva a cabo, como la 
//propia palabra indica, mediante secuencia de bytes, entonces
//tendremos que llevar un control de los "paquetes" de datos
//para identificar correctamente los 3 bytes de una codificacion
//del estilo "H02"

//Comprobamos si llega señal del router:
if (Serial.available()){
dato=Serial.read();
//En caso de que el primer byte sea una H o una L, nos 
//preparamos para decodificar el pin, leyendo, previamente
//el número de dicho pin. Para ello transformamos su nº
//a entero, restando al código ascii, 48
if (dato=='H' || dato=='L'){
//leemos primero las decenas, esperando en bucle hasta
//que se detecte el byte entrante.
while(! Serial.available()){
}
decenas=Serial.read();
//eco de comprobacion serialWrite(decenas);
pin=(decenas-48)*10;
//y después las unidades, para obtener el nº del pin
while(! Serial.available()){
}
unidades=Serial.read();
//eco de comprobacion serialWrite(unidades);
pin=pin+(unidades-48);
if(dato=='H'){
digitalWrite(pin,HIGH);
}
else{
digitalWrite(pin,LOW);
}
}
//En caso de que fuese A, entonces es un
//puerto analógico (por supuesto que todo esto debe
//controlarse desde el router), y necesitamos enviar
//los datos analógicos que pueda haber en dicho pin.
//Para ello codificamos el entero que nos devuelve una
//lectura de los 1024 posibles niveles, enviándolos como
//cadena de 4 dígitos.
if (dato=='A'){
//primero hacemos la lectura del pin en cuestión:
while(! Serial.available()){
}
dato=Serial.read();
//A continuación enviamos los datos byte a byte
//a través del puerto serie hacia el router.
//para ello debemos descomponer las unidades, decenas...
pin=dato-48;
delay(1000);
valor=analogRead(pin);
valoraux = valor;
digito = valoraux/1000;
serialWrite(digito+48);
valoraux = (valoraux - (digito * 1000));
digito = valoraux/100;
serialWrite(digito+48);
valoraux = (valoraux - (digito * 100));
digito = valoraux/10;
serialWrite(digito+48);
valoraux = (valoraux - (digito * 10));
digito = valoraux;
serialWrite(digito+48);
Serial.println();
}
}
}





CÓDIGO EN ROUTER

Cuando una página es accedida en internet, los servidores deben buscar información en sus bases de datos, y devolver las consultas oportunas. Se dice entonces que un código cgi (common gateway interface) está creando una página dinámica. El código cgi o lenguaje cgi puede implementarse mediante perl, javascript, ... En nuestro caso usaremos un shell script basado en comandos Unix.
Cuál será la organizacion? Pues bien, como yo no soy un gurú de Unix, y menos de HTML, me baso en ideas que creo que funcionarán (de hecho, podían funcionar mejor :-P ).
Es importante indicar que el código que se cree como interfaz cgi debe ir localizado en el directorio /www/cgi- bin/, que será, en cierta medida, la parte visible a la red (todo /www, de hecho). En ese directorio, crearemos el archivo shell script principal, el cuál creará la página HTML, y llevará a cabo la consulta de la entrada analógica 5 (del NTC).
Su código:

#!/bin/sh
../arduino/adquisitor &
VARIABLE=`cat nivel | cut -b 1,2,3,4`
AUX=`expr 870 - $VARIABLE`
TEMPERATURA=`expr $AUX / 5`
head -n 149 ../arduino/principal.html
echo "
MONITORIZACIÓN DE SENSOR DE TEMPERATURA:  $TEMPERATURA      º
tail -n 4 ../arduino/principal.html


Donde la segunda línea ejecuta otro shell script que es el que hace la llamada a través del puerto serie y lee los datos de Arduino. Las líneas 3, 4 y 5 hacen una conversión de los 1024 niveles analógicos recibidos de Arduino para "amoldarlos" a una presentación de temperatura en ºC. y finalmente se crea la página, ayudándonos de la impresión de un archivo HTML (principal.html) e inclyuendo, entre medias del archivo (fijarse que se imprime parte de principal.html y luego el final, mediante head y tail), la temperatura consultada. Este código se repite para cada uno de los botones que se crean. Es decir, al igual que existe el shell script principal, existe el H03, L04, H05, L05, ... cada uno activa su p uerto correspondiente, además de cargar la página HTML.

El código del script adquisitor es:

#!/bin
/sh
variable=0
echo A5 > /dev/cua/1
cat < /dev/cua/1 > nivel &
until test $variable -ge 300
do
variable=$(($variable + 1))
done
kill $$


En el cual, la tercera línea hace la consulta, como dijimos, mediante la codificación "A5" a través del puerto /cua/1 y se espera la respuesta, redirigiendo la entrada hacia un archivo auxiliar llamado "nivel". La lectura del puerto serie es un proceso que queda ejecutándose hasta que se mate. Por lo tanto, debemos, en primer lugar mandarlo a bacground (&) y finalmente asesinarlo :-) (kill $$). Un aspecto importante es que debemos esperar un cierto tiempo hasta que Arduino haga una lectura y retorne los datos. Para ello se hace uso de un bucle "tonto" (no se si habrá un comando tipo delay en ash).



Final me nte se g uarda la página web principal.html que es la que hace de presentación al usuario.

Debo destacar que hay muchos aspectos mejorables, pues hay algún problemilla con el control de procesos en bacground, con el código HTML, y con el acceso al router desde internet. Pero para una idea más o menos general, la creación de este montaje, creo que es acertada.






16 septiembre 2006

Gritando desde una biblioteca

Sólo faltan quince minutos para las diez de la noche y acabo de hacer un descanso.

Llevo toda la tarde en la biblioteca y como es sábado, y fin de exámenes, poca gente queda por aquí. Los compañeros de fatiga hoy no se han apuntado a la fiesta. Son inteligentes.
Yo desde este puesto de ordenador, grito en silencio.
Hoy si que se trata de un post de desahogo.
Si no hablo conmigo mismo, rebiento.
Más aún cuando tan sólo quedan dos días para el examen final. Cuando ves que se te amontonan las ideas. Cuando sabes que tienen que entrar más pero no hay tiempo.
Sólo queda confiar en la suerte, y en lo que has trabajado durante este último mes. Y esque el dicho "quien siembra recoge", o algo así, tiene su base, aunque en el tema de los exámenes puede quedar bajo la mano de un mal profesor :-(.
En fin, voy a ver si continúo mis quehaceres.

Ánimo a todos los que estáis de exámenes.

09 septiembre 2006

Conversación entre Arduino y Linksys

Mas proyectos en: http://eduardomarin.es/node/2

Al final Arduino y Linksys conversan.


La idea de este proyecto está, por un lado, en poder ampliar la limitada memoria de la que dispone Arduino, y, por otro, en poder acceder de forma remota a sus señales.
Para ello, necesitamos, como es lógico, la placa Arduino (en mi caso uso la versión USB), y un router Linksys WRT45GL, el cual está trabajando ahora mismo como punto de acceso libre a la red social FON.


Éste último necesita una pequeña modificación técnica, pues aunque viene de fábrica con la circuitería impresa para el puerto serie, éste no dispone del conector para cable plano. Por este motivo en primer lugar se lleva a cabo una identificación de los pines, y, una vez asegurados, empezamos a soldar el conector. Una vez soldado y montado el cable plano tan sólo nos queda establecer la conexión entre los dos.
















La idea de esta conexión se esboza en la siguiente imagen.

Por fortuna, gracias a que el router Linksys tiene un sistema embebido linux, podemos acceder a él de una forma muy flexible y potente. Ésto nos permite conectarnos en modo telnet desde un ordenador remoto, ya sea a través de su enlace wifi o a través de internet, si éste está conectado a la red (el router). Una vez conectados al router, podemos enviar datos a través del puerto serie hacia arduino, y, dependiendo de cómo hayamos programado éste, controlar todos aquellos dispositivos que nos podamos imaginar.
Es decir, la potencia de esta combinación es visible, tan sólo hay que echar imaginación, tiempo y ganas.

Veamos con más detalle en qué consiste este primer acceso remoto a arduino.


Vamos a controlar 10 deds conectados sobre las salidas digitales de la placa Arduino.
Para codificarlos, cada uno de ellos se encenderá o apagará según se envíe el dígito 0 - 9 desde el router. Es decir, a través del puerto serie, el router enviará el byte del carácter "0" y se iluminará o apagará el led nº 0, y así con todos los demás.
Ese caracter enviado, realmente se envía en primer lugar vía wifi desde el ordenador hasta el router, haciendo uso de la escritura sobre el fichero asociado al puerto serie.



Así, si mediante telnet escribimos: echo 0489 > /dev/cua/1 se iluminarán simultáneamente los leds 0, 4, 8, y 9; siendo el fichero /dev/cua/1 el equivalente al puerto serie COM2 del router (en otros modelos se identifican por ttyS0 y ttyS1). Cabe destacar que el proceso inverso, esto es, leer datos desde arduino, sería equivalente. Si Arduino envía datos al router (pongamos por ejemplo que hace lecturas periódicas de temperaturas, presion, etc), Linksys tan sólo tendría que adquirir estos datos viendo el contenido del archivo 1 (cat /dev/cua/1), e interpretarlo convenientemente.











Puede verse el resultado en el siguiente vídeo:




No hay que olvidar pasarse por cualquiera de estas direcciones, que contienen toda la información sobre Arduino y sobre FON.