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.






23 comentarios:

brainfart dijo...

Very nice, very interesting. Unfortunately I don't understand Spanish, but as far as I can see you are controlling the Arduino board via WLAN through a modified Linksys router. I like this a lot! So many possibilities!
Is this blog entry available in English, too?

KayaK dijo...

I'm sorry, but my english is bad bad... :-(, but if you have any question of this, I tell?? you.

JP dijo...

Hola soy Juan Pablo de Argentina, muy interesante el Blog. Te cuento que estoy tratando de hacer algo muuuy parecido a lo que hiciste vos, con ardiuno y un router linksys v2.0 Me gustaria ponerme en contacto con vos y contarte mi idea. Saludos
mi correo: juanpablocapilla@gmail.com

Anónimo dijo...

muy buenas,
estoy consultando este post junto con el publicado en http://ahorcandoeltiempo.blogspot.com/2006/10/versin-10-display-en-router-linksys.html
pero parece que las imagenes están "desaparecidas" (por si lo puedes actualizar :S)

Por cierto, estoy buscando info sobre arduino, y beo pcbs y tal...
...pero no veo donde conseguirlo "tal cual" ¿tu te lo hiciste o lo pillaste por otro lado?

kayak dijo...

Vaya... pues sí, se han caído las imágenes, en cuanto pueda las vuelvo a subir.

En cuanto a dónde adquirí yo la placa fue a través de internet, en esta página.

Un saludo!

Piniflopa dijo...

Encuentro genial esta manera de cacharrear. En estos momentos yo estoy intentando hacer que se entiendan el router con un PIC16F84A. Lo que no tengo tan claro es si la configuración en el router será la misma que la que tu usaste.... en fin iremos trasteando.

kayak dijo...

Claro Piniflopa, en mi caso, para arduino, más o menos usé esa solución porque era lo que me vino a la cabeza, y eso es lo bueno de esto, que las posibilidades son muy grandes. Seguro que tú con el PIC consigues buenos resultados.

Un saludo!

Luis dijo...

Muy buen blog, oye una pregunta tengo una aplicacion Win32 con la que quiero controlar directamente el Arduino , sabes si esto es posible ?

kayak dijo...

Buenas Luis,

Te refieres a una aplicación que controle todos los pines (analógicas o digitales) como si de una interfaz gráfica se tratara?

Esto es posible si utilizas el puerto serie de arduino y en tu aplicación envías órdenes a través del puerto serie.

No sé si es eso a lo que te refieres.

un saludo!

Luis dijo...

Gracias por tu respuesta, mira te platico , compre el mote que viene en la siguiente pagina http://www.libelium.com/squidbee/index.php?title=Main_Page , ya que trae los sensores incluidos y necesito, en mi aplicacion Win32 leo el puerto serie y me trae los siguientes valores @5|397|data0-354|data1-376|data2-50#, donde segun yo los valores son los siguientes |data0-354 Luminosidad
|data1-376 Humedad
|data2-50 Temperatura. Entonces segun yo para que te de las lecturas reales tendrias que hacer una formula, la cual no se como sea, no se si tu tienes alguna idea.

kayak dijo...

Luis, buenas de nuevo,

mándame, si no te importa, tu e-mail, (luego te borro el post pa proteger tu identidad XD), y así puedo ayudarte mejor.

He estado mirando la página de squidbee, y creo que no hay problemas.

Luis dijo...
Este comentario ha sido eliminado por un administrador del blog.
Anónimo dijo...

Podrías subir el código fuente tanto de los cgi como del interfaz web??

Gracias de antemano!!

kayak dijo...

Sí, en cuanto tenga un ratillo lo subo.

Un saludo!

Anónimo dijo...

muy buenas,

acabo de leer tu post y creo que me puede valer para lo que busco, pero tengo una consulta.

Primero te explico lo que intento:
tengo el arduino programado para que al mandarle una letra ("O" por ejemplo), mande 5V a un relé y encienda... y al mandarle otra letra ("C"), pues apague el relé.

Mi idea era poner el puerto serie al wrt54gl, pero he hecho un par de intentos y no consigo salir de los caracteres raros (lo he hecho siguiendo los esquemas del wiki de dd-wrt, intentado utilizar el de 3V de la fonera... pero nada).

He visto que tu lo conectas "a pelo", el rx y tx al arduino directamente... pero...
¿los conectas al db9 del arduino (pines 2 y 3) a modo de nullmodem (rx a tx y viceversa)?

¿o es que tienes el rx conectado a una entrada del arduino y cuando ve un pico de tensión arranca?

Si es "a pelo" -que es como me valdría para meter diferentes órdenes- entonces ¿ni masa ni vcc no? vamos, que alimentar al arduino y listo (aunque ya puestos, a lo mejor saco la alimentación del router :D).


gracias

LOCUS2004 dijo...

Hola amigo te felicito por lo que has logrado hacer, mira yo tengo que hacer un proyecto para la universidad, tengo que enviar un dato al pic de forma inalambrica, con este dato controlo el pwm del pic y realizo el control de un motor dc, x fa ayúdame como seria la forma de hacerlo, tengo conocimientos de electrónica, tengo el router, el pic pero no se como programar html, mi correo electrónico es yambay@ecuacontrol.com

GDARIO dijo...

Kayak. muy bueno tu articulo. oye actualmente quiero hacer un proyecto en el que monitorize la temperatura y la humedad de un recinto con Arduino y Xbee.. has hecho algo parecido ? gracias.

iapdm dijo...

Hola Kayak, muy buen post!!. Te comento lo que estoy haciendo, tal vez me puedas ayudar. Le he agregado al router una placa convertidora TTL 3.3v <> RS232 para agregarle dos puertos serie (esto funciona). Por otro lado he fabricado un pluviometro "digital" con un reed swicht y un velocimetro de bicicleta para hacer las lecturas de los mm de lluvia. Lo que pretendo ahora es conectar el pluviometro al router para ver los mm de lluvia en una pagina web (tengo instalado un servidor web en el router). Explicado esto, te pregunto como podria hacerlo?? tb me interesaria agregarle algun otro sensor como de temp, o un anemometro, etc. Quiero ver como llevar la info de varios sensores (digetales o analog) al router. Te dejo para que veas la pagina donde explico como hice el pluviometro y el convertidor TTL 3.3v <> RS232. http://altroque.sytes.net:8008/ Me gustaria que estremos en contacto y me des una mano, Saludos.

Witchking dijo...

Hola!! excelentes aporte!! te felicito por la claridad de lo expuesto.
Tengo una duda que quizas me puedas ajudar, es posible conectar por medio del router a un pocket pc (pda con windows mobile),que reciba y envie informacion al arduino. Ando buscando pero ando medio perdido.

Salu2

Fabien dijo...

EXELENTE TUTO QUE BUENO QUE ALGUIEN COMO TU LE DEDIQUE EL TIEMPO A COMPARTIR TAN VALIOSA INFORMACION ESTABA BUSCANDO ALGO ASI DESDE HACE TIEMPO VOY A HACER USO DE TU TUTO CON TU PERMISO....

Omnimusha dijo...

Hola, muy buen trabajo. quisiera q me aclarara unas dudas.

1)La comunicacion es a "punto a punto " o comun, es decir,a traves del ruter se conectan las pc. o ambas?
2)los cables a conectar son los 3, 5, 9 ò 10,tx, rx, gnd y gnd respectivamente
3)La programacion, se puede efectuar atraves de compilador del arduino?, basicamente la programacion es la misma q se biene
haciendo?, es decir la codificacion.
4)se puede colocar una wedcam Ethernet, y q envie a la pc?

nenexulo22 dijo...

hola buenas queria preguntarte una pequeña duda por que gracias a ti estoi intentando adaptarlo a un rooter wifi pero el wrt120n que tb es de linksys peor no es ni parecido y tb tiene 10 puntos donde soldar los cables que necesitamos pero hay otros 12 puntos en otro sitio y nose si voi a soldar en los correctos me gustaria hablar contigo te dejo mi mail aver si puedes enviarme un mesaje y hablamos. un saludo y gracias por tu colaboracion

Omnimusha dijo...

buenas, me preguntaba si podria usar un Router Linksys Wrt54g v6, para reproducir sus proyectos ?.
desde ya muchas gracias