Tecnologías IoT Para 2017 y 2018Descripción completa
IoT Guide
AWS Iot Mqtt
esp8266 manualFull description
In recent years, many of the bridges are monitored using non destructive testing methods. These methods are used for checking the structural damage, wreckage, strength of the bridges. To reduce the human losses, economic losses, protect the strength
Smart home system is very popular in current days that give many kind of application that make all simple and easy to control. In modern day, home machines are using wireless equipment and can be retrieved by internet that will make populations life
Estante multipropósito implementado al IoT. Pablo Urgiles Leon Wong ;Christian Pucha Cabrera,Anthony Cabrera,A nthony Jesús Yanza Verdugo Sistemas Microprocesados II;Circitos Digitales Avanzados. Avanzados.
Abstract. En el siguiente informe se presentará todo el procedimiento relacionado con el proyecto Estante multipropósito implementado al IoT de la materia de sistemas Microprocesados y Circuitos Digitales Avanzados, en el documento se podrá encontrar los conocimientos básicos necesarios para realizar éste proyecto, además de los elementos electrónicos que se utilizaron con sus respectivas características principales. Conjuntamente se colocará esquemas, programación y gráficas utilizadas en el procedimiento de configuración de cada uno de los módulos y sus dispositivos de control principales, tanto como la Raspberry y el Arduino. Y finalmente para el lector se presentará el dispositivo terminado con las respectivas conclusiones de los autores tanto para seguir con el avance de éste dispositivo o su mejora en futuras generaciones.. Keywords: Raspberry, Raspberry, IoT, vision artificial, wifi.
1
Objetivos 1.
Objetivo General Realizar un dispositivo capaz de reconocer objetos de consumo básico que se encuentran en un estante y enviar los datos mediante Wi-Fi a una aplicación en el móvil que permita identificar la cantidad productos que se encuentran y faltantes
2.
Objetivos Específicos Diseño y Construcción del Dispositivo que si mula un estante de un refrigerador. Diseño y construcción de una balanza que detecte el peso de los objetos dentro de ella mediante Arduino. Almacenamiento de datos de los productos que se encuentran en un refrigerador. Reconocimiento de imagen mediante una cámara y una Raspberry. Cuantificación de productos mediante un sensor de proximidad. Envío de datos vía Wi-fi. Diseño y creación de una aplicación en Android para comunicación con módulo Wi-fi.
2
Introdución
La tecnología a avanzado de manera desmesurada en las últimas décadas, sin duda alguna, ahora los artefactos “Smart” están ocupando un gran espacio en la vida del ser humano, por ejemplo, podemos encontrar smarphones, lavadoras inteligentes, ciudades inteligentes “Smart city”, computadoras, Smart Tv. En lo que nos centramos hoy en día es también en los artefactos que harían cada vez más fácil la vida del usuario, refiriéndonos a las refrigeradoras, sin d uda, el tener que ir a cada momento que falte algo en la refrigeradora es un poco molesto, al poder implementar un sistema “Smart” en una refrigeradora, estamos permitiéndole al usuario tener u na experiencia mucho más placentera, y no solo en ese aspecto, si no también, le ahorrará tiempo, ya que la refrigeradora por sí sola, le avisará al usuario cuando cuando no haya algo que se necesite necesite en el día a día, esto se puede llegar a logra por medio del desarrollo de aplicaciones de Smartphone, los cuales estén conectados al servidor de la refrigeradora y que a cada momento este se pueda ir actualizado, cada vez que se actualice, mostrará la lista de alimentos, tales como: carnes, lácteos, vegetales, etc. Hagan falta en el hogar, sin duda, el poder lograr tecnología como esta, son cosas que hoy en día dejan marca tanto en la industria como en la complacencia del usuario.
3
Marco Teórico
3.1
Arduino.
Arduino (Estados Unidos), Genuino a nivel internacional, es una compañía de hardware libre y una comunidad tecnológica que diseña y manufactura placas computadora de desarrollo de hardware y software, compuesta respectivamente por circuitos impresos que integran un microcontrolador y un entorno de desarrollo (IDE), en donde se programa cada placa. Arduino se enfoca en acercar y facilitar el uso de la electrónica y programación de sistemas embebidos en proyectos multidisciplinarios . Toda la plataforma, tanto para sus componentes de hardware como de software, son liberados con licencia de código abierto que permite libertad de acceso a ellos. El hardware consiste en una placa de circuito impreso con un microcontrolador, usualmente Atmel AVR, puertos digitales y analógicos de entrada/salida, , los cuales pueden conectarse a placas de expansión (shields), que amplían las características de funcionamiento de la placa Arduino. Asimismo, posee un puerto de conexión USB desde donde se puede alimentar la placa y establecer comunicación con el computador. Por otro lado, el software consiste en un entorno de desarrollo (IDE) basado en el entorno de Processing y lenguaje de programación basado en Wir ing, así como en el cargador de arranque (bootloader) que es ejecutado en la placa. El microcontrolador de la placa se programa mediante un computador, usando una comunicación comunicación serial mediante un convertidor de niveles RS-232 a TTL serial. [1]
2
Introdución
La tecnología a avanzado de manera desmesurada en las últimas décadas, sin duda alguna, ahora los artefactos “Smart” están ocupando un gran espacio en la vida del ser humano, por ejemplo, podemos encontrar smarphones, lavadoras inteligentes, ciudades inteligentes “Smart city”, computadoras, Smart Tv. En lo que nos centramos hoy en día es también en los artefactos que harían cada vez más fácil la vida del usuario, refiriéndonos a las refrigeradoras, sin d uda, el tener que ir a cada momento que falte algo en la refrigeradora es un poco molesto, al poder implementar un sistema “Smart” en una refrigeradora, estamos permitiéndole al usuario tener u na experiencia mucho más placentera, y no solo en ese aspecto, si no también, le ahorrará tiempo, ya que la refrigeradora por sí sola, le avisará al usuario cuando cuando no haya algo que se necesite necesite en el día a día, esto se puede llegar a logra por medio del desarrollo de aplicaciones de Smartphone, los cuales estén conectados al servidor de la refrigeradora y que a cada momento este se pueda ir actualizado, cada vez que se actualice, mostrará la lista de alimentos, tales como: carnes, lácteos, vegetales, etc. Hagan falta en el hogar, sin duda, el poder lograr tecnología como esta, son cosas que hoy en día dejan marca tanto en la industria como en la complacencia del usuario.
3
Marco Teórico
3.1
Arduino.
Arduino (Estados Unidos), Genuino a nivel internacional, es una compañía de hardware libre y una comunidad tecnológica que diseña y manufactura placas computadora de desarrollo de hardware y software, compuesta respectivamente por circuitos impresos que integran un microcontrolador y un entorno de desarrollo (IDE), en donde se programa cada placa. Arduino se enfoca en acercar y facilitar el uso de la electrónica y programación de sistemas embebidos en proyectos multidisciplinarios . Toda la plataforma, tanto para sus componentes de hardware como de software, son liberados con licencia de código abierto que permite libertad de acceso a ellos. El hardware consiste en una placa de circuito impreso con un microcontrolador, usualmente Atmel AVR, puertos digitales y analógicos de entrada/salida, , los cuales pueden conectarse a placas de expansión (shields), que amplían las características de funcionamiento de la placa Arduino. Asimismo, posee un puerto de conexión USB desde donde se puede alimentar la placa y establecer comunicación con el computador. Por otro lado, el software consiste en un entorno de desarrollo (IDE) basado en el entorno de Processing y lenguaje de programación basado en Wir ing, así como en el cargador de arranque (bootloader) que es ejecutado en la placa. El microcontrolador de la placa se programa mediante un computador, usando una comunicación comunicación serial mediante un convertidor de niveles RS-232 a TTL serial. [1]
Un arduino dispone de 14 pines que pueden configurarse como entrada o s alida y a los que puede conectarse cualquier dispositivo que sea capaz de transmitir o recibir señales digitales de 0 y 5 V. 7
Fig. 1. Apariencia física de un Arduino UNO.
3.1.1
Entradas y Salidas Arduino.
Cada uno de los 14 pines digitales se puede usar como entrada o como salida. Funcionan a 5V, cada pin puede suministrar hasta 40 mA. La intensidad máxima de entrada tam bién es de 40 mA. Cada uno de los pines digitales dispone de una resistencia de pull-up interna de entre 20KΩ y 50 KΩ que está desconectada, salvo que nosotros in diquemos lo contrario. Arduino también dispone de 6 pines de entrada analógicos que trasladan las señales a un conversor analógico/digital de 10 bits. Tenemos también pines especiales, de los cuales se encuentran los siguientes: RX y TX: Se usan para transmisiones serie de señales TTL. Interrupciones externas: Los pines 2 y 3 están configurados para generar una interrupción en el atmega. Las interrupciones pueden disparar se cuando se encuentra un valor bajo en estas entradas y con flancos de subida o bajada de la entrada. PWM: Arduino dispone de 6 salidas destinadas a la generación de señales PWM de hasta 8 bits. SPI: Los pines 10, 11, 12 y 13 pueden utilizarse para llevar a cabo comunicaciones SPI, que permiten trasladar información full dúplex en un entorno Maestro/Esclavo.
3.1.2
I2C: Permite establecer comunicaciones a través de un bus I2C. El bus I 2C es un producto de Phillips para interconexión de sistemas embebidos. Actualmente se puede encontrar una gran diversidad de dispositivos que utilizan esta interfaz, desde pantallas LCD, memorias EEPROM, sensores, etc. Alimentación Arduino UNO.
Puede alimentarse directamente a través del propio cable USB o mediante una fuente de alimentación externa, como puede ser un pequeño transformador o, por ejemplo una pila de 9V. Los límites están entre los 6 y los 12 V. Como única restricción hay que saber que si la placa se alimenta con menos de 7V, la salida del regulador de tensión a 5V puede dar menos que este voltaje y si sobrepasamos los 12V, probablemente dañaremos la placa. La alimentación puede conectarse mediante un conector de 2,1mm con el positivo en el centro o directamente a los pines Vin y GND marcados sobre la placa. Hay que tener en cuenta que podemos medir el voltaje presente en el jack directamente desde Vin. En el caso de que el Arduino esté siendo alimentado mediante el cable USB, ese voltaje no podrá monitorizarse desde aquí. 3.1.3
Resumen de Características.
Table 1. Características principals Arduino UNO.
Microcontrolador Voltaje de Operación Voltaje de Entrada (Recomendado) Voltaje de Entrada (Límite) Pines de entrada-salida digital. Pines de entrada analógica. Corriente continua por PIN. Corriente continua en el PIN 3.3V Memoria FLASH SRAM EEPROM
ATmega328 5V 7 - 12 V 6 - 20 V 14 (6 pueden ser PWM) 6 40mA 50mA 32Kb (0.5Kb ocupados por el blootloader. 2Kb 1Kb
[2] 3.2
Raspberry
Raspberry Pi es un computador de placa reducida, computador de placa única o computador de placa simple (SBC) de bajo coste desarrollado en Reino Unido por la Fundación Raspberry Pi, con el objetivo de estimular la enseñanza de ciencias de la computación en las escuelas. Las ventas iniciales fueron del modelo B. El modelo A solo tiene un puerto USB, carece de controlador Ethernet y cuesta menos que el modelo B, el cual tiene dos puertos USB
y controlador Ethernet 10/100. En 2014 se lanzó el modelo Raspberry Pi 2 B. El último modelo lanzado en 2015 es el Raspberry Pi Zero. A pesar que el Modelo A no tiene un puerto RJ45, se puede conectar a una red usando un adaptador USB-Ethernet suministrado por el usuario. Por otro lado, a ambos modelos se puede conectar un adaptador Wi-Fi por USB, para tener acceso a redes inalám bricas o internet. El sistema cuenta con 256 MB de memoria RAM en su modelo A, y con 512 MB de memoria RAM en su modelo B. Como es típico en las computadoras modernas, se pueden usar teclados y ratones con conexión USB compatible con Ras pberry Pi. El Raspberry Pi no viene con reloj en tiempo real,5 por lo que el sistema operativo debe usar un servidor de hora en red, o pedir al usuario la hora en el momento de arrancar el computador. Sin embargo se podría añadir un reloj en tiempo real (como el DS1307) con una batería mediante el uso de la interfaz I2C. 3.2.1 Software.
El Raspberry Pi usa mayoritariamente sistemas operativos GNU/Linux. Raspbian, una distribución derivada de Debian que está optimizada para el hardware de Raspberry Pi, se lanzó durante julio de 2012 y es la distribución recomendada por la fundación para iniciarse. Slackware ARM (también llamada ARMedslack) versión 13.37 y posteriores arranca sin ninguna modificación. Los 128-496 MiB de memoria RAM disponible en la Ras pberry Pi, cubren los necesarios 64 MiB de RAM para arrancar esta distribución en sistemas ARM y i386 sin usar interfaz gráfica (el administrador de ventanas Fluxbox que funciona bajo X Window System requiere 48 MiB de memoria RAM adicional). Por otro lado, se están creando distribuciones más específicas y ligeras como IPfire (distribución para ser usada como firewall), u OpenELEC y OSMC (distribuciones con el centro multimedia Kodi). A la GPU se accede mediante una imagen del firmware de código cerrado (un blob binario, en inglés), que se carga dentro de la GPU al arrancar desde la tarjeta SD. El archivo está asociado a los controladores del nucleo Linux que también son de código cerrado. Las aplicaciones hacen llamadas a las bibliotecas de tiempo de ejecución que son de código abierto, y las mismas hacen llamadas a unos controladores de código abierto en el núcleo Linux. La API del controlador del núcleo es específica para estas bibliotecas. Las aplicaciones que usan vídeo hacen uso de OpenMAX, las aplicaciones tridimensionales usan OpenGL ES y las aplicaciones 2D usan OpenVG; OpenGL ES y OpenVG hacen uso de EGL y este último, del controlador de código abierto del núcleo. [3] 3.2.2 Características
Entre las novedades más destacadas de la Raspberry Pi 3 están:
Procesador, un ARM Cortex A53, un procesador de cuatro núcleos a 1.2GHz de 64 bits y que, según sus datos, tiene un rendimiento 10 veces superior al de la Raspberry Pi original y un 50 % más que la Raspberry Pi 2, el modelo anterior. Bluetooth 4.1 (de bajo consumo). WiFi 802.11n integrado. Ranura MicroSD. Puerto USB. Ethernet. CPU 1.2GHz 64-bit quad-core ARMv8. GPU Broadcom VideoCore IV, OpenGL ES 2.0, MP EG-2 y VC-1 (con licencia), 1080p30 H.264/MPEG-4 AVC. Memoria SDRAM 1 GB (compartidos con la GPU) Entradas de video, conector MIPI CSI que permite instalar un módulo de cámara desarrollado por la RPF. Salida de video, conector RCA (PAL y NTSC), HDMI (rev1.3 y 1.4), Interfaz DSI para panel LCD. Salida de audio, conector de 3.5 mm, HDMI. Consumo de 800mA (4W). Alimentación 5V vía Micro USB o GPIO header.
[4]
Fig. 2. Apariencia física Raspberry PI.
3.3
Reconocimiento de Imagen
Los sistemas de computadoras son cada vez más potentes y menos costosos, lo que permite crear nuevas formas de arte que antes no era posible, y algunas otras formas de arte antiguas pueden ahora verse beneficiadas con novedosas técnicas asistidas por computadora. El reconocimiento de imágenes ha evolucionado a medida que mejora la tecnología. Puede encontrarse en numerosos campos. Utilizando los conceptos derivados del OCR (Optical Carácter Recognition), el primer paso para comparar dos imágenes es vectorizar cada imagen y cada cuadro para luego, comparar las formas de los objetos resultantes. El proceso de vectorización consiste en definir imágenes utilizando la geometría y funciones matemáticas. Los algoritmos existentes para este proceso consumen una gran cantidad de recursos, y la metodología para reconocer la similitud entre estos objetos resulta muy compleja. La manera más directa de comparar un cuadro la imagen original con una colección de imágenes, es comparar cada píxel del cuadro de la imagen original con su correspondiente píxel en la imagen de la colección imágenes, y acumular las distancia entre cada pareja de píxeles para determinar la distancia general entre l as dos imágenes. Aunque esta es una estrategia relativamente buena para comparar imágenes, la cantidad de com paraciones necesarias es muy grande. Por cada comparación debe calcularse la distancia entre los píxeles de las dos imágenes y por cada pareja de píxeles debe compararse cada uno de los tres canales RGB. [5]
Fig. 3. Modelo de un reconocimiento de imagen.
3.4
Desarrollo del Reconocimiento de imagen.
Para llevar a cabo el proceso de reconocimiento de imágenes utilizamos DeepBeliefSDK, la herramienta desarrollada por P ete Warden aunque solo la p arte relacionada
con la Raspberry Pi 3. A diferencia del uso de dicha librería en la Raspberry Pi 1 y 2, donde la mayoría de cálculos matriciales que necesita la red neuronal se realizan en la GPU (VideoCore), en el modelo 3 se pasa a utilizar la CPU. Esto se debe a que, mientras el VideoCore sigue siendo el mismo, el nuevo procesador ARMv7 ha mejorado bastante e incluye nuevas instrucciones. Sin embargo, el uso de la CPU no es impedimento para realizar el proyecto, puesto que no disminuye el rendimiento y además nos permite utilizar el VideoCore para la visualización de la interfaz de usuario en la pantalla T FT. El motivo por el que el rendimiento entre las dos placas sea muy similar, aunque utilicemos componentes muy distintos, es que el nuevo procesador ARMv7 cuenta con 4 núcleos que son optimizados además con las instrucciones NEON de tipo vectorial, frente al ARMv6 de un sólo núcleo de la Raspberry Pi or iginal. El reloj del procesador también ha pasado de 700 MHz a 900 Mhz. Para sacar provecho de estas instrucciones se utiliza a su vez la librería de C++ EIGEN, con la que se optimizan todos los cálculos de álgebra lineal, utilizando la vectorización explícita para las instrucciones NEON. Esta librería no tiene ninguna dependencia, exceptuando las bibliotecas estándar. 3.4.1
Rutinas GEMM
La optimización de los cálculos de Deep Learning en la lib rería DeepBeliefSDK se basa en usar una implementación muy eficiente de las rutinas GEMM (General Matrix to Matrix Multiplication) en 13 cada plataforma. Estas rutinas tratan esencialmente de multiplicar matrices de una forma eficiente sin aprovechar ninguna estructura especial en las matrices. Para esto, en la memoria RAM las matrices deben almacenarse de for ma consecutiva, ya sea fila a fila, o columna a columna; es decir, convirtiendo la matriz en un vector. Estas rutinas nacen como parte de la biblioteca BLAS (Basic Linear Algebra Subrutines), creadas en 1979 para el lenguaje FORTRAN. La importancia de las rutinas GEMM en el Deep Learning se debe a que las multiplicaciones de matrices ocupan entre el 89 y el 95% del tiempo que necesitan las capas de la red para el reconocimiento. Esto se debe a que una sola capa de una red típica puede requerir la multiplicación de una matriz de 256 X 1152 y otra de 1152 X 192, lo que lleva un total de 57 millones de operaciones en punto flotante. Para este proyecto, como mencionamos antes, utilizamos la biblioteca EIGEN que implementa sus propias rutinas GEMM. 3.4.2
Instrucciones NEON
Son instrucciones de propósito general SIMD (Single Instruction, Multiple Data) de ARM, pensadas para procesar eficientemente formatos multimedia, tales como decodificación de vídeo, procesado de gráficos 2D y 3D, procesamiento del habla, síntesis de sonido, etc. Estas instrucciones son una extensión de los procesadores ARM Cortex, como mencionamos anteriormente la Raspberry Pi 3 lleva el procesador ARM Cortex A7, por lo que se aprovechan dichas instrucciones. Algunas características y formas de funcionamiento: – Los registros se consideran vectores de elementos del mismo tipo de datos. – Los tipos de datos pueden ser signed/unsigned de 8, 16, 32 o 64 bits y float con precisión simple. – Como son del tipo SIMD, se realiza la misma operación a todos los carriles.
3.4.3
3.5
Acciones seguidas para obtener el reconocimiento de la imagen.
Acción capturar Con la acción capturar sacamos la foto, la almacenamos y la mostramos durante 3 segundos en la pantalla. Para esto utilizamos la librería “picamera” implementada por Dave Jones con la que, cambiamos la r esolución por defecto para poder adaptar la imagen a la pantalla TFT (320, 240) y realizamos la captura. Para el algoritmo de reconocimiento no es necesario escalar la imagen, ya que no importa el tamaño, todas se reescalan en el código a 256 X 256px. Para enviar la captura a la pantalla hacemos uso del comando mencionado anteriormente “fbi” (Linux Frame Buffer Image). Acción pre visualizar Esta opción del menú simplemente nos enseña durante 4 segundos la foto que tenemos almacenada, en caso de no encontrar imagen, se imprime un error en la pantalla. Para esta tarea utilizamos la función “envía foto (foto)”. Acción reconocer Se trata de la acción principal del programa, en este momento es donde se realiza el reconocimiento de la imagen capturada. En primer lugar realizamos una llamada al programa jpcnn pasándole como argumento la foto capturada y la red neuronal a utilizar. Esta llamada escribe en un fichero los resultados obtenidos. Todo esto lo hacemos invocando a la función “reconoce (foto)”. Una vez tenemos el fichero resultado, con la llamada a la función “resultado (fichero)” ordenamos el fichero con los datos, dejando en la primera línea el resultado con la probabilidad más alta. Al leer la línea aplicamos el filtro de que la probabilidad sea mayor que 0.05, si esto se cu mple imprimimos en la pantalla el resultado obtenido. En caso de no cumplirse, se muestra un error.
Comunicación WI-FI
Cuando hablamos de WIFI nos referimos a una de las tecnologías de comunicación inálambrica mediante ondas más utilizada hoy en día. WIFI, también llamada WLAN (wireless lan, red inalámbrica) o estándar IEEE 802.11. WIFI no es una abreviatura de Wireless Fidelity, simplemente es un nombre comercial. En la actualidad podemos encontrarnos con dos tipos de comunicación WIFI:
802.11b, que emite a 11 Mb/seg 802.11g, más rapida, a 54 MB/seg
De hecho, son su velocidad y alcance (unos 100-150 metros en hardaware asequible) lo convierten en una fórmula perfecta para el acceso a internet sin cables. Para tener una red inalámbrica en casa sólo necesitaremos un punto de acceso, que se conectaría al módem, y un dispositivo WIFI que se conectaría en nuestro aparato. Existen terminales WIFI que se conectan al PC por USB, pero son las tarjetas PCI (que se insertan directamente en la placa base) las recomendables, nos permite ahorrar espacio
físico de trabajo y mayor rapidez. Para portátiles podemos encontrar tarjetas PCMI externas, aunque muchos de los aparatos ya se venden con tarj eta integrada. En cualquiera de los casos es aconsejable mantener el punto de acceso en un lugar alto para que la recepción/emisión sea más fluida. Incluso si encontramos que nuestra velocidad no es tan alta como debería, quizás sea debido a que los dispositivos no se encuentren adecuadamente situados o puedan existir barreras entre ellos (como paredes, metal o puertas). El funcionamiento de la red es bastante sencillo, normalmente s ólo tendrás que conectar los dispositivos e instalar su software. Muchos de lo s enrutadores WIFI (routers WIFI) incorporan herramientas de configuración para controlar el acceso a la información que se transmite por el aire. Pero al tratarse de conexiones inalámbricas, no es difícil que alguien interceptara nuestra comunicación y tuviera acceso a nuestro flujo de información. Por esto, es r ecomendable la encriptación de la transmisión para emitir en un entorno seguro. En WI FI esto es posible gracias al WPA, mucho más seguro que su predecesor WEP y con nuevas características de seguridad, como la generación dinámica de la clave de acceso. Para usuarios más avanzados exite la posibilidad de configurar el punto de acceso para que emita sólo a ciertos dispositivos. Usando la d irección MAC, un identificador único de los dispositivos asignados durante su construcción, y permitiendo el acceso solamente a los dispositivos instalados. Por último, también merece la pena comentar la existencia de comunidades wireless que permiten el acceso gratuito a la red conectando con nodos públicos situados en diferentes puntos, por ejemplo, en tu ciudad. Esta tendencia aún no está consolidada y tiene un futuro impredecible, pues es muy probable que las compañías telefónicas se interpongan a esta práctica. Si te interesa este tema y quieres más información algunos sitios de interés serían valencia wireless o RedLibre. [6]
Fig.4. Logotipo de WI-FI
3.5.1 Módulo Esp8266.
El módulo ESP8266 nos permite añadir conexión Wifi a nuestro Arduino por, ello nos posibilita el control inalámbrico en un entorno de bastantes metros y sin cables, b ien a través de nuestra red local o (si configuramos el Router y tenemos IP fija) vía Internet desde cualquier parte con un ordenador o un móvil. El módulo mide 1,5x2,5 cm y solo necesita dos hilos para funcionar, ya que se comunica vía serie con el Arduino. No hay una autentica comunicación Wifi, solo es serie, pero es más que suficiente para recibir datos o enviar comandos a cualquiera de los pines del Arduino. Al contrario que con el módulo HLK-RM04 que dispone de una página Web p ara configuración, el ESP8266 se configura por medio de comandos AT. Funciona a 3,3V y a veces consume bastante. Con una fuente de alimentación y limitando la salida a 100mA, no es capaz de arrancar. Aunque después baja el consumo. Los que no tengan fuente con 3,3 V, pueden usar las salidas de ese voltaje d e una fuente de PC o incluso dos pilas de 1,5V en serie. [7] Características.
CPU RISC de 32 bits: Tensilica Xtensa LX106 a 80 MHz 64 KiB de RAM de instrucción, 96 KiB de RAM de d atos Flash QSPI externo - 512 KiB a 4 MiB * (hasta 16 MiB es compatible) IEEE 802.11 b / g / n Wi-Fi Interruptor TR integrado, balun, LNA, amplificador de potencia y red de conexión Autenticación WEP o WPA / W PA2 o redes abiertas 16 clavijas GPIO SPI, I²C, Interfaces I²S con DMA (compartir clavijas con GPIO) UART en pines dedicados, además de un UART de sólo transmisión se puede activar en GPIO2 1 ADC de 10 bits [8]
Fig.5. Módulo ESP8266
3.6
Sensor de Peso (Celda de carga)
Una celda de carga es un transductor capaz de convertir una fuerza en una señal eléctrica, esto la hace a través uno o más galgas internas que posee, configuradas en un puente Wheatstone. Usaremos una celda de carga de 10Kg que es el valor máximo que puede sensar. [9] La celda de carga es una estructura diseñada para soportar cargas de compresión, tensión y flexión, en cuyo interior se encuentra uno o varios sensores de deformación llamados Strain Gages que detectan los valores de deformación. La celda de carga digital produce esta deformación mediante circuitos wheatstone, que actúan en las bases de la máquina o sistemas de pesaje para encontrar reacciones, una vez obtenida la resistencia, se produce la transducción y se puede obtener el valor que la máquina resiste.
Fig.6. Celda de carga.
También son llamadas Digital Load Cell (es su traducción en Inglés), esta se fija en la parte donde quiere registrarse una carga que aplique un sistema mecánico. La señal de la carga se lleva a un dispositi vo electrónico, microchip o computadora central (dependiendo de su utilidad) para recopilar los datos totales de una o varias celdas de carga, inclusive desarrollar análisis estadísticos de las cargas durante un tiempo determinado o evento en particular. [9] 3.6.1
Trasmisor de celda de carga HX711
Este módulo es una interface entre las celdas de carga y el microcontrolador, permitiendo poder leer el peso de manera sencilla. Internamente se encarga de la lectura del puente wheatstone formado por la celda de carga, convirtiendo la lectura analógica a digital con su conversor A/D interno de 24 bits. [10] Es muy utilizado en procesos industriales, sistemas de medición automatizada e industria médica. Se comunica con el microcontrolador mediante 2 pines (Clock y Data) de forma serial.
Fig.7. Trasmisor de celda de carga HX711
4
Desarrollo
4.1
Maqueta del Estante
El diseño de la maqueta es importante ya que se encargará en gran porcentaje de la funcionalidad de nuestro dispositivo, en el cual se tomaron muchas cosas en cuenta, y podemos numerar las principales. 4.1.1
Estructura Externa
La estructura externa es una caja con medidas de 41x26x23cm y la madera que la conforma es de 1cm de espesor. Se tomó estas medidas de acuerdo a un diseño pequeño pero adecuado para productos indispensables en el hogar, además de tener en cuenta que es un prototipo y sería exagerado hacerlo demasiado grande.
Fig.8. Fotografía de la Estructura externa del estante.
4.1.2
Soporte de Cámara
El soporte se lo utiliza para ajustar la cámara a un nivel óptimo en donde se pueda ajustar la visibilidad en un rango que se pueda manejar, por eso de la colocación de un soporte ajustable como se observa en la siguiente figura.
Fig.9. Fotografía del soporte de cámara.
4.1.3
Estructura de la Balanza
Para la estructura que soporta el sensor de peso, está construido de forma en que la celda de carga soporte toda la parte en donde va la balanza. De esta forma el sistema funciona de manera óptima. Para instalar la celda de carga hay que hacerlo con separadores, los cuales deben de distanciar a la base y recipiente de la celda para que la parte central quede libre; además hay que tener en cuenta que el sentido de la flecha indica la dirección de la fuerza o peso a aplicar. [10]
Fig.10. Fotografía de la Estructura soporte de la carga.
4.2
Balanza Electrónica.
4.2.1 Conexiones.
Conexión entre la Celda de carga y módulo HX711
Table 2. Conexión entre la celda de varga y el módulo.
Celda De Carga
Módulo HX711
Cable Rojo
Pin E+
Cable Negro
Pin E-
Cable Verde
Pin A-
Cable Blanco
Pin A+
Conexión entre HX711 y Arduino
Table 3. Conexión entre el módulo y Arduino.
Módulo
Arduino UNO, MEGA,
HX711
NANO
Pin GND
Pin GND
Pin DT
Pin A1
Pin SCK
Pin A0
Pin VCC
Pin 5V
La conexión final sería como se muestra en la i magen.
Fig.11. Conexión Final al arduino.
4.2.2. Librería HX711 Explicaremos las funciones principales de esta librería. HX711(byte PinData, byte PinClock) Es el constructor del objeto HX711, se puede trabajar con cualquiera de los pines. void tare(byte n); Establece el peso actual como el peso de tara, n indica el número de lecturas que se realizan para obtener la tara, por defecto n=10; void set_scale(float scale); Establece el valor de la escala, que es el factor de conversión para convertir valor de lectura en un valor con unidades de peso. Por defecto es scale=1;
long read() Espera hasta que el dispositivo esté listo y devuelve la lectura del ADC del HX711 long read_average(byte n) Realiza n veces la lectura del ADC y devuelve el promedio double get_value(byte n) Devuelve el valor actual restando el peso de tara. Equivalente a (read_average() OFFSET) . Si se especifica un valor de n, devuelve el promedio de n lecturas. float get_units(byte n) Devuelve el valor actual restado del peso de tara y dividido por la escala. Es equivalente a (get_value()/SCALE). Si se especifica un valor de n, devuelve el promedio de n lecturas. [10] 4.2.3 Calibración
Lo primero que se debe de hacer es calibrar, que es básicamente hallar el valor de la escala que se usará; es decir hallar el factor de conversión para convertir valor de lectura en un valor con unidades de peso. La escala es diferente para cada celda y cambia de acuerdo a la forma de instalar, al peso máximo o modelo de celda de carga, incluso así se trate del mismo modelo de celdas no necesariamente tienen el mismo valor de escala. Primero necesitamos conseguir un objeto con peso conocido, en otras palabras debemos saber el peso real del objeto. Se recomienda que el peso conocido sea cercano al valor máximo del rango de trabajo de la celda de carga. [10] El siguiente paso es cargar el siguiente Sketch a n uestro Arduino. #include "HX711.h" #define DOUT A1 #define CLK A0 HX711 balanza(DOUT, CLK); void setup() { Serial.begin(9600); Serial.print("Lectura del valor del ADC:t"); Serial.println(balanza.read()); Serial.println("No ponga ningun objeto sobre la balanza"); Serial.println("Destarando..."); balanza.set_scale(); //La escala por defecto es 1 balanza.tare(20); //El peso actual es considerado Tara. Serial.println("Coloque un peso conocido:"); }
void loop() { Serial.print("Valor de lectura: t"); Serial.println(balanza.get_value(10),0); delay(100); } El programa debe correr sin el peso colocado, pues al inicio de programa calcula la tara. Después de poner el peso en la balanza, en el monitor serial se mostraran las lecturas del peso, son lecturas sin escalar, por lo que les deben aparecer números grandes. Con uno o el promedio de estos datos calculamos el valor de la escala que usaremos, para esto usaremos la siguiente formula: =
El valor del peso debe estar en las unidades con las que queremos que trabaje nuestra balanza, por ejemplo podría ser 4Kg o 4000g para Kilogramo o gramos respectivamente. Entonces el valor de la Escala que usaremos es: 1757721 =
4000
= 439.43
Con este dato ya obtenido pasamos a programar el sketch que vamos a utilizar para pesar. [10] #include "HX711.h" #define DOUT A1 #define CLK A0 HX711 balanza(DOUT, CLK); double aq; void setup() { Serial.begin(9600); Serial.print("Lectura del valor del ADC:t"); Serial.println(balanza.read()); Serial.println("No ponga ningun objeto sobre la balanza"); Serial.println("Destarando..."); Serial.println("..."); balanza.set_scale(189.39); // Establecemos la escala balanza.tare(25); Serial.println("Listo para pesar");
} void loop() { Serial.print("Peso: "); aq=((balanza.get_units(20))*-1); if (aq<0){ aq=0; } Serial.print(aq,3); Serial.println("g"); delay(500); } Como se observa en el código, es necesario encender el Arduino antes de colocar los objetos que se desean pesar, de lo contrario el peso que esté sobre la balanza se considerará como tara. [10] 4.3
Conexión WI-FI
Para lograr esta comunicación al Arduino se lo configuró por medio de los puertos serial del dispositivo y del módulo Wi-Fi utilizando los comandos AT, los cuales vienen incluidos en la configuración del módulo, los cuales sirven para configurar los diferentes modos y funcionalidades del dispositivo. A continuación, observaremos parte del código utilizado en la configuración tanto serial como del módulo. #include SoftwareSerial BT1(3, 2); // RX | TX void setup() { Serial.begin(115200); BT1.begin(115200); } void loop() { String B= "." ; if (BT1.available()) { char c = BT1.read() ; Serial.print(c); } if (Serial.available()) { char c = Serial.read(); BT1.print(c); } }
Para la aplicación en el celular se utilizó una comunicación UDP, el cual utiliza los sockets UDP que envían los mensajes a través del módulo ESP8266 hacia el socket UDP de la aplicación que se puede visualizar en la pantalla de un Smartphone. La aplicación en el celular es la siguiente.
Fig.12. Aplicación para Android.
Una vez que le instruimos para que se conecte a nuestra WIFI, el modulo es capaz de enviar información que le remitimos vía la puerta serie a una dirección IP y puerto que deseemos. Cuando se trata de recibir, limpia todo el empaquetado TCPIP y nos reenvía por la puerta serie la información de datos limpia de polvo y paja, con lo que tiene la enorme virtud de permitirnos olvidarnos de la gestión del TCPIP y de las demandas de procesador y memoria que suponen. A cambio no es exactamente una conexión WIFI, porque no tenemos acceso al stack o al socket IP pero para el Arduino esto es casi una ventaja. [11]
4.5
Open CV (Reconocimiento).
OpenCV es una librería de Visión por Computador y Análisis de Imagen, 100% de código libre. Con pocas líneas de código es posible realizar operaciones complejas tales cómo identificar personas en movimiento (¡lo cuál es ideal para construir adorables torretas automáticas!), detectar objetos en movimiento y separarlos del fondo estático, encontrar rostros humanos en una imagen… Es multiplataforma y puede usarse en gran cantidad de lenguajes: Python, C++, C, Java e incluso Matlab. Entre otros. [12]
OpenCV es utilizada por empresas minoritarias y poco conocidas como Google, Yahoo e IBM [desactivando módulos de sarcasmo]. Y por multitud de aficionados a la ro bótica y makers, que gracias a su sencillez han conseguido hacer cosas realmente asombrosas. [12] Para la instalación de una Raspberry PI con Raspbian: Abrimos la Terminal y escribimos: sudo apt-get update sudo apt-get install libopencv-dev python-opencv Una vez instalado, escribimos de nuevo: sudo apt-get install libopencv-dev python-opencv Con esto se tiene libopencv instalada. 4.5.1
Filtros Gaussinaos
Lo primero que hacemos es iniciar la cámara de la Raspberry con una resolución concreta, para ir procesando cada imagen que vamos leyendo. Dibujamos un cuadrado en la posición de la imagen donde estará el objeto. [13]
Fig.13. Cuadro en la posición de imagen.
A continuación se conveirte en escala de grises:
Fig.14. Conversión a escala de grises.
Le aplicamos un filtro Gaussiano, que desenfoca la imágen de la siguiente forma: [13]
Fig.15. Aplicación del filtro Gaussiano.
4.5.2 Segmentación de Imagen
En OpenCV se implementó un algoritmo basado en marcadores donde se especifican cuáles son todos los puntos que se van a fusionar y cuáles no. Se trata de una segmentación de imágenes interactiva. Lo que hacemos es dar etiquetas diferentes para nuestro objeto que conocemos. Etiqueta la región que estamos seguros de ser el primer plano u objeto con un color (o intensidad), etiquetar la región que estamos seguros d e ser de fondo o no objeto con otro color y, finalmente, la región que no estamos seguros de nada, se lo etiqueta con 0. Ese es nuestro marcador. A continuación, se aplica el algoritmo. Entonces nuestro marcador se actualizará con las etiquetas que dimos, y los límites de los objetos tendrán un valor de -1. [14]
A continuación, usamos la Transformación de Distancia junto con la línea divisoria de aguas para segmentar objetos que se tocan mutuamente. Comenzamos con la búsqueda de una estimación aproximada. Para eso, podemos usar la binarización de Otsu. import numpy as np import cv2 from matplotlib import pyplot as plt img = cv2.imread('coins.png') gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) ret, thresh = old(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
cv2.thresh-
Las regiones restantes son aquellas que no tenemos idea. Estas áreas están normalmente alrededor de los límites donde el primer plano y el fondo se encuentran. Lo llamamos frontera. Puede obtenerse restando el área sure_fg del área sure_bg. [14] # noise removal kernel = np.ones((3,3),np.uint8) opening = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel, iterations = 2) # sure background area sure_bg = cv2.dilate(opening,kernel,iterations=3) # Finding sure foreground area dist_transform = cv2.distanceTransform(opening,cv2.DIST_L2,5) ret, sure_fg = cv2.threshold(dist_transform,0.7*dist_transform.max(),255,0) # Finding unknown region sure_fg = np.uint8(sure_fg) unknown = cv2.subtract(sure_bg,sure_fg) Empleando monedas, en la imagen de umbral, tenemos algunas regiones que estamos seguros de las monedas y que se d esprenden ahora.
Fig.16. Regiones de segmentación.
Ahora sabemos con certeza cuál es la región de las monedas, que son de fondo y todo. Así que creamos marcador y etiquetamos las regiones dentro de ella. Las regiones que sabemos con certeza (ya sea en primer plano o de fondo) están etiquetados con cualquier entero positivo, pero enteros diferentes, y el área que no sabemos a ciencia cierta se queda como cero. Para ello utilizamos cv2.connectedComponents (). Marca el fondo de la imagen con 0 y, a continuación, los demás objetos se etiquetan con números enteros a partir de 1. [14] Pero sabemos que si el fondo está marcado con 0, el algoritmo lo considerará como área desconocida. Así que queremos marcarlo con un entero diferente. En lugar de eso, marcaremos una región desconocida, definida por desconocida, con 0. # Marker labelling ret, markers = cv2.connectedComponents(sure_fg) # Add one to all labels so that sure background is not 0, but 1 markers = markers+1 # Now, mark the region of unknown with zero markers[unknown==255] = 0
El resultado es mostrado en el mapa de colores JET. La región azul oscuro muestra la región desconocida. Las monedas están coloreadas con diferentes valores. El área restante que es fondo seguro se muestran en azul más claro en comparación con la región desconocida. [14]
Fig.17. Resultado en mapa de colores JET.
Entonces se modificará la imagen del marcador. La región límite se marcará con - 1. markers = cv2.watershed(img,markers) img[markers == -1] = [255,0,0] Para algunas monedas, la región donde se tocan se segmenta adecuadamente.
Fig.18. Resultado de la segmentación.
4.5.3 Histograma de la imagen
En las imágenes digitales un histograma de color representa el número de pixeles que tienen colores en cada una de las listas fijas de rangos de color es, que se extienden sobre el espacio de color de la imagen, es d ecir el conjunto de todos los p osibles colores. [15]
Ahora usamos la función cv2.calcHist () para encontrar el histograma. Vamos a familiarizarnos con la función y sus parámetros: Cv2.calcHist (imágenes, canales, máscara, histSize, intervalos [, hist [, acumular]])
Imágenes: es la imagen fuente del tipo uint8 o float32. Debe ser entre corchetes, es decir, "[img]". Canales: también se indica entre corchetes. Es el índice del canal para el cual calculamos el histograma. Por ejemplo, si la entrada es de escala de grises, su valor es [0]. Para la imagen en color, puede pasar [0], [1] o [2] para calcular el histograma del canal azul, verde o rojo, respectivamente. Máscara: imagen de máscara. Para encontrar el histograma de imagen com pleta, se da como "Ninguno". Pero si quieres encontrar el histograma de una determinada región de la imagen, tienes que crear una imagen de máscara para que y darlo como máscara. (Voy a mostrar un eje mplo más tarde.) HistSize: esto representa nuestro recuento BIN. Debe darse entre corchetes. Para la escala completa, pasamos [256]. Gamas: esta es nuestra GAMA. Normalmente, es [0,256].
Comencemos con una imagen de muestra. Basta con cargar una imagen en el modo de escala de grises y encontrar su histograma completo. [15] Img = cv2.imread ('home.jpg', 0) Hist = cv2.calcHist ([img], [0], Ninguno, [256], [0,256]) Hist es una matriz 256x1, cada valor corresponde al número de píxeles en esa imagen con su valor de píxel correspondiente. Se obtiene lo siguiente:
Fig.19. Histograma completo en base a la escala de grises.
Se puede utilizar trama normal de matplotlib, que sería bueno para la tra ma BGR. Para ello, primero debe buscar los datos del histograma. import cv2 import numpy as np from matplotlib import pyplot as plt img = cv2.imread('home.jpg') color = ('b','g','r') for i,col in enumerate(color): histr = cv2.calcHist([img],[i],None,[256],[0,256]) plt.plot(histr,color = col) plt.xlim([0,256]) plt.show() Lo que resulta en:
Fig.20. Altos valores de la imagen.
Usamos cv2.calcHist () para encontrar el histograma de la imagen completa. Si se desea encontrar histogramas en solo unas regiones de la imagen, basta con crear una imagen de máscara con color blanco en la región que desea encontrar el histograma y negro de lo contrario. img = cv2.imread('home.jpg',0) # create a mask mask = np.zeros(img.shape[:2], np.uint8) mask[100:300, 100:400] = 255 masked_img = cv2.bitwise_and(img,img,mask = mask) # Calculate histogram with mask and without mask # Check third argument for mask hist_full = cv2.calcHist([img],[0],None,[256],[0,256]) hist_mask = cv2.calcHist([img],[0],mask,[256],[0,256])
plt.subplot(221), plt.imshow(img, 'gray') plt.subplot(222), plt.imshow(mask,'gray') plt.subplot(223), plt.imshow(masked_img, 'gray') plt.subplot(224), plt.plot(hist_full), plt.plot(hist_mask) plt.xlim([0,256]) plt.show() En el gráfico del histograma, la línea azul muestra el histograma de la imagen completa mientras que la línea verde muestra el histograma de la región enmascarada.
Fig.20. Gráfico del histograma aplicando mascaras.
4.5.4 Generación de base de datos de imágenes de prueba.
Finalmente se genera un código empleando todo lo visto anteriormente. Para la segmentación y el reconocimiento de las palabras. Empleando código ASCII se logra el cometido del reconocimiento de letras. El código empleado es el siguiente: # TrainAndTest.py
import cv2 import numpy as np import operator import os
def checkIfContourIsValid(self): # this is oversimplified, for grade program if self.fltArea < MIN_CONTOUR_AREA: return False checking would be necessary
# declare empty lists, # we will fill these shortly
try: npaClassifications = np.loadtxt("classifications.txt", np.float32) # read in classifications except: print "error, unable to open classifications.txt, exiting program\n" os.system("pause") return # end try try: npaFlattenedImages = np.loadtxt("flattened_images.txt", np.float32) #
read in training images except: print "error, unable to open flattened_images.txt, exiting program\n" os.system("pause") return # end try
npaClassifications = npaClassifications.reshape((npaClassifications.size, 1)) shape numpy array to 1d, necessary to pass to call to train kNearest = cv2.ml.KNearest_create()
# re-
# instantiate KNN object
kNearest.train(npaFlattenedImages, cv2.ml.ROW_SAMPLE, npaClassifications) imgTestingNumbers = cv2.imread("test1.png") age if imgTestingNumbers is None: fully
# if image was not read success-
print "error: image not read from file \n\n" os.system("pause") return
# read in testing numbers im-
# print error message to std out
# pause so user can see error message # and exit function (which exits program)
# end if imgGray = cv2.cvtColor(imgTestingNumbers, cv2.COLOR_BGR2GRAY) grayscale image imgBlurred = cv2.GaussianBlur(imgGray, (5,5), 0)
# get
# blur
# filter image from grayscale to black and white imgThresh = cv2.adaptiveThreshold(imgBlurred, 255,
# input image # make pixels that pass the threshold
full white cv2.ADAPTIVE_THRESH_GAUSSIAN_C, ian rather than mean, seems to give better results cv2.THRESH_BINARY_INV, ground will be white, background will be black 11, to calculate threshold value 2)
# use gauss-
# invert so fore-
# size of a pixel neighborhood used
# constant subtracted from the mean
or weighted mean imgThreshCopy = imgThresh.copy() # make a copy of the thresh image, this in necessary b/c findContours modifies the image
imgContours, npaContours, npaHierarchy = cv2.findContours(imgThreshCopy, # input image, make sure to use a copy since the function will modify this image in the course of finding contours cv2.RETR_EXTERNAL,
# retrieve the outermost contours only
cv2.CHAIN_APPROX_SIMPLE) # compress horizontal, vertical, and diagonal segments and leave only their end points
for npaContour in npaContours: contourWithData = ContourWithData()
# for each contour # instantiate a contour with data object
contourWithData.npaContour = npaContour
# assign contour with data
contourWithData.boundingRect = cv2.boundingRect(contourWithData.npaContour) # get the bounding rect contourWithData.calculateRectTopLeftPointAndWidthAndHeight() # get bounding rect info contourWithData.fltArea = cv2.contourArea(contourWithData.npaContour) # calculate the contour area allContoursWithData.append(contourWithData) contour with data object to list of all contours with data
# add
# end for
for contourWithData in allContoursWithData: if contourWithData.checkIfContourIsValid():
# for all contours # check if valid
validContoursWithData.append(contourWithData) # end if # end for
validContoursWithData.sort(key = operator.attrgetter("intRectX")) tours from left to right
# sort con-
strFinalString = "" # declare final string, this will have the final number sequence by the end of the program
for contourWithData in validContoursWithData:
# for each contour
# draw a green rect around the current char cv2.rectangle(imgTestingNumbers,
imgROI = imgThresh[contourWithData.intRectY : contourWithData.intRectY + contourWithData.intRectHeight, # crop char out of threshold image contourWithData.intRectX : contourWithData.intRectX + contourWithData.intRectWidth] imgROIResized = cv2.resize(imgROI, (RESIZED_IMAGE_WIDTH, RESIZED_IMAGE_HEIGHT)) # resize image, this will be more consistent for recognition and storage npaROIResized = imgROIResized.reshape((1, RESIZED_IMAGE_WIDTH * RESIZED_IMAGE_HEIGHT)) # flatten image into 1d numpy array npaROIResized = np.float32(npaROIResized) ray of ints to 1d numpy arra y of floats
1)
# convert from 1d numpy ar-
retval, npaResults, neigh_resp, dists = kNearest.findNearest(npaROIResized, k = # call KNN function find_nearest
strCurrentChar = str(chr(int(npaResults[0][0]))) strFinalString = strFinalString + strCurrentChar full string # end for
# get character from results # append current char to
print "\n" + strFinalString + "\n"
# show the full string
cv2.imshow("imgTestingNumbers", imgTestingNumbers) with green boxes drawn around found digits cv2.waitKey(0) cv2.destroyAllWindows()
# show input image
# wait for user key press # remove windows from memory
return ##################################################################### ############################## if __name__ == "__main__": main() # end if
Conclusiones El proyecto se lo realizó pensando en la s múltiples utilidades que le vendrían bien a un estante que reconozca objetos o etiquetas. Principalmente pueden ser innumerables de pendiendo de la imaginación del usuario y de la perspicacia del programador. Puede utilizarse para reconocer alimentos en un refrigerador, elementos de medicina en una farmacia o simplemente insumos de cocina o alimenticios. Todo esto es gracias a que puede comunicarse por medio de una aplicación hacia un dispositivo Android y dar a conocer los valores del peso así como el reconocimiento de letras, colores o imágenes para distinguir los objetos en el interior del estante. Cabe recalcar que el procedimiento necesario para su funcionamiento fue muy largo y tedioso ya que no existen mucha información en español de la manera de trabajar con la visión artificial o en nuestro país no se ha inmerso lo suficiente en esta tecnología
References 1. 2. 3. 4. 5. 6. 7. 8.
https://es.wikipedia.org/wiki/Arduino http://www3.gobiernodecanarias.org/medusa/ecoblog/ralvgon/files/2013/05/Caracter%C3%Assticas-Arduino.pdf https://es.wikipedia.org/wiki/Raspberry_Pi http://www.omicrono.com/2016/02/raspberry-pi-3-model-b/ Capítulo IX Reconocimiento de Imágenes y Caracteres - Daisy Elizabeth Imbaquingo Es parza. http://www.aulaclic.es/articulos/wifi.html Wifi para Arduino con ESP8266, disponible en: http://83.56.32.125/esp8266.html https://en.wikipedia.org/wiki/ESP8266