Ictiometro digital de bajo coste con Arduino y Python (2)

En el anterior capítulo de esta saga os describía cómo comenzaron a surgir algunas ideas para construir un ictiometro digital y cómo decidí comenzar la andadura explorando las posibilidades de los ADC (Conversores analógico-digital). EN este os hablaré de cómo y porqué deseché esa idea y cómo Arduino entró en mi vida

El problema de los ADC y el ictiometro digital

Un conversor analógico digital convierte una señal analógica en otra digita. Para os hagáis una idea de cómo funciona voy a intentar explicarlo: Supongamos que queremos medir la fuerza con que lanzamos una pelota hacia arriba. Cogemos unos tableros y unos tornillos y construimos una estantería con muchas repisas y muy alta, y lanzamos la pelota hacia arriba y vemos en qué repisa ha quedado la pelota, lo que nos dará una idea de la fuerza con la que la hemos lanzado. Naturalmente, la estantería debe ser lo suficientemente alta como para poder registrar cualquier lanzamiento y que ninguno  se vaya al patio del vecino.

Ahora bien, una misma estantería (pongamos la serie Billy de IKEA) puede tener diferentes números de baldas, y es aquí donde la cosa se nos complica.

Imagina que tu estantería tiene sólo 1 balda (en realidad son dos, la repisa intermedia y la inferior del cuerpo de la estantería). Nuestras “lecturas” de la fuerza con la que lanzamos la pelota sólo pueden tener dos valores (digamos “fuerte” y “flojo”), dependiendo si caen en la balda inferior o la superior. Esto no es muy revelador que digamos.

Si queremos aumentar la “resolución” de nuestra estantería-mide-fuerza sólo tenemos que añadir más baldas, de manera que cuando lancemos la pelota tenga más huecos donde colarse. Así, con cuatro huecos la pelota la habríamos lanzado flojo,medio-flojo,medio-fuerte y fuerte, por ejemplo… poniendo muchas más baldas podremos conseguir resoluciones mayores (a mayor coste, claro, necesitamos más madera), pero… ¿hasta cuándo? Pues hasta que el tamaño del hueco sea menor que la pelota. Entonces la pelota no cabe en ningún hueco y  no es posible registrar la fuerza del lanzamiento.

De la misma manera, los ADC se construyen con una resolución  determinada, que se mide en bits y expresa la cantidad de “baldas” que tiene nuestro ADC. Así, un ADC de 8 bits nos ofrece [latex]8^2=256 pasos[/latex], uno de 10 bits [latex]2^{10}=1024 pasos[/latex] y así sucesivamente. Un mayor número de bits significa más resolución pero también más dinerito. Por otro lado, los ADC tienen un rango de voltaje de trabajo determinado y suelen incluir una entrada para un valor de referencia y un offset. Los dos últimos parámetros no son, en estos momentos, importantes, pero sí el rango de voltaje.

El rango determina el valor máximo y mínimo que es capaz de detectar y convertir nuestro ADC. Es como la altura de la estantería, lo que pase o no llegue no lo medirá. Entonces, suponiendo que nuestro ADC sea de 8 bits tendremos 256 pasos y la diferencia de voltaje entre cada paso (la resolución) será de [latex]\frac{5V}{256 pasos}=0,0195312 V o 19 mV[/latex]. Si empleamos un ADC de 10 bits, será de [latex]\frac{5V}{1024 pasos}=0,0048828125 V o 4.8 mV[/latex]. Ahora bien, nosotros podremos juntar varios de estos pasos, ya que no tenemos por qué aprovechar el ADC al máximo.

Si lo que queremos es, como decíamos al principio, usar botones para marcar clases de talla, no tenemos que apurar tanto. En este caso, y suponiendo un ictiometro digital para pequeños pelágicos (25 cm de longitud), con clases de talla de 0,5 cm, tendríamos que emplear 50 botones (bueno, alguno más para borrar y otras funciones, pero simplifiquemos). Por lo tanto, nuestros escalones serían de [latex]\frac{5V}{50 escalones}=0.1V=100 mV[/latex] Eso quiere decir que tendremos que elaborar nuestra escalera de resistencias a la que vamos a conectar los botones de nuestro ictiometro digital de manera que la diferencia de voltaje entre botones no sea mayor que esos 100 mV.

Un ictiometro digital de mayor longitud necesitaría más botones, más escalones y por tanto ajustes más finos de las resistencias. Y este és el problema. Según la fórmula del divisor de tensión [latex]V_out=\frac{R_2}{R_1+R_2}\dot V_in[/latex], al variar la resistencia en el numerador (la que, digamos, genera el voltaje de salida que medimos) también varía la resistencia en el denominador (la resistencia hacia tierra), de manera que el comportamiento del divisor de tensión no es lineal. Por lo tanto, primer escollo: No podemos usar un único valor de resistencia para todos los botones y además este valor no es el mismo si el ictiometro digital es de 25 cm que de 26 ni de 30 o 60. He extraviado los cálculos que hice en su momento pero las conclusiónes que saqué fue que era preciso emplear resistencias de precisión (Tolerancia 1%)  y que el sistema era muy original (hasta cierto punto, como comentaré luego) pero  no era práctico. Entre otras cosas porque cada “modelo” de ictiometro digital necesita un juego diferente de resistencias.

Googleando descubrí que la idea no era ni mucho menos original, pues este sistema de botones y divisor de tensión fue inventado a principios de los 80 si no recuerdo mal y profusamente usado en aparatos electrónicos que precisaran de una botonera con un pequeño número de botones, como por ejemplo en cadenas musicales. Y además, que adolecía de un buen número de inconvenientes, como las pequeñas variaciones en resistencia que aparecían con el tiempo a causa del uso, del polvo entre los contactos de los pulsadores…

Y estaba el tema de la conexión del icitiometro digital con el ordenador. Mi primera idea era aprovechar la salida de 8 bits del ADC para “enchufarla” directamente al puerto paralelo y leerla desde allí. La idea no era mala, pues a priori es mucho más sencillo inyectar el valor correspondiente a la tecla pulsada en el puerto paralelo usando los 8 bits disponibles en el mismo que mediante comunicación serie. Daos cuenta que mi idea era ensamblar yo mismo la circuitería partiendo de componentes discretos y circuitos integrados. Una vez que el puerto paralelo recibía el valor, se leía via software y se actuaba en consecuencia.

Pero, ¡ay!, las cosas no son ni de lejísimos tan sencillas. Lo primero es que hay que garantizar que no vamos a freír nuestra computadora al meterle voltajes inadecuados. No es un problema, pero obliga a pensar en aislar de alguna manera el ictiometro digital del computador (optoacopladores, pensaba yo, pueden ser la solución). Por otro lado, los cable paralelo son voluminosos y no permiten grandes longitudes. Y por otro, por no mencionar más, una cosa es querer poner un valor en el puerto paralelo… y otra conseguirlo, pues nos enfrentamos, aún teniendo conocimientos de electrónica suficientes como para elaborar correctamente el circuito (de los que yo, como os he comentado, carezco para mi desgracia) entre otras cosas al bouncing.

El bouncing es un fenómeno producido al pulsar una tecla y consistente en que lo que nosotros percibimos como un abrir y cerrar de un interruptor, a pequeña escala en lugar de un bonito escalón representando el 0 y el 1, tenemos una señal con un montón de oscilaciones debidas a las imperfecciones en el diseño del interruptor y pequeños arcos eléctricos… que lo que generan es una señal impura a la que tenemos que hacer algo para que se interprete correctamente. Las técnicas empleadas para eliminar este efecto se denominan debouncing y la más habitual consiste en obviar todas las señales ‘on’ que lleguen una vez que se ha detectado una primera señal ‘on’ durante un tiempo determinado, generalmente de unos milisegundos. La elección del tiempo es clave: poco tiempo no elimina el debouncing y demasiado provoca que nuestro teclado nos ofrezca una respuesta lenta o que haya pulsaciones que se pierdan. Habitualmente, viene a ser de entre 10 y 40 milisegundos.

Bueno, pues yo tenía la intención de hacer todo eso vía hardware a partir de componentes discretos y algún integrado. Pues iba a ser que no. Al final, de toda esta primera fase sólo puedo deciros que la primera víctima de mi proyecto fue mi breadboard que sufrió un calentón de narices. La segunda, un optoacoplador que saltó por los airesy un ADC de siete euros quemado de todas, todas. Y la tercera, el proyecto de ictiometro digital entero, tal y como lo había concebido.

Y entoces apareció Arduino.

Haría falta (bueno, en realidad hace falta) algo más que un blog para explicar qué es y qué se puede hacer con Arduino. Para abreviar y para aquellos que no lo conocéis, Arduino es una placa open hardware de prototipado rápido. O, dicho de otra manera: una plataforma electrónica que te permite experimentar con libertad y facilidad montajes electrónicos que pueden llegar a ser muy sofisticados. La placa Arduino no se entendería sin el software Arduino, una implementación del lenguaje Processing que permite la programación de la placa para que haga lo que nosotros queramos.

Simplificando, lo que nos ofrece Arduino es un cierto número de pines con los que podemos entradas y salidas  por las que podemos meter y sacar señales digitales y analógicas y procesarlas com corresponda. Los programas se programan mediante el IDE Arduino y se cargan en la placa mendiante un cargador que facilita el IDE.

Hay multitud de versiones, dependiendo entre otras cosas del procesador, memoria y número de pines de entrada/salida de que dispongan. Existe la versión LillyPad, una placa flexible que nos permite incluso incorporar un proyecto arduino a prendas de vestir. Su concepción es modular. Existen multitud de shields, más o menos estándar, que  son circuitos adicionales que se acoplan a través de los pines de la placa sobre ésta, aportando nuevas funcionalidades a la placa, como por ejemplo conexion a redes (tanto cabeada como wifi), bluetooth, módulos gps, de radio frecuencia (especialmente interesante parece toda la gama de dispositivos inalámbricos X-Bee), control de motores, etc.

Una de las diferencias que presentan las placas Arduino es el número de pines de entrada y salida que presentan, lo que va a ser clave para nuestro ictiometro digital.

En cuanto al software, y  aquí es donde realmente mi proyecto recibió un impulso gigante, existe una gran comunidad de usuarios de Arduino que pone a disposición del público librerías para ser usadas con el software Arduino. Estas librerías  abarcan multitud de tareas, desde controlar displays LED hasta establecer comunicaciones con otros dispositivos. Y mira tú por donde, hay una librería dedicada a controlar teclados. Es lo ideal para poder gestionar las pulsaciones de nuestro ictiometro digital.

En mi próximo post os hablaré de cómo, finalmente, di forma a este proyecto. ¡¡Mientras tanto, espero que os pique la curiosidad y me sigáis leyendo!!!

PostGIS, PostgreSQL y triggers: Georreferenciar es fácil

Los triggers o disparadores de PostgreSQL  son una de sus funcionalidades más tractivas.Ante una determinada operación (INSERT, UPDATE O DELETE) provocan la ejecución de una función en nuestra base de datos. Si esto lo usamos en conjunción con PostGIS, nos permite tener tablas en las que el manejo de datos espaciales sea sencillo. La documentación sobre los triggers es prolija y yo, sobre todo por falta de conocimiento profundo, no quisiera extenderme demasiado e ir al grano.

¿Y para qué quiero Postgis, PostgreSQL y los triggers?

A menudo, en nuestro trabajo, tenemos que elaborar mapas y por lo tanto precisamos de herramientas que nos permitan posicionar correctamente nuestra información. O nos puede interesar establecer relaciones entre nuestros datos teniendo en cuenta su distribución o posición geográfica. Estas herramientas no tienen que ser necesariamente Sistemas de Información Geográfica. Hay personas que elaboran mapas de primera con herramientas no necesariamente pensadas para esto (por ejemplo, con Excel). En todo caso, tendremos que proporcionar de una manera u otra nuestros datos a la aplicación que empleemos.

Para ese fin algunos Sistemas de Gestión de Bases de Datos proporcionan, de alguna manera, soporte para almacenar y manipular datos espaciales. En el caso de PostgreSQL esta funcionalidad se logra mediante la extensión PostGIS, que no hace sino incorporar a nuestra base de datos un conjunto de funciones, tablas y tipos de datos que nos permitirán almacenar y manipular datos espaciales. La instalación de PostGIS es bastante sencilla, aunque no tanto la actualización de las bases de datos que incorporen PostGIS, pero eso será materia de otro post. Otras bases de datos cuentan con funcionalidades similares (OracleSpatial, SpatiaLite) pero yo me centraré en PostgreSQL + PostGIS porque es la que uso y más o menos entiendo y porque quizá es el Sistema de Gestión de Bases de Datos que más se  entiende con el software SIG disponible y sobre todo, con QuantumGIS que es software GIS que yo utilizo.

Una ventaja adicional de emplear un sistema tipo PostgreSQL + PostGIS es que no es necesario el uso de software GIS para realizar algunas tareas en las que estos softwares osn de aplicación. Así, por ejemplo, es posible consultar si un elemento espacial está dentro de otro, o qué otros elementos gráficos están contenidos en uno determinado. Una aplicación de esto último puede ser, por ejemplo, obtener los lances de pesca ubicados dentro de un determinado lugar de una cuadrícula, o en una determinada zona delimitada por unas coordenadas o, utilizando las funciones de creación de buffers espaciales, conocer qué CTD se han efectuado a una distancia determinada de un punto dado, etc. En otras palabras, nos permiten prescindir, hasta cierto punto, de un software dedicado para realizar las consultas espaciales.

Ahora bien, existe un problema y es que que PostgreSQL + PostGIS no almacenan la información espacial de una manera directamente interpretable por el usuario, como unos valores numéricos de latitud y longitud, por ejemplo, ni los programas leen la información de bases de datos PostGIS de esa manera, sino que para ello utilizan un formato descrito por el Open Geospatial Consortium denominado WKB (Well-Known Binary) que es el formato en el que las bases de datos almacenan la información espacial.

El WKB tiene un hermano mellizo que es el WKT (Well-Known Text) que es la representación digamos… humanamente entendible del objeto que almacenamos como WKB. He hecho mención al objeto porque hay diferentes tipos de objetos espaciales. Los más habituales y que en los que pensaremos inmediatamente son el punto y la línea… pero tenemos también multilíneas, polígonos, multipolígonos, multipuntos… y cada uno de ellos con su SRID o sistema de coordenadas asociado. Por eso, una tabla que almacene un objeto de tipo punto no tiene una columna para latitud y otra para longitud, sino que tiene una única columna que almacena el objeto. Para almacenarlo, PostGIS proporciona unas funciones que permiten la creación de los objetos a partir de sus coordenadas, tipo de objeto, SRID, etc.

Pero es probable que a nosotros nos interese recuperar sin mayor problema las coordenadas numéricas de nuestros puntos o líneas o, simplemente, que podamos interactuar con mayor facilidad con nuestra base de datos. Es más fácil introducir los datos numéricamente, tal y como los podemos tomar en el barco que teniéndonos que acordar cada vez de pasar la función con los parámetros adecuados.Y nos puede interesar, para facilitar luego medidas de distancia, etc o la representación de los lances en un mapa, disponer de nuestro lance como un objeto de tipo línea en lugar de de puntos separados. Y aquí es donde aparecen los triggers.

¿Qué queremos hacer con el trigger?

Lo que queremos hacer es sencillo. Simplemente, que cuando demos de alta un registro o cambiemos sus coordenadas el objeto espacial correspondiente almacenado en la base de datos se cree o se actualice convenientemente.

Lo que ocurre es que esto requiere de unos pasos previos. Lo primero que tenemos que hacer es tener una tabla con columnas espaciales del tipo de dato que nos convenga. En el ejemplo que os describo, voy a suponer que queremos disponer de una tabla donde almacenamos los lances de pesca de una campaña. Esta tabla constará de un nombre de campaña, un número de lance, una posición de largado, otra de firmes, otra de virado y otra de arte a bordo. Además, queremos almacenar, por las razones que hemos comentado antes, una línea que una los puntos de firme y virado.

Creando la tabla en PostgreSQL

Para trabajar con datos espaciales en PostgreSQL + PostGIS no es posible crear mediante una sola sentencia CREATE TABLE la tabla con soporte espacial. Es preciso hacerlo en dos fases, primero creando la tabla normal sin las columnas espaciales y posteriormente añadiéndoles éstas mediante una función de PostGIS llamada (muy original no es, pero sí práctico y lógico, como debe ser)  AddGeometryColumn(),

La creación de la tabla es trivial, ahora bien… hemos de tener en cuenta que necesitaremos, para cada uno de los puntos involucrados en la creación de nuestro objeto espacial (uno si es un punto, dos si es una línea…) , dos columnas; una almacenará la longitud y la otra la latitud.

Añadiendo las columnas espaciales

Ahora tendremos que hacer uso de las funciones que PostGIS pone a nuestra disposición para dotar a una tabla de capacidades de almacenamiento de datos espaciales.

Esta función se llama AddGeometryColumn y su sintaxis es:

Donde:

  • tabla es el nombre de la tabla a la que vamos a añadir la columna,
  • columna es el nombre de la columna a añadir,
  • srid es el sistema de referecia de coordenadas del elemento que vamos a añadir. Para los que usamos el sistema WGS84 (que es el SRID de las coordenadas que proporcionan los GPS habitualmente, o al menos las sentencias NMEA a las que tenemos acceso), este valor es 4326. Para otros SRID es buena idea buscar en www.spatialreference.org.
  • tipo es el tipo de elemento a insertar (linea, punto…)
  • dimension es el numero de dimensiones del mismo (en nuestro caso, 2)

Con esto y un poquito de ganas, creamos nuestras columnas para los puntos y la línea:

Ahora ya viene la parte más delicada y es la creación del trigger.

Creando el trigger en PostgreSQL

La creación del trigger es un proceso que se realiza en dos fases. Puedes obtener información detallada sobre triggers y funciones en las páginas de documentación de PostgreSQL sobre programación del servidor.

En la primera, programaremos la función que dará, valga la redundancia, funcionalidad a nuestro trigger. Las funciones para los trigger son especiales, en tanto en cuanto no tienen valor de retorno, sino que devuelven un objeto de tipo trigger. Lo que hará nuestra función es tomar cada uno de los pares de coordenadas que introdujimos en nuestra tabla (un par por cada uno de los puntos que vamos a almacenar) y construir un dato geométrico que almacenará en la columna correspondiente. Además, una vez construidos los puntos, creará un objeto de tipo línea que almacenará la línea del lance de pesca.

En la segunda fase, asociaremos ese trigger a nuestra tabla en la base de datos. Esta es, al menos léxicamente, la verdadera creación del trigger.

El código para crear la función es el siguiente:

Aparte de las líneas que crean formalmente la sentencia, las que nos interesa conocer cómo funcionan son las del tipo

Básicamente, lo que le decimos a nuestro servidor es que cuando al ejecutar el trigger se le pase a la función que vamos a crear el registro que se inserta o actualiza, el NUEVO valor de la columna XXX_punto será el resultado de:

  • Crear un punto mediante la función ST_MakePoint() de PostGIS.
  • Asignar un SRID a ese punto, en nuestro caso el 4326 (WGS84)

Fijaos en lo de NEW, porque volveremos sobre ello más adelante.

Una vez creado los puntos y aprovechando que éstos tienen ya asignado su SRID, mediante la sentencia

Creamos la línea que unirá los puntos de largado y virada.

Ahora, lo que hace el resto de la función

es retornar el registro NUEVO , indicar que la función termina y cerrar la declaración de la función.

Ahora, como dijimos antes, viene la segunda fase y es la declaración del trigger. Esto lo hacemos mediante las siguientes sentencias:

¿ Os acordáis de lo que os dije antes acerca de los registros NUEVOS? Pues bien, si os fijáis en la parte de BEFORE INSERT OR UPDATE IN lances , lo que decimos aquí es que antes de que se inserte o actualice el nuevo registro ejecute la función que hemos creado sobre cada tupla que se inserte. Por tanto, las variables sobre las que operamos son las columnas de cada tupla, y nos referimos a ellas con NEW.nombre_de_columna, con lo cual, para que quede insertada correctamente la columna de geometría nos referimos a ella en la función como NEW igualmente.

Ahora ya tenemos nuestra tabla lances habilitada para los datos espaciales y, lo que es mejor aún, podemos introducir las coordenadas de los mismos sin necesidad de emplear funciones de PostGIS en cada una de nuestras consultas de inserción o actualización de datos.

¡¡¡Espero que el artículo os sea de utilidad!!!

 

Ictiometro digital de bajo coste con Arduino y Python (1)

Voy a comenzar una serie sobre cómo estoy intentando construir un ictiometro digital, herramienta que la gran mayoría de la gente desconoce para qué sirve. Un ictiómetro es un instrumento de medida que se utiliza para medir peces. La fabricación de un ictiometro convencional es muy sencilla, apenas es una tabla que cuenta en uno de sus extremos con un tope contra el que se apoya un extremo del pez (generalmente la cabeza) y que está dotada con una escala de medida en la que se lee la longitud del pez.

 ¿Necesitamos un ictiometro digital?

Hace unos cinco o seis años estaba yo con mi compañero Carlos muestreando (no me acuerdo qué) y  comentamos que algo tendría que haber para hacer más fácil la introducción de los datos de muestreo. Un muestreo, generalmente, no se acaba cuando destripas el último pez… luego viene el chequeo de los datos y por supuesto picarlos (incorporarlo a las bases de datos, etc.).

Por aquel entonces, y  mientras se rehabilitaba el que al poco tiempo sería el Centro Oceanográfico de Cádiz en el Muelle Pesquero del Puerto de Cádiz, estábamos alquilados en el CACYTMAR de la Universidad de Cádiz. La introducción de los datos al mismo tiempo que se muestreaba hubiera sido, aparte de una novedad quizá demasiado insoportable, tecnológicamente invivable. La aplicación SIRENO presentaba problemas por microcortes en la comunicación y otros que si ya dificultaban el trabajo con papeles en la mano, imaginad con datos provenientes de ensayos no ya destructivos, sino con ejemplares únicos e irrepetibles.

Pensamos en dispositivos que fueran como muchos contadores de células, mecánicos, pero pronto llegué a una conclusión y fue que concebir un instrumento que descansara en principios  mecánicos era perder el tiempo pues son muchas las desventajas, principalmente la dificultad de fabricar esos componentes con la precisión requerida por parte de un aficionado. De manera que la electrónica se perfilaba como la solución y en todo caso como la mejor: puesto que la idea última era suprimir la fase de picado de datos, con un  dispositivo electrónico es más sencillo comunicarse con un ordenador que con uno mecánico.

Primeros pasos

Después de mucho tiempo en el que la idea iba y venía, hace un par de años SSMM los Reyes de Oriente dejaron en mis zapatos un curso de electrónica básica. Aunque ya tenía conocimiento de qué era un ADC (Digital-to-Analog Converter, conversor analógico-digital), el cursillo me refrescó la memoria y juntando esto (el ADC) y lo otro (el divisor de tensión), me dije que si colocaba interruptores y resistencias de manera que cada pulsador hiciera que la corriente pasara por un número diferente de resistencias, lo que tendríamos en definitiva sería un “Divisor de tensión variable” en pasos discretos, lo que sería, según mi pobre criterio, ideal. Si yo le meto ese voltaje a un ADC, puesto que cada pulsador del ictiometro digital generaría un voltaje diferente, sería sencillo leer ese voltaje con el ADC y transmitir al ordenador un valor único para cada pulsación (un valor arbitrario y descodificable o una medida directa). Así podría introducir directamente clases de talla asignando una clase de talla a cada botón del ictiometro digital.

Otra idea en el mismo sentido, pero que perseguía obtener mayores precisiones consistía en usar una tira metálica dispuesta en la base del ictiometro digital y un puntero como si fuera un potenciómetro, de manera que la lectura del ADC se efectuara sobre el voltaje que suministrara el puntero del ictiometro digital. De esta manera, los valores que se pudieran obtener no eran ya discretos sino que, en principio, podría registrarse cualquier valor (aunque está claro que dar una medida en mm ya es dar medidas discretas) No obstante, esta segunda idea la deseché enseguida ya que por un lado nuestro ambiente de trabajo está siempre rodeado de suciedad y humedad y sobre todo el agua de mar que conduce la electricidad podría provocar efectos indeseados y por otro, como explicaré después, utilizar ADCs y variaciones de resistencia para obtener medidas se antojaba imposible.

¡¡¡Ojo, hago hincapié de que estas observaciones son las de una persona con muy poca formación en electrónica/mecánica, nulo o escaso presupuesto y muy poca disponibilidad de herramientas!!

Bueno, ya os seguiré contando…