# G4 - スマルト Touch

## Explicación del proyecto
スマルト Touch (o Smart Touch) es una herramienta de escritura digital que permite transcribir de forma fácil y rápida carácteres o palabras escritas en una pantalla táctil y guardarlos en un formato digital o visualizarlos en otro dispositivo.
Con スマルト Touch, se pretende dar visibilidad y concienciar sobre los problemas de discapacidad física a nivel de escritura y mejorar la accesibilidad e inclusión de las personas con dichas discapacidades de cara al uso de las tecnologías que nos rodean hoy en día.
## Casos de uso / interacción
Para darle una utilidad a nuestro prototipo, hemos planteado 5 escenarios/casos de uso ideales para sacarle el máximo provecho. Estos casos incluyen el uso del text-to-speech, botones, etc., además de funcionalidades futuras a implementar que podrían mejorar aún más la experiencia e interacción del usuario.
### Caso 1 - Dinámica educativa-pedagógica

En una hipotética situación de ubicarnos en una clase con una maestra y un grupo de niños que sufren de discapacidades relacionadas con la dificultad de lectura de textos o escritura, este prototipo les ayudaría a mejorar esas facultades gracias a una dinámica de aprendizaje que consiste en un alumno, con dificultad de escritura, practicando su caligrafía en el prototipo, pasa el mensaje mal escrito a un formato legible que luego a través del portal web desarrollado por nosotros también, el mensaje pasa a un ordenador conectado a una pizarra digital que permite pues mostrar los contenidos del mensaje a toda la clase. Esto permite que el resto de alumnos puedan aprender a leer leyendo lo se ha escrito en la pantalla de su compañero, además de habilitar a la profesora un proceso de análisis más ágil y eficiente a la hora de valorar el progreso que hacen tanto los alumnos que ven el mensaje en pantalla como el alumno que practica su escritura.
### Caso 2 - Evento social

En un evento social donde haya gente con diferentes tipos de discapacidades diferentes, que hay gente sorda, ciega, etc. como nuestra aplicación es todoterreno, todo el mundo podrá socializar, ya que si uno no ve, puede escuchar los mensajes, que uno que no puede escuchar, podrá leerlos, etc, etc. En general, permite habilitar la comunicación entre todos los participantes del evento, con o sin uso del text-to-speech.
### Caso 3 - Defensa judicial

En un escenario de carácter judicial como es el caso de una sala de juicio donde están presentes tanto el juez como ambos bandos (criminal y víctima) con sus respectivos abogados, aquella persona (sea criminal o víctima) que sufre de discapacidad (muda para ser más exactos), le ayudaría tener nuestro prototipo en mano al ponerse al estrado para defenderse de las preguntas de la oposición, que normalmente lo haría el abogado porque es el que está "capacitado" para poder responder a las respuestas de la oposición. En general, en este caso particular, utilizando nuestro prototipo, permitiríamos al mudo que pudiese defenderse a sí mismo, y utilizar el texto to speech para que todo el mundo en la sala pudiese oir su versión de la historia sin tener que recurrir a un elemento intermediario como es el abogado.
### Caso 4 - Rehabilitación médica

En un escenario hipotético de un paciente que es soldado de guerra, es decir, que sufre heridas tanto físicas como psicológicas, al tener dificultad para poder transmitir sus pensamientos a los médicos a la hora de escribir (mal) o hablar, nuestro prototipo le ayudaría a poder transcribir los mensajes de forma eficiente y utilizar la funcionalidad de text-to-speech para poder comunicarse con el personal médico de forma ágil, sin necesidad de tener que recurrir a otros medios tradicionales como es el papel, ya que no permite la legibilidad que tanto el paciente como el personal médico desearían tener.
### Caso 5 - Comunicación sordo-ciega

En un escenario donde se presentan un ciego y un sordo-mudo para comunicarse, nuestro prototipo ayudaría a solventar ese problema gracias a que, por un lado, el ciego con un teléfono móvil puede escuchar a través del text-to-speech del portal web desarrollado, el mensaje que el ciego escribe con el prototipo. A su vez, el sordo-mudo puede recibir los mensajes del ciego con una funcionalidad futura a implementar que consiste en la transcripción de audio a texto para que le pueda llegar los mensajes hablados al sordo-mudo y habilite la comprensión lectora de forma ágil.
## Departamento de Pantalla
### Objetivo
El objetivo del departamento de pantalla es conseguir que al encender la Raspberry Pi automaticamente aparezca una ventana con un terminal conectado a un tópico mqtt y otra ventana con una aplicación de escritura.
### Material
* Raspberry Pi model 4
* Pantalla tactil:
[ELECROW - Pantalla táctil de 5 pulgadas 800x480px](https://www.amazon.es/elecrow-Raspberry-Pantalla-Windows-Widerstand/dp/B07H7899W5)
* Botones para PCB:
[RUNCCI-YUN - Botón interruptor 80pcs 12 x 12 x 7.3 mm 5 colores](https://www.amazon.es/dp/B07WPBQXJ9)
* Mini ventilador:
[GeeekPi - Ventilador Raspberry Pi 30x30x7mm DC 5V](https://www.amazon.es/dp/B07FVR3TB8)
* Placa PCB y cables
### Preparación
Descargar [Raspberry Pi Imager](https://www.raspberrypi.com/software/) para poder crear una imagen la SD.
Nosotros elegimos instalar SO Lite de 64 Bits, porque no necesitamos un entorno de escritorio completo.
Una vez configurada y creada la imagen, pasamos a la instalación de la pantalla.
### Montaje de la pantalla
La pantalla se conecta a la Pi usando el socket de 13x2 pines y queda perfectamente encajada.
La caja de la pantalla trae un lapiz de tipo nintendo DS y dos adaptadores, uno de HDMI a HDMI (Para Raspberry Pi model 3) y otro HDMI a micro-HDMI (Para Raspberry Pi model 4). El adaptador HDMI tambien queda perfectamente encajado en la Raspberry Pi.
### Instalación y configuración de la pantalla
Encendemos la Raspberry Pi y nos conectamos mediante SSH:
```
SSH g4@touch.local
```
En nuestro caso g4 es el nombre de nuestro usuario y touch el nombre de nuestro dispositivo Raspberry Pi. Alternativamente también se podria acceder usando la dirección IP del dispositivo.
Una vez abierto el terminal, accedemos al archivo de configuración del booteo
`sudo nano /boot/config.txt`
y añadimos las siguientes lineas de codigo al final del archivo:
```
# --- added by elecrow-pitft-setup ---
hdmi_force_hotplug=1
max_usb_current=1
hdmi_drive=1
hdmi_group=2
hdmi_mode=1
hdmi_mode=87
hdmi_cvt 800 480 60 6 0 0 0
dtoverlay=ads7846,cs=1,penirq=25,penirq_pull=2,speed=50000,keep_vref_on=0,swapxy=0,pmax=255,xohms=150,xmin=200,xmax=3900,ymin=200,ymax=3900
display_rotate=0
# --- end elecrow-pitft-setup ---
```
Si estamos usando una Raspberry Pi 4 también tenemos que comentar la linea de codigo del archivo que pone `dtoverlay = vc4-fkms-V3D`
A continuación, ejecutamos las siguientes comandas para poder instalar los drivers de la pantalla:
```
sudo apt-get update
sudo apt-get install git
git clone https://github.com/goodtft/LCD-show.git
chmod -R 755 LCD-show
cd LCD-show
sudo ./LCD5-show
```
Despues reiniciamos la Pi y ya deberiamos ver la pantalla en funcionamiento.
### Instalación de MQTT y Node-red
Mosquitto (MQTT) es un software que nos permite conectarnos a un broker , en nuestro caso será nuestra propia Pi.
Para instalar MQTT ejecutamos en el terminal:
```
sudo apt install mosquitto mosquitto-clients
```
Para permitir que cualquiera pueda publicar y recibir mensajes hay que editar el archivo de configuración de MQTT `sudo nano /etc/mosquitto/mosquitto.conf`
Y agregamos estas lineas al final del archivo:
```
listener 1883
allow_anonymous true
listener 9001
protocol websockets
```
Finalmente reiniciamos MQTT con `sudo systemctl restart mosquitto`
Node-RED es una herramienta de desarrollo basada en flujos para programación visual que usaremos para el software de este proyecto.
Para instalar Node-RED ejecutamos la siguiente comanda:
```
bash <(curl -sL https://raw.githubusercontent.com/node-red/linux-installers/master/deb/update-nodejs-and-nodered)
```
Una vez terminada la instalación, para iniciar el servidor node-red podemos ejecutar:
```
sudo systemctl start nodered.service
```
Y para que se inicie siempre al arrancar nuestra raspberry ejecutamos:
```
sudo systemctl enable nodered.service
```
### Instalación y configuración de Xorg
Xorg es un entorno gráfico que usaremos como base para los siguientes procesos de nuestro proyecto.
Para instalar Xorg, abrimos un terminal y ejecutamos:
```
sudo apt-get install xorg
```
Para iniciar Xorg ejecutamos:
```
startx
```
Como nuestro objetivo es que al encender la Pi directamente se ejecute Xorg, tenemos que editar el archivo bashrc `sudo nano ~/.bashrc`
Y añadimos al final del archivo:
```
if [[ -z $DISPLAY ]] && [[ $(tty) = /dev/tty1 ]]; then
startx
fi
```
Ahora si reiniciamos la Pi veremos que accede directamente a Xorg.
### Instalación y configuración de Xournal++
Xournal++ es una aplicación de escritura que usaremos para capturar el texto escrito.
Para instalar Xournal++ abrimos un terminal y ejecutamos:
```
sudo apt-get install xournalpp
```
Nosotros tuvimos problemas con las dependencias así que optamos por una alternativa que es instalar Xournal++ desde la [Snap Store](https://snapcraft.io/install/xournalpp/raspbian):
```
sudo apt-get update
sudo apt install snapd
sudo reboot
sudo snap install core
sudo snap install xournalpp
```
Para abrir Xournal++ ejecutamos:
```
sudo snap run xournalpp
```
Dentro de Xournal++ debemos ir a preferencias y activar la opción de permitir la escritura usando el lapiz tactil y también activar alguno de los métodos de smoothing a nuestro gusto.
### Instalación y configuración de i3
i3 es un gestor de ventanas para Linux que usaremos para poder visualizar en la pantalla a la vez un terminal suscrito a un tópico MQTT y Xournal++
Para instalar i3 abrimos un terminal y ejecutamos:
```
sudo apt-get install i3
```
Para conseguir que al encender la Raspberry Pi aparezca en la pantalla una ventana en la parte superior con un terminal suscrito a un tópico MQTT y una ventana en la parte inferior con Xournal++, tenemos que hacer unas configuraciones.
En el archivo de configuración de i3 `sudo nano /etc/i3/config` añadimos al final:
```
# exec i3-config-wizard
# Configuración para las ventanas de xterm y Xournal++
set $mod Mod1
# floating_modifier $mod
# workspace "1"
exec_always /home/g4/startup.sh
exec_always /home/g4/buttons.sh
for_window [class="XTerm"] floating enable, move position 0px 0px, resize set 800px 60px, border none
for_window [class="Xournalpp"] floating enable, move position 0px 60px, resize set 800px 420px, border none
```
Creamos un script startup `sudo nano /home/g4/startup.sh` con el siguiente contenido:
```
#!/bin/bash
# Establecer la variable de entorno DISPLAY en la pantalla predeterminada
export DISPLAY=:0.0
# Abrir terminal en la parte superior de la pantalla
i3-msg 'exec xterm -e /usr/bin/mosquitto_sub -h touch.local -t touch_topic'
# Abrir Xournal++ en la parte inferior de la pantalla
i3-msg 'exec xournalpp; floating enable'
# Configurar la disposición de las ventanas
i3-msg "workspace 1; layout splitv; split v"
```
Este script ejecuta los comandos i3-msg para abrir un terminal suscrito al topico MQTT y la aplicación Xournal++ tal y como hemos configurado anteriormente en el archivo de configuración de i3.
Ahora si reiniciamos la Raspberry Pi deberiamos tener las ventanas configuradas como deseamos.
### Instalación y configuración de los botones
Tenemos que conectar los botones siguiendo este esquema:

* PIN 4 (5V): Pin de 5 Voltios para conectar el ventilador
* PIN 6 (Tierra): Pin de tierra para conectar el ventilador
* PIN 7 (GPIO 4): Botón verde
* PIN 9 (Tierra): Conexión de tierra para los botones
* PIN 11 (GPIO 17): Botón amarillo
* PIN 13 (GPIO 27): Botón rojo
* PIN 15 (GPIO 22): Botón negro
Hemos decidido soldar unos pines en la pantalla para poder hacer las conexiones facilmente usando cables en vez de soldar directamente cada cable a la pantalla:

Los botones los soldamos en una placa PCB con un circuito que conecte una pata de cada botón a tierra y la otra en el GPIO correspondiente. Tambien soldamos un mínimo de 5 pines (4 para GPIO y 1 para Tierra). De esta forma para hacer la conexión de la PCB a la pantalla solo necesitamos 5 cables hembra a hembra.


Finalmente así queda el resultado con todos los componentes conectados:

Para detectar los botones y darles una funcionalidad creamos un script de python buttons `sudo nano /home/g4/buttons.sh` con el siguiente contenido:
```
#!/usr/bin/env python3
import os
os.environ['DISPLAY'] = ':0'
import subprocess
from gpiozero import Button
from time import sleep
button4 = Button(4)
button17 = Button(17)
button27 = Button(27)
button22 = Button(22)
while True:
if button4.is_pressed:
print("Green Pressed")
subprocess.run(["import", "-window", "root", "-crop", "760x360+20+120", "/home/g4/images"])
subprocess.run(["xdotool", "key", "--clearmodifiers", "ctrl+d"])
sleep(1)
if button17.is_pressed:
print("Yellow Pressed")
subprocess.run(["xdotool", "key", "--clearmodifiers", "ctrl+d"])
sleep(1)
if button27.is_pressed:
print("Red Pressed")
sleep(1)
if button22.is_pressed:
print("Black Pressed")
sleep(1)
```
Con este script detectamos si se pulsa un botón en el GPIO 4, 17, 27 y 24 que es donde tenemos conectados los botones fisicamente y realizamos una función concreta con cada uno:
* Botón verde (GPIO 4): Hacemos una captura de la pantalla en la zona de la aplicación Xournal++ y borramos todo el contenido escrito en ella. La captura es detectada y procesada por node-red automaticamente.
* Botón amarillo (GPIO 17): Borramos todo el contenido escrito en la aplicación Xournal++ pero esta vez sin hacer captura.
* Botón rojo (GPIO 27): En este script simplemente lo detectamos pero no tiene ninguna funcionalidad. Node-red detecta cuando se pulsa este botón y borra la ultima letra escrita del mensaje.
* Botón negro (GPIO 22): En este script simplemente lo detectamos pero no tiene ninguna funcionalidad. Node-red detecta cuando se pulsa este botón y borra todo mensaje escrito ahora.
### Realización de la maqueta
Para poder realizar la maqueta, primero se hizo un diseño con todas las medidas de la carcasa juntamente con las medidas de la pantalla y los botones para poder crear los agujeros.



Una vez teníamos el diseño hecho, procedimos a realizar la primera maqueta. La carcasa la hicimos con una caja de Amazon de cartón y SuperGlue para poder unir cada parte de la carcasa.

Una vez teníamos la maqueta hecha, hicimos test de usabilidad, en la que se llegó a dos conclusiones. La primera conclusión fué hacer más grande el agujero de la parte de atrás de la carcasa porque no había espacio para el cable de alimentación.

Y la segunda conclusión fué decidir donde iban a ir los agujeros para la correcta ventilación de la Raspberry Pi.

### Modelaje e impresión 3D de la carcasa
Siguiendo las medidas de los bocetos se empezó a desarrollar un modelo 3D de la carcasa.
**Primera Versión:**




Después de modelar esta primera versión vimos que el saliente superior era un poco innecesario y que con dejar solo el hueco ya nos iba bien (y facilitaba la posterior impresión 3D).
Al hacer el test de usabilidad con la caja de cartón nos dimos cuenta de que había que hacer algún cambio en algunas medidas y que hacía falta ampliar el agujero de arriba. Esos cambios se aplicaron al modelo de cara a la siguiente versión.
También cambiamos los agujeros inferiores para la ventilación y las esquinas de la caja, ya que con ese perfil de curva el plástico no tiene apoyo suficiente y la impresión 3D no habría salido bien.
Finalmente, separamos la parte trasera de la carcasa para que hiciera de tapa y añadimos cuatro piezas en la otra parte de la carcasa para así poder ponerle los tornillos para cerrarla.
**Segunda Versión:**





Una vez acabada y revisada esta segunda versión pasamos ya a imprimir la carcasa.
**Primera impresión:**

Como se puede apreciar en la imagen, la primera impresión no salió bien debido a que la impresora 3D se quedó sin hilo y no acabo toda la carcasa. Aun así nos sirvió para ver que los botones encajaban perfectamente y que hacía falta incrementar un poco la distancia del marco de la pantalla, tanto por arriba como por abajo.
**Segunda impresión:**




Esta segunda impresión se pudo realizar con éxito y, como se puede ver en las imágenes, el resultado final fue bastante bueno.
## Departamento de Software
### Objetivo
El objetivo del departamento de software es el conseguir que, todo aquello que se escriba en la pantalla se interprete, se pase a texto y se limpie de incorrecciones para luego ser publicado en un tópico MQTT y se pueda ver de vuelta en la pantalla.
### Material
- Un ordenador
- Software de Node-RED
- Una raspberry pi para su implementación
### Preparación y problemas iniciales
Para poder empezar con la parte de software del proyecto, se necesitaba instalar Node-RED en la Raspberry Pi, pues es donde estaría corriendo el código en el proyecto final.
No obstante, fue aquí donde nos encontramos con un problema el cual, mientras su soloción era fácil, volvía la implementación un proceso tedioso.
Resulta que sólo disponíamos de una Raspberry Pi, por lo que todo el código tenía que ser desarrollado y comprobado desde un ordenador externo, sin saber si la Raspberry podría correr el código.
No obstante, el procedimiento a la hora de desarrollar resultaba el mismo, con la única diferencia siendo que tendríamos que copiar los nodos manualmente a la hora de juntar los avances de software y hardware, por lo que no hubo parón alguno.
### Nodos utilizados
- Inject node: Este nodo es usado cuando se quiere ejecutar una parte del código mediante el envío de datos (que activan los nodos siguientes) o cuando se requiere insertar contenido específico en el payload del mensaje (como se ha hecho para el caso de querer borrar el mensaje).
- Watch node: Este nodo es utilizado cuando se quiere una observación de un archivo del sistema, enviando una señal cuando se ha cometido un cambio en el fichero observado (parecido en modo al inyector, pero en modo automático). En nuestro caso se ha utilizado para la detección de una nueva imagen a analizar.
- Read file node: Este nodo es utilizado cuando, tal como indica su nombre, se quiere leer un fichero del sistema para ser usado en node-red. Esta lectura se puede llevar a cabo de divrsas maneras, siendo la escogida la lectura en formato *buffer*, pues era el método más fácil para la lectura de imágenes. El problema que conlleva este nodo es que necesita de un trigger para activarse, y es por ello que se tuvo que añadir el inyector/watcher.
- Image Tools Nodes: Esta [libreria de nodos](https://flows.nodered.org/node/node-red-contrib-image-tools) aporta diferentes aplicaciones para las imágenes que se leen en node red, ya sea desde un visualizador hasta un procesador de imágenes (para recortar, pixelar, subir o bajar el contraste...). Mientras que se hicieron diversas pruebas para mejorar la lectura y la eficacia del algoritmo (ver [Implementación](#Implementación-en-la-Raspberry-Pi), al final solamente se usó el visualizador, pues nos facilitaba el trabajo dentro de node-red)
- Tesseract node: Este nodo es el encargado de realizar la fuerza bruta del proyecto, pues es el encargado de la detección de texto en la imagen. Aunque la librería utilizada te permite introducir diferentes tipos de información, al final decidimos usar el *buffer binario*, pues no tendríamos que realizar ningún cambio. (más información en [Tesseract](#Tesseract-y-la-búsqueda-de-un-OCR))
- Function nodes: Estos nodos se han utilizado cuando se requería de código para llevar a cabo una fase del proyecto. En este caso, se han utilizado para la [limpieza de las string](#Limpieza-del-mensaje) que exporta el algoritmo de Tesseract y para algunas de las [acciones extra](#Acciones-extra), tales como el borrar el mensaje.
- Debug nodes: Estos nodos son utilizados como soporte en el desarrollo de proyectos de node-red, pues te permiten mostrar la información del mensaje que pasa por el nodo, ya sea el tópico o la payload, en formato de consola web o la consola propia de node-red. En este caso en concreto se han utilizado, no sólo para estar seguros que cada paso se está realizando correctamente, sino que permite saber cierta información del output del algoritmo, como por ejemplo el *Confidence Level* de una transcripción, siendo este nodo el único que puede mostrarlo.
- MQTT nodes: Los nodos MQTT de node-red tienen como funcionalidad actuar como publisher de un tópico (MQTT Out) o como listener (MQTT In). Dentro de dichos nodos tienes la opción no sólo de indicar el *Broker* al que conectarse, sino también a qué tópico tienen que enviar información / escuchar. En este caso, se ha usado el nodo MQTT Out para devolver el mensaje generado de vuelta a la pantalla.

### Tesseract y la búsqueda de un OCR
Uno de los pasos del proyecto, y de hecho el más vital, era no solo encontrar la manera de cómo podíamos leer el texto de una imagen, sino el cómo podíamos hacerlo desde un proyecto de node-red conectado a una raspberry pi la cual, aunque relativamente capaz y útil, no es tan potente como un ordenador.
Este punto se consideró vital en el inicio del proyecto debido a que el objetivo y el desarrollo de la práctica era directamente dependiente del hecho de que este paso fuera posible, ya que en caso contrario tendríamos que replantear el proyecto.
La primera idea que se barajó fue, mediante un algoritmo de inteligencia artificial creado en python, crear un modelo entrenado con la base de datos del [EMNIST](https://www.nist.gov/itl/products-and-services/emnist-dataset) (una base de datos de números y letras) que fuera capaz de detectar lo que se escribiera.
No obstante, a la que se empezó a investigar, rápidamente nos dimos cuenta de que la complejidad estaba muy por encima de los requeridos por el proyecto, por lo que fue rápidamente descartada.
El paso siguiente fue, viendo que no íbamos a poder crear nosotros el modelo, intentar buscar alguno público que ya estuviera creado, y simplemente retocarlo para nuestras necesidades. Fue en este entonces cuando encontramos los OCR (Optical Character Recognition), de los cuales ya había modelos.
Después de buscar y de disponer de varias opciones, el siguiente paso era su importación a node-red. Y allí nos encontramos con otro problema, pues no solo la implementación de python en node-red es excesivamente compleja (ya sin contar el tener que leer y ejecutar un script externo a node-red) sino que estos modelos eran más pesados de lo que la memoria de la raspberry pi podía soportar, ya que están pensados para ser ejecutados en ordenadores o servidores.
Lo que hicimos entonces fue buscar directamente en el buscador de nodos de node-red, pues si encontrábamos algún modelo allí, significaría que estaría suficientemente optimizado para su uso en el proyecto, más allá de facilitarnos muco el proceso a nosotros. Aunque no encontramos ningún OCR de python, nos encontramos con [Tesseract](https://tesseract.projectnaptha.com/).
Tesseract es un OCR desarrollado por Google el cual dispone de un port completo a Javascript, lenguaje utilizado por defecto en node-red (puesto que está construido sobre node, el cual está creado con javascript) y del que se disponía deferentes nodos creados por la comunidad.

Después de investigar sobre cuál nos iría mejor, obtuvimos dos finalistas: [node-red-contrib-tesseract](https://flows.nodered.org/node/node-red-contrib-tesseract) y [@martip/node-red-ocr](https://flows.nodered.org/node/@martip/node-red-ocr), ya que eran los más completo, los que tenían más descargas, y los que estaban mejor documentados. Al final acabamos decantándonos por el primero por una razón muy simple. Aunque no perfecto (pues las transcripcioes rondan la media del 60% de *Confidence Level*), era el único que funcionaba, ya que el segundo no aceptaba la imagen (aunque se introdujera en el modo indicado en la documentación).

### Limpieza del mensaje
Uno de los problemas que representaba la no-óptima transcripción del modelo era que en muchos casos no devolvía lo que se había escrito. Aunque en los casos menos precisos simplemente con borrar el mensaje o letra y reescribirlo ya servía, había muchos casos donde el mensaje sí era correcto, pero había ruido.
Entre este ruido, destacaban la aparición de comillas (') o puntos (.) extra, debido a posibles temblores a la hora de escribir o de algún trazo extra que se hubiera realizado en la pantalla. Además, también destaca la aparición de carácteres de fin de línea (\n, p.ex.), los cuales eran introducidos por el algoritmo debido a su característica de detección de texto multi-línea (el cual no utilizábamos en nuestro caso, por lo que para nosotros contaba como ruido).
La solución que decidimos utilizar fue el análisis y formateo del output del algoritmo mediante el uso de una función directamente en node-red, aprovechándonos de las capacidades de javascript.

En resumen, lo que se está llevando a cabo en esta función es el reemplazo de los carácteres no deseados en favor de espacio en blanco, lo que en la práctica los elimina. Para evitar mensajes potencialmente maliciosos o corruptos, se usa la función try-catch, permitiendo correr código en caso de que la función de reemplazar fallase.
Una de las ventajas que conlleva esta forma de formateo de strings, es que es ampliable, lo que te permite poner más detalle en la corrección, como sería el caso de corregir el caso de @ a o (un error que nos hemos encontrado más de una vez). No sólo esto, también se podría usar para poder eliminar mensajes maliciosos en caso de que el usuario final pudiese ser una persona menor o en riesgo (con el uso de ****, por ejemplo).
### Acciones extra
Aunque en este punto ya disponíamos de una imagen pasada a texto y disponible para ser enviada de vuelta a la pantalla, aún le faltaban diversos requisitos y características que queríamos que tuviera la aplicación, y que tendríamos que añadir a mano.
Una de estas er la opción de poder borrar lo que se escribiera, ya fuese sólo la última letra como si se quería borrar todo el mensaje, así como la capacidad de ir alineando outputs del algoritmo por si se quería crear una oración entera compuesta de múltiples palabras escritas una a una (y no sólo la última palabra que se ha escrito), con su respectivo espacio.
Para la realización de este paso, se utilizó un método muy parecido al método utilizado en la limpieza de strings, es decir, también se hizo uso de un nodo de función y se aprovechó las capacidades de javascript para el formateo de strings.

En el caso de esta función, lo que se está realizando es, según el payload del input que se recibe, se ejecuta una opción u otra, en este caso el borrar o el concatenar el mensaje del algoritmo.
Este método, al igual que el anterior, es ampliable a nuevas características, ya que al nodo de funcion se le pueden introducir múltiples entradas, cada una con una payload diferente caracterizado por una palabra clave indicativa (como "CLEAN") y (en caso de cambiar el if a un switch, mucho más óptimo) su funcionalidad correspondiente, como sería el añadir espacios, borrar carácteres...
### Implementación en la Raspberry Pi
Una vez el código estuvo desarrollado, sólo quedaba un paso más: implementarlo en la raspberry para no necesitar de un ordenador al ejecutar el proyecto. Para dicha implementación, teníamos que seguir ciertos pasos.
El primer paso de todos, era conseguir que la imagen se leyera correctamente y que el mensaje se mostrara en la pantalla. Mientras que la parte de la imagen fue fácil, ya que sólo teníamos que cambiar el *path* de la imagen, la pantalla dio más problemas.
En un principio, la idea que se tenía era utilizar una aplicación y mostrar por allí el texto, pero eso conllevaba un nivel de complejidad que, como el caso del modelo, no era necesario en el proyecto. Al final se utilizó MQTT en parte también al hecho de que node-red ya incorpora nodos de MQTT, por lo que enviar el mensaje de vuelta a la pantalla se transformaba en un trabajo mucho más asequible.

Una vez estuvieran todos los nodos, quedava pasarlo a la raspberry pi. Para esto, fuimos copiando los nodos a mano, funciones incluidas, desde el node-red del ordenador al node-red de la raspberry pi.
Hasta que vimos la opción de importar y exportar flows, lo que nos permitía incluso no tener que estar físicamente los dos departamentos a la vez ya que podíamos enviar el fichero a traves de mail o un chat (ya que la exportación en en formato JSON).
Sin embargo, no todo fue como queríamos. dadas las limitaciones de la pantalla a la hora de escribir el texto, la imagen generada no era leída correctamente por el algoritmo, por lo que no exportaba nada, o exportaba mucho ruido (que no era nada parecido a lo que se había escrito).
Una de las soluciones que se internaron llevar a cabo fue mediante nodos de procesamiento de imagen, utilizando funciones tales como la pixelación, compresión, convolución, erosión... Sin embargo, ninguna combinación que utilizamos nos daba el resultado que queríamos, ya que las pocas veces que sí exportaba información, no lo hacía de manera consistente.
El resultado llegó casi por accidente, pues un día, haciendo pruebas con la aplicación de escribir (probando colores, tamaños de lápiz...) se decidió hacer una captura para ver qué exportaba si tenía como input una imagen random. Fue entonces cuando nos dimos cuenta que con ampliar al tamaño del lápiz ya bastaba para leer la imagen consistentemente, y que no se necesitaba el aplicar procesado de imagen.
Ejemplo de lo que se vería (aunque sin la patalla):

### Retoques del modelo de Node-Red
Dado que en lo que hace referencia al Node-Red ya estaba casi completo, lo único que se hizo fue retocar un par de funciones existentes, y añadir un par de nodos más: los GPIO in.

Los nodos GPIO in eran necesarios para poder “comunicarnos” con el modelo creado en Node-Red de manera externa al programa, es decir, mediante botones conectados directamente a la Raspberry PI. La única dificultad que se encontró al añadir estos nuevos nodos fue que los números de los pines no correspondían al numero identificativo del pin, por lo que tuvimos que ayudarnos de una imagen de internet (por ejemplo, el pin número 15 de la imagen tenía como identificativo GPIO27).
Con la nueva implementación de los nodos, también se tuvo que crear funciones adaptativas (nodos de función “ERASE” y “CLEAN”), puesto que los nodos GPIO solo exportan como payload el valor 0 o 1 dependiendo de si están activados o no, mientras que, tal y como teníamos estructurado el código en la función “Message”, necesitábamos que el payload y el tópico tuvieran unos valores concretos, pues si no podría llegar a exportar cosas que no querríamos.
La función “Message” también ha recibido algún que otro cambio, de los cuales destacan el cambio de “ifs” a un “switch” para añadirle más escalabilidad al modelo, así como la creación del nuevo método “ERASE”, el cual borra la última letra del mensaje en vez de borrarlo entero.

### Aplicación web de soporte para el sistema
Otra de las características del proyecto a nivel de software, más allá del modelo creado en Node-Red, es la creación de una página web de soporte donde se puedan llevar a cabo otras dos actividades diferentes.
Por una parte, está el poder conectarse a una IP para escuchar un bróker de MQTT y así poder ver qué mensajes están apareciendo en un tópico en concreto (el cual lo llamamos “touch_topic”), apareciendo en la página web, cambiando cada vez que hay un mensaje nuevo.
Por otra parte, otra de las características que dispone la aplicación web es, una vez se ha recibido un mensaje, tener la posibilidad de que un sistema de text-to-speech que lo diga en voz alta solo apretando un botón.
Para lo que representa la página web, esta se tuvo que estructurar un poco, pensando sobretodo en que pudiera ser usable y no muy incómoda de navegar y de ver. Es por eso que la aplicación en si está estructurada en diferentes páginas:
- La página de inicio, donde como usuario debes introducir la IP donde se sitúa el bróker MQTT (debes estar en la misma red que el bróker para que esto funcione). Si introduces una IP equivocada, aparecerá un error explicando cómo tienes que hacerlo.
- La página de error, que aparece en caso de que no puedas conectarte al bróker, ya sea porque no está encendido, te has equivocado de IP o estés en otra red, desde donde vas a poder volver a la pantalla principal.
- La pantalla del mensaje, donde van apareciendo los nuevos mensajes del tópico, y donde hay un botón para poder decirlo en voz alta.

Para la realización de la aplicación se han utilizado todo tipo de tecnologías del ámbito de la programación web, siendo varias de ellas tecnologías punta. Se puede separar la aplicación en 3 grandes apartados:
- Para la creación de la web en si, se ha utilizado Vue, así como sus librerías auxiliares tales como vue-router (para poder tener varias páginas web dentro de una misma aplicación). Se ha utilizado este framework en concreto más que nada por la habitualidad de los desarrolladores con esta tecnología, pues ha se han realizado otros proyectos y la tecnología es conocida y cómoda.
- Para el apartado de diseño, primero se han dibujado los sketches y wireframes de como queríamos que se viera la aplicación y cada una de las pantallas, para luego ser pasadas a código. Para esta parte, se ha hecho uso de una librería llamada Vuetify, un design system que nos provee de componentes estándar (aunque altamente customizables) de modo que la aplicación tendría una sensación de unidad, integridad y profesionalidad.
- Para hacer el deployment de la aplicación a internet se acabó utilizando Vercel y, aunque había otras alternativas tales como Heroku o GitHub Pages, ésta resultó la única que nos daba lo que pedíamos. Para lo que es el deploy en sí, o único que tendríamos que hacer nosotros como desarrolladores sería publicar el proyecto en GitHub, y Vercel ya se encargaría de subirlo a internet. La página web se puede encontrar [aquí](https://smart-touch.vercel.app/).

No obstante, también se hace uso de otras tecnologías y librerías las cuales, aunque no destacan mucho a primera vista, son las que hacen todo el trabajo sucio de la aplicación. De estas, destacan la librería para las conexiones MQTT, y la librería del text-to speech.

Para las conexiones MQTT, se hace uso de una librería de node llamada “mqtt”, la cual se conecta con el bróker mediante un protocolo WebSockets (debido a ejecutarse desde un navegador), aunque a nivel práctico no haya diferencia con una conexión directa.
Inicialmente no se iba a utilizar esta, sino que la aplicación se estaba desarrollando originalmente con una librería llamada PAHOMqtt pero, como con la implementación de HTTPS se requieren de protocolos más seguros (y PAHO solo disponía de ws://), se tuvo que descartar en frente de esta otra.
Aun así, hubo bastantes problemas en lo que refiere a poder hacer uso de la librería, debido a algunas incompatibilidades con los builders (en esta ocasión se utiliza uno llamado Vite, que es el predeterminado en una aplicación hecha con Vue), ya que no nos permitía hacer uso de las variables de la librería, como el poder llamar a la variable “Client”. Tras investigar por mucho tiempo, nos dimos cuenta de que, si en vez de instalar e importar la librería en el proyecto, utilizábamos un CDN (el mismo código, pero subido a internet), no nos aparecían más errores ya que conseguíamos dar la vuelta.
Para las librerías de text-to-speech, también tuvimos diversos problemas hasta encontrar la solución.

El primero de todos, es el hecho de que hay mucha escasez de librerías de text-to-speech que funcionen en un navegador ya que, mientras que desde una aplicación uno puede acceder al sistema de audio de un dispositivo, no es el caso cuando hay un navegador de por medio. Además, de las de por si pocas librerías que existen, hay algunas que están o bien obsoletas o bien directamente no funcionan por problemas internos, como fue el caso de una de las librerías que probamos, llamada “text-to-speech-js”.
Al final, tras mucho tiempo también, conseguimos encontrar una que no solo cumplía con lo que queríamos, sino que además nos daba un abanico de customización muy grande, aunque solo fuéramos a utilizar una parte pequeña de la librería. Esta se llama “speak-tts”, y dispone de más de 15 idiomas diferentes (incluido el catalán), capacidad para poner audios en búfer para que vayan sonando y capacidad para alterar características de los audios tales como el pitch o el volumen.
Con todo puesto en su sitio y funcionando correctamente, ya se puede dar por acabada la primera versión de nuestra aplicación web de soporte para el sistema de la Raspberry PI. Aún así, aún se pueden ir añadiendo funcionalidades, así como retocar y pulir aquellas que no acaban de convencer por el momento.
### Retoques de la aplicación web
Aunque a grandes rasgos la aplicación ya estaba acabada, pues ya disponía de todas sus características importantes (recibir y mostrar el mensaje y poder escucharlo mediante text-to-speech), nos dimos cuenta de que teníamos un problema, sobre todo en el contexto en el que se iba a utilizar nuestro proyecto: la aplicación web no era muy usable.
No obstante, dada nuestra experiencia estudiando ingeniería multimedia, teníamos bastante claro qué podíamos retocar al fin de conseguir una aplicación usable finalmente.
El primer cambio que se hizo fue el añadir una pantalla de bienvenida al portal web ya que antes no existía, haciendo que nuestra aplicación tuviese un aire mucho más profesional a la vez que la hacía mucho más agradable en su uso.

Aunque la paleta de colores no la cambiamos ya que ya disponía del contraste que buscábamos, sí que hicimos la aplicación “más grande”. Ampliamos el tamaño de los botones, así como el tamaño del texto y la separación entre ellos ya que, si la aplicación iba a ser potencialmente usada con gente con problemas o discapacidad, queríamos reducir al máximo la confusión y errores generados por la aplicación.
## Vídeo de demostración del proyecto
[Vídeo aquí](https://youtu.be/m3UxLZgIkvw)