Una placa Arduino, desde la más sencilla, como Arduino Uno, es capaz de monitorizar varios sensores e incluso almacenar los valores usando, por ejemplo, una tarjeta de memoria SD pero es obvio que esa información se donde mejor se podrá gestionar es en un ordenador.
Como explicaba hablando de la adquisición de datos y administración desde ordenador de dispositivos microcontrolados, dependiendo de las circunstancias puede convenir almacenar los datos resultado de la monitorización localmente o, más frecuentemente, transmitirlos a un ordenador usando comunicaciones serie UART, si la distancia lo permite, Ethernet o WiFi, si el equipo microcontrolado se encuentra en un entorno de red local o alguna implementación del IEEE 802.15 en redes de bajo consumo.
Una implementación muy sencilla, tanto en hardware como en software, es la que usa las comunicaciones serie, ya que están incorporadas a cualquier placa Arduino. Para desarrollar el software que funciona del lado del ordenador puede utilizarse el lenguaje de programación Python, de aprendizaje muy sencillo, de uso muy inmediato (especialmente por ser interpretado) y extensible gracias a innumerables librerías disponibles para igual número de aplicaciones que además es software libre.
El lenguaje de programación Python está presente en muchos sistemas, entre otras razones porque se usa frecuentemente para escribir guiones (scripts) de mantenimiento. En cualquier caso, antes de empezar la programación, es importante verificar que ya está disponible o instalar Python y las librerías para desarrollo de comunicaciones serie así como el entorno de desarrollo de Arduino.
Para explicar el proceso de adquisición de datos enviados por Arduino desde Python se supone un montaje formado por cierto número de sensores analógicos (4 en el ejemplo, que se pueden modificar fácilmente cambiando el valor de CANTIDAD_SENSORES
en el programa para Arduino) que iría recibiendo datos cada cierto intervalo de tiempo (correspondiente al valor de MINIMO_TIEMPO_LECTURA
expresado en milisegundos) y los enviaría por el puerto serie si hubiera cambios respecto de la última lectura.
El estado de monitorización activo se representa por un LED que parpadea a cierta velocidad también regulable como parte de la configuración de la aplicación cambiando el valor de TIEMPO_PARPADEO
.
El circuito se activa y se desactiva accionando un pulsador (protegido contra rebotes por un condensador) que genera una interrupción de forma que sólo está enviando datos de monitorización al ordenador cuando el usuario lo desea. En el programa de ejemplo en Python se escribe toda la información en el mismo documento pero es trivial cambiar el código para generar un documento nuevo cada vez si fuera necesario (cambiando el nombre para usar un código numérico, horario…) aunque, como se almacena la fecha y la hora de cada estado monitorizado, puede servir perfectamente para múltiples sesiones sin cambios.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
#!/usr/bin/python import time import serial puerto_serie=serial.Serial(2,9600,timeout=0) monitor_activo=0 while 1: lectura=puerto_serie.readline().strip() if lectura=='inicio': fichero=open('informe_sensores.csv','a') monitor_activo=1 else: if monitor_activo: if lectura=='fin': monitor_activo=0 fichero.close() else: if len(lectura)>2: fichero.write(str(time.time())+','+lectura[:-1]+'\n') # Sólo para la fase de prueba para ver los datos enviados por Arduino # print lectura # time.sleep(0.01) puerto_serie.close() # Nunca llega a ejecutarse al estar fuera del bucle while pero se incluye para ilustrar la secuencia correcta de manejo de un puerto serie en Python con PySerial |
Para almacenar los datos se ha elegido el formato CSV que tiene la ventaja de ser fácilmente interpretado por muchas aplicaciones aunque con el inconveniente de ocupar mucho más de lo necesario dado que almacena como texto todos los valores, lo que no parece un problema especialmente importante al estar guardando los datos en algún dispositivo de almacenamiento masivo del ordenador.
Se han elegido las palabras clave «inicio» y «fin» para indicar respectivamente el inicio y el final de cada sesión de envío de datos desde la placa Arduino.
La secuencia de lectura de los datos serie corresponde con el esquema
-
puerto_serie=serial.Serial(2,9600,timeout=0)
-
puerto_serie.open()
(Sólo si no se configura al instanciar el objeto y se hace después) -
repetir:
lectura=puerto_serie.readline().strip()
(strip
elimina el final de línea) -
puerto_serie.close()
La secuencia de escritura en archivo de los valores leídos por el puerto serie corresponde con el esquema
-
fichero=open('informe_sensores.csv','a')
-
repetir:
fichero.write(str(time.time())+','+lectura[:-1]+'\n')
-
fichero.close()
El puerto serie se ha configurado con un tiempo de espera (timeout) de cero, es decir, espera indefinidamente a que llegue la información. Como en el código se ha usado readline()
para leer los datos, antes de dar por terminada una lectura esperará el código de fin de línea así que hay que asegurarse de enviarlo o quedará esperando (colgado) si no se enviara desde Arduino con Serial.println()
o enviando \n en una sentencia Serial.print()
El intercambio de datos se hace enviando desde Arduino una línea de texto formada por los valores obtenidos al leer los sensores y el carácter coma detrás de cada uno de ellos, así que al leerlos con Python se elimina el final de línea y la última letra (la última coma) se le añade la fecha al inicio antes de grabarlo con un nuevo fin de línea para que resulte un documento en formato CSV.
Como todavía no se dispone de una GUI (interfaz gráfica de usuario) para la aplicación y se debe ejecutar desde la consola, para detenerlo habría que cancelarlo (por ejemplo, pulsando Control+C) o terminando la instancia del terminal desde el que se ejecuta.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
#define VELOCIDAD_SERIE 9600 #define CANTIDAD_SENSORES 4 #define MINIMO_TIEMPO_LECTURA 3000 #define TIEMPO_PARPADEO 200 #define NUMERO_INTERRUPCION 0 // La interrupción 0 en una placa Leonardo corresponde al pin 3 y al 2 en las otras #if defined(__AVR_ATmega32U4__) #define PIN_PULSADOR_MONITOR 3 #define ESPERAR_LEONARDO while(!Serial){;} #else #define PIN_PULSADOR_MONITOR 2 #define ESPERAR_LEONARDO // Si no es una placa Leonardo no hay que esperar al puerto serie #endif #define PIN_LED_INDICADOR_MONITOR 13 unsigned long cronometro_sensor; unsigned long cronometro_parpadeo; byte contador; unsigned int lectura; unsigned int sensor[CANTIDAD_SENSORES]; boolean cambio_detectado; String resultado; boolean monitor_activo; // si cambia desde la función de la interrupción -> volatile boolean monitor_activo; boolean estado_led_monitor; void setup() { pinMode(PIN_PULSADOR_MONITOR,INPUT); pinMode(PIN_LED_INDICADOR_MONITOR,OUTPUT); Serial.begin(9600); ESPERAR_LEONARDO for(contador=0;contador<CANTIDAD_SENSORES;contador++) { sensor[contador]=0; } cronometro_sensor=0; cronometro_parpadeo=0; monitor_activo=false; estado_led_monitor=false; attachInterrupt(NUMERO_INTERRUPCION,cambiar_monitor,RISING); } void loop() { if(monitor_activo) { if(millis()>cronometro_parpadeo) { digitalWrite(PIN_LED_INDICADOR_MONITOR,estado_led_monitor); estado_led_monitor=!estado_led_monitor; cronometro_parpadeo=millis()+TIEMPO_PARPADEO; } if(millis()>cronometro_sensor) { cronometro_sensor=millis()+MINIMO_TIEMPO_LECTURA; cambio_detectado=false; resultado=""; for(contador=0;contador<CANTIDAD_SENSORES;contador++) { lectura=analogRead(contador); resultado+=String(lectura,DEC)+","; if(lectura!=sensor[contador]) { sensor[contador]=lectura; cambio_detectado=true; } } if(cambio_detectado) { Serial.println(resultado.substring(0,resultado.length()-1)); } } } } void cambiar_monitor() { digitalWrite(PIN_LED_INDICADOR_MONITOR,LOW); monitor_activo=!monitor_activo; if(monitor_activo) { Serial.println("inicio"); //iniciar_sesion(); // Si el inicio de sesión requiere operaciones más complejas seguramente conviene usar una función en lugar de incluir el código en la de la interrupción } else { Serial.println("fin"); //terminar_sesion(); // Si el finalización de sesión requiere operaciones más complejas seguramente conviene usar una función en lugar de incluir el código en la de la interrupción } } /* // Si el código de inicio y/o finalización de la sesión es mínimamente complejo puede merecer la pena usar funciones en lugar de incluir el código dentro de la función de la interrupción void iniciar_sesion() { Serial.println("inicio"); } void terminar_sesion() { Serial.println("fin"); } */ |
Los datos almacenados en formato CSV se pueden leer fácilmente en una aplicación de hoja de cálculo (como LibreOffice Calc, usada en el ejemplo de la captura de pantalla de abajo) y postprocesarlos, por ejemplo para obtener información de tipo estadístico o para representarlos gráficamente.
Con esto queda bastante resuelta la presentación de datos en diferido pero para el control en tiempo real y/o interactivo será necesario poder ir visualizando la información según se produce, es decir, monitorizar el estado del sistema que se controla con los sensores conectados a la placa Arduino y así desarrollar una suerte de SCADA a pequeña escala, objetivo del proyecto al que pertenece este texto.
Hay también un par de cuestiones importantes para un programa usado en producción que habría que utilizar para optimizarlo y que aquí se han omitido para simplificar el código; por ejemplo, para las comunicaciones es interesante usar hilos de ejecución (usando el módulo threading
de Python) para organizar el uso del procesador.
En el próximo artículo se explica la instalación y el uso de matplotlib, una librería para Arduino con la que trazar gráficas con datos obtenidos de la monitorización de sensores (que pueden usarse también para mostrar información postprocesada) tanto en diferido como en tiempo real.
Federico Gilberto Barberis
Excelente artículo… Mi proyecto es prender y apagar las luces de una habitación y registrar el estado de las mismas, luego subir esa información a una web y desde la misma manejar también los estados de las luces…
Víctor Ventura
Muchas gracias, Federico ¡Suerte con tu proyecto!
Francisco
Saludos!!! Muchas gracias por el aporte, estoy trabajando bajo linux y estoy tratando de grabar los datos en filas y columnas, pero solo me salen en una sola fila cuando lo exporto, pero estoy usando este codigo, me preguntaba si con tu experiencia me puedes ayudar con mi codigo.
# Read & print/write data
import time
import serial
port_serie=serial.Serial(‘/dev/ttyACM0’,9600,timeout=0)
# Open ve_direct.csv
file_data = open(‘ve_data.csv’, ‘w’)
# Listen for the input, exit if nothing received in timeout period
output = » »
while True:
while output != «»:
output = port_serie.readline().strip()
file_data.write(output)
print output,
output = » »
# Close file
print «Stopped writing to ve_data.csv»
file_data.close()
GRACIAS POR TU TIEMPO!!! 🙂
Víctor Ventura
Hola, Francisco.
Para que el documento CSV tenga varias columnas deben grabarse varias líneas con datos separados por comas.
El código que mandas es la parte que recibe los datos y los graba en un documento CSV. El código que los envía ¿Incluye la coma para separarlos?
Gracias por participar en polaridad.es
cristhian david carrasco
buen día soy estudiante de pre grado en ingeniería Biomedica en bogota-Colombia actualmente me encuentro desarrollado un dispositivo para rehabilitación, una parte del proyecto se basa en obtener una gráfica de la fuerza ejercida, esta gráfica se hace necesario que se construya en tiempo real. he intentado realizar la gráfica utilizando matploit pero no lo obtener las gráfica de lo datos que recibo por el puerto serie. me gustaría poder contar con su guía para poder solucionar dicho problema.
agradezco su atención:
Cristhian David Carrasco Villalba
Víctor Ventura
Hola, Cristhian David.
Con tan poca información no sé cómo podría ayudarte. Me queda claro que presentar en tiempo real los datos puede ser un reto interesante del que tomo nota para futuros artículos.
Gracias por visitar polaridad.es
Nicolas Aragon Lopez
Hola buen dia muchas gracias por compartir tus conocimientos.
Hoy en dia estoy trabajando en un proyecto muy similar al que expones, pero tengo algunas dudas qusiera que me ayudaras porfavor. Tengo conectados 8 sensores a mi arduino mega, necesito monitoriar los 8 sensores y compartir esos datos a una raspberry pi (con python), lo que necesito es guardar ese registro en txt. Lo que eh conseguido por ahora es leer el puerto, pero no eh conseguido guardar los datos en un archivo txt.
Víctor Ventura
Hola, Nicolas.
Creo que no entiendo tu pregunta. En el artículo se explica cómo grabar un documento con los datos (un .csv, aunque un .txt sería igual) Básicamente consiste en abrir el documento de forma que se pueda escribir, escribir en él y cerrarlo. Algo como:
Aunque sospecho que algo tan sencillo no va a ser lo que preguntas 🙁 A lo mejor si nos das más información podemos ayudarte mejor.
Gracias por participar en polaridad.es
Nicolas Aragon Lopez
Tengo mi tarjeta arduino la cual tiene 8 sensores de corriente, necesito monitoriar los 8 sensores 24 horas del dia los 7 dias de la semana, los dato de esos sensores lo llevo via serial a raspberry pi (python).
Hasta ahi todo muy bien, que quiero hacer con esos datos? quiero recojerlos de puerto serial, abrir uu archivo plano txt y empesar a gravar los datos que recoja del puerto serial, lo que necesito es un historial de consumo osea que no se puede borrar los datos anteriores. Gracias por tu pronta respuesta presiento que estoy a punto de terminar.
Víctor Ventura
Hola, Nicolas.
Me temo que tienes que releer el artículo, en los ejemplos se hace precisamente lo que pides.
Saludos.
aragon
ingeniero usted en el codigo trabaja con arduino leonardo, yo lo debo de reepplazar por arduino mega?
Víctor Ventura
Hola, Aragon. Lo único que tiene el código para Arduino Leonardo el pin al que se conecta el pulsador que inicia el envío de datos y la espera del puerto serie (línea 31). No creo que afecte a tu programa, pero la espera del programa puedes borrarla sin problemas junto con las líneas que lo definen (las líneas 9 y 12)
Lógicamente, el programa que tú uses será diferente, no porque se ejecute en una placa Arduino Mega, sino porque la monitorización de tus sensores no será como la del ejemplo. Supongo que eso está claro pero mejor recordarlo para evitar más confusiones 🙂
Nicolas Aragon Lopez
por ultimo, cual es el programa en arduino que utilisaste para este ejemplo
Víctor Ventura
Hola, Nicolas.
Creo que hay algo en lo que no nos estamos entendiendo 🙁 Solamente hay dos programas, uno en Python que se ejecuta en el PC y otro para Arduino.
¿Te refieres a eso?
aragon
si señor al de arduino
Víctor Ventura
Pues el del ejemplo del artículo
aragon
File «A.py», line 6
SyntaxError: Non-ASCII character ‘\xc3’ in file A.py on line 6, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details
Víctor Ventura
Hola, Aragon.
El error al que te refieres parece el típico conflicto entre codificaciones (UTF-8 frente a ASCII) ¿Has probado a escribir al principio del documento la línea
# coding: utf-8
o la línea# -*- coding: utf_8 -*-
? Puede que ese sea el problema, como se describe en el enlace de tu error:https://www.python.org/dev/peps/pep-0263
Saludos.
aragon
sigue lo mismo ingeniero
Víctor Ventura
Entonces, parece que no es UTF-8, pero desde luego no es ASCII ¿Qué codificación has usado? ¿Es imprescindible, no puedes sustituir ese signo por otro que sea ASCII?
MIGUE
a mi me pasó lo mismo en Windows 10 al cambiar de editor de texto, pero poniendo lo de coding ya me funciona sin problemas, y sin tener que escribir #!/usr/bin/python
Víctor Ventura
Hola, Migue.
Algunos editores de texto trabajan por defecto en UTF-8, seguramente es lo que le ocurre a tu nuevo editor. Codificar en UTF-8 es muy correcto (creo que hasta podría decirse que es lo normal) y guarda bien la compatibilidad con los caracteres ASCII, la única precaución que hay que tener es usar la codificación UTF-8 sin marca de orden de bytes (BOM).
La línea
#!/usr/bin/python
(que también puedes encontrar como#!/usr/bin/env python
, siempre empezando por#!
, llamado SheBang en GNU/Linux y otros sistemas operativos que proceden de Unix) sirve para localizar el intérprete del lenguaje, Python, en este caso, para poder usar el documento directamente con un ejecutable.Gracias por participar en polaridad.es
aragon
Me sigue aparesiendo el mismo error, que pena con usted tanta molestia ingeniero, es que despues de tanto buscar es su informacion la mas clara que eh encontrado y presiento que es la que necesito para terminar mi proyecto. con cual codigo en arduino pusiste a correr el programa?
Víctor Ventura
Hola, Aragon.
Me parece que estamos organizando un pequeño lío por no seguir el mismo hilo de preguntas y respuestas. Espero no confundirte mucho, ni al resto de lectores, claro 🙂
El error que te aparece indica que has usado texto en una codificación diferente a la que usa el programa (pensaba que UTF-8, pero se ve que no, sin más datos no puedo saberlo)
Otra solución puede ser no utilizar caracteres que no sean ASCII. Quita todas las tildes (acentos) eñes y cualquier otro signo que no corresponda al alfabeto anglosajón.
Espero que esto te ayude ¡Suerte con tu proyecto!
aragon
estoy sobre linux (raspberry pi 3) y tengo python 3.4.2
diego suarez
muy bueno tu aporte!
Tambien lo estoy haciendo sobre una raspberry y con un arduino uno, a la hora de conectar el arduino el programa arranca pero por ningun lado me crear el archivo, que estoy haciendo mal? este programa lee todos los puertos analogos de un arduino leonardo? en que momento el programa inicia a leer los datos del puero serial? debo pulsar algun boton para que el arduino arroje datos?
Muchas gracias
Víctor Ventura
Hola, Diego.
No se me ocurre por qué no encuentras el documento que crea el programa. A lo mejor sería bueno que añadieras una ruta al nombre del documento, algo como:
fichero=open('/carpeta/informe_sensores.csv','a')
También puedes probar el código de ejemplo que le puse a Nicolas para ver si es algo relacionado con la estructura de archivos. Los permisos son un «gran clásico».
También puede ser que no estés utilizando el puerto serie adecuado. Puedes ver los puertos disponibles con la utilidad
python -m serial.tools.list_ports
y luego configurarlo con
puerto_serie.port="/dev/ttyACM2"
y conpuerto_serie.baudrate=9600
para establecer la velocidad (suponiendo que esos sean el puerto y la velocidad correcta para tu caso).El envío de datos desde Arduino empieza cuando pasa a nivel alto el pulsador que hay conectado en el pin de la interrupción correspondiente (pin 3 en mi ejemplo)
Gracias por participar en polaridad.es
Víctor Ventura
Se me olvidaba. El programa del ejemplo lee los (hipotéticos) sensores conectados a los puertos del 0 a
CANTIDAD_SENSORES-1
diego suarez
del 0 a?
Víctor Ventura
Hola, Diego.
En la línea 2 del programa de ejemplo para Arduino se define la macro
CANTIDAD_SENSORES
con número de sensores que se leen, como empieza en 0 leeCANTIDAD_SENSORES-1
.Espero que así se entienda mejor. Saludos.
diego suarez
unsigned int sensor[CANTIDAD_SENSORES];
esta es la parte que no te entiendo muy bien, yo por ejemplo en mi arduino voy a leer por el puerto analogo 1 solo voy a utilizar ese. en que parte debo nombrarlo
Víctor Ventura
Hola, Diego.
Si solamente vas a leer un sensor, te puedes ahorrar el bucle
for
de la línea 58 y leer el sensor directamente en la línea 60. Tampoco necesitas separar con la coma los datos (línea 61)Saludos.
diego suarez
si quisiera leer por los 5 puertos de mi arduino en 5 columnas diferentes como lo podria hacer?
Víctor Ventura
Hola, Diego.
Aprovechando que en Arduino Se puede realizar la lectura analógica con (por ejemplo)
analogRead(3)
igual que conanalogRead(A3)
, el bucle de la línea 58 recorre los puertos analógicos empezando en el primero (cero) hasta el que indiqueCANTIDAD_SENSORES
menos uno.Si quieres leer los seis puertos «compatibles» de Arduino que van del cero al cinco (de A0 hasta A5) puedes asignar a
CANTIDAD_SENSORES
un 6 en la línea 2 de la forma:#define CANTIDAD_SENSORES 6
Espero que esto te resulte útil.
Saludos.
diego suarez
Victor bueno dias muchas gracias por todas tus respuesta de verdad me han ayudado mucho aunque aun tengo un problemita espero me puedas seguir ayudando.
Quiero abrirlo en txt y este es el cambio que realise.
fichero=open(‘informe_sensores.txt’,’a’)
pongo a correr el codigo en mi raspberry y todo funciona bien no aparesen errores, y mi arduino uno enciende y apaga el led rx, que es el que indica que esta enviando datos por el puerto serial. hasta ahi todo muy bien, solo quiero leer una entrada analogica en este caso (A0). lo que hago es que la tengo conectada a 5 voltios esta entrada, osea no la tengo por ahora a ningun sensor pero se supone que me debe de estar leyendo esos 5 voltios de la tarjeta arduino. como te indico el led rx parpadea enviando datos, la carpeta se crea con el nombre sensores.txt pero al momento de abrirla con el editor de texto esta en blanco. sabes porque sucede eso?
Víctor Ventura
Hola, Diego.
¿La carpeta se crea? ¿Qué carpeta? ¿No estás creando un documento?
Que la luz de transmitir se encienda es solamente «media pista» ¿Es seguro que hay algún programa leyendo esos datos?
¿Has probado a grabar algo en el documento como te dije más arriba? con un código como
fichero.write('algo')
te aseguras de que estás grabando correctamente el documento y así puedes ir a buscar los problemas al resto del código.Para saber si están llegando datos por el puerto serie puedes utilizar algún programa que haga de terminal serie (como PuTTY o CuteCom) y así ver si el problema es el programa en la placa Arduino o el programa en la Raspberry Pi.
Suerte con el proyecto.
Nicolas
Por fin!!!
ya todo esta bien muchas gracias…
ingeniero por ultimo, necesito que el archivo txt que estoy creando, crearle una ruta diferente, necesito que ese archivo quede guardado en una carpeta compartida la cual la comparto por samba. tiene alguna informacion de como hacer eso? me refiero a que ya tenemos el archivo pero necesito darle una ruta, por que lo de samba y lo de mas ya lo tengo listo.
Mil gracias
alberto
Que buen aporte!
Te hago una pregunta, necesito leer corrrientes para eso tengo que hacer una pequeña operacion matematica en el IDE de arduino para que por el serial me entregue el valor real de la corriente y no un 5 o 4…. que parte del programa debo modificar para esto?
am1=analogRead(1)*0.021;
Jenifer
Buenas tardes, alguien me podria ayudar con este tema. Tengo una interfas grafica para mostrar la lectura de un sensor LM35 desde arduino, en PyQt5, la lectura se mostrara en la caja de texto sensor_LM35, pero no lo logro. Alguien me podria echar una mano para saber donde esta mi errror adjunto el codigo. muchas gracias
diego suarez
Hola buen dia
Si quiero enviar datos desde que encienda el arduino que parte debo cambiar o suprimir? lo que no quiero es utilizar pulsador, quiero que desde que se encienda el arduino empiese a enviar datos
Angel castro
Hola la verdad vengo buscando, aunque suene mal quien me ayude(haga) mi tarea de programacion es para salvar el semestre , tengo que hacer que python y arduino me digan la temperatura en piserial con el sensor dht 11
alguien que sea tan amable
Fer
Buenas tardes, estoy siguiendo tu post, me da un error de sintaxis en el primer else del codigo en python, que puede ser? esta copiado directamente desde lo que pusiste. Gracias
Víctor Ventura
Hola, Fer.
Seguramente será la versión de Python. Este post del blog es de febrero de 2015 y utilicé Python 2 y seguramente tú trabajes con Python 3
¡¡ Gracias por visitar polaridad.es !!
juan carlos rosas valencia
HOLA, ME GUSTO MUCHO ESTE ARTICULO , me gustaria queme ayudaran , me encargaron una practica de graficar los datos de un RTDPT100 , el que recibe los datos es aruduino y python genera la grafica, el problema que donde tenemos que obtener el como se hace la practica nos da la programacion para python el unico inconveniente es que lo hace en forma de una barra y me gustaria hacerla en forma de grafica de puntos pero no se como cambiarla ya que soy nuevo en python si me ayudaran se los agradeceria mucho aqui les dejo el codigo si me ayudaran a cambiarle para que me de un agrafica de puntos porfavor
# Mostrar valores numericos ( enviados como cadenas ASCII ) desde un dispositivo externo por un puerto serial
# La aplicacion envia un byte al dispositivo y muestra la respuesta tambien en forma de grafico de barra
# importar paquetes
import Tkinter as tk # para la interfaz grafica
import ttk # para widgets de la interfaz grafica
import tkMessageBox # Para cuadro de mensaje
import serial # para la comunicacion por puerto serial
import time # para los temporizadores
import threading # para realizacion de procesos en paralelo (hilos)
from matplotlib import pyplot as plt #Importa pyplot para realizar la gráfica.
from matplotlib import animation #Importa animation que permite actualizar la gráfica en intervalos concretos
from matplotlib import style #Permite cambiar el estilo de nuestra gráfica.
import serial #Importa librería para trabajar con el puerto serie.
# El proceso (hilo) que continuamente hara peticiones por el puerto serial al dispositivo externo
class myThread (threading.Thread):
# inicializar la clase
def __init__(self, name, ser):
threading.Thread.__init__(self)
# Nombre del proceso (hilo)
self.name = name
# Informacion del puerto serial
self.ser = ser
# la cadena que se recibira
self.rcvstr=»
# la cadena que se mostrara
self.prnstr=»
# Esto es llamado cuando el proceso (hilo) es iniciado con .start()
def run(self):
# contador de cada una de las lecturas
self.conteo_datos = 0
while self.ser.isOpen():
# incrementar el contador …
self.conteo_datos += 1
# asignar el valor de la variable que sera mostrada en la interfaz grafica
conteoLecturas.set(«conteos lectura: «+str(self.conteo_datos))
# Enviando el comando (byte) al dispositivo serial
try:
# enviando comando
self.ser.write(«a»)
# esperar a que el dispositivo conteste
time.sleep(0.1)
# crear una cadena para los datos recibidos
rcvstr = »
# Si hay algun dato disponible en el puerto serial, leerlo
while self.ser.inWaiting() > 0:
self.rcvstr= self.ser.read(self.ser.inWaiting())
except:
# no hacer nada si el comando no se puede enviar
pass
# Asignando las variables de la interfaz grafica con la respuesta recibida
self.prnstr=self.rcvstr.rstrip(‘\n’)
self.prnstr = self.prnstr +» C»
etiquetaVariable.set(self.prnstr)
try:
valorVariable.set(float(self.rcvstr)+ offsetBarra )
except:
# No hacer nada en caso que la conversion falle por una cadena mal formateada
pass
# Tiempo en segundos entre peticiones de dato
time.sleep(0.5)
# procedimiento de salida
def mSalir():
# Preguntar si/no a la confirmacion de salida
mExit = tkMessageBox.askyesno(title = «Salir», message = «Realmente desea salir?»)
if mExit > 0:
# cerrar el puerto
ser.close()
# destruir la interfaz grafica
root.destroy()
return
# Enviar comandos por el puerto serial al dispositivo
def mSend(command):
try:
ser.write(command)
except:
print «No se puede enviar comando puerto cerrado?»
return
# ===========================
# Inicio del programa principal
# ===========================
# provee informacion del puerto serial
ser = serial.Serial()
# Modificar dependiendo de la situacion
ser.port = ‘/dev/ttyUSB0’
#ser.port = ‘COM6′
ser.baudrate = 9600
ser.timeout = 0
# abrir el puerto si este aun no se encuentra abierto
if ser.isOpen() == False:
ser.open()
# inicializar la ventana principal
root = tk.Tk()
root.configure(background=’white’)
root.geometry(«400×400»)
root.title(«Lectura variable dispositivo serial «)
# variables.
etiquetaVariable = tk.StringVar()
conteoLecturas = tk.StringVar()
valorVariable = tk.DoubleVar()
# modificar dependiendo de los limites de la variable a visualizar
maximoBarra = 200.0
minimoBarra = 00.0
rangoBarra = tk.DoubleVar()
offsetBarra = tk.DoubleVar()
# Texot, titulos, etc
textoTitulo = ttk.Label(root, text = «LECTURA VARIABLE DISPOSITIVO SERIAL», foreground=»white»,background=»black»).grid(row=0, column=1)
textoPuerto = ttk.Label(root, text = «Puerto serial abierto: «+str(ser.isOpen()), foreground=»white»,background=»black»).grid(row=1, column=1)
textoNombrevariable = ttk.Label(root, text = «TEMPERATURA», foreground=»white»,background=»black»).grid(row=3, column=1)
textoConteolecturas = ttk.Label(root,textvariable = conteoLecturas, foreground=»white»,background=»black»).grid(row=2,column=1)
textoValorvariable = ttk.Label(root, textvariable = etiquetaVariable, foreground=»yellow», background=»black» ).grid(row=5, column=2)
textoPiedepagina = ttk.Label(root, text = «Automatizanos.com», foreground=»grey»,background=»black»).grid(row=7, column=1)
# Boton de salir
botonSalir = ttk.Button(root, text = «cerrar puerto y salir», command = mSalir).grid(row=6, column=1)
#Barra de progreso
if maximoBarra > 0.0 and minimoBarra >= 0.0 :
rangoBarra = maximoBarra – minimoBarra
offsetBarra = (-1) * minimoBarra
if maximoBarra > 0.0 and minimoBarra < 0.0 :
rangoBarra = maximoBarra +abs(minimoBarra)
offsetBarra = abs(minimoBarra)
if maximoBarra < 0.0 and minimoBarra < 0.0 :
rangoBarra = abs(minimoBarra) – abs(maximoBarra)
offsetBarra = abs(minimoBarra)
s = ttk.Style()
s.theme_use('clam')
s.configure("yellow.Vertical.TProgressbar", foreground='yellow', background='yellow')
progBar = ttk.Progressbar(root, orient="vertical",length=200, mode="determinate",maximum=rangoBarra,variable=valorVariable,style="yellow.Vertical.TProgressbar" ).grid(row=5,column=1)
# esperar
time.sleep(1)
# llamar e iniciar el proceso (hilo) de actualizacion de datos
thread1 = myThread("Actualizando", ser)
thread1.start()
# iniciar la interfaz grafica
root.mainloop()
John
Buen trabajo, de los mas completos que se encuentran, bien explicado donde se entiende facilmente para que es cada linea de codigo, me sirvio mucho para un proyecto