antonio vargas gómez automatización, mediante raspberry pi...
TRANSCRIPT
Antonio Vargas Gómez
Automatización, mediante Raspberry pi, de la gestión de los equipos de medidas eléctricas durante la caracterización de sensores de gases.
TRABAJO FIN DE GRADO
Dirigido por José Luis Ramírez Falo
Grado de Ingeniería en Electrónica Industrial y Automática
Tarragona
2018
2
1. Índice
1. Índice ................................................................................................................................. 2
2. Memoria Descriptiva ........................................................................................................ 4
2.1 Introducción ............................................................................................................. 4
2.2 Antecedentes ........................................................................................................... 4
2.3 Estado del arte ......................................................................................................... 5
2.3.1 Microcontrolador ..................................................................................... 5
2.3.2 Lenguaje de programación ....................................................................... 8
2.4 Objetivos ................................................................................................................. 9
3. Memoria de creación de software .................................................................................... 11
3.1 Instrumentación ..................................................................................................... 11
3.2 Programa principal ................................................................................................ 13
3.3 Comunicación LAN ................................................................................................ 15
3.3.1 Módulos para la comunicación LAN ..................................................... 16
3.4 Autodetección de equipos ...................................................................................... 19
3.5 Instrucciones SCPI ................................................................................................ 21
3.6 Petición de canales ................................................................................................. 25
3.7 Creación y guardado de fichero .csv ....................................................................... 27
3.8 Adquisición de datos ............................................................................................. 28
3.8.1 Toma de datos ........................................................................................ 28
3.8.2 Almacenamiento de datos ...................................................................... 31
3.8.3 Cierre de comunicación ......................................................................... 31
3.9 Terminal de usuario ................................................................................................. 32
3.10 Representación gráfica de datos ............................................................................ 33
3.11 Librerías utilizadas ............................................................................................... 36
4. Manual de usuario ........................................................................................................... 38
4.1 Creación del archivo ejecutable .............................................................................. 38
4.2 Uso del software ...................................................................................................... 39
4.3 Interpretación del archivo .csv ................................................................................. 44
5. Resultados ........................................................................................................................ 48
6. Mejoras ............................................................................................................................ 49
7. Conclusiones .................................................................................................................... 50
8. Presupuesto ...................................................................................................................... 51
3
9. Pliego de condiciones ...................................................................................................... 52
10. Referencias Bibliográficas ............................................................................................. 53
11. Anexos .......................................................................................................................... 55
11.1. Tablas de datos ..................................................................................................... 55
11.2. Código fuente ....................................................................................................... 61
11.2.1. __init__.py ............................................................................................ 61
11.2.2. Main.py ................................................................................................ 61
11.2.3. Comunicacion.py .................................................................................. 63
11.2.4. LAN.py ................................................................................................. 64
11.2.5. adquisicion_datos.py ............................................................................ 64
11.2.6. SAVE.py............................................................................................... 69
11.2.7. CSV_Data.py ........................................................................................ 70
11.2.8. PLOT.py ............................................................................................... 71
11.2.9. Lista_Instrucciones.py .......................................................................... 75
11.2.10. Select_Chan.py ................................................................................... 83
11.2.11. PIN_Instrumento.py............................................................................ 84
11.2.12. Terminal.py ........................................................................................ 88
4
2. Memoria descriptiva
2.1. Introducción
En este proyecto se llevará a cabo la gestión de varios equipos de medidas
eléctricas durante la caracterización de sensores de gases de forma automática.
El grupo de investigación al que va dirigido este proyecto es el grupo MINOS
(Microsistemas y Nanotecnologías para el Análisis Químico), situado en el edificio de
plantas piloto del Campus Sescelades de Tarragona (Cataluña, España) de la Universidad
Rovira i Virgili.
El cometido de dicho grupo está orientado a la investigación, fabricación y
caracterización de microsistemas químicos, especialmente orientados a sensores de gases.
Esta automatización se llevará cabo sobre hardware de Raspberry Pi, en concreto
sobre la placa de desarrollo Raspberry PI 3-B, utilizando el lenguaje de programación
Python 2.7.
El motivo de la realización de este proyecto es el de complementar proyectos
anteriores orientados a la actualización y mejora del sistema actual de medición de gases.
La actualización de este sistema viene dada debido a factores tales como la
obsolescencia de algunos componentes como los equipos PC, la reducción del espacio
utilizado en pos de la instalación de nuevos sistemas y la mejora de rendimiento global
del sistema actual.
2.2. Antecedentes
Para poder contextualizar el proyecto, es necesario conocer cuáles son las
referencias y los aspectos técnicos de los que parte y sobre los que se encuentra
fundamentado.
Este proyecto se complementa junto con otros proyectos realizados con
anterioridad para la mejora del sistema actual de caracterización de sensores de gases.
El sistema actual de control de gases está basado en un sistema de control de
MassFlow (Controladores de Flujo Másico) para la regulación de estos gases. Dicho
sistema trabaja con un software creado bajo el lenguaje de programación Visual Basic, lo
que implica que el único sistema operativo sobre el que puede funcionar el sistema de
control sea Windows, reduciendo así la versatilidad. A demás, dicho software fue
optimizado para el sistema operativo Windows XP, el mantenimiento del cual ha sido
abandonado por la empresa distribuidora Microsoft, de ahí la necesidad de actualización
del software, entre otros motivos.
Puesto que este proyecto es continuidad de otros proyectos de mejora del sistema
de caracterización, debemos conocer dichas mejoras introducidas. Entre estas, podemos
encontrar un sistema de introducción de datos mediante ventanas para el control y
funcionamiento de los MassFlow, un sistema de log-in para diferenciar entre distintos
usuarios y un sistema de almacenaje de los datos obtenidos por los MassFlow, entre otras.
5
2.3. Estado del arte
Para la realización del proyecto, se ha tenido que tener en cuenta diferentes
aspectos como la plataforma donde desarrollarlo, el lenguaje de programación a utilizar,
costes de hardware etc.
A continuación se detallan los motivos por los que se han elegido las distintas
características sobre las que se fundamenta el proyecto tales como el microcontrolador y
el lenguaje de programación. En este apartado no tendremos en cuenta elementos como
los MassFlow, relés etc debido a que, a pesar de formar parte del proyecto global, no
tienen relación directa con este proyecto
2.3.1 Microcontrolador
Un microcontrolador es un circuito digital integrado capaz de realizar diferentes
tareas debido a que puede ser programado. Está compuesto por la unidad central de
procesado (CPU), distintos tipos de memoria (RAM, ROM) y diferentes líneas de entrada
y salida para la conexión de periféricos.
Para la realización del proyecto, es necesario buscar un hardware que no se exceda
demasiado en su coste y que a la vez nos proporcione ciertas características necesarias
para el desarrollo. El mercado actual ofrece centenares de opciones, por lo que es difícil
hacer un estudio comparativo de todas, por este motivo, reduciremos las opciones a las
más utilizadas comúnmente, siendo estas opciones las plataformas ofrecidas por las
marcas Arduino y Raspberry Pi.
Arduino
Arduino es una plataforma de hardware libre, basada en una placa con un
microcontrolador incorporado que trabaja junto con diferentes periféricos de entrada
y salida, diseñada para el uso de la electrónica en proyectos multidisciplinares.
Además, proporciona un software de compilación propio, también libre, bajo un
entorno de desarrollo (IDE) para poder ser programada y cumplir así con
prácticamente cualquier cometido.
Arduino puede ser utilizado para desarrollar elementos autónomos, conectarse con
diferentes dispositivos e interactuar tanto con software como con hardware.
Entre los periféricos que puede utilizar, se encuentran conversores AD/DA,
PWM, USB, Ethernet, Wifi etc. A parte, cabe la posibilidad de añadirle placas de
expansión (shields) para incrementar las posibilidades de uso.
En cuanto al software, entre los lenguajes más comunes para su programación se
encuentran C/C++/C#, Matlab, Python o Scratch (S4A) entre otros. Puesto que se
trata de una plataforma abierta, al igual que muchos de los lenguajes de programación
mencionados, cuenta con una gran variedad de librerías de dominio público para su
uso.
En el mercado actual podemos encontrarnos con diferentes propuestas como
Arduino Mega, Arduino Ethernet o Arduino Due.
6
Arduino Mega es la versión más completa de la plataforma, con un
microcontrolador ATmega2560 con una frecuencia de 16 MHz, 54 pines I/O digitales,
16 entradas analógicas, una memoria flash de 256 KB, un puerto USB y
comunicaciones tipo UART y SPI a un precio de 42 €. Es una opción poco interesante
puesto que carece de conexión tipo Ethernet par la comunicación LAN que vamos a
necesitar en el proyecto.
Arduino Ethernet está basado en la placa Arduino Uno y permite comunicación
mediante un puerto de red. Consta de un procesador ATmega328 con una frecuencia
de reloj de 16 MHz, 14 pines I/O digitales y una memoria flash de 32 KB a un precio
de 48 €.
Arduino Due está formado por un procesador AT91SAM3X8E, con una
frecuencia de 84 MHz, el más potente de la plataforma, 54 pines I/O digitales y una
memoria flash de 512 KB, a un precio de 43 €. Al igual que el primer caso, no dispone
de conexión Ethernet, por lo que no sería apta para el proyecto.
Podemos encontrar una comparativa1 entre las diferentes opciones proporcionadas
por esta plataforma en su página web oficial.
Raspberry Pi
Raspberry Pi es una placa computadora de bajo coste, es decir un ordenador de
tamaño reducido al que se le puede instalar un sistema operativo. El concepto es el de
un ordenador eliminando todos los accesorios posibles sin que esto afecte al
funcionamiento básico.
Consta de diferentes periféricos de entrada y salida, según modelo, y su software
es open source.
A diferencia de Arduino, el catálogo de Raspberry es algo más reducido. En todas
sus versiones, Raspberry ofrece un procesador Broadcom, una memoria RAM, una
GPU, 40 pines GPIO, puertos USB, HDMI y Ethernet, exceptuando el primer modelo,
motivo por el cual lo excluiremos de la lista de posibles opciones. Cabe mencionar
que todos los modelos necesitan una tarjeta microSD para la instalación del S.O.
Entre los distintos modelos a elegir, obviando el primer modelo ya mencionado,
podemos encontrar los modelos 2B, 3B/3B+, entre algunos otros de menor interés.
El modelo 2B posee un procesador de 4 núcleos de 900 MHz, 1 GB de memoria
RAM, 40 pines GPIO, conexión HDMI, 4 puertos USB, un puerto Ethernet, un puerto
para jack de audio de 3.5 mm y conexión para cámara de Raspberry a un precio de
29.50 €.
El modelo 3B consta, al igual que su antecesor, de un procesador de cuatro
núcleos, pero con una mayor frecuencia de reloj, pasando a tener de 1 a 1,4 GHz.
Mantiene la misma memoria RAM, puertos GPIO y puertos de conexión. La
diferencia entre el modelo B y B+ reside en la mejora del Wifi, Bluetooth y el
Ethernet, pasando a una conexión wifi de doble banda, Bluetooth 4.2 y mejora de la
1 https://www.arduino.cc/en/Products/Compare - Comparativa de productos marca Arduino
7
velocidad de transmisión del puerto Ethernet de 100 a 300 Mbps. Al ser el modelo B+
una renovación del modelo predecesor, la compañía ha decidido mantener el precio
de venta, siendo este de 30 €.
A modo de comparativa entre las dos plataformas de desarrollo planteadas,
podemos ver que por el mismo precio, o incluso un poco menos, Raspberry Pi ofrece
mejores prestaciones que la plataforma Arduino. La única desventaja que ofrece frente a
la plataforma rival es la carencia de conversor AD/DA y de PWM. Puesto que estos
elementos no van a ser necesarios en el proyecto, no suponen ningún tipo de pérdida o
desventaja.
Puesto que este proyecto es complementario junto con otros realizados con
anterioridad y que forman parte de un proyecto mayor, el microcontrolador utilizado ha
sido el mismo que en dichos proyectos.
El microcontrolador elegido es el proporcionado por la plataforma Raspberry PI,
en concreto el modelo 3-B.
Las razones por las que eligieron esta plataforma y modelo fueron el bajo coste
del producto y la versatilidad de este.
El precio es realmente asequible para el propósito del proyecto, ya que el hardware
no supera los 40 € y el software es de libre distribución. Al tratarse de un mini ordenador,
cabe la posibilidad de instalarle un sistema operativo como Linux, Ubuntu o Raspbian,
que es SO distribuido de forma gratuita por la misma empresa que subministra el
hardware. Como ventajas principales de poder instalar un SO, tenemos que podemos
programar el software en cualquier lenguaje de programación utilizando cualquier
herramienta de desarrollo (IDE) que esté a nuestra disposición, podemos controlar
distintos dispositivos periféricos y tenemos un soporte gráfico que facilita su uso y
entendimiento.
A parte, en relación con el hardware, este modelo dispone de conexión Wi-Fi y
Ethernet, lo cual es vital para la conexión LAN con los distintos instrumentos de medida
que se requieren para la realización del proyecto. A demás, ofrece una mayor potencia de
cómputo con respecto a sus versiones anteriores y a las placas Arduino a prácticamente
el mismo precio.
Las características del microcontrolador son las siguientes:
Procesador Quad Core Broadcom 2837 ARMv8 64bits 1,2 GHz
1 Gb de memoria RAM
Wifi integrado (BCM43143)
Bluetooth integrado
40 pines GPIO
4 puertos USB
Salida de video y audio HDMI
Puerto CSI para cámara Raspberry PI
Puerto DSI para pantalla táctil
Lector de tarjeta MicroSD
Micro USB para alimentación, máximo 2.5 A
8
2.3.2 Lenguaje de programación
Al igual que se ha hecho con el hardware, es necesario hacer un pequeño estudio
comparativo con las diferentes opciones de software disponibles para evaluar qué
lenguaje de programación es el más adecuado para la realización del proyecto.
De entre la gran cantidad de lenguajes posibles, se valorarán los tres que se
podrían considerar los más adecuados para el proyecto por sus características. Estos tres
lenguajes candidatos son Visual Basic, C/C++ y Python.
Visual Basic
Se trata de un lenguaje creado por la empresa Microsoft. Está orientado a la
programación por eventos, es decir, la estructura y la ejecución del programa se
determinan según los sucesos que ocurran, ya sean estos definidos por el usuario o por
otros eventos.
Dado que el programa original que se utiliza actualmente está programado en este
lenguaje, no se podía obviar de lista de posibles opciones. Uno de los problemas que
introduce este lenguaje es que sólo es funcional sobre sistemas operativos Windows, lo
que conlleva la reducción de la versatilidad del código utilizado ya que, en caso de
renovación de equipos, como ocurre actualmente, se requeriría de forma obligatoria
trabajar sobre equipos con sistema operativo Windows. Otra problemática sería que, en
caso de renovación del código del programa actual, nos veríamos forzado a trabajar con
procesadores con arquitectura x86 puesto que la comunicación de los MassFlow se realiza
con el software distribuido por la marca Bronkhorst, el cual sólo funciona sobre este tipo
de arquitectura.
A pesar de que este proyecto no trata directamente con los MassFlow, es importante
tener en cuenta que tanto este proyecto como el que le precede, deberán trabajar
conjuntamente para la correcta caracterización de los sensores de gases, por lo que para
evitar problemas de compatibilidad, lo más adecuado es que ambos proyectos se realicen
bajo las mismas especificaciones técnicas.
C/C++
Se trata de un lenguaje de programación estructurada de bajo nivel, en el caso de C,
con el añadido de la orientación a objetos en C++. Además, este último permite la
programación multitarea en tiempo real y de entorno gráfico.
Como característica general, podríamos decir que se trata de un lenguaje ampliamente
extendido de carácter general. Esto hace que existan un gran número de librerías
disponibles para su uso. A la vez, esto crea un problema, el cual reside en que cada sistema
operativo tiene sus propias librerías, reduciendo así la versatilidad del proyecto puesto
que si se utilizan las librerías de Windows, el código deja de ser compatible con otros
sistemas operativos.
Python
Se trata de un lenguaje de programación de código abierto, interpretado y de alto nivel
que permite la programación orientada a objetos entre otros paradigmas de programación.
Además, permite la programación multitarea y de entorno gráfico.
9
El ser un lenguaje interpretado, en vez de compilado, lo convierte en un lenguaje
multiplataforma, pues sólo es necesario la instalación del intérprete para su correcto
funcionamiento sobre cualquier sistema operativo. A su vez, esto hace que no sea
compatible con la programación en tiempo real, ya que el tiempo de interpretación es
bastante superior al tiempo de compilación.
Es el lenguaje más utilizado para la programación sobre Raspberry Pi. Dispone de
una gran cantidad de librerías open source que facilitan en gran medida el trabajo con este
lenguaje.
De la misma manera que ocurre con el hardware, el lenguaje de programación
utilizado nos viene impuesto por los proyectos anteriormente realizados.
El lenguaje elegido es Python 2.7.
Los motivos por los que se eligió este lenguaje fueron que Python es un lenguaje
de código abierto que permite la programación multitarea y de entorno gráfico. A su vez,
es de simple aprendizaje en comparación con otros lenguajes, es intuitivo y compatible
con todos los sistemas operativos tras instalar su intérprete. Se trata del lenguaje de
programación más utilizado en la plataforma de Raspberry Pi entre otros entornos. Esto,
junto con el hecho de que se trate de un lenguaje de código abierto, hace que dispongamos
de una gran cantidad de librerías que pueden facilitar mucho la programación. Este en
concreto es el motivo por que se utiliza la versión 2.7 del lenguaje, ya que es la versión
con más módulos accesibles gratuitos creados por la comunidad.
Como única desventaja, hay que tener en cuenta que Python es un lenguaje
interpretado y no compilado, lo que no permite una programación en tiempo real.
2.4. Objetivos
El objetivo principal del proyecto es el de crear un software para llevar a cabo la
gestión de distintos equipos de medida durante la caracterización de sensores de gases.
Para alcanzar dicho objetivo, se ha precisado cubrir ciertos requisitos bajo una
serie de criterios técnicos que se listan a continuación:
Comunicación remota vía LAN de la placa Raspberri con distintos equipos de
medida.
Autodetección de los equipos de medida en uso.
Creación de fichero para almacenaje de datos tipo ‘.csv’.
Opción para poder elegir nombre y ruta de guardado del fichero.
Sincronismo de datos entre MassFlow y equipos de medida.
Representación gráfica constante de los datos obtenidos, con dos ejes de medida
con escalas independientes compartiendo el mismo eje temporal.
Como las medidas se tomarán con distintos instrumentos a lo largo del proyecto,
el software de comunicación debe ser lo más modular posible, es decir, que sea funcional
10
independientemente de los instrumentos con los que se pretenda realizar las medidas
pertinentes.
A demás de la autodetección de los instrumentos, se debe poder elegir para cada
uno de ellos qué tipo de medidas realizarán y en qué canales se llevarán a cabo, en caso
de que exista este parámetro en el instrumento de medida, puesto que cada instrumento
es capaz de realizar distintos tipos de medida según interés.
A parte, existe la posibilidad de conectarnos con instrumentos vía LAN que no
sean de medida, sino generadores de señales tales como fuentes de tensión, corriente, o
generadores de funciones. Estos instrumentos también deben ser detectados
automáticamente y se deben almacenar los datos de las consignas que introducen en el
sistema.
11
3. Memoria de creación del software
3.1. Instrumentación
En este apartado se muestra un listado de los distintos instrumentos con los que
se puede trabajar de forma remota y sus características principales. Dichos equipos son
los siguientes:
Dataloguer. Keysight/Agilent 34972A LXI
Dataloguer de las marcas Keysight y Agilent. Modelos 34972A LXI. Utilizado
para la toma de medidas de tensión y corriente AC/DC y medida de resistencia a
2 y 4 hilos entre otras.
Figure 1. Dataloguer Agilent. Modelo 34972A LXI. Panel frontal y trasero con distintos módulos de conexión.
Power Supply. Agilent N5752A LXI
Fuente de tensión regulada por corriente de la marca Agilent. Modelo N5752A.
Tensión máxima: 600 V DC. Corriente máxima capaz de subministrar: 1,3 A DC.
Figure 2. Power Supply Keysight. Modelo N5752A. Panel frontal y trasero.
12
Arbitrary Waveform Generator. Agilent 33521A LXI
Generador de funciones aleatorias de la marca Agilent. Modelo 33521A LXI.
Sin uso para el proyecto. Se ha contemplado su futura implementación y se han
añadido pautas al código para la facilitación de esta.
Figure 3. Arbitrary Waveform Generator Agilent. Modelo 33521A LXI. Panel frontal
Bench LCR meter. BK Precision 891
Medidor de impedancias de la marca BK Precision. Modelo 891. Utilizado para
la toma de medidas de inductancia y capacitancia con resistencias en serie y
paralelo, valores de impedancias, conductancias, admitancias, resistencias
equivalentes y factores de calidad.
Figure 4. Bench LCR meter de BK Precision. Modelo 891. Panel frontal.
13
3.2. Programa principal
El programa principal es el encargado de gestionar las llamadas a los distintos
módulos y de la creación y activación de los distintos hilos de ejecución para poder
trabajar en un sistema multitarea.
Puesto que se trata de una ejecución concurrente de código, el esquema de
funcionamiento es el siguiente:
Inventario_Instrumentos.txt¿Conexión
Instrumentos?
SÍ
Seleccion instrucciones de
medida
¿Canales?
SÍ
Selección de canales
NO
Creación archivo .csv
Etiquetas Plot
Datos Medidas
Thread Medidas
Toma de medidas
Thread Plot
Plot tiempo real
Thread Terminal
N5752A?
SÍ
Cambio consigna
NO
Fin Programa
NO
Fin Programa
Figure 5. Esquema de funcionamiento del programa principal
14
El orden de ejecución establecido se debe en gran parte a la lógica de uso y
funcionamiento de los instrumentos.
En primer lugar se comprueba que se pueda establecer conexión con al menos un
instrumento. Para ello debe existir en la carpeta contenedora del programa un archivo tipo
.txt denominado ‘Inventario_Instrumentos.txt’. Este archivo debe contener tres datos por
cada instrumento separados por coma simple, diferenciando cada instrumento con un
retorno de carro. Estos datos son la IP del instrumento, el nombre y modelo y el tiempo
de espera en segundos o timeout para establecer la conexión. Mediante la IP el programa
podrá establecer una conexión vía internet con el instrumento para su uso remoto. La IP
se obtiene directamente desde el panel frontal de cada instrumento estando estos
conectados a la red mediante un cable Ethernet. Con el nombre y modelo se podrá
diferenciar entre los distintos instrumentos tanto en la ventana de ejecución del programa,
como en el archivo .csv que se creará a posteriori para almacenar los datos, como en el
plot o gráfico de datos que se mostrará durante la ejecución. Finalmente, el timeout es
necesario para establecer el tiempo máximo de espera para la conexión con cada
instrumento. Si los tiempos de espera son demasiado largos, dado que el programa
comprueba la conexión con todos los instrumentos del inventario, la espera de la primera
conexión puede llegar a ser de minutos. Sin embargo, si el tiempo de espera es demasiado
corto, este puede ser insuficiente para establecer la conexión y no se detectará ningún
instrumento conectado. Como apunte, un tiempo de 0,5 segundos sería suficiente para la
conexión con cualquier instrumento, a excepción del Keysight/Agilent 34972A que
requiere de un timeout mínimo de 6 segundos.
Una muestra del contenido del archivo .txt sería la siguiente:
10.30.239.203,Keysight 34972A,6
169.254.9.72,Agilent 34972A,0.5
10.30.240.134,Agilent N5752A,0.5
10.30.231.254,Agilent 33521A,0.5
10.30.235.170,BK Precision 891,0.5
Si no se detecta ningún instrumento conectado o no se desea utilizar ninguno de
los instrumentos detectados, el programa finalizará de forma automática emitiendo un
mensaje de aviso en el primer caso, o se podrá forzar su cierre en caso de no desear utilizar
ningún instrumento. Este último punto es de vital importancia ya que el programa
detectará cualquiera de los instrumentos del inventario que se encuentren conectados a la
red. Esto implica que se detectará cualquier instrumento en uso por cualquier otra persona
que esté realizando medidas de forma remota. Si seleccionamos un instrumento que no
sea el que nosotros deseamos utilizar, modificaremos el tipo medidas que otra persona
esté tomando en ese momento interfiriendo en su trabajo. La opción de salir del programa
sin seleccionar ningún instrumento se ha implementado para evitar interferir en medidas
ajenas en caso de no estar seguros de cuál es nuestro instrumento o de que este no haya
sido detectado. Si se detectan dos instrumentos de la misma marca y modelo, la manera
de diferenciarlos es a través de su IP, la cual se muestra en la pantalla de selección de
instrumentos para cada uno de ellos. Como ya se ha dicho, la IP de un instrumento se
puede obtener conectando este a la red mediante un cable Ethernet y visualizándola en el
panel frontal. A demás, la IP de cada instrumento debe estar incluida obligatoriamente en
el fichero ‘Inventario_Instrumentos.txt’ anteriormente mencionado.
15
Figure 6. Pantalla de selección de instrumentos con diferentes opciones de selección
Una vez establecida la conexión, si nuestros instrumentos se encuentran en la lista
de opciones a seleccionar, podemos elegir hasta dos instrumentos distintos para que
trabajen a la vez. Tras seleccionarlos, se pedirá el tipo de medidas a realizar con cada
instrumento pudiendo elegir entre 1 o 2 tipos distintos de medidas, según el caso. Una
vez seleccionadas las medidas de cada instrumento, el programa comprueba si alguno de
esos instrumentos trabaja mediante la selección de canales para la toma de medidas. En
caso afirmativo, se pedirá introducir por pantalla el canal en el que medir para cada tipo
de medida. Cabe mencionar, que los únicos instrumentos que trabajan mediante la
selección de canales de medida son los dataloguer modelo 34972A (Keysight/Agilent).
Tras haber seleccionado los tipos de medidas a realizar con cada instrumento, se
pedirá al usuario que elija una ruta para crear un archivo tipo .csv para almacenar los
datos. Tras ello, el programa enviará automáticamente los datos de cada instrumento y
medida a los módulos de creación del plot y toma de datos y seguidamente procederá a
crear los threads respectivos de dichos módulos.
Tras el inicio de la toma de datos y mientras estos se muestran por pantalla
mediante el plot en tiempo real, se mostrará en la terminal de ejecución del programa la
opción de cerrar la comunicación y finalizar el programa. El cierre de la comunicación
implica la detención de todas las medidas y la puesta a 0 y desactivación de todas las
consignas entregadas a parte de la propia desconexión con el instrumento. A su vez, si el
instrumento conectado es la fuente de tensión N5752A, se dará la opción de modificar su
consigna, tanto en tensión como en corriente, en tiempo real. Durante la modificación de
la consigna no será posible cerrar la comunicación. Es importante destacar que el cierre
de comunicación se trata a modo de paro de emergencia, pudiendo activarse mediante el
uso de cualquier tecla. Esto se debe a que en ciertos casos puede ser de vital importancia
la desconexión de ciertos instrumentos como la fuente de tensión.
3.3. Comunicación LAN
En este apartado se explica el funcionamiento de las distintas partes que
componen la comunicación LAN con los distintos equipos de medida. Se trata de un
conjunto de funciones, distribuidas en distintos módulos, que interactúan entre ellas
enviando y recibiendo información de los distintos instrumentos conectados.
16
La comunicación se divide en tres partes, el módulo que ejecuta la comunicación
LAN con los equipos a través de un socket, el módulo de detección de equipos y las
instrucciones SCPI de cada instrumento.
3.3.1. Módulos para la comunicación LAN
La comunicación LAN, propiamente dicha, está formada por dos módulos
distintos, el módulo Comunicación.py y el módulo LAN.py, la combinación de los cuales
permite la conexión remota con los instrumentos.
El primer módulo, el cual puede considerarse el módulo principal de
comunicación, contiene únicamente una clase llamada ‘comunicación_instrumento’. Esta
clase hereda sus variables principales de la librería socket, la cual es de código abierto y
es la que permite la comunicación remota vía internet. Estas variables heredadas, tales
como la IP, el puerto de conexión del instrumento, el tamaño del buffer de datos y el
timeout de conexión, se inicializan mediante el constructor de la clase.
Este constructor de clase puede ser considerado el núcleo de la comunicación.
Antes de inicializar las distintas variables con los valores recibidos, los cuales se
explicaran a continuación, se invoca al constructor de la clase socket, inicializándola con
los valores predeterminados para el tipo de comunicación que queremos realizar. Tras
ello, se establecen los valores de las variables principales que permitirán la comunicación.
Estos valores son la IP del instrumento, el puerto de comunicación LAN del instrumento
y el tamaño de datos del buffer. Tanto el puerto como el tamaño del buffer suelen ser
valores fijos, siendo el puerto de comunicación el 5025 y el tamaño del buffer de 1024.
Es importante comprobar el puerto de comunicación si se pretende instalar un nuevo
instrumento ya que, a pesar de que se utiliza el mismo puerto de manera estándar para la
comunicación LAN, podría no ser el mismo para todos los instrumentos. Lo mismo ocurre
con el tamaño del buffer, debemos asegurarnos que los datos que vamos a recibir son
inferiores al tamaño establecido. Finalmente se establece el valor de timeout, el cual no
es un valor propio del constructor de la clase socket, si no que forma parte de una de las
funciones propias de dicha librería, y que ha sido añadido al constructor para poder
establecer distintos tiempos de comunicación con los diferentes instrumentos. Podemos
observar esta adición al constructor viendo que el valor de timeout se envía como
parámetro a la función ‘settimeout()’, la cual pertenece a la clase socket.
Tras establecer los diferentes parámetros, se comprueba que se pueda establecer
una conexión con la IP mediante el método connect, propio de la clase socket. Si se
confirma la conexión, finaliza la ejecución del constructor de la clase al crear el objeto,
si no, se crea una excepción y se evita realizar ninguna acción tal como detener el
programa o mostrar ningún aviso. Esto se debe a que, como se mostrará más adelante, se
crea y destruye un objeto de esta clase para cada IP de cada instrumento para comprobar
únicamente qué instrumentos se encuentran conectados a la red. Si un instrumento se
detecta, se volverá a crear otro objeto para volver a establecer la conexión.
A parte del constructor de nuestra clase, también se han creado tres funciones
diferentes. Una para el envío de datos, otra para la recepción de datos y una última para
el cierre de la comunicación con el socket. Como nuestra clase funciona con la herencia
17
de la clase socket, tanto el envío y recepción de datos, como el cierre de la comunicación,
funcionan utilizando métodos propios de la clase padre.
El segundo módulo utilizado para el funcionamiento de la comunicación es el
módulo LAN. Al igual que en el anterior, este módulo contiene una clase que hereda sus
atributos principales de la clase creada en el módulo anterior. La estructura de
funcionamiento es la misma. Tras crear el objeto enviándole los valores pertinentes (IP,
puerto de conexión, tamaño del buffer de datos y timeout) como parámetros, se inicializa
la clase padre (comunicacion_instrmento) del módulo ‘Comunicación’. Esto hará, como
ya se ha explicado, que se inicialice la clase socket mediante su constructor, lo que nos
permitirá comunicarnos de forma remota vía internet.
Al igual que en el caso anterior, la clase se compone de diferentes funciones que
nos proporcionaran el apoyo adecuado para las distintas peticiones y envíos de datos. Se
podría pensar que esta segunda clase es innecesaria debido a la existencia de la clase
básica de la comunicación. El motivo por el que se ha creado esta segunda clase que se
apoya sobre la clase padre del anterior módulo, es para permitir que se puedan
personalizar las distintas demandas y envíos de información durante el funcionamiento
del programa. Como se verá más adelante, en ciertas ocasiones es necesario hacer envíos
de información, pero no recibir ningún tipo de respuesta o enviar información con más o
menos datos, dependiendo del instrumento conectado. Estos casos se pueden ver
reflejados en las cuatro funciones implementadas en la clase.
La primera función, llamada ‘Dato_Auxiliar’, se encarga de enviar un dato al
instrumento, como por ejemplo la petición de su IDN para identificarse la cual veremos
más adelante, y devolver esa información al módulo que ha hecho la petición. La segunda
función, ‘Dato_auxiliar_2’, cumple un cometido similar. Hace un envío de información
al instrumento, pero no pide ni devuelve al módulo que la ejecuta ningún tipo de
información. Esta función se utiliza para establecer el tipo de medidas a realizar o enviar
instrucciones que no requieren una respuesta para que sea tratada, como la desactivación
de consignas o medidas en curso. La tercera función recibe el nombre de ‘hacer_medida’.
Su objetivo consiste en enviar al instrumento la petición de realizar una medida y obtener
de él un dato. Según si el instrumento funciona mediante el uso de canales o no, la función
realiza un tipo de pedio u otro. La información sobre si se debe utilizar peticiones de datos
con canales o no, debe ser indicada a la función mediante parámetro, además del tipo de
medida a realizar y el canal en el que realizar la medida si es necesario. Finalmente, la
última función denominada ‘cierre_Com’ se encarga de cerrar la comunicación.
Para la conexión con un instrumento es necesario la creación del objeto de la clase
LAN y la correcta definición de sus parámetros. La forma correcta para crear el objeto
sería utilizando el siguiente método:
Nombre_Objeto=LAN.LAN (IP, PUERTO, BUFFER_SIZE, TIMEOUT)
Todos estos parámetros pueden ser definidos previa creación del objeto o
introducidos de forma directa al crear el objeto como parámetros. En ciertos casos, como
por ejemplo al comprobar qué instrumentos hay conectados a la red de forma automática,
algunos de estos parámetros como la IP o el timeout se obtendrán mediante distintos
algoritmos, como se verá más adelante.
18
Para el uso de las distintas funciones de la clase, el método a utilizar es el uso del
nombre del objeto seguido de un punto y el nombre de la función con los parámetros
pertinentes, como se muestra en el siguiente ejemplo:
Nombre_Objeto.Dato_auxiliar_2 (‘instrucción’)
Si lo que se desea es obtener un valor o dato tras la llamada a alguna de las
funciones que componen la clase, el funcionamiento es el mismo. Se utiliza el nombre
del objeto seguido por un punto y los parámetros pertinentes igualándolo a una variable.
A continuación se muestra un ejemplo:
Varaible_Aux = Nombre_Objeto.Dato_auxiliar (‘instrucción’)
Es importante tener en cuenta que esto sólo debe hacerse con las funciones que
retornen un valor, de no ser así esta acción carecería de sentido puesto que la variable
auxiliar que utilizamos no contendrá ningún valor útil.
Parametros constructor (IP, PORT, BUFF_SIZE,
TIMEOUT)
Objeto LAN.LAN
Constructor Clase 'comunicacion_instrumento'
Constructor clase 'Socket'
Dato_Auxiliar
enviar_dato
send
recibir dato
recv
Dato_Auxiliar_2
enviar_dato
send
hacer_medida
¿Canales?
enviar_dato
send
recibir_dato
recv
cierre_Com
cerrar_puerto
close
Figure 7. Esquema de funcionamiento de la comunicación LAN
19
3.4. Autodetección de equipos
La detección de los distintos equipos conectados a la red debe gestionarse de
forma automática y totalmente ajena al usuario. La única labor que este deberá llevar a
cabo será la de seleccionar con qué instrumento trabajar una vez hayan sido detectados.
Todo el sistema de autodetección de los distintos instrumentos se gestiona en un
mismo módulo llamado PIN_Instrumento.py. En primer lugar, desde el programa
principal, se invoca a la función ‘Leer_Inventario’ de este módulo. Como su nombre
indica, esta función se encarga de leer el archivo .txt, mencionado en los apartados
anteriores, que contiene el inventario de instrumentos. Como ya se ha explicado, el
inventario debe estar formado por el nombre, la IP y el tiempo máximo de espera para
establecer la conexión con cada uno de los instrumentos. Es importante que, tanto el
nombre como la composición del archivo, no se vean modificados en ningún momento,
pues eso impediría la ejecución del programa.
Tras leer y separar los distintos datos dependiendo del tipo, estos se envían a la
siguiente función del módulo, llamada PIN. Esta función se encarga de intentar crear una
conexión con todas las IP listadas teniendo en cuenta el tiempo máximo de conexión
establecido para cada una de ellas. Esta acción se lleva a cabo creando un objeto para la
comunicación, del tipo LAN.LAN, explicado con anterioridad. Esto se hace para cada
instrumento de forma progresiva siguiendo el orden establecido en el inventario. Tras
crear el objeto e inicializar el constructor con los datos del instrumento a probar, se le
envía la instrucción ‘*IDN?’. Esta es una instrucción en lenguaje SCPI (Standard
Commands for Programmable Instruments) con el que se puede programar la gran
mayoría de instrumentos programables, como indica su nombre. Cualquier instrumento
que reciba este comando devolverá su IDN. El IDN de un instrumento consiste en una
cadena de caracteres de identificación con el nombre del fabricante, modelo y versión de
software, entre otros datos. Si el instrumento con el que estamos intentado realizar la
conexión nos retorna un IDN, significa que se encuentra conectado a la red y que hemos
podido establecer una conexión con él. En caso de no obtener ninguna respuesta, puede
significar que el instrumento no esté conectado o que el tiempo de conexión establecido
es demasiado pequeño. Si estamos seguros de que cierto instrumento se encuentra
conectado a la red y no es detectado, es necesario modificar el timeout de la conexión.
Tras realizar la comprobación, se haya establecido o no una conexión con el instrumento,
esta se cierra y se pasa a crear otro objeto para probar a conexionar con el siguiente
instrumento listado.
Es importante comprender el funcionamiento del código por si es necesario
realizar modificaciones futuras. Tras crear el objeto para la conexión, se envía la
instrucción ‘*IDN?’ al instrumento utilizando el método try-except de Python. Este
método consiste en ejecutar inicialmente el código contenido dentro de ‘try’. Si durante
la ejecución de ese código aparece una excepción que impide la ejecución de dicho
código, se pasa a ejecuta el código contenido dentro del ‘except’. De esta manera, si el
envío de la instrucción genera una excepción indicando que no se ha podido conectar con
el instrumento, el programa cierra directamente la comunicación con este para evitar
posibles errores mediante el método ‘except’, en lugar de detener la ejecución. Si el
instrumento contesta enviando su IDN, no se generaría ninguna excepción y se procedería
20
a ejecutar el código contenido en el método ‘try’, en el cual se obtienen el nombre y
modelo del instrumento para su futuro uso. A demás, tras la conexión con un objeto, se
incrementa un contador cuya función es almacenar la cantidad de instrumentos
conexionados. Si esta cantidad es mayor que 0, se establece como cierta la variable
booleana ‘conexión’, la cual es devuelta a la función anterior que invocaba a la actual. Si
la cantidad es 0, la variable se establece como falsa.
Tras finalizar la ejecución de la función PIN, la función Leer_Inventario, la cual
había llamado a la anterior, recibe el valor de la variable ‘conexión’ y a su vez lo retorna
al programa principal. Una vez en este, se comprueba el valor recibido. Si este es
verdadero, se proseguiría con la ejecución del código. En caso de ser falso, finalizaría la
ejecución del programa, puesto que no se habría encontrado ningún instrumento
conectado o no se habría realizado la conexión con ningún instrumento.
Programa principal
Módulo PIN_Instrumento.py
Leer_Inventario
PIN
CONEXIONES
Retorno de datos a función Leer_Inventario
Retorno de datos a Programa principal
¿Conexión?
SÍ
Prosigue la ejecución
NO
Fin programa
Figure 8. Esquema de ejecución para autodetección de instrumentos
21
Finalmente, si se ha detectado algún instrumento y se prosigue con la ejecución
normal del programa, pasaríamos a seleccionar los instrumentos a utilizar. Esto se lleva
a cabo en otra función del mismo módulo, la cual recibe el nombre de INSTRUMENTS.
Esta función es llamada desde el programa principal para poder obtener los datos de los
instrumentos y poder enviarlos a otros módulos con mayor facilidad.
Tras indicar por pantalla la cantidad de instrumentos conectados, se muestra un
listado de estos con sus correspondientes nombres, modelos e IP. A demás, se muestra un
breve comentario explicando que tan sólo pueden elegirse dos instrumentos como
máximo, que en caso de tan sólo desear utilizar uno de los que componen la lista puede
hacerse, o que se puede salir del programa sin seleccionar ninguno (Ver figura 6). El
hecho de permitir seleccionar únicamente un instrumento o ninguno se debe a evitar
interferir en las medidas de otros compañeros al poder seleccionar cualquier instrumento
que se encuentre conectado a la red, como se ha explicado con anterioridad en el
documento. La limitación a dos en el número máximo de instrumentos a utilizar se debe
a los planteamientos iniciales del proyecto. Como posible futura revisión de este, podrían
añadirse a la ejecución la toma de medidas simultáneas de más instrumentos. Esto
implicaría la modificación de los distintos módulos que intervienen en el proceso.
Tras seleccionar los instrumentos, el programa obtiene la IP, el nombre y el
modelo de cada uno y lo retorna al programa principal para ser utilizado en otros módulos
y funciones. Si tan sólo se ha seleccionado un instrumento, ya sea porque tan sólo se ha
encontrado uno conectado o porque sólo se desee utilizar uno de toda la lista, los datos
del segundo instrumento se rellenarán de espacios en blanco para representar la ausencia
de estos y facilitar así la programación. Es importante mencionar que, tanto en esta como
en todas las selecciones de instrumentos o instrucciones del programa, se ha tenido en
cuenta que no puedan elegirse valores que no sean los predefinidos para evitar errores
durante las selecciones. Si se introduce un comando no definido en el panel de ejecución,
se mostrará un mensaje de error y se volverá a ofrecer la opción de hacer la selección
pertinente.
Como en el caso de la detección de los instrumentos, si no deseamos utilizar
ninguno de los listados, finalizará la ejecución del programa sin interferir en ninguno de
los otros posibles instrumentos conectados para no perjudicar la toma de medidas ajenas.
3.5. Instrucciones SCPI
Cada instrumento es capaz de realizar distintos tipos de medida o entregar
distintas consignas. Para ello, es necesario enviarles las instrucciones pertinentes según
nos convenga en cada caso. Puesto que lo que estamos haciendo es programar en tiempo
real los instrumentos, las instrucciones deben ser enviadas en lenguaje SCPI. En el caso
anterior, para la identificación de cada instrumento mediante su IDN, enviábamos la
misma instrucción SCPI a todos. Esto se debe a que todos los instrumentos tienen ciertas
instrucciones básicas para proporcionar información sobre su sistema que son comunes
para todos ellos, pero puesto que cada instrumento realiza medidas diferentes o entregan
distintas consignas, las instrucciones SCPI para programarlos no son las mismas para
todos. Esto implica que cada instrumento debe ser tratado de forma independiente para
su programación y uso.
22
Para cada instrumento, es necesario hacer un estudio de sus funcionalidades y de
qué instrucciones se deben utilizar para poderlas poner en uso. Además, es necesario
conocer las limitaciones de tensión y corriente, entre otras de ciertos instrumentos para
evitar que las instrucciones que entreguemos no entren en conflicto con la programación
interna del instrumento y su funcionamiento. Todos estos datos pueden encontrarse en los
distintos manuales de uso de cada instrumento.
La selección de las diferentes instrucciones de cada instrumento se realiza en el
módulo Lista_Instrucciones.py. Este módulo está compuesto por diferentes funciones, las
cuales están enfocadas a la selección de las instrucciones propias de cada instrumento.
Desde el programa principal se llama a la función Instrucción_medir enviándole por
parámetros el modelo y el nombre del instrumento. Mediante el modelo, la función
comprueba de qué instrumento se trata e invoca a la función pertinente según el
instrumento. Llegados a este punto es importante destacar uno de los instrumentos, en
concreto el dataloguer de la familia Agilent 34972A. Se hace una especial mención
debido a que es el único que funciona mediante la selección manual de canales y permite
realizar uno o dos tipos de medida simultáneamente. Debido a este último punto, antes de
hacer la llamada a la función que le corresponde para seleccionar sus instrucciones,
primero se hace la llamada a la función Num_meas. El cometido de esta función es el de
dar a elegir al usuario si desea realizar una única medida con el instrumento o si desea
realizar dos de manera simultánea. Como patrón general, todas las funciones ejecutan el
mismo procedimiento. Inicialmente se mostrará el nombre del instrumento y la lista de
instrucciones o medidas que este puede realizar. A continuación se le pedirá al usuario
que seleccione el número de la medida a realizar. Puesto que cada instrumento realiza las
medidas de una manera diferente, a continuación se detalla brevemente las características
propias a la hora de seleccionar las medidas para cada uno de ellos.
Agilent/Keysight 34972A Como característica principal, la función se ajusta a la elección del usuario de
realizar una o dos medidas. En caso de querer realizar tan sólo una, tras seleccionarla
se pasará al siguiente paso del programa. Si se desean realizar dos medidas, tras la
primera selección se pedirá elegir una segunda.
Figure 9. Menú de selección de medidas Agilent/Keysight 34972A
23
BK Precision 981
Se trata de un instrumento que realiza dos medidas simultáneamente. Estas
medidas se encuentran parametrizadas. Para seleccionar un tipo de medida, es
necesario seleccionar el parámetro principal y secundario para conformar una única
medida de dos magnitudes diferentes. Por ejemplo, si se desea medir el valor de una
capacitancia en serie con un resistor y a la vez se desea medir la resistencia
equivalente, debe seleccionarse como parámetro principal el parámetro ‘CS’ para la
capacitancia serie y a continuación el parámetro secundario ‘R’ para la medida de la
resistencia equivalente. Es de gran importancia mencionar que a cada parámetro
principal le corresponden tan sólo ciertos parámetros secundarios. Es decir no se
podrá medir un parámetro secundario que no corresponda con el principal. Para
facilitar el uso, inicialmente se muestran los distintos parámetros principales que se
pueden seleccionar, y tras hacerlo, tan sólo se mostrarán los parámetros secundarios
que permita el principal.
Figure 10. Menú de selección de medidas BK Precision 891
Tras la selección de los parámetros, se crea un objeto de comunicación que los envía
al instrumento para establecer el tipo de medida que se van a realizar. Puesto que este
instrumento es el único que nos devuelve el valor medido junto con sus unidades,
aprovechamos esta situación para obtener cuales son. Para ello, mediante la
comunicación previa establecida, se le envía al instrumento una primera orden de
lectura. Tras obtener el valor leído, se envía a la función BK_Unidades para separar
el dato de las unidades de la medida, las cuales se utilizarán para ser mostradas tanto
en el futuro archivo .csv como en los ejes de medida del plot.
Keysight N5752A Al tratarse de una fuente de tensión, no se eligen tipos de medida, si no que se
entregan unas consignas, tanto de corriente como de tensión, según necesite el
usuario. En primer lugar se establece una conexión con el instrumento y a
continuación se le pide al usuario que establezca un límite de corriente y una tensión
24
de inicio, mostrando los valores máximos y mínimos para cada una de las consignas.
En ningún caso se permite que se superen los valores máximos o mínimos, mostrando
un mensaje de error si esto ocurre y volviendo a preguntar la consigna deseada.
Figure 11. Menú de selección de consignas para la fuente de tensión Agilent N5752A
Tras ello, y mediante la comunicación ya establecida, se entregan las consignas al
instrumento de modo que estas no se disparen hasta que se reciba la instrucción
adecuada que indique dicho disparo. Por razones de seguridad, dicha instrucción se
recibirá una vez se inicie la toma de medidas. Esto se debe a que entre el proceso de
establecimiento de las consignas y la toma de medidas, existen diferentes pasos a
llevar a cabo. Uno de ellos es la selección de la ruta de guardado del archivo .csv. El
inconveniente de este paso, es que no hay un tiempo límite para establecer la ruta de
guardado. Este tiempo dependerá directamente del usuario. Puesto que se trata de una
fuente de tensión, la consigna entregada podría causar daños a los equipos o elementos
conectados a ella, pudiendo causar accidentes, lesiones o iniciar fuegos. Si no
podemos desconectar la fuente remotamente de forma rápida tras disparar las
consignas, esto podría derivar en los problemas mencionados. Por ello, el disparo se
establece una vez se empiecen a tomar medidas y el usuario no tenga que interactuar
con el programa más que para detenerlo si así lo desea. Si entre el disparo y la opción
de detener el programa se intercalase este tiempo variable, el cual depende del usuario,
estaríamos reduciendo drásticamente la seguridad de todo el sistema.
Cabe mencionar que tras seleccionar las instrucciones de medida o las consignas
a entregar, estos datos son devueltos al programa principal para poder ser utilizados por
otros módulos. Puesto que podemos trabajar con hasta dos instrumentos, todo este
procedimiento se repetirá para un segundo instrumento si es necesario. En caso de que no
hubiese un segundo instrumento, desde el programa principal se llamaría a la función
‘No_instrument’, contenida en el mismo módulo, cuya función es la de retornar todos los
valores necesarios para definir el tipo de medida en blanco. Al igual que en el caso de la
selección e instrumentos, estos valores deben ser conjuntos en blanco para simular la
ausencia de estos. Más adelante, estos datos serán utilizados para reconocer si es necesario
realizar ciertas acciones o no, como un plot doble o la inclusión de medidas o no en el
archivo .csv donde se almacenarán.
25
3.6. Petición de canales
Tras la selección de los instrumentos y de los tipos de medida a realizar con cada
uno, el programa comprueba si alguno de estos instrumentos necesita información previa
a realizar las medidas de los canales en los que realizarlas. Los únicos instrumentos que
necesitan estos datos son los dataloguers modelo 34972A LXI, ya sean de la marca
Keysight o Agilent.
Tanto la comprobación como la selección de los canales, si son necesarios, se
llevan a cabo en el módulo Select_Chan.py. Mediante la función ‘Diferenciar_Modelo’
se comprueba cuál es el modelo del instrumento y de coincidir con los anteriormente
mencionados, se hace una llamada a la función ‘CHANELS’ para obtener la lista de
canales a utilizar, dependiendo de si se necesitan hacer una o dos medidas.
Figure 12. Menú de selección de canales para medidas de tensión AC y DC con Keysight 34972A
Dentro de la función ‘CHANELS’ se comprueba que los canales seleccionados se
encuentren dentro de los rangos especificados por la documentación del instrumento para
evitar conflictos con la programación interna de es este. A su vez, en caso de haber
seleccionada una medida resistiva a 4 hilos, se muestra un mensaje de aviso indicando
qué canales deben ser cableados para la toma de esta medida y la comprobación de que
estos no estén ya en uso.
Figure 13. Selección de instrucciones y canales con medida resistiva a 4 hilos con Keysight 3492A
Como dato importante para comprender el funcionamiento del programa para
futuras revisiones de este, tras la selección de los canales, las variables booleanas de
nombre ‘BI_CHAN_1’ y ‘BI_CHAN_2’ pasarán a ser ciertas, dependiendo de si se trata
del primer o segundo instrumento. Estas variables se encuentran en el programa principal
junto con los datos de los instrumentos y sus canales, en caso de necesitarlos. Estas dos
variables mencionadas, serán las que determinen qué tipo de mensaje se enviará al
26
instrumento desde la clase de comunicación. Si la variable es cierta, la instrucción de
medida se enviará junto con el canal en el que realizarla. Si es falsa no se indicará ningún
canal de medida.
Como en los casos anteriores, este procedimiento se realizará para cada
instrumento conectado a la red que requiera de una selección de canales. En caso de no
ser necesario, se llamará a la función ‘No_Instrument’ del mismo módulo para devolver
al programa principal los datos de los canales como espacios en blanco, del mismo modo
que se hacía en los puntos anteriores.
Programa Principal
Módulo Select_chan
Diferenciar_Modelo
¿34972A?
SÍ
CHANELS
1 Medida
CH_1=''CH_2=xxx
BI_CHAN_1=FalseBI_CHAN_2=True
CH_1=xxxCH_2=''
BI_CHAN_1=TrueBI_CHAN_2=False
2 Medidas
CH_1=xxxCH_2='yyy'
BI_CHAN_1=TrueBI_CHAN_2=True
NO
No_Instrument
CH1=''CH2=''
BI_CHAN_1=FalseBI_CHAN_2=False
Figure 14. Esquema de funcionamiento del selector de canales
27
3.7. Creación y guardado de fichero .csv
Para el almacenamiento y posterior tratado de los datos obtenidos, durante la
ejecución del programa, se creará un archivo de extensión ‘.csv’ (comma separated
values). Este tipo de archivos se caracterizan por almacenar datos separándolos mediante
una coma simple en una misma celda dentro de un fichero tipo Excel o similar.
Para obtener el fichero de almacenamiento, primero se debe elegir la ruta de
guardado. Para ello, mediante el uso de la librería de código libre ‘wx’ de Python, se crea
una ventana auxiliar en la que el usuario puede seleccionar una ruta específica de
guardado. El funcionamiento de esta ventana es idéntico al que ya conocemos en nuestro
sistema operativo habitual. Mediante la interfaz gráfica de carpetas, podemos seleccionar
la ubicación dónde guardar el archivo o escribir directamente la ruta de guardado. A
demás, podremos elegir el nombre del archivo y obtener un mensaje de aviso si alguno
de los ya existentes va a ser sobrescrito en este proceso. Es importante destacar que
únicamente podrán crearse archivos tipo .csv y de ningún otro tipo.
Puesto que este archivo de guardado es de suma importancia para la realización
de cualquier experimento, puesto que es donde se almacenarán los datos, se han tomado
ciertas medidas de seguridad. La primera de ellas consiste en la creación de un archivo
de seguridad en caso de cerrar la ventana de guardado anteriormente mencionada sin
haber elegido una ruta específica. Este archivo de seguridad se almacenará en la misma
ruta en la que se esté ejecutando el programa y tomará el nombre de ‘Security_file_’
seguido de la fecha y hora en la que se cree el archivo. Además se mostrará un mensaje
por pantalla indicando este suceso y mostrando el nombre y la ubicación exacta del
fichero. La otra medida de seguridad tomada es la aparición de un mensaje de error en
pantalla en caso de no haber podido crear el archivo. Si esto ocurre, el programa dejaría
de ejecutarse al intentar almacenar datos en un archivo inexistente.
Para llevar esto a cabo, se ejecuta el código contenido en el módulo SAVE.py. Este
módulo consta de cuatro funciones. La primera es la función ‘save’, en la cual se
encuentra el código que realiza todas las acciones necesarias para llevar a cabo lo
anteriormente descrito. La segunda es la función de nombre ‘exe’. Esta función es la que
permite ejecutar la interfaz gráfica de la función anterior. Esto se debe a que estamos
trabajando con clases y funciones de la librería ‘wx’, mencionada al principio, la cual
requiere de ciertas instrucciones específicas para ejecutarse y que se encuentran
contenidas en esta función. Finalmente nos encontramos con las dos últimas funciones,
las cuales son ‘Nombre_instrumento’ y ‘Leer_Pathname’. La primera, previo a la
creación del fichero, recibe desde el programa principal el nombre, modelo y medidas a
realizar de cada instrumento y ejecuta la función ‘exe’ para que aparezca la interfaz
gráfica. Esto es debido a que el fichero no sólo almacenará datos, si no que contendrá
información sobre qué instrumento ha tomado el dato y a qué tipo de medida se refiere
cada uno de ellos, como se ve en la Figura 15. La segunda función se encarga de enviar
al módulo que la invoque la dirección exacta de guardado del fichero. Esta dirección o
‘pathname’ es de suma importancia puesto que más adelante será necesario saber la
ubicación del fichero en el que se guardarán los datos y que, a su vez, será leído para
mostrarlos en el plot.
28
Figure 15. Diferenciación de las distintas medidas en el archivo .csv
3.8. Adquisición de datos
La adquisición de datos por parte del programa consiste en enviar de forma
periódica una misma instrucción de lectura al instrumento pertinente para que este tome
una muestra de las magnitudes físicas previamente indicadas y seguidamente las
almacene en el archivo .csv creado. Este procedimiento se llevará a cabo en un hilo de
ejecución distinto al del programa principal y será uno de los cuatro hilos que habrá
ejecutándose simultáneamente a partir de este punto.
Podemos separar la adquisición de datos o medidas en dos partes, la toma de los
datos por parte de los instrumentos y el almacenamiento de estos para su posterior estudio.
3.8.1 Toma de datos
La toma de datos se realiza en su totalidad en el módulo adquisicion_datos.py
mediante el uso de diferentes funciones. Inicialmente, desde el programa principal se
invocan las funciones ‘Datos_para_lectura’ y ‘Control_Com’. La primera se encarga de
recibir todos los datos de los distintos instrumentos conectados, siendo estos la IP, los
canales de lectura, la información de si estos son o no necesarios, los tipos de medida a
realizar, y el modelo del instrumento. La segunda recibe la información necesaria para
determinar si se autoriza o no el inicio de la toma de medidas y si se debe o no cerrar la
comunicación con los instrumentos. Esta última función será la misma a la que se llame
más adelante desde otro módulo para dar fin a la toma de medidas desconectando los
instrumentos.
Tras obtener los datos de los equipos y autorizar las medidas, se crea e inicia el
hilo de ejecución para la toma de estas ejecutando la función ‘Adquirir_Datos’. Tras ello
se crearán entre uno y dos objetos distintos de comunicación, según la cantidad de
instrumentos en uso. Tras ello, y antes de la primera toma de datos, se comprobará si
alguno de los instrumentos utilizados es la fuente de tensión N5752A mediante la
comprobación del modelo. Si se da el caso, se procederá a iniciar el sistema de disparo
de las consignas previamente entregadas, se activarán las salidas del instrumento y se
realizarán los disparos de dichas consignas. Esto se llevará a cabo mediante las
instrucciones SCPI correspondientes y el uso del objeto de comunicación pertinente a
cada equipo. Como ya se explicó anteriormente, que los disparos de las consignas de
tensión y corriente de la fuente se realicen justo antes de iniciar la toma de medidas se
29
debe a una razón de seguridad. Si tras realizar el disparo los valores fuesen demasiado
elevados y pudieran provocar daños en los equipos conectados a la fuente, esta podría
detenerse inmediatamente justo tras realizar la primera medida, el tiempo de realización
de la cual es prácticamente inmediato a efectos de uso del usuario.
Tras esta comprobación, se dará inicio a la toma de medidas. Estas tomas se
realizarán dentro de un bucle infinito de ejecución del cual sólo se saldrá si así lo indica
el usuario, como veremos más adelante. Puesto que cada instrumento puede realizar hasta
dos tipos distintos de medida, tendremos un total posible de hasta cuatro llamadas a la
función ‘hacer_medida’ del módulo LAN de comunicación ya explicado. La cantidad de
tipos de medidas a realizar vendrá dada por el nombre de la instrucción SCPI de cada una
a realizar por cada instrumento. En cada ciclo de ejecución del bucle se comprobará si
existe o no un nombre de instrucción o medida a realizar para cada instrumento. En caso
de no ser un conjunto vacío (‘’) se utilizará el objeto de comunicación asignado al
instrumento pertinente para indicarle que realice el tipo de medida previamente
seleccionada. Puesto que se crean dos objetos para comunicarse, cada uno será asignado
al primer y segundo instrumento seleccionado respectivamente. Si un mismo instrumento
realiza dos tipos distintos de medida, mediante el mismo objeto, se enviará primero una
instrucción y a continuación, tras recibir el dato de esta, se enviará la otra. Si un
instrumento tan solo realiza un tipo de medida o no existe un segundo instrumento, estos
datos se considerarán, como en anteriores casos en los que no había ningún dato, como
conjuntos vacíos (‘’).
Objeto Comunicación Instrumento 1
¿IP_2?
SÍ
Objeto Comunicación Instrumento 2
NO
Medida 1 Instrumento 1
¿Instrucción medida 2 Instrumento 1?
SÍ
Medida 2 Instrumento 1
NO
¿Objeto de comunicación 2?
SÍ
Medida 1 Instrumento 2
¿Intrucción medida 2 Instrumento 2?
SÍ
Medida 2 Intrumento 2
NO
NO
Figure 16. Esquema de ejecución de las distintas medidas según instrumentos conectados
30
Tras cada ciclo de toma de medidas, todos los datos son almacenados en un array
de cuatro posiciones que se envía al módulo CSV_Data junto con la hora de las lecturas
para ser almacenadas en el archivo .csv. Es importante mencionar que la hora se toma
justo tras realizar la última medida de cada ciclo del bucle de lecturas, por lo que habrá
una pequeña variación de tiempo respecto a la toma real de las primeras medidas con
respecto a las últimas de cada ciclo. Puesto que esta variación de tiempo oscila entre los
0.001 y los 0.006 segundos en prácticamente el cien por cien de los casos, podemos
considerar que no interfiere en la veracidad de los tiempos de medida, pudiendo
considerar la totalidad de las medidas de un ciclo como simultáneas puesto que el tiempo
mínimo establecido entre lecturas es de un segundo. Estas diferencias de tiempo han sido
medidas almacenando los datos en la memoria interna de la Raspberry que se utilizará
para llevar a cabo el proyecto, en una memoria externa tipo flash y en la memoria interna
de un pc portátil. En los tres casos se confirman las diferencias de tiempo entre medidas
anteriormente mencionadas, incluyendo estas el tiempo de almacenamiento en el archivo
.csv. Excepcionalmente, y tras realizar distintas pruebas, se han dado casos de tiempos
de mayor duración de forma totalmente aislada de 0.063 segundos, los cuales siguen
siendo lo suficientemente pequeños como para comprometer las medidas que se realicen.
Antes de ser enviados al módulo CSV_Data para ser almacenados, los datos pasan
por un último filtro. Si el modelo de alguno de los instrumentos con los que se están
tomando las medidas coincide con el del BK 891, los datos recibidos por este instrumento
serán tratados antes de ser almacenados en el archivo .csv. Esto es debido a que este
instrumento entrega los datos obtenidos de las lecturas junto con caracteres alfanuméricos
indicando las unidades de estas medidas. Por el modo en cómo se tratan los datos para ser
mostradas en el plot, que veremos más adelante, los datos almacenados en el archivo .csv
deben ser únicamente caracteres numéricos que no contengan ninguna letra u otro
símbolo distinto a un número. Para eliminar estos caracteres sobrantes de las medidas
realizadas con el BK 891, tras comprobar qué datos provienen de él, estos son enviados
a la función ‘BK_DATA’. Es importante saber que este instrumento siempre realiza dos
tipos de medida y que ambas son devueltas como si se tratase de un único dato,
separándolas por una coma simple. Estos datos, tras ser recibidos en la función
anteriormente nombrada, son separados mediante la coma simple y enviados por separado
a la función ‘BK_Num_Transform’. En esta función se eliminan los espacios en blanco
y los caracteres que indican las unidades de la medida. Recordemos que estas unidades
ya han sido obtenidas tras realizar la conexión con el instrumento la primera vez. Puesto
que todas las medidas se deben encontrar dentro de ciertos márgenes debido a las
características del instrumento, si estos márgenes se rebasan el instrumento responderá
con un mensaje de error. Este mensaje será una serie de caracteres alfanuméricos, los
cuales debemos conservar para guardar en el archivo .csv ya que es de sumo interés saber
cuándo ha habido un error en la lectura. Puesto que en la última función mencionada se
eliminan todo tipo de caracteres no numéricos, se permite que ciertas cadenas no sean
eliminadas y se consideren válidas para ser almacenadas. Esas cadenas de caracteres son
los posibles mensajes de error que el instrumento ofrece al superar los rangos de medida
de cualquier magnitud. Se ha mencionado que todos los datos almacenados deben ser
numéricos para que puedan ser tratados por el módulo que mostrará el plot. Como se
explicará más adelante, si al leer el archivo .csv se encuentran valores no transformables
31
en tipo float, se considerarán mensajes de error y se les dará un valor predeterminado
para hacer visible ese error en la medida a simple vista.
3.8.2 Almacenamiento de datos
Como se ha mencionado en el punto anterior, una vez por cada ciclo de lectura de
las distintas magnitudes seleccionadas, estos datos se almacenan en un archivo de
extensión .csv. Esto se lleva a cabo en el módulo CSV_Data. Para ello, tras haber creado
el fichero y desde el mismo módulo SAVE, se le envía al módulo actual la ruta de guardado
del archivo mediante la llamada a la función ‘Rec_Path’. Una vez obtenido el ‘pathname’
del archivo y obtenida la primera tanda de datos del primer ciclo de ejecución del bucle
de lecturas mencionado anteriormente, la función ‘escribir’ recibe el array con los datos
y la hora de la lectura de estos. Tras ello, los separa, abre el archivo .csv, y los escribe en
él siguiendo un orden preestablecido.
Sería de esperar un algoritmo de exclusión mutua (MUTEX) a la hora de abrir el
archivo .csv para escribir y leer, pero no es necesario. La ausencia del MUTEX recae en
que sólo hay una única función en todo el código que escribe en el fichero, lo que provoca
que no exista la posibilidad de ser modificado por un tercero y corromper los datos
sobrescribiéndolos y perdiendo lecturas. A parte, la lectura del archivo tampoco modifica
los datos, por lo que esta se puede dar en cualquier momento sin ningún tipo de peligro,
teniendo en cuenta únicamente que tras cada lectura, al igual que con la escritura, debe
cerrarse el fichero.
Finalmente, si durante la escritura sucede algún error, se mostrará por pantalla un
aviso de este indicando que no se están almacenando los datos en el archivo. El error
típico, el cual es de suma importancia evitar, es el de abrir el archivo .csv mientras se
están almacenando los datos es él. La apertura del archivo impediría que el programa
pudiera abrirlo él mismo para almacenar datos, los cuales se perderían irremediablemente.
Al igual que en el caso anterior, la inclusión de un algoritmo de exclusión mutua no
solventaría este error, puesto que la apertura del archivo que provocaría la pérdida de
información se daría fuera de la ejecución del código del programa.
3.8.3 Cierre de comunicación
Una vez esté en proceso la toma de datos, el usuario podrá detener este
procedimiento en cualquier instante. Esta opción se dará en el tercer y último hilo de
ejecución, que se explicará más adelante, en el módulo Terminal.py. Tras modificar los
valores de las variables de la función ‘Control_Com’, que autorizan el inicio de medidas
y controlan el cierre de las comunicaciones, se saldrá del bucle de ejecución de las lecturas
y se ejecutará la última parte de la función ‘Adquirir_Datos’. Esta última parte consiste
en una serie de comprobaciones de los distintos modelos de instrumentos para asegurar
una total desconexión de estos.
Puesto que todos los instrumentos a excepción del BK Precision 891 son de la
marca Agilent o Keysight, comparten ciertas instrucciones SCPI que afectan al sistema
principal de estos y que son comunes para todos ellos. Una de estas instrucciones consiste
en finalizar cualquier subsistema de toma de datos, de tal manera que todos los
instrumentos dejarían de tomar medidas. Esto sería suficiente para dejar de utilizar de
forma segura los dataloguers 34972A. Aparte, se hace otra comprobación para detectar si
32
está en uso la fuente de tensión N5752A. Si se detecta que este instrumento está siendo
utilizado, no sólo se detiene la medida de las consignas que están siendo entregadas, si no
que se desactiva por completo el sistema de entrega y a su vez estas retoman el valor 0.
Esto es de vital importancia puesto que indicar tan sólo que se deje de medir las consignas
no es impedimento para que estas sigan activas. Apagar el sistema de entrega de consignas
hace que al encender la fuente o volverla a utilizar tras trabajar con ella de forma remota,
no sólo no tenga ningún valor de consigna activo, si no que estas estén a cero. De no
proceder así, tras la desconexión, la fuente podría seguir entregando tensión y corriente,
lo que podría provocar daños a equipos o lesiones a personas puesto que no se tendría
ningún control sobre la fuente que no fuese presencial. El que las consignas retomen
siempre un valor absoluto de 0 impide que, si por error o desconocimiento se activara el
sistema de disparo de consignas, estas puedan provocar algún tipo de daño a los usuarios
o equipos ya conectados a ella subministrando los valores establecidos en su último uso.
Tras todas estas comprobaciones, se invoca a la función ‘cierre_Com’ de los
objetos de comunicación creados desconectándonos así de los instrumentos en uso. Es
importante mencionar que el instrumento de medida BK 891 no tiene ninguna instrucción
que detenga las medidas que esté realizando. Esto se debe a que el instrumento empieza
a realizar medidas nada más ser encendido, por lo que con desconectarnos de él nos sería
suficiente puesto que no supone ningún riesgo que este quede encendido sin que tengamos
control sobre él de forma remota.
3.9. Terminal de usuario
Se trata del último hilo de ejecución creado. Su funcionamiento consiste en
mantener de forma constante en la terminal de ejecución del programa la opción de cerrar
la comunicación y desconectarse de los instrumentos deteniendo las medidas y, si se
encuentra conectada, la opción de modificar las consignas de la fuente de tensión N5752A
en tiempo real.
La ejecución se lleva a cabo en los módulos Terminal.py y adquisicion_datos.py,
siendo este último necesario sólo para llevar a cabo las modificaciones de consigna de la
fuente. Tras crear y poner en marcha el hilo de ejecución mediante la función ‘Terminal’,
inicialmente se comprueba la cantidad de fuentes N5752A conectadas. Es importante
tener en cuenta que puede haber hasta dos fuentes de tensión en uso a la vez y que se debe
modificar la consigna de cada una de ella por separado y de forma totalmente
independiente. Dependiendo de la cantidad de fuentes conectadas se mostraran diferentes
opciones en la terminal. Si tan sólo hay una fuente conectada, se mostrará un mensaje
indicando que se debe pulsar la tecla numérica ‘1’ para pasar al menú de modificación de
consigna. En caso de haber dos fuentes conectadas, se indicará que se debe pulsar la tecla
‘1’ para modificar los valores de la primera fuente o ‘2’ para los de la segunda. Estos
valores se establecen según el orden de conexión con las fuentes. El usuario conocerá
dicho orden puesto que previamente habrá tenido que seleccionarlas de forma manual y
habrá tenido el identificador IP propio de cada fuente. Además, el usuario conocerá qué
consignas desea modificar puesto que también las habrá seleccionado previamente de
manera manual. Tanto en el caso de haber una o dos fuentes conectadas, como en el caso
de que no hubiera ninguna, en todo momento se mostrará la opción de desconectarse de
los equipos en uso presionando cualquier tecla. Debido a cómo funciona la terminal, tras
33
presionar una tecla para introducir cualquier comando es necesario presionar la tecla
Enter. De tal manera, si se presiona directamente esta tecla nos ahorraríamos tener que
introducir cualquier otra previamente, ganando así en tiempo. Es importante destacar este
punto puesto que el cierre de comunicación y desconexión con los instrumentos pretende
ser tratado, como ya se mencionó con anterioridad, como una parada de emergencia para
evitar posibles daños o accidentes en caso de error al introducir datos no deseados en el
programa, o para detener la entrega de consigna de las fuentes de tensión.
Si lo que se desea es modificar alguna de las consignas de las fuentes de tensión,
desde la función ‘Terminal’ se llamará a la función ‘Mod_Consigna_N5752A’
indicándole qué fuente se ha seleccionado, la 1 o la 2. Este dato será de vital importancia
para que más adelante se modifiquen las consignas de la fuente correcta. Dentro de esta
función, se le pedirá al usuario que seleccione si desea modificar la tensión o la corriente
entregada, y una vez seleccionado, se invocará a la función ‘Consigna_N5752A’ del
módulo adquisición_datos. Hasta el momento actual, será posible desconectarse de los
instrumentos en uso. Una vez dentro de la última función mencionada, no se podrá forzar
esta desconexión hasta haber seleccionado una nueva consigna. El código a ejecutar por
esta función para modificar la consigna es idéntico al de la función ‘Keysight_N5752A’
del módulo Lista_Instrucciones ya explicado anteriormente. El único añadido es la
distinción entre qué fuente debe ser la que modifique sus valores. A su vez, esta distinción
es la que obliga a que exista la función ‘N5752A’ dentro del módulo adquisicion_datos
en lugar de volver a utilizar la función ‘Keysight_N5752A’ del módulo
Lista_Instrucciones, como sería lo más lógico. La creación de una nueva función para
modificar las consignas se debe a que, tras seleccionar los nuevos valores de consigna,
estos deben ser enviados al instrumento utilizando el objeto de comunicación pertinente,
dependiendo de si estamos modificando la primera o la segunda fuente en uso. Puesto que
este objeto se crea justo antes de empezar a adquirir los datos de las medidas en el módulo
adquisición_datos, las consignas deben ser modificadas en el mismo módulo para poder
utilizar los objetos de comunicación y transmitir los nuevos valores a entregar. De no
hacerlo así, habría que interrumpir la comunicación cerrándola y creando otro objeto
distinto cada vez que se pretenda modificar una consigna, lo que interrumpiría las
medidas que ya estuviesen en curso.
3.10. Representación gráfica de datos
Durante la toma de datos, estos podrán ser visualizados mediante un plot, gracias
al cual podremos tener una rápida visualización del progreso del experimento. Puesto
que este plot es meramente de apoyo, ya que los datos serán tratados con posterioridad
gracias al archivo .csv, se mostrará una interfaz gráfica lo suficientemente simple como
para no sobrecargar el procesador en caso de estar trabajando sobre la Raspberry.
Este proceso se lleva a cabo en el módulo PLOT, recibiendo la información
necesaria y la orden de inicio desde el programa principal. En este, previa a la creación y
arranque del thread, tras haber obtenido el nombre de los instrumentos y las distintas
instrucciones de medida a realizar, se invoca a la función ‘Label_name’. Esta función es
la encargada de recibir todos los datos mencionados, los cuales son necesarios para, una
vez mostrado el plot en pantalla, diferenciar los distintos datos representados indicando a
qué instrumento corresponde cada uno. Tras recibir los datos, se hace una llamada a la
34
función ‘Create_Figure’. Esta función es de gran importancia puesto que en ella es dónde
se indicará según los datos obtenidos cuál será la configuración que tomará el plot.
Inicialmente se indica la creación de una única figura o ventana. Tras ello, según si hay
uno o dos instrumentos en uso, se indicará que en la misma ventana se deben mostrar uno
o dos plots diferentes. Una vez establecido el número de gráficos a mostrar, según se
tenga una o dos instrucciones, se indicará para cada plot cuantos tipos de datos se deben
mostrar, si uno o dos. En caso de que se deban mostrar dos datos distintos, estos deben
compartir el eje x de tiempo, lo cual también debe ser indicado en esta configuración
inicial. Tras recibir los datos y configurar el estilo de la ventana del plot, la ejecución es
devuelta al programa principal.
Tras el inicio de las medidas, y aún en el programa principal, se crea el thread que
ejecutará de forma constante la interfaz gráfica del plot. Tras ello, se comprueba que se
haya obtenido la ruta de guardado del archivo .csv. Esta ruta se obtiene en el programa
principal mediante la función ‘Leer_Pathname’ del módulo SAVE justo después de haber
creado el archivo. Tras la comprobación, se da paso al inicio del thread utilizando para
ello la función ‘Go_plot’ del módulo PLOT.
Desde la función ‘Go_plot’ se utilizan dos recursos propios de la librería pública
‘matplotlib’. Estos recursos consisten en las funciones ‘FuncAnimation’ y ‘show’. La
primera se encarga de ejecutar en bucle, según ciertos parámetros, una función
determinada. Esos parámetros consisten en indicar el nombre de la ventana creada, el
nombre de la función a ejecutar y el intervalo de tiempo de espera entre ejecuciones. Este
intervalo de espero es el tiempo de refresco del plot. Debemos saber que el modo de
funcionamiento del plot mediante este método consiste en redibujar punto a punto todos
los valores que se indiquen en la función seleccionada. Este redibujado se dará, en el caso
de nuestro programa, cada segundo. Es decir, la información mostrada en el plot se
actualizará cada segundo mientras se estén tomando medidas. La función ‘show’ tiene el
cometido de mantener la ventana del plot abierta hasta que el usuario la cierre o termine
la ejecución del código.
Como se ha dicho, la función ‘FuncAnimation’ propia de la librería ‘matplotlib’,
ejecuta cíclicamente una función determinada. Esta función recibe el nombre de
‘Plotting’. El cometido de esta nueva función no es más que el de indicar qué valores
deben ser dibujados en cada plot a cada ciclo de ejecución. Para ello, llama a la función
‘Plot_Data’ para recibir cada vez una lista de los distintos valores a dibujar. Estos valores
se van añadiendo cada vez al array de valores a ser redibujados, es decir, no se recibe un
valor nuevo cada vez, si no que se recibe un valor nuevo más todos los anteriores. Esto
es necesario por la forma que tiene de trabajar este método de dibujo gráfico. Dentro de
la función ‘Plot_Data’ se abre en modo lectura el fichero .csv, se obtienen todos sus datos
y se vuelve a cerrar para evitar posibles problemas en futuras lecturas. Tras ello, los datos
se separan por líneas y a continuación por comas simples, obteniendo así los datos de
cada una de las lecturas por separado. Tras ello, y como se explicó en el apartado 3.8.1
sobre la adquisición de datos, ya que estos van a ser mostrados en un gráfico, se debe
comprobar que ninguno de los datos leídos sea una cadena string que indique una lectura
errónea. Si no es así, los datos se añaden a distintos arrays según en qué eje vayan a ser
dibujados para ser devueltos a la función ‘Plotting’. Si alguno de los datos es un mensaje
de error, ya que no se puede graficar una cadena de strings, este mensaje es substituido
35
por un valor predefinido para mostrar de manera gráfica que se ha dado un error en las
lecturas. Este valor predefinido se ha establecido en 0. Tras ello, se almacena de manera
normal en el array correspondiente para ser devuelto y graficado. Es destacable mencionar
que estas comprobaciones se han hecho mediante el método ya explicado ‘try-except’,
comprobando si el dato puede ser convertido o no en un tipo float para ser representado.
Finalmente, tras obtener todos los datos hasta el momento del archivo .csv, dentro
de la función ‘Plotting’, se procede a indicar qué datos deben ser graficados en el ciclo de
ejecución en el que se encuentre el programa. Para ello, mediante las distintas variables
de representación creadas en la función ‘Create_Figure’ durante la configuración del plot,
se indica para cada una de ellas los datos a dibujar, el color de la línea, las distintas
etiquetas de cada eje para la distinción de los distintos datos y la cantidad de puntos
temporales a dibujar. Estas indicaciones se dan mediante el uso de distintas funciones
propias de la librería ‘matplotlib’.
Cabe mencionar que el plot, puesto que se encuentra ejecutándose en un hilo
propio, se mantendrá abierto hasta que el usuario cierre la ventana de este aunque haya
finalizado la toma de medidas. Si el usuario cierra la ventana del plot durante la toma de
medidas, esta no podrá ser abierta de nuevo.
Figure 17. Imagen de la ventana de interfaz gráfica con 1 plot
Figure 18. Imagen de la ventana de interfaz gráfica con 2 plots
36
3.11. Librerías utilizadas
Durante la creación del software se han utilizado diferentes librerías de carácter
público, como se ha mencionado en los puntos anteriores, para el lenguaje de
programación Pyhton 2.7. Estas librerías son de total necesidad para el correcto
funcionamiento del programa, es decir, deben estar instaladas en el equipo dónde el
software vaya a ser utilizado. En caso de ser necesaria una modificación del código, es
importante tener en cuenta que algunas de estas librerías pueden ser substituidas por otras,
como en el caso de las librería para la creación del plot, pero eso conllevaría la creación
de un código completamente nuevo. A su vez, hay librerías que no pueden ser substituidas
por ninguna otra, como podrían ser las librerías para el uso del socket de comunicación o
la librería de funcionalidades sobre el sistema operativo.
A continuación se muestra una lista de las distintas librerías utilizadas durante el
desarrollo junto con una breve explicación de su motivo de uso.
socket
Librería necesaria para la comunicación remota vía internet del equipo con los
diferentes instrumentos a utilizar.
time
Librería para gestión y conversión de tiempo. Utilizada para crear esperas en los
distintos hilos de ejecución y determinar el tiempo mínimo entre las distintas
lecturas de cada instrumento.
numpy
Librería básica para computación científica. Compuesta, entre otros elementos, de
objetos para dimensionar arrays de N dimensiones, herramientas para algebra
linear, transformaciones de Fourier, e implementación de la capacidad de uso de
números aleatorios. Pese a que no se utiliza de forma directa, es necesaria para
dar apoyo a otras librerías como la de dibujado del plot. Se ha utilizado la versión
para Python 2.7 +32.
matplotlib
Librería que permite la creación, uso y parametrización de diferentes herramientas
gráficas para la representación de datos. Utilizada para crear y modificar el plot
en el que se muestran los datos tomados en tiempo real.
wx
Librería que proporciona diferentes herramientas gráficas para el uso de interfaces
nativas en Windows, Linux y Mac. Utilizada para crear la ventana de guardado
del archivo .csv mediante interfaz gráfica.
csv
Librería que da soporte a la creación y manipulación de archivos tipo ‘.csv’
(Comma Separated Values). Utilizada para la creación del archivo .csv.
os
Librería que permite utilizar funcionalidades del sistema operativo sobre el que se
37
ejecuta el programa. Utilizada para obtener la ruta de ejecución del programa para
la creación del archivo de seguridad en caso de ser necesario.
datetime
Librería que proporciona herramientas para la obtención y manipulación de datos
referentes a fechas y horas. Utilizada para la obtención de la hora de cada lectura
además de la hora de creación del archivo de seguridad en caso de ser necesario.
38
4. Manual de usuario
Este apartado pretende ser una guía para el usuario del uso del software sin entrar
en detalles técnicos sobre la programación de este. En esta guía se mostrará cómo crear
el archivo ejecutable del código, el funcionamiento paso a paso del programa y cómo
obtener una correcta interpretación de los datos obtenidos mediante el archivo .csv que
generará el programa.
4.1 Creación del archivo ejecutable
Para poder ejecutar y utilizar el software, es necesario obtener un fichero
ejecutable. Para ello, en primer lugar se necesitan todos los módulos o archivos con la
extensión .py que contienen el código fuente del programa. En segundo lugar, es necesaria
la obtención de un software que permita convertir los archivos .py en archivos ejecutables
tipo .exe. A continuación se describe el método a seguir para la creación de dicho archivo
ejecutable mediante el uso del software externo PyInstaller.
Es importante mencionar que al tratarse de código escrito en Python, este puede
ser ejecutado directamente mediante el archivo .py que inicialice el programa, en nuestro
caso el archivo ‘__init__.py’, evitando así el proceso de creación de un archivo .exe. Pese
a ello, se recomiende encarecidamente la creación del archivo ejecutable para evitar
modificaciones o vulnerabilidades en el código fuente ya que este es encriptado y no
permite modificaciones directas sobre él.
PyInstaller
Se trata de un programa orientado específicamente a empaquetar archivos con
extensión .py, convirtiéndolos en ficheros ejecutables estándar tipo .exe para poder ser
ejecutados sobre cualquier sistema operativo. Como ventaja principal sobre otras
herramientas, podemos destacar que permite trabajar tanto con Python 2.7 como con
versiones superiores como la 3.3 y 3.6, creando ejecutables de menor tamaño que otras
herramientas con la misma funcionalidad.
En primer lugar, debemos descargar el programa en nuestro equipo a través de la
web2 oficial del software. El archivo a descargar lleva el siguiente nombre: ‘PyInstaller
3.3.1 (tar.gz)’. Tras haberlo descargado, debemos descomprimir el archivo, utilizando
cualquier herramienta que tengamos en nuestro equipo para ello, en la ruta que el usuario
quiera. Seguidamente debemos ejecutar la consola del sistema también conocida como
CMD. Desde la consola, debemos dirigirnos a la carpeta donde se haya descomprimido
el archivo descargado. Suponiendo que estemos realizando este proceso en la Raspberry
PI, deberíamos escribir algo parecido a lo siguiente: ‘cd /home/pi/Downloads/PyInstaller-
3.3.1’. Mediante la instrucción ‘cd /’, se accede a la carpeta o ruta que se indique a
continuación, siendo esta ruta en la que se ha instalado el programa descargado. Si se está
trabajando sobre Windows, se debe seguir exactamente el mismo procedimiento mediante
la instrucción ‘cd /‘, modificando únicamente la ruta en la que se ha descomprimido el
archivo. Una vez dentro de este directorio, y utilizando todavía la consola del sistema,
debemos ejecutar la siguiente instrucción: ‘sudo python setup.py install’. Tras ello se
2 http://www.pyinstaller.org/downloads.html
39
instalará el software, mostrando un mensaje en la misma terminal indicando que todo ha
ido correctamente.
Tras la correcta instalación podemos pasar a crear el archivo ejecutable de nuestro
software. Para ello, y mediante el uso de la terminal del sistema ya sea en Windows o
sobre la Raspberry, debemos ir al directorio donde se encuentren los archivos de
extensión .py que contienen el código fuete. De igual modo que durante la instalación del
programa, debemos utilizar la instrucción ‘cd /’ añadiendo a continuación el directorio
donde se encuentren esos archivos. Una vez dentro del directorio, crearemos el fichero
ejecutable utilizando la instrucción ‘pyinstaller __init__.py’. Mediante esta instrucción,
ejecutamos el programa instalado indicándole que archivo debe convertir. Este archivo
debe ser el módulo que lleva por nombre ‘__init__’ debido a que es el módulo principal
que permite que el programa empiece a ejecutarse, además de importar todos los demás
módulos que forman el conjunto del software creado.
Una vez realizado los pasos anteriores, en el mismo directorio donde hemos
creado el archivo ejecutable, aparecerán dos carpetas distintas. El archivo ejecutable se
encontrará en la carpeta de nombre ‘dist’, bajo el nombre ‘__init__.exe’.
4.2 Uso del software
A continuación se muestra un ejemplo de uso del programa mediante el uso de
dos equipos de manera simultánea, la fuente de tensión N5752A y el BK 891.
1. Detección de los instrumentos en uso.
Tras iniciar el programa, este intentará conexionar automáticamente con los
instrumentos del inventario, los cuales deben estar en el formato que se especificó
en el apartado 3.2 dentro de un fichero.txt. Durante este proceso, se indicará con
qué instrumentos se ha podido establecer comunicación y finalmente aparecerán
listados en orden para que el usuario pueda escoger con cuales trabajar.
Figure 19. Pantalla de ejecución. Intento de conexión remota con los distintos instrumentos
2. Selección de instrumentos a utilizar.
Tras obtener la lista de instrumentos conectados, el usuario deberá elegir hasta un
máximo de dos de ellos para trabajar. Esta selección se llevará a cabo mediante la
introducción en la terminal del número asignado a cada instrumento. En caso de
sólo querer utilizar uno de los instrumentos listados, se debe presionar la tecla
40
‘Enter’ cuando el programa pida el número del segundo instrumento. En este caso,
se mostrará un mensaje indicando que tan sólo hay un instrumento en uso. Si no
se desea utilizar ninguno, el usuario debe introducir el valor 0, lo que dará fin a la
ejecución del programa. En caso de haber sólo un instrumento conectado, si se
selecciona para su uso, no se pedirá seleccionar un segundo instrumento.
Figure 20. Pantalla de ejecución. Selección de instrumentos. Sólo BK 891 en uso.
3. Selección de instrucciones y consignas
Una vez seleccionados los instrumentos, se pasará a la introducción de las
consignas o selección de instrucciones, según instrumento. En caso de haber
seleccionado la fuente de tensión N5752A, se pedirá por pantalla que se
introduzca una consigna para el límite de corriente y a continuación para la tensión
de trabajo. La consigna no será disparada hasta el inicio de la toma de datos. A su
vez, mientras se eligen las consignas, se mostrarán los valores máximos
permitidos. En caso de utilizar cualquier otro instrumento, el programa pedirá que
se seleccionen los tipos de medida a realizar. En el caso del BK 891, por ejemplo,
se seleccionará el tipo de medida principal, según el número asignado a cada una,
y a continuación aparecerán las medidas secundarias posibles asociadas a la
principal.
Figure 21. Pantalla de ejecución. Introducción de consignas para fuente de tensión N5752A.
41
Figure 22. Pantalla de ejecución. Selección de parámetro principal de medida con BK 891
Figure 23. Pantalla de ejecución. Selección de parámetro secundario de medida según parámetro principal con BK 891
En caso de haber seleccionado cualquier dataloguer modelo 34972A, inicialmente
se pedirá cuántos tipos de medida se desean realizar, pudiendo elegir hasta dos
tipos de medidas distintas. Tras ello, y según la cantidad elegida, se procederá a
seleccionar el tipo de medida a realizar del mismo modo que en los casos
anteriores. Puesto que los dataloguers toman los datos mediante el uso de canales,
una vez indicados los tipos de medias, se pedirá que se seleccionen los canales en
los que realizarlas. Si se selecciona una medida a 4 hilos, el programa emitirá un
mensaje indicando qué canales deben ser cableados según la selección del usuario.
Figure 24.Pantalla de ejecución. Selección de cantidad de tipos de medida a realizar. Keysight 34972A.
Figure 25. Pantalla de ejecución. Selección de medidas con Keysight 34972A.
42
Figure 26. Pantalla de ejecución. Selección de canales para tipo de medida. Keysight 34972A.
4. Selección de la ruta de guardado del archivo .csv
Una vez se ha terminado con la selección de tipos de medida o con la introducción
de consignas, se mostrará en pantalla una ventana para que el usuario seleccione
la ruta de guardado del archivo .csv que contendrá los datos tomados. La
apariencia de esta ventana puede variar dependiendo del sistema operativo en que
se ejecute el programa, pero su contenido será el mismo en todos.
Figure 27. Ventana de guardado de archivo .csv
5. Representación gráfica de los datos
Tras haber realizado los pasos anteriores, aparecerá una nueva ventana en la que,
una vez se dé inicio a la toma de medidas de forma automática, se mostrarán en
tiempo real los datos tomados durante todo el experimento. Esta ventana
permanecerá abierta hasta que el usuario la cierre de manera manual. El hecho de
finalizar las medidas y desconectarse de los instrumentos no afecta al muestreo de
los datos, permitiendo así realizar capturas de pantalla o guardar la imagen
obtenida si así lo desea el usuario. Los datos de la representación gráfica se
actualizarán automáticamente cada dos segundos. No se podrá volver a abrir la
ventana en caso de cerrarla durante la toma de datos.
43
Figure 28. Ventana con la representación gráfica en tiempo real de los datos tomados
6. Terminal de espera
Tras seleccionar la ruta de guardado y mostrarse la ventana del plot, se hará el
disparo de las consignas de la fuente de tensión si es necesario y se dará inicio a
la toma de medidas. Tras ello, en la terminal de ejecución se mostrará un mensaje
para finalizar la toma de datos en cualquier momento. Esto conllevará la
desconexión con los instrumentos y la finalización del programa. Si se encuentra
conectada una fuente de tensión, a la vez que la opción de finalizar las medidas,
se dará también la opción de modificar la consigna, tanto de tensión como de
corriente, de las fuentes conectadas. Durante la modificación de las consignas no
se podrá detener el programa hasta haber finalizado la introducción de estas.
Figure 29. Pantalla de ejecución. Finalización de las medidas y desconexión con los instrumentos
44
Figure 30. Pantalla de ejecución. Modificación de las consignas de tensión y corriente durante las medidas
4.3 Interpretación del archivo .csv
Una vez finalizada la ejecución del programa, tendremos acceso al archivo de
extensión .csv con los datos obtenidos durante el experimento realizado. El archivo se
encontrará en la ruta de guardado que el usuario haya especificado, o en la misma carpeta
desde donde se haya ejecutado el programa en caso de no haber elegido una ruta.
Tras abrir el archivo, podremos observar que los datos se encuentran separados
por comas y estarán encasillados en distintas celdas de forma vertical (Fig. 19). Para
organizar los datos en distintas celdas, separándolos en filas y columnas, para poder
tratarlos más tarde, debemos seguir el siguiente procedimiento.
1. Seleccionar la columna ‘A’ en su totalidad haciendo clik sobre el nombre de la
columna.
2. Seleccionar la pestaña de ‘Datos’
3. Seleccionar la opción ‘Texto en columnas’
4. Marcar la opción ‘Delimitados’ y hacer clik en ‘siguiente’
5. Dentro del cuadro de ‘Separadores’, seleccionar la opción ‘Coma’
6. Hacer clik en ‘Finalizar
Figure 31. Datos con el formato base, separados por coma simple.
45
Figure 32.Opcion 'Delimitados' para dar formato a los datos
Figure 33. Opción para la separación de los datos
46
Tras seguir los pasos indicados, el resultado obtenido es el que se muestra en la
Figura 22, donde los datos ya han sido separados en sus respectivas celdas y columnas.
Este procedimiento es el mismo independientemente de la cantidad de instrumentos o
medidas almacenadas en el fichero.
Figure 34. Formato de datos modificado para su correcto tratado
Tras la modificación de la estructura de los datos, podemos apreciar que estos aún
no son del todo correctos para su tratado debido al formato de las horas de la primera
columna. Para corregir este error de formato, seguiremos el procedimiento siguiente.
1. Seleccionar todo el contenido de la primera columna haciendo clik sobre la letra
‘A’ que la representa.
2. Ir a la pestaña ‘Inicio’
3. En el desplegable del apartado ‘Número’, modificar ‘General’ por ‘Hora’
Figure 35. Menú principal EXCEL para modificación de formato horario
47
Figure 36. Formato final corregido de los datos obtenidos
48
5. Resultados
En este apartado se comentarán los resultados obtenidos durante la realización de
dos test del programa final, obteniendo los datos de forma remota mediante el uso las
parejas de instrumentos Keysight 34972A y BK Precision 891 y Bk Precision y Agilent
N5752A.
Los datos obtenidos se muestran en las tablas 1 y 2 de los anexos.
En ambos casos se han realizado medidas durante varios minutos para demostrar
que el tiempo de duración del experimento no supone un hándicap para la ejecución del
programa. La obtención de los datos demuestra que no se han producido errores de
ejecución durante el almacenaje de estos ni durante la creación del archivo .csv. A su vez,
se ha podido comprobar que las instrucciones entregadas a los distintos instrumentos se
envían y se ejecutan de forma correcta. Durante el uso de la fuente de tensión se ha
comprobado que las consignas pueden ser modificadas de forma tanto remota como
manual, utilizando el panel frontal del instrumento, sin que esto provoque errores de
ejecución o errores en la toma de medidas de consigna. A su vez, se ha comprobado el
correcto funcionamiento del paro de emergencia y la desactivación del sistema de entrega
de consigna.
49
6. Mejoras
Como posibles mejoras a implementar en futuras revisiones del software, podrían
considerarse las listadas a continuación.
Añadir más variedad de instrumentos para ser utilizados de forma remota.
Añadir la posibilidad de conexión con más de dos instrumentos a la vez.
Añadir la posibilidad de realizar más de dos medidas simultáneas con los
instrumentos que así lo permitan.
Comprobación y aviso de la potencia entregada por la fuente de tensión N5752A.
Confirmación de las consignas de tensión y corriente entregadas por la fuente de
tensión N5752A.
Creación de una interfaz gráfica para substituir la consola de comandos del
sistema (CMD)
Creación de un menú de ajustes de valores internos como el tiempo entre lecturas,
el tiempo de redibujado del plot o el valor predeterminado para la representación
de errores en el plot.
Permitir que se pueda volver a abrir el plot durante las lecturas si este se cierra.
50
7. Conclusiones
Nos encontramos ante un software creado desde cero bajo unas condiciones
previas establecidas por el demandante. Esto ha supuesto para el proyectista el
aprendizaje de un nuevo lenguaje de programación y del uso de librerías públicas y
software libre desconocido para él hasta la realización del proyecto. Además, la
realización de este, ha obligado a realizar un estudio y profundización de herramientas de
programación utilizadas con anterioridad, lo que ha supuesto un aumento en el
conocimiento de estas, tanto a nivel teórico como práctico.
A nivel de hardware, el proyecto está basado en especificaciones creadas a partir
de proyectos anteriores. Esto ha obligado a realizar un estudio de dichos proyectos
además del estudio y familiarización pertinente con el hardware utilizado, también
desconocido para el proyectista. Además, ha sido necesario el estudio minucioso de todos
los instrumentos que debían ser integrados en el proyecto, tanto a nivel de software como
de hardware.
Durante la realización del proyecto se han incorporado mejoras que no habían sido
demandadas en un principio debido a la necesidad de estas durante el desarrollo y
creación del software. A su vez, se han añadido medidas de protección tanto para los datos
obtenidos en futuros experimentos, como para los usuarios que los realicen y deban
manipular equipos que puedan ocasionar daños o lesiones.
Finalmente, como resultado, se ha obtenido un programa que cumple con todas
las especificaciones requeridas al inicio del proyecto. Se han añadido mejoras a estas
especificaciones y se han implementado medidas de seguridad para evitar daños en la
medida de lo posible. Se ha obtenido un programa totalmente funcional que ha pasado
por diferentes etapas, tanto de creación como de corrección de errores. Estos errores han
sido corregidos mediante ensayos con cada uno de los instrumentos, probando la gran
mayoría de los casos posibles que podían llevar a error durante la ejecución. Además, el
software ha sido programado para que sea lo más modular posible para futuras revisiones,
y se ha tenido en cuenta que los usuarios no tienen por qué tener conocimientos previos
sobre programación o electrónica para poder utilizarlo sin ningún tipo de inconveniente.
51
8. Presupuesto
Artículo Coste
Unitario Unidades Total
Raspberry Pi 3 Modelo B 29,5 € 1 29.50 €
Conectores, carcasa, disipador y ventilador 15 € 1 15.00 €
Power Supply Agilent N5752A LXI 2830,19 € 1 2830.19 €
Bench LCR meter BK Precision 891 1.524,09 € 1 1524.09 €
Dataloguer Keysight 34972A LXI 2041,27 € 1 2041.27 €
Programación del software 25 € 480 12000.00 € Total sin I.V.A 14567.64 € I.V.A 21.00% 3872.41 € TOTAL 18440.05 €
52
9. Pliego de condiciones
Este apartado no es de aplicación ya que se trata de un proyecto de investigación
para la Universidad
53
10. Referencias Bibliográficas
[1] Documentación oficial de Raspberry Pi. Fundación Raspberry Pi. Página web
gratuita, consultada el día 16/10/2017.
https://www.raspberrypi.org/documentation/
[2] Guía interactiva de los pines I/O GPIO de Raspberry Pi. Página web gratuita,
consultada el día 17/10/2017. https://pinout.xyz/
[3] Curso web interactivo de programación en Python. Página web gratuita y de pago,
consultada el día 23/10/2017. https://www.codecademy.com/learn/learn-python
[4] Guía de usuario básica para Python. Página web gratuita, consultada el día
06/11/2017. https://wiki.python.org/moin/BeginnersGuide/Programmers
[5] Referencia de la biblioteca de Python. Página web gratuita, consultada el día
20/11/2017 http://pyspanishdoc.sourceforge.net/lib/lib.html
[6] Sweigart, A. (2015). Automate the Boring Stuff with Python. 1st ed. [ebook] San
Francisco: William Pollock., consultada el día 22/11/2017. Available at:
http://pyspanishdoc.sourceforge.net/lib/lib.html
[7] Documentación oficial de la versión 2.7 de Python. Página web gratuita,
consultada el día 22/11/2017. https://docs.python.org/2/contents.html
[8] Documentación oficial Python 2.7 PEP-8. Guía de estilo de programación.
Página web gratuita, consultada el día 22/11/2017.
https://www.python.org/dev/peps/pep-0008/#code-lay-out
[9] Tutorial sobre uso de métodos en Python. Página web gratuita, consultada el día
05/02/2018. https://www.tutorialspoint.com/python/index.htm
[10] Documentación oficial Python 2.7. Errores y excepciones. Página web gratuita,
consultada el día 15/02/2018. http://docs.python.org.ar/tutorial/3/errors.html
[11] Web oficial de Keysight. Foro de consulta sobre puerto de conexión Ethernet en
instrumentos de la marca Keysight y Agilent. Página web gratuita, consultada el
día 20/10/2017. https://community.keysight.com/thread/18857
[12] Foro de desarrollo en Python. Creación de comunicación remota vía socket.
Página web gratuita, consultada el día 22/10/2017.
http://developeando.net/sockets-python/
[13] Foro de desarrollo en Python. Creación de comunicación remota vía socket.
Página web gratuita, consultada el día 22/10/2017.
http://www.pythondiario.com/2015/01/simple-programa-clienteservidor-
socket.html
[14] Foro de desarrollo en Python. Creación de comunicación remota vía socket.
Página web gratuita, consultada el día 22/10/2017.
http://mundogeek.net/archivos/2008/04/12/sockets-en-python/
[15] Foro de desarrollo en Python. Uso de ficheros de texto en Python. Página web
gratuita, consultada el día 16/02/2018.
http://pitando.australiando.es/2015/10/01/ficheros-de-texto-en-python/
[16] Web oficial de PyInstaller. Documentación sobre el uso del software PyInstaller.
Página web gratuita, consultada el día 03/05/2018. http://www.pyinstaller.org/
[17] Documentación oficial de Python. Librería se lectura y escritura de ficheros
CSV. Página web gratuita, consultada el día 13/02/2018.
https://docs.python.org/3.4/library/csv.html
54
[18] Foro de desarrollo y programación. Página web gratuita, consultada el día
14/02/2018. https://es.stackoverflow.com/
[19] Web oficial de la librería Matplotlib de Python. Guía de uso. Consultada el día
02/04/2018.https://matplotlib.org/users/index.html
[20] Web oficial de Keysight. Manual de instrucciones SCPI para programación de
instrumentos. Página web gratuita, consultada el día 11/04/2018.
http://rfmw.em.keysight.com/bihelpfiles/Truevolt/WebHelp/US/Content/__I_SC
PI/MEASure_Subsystem.htm#RES-FRES
[21] Foro de desarrollo en Python. Documentación oficial de la librería Wx. Página
web gratuita, consultada el día 16/12/2017.
https://newville.github.io/wxmplot/plotpanel.html
[22] Web oficial de la librería Matplotlib de Python. Ejemplos de uso. Página web
gratuita, consultada el día 12/04/2018.
https://matplotlib.org/examples/index.html
[23] Web oficial de la librería Matplotlib de Python. Documentación oficial. Página
web gratuita, consultada el día 12/04/2018.
https://matplotlib.org/api/pyplot_summary.html
[24] Web oficial de la librería Wx de Python. Documentación oficial. Página web
gratuita, consultada el día 15/12/2017.
https://wiki.wxpython.org/Getting%20Started
[25] Linda, Y. (2015-17) BK Precission. Model: 981. 300 kHz Bench LCR Metre.
User’s Manual. Available at:
https://bkpmedia.s3.amazonaws.com/downloads/manuals/en-us/891_manual.pdf
[26] Keysight Technologies (2009-2014) Keysight 34970A/34972A Data Acquisition
/Switch Unit. User’s Guide. 4th edition. Available at:
https://literature.cdn.keysight.com/litweb/pdf/34972-90001.pdf
[27] Agilent Technologies, Inc. (1997-2003). Keysight 34970A/34972A Data
Acquisition /Switch Unit. Quick Reference Guide. SCPI Command Summary.
March 2003. Available at: http://instructor.physics.lsa.umich.edu/adv-
labs/Tools_Resources/HP%2034970A%20quick%20reference%20guide.pdf
[28] Keysight Technologies (2004-2015) Keysight Series N5700 System DC Power
Supply. User’s Guide. 8th Edition. Available at:
http://literature.cdn.keysight.com/litweb/pdf/5969-2917.pdf
55
11. Anexos
11.1 Tablas de datos
Keysight 34972A B&K Precision 891
Hora Lectura
2-Wire Resistance (Ω) CS (nF) R (kohm)
16:56:15 9.93E+11
10.19 9.918
16:56:17 9.93E+11
10.19 9.918
16:56:19 9.93E+11
10.19 9.918
16:56:20 9.93E+11
10.19 9.918
16:56:22 9.93E+11
10.19 9.918
16:56:23 9.93E+11
10.19 9.919
16:56:24 9.93E+11
10.19 9.918
16:56:26 9.93E+11
10.19 9.918
16:56:28 9.93E+11
10.19 9.918
16:56:29 9.93E+11
10.19 9.918
16:56:31 9.93E+11
10.19 9.918
16:56:32 9.93E+11
10.19 9.917
16:56:34 9.93E+11
10.19 9.917
16:56:36 9.93E+11
10.19 9.918
16:56:37 9.93E+11
10.19 9.919
16:56:38 9.93E+11
10.19 9.918
16:56:40 9.93E+11
10.19 9.918
16:56:42 9.93E+11
10.19 9.919
16:56:43 9.93E+11
10.19 9.918
16:56:44 9.93E+11
10.19 9.918
16:56:46 9.93E+11
10.19 9.918
16:56:48 9.93E+11
10.19 9.918
16:56:49 9.93E+11
10.19 9.918
16:56:51 9.93E+11
10.19 9.918
16:56:52 9.93E+11
10.19 9.918
16:56:54 9.93E+11
10.19 9.918
16:56:55 9.93E+11
10.19 9.918
16:56:57 9.93E+11
10.19 9.918
16:56:58 9.93E+11
10.19 9.918
16:57:00 9.93E+11
10.19 9.918
16:57:01 9.93E+11
10.19 9.918
16:57:03 9.93E+11
10.19 9.918
16:57:04 9.93E+11
10.19 9.918
16:57:06 9.93E+11
10.19 9.918
16:57:07 9.93E+11
10.19 9.917
16:57:09 9.93E+11
10.19 9.917
16:57:10 9.93E+11
10.19 9.918
16:57:12 9.93E+11
10.19 9.918
56
16:57:13 9.93E+11
10.19 9.917
16:57:15 9.93E+11
10.19 9.918
16:57:16 9.93E+11
10.19 9.918
16:57:18 9.93E+11
10.19 9.918
16:57:19 9.93E+11
10.19 9.917
16:57:21 9.93E+11
10.19 9.917
16:57:22 9.93E+11
10.19 9.917
16:57:24 9.93E+11
10.19 9.917
16:57:25 9.93E+11
10.19 9.917
16:57:27 9.93E+11
10.19 9.917
16:57:28 9.93E+11
10.19 9.917
16:57:30 9.93E+11
10.19 9.917
16:57:31 9.93E+11
10.19 9.917
16:57:33 9.93E+11
10.19 9.918
16:57:34 9.93E+11
10.19 9.918
16:57:36 9.93E+11
10.19 9.916
16:57:37 9.93E+11
10.19 9.918
16:57:39 9.93E+11
10.19 9.917
16:57:40 9.93E+11
10.19 9.918
16:57:42 9.93E+11
10.19 9.917
16:57:43 9.93E+11
10.19 9.917
16:57:45 9.93E+11
10.19 9.917
16:57:46 9.93E+11
10.19 9.917
16:57:48 9.93E+11
10.19 9.917
16:57:49 9.93E+11
10.19 9.918
16:57:51 9.93E+11
10.19 9.917
16:57:52 9.93E+11
10.19 9.917
16:57:54 9.93E+11
10.19 9.917
16:57:55 9.93E+11
10.19 9.917
16:57:57 9.93E+11
10.19 9.917
16:57:59 9.93E+11
10.19 9.917
16:58:00 9.93E+11
10.19 9.917
16:58:02 9.93E+11
10.19 9.917
16:58:03 9.93E+11
10.19 9.917
16:58:05 9.93E+11
10.19 9.917
16:58:06 9.93E+11
10.19 9.917
16:58:08 9.93E+11
10.19 9.917
16:58:09 9.93E+11
10.19 9.916
16:58:11 9.93E+11
10.19 9.917
16:58:12 9.93E+11
10.19 9.917
16:58:14 9.93E+11
10.19 9.917
16:58:15 9.93E+11
10.19 9.917
16:58:17 9.93E+11
10.19 9.917
16:58:18 9.93E+11
10.19 9.917
57
16:58:20 9.93E+11
10.19 9.916
16:58:21 9.93E+11
10.19 9.917
16:58:23 9.93E+11
10.19 9.916
16:58:24 9.93E+11
10.19 9.917
16:58:26 9.93E+11
10.19 9.917
16:58:27 9.93E+11
10.19 9.917
16:58:29 9.93E+11
10.19 9.916
16:58:30 9.93E+11
10.19 9.917
16:58:32 9.93E+11
10.19 9.917
16:58:33 9.93E+11
10.19 9.917
16:58:35 9.93E+11
10.19 9.917
16:58:36 9.93E+11
10.19 9.917
16:58:38 9.93E+11
10.19 9.917
16:58:39 9.93E+11
10.19 9.916
16:58:41 9.93E+11
10.19 9.917
16:58:42 9.93E+11
10.19 9.917
16:58:44 9.93E+11
10.19 9.916
16:58:45 9.93E+11
10.19 9.916
16:58:47 9.93E+11
10.19 9.917
16:58:48 9.93E+11
10.19 9.917
16:58:50 9.93E+11
10.19 9.916
16:58:51 9.93E+11
10.19 9.916
16:58:53 9.93E+11
10.19 9.917
16:58:54 9.93E+11
10.19 9.917
16:58:56 9.93E+11
10.19 9.917
16:58:57 9.93E+11
10.19 9.917
16:58:59 9.93E+11
10.19 9.917
16:59:00 9.93E+11
10.19 9.916
16:59:02 9.93E+11
10.19 9.916
16:59:03 9.93E+11
10.19 9.916
16:59:05 9.93E+11
10.19 9.917
16:59:06 9.93E+11
10.19 9.917
16:59:08 9.93E+11
10.19 9.917
16:59:09 9.93E+11
10.19 9.916
16:59:11 9.93E+11
10.19 9.917
16:59:12 9.93E+11
10.19 9.916
16:59:14 9.93E+11
10.19 9.917
16:59:15 9.93E+11
10.19 9.916
16:59:17 9.93E+11
10.19 9.917
16:59:18 9.93E+11
10.19 9.917
16:59:20 9.93E+11
10.19 9.916
16:59:21 9.93E+11
10.19 9.917
16:59:23 9.93E+11
10.19 9.916
16:59:24 9.93E+11
10.19 9.917
58
16:59:26 9.93E+11
10.19 9.916
16:59:27 9.93E+11
10.19 9.917
16:59:29 9.93E+11
10.19 9.916
16:59:30 9.93E+11
10.19 9.916
16:59:32 9.93E+11
10.19 9.917
16:59:33 9.93E+11
10.19 9.917
16:59:35 9.93E+11
10.19 9.917
16:59:36 9.93E+11
10.19 9.916
16:59:38 9.93E+11
10.19 9.916
16:59:39 9.93E+11
10.19 9.916
16:59:41 9.93E+11
10.19 9.916
16:59:42 9.93E+11
10.19 9.916
16:59:44 9.93E+11
10.19 9.916
16:59:45 9.93E+11
10.19 9.916
16:59:47 9.93E+11
10.19 9.916
16:59:48 9.93E+11
10.19 9.916
16:59:50 9.93E+11
10.19 9.917
16:59:51 9.93E+11
10.19 9.916
16:59:53 9.93E+11
10.19 9.916
16:59:54 9.93E+11
10.19 9.916
16:59:56 9.93E+11
10.19 9.915
16:59:57 9.93E+11
10.19 9.917
Table 1.Datos experimentales tomados con Keysight 34972A y BK Precision 891
Agilent Technologies N5752A
B&K Precision 891
Hora Lectura
Voltage (V)
Current (A)
CS (nF) R (kohm)
17:07:47 5.05E+06 2.80E+03 10.27 4.064
17:07:49 3.42E+06 2.80E+03 10.27 4.070
17:07:51 3.42E+06 2.80E+03 10.27 4.083
17:07:53 3.43E+06 2.80E+03 10.27 4.061
17:07:54 3.43E+06 2.80E+03 10.27 4.083
17:07:56 3.43E+06 2.80E+03 10.27 4.077
17:07:58 3.43E+06 2.80E+03 10.27 4.083
17:07:59 3.43E+06 2.80E+03 10.27 4.066
17:08:01 3.43E+06 2.80E+03 10.27 4.072
17:08:03 3.43E+06 2.80E+03 10.27 4.092
17:08:05 3.43E+06 2.80E+03 10.27 4.094
17:08:06 3.42E+06 2.80E+03 10.27 4.068
17:08:08 3.43E+06 2.80E+03 10.27 4.072
17:08:10 3.43E+06 2.80E+03 10.27 4.068
17:08:11 3.43E+06 2.80E+03 10.27 4.081
59
17:08:13 3.43E+06 2.80E+03 10.27 4.094
17:08:14 3.43E+06 2.80E+03 10.27 4.088
17:08:16 3.44E+06 2.80E+03 10.27 4.099
17:08:18 3.43E+06 2.80E+03 10.27 4.064
17:08:19 3.43E+06 2.80E+03 10.27 4.097
17:08:21 3.42E+06 2.80E+03 10.27 4.085
17:08:22 3.42E+06 2.80E+03 10.27 4.085
17:08:24 3.42E+06 2.80E+03 10.27 4.094
17:08:26 3.41E+06 2.80E+03 10.27 4.092
17:08:28 4.50E+06 3.90E+03 10.27 4.099
17:08:29 4.51E+06 4.00E+03 10.27 4.094
17:08:31 4.50E+06 4.00E+03 10.27 4.094
17:08:33 4.50E+06 4.00E+03 10.27 4.109
17:08:34 8.65E+06 8.30E+03 10.27 4.105
17:08:36 8.65E+06 8.30E+03 10.27 4.099
17:08:38 8.65E+06 8.30E+03 10.27 4.094
17:08:39 4.50E+06 4.00E+03 10.27 4.096
17:08:41 4.49E+06 4.00E+03 10.27 4.105
17:08:43 4.49E+06 4.00E+03 10.27 4.107
17:08:44 4.49E+06 4.00E+03 10.27 4.096
17:08:46 4.48E+06 4.00E+03 10.27 4.094
17:08:48 4.49E+06 4.00E+03 10.27 4.094
17:08:49 8.64E+06 8.30E+03 10.27 4.103
17:08:51 8.64E+06 8.30E+03 10.27 4.096
17:08:53 8.64E+06 8.30E+03 10.27 4.070
17:08:54 8.64E+06 8.30E+03 10.27 4.101
17:08:56 8.64E+06 8.30E+03 10.27 4.099
17:08:58 1.28E+07 1.25E+04 10.27 4.114
17:08:59 1.28E+07 1.25E+04 10.27 4.114
17:09:01 1.29E+07 1.68E+04 10.27 4.108
17:09:03 1.70E+07 2.21E+04 10.27 4.097
17:09:04 2.11E+07 2.11E+04 10.27 4.094
17:09:06 2.11E+07 2.11E+04 10.27 4.099
17:09:07 2.11E+07 2.11E+04 10.27 4.101
17:09:09 2.11E+07 2.12E+04 10.27 4.097
17:09:11 2.11E+07 2.12E+04 10.27 4.103
17:09:12 2.11E+07 2.12E+04 10.27 4.097
17:09:14 2.09E+07 2.09E+04 10.27 4.105
17:09:16 2.09E+07 2.09E+04 10.27 4.114
17:09:17 2.09E+07 2.09E+04 10.27 4.110
17:09:19 2.08E+07 2.09E+04 10.27 4.103
17:09:20 2.08E+07 2.09E+04 10.27 4.099
17:09:22 2.08E+07 2.09E+04 10.27 4.107
17:09:24 2.11E+07 2.13E+04 10.27 4.103
60
17:09:25 2.11E+07 2.13E+04 10.27 4.090
17:09:27 2.53E+07 2.57E+04 10.27 4.110
17:09:29 2.53E+07 2.58E+04 10.27 4.101
17:09:30 2.53E+07 2.59E+04 10.27 4.099
17:09:32 2.53E+07 2.59E+04 10.27 4.088
17:09:34 1.69E+07 1.71E+04 10.27 4.092
17:09:35 1.69E+07 1.71E+04 10.27 4.114
17:09:37 1.69E+07 1.70E+04 10.27 4.114
17:09:38 1.69E+07 1.70E+04 10.27 4.101
17:09:40 1.69E+07 1.70E+04 10.27 4.090
17:09:42 1.69E+07 1.70E+04 10.27 4.079
17:09:43 1.69E+07 1.69E+04 10.27 4.083
17:09:45 1.69E+07 1.69E+04 10.27 4.103
17:09:47 1.69E+07 1.69E+04 10.27 4.099
17:09:48 1.69E+07 1.69E+04 10.27 4.090
17:09:50 1.69E+07 1.69E+04 10.27 4.099
17:09:52 1.69E+07 1.69E+04 10.27 4.096
17:09:53 1.69E+07 1.69E+04 10.27 4.077
17:09:55 1.69E+07 1.69E+04 10.27 4.086
17:09:56 1.69E+07 1.68E+04 10.27 4.095
17:09:58 1.69E+07 1.69E+04 10.27 4.101
17:10:00 1.69E+07 1.68E+04 10.27 4.097
17:10:02 1.69E+07 1.68E+04 10.27 4.092
17:10:03 1.69E+07 1.68E+04 10.27 4.079
17:10:05 1.69E+07 1.68E+04 10.27 4.084
17:10:07 1.69E+07 1.68E+04 10.27 4.084
17:10:09 1.69E+07 1.68E+04 10.27 4.075
17:10:10 1.69E+07 1.68E+04 10.27 4.086
17:10:12 1.69E+07 1.67E+04 10.27 4.086
17:10:14 1.69E+07 1.67E+04 10.27 4.088
17:10:15 1.69E+07 1.67E+04 10.27 4.105
17:10:17 1.69E+07 1.67E+04 10.27 4.079
17:10:19 1.69E+07 1.67E+04 10.27 4.073
17:10:20 1.69E+07 1.67E+04 10.27 4.086
17:10:22 1.69E+07 1.66E+04 10.27 4.090
17:10:23 4.20E+05 0.00E+00 10.27 4.077
17:10:25 4.00E+05 0.00E+00 10.27 4.055
17:10:27 4.00E+05 0.00E+00 10.27 4.073
17:10:28 3.90E+05 0.00E+00 10.27 4.068
Table 2. Datos experimentales tomados con Agilent N5752A y BK Precision 891
61
11.2 Código fuente
11.2.1 __init__.py
#!/usr/bin/env python
import Comunicacion
import LAN
import adquisicion_datos
import SAVE
import CSV_Data
import PLOT
import Lista_Instrucciones
import Select_Chan
import PIN_Instrumento
import Terminal
import Main
import time
def START():
Main.programa_principal()
time.sleep(5)
if __name__ == "__main__":
START()
11.2.2 Main.py
#!/usr/bin/env python
import threading
import adquisicion_datos
import PLOT
import PIN_Instrumento
import SAVE
import Terminal
import Lista_Instrucciones
import Select_Chan
def programa_principal():
#Instento de conexion con los distintos instrumentos del
inventario
CONEXION=PIN_Instrumento.Leer_inventario()
if CONEXION is not True:
return(0) #Si no hay conexion con instrumentos, fin del
programa
#Seleccion de instrumento a usar
CONEXION,IP_1,IP_2,NAME_1,NAME_2,MODELO_1,MODELO_2=PIN_Instrumento.INS
TRUMENTS()
if CONEXION is not True:
return(0) #Si ninguno de los instrumentos conectados es
necesario
#Insruciones SCPI, nombre de la instruccion(estetico) y cantidad
de instrucciones (1/2)
#Instrumento 1
62
MEAS_1A,MEAS_1B,MEAS_NAME_1A,MEAS_NAME_1B=Lista_Instrucciones.Instrucc
ion_medir(MODELO_1,NAME_1)
#Instrumento2
if MODELO_2!='':
MEAS_2A,MEAS_2B,MEAS_NAME_2A,MEAS_NAME_2B=Lista_Instrucciones.Instrucc
ion_medir(MODELO_2,NAME_2)
#NO hay segundo instrumento
if MODELO_2=='':
MEAS_2A,MEAS_2B,MEAS_NAME_2A,MEAS_NAME_2B=Lista_Instrucciones.No_Instr
ument()
#Autodeteccion de canales o demanda de ellos, segun caso.
#Instrumento1
CANAL_1A,CANAL_1B,BI_CHAN_1=Select_Chan.Diferenciar_Modelo(MODELO_1,NA
ME_1,MEAS_NAME_1A,MEAS_NAME_1B)
#Instrumento2
if MODELO_2!='':
CANAL_2A,CANAL_2B,BI_CHAN_2=Select_Chan.Diferenciar_Modelo(MODELO_2,NA
ME_2,MEAS_NAME_2A,MEAS_NAME_2B)
#NO hay segundo Instrumento
if MODELO_2=='':
CANAL_2A,CANAL_2B,BI_CHAN_2=Select_Chan.No_Instrument()
#Nombre de las medidas para el archivo .csv
SAVE.Nombre_instrumento(NAME_1,MODELO_1,MEAS_NAME_1A,MEAS_NAME_1B,NAME
_2,MODELO_2,MEAS_NAME_2A,MEAS_NAME_2B)
pn=SAVE.Leer_Pathname()
#Nombre de las medidas para etiquetas de los ejes del plot
TITLE_1=NAME_1+' '+MODELO_1
TITLE_2=NAME_2+' '+MODELO_2
PLOT.Label_name(MEAS_NAME_1A,MEAS_NAME_1B,MEAS_NAME_2A,MEAS_NAME_2B,TI
TLE_1,TITLE_2)
#Paso de parametros para inicializar la comunicacion
Autorizar_Medida=1
Cerrar_Com=0
adquisicion_datos.Control_Com(Autorizar_Medida,Cerrar_Com)
adquisicion_datos.Datos_para_lectura(IP_1,CANAL_1A,CANAL_1B,MEAS_1A,ME
AS_1B,BI_CHAN_1,MODELO_1,
IP_2,CANAL_2A,CANAL_2B,MEAS_2A,MEAS_2B,BI_CHAN_2,MODELO_2)
#Creacion y arranque del Thread de lectura
thread_datos=threading.Thread(target=adquisicion_datos.Adquirir_Datos,
name='DATOS_INSTRUMENTO')
thread_datos.start()
#Creacion del Thread para plot en tiempo real de datos
thread_plot=threading.Thread(target=PLOT.Go_plot, name='PLOTTING')
63
ruta_csv=False
while(not ruta_csv): #Espera hasta tener la ruta del archivo
.csv de donde leera el plot
if(pn):
thread_plot.start() #Arranque Thread Plot
ruta_csv=True
#Creacion y arranque del Thread para Cierre de Comunicacion
Autorizar_Medida=0
Cerrar_Com=1
th_Terminal=threading.Thread(target=Terminal.Terminal(MODELO_1,MODELO_
2), name='Terminal')
th_Terminal.start()
return(0)
11.2.3 Comunicacion.py
#!/usr/bin/env python
import socket
class comunicacion_instrumento (socket.socket):
def __init__(self,IP,PORT,BUFFER_SIZE,TIMEOUT):
socket.socket.__init__(self, socket.AF_INET,
socket.SOCK_STREAM,) #Inicializacion de la calse padre socket
self.TCP_IP = IP #IP para conexion
self.TCP_PORT = PORT #Puerto de conexion
self.BUFFER_SIZE = BUFFER_SIZE #Size del buffer de
datos
self.settimeout(TIMEOUT) #Tiempo de espera para
la conexion con instrumento (segundos)
try:
self.connect((self.TCP_IP, self.TCP_PORT)) #Conexion
con IP y puerto
except socket.error:
pass #NO hay conexion con instrumento.
def enviar_dato(self,dato_enviar): #Se envia un dato mediante
el metodo send(dato) de la clase socket
dato_enviar=dato_enviar+'\n'
self.send(dato_enviar)
def recibir_dato(self): #Se recibe un dato mediante
el metodo recv(buffer_sicze) de la casle socket
try:
dato_recibido=self.recv(self.BUFFER_SIZE)
return dato_recibido
except socket.error:
pass
def cerrar_puerto(self): #Se cierra la comunicacion
del socket.
self.close()
64
11.2.4 LAN.py
#!/usr/bin/env python
import Comunicacion
import time
class LAN (Comunicacion.comunicacion_instrumento):
def __init__(self,IP,PORT,BUFFER_SIZE,TIMEOUT): #Constructor
clase 'comunicacion_instrumento'
Comunicacion.comunicacion_instrumento.__init__(self,IP,PORT,BUFFER_SIZ
E,TIMEOUT)
#Funcion para datos auxiliares tipo PIN, tipo de consigna
(N5752A), etc. que retorna un valor
def Dato_Auxiliar(self,Comand_Aux):
self.enviar_dato(str(Comand_Aux))
dato_aux=self.recibir_dato()
return str(dato_aux)
#Funcion para datos auxiliar. Establecer tipos de medida (BK_981),
instruccion 'ABOR' etc. No retorna ningun valor
def Dato_Auxiliar_2(self,Comand_Aux):
self.enviar_dato(str(Comand_Aux))
#Funcion para la toma de datos
def hacer_medida(self,CANAL, TIPO_MEDIDA, BI_CHANEL):
if BI_CHANEL==True: #34972A
self.enviar_dato(TIPO_MEDIDA+' (@'+CANAL+')')
valor=self.recibir_dato()
else:
self.enviar_dato(TIPO_MEDIDA)
time.sleep(0.2)
valor=self.recibir_dato()
return str(valor)
#Cierre de la comunicacion
def cierre_Com(self):
self.close()
11.2.5 adquisicion_datos.py
#!/usr/bin/env python
import LAN
import time
from datetime import datetime
import CSV_Data
def Adquirir_Datos():
#Datos fijos para comunicacion
PORT=5025 #Puerto Ethernet
BUFFER_SIZE=1024 #tamanio buffer
TIMEOUT=10 #TIMEOUT sufucientemente grande como para
permitir lecturas
global com_lan_1
65
com_lan_1=LAN.LAN(IP_1,PORT,BUFFER_SIZE,TIMEOUT) #Constructor
de clase para comunicacion del instrumento 1
if(IP_2!=''):
global com_lan_2
com_lan_2=LAN.LAN(IP_2,PORT,BUFFER_SIZE,TIMEOUT)
#Constructor de clase para comunicacion del instrumento 2
else: com_lan_2=False #NO hay segundo instrumento para
realizar medidads
#Bucle para lectura continuada hasta cancelar autorizacion (Cerrar
comunicacion)
while Cerrar_Comunicacion==0:
data=['','','',''] #Array 4 posiciones para almacenar y
enviar los datos recibidos
if MODELO_1=='N5752A' and Autorizar_Medida==1:
com_lan_1.Dato_Auxiliar_2('INIT') #Inicia
el sistema para disparo de consigna
com_lan_1.Dato_Auxiliar_2('OUTP ON') #OUTPUT
ENABLE
com_lan_1.Dato_Auxiliar_2('TRIG') #Disparo
de las consignas entregadas a N5752A
if MODELO_2=='N5752A' and Autorizar_Medida==1:
com_lan_2.Dato_Auxiliar_2('INIT') #Inicia
el sistema para disparo de consigna
com_lan_2.Dato_Auxiliar_2('OUTP ON') #OUTPUT
ENABLE
com_lan_2.Dato_Auxiliar_2('TRIG') #Disparo
de las consignas entregadas a N5752A
while ((Autorizar_Medida==1)and(Cerrar_Comunicacion==0)):
# Toma de datos del primer instrumento
dato_1A=com_lan_1.hacer_medida(CANAL_1A,MEAS_1A,BI_CHAN_1)[:-1]
#Lectura DATO_1 Instrumento 1
#print dato_1A
if (MEAS_1B!=''):
dato_1B=com_lan_1.hacer_medida(CANAL_1B,MEAS_1B,BI_CHAN_1)[:-1]
#Lectura DATO_2 Instrumento 1
else:
dato_1B=''
#Toma de datos del segundo instrumento
if (com_lan_2 is not False):
dato_2A=com_lan_2.hacer_medida(CANAL_2A,MEAS_2A,BI_CHAN_2)[:-1]
#Lectura DATO_1 Instrumento 2
if(MEAS_2B!=''):
dato_2B=com_lan_2.hacer_medida(CANAL_2B,MEAS_2B,BI_CHAN_2)[:-1]
#Lectura DATO_2 Intrumento 2
else:
dato_2B=''
else:
66
dato_2A=''
dato_2B=''
#Si estamos recibiendo datos del BK 891 (los datos
se reciben juntos por un mismo canal de comunicacion)
if MODELO_1=='891':
dato_1A,dato_1B=BK_DATA(dato_1A)
if MODELO_2=='891':
dato_2A,dato_2B=BK_DATA(dato_2A)
data[0]=dato_1A
data[1]=dato_1B
data[2]=dato_2A
data[3]=dato_2B
#Hora de las lecturas.
hora_lectura=str(datetime.now().strftime('%H:%M:%S.%f')[:-5])
#Hora de la lectura
#La hora de la lectura almacenada en el .csv es la
correcta. Al mostrar los datos en celdas en el .csv,
#hay que modificar el tipo de dato y ponerlos en
Hora (Suele estar en 'General')"""
#Enviamos los datos para ser almacenados en el .csv
CSV_Data.escribir(hora_lectura,data)
time.sleep(1) #Tiempo de espera tras lectura
time.sleep(0.5) #Espera para cerrar comunicación
#Termina/Abortar la lectura o la consigna entergda
#Solo para los Keysight/Agilent. El BK NO tiene esta instruccion.
if MODELO_1!='891':
com_lan_1.Dato_Auxiliar_2('ABOR') #Finalizacion de
la lectura Instrumento_1
if MODELO_1=='N5752A':
com_lan_1.Dato_Auxiliar_2('OUTP OFF') #Cierre de la
salida. Conigna=0 (Solo para N5752A)
if MODELO_2!='891' and com_lan_2 is not False:
com_lan_2.Dato_Auxiliar_2('ABOR') #Finalizacion de
la lectura Intrumento_2
if MODELO_2=='N5752A':
com_lan_2.Dato_Auxiliar_2('OUTP OFF') #Cierre de la
salida. Conigna=0 (Solo para N5752A)
com_lan_1.cierre_Com() #Cierre de
comunicacion Instrumento_1
if com_lan_2 is not False:
com_lan_2.cierre_Com() #Cierre de
comunicacion Instrumento_2
def BK_DATA(dato_XA):
#Separamos el dato en dos datos distintos (Medida 1 y Medida 2)
a,b=dato_XA.split(',')
A=BK_Num_Transform(a) #Eliminamos letras y espacios del dato
recibido
67
B=BK_Num_Transform(b) #Eliminamos letras y espacios del dato
recibido
return A,B
def BK_Num_Transform(num):
#Los datos del BK se reciben tal que asi: ' 47.35 nF , 5.580
kohm'. Necesitamos que solo sea '47.53' y '5.580'
#Comprobamos el string recibido caracter por caracter. Si es un
numero o un '.' nos lo quedamos
dato=''
letras=''
for x in num:
if x.isdigit()==True or x=='.':
#Add numero o punto decimal al dato
dato=dato+x
else:
if x!=' ':
#Eliminamos espacios en blanco
letras=letras+x
if letras=='+Over' or letras=='-Over' or
letras=='Non': #Error en la medida
dato=letras
#Se mantiene el nombre del error para el .csv
return dato
def Consigna_N5752A(key,param):
global com_lan_1
global com_lan_2
if param==1: #Param_1 = Voltage
OK=0
while (not OK):
try:
print ('\nIntroduce Voltage (V):')
vol_level=(float(raw_input('NOTE: MAX Voltage allowed:
600 V\n')))
if vol_level>=0.0 and vol_level<600.1:
if key=='1': #Key_1 = Primer
Instrumento
com_lan_1.Dato_Auxiliar_2('VOLT
'+str(vol_level))
if key=='2': #Key_2 = Segundo
Instrumento
com_lan_2.Dato_Auxiliar_2('VOLT
'+str(vol_level))
print 'Supply level: '+str(vol_level)+ ' V'
OK=1
else:
print 'Out of Voltage range'
except ValueError:
print 'Error Input - Do not introduce characters'
except:
68
print '\tCom_Error'
print('NOTE: Values can be modified in the front panel of the
instrument\n')
if param==2: #Param_2 = Current
OK=0
while (not OK):
try:
print ('\nIntroduce current max (A):')
curr_level=(float(raw_input('NOTE: MAX Current
allowed: 1.3 A\n')))
if curr_level>=0.0 and curr_level<1.3:
if key=='1':
com_lan_1.Dato_Auxiliar_2('CURR
'+str(curr_level)) #Entregamos consigna de corriente maxima
if key=='2':
com_lan_2.Dato_Auxiliar_2('CURR
'+str(curr_level)) #Entregamos consigna de corriente maxima
print 'Current limited to '+str(curr_level)+ '
A\n'
OK=1
else:
print 'Out of Current range\n'
except:
print 'Error Input - Do not introduce characters\n'
def Control_Com(Medir,Cerrar):
#Variables de control para autrizar o detener la lectura y
comunicacion con intrumentos
global Autorizar_Medida
global Cerrar_Comunicacion
Autorizar_Medida=Medir
Cerrar_Comunicacion=Cerrar
def
Datos_para_lectura(Ip_1,Canal_1A,Canal_1B,Meas_1A,Meas_1B,Bi_Chan_1,Mo
delo_1,
Ip_2,Canal_2A,Canal_2B,Meas_2A,Meas_2B,Bi_Chan_2,Modelo_2):
#Variables Instrumento 1
global IP_1
global CANAL_1A
global CANAL_1B
global MEAS_1A
global MEAS_1B
global BI_CHAN_1
global MODELO_1
#Variables Instrumento 2
global IP_2
global CANAL_2A
global CANAL_2B
global MEAS_2A
global MEAS_2B
global BI_CHAN_2
global MODELO_2
69
IP_1=Ip_1
CANAL_1A=Canal_1A
CANAL_1B=Canal_1B
MEAS_1A=Meas_1A
MEAS_1B=Meas_1B
BI_CHAN_1=Bi_Chan_1
MODELO_1=Modelo_1
IP_2=Ip_2
CANAL_2A=Canal_2A
CANAL_2B=Canal_2B
MEAS_2A=Meas_2A
MEAS_2B=Meas_2B
BI_CHAN_2=Bi_Chan_2
MODELO_2=Modelo_2
11.2.6 SAVE.py
#!/usr/bin/env python
import wx
import csv
import CSV_Data
import PLOT
import os
from datetime import datetime
def save(self, event):
global pathname
#Creacion de ventana de guardado de archivos
save_window=wx.FileDialog(self, "Creating new .csv
file",wildcard="CSV Files (*.csv)|*.csv",style=wx.FD_SAVE |
wx.FD_OVERWRITE_PROMPT)
#Si cerramos la ventana de guardar archivo sin elegir la ruta de
guardado, se crea automaticamente un archivo de
#seguridad para almacenar las medidas. De no ser asi, se crearia
una excepcion y terminaria el programa.
if save_window.ShowModal() == wx.ID_CANCEL:
date=str(datetime.today())[:-10] #Year-Month-
Day_Hour-Min
date_today=''
for x in date:
if x==':': x='.' #Eliminamos ':' por
ser caracter prohibido al guardar un archivo
if x==' ': x='_' #Eliminamos el
espacio entre fecha y hora por estetica
date_today=date_today+x
with open('Security_file'+'_'+date_today+'.csv', 'w') as f:
path=os.getcwd() #Directorio actual
de ejecucion
pathname=path+'/Security_file'+"_"+date_today+'.csv'
print '\nSave window closed. A security file has been
created to store data.'
print 'Security file created in: '+pathname
f.close()
else:
70
pathname = save_window.GetPath() #Obtencion de la
ruta de guardado seleccionada
CSV_Data.Rec_Path(pathname) #Enviamos el
pathname del .csv para escritura
PLOT.Rec_Path(pathname) #Enviamos el
pathname del .csv para lectura en el plot
try:
with open(pathname, "wb") as f:
writer = csv.writer(f, delimiter=',')
INSTRU_1=NAME_1+' '+MODELO_1 #Nombre
del instrumento 1
INSTRU_2=NAME_2+' '+MODELO_2 #Nombre
del instrumento 2
writer.writerow(('',INSTRU_1,'', INSTRU_2)) #Primera
line de texto con el nombre del los instrumentos
#Hora lectura y nombre de las instruciones
writer.writerow(("Hora
Lectura",MEAS_NAME_1A,MEAS_NAME_1B,MEAS_NAME_2A,MEAS_NAME_2B))
f.close()
except IOError:
wx.LogError("An error has ocurred creating the .csv file.
Reboot the program please.")
return
def exe(): #Mantiene la ventana abierta
app = wx.App(False)
frame = save(None,"")
app.MainLoop()
def
Nombre_instrumento(nombre_1,modelo_1,dato_1a,dato_1b,nombre_2,modelo_2
,dato_2a,dato_2b):
global NAME_1, MODELO_1, MEAS_NAME_1A,MEAS_NAME_1B
global NAME_2,MODELO_2, MEAS_NAME_2A,MEAS_NAME_2B
NAME_1=nombre_1
MODELO_1=modelo_1
MEAS_NAME_1A=dato_1a
MEAS_NAME_1B=dato_1b
NAME_2=nombre_2
MODELO_2=modelo_2
MEAS_NAME_2A=dato_2a
MEAS_NAME_2B=dato_2b
exe() #Ejecucion de la ventana de creacion de archivo .csv
def Leer_Pathname():
#Se utiliza en MAIN para obtener el pathname
return pathname
11.2.7 CSV_Data.py
#!/usr/bin/env python
cnt=1 #Contador para printear cantidad de lecturas (no necesario)
def escribir(data_time, data):
71
global cnt
data_1A=data[0] #Dato 1/Instrumento 1
data_1B=data[1] #Dato 2/Instrumento 1
data_2A=data[2] #Dato 1/Instrumento 2
data_2B=data[3] #Dato 2/Instrumento 2
try:
with open(pathname, 'a') as f:
f.write(data_time+","+data_1A+","+data_1B+','+data_2A+','+data_2B+'\n'
) #Escritura de datos recibidos
f.close()
#print 'Hora lectura: '+data_time
#print("Num. escrituras: "+str(cnt))
cnt=cnt+1
except IOError:
print 'An error has occurred. Data is not been stored. \n \tIf
you have the .csv file opened, close it to continue.'
def Rec_Path(PATH):
#Recibimos el pathname del archivo .csv desde el modulo SAVE
global pathname
pathname=PATH
11.2.8 PLOT.py
#!/usr/bin/env python
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import matplotlib.ticker as mtiker
from matplotlib import style
def Plot_Data():
#////////////////////////////////////////// DATA
//////////////////////////////////////////
error_value=0 #Valor que tomara el dato para ser ploteado si el
original es un error
with open(pathname,'r') as f: #Apertura del archivo a leer
graph_data=f.read() #Lectura del archivo
f.close #Cierre del archivo para
permitir actualizaciones
lines = graph_data.split('\n') #Separacion de las distintas
lineas leidas
TIME=[] #Arrays almacenador de datos de tiempo
y1=[] #Arrays almacenador de datos de eje Y Izquierda -
Instrumento 1
y2=[] #Arrays almacenador de datos de eje Y Derecha -
Instrumento 1
y3=[] #Arrays almacenador de datos de eje Y Izquierda -
Instrumento 2
y4=[] #Arrays almacenador de datos de eje Y Derecha -
Instrumento 2
72
cnt=0 #Contador para evitar leer las primeras lineas de
texto (no datos) del .csv
for line in lines:
if cnt>2 and line!='': #Evitamos leer primera y
segunda linea (texto) y ultima(espacio en blanco)
t,L_1,R_1,L_2,R_2=line.split(',') #Separacion de cada
linea por datos (tiempo, medida_1, medida2)
TIME.append(str(t)) #conv. a string de las
horas para mostrar en plot. Add to array TIME[]
try:
y1.append(float(L_1)) #conv. a float para
representacion grafica de DATO_1. Add to array y1[]
except: #Si es un str no se
puede convertir a float - Dato Erroneo - Dato=0 para representacion
L_1=error_value
y1.append(float(L_1))
if(LABEL_1B!=''):
try:
y2.append(float(R_1)) #conv. a float para
representacion grafica de DATO_2. Add to array y2[]
except: #Si es un str no se
puede convertir a float - Dato Erroneo - Dato=0 para representacion
R_1=error_value
y2.append(float(R_1))
if (LABEL_2A!=''):
try:
y3.append(float(L_2)) #conv. a float para
representacion grafica de DATO_3. Add to array y3[]
except: #Si es un str no se
puede convertir a float - Dato Erroneo - Dato=0 para representacion
L_2=error_value
y3.append(float(L_2))
if (LABEL_2B!=''):
try:
y4.append(float(R_2)) #conv. a float para
representacion grafica de DATO_4. Add to array y4[]
except: #Si es un str no se
puede convertir a float - Dato Erroneo - Dato=0 para representacion
R_2=error_value
y4.append(float(R_2))
else: cnt=cnt+1 #Incremento de contador
de lineas leidas
return TIME,y1,y2,y3,y4
def Plotting(i):
TIME,y1,y2,y3,y4=Plot_Data() #Actualizacion de los datos a
plotear
#////////////////////////////////////////// PLOT
//////////////////////////////////////////
73
#--------------------------------- Eje X, Eje Y_Izquierda, 1r DATO ---
------------------------------
ax1.plot(TIME, y1, marker='o', color='blue')
#Dibujado de valores 1
ax1.autoscale()
#Atoescala
ax1.set_xlabel('time (s)')
#Etiqueta eje X
ax1.set_ylabel(str(LABEL_1A), color='blue')
#Etiqueta eje Y izquierda
ax1.tick_params('y', colors='blue', labelsize='small')
#Numeros escala izquierda
#ax1.grid(color='#4285f4') #Color
rejilla
ax1.grid(False)
#Rejilla izquierda (sin rejilla)
ax1.xaxis.set_major_locator(mtiker.MaxNLocator(20))
#Cantidad maxima de valores en eje X
#--------------------------------- Eje Y_Derecha, 2o DATO ------------
----------------------
#Solo si hay segundo dato
if (LABEL_1B!=''):
ax2.plot( y2, marker='D', color='green')
#Dibujado de valores 2
ax2.autoscale()
#Autoescala
ax2.set_ylabel(str(LABEL_1B), color='green')
#Etiqueta eje Y derecha
ax2.tick_params('y', colors='green', labelsize='small')
#Numeros escala derecha
#ax2.grid(color='#742157') #color
rejilla
ax2.grid(False)
#Rejilla derecha (sin rejilla)
else:
#Ponemos el eje Y_Derecho en blanco para ocultarlo en caso de
solo haber 1 dato
ax2.tick_params('y', colors='white', labelsize='small')
######################################### PLOT SEGUNDO INSTRUMETO
#########################################
#--------------------------------- Eje X, Eje Y_Izquierda, 1r DATO ---
------------------------------
if (LABEL_2A!=''):
ax3.plot( TIME, y3, marker='X', color='purple')
#Dibujado de valores 1
ax3.autoscale()
#Atoescala
ax3.set_xlabel('time (s)')
#Etiqueta eje X
ax3.set_ylabel(str(LABEL_2A), color='purple')
#Etiqueta eje Y izquierda
ax3.tick_params('y', colors='purple', labelsize='small')
#Numeros escala izquierda
#ax3.grid(color='#4285f4')
#Color rejilla
74
ax3.grid(False)
#Rejilla izquierda (sin rejilla)
ax3.xaxis.set_major_locator(mtiker.MaxNLocator(10))
#Cantidad maxima de valores en eje X
#--------------------------------- Eje Y_Derecha, 2o DATO ------------
----------------------
#Solo si hay segundo dato
if (LABEL_2B!=''):
ax4.plot(y4, marker='D', color='red')
#Dibujado de valores 2
ax4.autoscale()
#Autoescala
ax4.set_ylabel(str(LABEL_2B), color='red')
#Etiqueta eje Y derecha
ax4.tick_params('y', colors='red', labelsize='small')
#Numeros escala derecha
#ax4.grid(color='#742157')
#color rejilla
ax4.grid(False)
#Rejilla derecha (sin rejilla)
else:
#Ponemos el eje Y_Derecho en blanco para ocultarlo en caso
de solo haber 1 dato
ax4.tick_params('y', colors='white', labelsize='small')
fig.tight_layout() #Autoajuste a pantalla
fig.autofmt_xdate() #Formato numeros exe X en vertical
def Go_plot():
#Muestra y mantiene el plot abierto
ani=animation.FuncAnimation(fig, Plotting, interval=1000)
#interval(ms).Intervalo de redibujado
plt.show() #Mostrar plot
def Label_name(name_1A,name_1B,name_2A,name_2B,titulo_1,titulo_2):
#Obtencion de las etiquetas de cada dato
global LABEL_1A
global LABEL_1B
global LABEL_2A
global LABEL_2B
global TITLE_1
global TITLE_2
LABEL_1A=name_1A
LABEL_1B=name_1B
LABEL_2A=name_2A
LABEL_2B=name_2B
TITLE_1=titulo_1
TITLE_2=titulo_2
#Para creacion de segndo plot. Se creara un segundo plot en la
misma ventana si hay datos de un segundo instrumento
Create_Figure(LABEL_2A)
def Rec_Path(PATH):
#Recibimos el pathname del archivo .csv desde el modulo SAVE para
leer
global pathname
pathname=PATH
75
def Create_Figure(Second_plot):
#---------------------- Configuracion del PLot -----------------------
--------
global fig
global ax1, ax2, ax3, ax4
#style.use('bmh') #Posible estilo artistico del plot
style.use('seaborn') #Estilo artistico del plot
fig=plt.figure() #Creacion de la figura (ventana)
if Second_plot=='': #Si no hay segundo instrumento
ax1=fig.add_subplot(111) #1 plot en ventana
ax2=ax1.twinx() #ax2 comparte eje X con ax1
plt.title(TITLE_1)
else: #Si hay segundo instrumento
ax1=fig.add_subplot(211) #2 plots en ventana. Posicion UP
ax2=ax1.twinx()
plt.title(TITLE_1) #ax2 comparte eje X con ax1
ax3=fig.add_subplot(212) #2 plots en ventana. Posicion DOWN
ax4=ax3.twinx() #ax4 comparte eje X con ax3
plt.title(TITLE_2)
fig.tight_layout() #Autoajuste a pantalla
fig.autofmt_xdate() #Formato numeros exe X en vertical
11.2.9 Lista_Instrucciones.py
#!/usr/bin/env python
"""*******************************************************************
***********************************************
Este modulo es llmado entre 1 y 2 veces durante la ejecucion del
programa principal, dependiendo de si hay 1 o 2
instrumentos en uso.
Recibe el modelo y el nombre(estetico, para mostrar por pantalla y
diferenciar, pero indispensable) del instrumento.
Segun el modelo, se mostraran por pantala las distintas opciones de
medida y si se da el caso (Agilent/Keysight_34972A-
BK 891), se preguntara la cantidad de tipos de medidas (1 o 2) que se
desean realizar entre las distintas opciones.
El modulo retorna la instruccion SCPI para enviar al instrumento y su
nombre (estetico pero necesario).
En caso de solo haber 1 instruccion, se retornara un espacio en blanco
'' siempre.
**********************************************************************
********************************************"""
import LAN
def Instruccion_medir(MODELO, NAME):
if MODELO == '34972A':
Num_Meas('Agilent/Keysight 34972A') #Pedir cantidad de
tipos de medidas a realizar con el instrumento (1/2)
MEAS_1,MEAS_2,MEAS_NAME_1,MEAS_NAME_2 =
Agilent_Keysight_34972A(NAME)
76
if MODELO == '891':
MEAS_1,MEAS_2,MEAS_NAME_1,MEAS_NAME_2 = BK_891()
if MODELO == 'N5752A': #Power supply.
MEAS_1,MEAS_2,MEAS_NAME_1,MEAS_NAME_2=Keysight_N5752A()
if MODELO == '33521A': #Waveform generatior.
MEAS_1,MEAS_2,MEAS_NAME_1,MEAS_NAME_2=Keysight_33521A()
return MEAS_1,MEAS_2,MEAS_NAME_1,MEAS_NAME_2
def Num_Meas(name):
global num_meas
OK=0
while (not OK):
try:
num_meas=int(raw_input('\nTypes of measurements to do with
'+name+'? (1/2)\n'))
if (num_meas==1 or num_meas==2): OK=1
if (not OK): print 'ERROR INPUT - Out of range'
except:
print 'Error Input - Do not introduce characters'
def Agilent_Keysight_34972A(NAME):
#NAME sirve para diferenciar entre Agilent y Keysight
#Lista de comandos SCPI para Agilent/Keysight_34972A
Agi_Key_measures='1':'MEAS:VOLT:DC?','2':'MEAS:VOLT:AC?','3':'MEAS:RE
S?','4':'MEAS:FRES?','5':'MEAS:CURR:DC?',
'6':'MEAS:CURR:AC?','7':'MEAS:FREQ?','8':'MEAS:PER?','9':'MEAS:TEMP?'
#Lista de nombres para mostrar por pantalla
Agi_Key_names='1':'Voltage DC (V)','2':'Voltage AC (V)','3':'2-
Wire Resistance (Ohm)','4':'4-wire resistance (Ohm)','5':'Current DC
(A)',
'6':'Current AC (A)','7':'Frequency (Hz)','8':'Period
(seg)','9':'Temperature'
#Instruciones para elegis comandos SCPI
Ag_Ke=""""============================================================
======================="
"""+NAME+""" 34972A
1)Voltage DC 2)Voltage AC 3)2-Wire Resistance 4)4-Wire
Resistance
5)Current DC 6)Current AC 7)Frequency 8)Period
9)Temperature
"""
print Ag_Ke
#---------------------------------- Primera Medida ---------------
--------------------------------------------
OK=0 #Variable de control para bulce
while(not OK):
x=str(raw_input('Choose NUMBER of FIRST measure: '))
#Eleccion de comando para primer tipo de medida
try:
x=int(x)
if (x in range (1,10)):OK=1
if (OK==0): print 'ERROR INPUT - Out of range'
except:
77
print 'ERROR INPUT - Introduce a number'
x=str(x)
meas_1=Agi_Key_measures[x] #Eleccion de comando SCPI 1 segun
numero introducido
meas_name_1=Agi_Key_names[x] #Nombre del comando 1 para .csv y
plot
print meas_name_1
#if meas_name_1=='4-wire resistance (Ohm)':
#num_meas=1
if (num_meas==1): #Solo se realiza una medida
meas_2=''
meas_name_2=''
return (meas_1,meas_2,meas_name_1,meas_name_2) #Retornamos
comandos pedidos para medidas
#---------------------------------- Segunda Medida ---------------
--------------------------------------------
OK=0 #Variable de control para bulce
while(not OK):
y=str(raw_input('Choose NUMBER of SECOND measure: '))
#Eleccion de comando para segundo tipo de medida
try:
y=int(y)
if (y in range (1,10)):OK=1
if (OK==0): print 'ERROR INPUT - Out of range'
except:
#Error al convertir a integer
print 'ERROR INPUT - Introduce a number'
y=str(y)
meas_2=Agi_Key_measures[y] #Eleccion de comando SCPI 2 segun
numero introducido
meas_name_2=Agi_Key_names[y] #Nombre del comando 2 para .csv y
plot
print meas_name_2
return (meas_1,meas_2,meas_name_1,meas_name_2) #Retornamos
comandos pedidos para medidas
def BK_891():
#Lista de comandos SCPI para BK Precision 891
BK_meas='CSQ':'MEAS:FUNC CSQ','CSD':'MEAS:FUNC
CSD','CSR':'MEAS:FUNC CSR','CPQ':'MEAS:FUNC CPQ','CPD':'MEAS:FUNC
CPD',
'CPR':'MEAS:FUNC CPR','CPG':'MEAS:FUNC CPG','LSQ':'MEAS:FUNC
LSQ','LSD':'MEAS:FUNC LSD','LSR':'MEAS:FUNC LSR',
'LPQ':'MEAS:FUNC LPQ','LPD':'MEAS:FUNC LPD','LPR':'MEAS:FUNC
LPR', 'LPG':'MEAS:FUNC LPG', 'ZTH':'MEAS:FUNC ZTH',
'YTH':'MEAS:FUNC YTH','RX':'MEAS:FUNC RX','GB':'MEAS:FUNC
GB','DCR':'MEAS:FUNC DCR'
78
BK_meas_prim='1':'CS','2':'CP','3':'LS','4':'LP','5':'Z','6':'Y','7':
'R','8':'G','9':'DCR'
BK_meas_second='1':'Q','2':'D','3':'R','4':'G','5':'X','6':'B'
#Instruciones para elegis comandos SCPI
BK_Prim="""===========================================================
===================================
"BK Precision 891"
Primary parameters:
1) CS- Capacitance value measured using a series equivalent circuit
model
2) CP- Capacitance value measured using a parallel equivalent circuit
model
3) LS- Inductance value measured using a series equivalent circuit
model
4) LP- Inductance value measured using a parallel equivalent circuit
model
5) Z- Impedance value
6) Y- Admittance value
7) R- Resistance value using a specified AC frequency and level
8) G- Conductance value
9) DCR- Resistance value using a DC bias
"""
BK_Second_1="""
Secondary Parameters:
Q- Quality factor
D- Dissipation factor
R- Equivalent resistance
"""
BK_Second_2="""
Secondary Parameters:
Q- Quality factor
D- Dissipation factor
R- Equivalent resistance
G- Conductance
"""
BK_Second_3="""
Secondary parameters:
TH- Thevenin
"""
BK_Second_4="""
Secondary Parameters:
X- Reactance
"""
BK_Second_5="""
Secondary Parameters:
B- Susceptance
"""
BK_CS="""1)CS-Q 2)CS-D 3)CS-R"""
BK_CP="""1)CP-Q 2)CP-D 3)CP-R 4)CP-G"""
BK_LS="""1)LS-Q 2)LS-D 3)LS-R"""
BK_LP="""1)LP-Q 2)LP-D 3)LP-R 4)LP-G"""
BK_ZTH="""1)Z-TH"""
BK_YTH="""1)Y-TH"""
BK_RX="""1)R-X"""
BK_GB="""1)G-B"""
BK_DCR="""DCR - Secondary parameters not alowed"""
79
#-------------------------------- Parametros principales -------------
------------------------------
print BK_Prim #Parametros principales
OK=0
while (not OK):
prim=str(raw_input('Choose the number of primary parameter:
'))
try:
prim=int(prim) #Conversion a int
if prim in range (1,10):
OK=1
x=BK_meas_prim[str(prim)] #Nombre de la instruccion
primaria
print x
if prim not in range(1,10):
print 'Error Input - Out of range' #Fuera de rango
except:
print 'Error Input - Introduce a number' #No se ha
introducido un int
#-------------------------------- Parametros secundarios -------------
------------------------------
if prim == 9:
print BK_DCR #9)DCR
inst='DCR'
else:
if prim==1 or prim == 3: #1)CS 2)LS
print BK_Second_1 #Q/D/R
if prim==1: print BK_CS #Instrcciones CS
if prim==3: print BK_LS #Instrucciones LS
OK=0 #Peticion de numero de instrucion
while (not OK):
second=str(raw_input('Choose the number of secondary
parameter: '))
try:
second=int(second)
if second in range (1,4):
OK=1
y=BK_meas_second[str(second)] #Nombre de la
instruccion primaria
inst=x+y
print inst
if second not in range(1,4):
print 'Error Input - Out of range'
except:
print 'Error Input - Introduce a number'
if prim==2 or prim==4: #2)CP 3)LP
print BK_Second_2 #Q/D/R/G
if prim==2: print BK_CP #Instruciones CP
if prim==4: print BK_LP #Instruciones LP
OK=0 #Peticion de numero de instrucion
while not OK:
second=str(raw_input('Choose the number of secondary
parameter: '))
try:
80
second=int(second)
if second in range (1,5):
OK=1
y=BK_meas_second[str(second)] #Nombre de la
instruccion primaria
inst=x+y
print inst
if second not in range(1,5):
print 'Error Input - Out of range'
except:
print 'Error Input - Introduce a number'
if prim==5 or prim==6 or prim==7 or prim==8: #5)ZTH
6)YTH 7)RX 8)GB
if prim==5:
print BK_Second_3 #TH
print BK_ZTH #Instruciones Z
y='TH'
if prim==6:
print BK_Second_3 #TH
print BK_YTH #Instruciones Y
y='TH'
if prim==7:
print BK_Second_4 #X
print BK_RX #Instruciones R
y='X'
if prim==8:
print BK_Second_5 #B
print BK_GB #Instruciones G
y='B'
OK=0 #Peticion de numero de instrucion
while not OK:
second=str(raw_input('Choose the number of secondary
parameter: '))
try:
second=int(second)
if second==1:
OK=1
inst=x+y
print inst
if second!=1:
print 'Error Input - Out of range'
except:
print 'Error Input - Introduce a number'
#---------------------------------------------------------------------
--------------------------------
medida=BK_meas[inst] #Instrucion SCPI para establecer tipo de
medida
IP='10.30.235.170' #IP Para la comunicacion previa a la
medida (set del tipo de medida)
PORT=5025
Buffer_Size=1024
TIMEOUT=10 #TIMEOUT sufucientemente grande como para
permitir lecturas
com_lan=LAN.LAN(IP,PORT,Buffer_Size,TIMEOUT) #Constructor
de clase para comunicacion
81
com_lan.Dato_Auxiliar_2(medida) #Establecemos
el tipo de medida a realizar
aux_data=com_lan.Dato_Auxiliar('MEAS:RESU?') #Medida
temporal para tomar las unidades
com_lan.cierre_Com() #Cerramos la
comunicacion
uds_1,uds_2=BK_Unidades(aux_data)
#Los datos del BK981 se reciben juntos por el mismo canal de
medida, por lo que hay que separarlos al recibirlos
#Esto se hace en el modulo de adquisicion de datos. Aun asim hay
que indicar el nombre de la segunda medida como
#si se recibiesen de forma separada.Fisicamente, NO se puede hacer
solo la medida principal (excepto la DCR)
meas_1='MEAS:RESU?' #instrucion para pedida de datos.
meas_name_1=x+' '+'('+uds_1+')'
meas_2=''
meas_name_2=y+' '+'('+uds_2+')'
return (meas_1, meas_2, meas_name_1, meas_name_2) #Retornamos
comandos pedidos para medidas
def BK_Unidades(num):
#Los datos del BK se reciben tal que asi: ' 47.35 nF , 5.580
kohm'. Necesitamos que solo sea 'nF' y 'kohm'
#Comprobamos el string recibido caracter por caracter. Si es una
letra nos lo quedamos
un_1='' #Si no se obtiene ningun
dato o si el dato no tiene unidades se retornara ''
un_2=''
try:
a,b=num.split(',') #Separamos los dos datos
mediante las comas
for x in a: #Primer dato. Lectura
caracter a caracter
if x.isalpha()==True:
un_1=un_1+x #Si el caracter es una
letra, se actualiza
for x in b: #Segundo dato. Lectura
caracter a caracter
if x.isalpha()==True:
un_2=un_2+x #Si el caracter es una
letra, se actualiza
except:
print 'Units label not obtained' #Error de lectura. No se
ha obtenido ningun dato
return un_1,un_2
def Keysight_N5752A():
82
IP='10.30.240.134' #IP para la comunicacion para el envio y
disparo de consignas
PORT=5025
Buffer_Size=1024
TIMEOUT=10 #TIMEOUT sufucientemente grande como para
permitir lecturas
com_lan=LAN.LAN(IP,PORT,Buffer_Size,TIMEOUT) #Constructor
de clase para comunicacion. Conexion
OK=0
while (not OK):
try:
print ('\nIntroduce current max (A):')
curr_level=(float(raw_input('NOTE: MAX Current allowed:
1.3 A\n')))
if curr_level>=0.0 and curr_level<1.3:
print 'Current limit: '+str(curr_level)+ ' A\n'
OK=1
else:
print 'Out of Current range'
except:
print 'Error Input - Do not introduce characters'
OK=0
while (not OK):
try:
print ('\nIntroduce Voltage (V):')
vol_level=(float(raw_input('NOTE: MAX Voltage allowed: 600
V\n')))
if vol_level>=0.0 and vol_level<600.1:
print 'Supply level: '+str(vol_level)+ ' V'
OK=1
else:
print 'Out of Voltage range'
except:
print 'Error Input - Do not introduce characters'
print('NOTE: Values can be modified in the front panel of the
instrument\n')
com_lan.Dato_Auxiliar_2('CURR:TRIG '+str(curr_level))
#Entregamos consigna de corriente maxima
com_lan.Dato_Auxiliar_2('VOLT:TRIG '+str(vol_level))
#Entregamos consigna de voltage
com_lan.cierre_Com()
#Cerramos comunicacion
#Retornamos el paedido de medidas de voltage y corriente.
return('MEAS:VOLT?','MEAS:CURR?','Voltage (V)','Current (A)')
def Keysight_33521A():
pass
#Lista de intrucciones no implementada debido a que el instrumento
no es necesario por el momento.
def No_Instrument():
#Retorna espacios en blanco para indicar que no hay ninguna medida
83
#Lo hacemos en una funcion a parte para no 'ensuciar' el programa
principal
return ('','','','')
11.2.10 Select_Chan.py
#!/usr/bin/env python
"""*******************************************************************
************************************
Este modulo diferencia entre los intrumentos que necesitan un canal y
los que no para tomar las medidas.
#Los unicos intrumentos que necesitan selecionar un canal para tomar
medidas son los dataloguers.
**********************************************************************
*********************************"""
def Diferenciar_Modelo(MODELO,NAME,MEAS_NAME_1,MEAS_NAME_2):
if MODELO=='34972A' or MODELO=='34970A': #Instrumentos con 2
caneles de medida
if(MEAS_NAME_2==''):NUM=0 #1 tipo de medida
if(MEAS_NAME_2!=''):NUM=1 #2 tipos de medida
CANAL_1,CANAL_2=CHANELS(NUM, MODELO, NAME,
MEAS_NAME_1,MEAS_NAME_2)
BI_CHAN_INSTR=True
else:
CANAL_1=''
CANAL_2=''
BI_CHAN_INSTR=False
return (CANAL_1,CANAL_2,BI_CHAN_INSTR )
def CHANELS(NUM, MODELO, NAME, MEAS_NAME_1,MEAS_NAME_2):
print("""\nCHANELS: Xnn\nX=Slot [1,2,3]\nnn=Channel [1...22]\n""")
#----------------------------------------- Primer Canal --------------
------------------------------------------
OK=0
while (not OK):
try:
chan_1=int(raw_input('Introduce first channel to read
'+MEAS_NAME_1+' with '+NAME+' '+MODELO+': \n'))
if (chan_1 in range (101,122)):OK=1
if (chan_1 in range (201,222)):OK=1
if (chan_1 in range (301,322)):OK=1
if (OK==0): print "ERROR INPUT - Out of range.\n"
#Numero no valido
if ((OK==1)and(MEAS_NAME_1=='4-wire resistance (Ohm)')):
chan=chan_1+10
print 'NOTE: As you have select 4-wire resistance
measure for the '+str(chan_1)+' channel, be sure you have wired the
'+str(chan)+' channel\n'
else:
#Para evitar la aparacicion de un error, si la medida
no es a 4 hilos, chan=chan_1
chan=chan_1
except:
84
print 'Error Input - Do not introduce characters.\n'
if (not NUM): #Solo hay 1 canal en uso. NUM=0
return (str(chan_1),'')
#----------------------------------------- Segundo Canal -------------
-------------------------------------------
OK=0
while (not OK):
try:
chan_2=int(raw_input('Introduce second channel to read
'+MEAS_NAME_2+' with '+NAME+' '+MODELO+': \n'))
if ( (chan_2 in range (101,122)) and (chan_2!= chan_1) and
chan_2!= chan ):OK=1
if ( (chan_2 in range (201,222)) and (chan_2!= chan_1) and
chan_2!= chan ):OK=1
if ( (chan_2 in range (301,322)) and (chan_2!= chan_1) and
chan_2!= chan ):OK=1
if (OK==0): print "ERROR INPUT - Out of range or channel
already selected.\n" #Numero no valido
if ((OK==1)and(MEAS_NAME_2=='4-wire resistance (Ohm)')):
chan=chan_2+10
print 'NOTE: As you have select 4-wire resistance
measure for the '+str(chan_2)+' channel, be sure you have wired the
'+str(chan)+' channel\n'
except:
print 'Error Input - Do not introduce characters.\n'
return (str(chan_1),str(chan_2))
def No_Instrument():
return ('','','')
#CHANELS(1, 'MODELO', 'NAME', '4-wire resistance','4-wire resistance')
11.2.11 PIN_Instrumento.py
#!/usr/bin/env python
import LAN
import Comunicacion
import time
def Leer_inventario():
#El archivo 'Inventario_Instrumentos.txt' debe encontrarse en la
carpeta del archivo ejecutable
#que contenga el codigo. Los datos almacenados deben estar en este
formato:
#10.30.239.203,Keysight 34972A,6
#10.30.240.134,Agilent N5752A,0.5
# .
# .
# .
85
with open("Inventario_Instrumentos.txt",'r') as f: #Leemos
fichero
lectura = f.read() #Guardamos
texto leido
f.close() #Cerramos
fichero
lines = lectura.split('\n') #Sepramos
lectura en lineas
IPs=[] #Arrays para alamcenar datos leidos
INST=[]
TIMEOUT=[]
for line in lines:
if line!='': #Evitamos lineas en blanco. Si no, da error en
cantidad de argumentos
ip,inst,timeout = line.split(',') #Separamos
elementos de cada linea por comas
IPs.append(str(ip)) #Guardamos
las IPs de cada instrumento
INST.append(str(inst)) #Guardamos
lso nombres de cada instrumento
TIMEOUT.append(str(timeout)) #Guardamos
los timeouts de cada instrumento
conexion=PIN(IPs,INST,TIMEOUT) #Comprobacion de conexion a
la red de los distintos instrumentos
return (conexion) #Retornamos si ha habido conexion con
algun instrumento
def PIN(IPs,INST,TIMEOUT):
PORT=5025 #Puerto Ethernet
BUFFER_SIZE=1024 #tamanio buffer
global arr_IP #Arrays para guardar datos de instrumentos
global arr_NAME
global arr_MODELO
global x #Contador cantidad de instrumentos
arr_IP=[]
arr_NAME=[]
arr_MODELO=[]
arr_TIME=[]
x=0 #Contador de instrumentos
indice=0 #Indice de cada instrumento conectado
for timeouts in TIMEOUT:
arr_TIME.append(float(timeouts)) #Obtenemos los tiempos de
espera para cada instrumento del inventario
print ('Searching for instruments from inventary.........')
for ip_try in IPs:
print 'Trying connexion with '+INST[indice]+' '+'->'+ip_try
86
com_lan=LAN.LAN(ip_try,PORT,BUFFER_SIZE,arr_TIME[indice])
#Constructor de clase para comunicaciones. TIMEOUT en fichero .txt
indice+=1
IDN='' #Vaciamos el IDN para comprobacion de cada
instrumento
try:
IDN=com_lan.Dato_Auxiliar('*IDN?') #Preguntamos ID del
instrumento (SCPI)
com_lan.cierre_Com() #Cerramos
comunicacion
if IDN=='HEWLETT-PACKARD,34970A,0,1012-1-
2\n':IDN='Keysight,34972A'
if IDN!='' and IDN!= 'None':
print 'Connected'
arr_IP.append(ip_try)
instru_name=IDN.split(',')
NAME=str(instru_name[0]) #Guardamos
fabricante y modelo del instrumento
arr_NAME.append(NAME)
MODELO=str(instru_name[1]) #Modelo
instrumento. Se utilizara para la lista de instruciones
arr_MODELO.append(MODELO)
x+=1 #Incremento del
contador de instrumentos detectados
except:
com_lan.cierre_Com() #Cerramos comunicacion para evitar
problemas en caso de no haber comuncacion
if x==0:
conexion=False
print ("Ther are no instruments connected.")
else:
conexion=True
return conexion
def INSTRUMENTS():
NAME=[] #Arrays para guardar datos de los instrumentos
MODELO=[]
IP=[]
if x==1:
print '\n'+str(x)+" INSTRUMENT DETECTED: "
if x>1:
print '\n'+str(x)+" INSTRUMENTS DETECTED: "
for cnt in range(x):
#Print del listado de instrumentos conectados
print str(cnt+1)+') '+ arr_NAME[cnt] + ' ' + arr_MODELO[cnt]+'
-> IP: '+arr_IP[cnt]
print '\nChoose a maximum of 2 to work with. If there are
different instruments and only one is needed, press ENTER after first
one.'
print 'If none of the detected instruments is needed, press 0'
OK=0 #Seleccion del primer instrumento
87
while(not OK):
num_1=str(raw_input('Select firs instrument: '))
try: #Hacemos 'try:'
para comprobar conversion a int y evitar strings
num_1=int(num_1)
if num_1==0:
CONEXION=False #No se quiere
utilizar ningun insturmento listado.
print '\n-------------End of execution'
time.sleep(2)
return (CONEXION,0,0,0,0,0,0) #No se quiere
utilizar ningun instrumento listado.
if(num_1 in range (1,x+1)):
NAME.append(arr_NAME[num_1-1]) #Almacenamos
NOMBRE del instrumento (Fabricante)
MODELO.append(arr_MODELO[num_1-1]) #Almacenamos
MODELO del instrumento (Num.Serie)
IP.append(arr_IP[num_1-1]) #Almacenamos IP
del instrumento
OK=1
CONEXION=True
if(num_1 not in range (1,x+1)):
print 'ERROR INPUT - Out of range'
except: #Conversion a
int fallida
print 'ERROR INPUT - Do not introduce characters'
#-----------------------------------------------------------------
------
if x==1:
NAME.append('') #Almacenamos '' al no haber segundo
instrumento
MODELO.append('') #Almacenamos '' al no haber segundo
instrumento
IP.append('') #Almacenamos '' al no haber segundo
instrumento
print 'Only '+NAME[0]+' '+MODELO[0]+' in use.\n'
if x>1:
OK=0 #Seleccion del segundo instrumento
while (not OK):
num_2=str(raw_input('Select second instrument: '))
if (num_2==''): #No se quiere un segundo instrumento de
los detectados o solo hay uno
OK=1
NAME.append('') #Almacenamos '' al no usar
segundo instrumento
MODELO.append('') #Almacenamos '' al no usar
segundo instrumento
IP.append('') #Almacenamos '' al no usar
segundo instrumento
print 'Only '+NAME[0]+' '+MODELO[0]+' in use.\n'
break
try: #Hacemos 'try:' para
comprobar conversion a int y evitar strings
num_2=int(num_2)
if( ( num_2 in range (1,x+1) ) and ( num_2!=num_1 )):
#Segundo instrumento
88
NAME.append(arr_NAME[num_2-1])
MODELO.append(arr_MODELO[num_2-1])
IP.append(arr_IP[num_2-1])
OK=1
if (num_2==num_1):print 'Instrument already
selected\n' #Instrumento ya seleccionado
except:
print 'ERROR INPUT - Do not introduce characters'
#Conversion a int fallida
#Condicion temporal. Comprobacion de conexion con Keysight_33521A
(Arbitrary Waveform Generator)
#Comuicacion con el instrumento. Instrucciones no implementadas
debido a que no es necesario su uso de momento.
n=0
for model in MODELO:
if model=='33521A':
IP[n]=''
NAME[n]=''
MODELO[n]=''
print ('Non-implemented instrument.\nPlease, contact with
the responsible technician if you need to use it.')
n+=1
return (CONEXION,IP[0],IP[1],NAME[0],NAME[1],MODELO[0],MODELO[1])
11.2.12 Terminal.py
#!/usr/bin/env python
import adquisicion_datos
def Terminal(modelo_1,modelo_2):
global main_bucle
main_bucle=False
cnt=0 #Contador de instrumentos N5752A (Power Supply)
conectados
if modelo_1=='N5752A':cnt+=1
if modelo_2=='N5752A':cnt+=1
while main_bucle==False:
if cnt==0:
key=raw_input('Press any key to close comunication\n')
if key or key=='':
Cierre_Com (0,1) #Medir=0, Cerrar=1
main_bucle=True
if cnt==1:
key=raw_input('\nPress (1) to change N5752A
parametres.\nPress any other key to close comunication\n')
if key=='1':
Mod_Consigna_N5752A(key)
if key!='1':
Cierre_Com (0,1) #Medir=0, Cerrar=1
main_bucle=True
if cnt==2:
89
key=raw_input('\nPress (1) to change first N5752A
parametres. Press (2) to change second N5752A parametres.\nPress any
other key to close comunication\n')
if key=='1':
Mod_Consigna_N5752A(key)
if key=='2':
Mod_Consigna_N5752A(key)
if key!='1' and key!='2':
Cierre_Com (0,1) #Medir=0, Cerrar=1
main_bucle=True
return 0
def Cierre_Com(Medir,Cerrar):
Medir=0
Cerrar=1
adquisicion_datos.Control_Com(Medir,Cerrar) #Cierre de
comunicacion. Consignas = OFF
print("COMUNICACION CERRADA")
return 0
def Mod_Consigna_N5752A(key):
global main_bucle
Medir=0
Cerrar=1
bucl=False
while not bucl:
param=raw_input('\nSelect the number of the parametre to
change.\nPress any other key to close comunication.\n1) Voltage
2)Current\n')
try:
param=int(param)
if param in range (1,3):
adquisicion_datos.Consigna_N5752A(key,param)
bucl=True #Salimos del bucle de
encuesta para coger consigna
else:
Cierre_Com(Medir,Cerrar) #Se selecciona
cualquier numero que no sea 1 o 2
main_bucle=True #Saldremos del bucle
principal sin volver a preguntar
bucl=True
except:
Cierre_Com(Medir,Cerrar) #Se selecciona
cualquier tecla que no sea un numero
main_bucle=True #Saldremos del bucle
principal sin volver a preguntar
bucl=True #Salimos del bucle de
encuesta para coger consigna
return 0