diff --git "a/IMPETOM-Cl\303\255nico/Arduino.py" "b/IMPETOM-Cl\303\255nico/Arduino.py" new file mode 100644 index 0000000000000000000000000000000000000000..595e07c88dcb2eac52397e421bf8872b96dd20c4 --- /dev/null +++ "b/IMPETOM-Cl\303\255nico/Arduino.py" @@ -0,0 +1,188 @@ +import time + +import numpy as np +import serial +import serial.tools.list_ports +import array as arr +from ImpetomCError import ImpetomCError +from Archivos import Archivos + +class Arduino: + """ + Esta clase permite la creación y manejo del objeto Arduino. + + """ + + + def __init__(self,baudrate, timeout,vThreshold): + """ + Método constructor para la clase Arduino. Permite la creación del objeto arduino. En caso de existir un Arduino conectado a la PC, lo detecta y guarda en este objeto el puerto COM y abre el canal serial. + + :param baudrate: Es la frecuencia del canal serial + :param timeout: Es el valor máximo de tiempo antes de que el canal se cierre sin que se haya recibido ningun dato. Se recomienda no poner timeout menor a 0.1 ya que si no da la conexión da problemas. + :param vThreshold: Es el valor de voltaje a partir del cual se considera que el electrodo esta mal conectado (debe ser un float) + + :exception ImpetomCError: Devuelve una excepción indicando que no se detecto ningun arduino conectado a la pc + """ + + self.puerto = self.__buscarPuertoCom() + self.baudrate = baudrate + self.modo = 0 # Modo Setup por defecto, modo Reconstrucción = 1 + self.timeout = timeout + self.frecuenciaDDS = "30000" + self.ard = serial.Serial(port=self.puerto,baudrate=self.baudrate,timeout=self.timeout) + self.vThreshold = vThreshold + self.__establecerComunicacion() + self.modoColocacionPares = False + self.datos = np.zeros(208) + + + def __buscarPuertoCom(self): + """ + Esta función permite buscar al arduino dentro de los puertos COM conectados al PC + + :exception ImpetomCError: Tira un error en caso de no encontrar ningún arduino conectado al sistema + + """ + + ports = list(serial.tools.list_ports.comports()) + ArduinoPort = '' + + for p in ports: + if "CH340" in p.description or "USB" in p.description or "COM3" in p.description:# Windows reconoce asà al arduino + ArduinoPort = p.name + if ArduinoPort == '': + raise ImpetomCError ("Error: No se encontró ningún dispositivo Arduino conectado.") + + else: + return ArduinoPort + + + def __establecerComunicacion (self): + """ + Esta función establece la comunicación entre la pc y el arduino de impetomC. + + :exception ImpetomCError: Devuelve una excepción indicando que el Arduino conectado no es el arduino de Impetom ClÃnico. + """ + + data = "" + intento = 0 + while data == "" and intento < 20: + self.ard.write(bytes("1", 'utf-8')) + time.sleep(0.05) + data = self.ard.readline().decode('utf-8').rstrip() + intento += 1 + if intento == 20 or data != "ImpetomC": + raise ImpetomCError("Error: No se encontró el dispositivo de ImpetomC.") + time.sleep(0.05) + + + def obtenerMedidas(self): + """ + Esta función obtiene las 208 medidas de tensión realizadas por el arduino ImpetomC para la reconstrucción tomográfica. + + :returns: **datos** - Devuelve el vector con las 208 medidas realizadas. + + **voltajesElevados** - Devuelve la cantidad de voltajes por encima de vThreshold. + + **frecuenciaArd** - Retorna el valor de la frecuencia a la que esta operando el dispositivo Impetom. + + **voltajesElevadosSeguidos** - Retorna la cantidad de voltajes elevados consecutivos (> vThreshold) que fueron detectados. Este dato se utiliza para verificar si hay electrodos desconectados en el dispositivo fÃsico. + + **tiraMedidaElevada** - Retorna el valor del electrodo que se detectó esta desconectado en el dispositivo fÃsico. + + :exception ImpetomCError: En caso de que el Arduino ImpetomC se haya desconectado durante la adquisición de datos devuelve una excepción. + """ + + modo = str(self.modo) + try: + self.ard.write(bytes(modo, 'utf-8'))# Indico al Arduino ImpetomC en que modo debe operar (0 - Setup ; 1 - Reconstrucción) + self.ard.write(bytes(self.frecuenciaDDS,'utf-8')) # Indico al Arduino ImpetomC a que frecuencia debe operar + i=0 + j=0 + tiraMedida = 0 + tiraMedidaElevada = np.zeros(16) + ele_seguidos=0 + voltajesElevadosSeguidos=0 + voltajesElevados=0 + while i < 208: + data = self.ard.readline().decode('utf-8').rstrip() + if data != "": # Esto es para asegurarme que cada vez que le pido un dato al equipo, lo recibo sin problemas. A veces sucede que no da la velocidad del canal + num = float(int(data) * 5 / 1023) + self.datos[i]= num + i += 1 + if i % 13 == 0: # Cada par de electrodos de corriente tiene 13 medidas de tensión asosciadas, con esto identifico los electrodos de corriente + tiraMedida += 1 + if num > self.vThreshold : + ele_seguidos +=1 + voltajesElevados += 1 + voltajesElevadosSeguidos = max(voltajesElevadosSeguidos, ele_seguidos) + if ele_seguidos % 13 == 0: # Registro tira de 13 voltajes elevados + if j<16 and tiraMedidaElevada[j] != tiraMedida: + tiraMedidaElevada[j] = tiraMedida + j += 1 + else: ele_seguidos = 0 + frecuenciaArd = self.ard.readline().decode('utf-8').rstrip() + except serial.SerialException:#Manejo del error de si el dispositivo se desconecta durante la adquisición de datos + raise ImpetomCError("El Hardware se desconectó durante la adquisición.") + self.datos=np.float32(self.datos) + return [self.datos,voltajesElevados,frecuenciaArd,voltajesElevadosSeguidos,tiraMedidaElevada] + + + def cambiarModoDeOperacion(self,mode): + """ + Esta función permite realizar el cambio de modo del Arduino ImpetomC. + + :param mode: String que debe indicar : "Reconstrucción" o "Setup". + + :exception ImpetomCError: Tira una excepción en caso de que mode sea distinto a los valores aceptados. + """ + + if (mode == "Reconstruccion"): + self.modo = 1 + elif (mode == "Setup"): + self.modo = 0 + else: + raise ImpetomCError("Error: Modo de operación incorrecto. Debe ser \"Reconstruccion\" o \"Setup\"") + + def cambiarFrecuenciaDDS(self,frecuenciaDDS): + """ + Función que permite cambiar el valor de la frecuencia del DDS del dispositvo ImpetomC. + + :param frecuenciaDDS: Valor de la nueva frecuencia del DDS. + + """ + + if(type(frecuenciaDDS) != str): + raise ImpetomCError("Error: La frecuencia del DDS debe estar en formato String") + self.frecuenciaDDS=str(frecuenciaDDS) + + def abrirPuertoSerie(self): + """ + Permite abrir el puerto serie. + Por defecto cuando se crea el objeto el puerto queda abierto, por lo que solo se debe usar si el puerto se + cerró en algun momento. + + :except ImpetomCError: En caso de utilizarse con el puerto ya abierto devuelve una excepción. + """ + + try: + self.ard.open() + self.__establecerComunicacion() + except serial.SerialException as se: # En caso de que se haya desconectado el dispositivo + if (str(se) == "El puerto ya está siendo utilizado"): # En caso de que el puerto ya esté abierto + raise ImpetomCError(str(se)) + else: # En caso de que el error sea por una desconexión + self.puerto=self.__buscarPuertoCom() + self.ard = serial.Serial(port=self.puerto,baudrate=self.baudrate,timeout=self.timeout) + self.__establecerComunicacion() + + + + def cerrarPuertoSerie(self): + """ + Permite cerrar el puerto serie. + """ + + self.ard.close() +