diff --git a/Readme.md b/Readme.md index 11a5197..2ed4208 100644 --- a/Readme.md +++ b/Readme.md @@ -168,19 +168,161 @@ En primer lugar, se importan todas las librerías o módulos necesarios, previam ``` from threading import Thread import collections -import matplotlib.pyplot as plt #Gráficación de datos -import matplotlib.animation as animation #Animar la gráfica -import time #Delays -import serial #comunicación con el monitor serial de Arduino -from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg #Crear una figura para insertar en tkinter -import tkinter as tk #Para la interfaz -from matplotlib.lines import Line2D #Para hacer las líneas de las gráficas +import matplotlib.pyplot as plt +import matplotlib.animation as animation +import time +import serial +from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg +import tkinter as tk +from matplotlib.lines import Line2Ds ``` -Aquí se encuentran las funcionaes necesarias para: crear hilos con *threading*, hacer una colección o lista con los datos a graficar con *collections*, dibujar los datos en una gráfica animada con líneas 2D y visualizarla en la interfaz utilizando los módulos de la librería de *matplotlib*, establecer la comunicación serial con Arduino usando *serial*, el diseño de la interfaz se hace con el paquete *tkinter* y finalmente, se importa *time* para ocupar algunos retardos de tiempo. +Aquí se encuentran las funcionaes necesarias para: crear hilos con `threading`, hacer una colección o lista con los datos a graficar con `collections`, dibujar los datos en una gráfica animada con líneas 2D y visualizarla en la interfaz utilizando los módulos de la librería de `matplotlib`, establecer la comunicación serial con Arduino usando `serial`, el diseño de la interfaz se hace con el paquete `tkinter` y finalmente, se importa `time` para ocupar algunos retardos de tiempo. A continuación, el código dispone de una serie de funciones que son llamadas entre sí y se utilizan también en los distintos objetivos de la interfaz para mostrar la información recibida de Arduino y mantener la interacción con el usuario: +Para comenzar, se declaran ciertas variables, aquellas cuyo valor es modificado dentro de alguna función se definen como globales, el resto se inicializan de manera normal. + +``` +global isRun +global on1 +global on2 +global conected +conected = False +on1 = False +on2 = False +isReceiving = False +isRun = False +numData = 2 #Número de datos a recibir de Arduino +datos = 0.0 #Variable de dato a leer desde Arduino +dato = 0.0 #Variable del dato convertido a float +serialPort = 'COM3' #Puerto al que está conectado el Arduino +baudRate = 9600 #Baudios configurados en Arduino +estado = "off" #Variable de estado que se enviará al serial +``` + +La variable `isRun` representa si la función de lectura y graficación de datos está corriendo, `on1` y `on2` son los estados de encendido o apagado en que se encuentran los transistores, mientras que `isReceiving` confirma que se han recibido datos correctamente. `numData` hace referencia a que se recibirán 2 datos desde Arduino, correspondientes al sensor 1 y 2, `datos` es la información leída desde Arduino en forma de string, `dato` es la variable dato leído convertido a flotante, `serialPort` es el puerto al que se encuentra conectado el micrcontrolador, `baudRate` es la velocidad de comunicación a la que está trabajando el monitor serial de Arduino, `estado` representa el dato que se envía a Arduino para encender o apagar alguno de los transistores. + +Ahora bien, la función `conectar_serial` se utliza para entablar la comunicación con el monitor serial de Arduino. + +``` +def conectar_serial(): + global arduino + global conected + try: + arduino = serial.Serial(serialPort, baudRate) + arduino.timeout = 0.2 + time.sleep(0.5) + print("CONECTADO") + btnStart.config(state = "normal") + btnConectar.config(state = "disabled") + btnManual.config(state = "normal") + btnManual2.config(state = "normal") + conected = True + except: + print("Error de conexión") +``` + +`arduino` es el objeto encargado de establecer la conexión, sus atributos son el puerto serie y la tasa de baudios, `timeout` es el tiempo en que se están leyendo los datos constantemente, además se requiere de un pequeño retardo para lograr correctamente la comunicación de datos en primera instancia. Posterior a ello, únicamente se habilitan y deshabilitan botones para su uso en la interfaz. + +La siguiente función `leer_datos` se usa para comenzar a recibir los datos de Arduino una vez lista la comunicación. + +``` +def leer_datos(): + time.sleep(1.0) + arduino.reset_input_buffer() + print("leyendo") + while(conected): + if(isRun == True): + global isReceiving + global dato + global data + for i in range(numData): + datos = arduino.readline().decode("utf-8").strip() + print(datos) + if(datos != ''): + print("RECIBIENDO..." + str(i)) + dato = float(datos) + data[i].append(dato) + if(i == 0): + var.set("TEMPERATURE 1: " + str(dato) + " °C") + else: + var2.set("TEMPERATURE 2: " + str(dato) + " °C") + else: + break; + isReceiving = True +``` + +Esta, a partir de un ciclo while al que se puede entrar una vez iniciada la conexión con Arduino, se encarga de leer y guardar en una variable `datos` la información decodificada en forma de cadena desde el monitor serie para, una vez asegurado que se ha leído un dato y no es información vacía, hacer su conversión a flotante y agregar este dato a la colección que se graficará posteriormente, además de poder visualizar el valor de la temperatura en la interfaz mediante una etiqueta ya sea que se trate del sensor 1 o 2. Cabe mencionar que cada que se muestra un `print` es para poder visualizar en la consola de python algún error o la parte del código donde nos encontramos. + +Puesto que la lectura de datos se debe efectuar simultaneamente a la graficación de los mismos, es necesario correr la función de `leer_datos` en un hilo a parte: + +``` +def iniciar_hilo(): + global thread + global isRun + btnStart.config(state = "disabled") + isRun = True + thread = Thread(target=leer_datos) + thread.start() #Inicio de la lectura + btnStart.config(state = "disabled") + btnPause.config(state = "normal") +``` + +Ahora, la siguiente función `iniciarGrafica` es la que se va a encargar de graficar mediante líeas 2D la colección de datos que recibe, pero para ello ocupa ser llamada posteriomente. + +``` +def iniciarGrafica(self, muestras,lines): + global dato + lines[0].set_data(range(muestras), data[0]) #Se grafica en la línea la colección de datos + lines[1].set_data(range(muestras), data[1]) +``` + +Para poder guardar la gráfica que se muestra actualmente en la interfaz se utiliza la función: + +``` +def guardarGrafica(): + plt.savefig('miFigura.png') +``` + +En control de los transistores se efectua a partir de las siguientes dos funciones: + +``` +def control1(): + global on1 + global estado + global arduino + if on1 == False: + on1 = True + btnManual.config(bg = "#55DE1E", text = "ON") + estado = "on1" + arduino.write(estado.encode()) + else: + on1 = False + btnManual.config(bg = "red", text = "OFF") + estado = "off1" + arduino.write(estado.encode()) +``` + +``` +def control2(): + global on2 + global estado + global arduino + if on2 == False: + on2 = True + btnManual2.config(bg = "#55DE1E", text = "ON") + estado = "on2" + arduino.write(estado.encode()) + else: + on2 = False + btnManual2.config(bg = "red", text = "OFF") + estado = "off2" + arduino.write(estado.encode()) +``` + +Según sea el botón de la interfaz con el que se interactúa, se hace la función de on/off de los transistores, para ello se hace uso de las variables `on1` y `on2` que indican el estado actual de estos dispositivos, de manera que si se presiona algún botón se ingresa a la función y se comprueba su estado actual, si el valor booleano actual de la variable `on` es *False* se enciende el transistor y se envía este cambio de estado al serial de Arduino, de lo contrario si el valor actual es *True* se apaga el transistor correspondiente e igualmente se envía la información a Arduino. El botón cambia de color y texto según el estado en que se encuentre el dispositivo, además se modifica el valor booleano de la variable `on1` u `on2`. + ![](http://gmarxcc.com:8088/MSP430/GUI-Heater-System/raw/branch/master/Esquematico%20Conexiones/Esquematico_Sistema_de_Calentamiento.png)