¡Enviando datos de Arduino a Python!

Introducción

En este proyecto aprenderás a realizar la comunicación serial entre cualquier placa Arduino y el lenguaje de programación: Python, esto para poder visualizar la data recogida por un sensor de temperatura y humedad (DHT11) en tiempo real. Algo a considerar es que estamos trabajando con una placa Arduino Nano y la versión 3.8.6 de Python.

Recordemos que las placas Arduino son excelentes para iniciar en la programación de microcontroladores y en el desarrollo de proyectos escalables, por otro lado, tenemos a Python, un lenguaje de programación de alto nivel y simple, esto debido a su gran similitud con el lenguaje humano. Además, es un lenguaje multiplataforma de código abierto.

Tanto Arduino como Python gozan de una gran comunidad en la cual podremos encontrar cualquier tipo de documentación, solución a errores y personas con el mismo interés que nosotros.

Circuito a realizar

Para este proyecto vamos a necesitar los siguientes componentes:

  • Placa Arduino (En este caso empleo un Arduino Nano).
  • Sensor de temperatura y humedad DHT11.
  • Cable USB-Mini B.
  • Cables Jumper Male-Male.
  • Protoboard.

Instalación de librerías en Arduino

Antes de pasar a programa debemos verificar si tenemos la librería necesaria para nuestro sensor de temperatura y humedad DHT11 o DHT22, en caso no contemos con ella, aquí se muestra su instalación desde el Administrador de bibliotecas de Arduino.

Código en Arduino

/*
 * Envío de datos de Arduino a Python
 * Carlos Andrés Saldaña Amézquita
 * 
 * ▬▬▬▬▬▬▬▬▬ SÍGUEME TODOMAKER ▬▬▬▬▬▬▬▬▬▬
 * Sitio web: https://todomaker.com/
 * Instagram: https://bit.ly/3v1NmXp
 * Facebook: https://bit.ly/34IWbuH
 * YouTube: https://bit.ly/3LJRtx6
 */

//--- Librerías a emplear ---
#include <DHT.h>

//--- Declaración de pines ---
#define pinDHT 9

// Parámetros necesarios para inicializar nuestro sensor
DHT dht(pinDHT, DHT11);

//--- Variables ---
double temperatura;
double humedad;

unsigned long lastTime = 0, sampleTime = 200;


void setup() {
  //Inicializamos el puerto serial
  Serial.begin(9600);
  
  //Inicializamos los sensores
  dht.begin();

}

void loop() {
  if (millis() - lastTime >= sampleTime){
    lastTime = millis();

    // Obtenemos la lectura de temperatura y humedad
    temperatura = dht.readTemperature();
    humedad = dht.readHumidity();

    // Imprimimos los valores obtenidos
    Serial.println(temperatura);
    Serial.println(humedad);
    
  }
  
}

Explicación del código en Arduino

Empezamos incluyendo las librería DHT.h que nos proporciona Adafruit. Esta librería es muy sencilla de utilizar y funciona para los modelos DHT11 y DHT22.

Pasamos a declarar en pin digital conectado, en nuestro caso es el pin 9 del Arduino Nano, e indicamos los parámetros necesarios para inicializar nuestro sensor.

//--- Librerías a emplear ---
#include <DHT.h>
//--- Declaración de pines ---
#define pinDHT 9
// Parámetros necesarios para inicializar nuestro sensor
DHT dht(pinDHT, DHT11);

Pasamos a la declaración de 2 variables de tipo double de nombre temperatura y humedad que almacenarán dichos datos respectivamente. También declaramos un par de variables long sin signo que permitirán tomar muestras de los datos cada 200 milisegundos

//--- Variables ---
double temperatura;
double humedad;

unsigned long lastTime = 0, sampleTime = 200;

Ahora nos encontramos en la función setup, aquí únicamente vamos a inicializar nuestro puerto serial, a una velocidad de baudio que creamos conveniente, y nuestro sensor DHT11.

void setup() {
  //Inicializamos el puerto serial
  Serial.begin(9600);
  
  //Inicializamos los sensores
  dht.begin();

}

Finalmente nos encontramos en la función loop, en la cual obtendremos los datos de temperatura y humedad leídos por el sensor, a través de las funciones readTemperature() y readHumidity, funciones que vienen incluídas en la librería que importamos. Luego de esto pasamos a imprimir los datos en el puerto serial del Arduino IDE para verificar que todo anda correctamente.

Todo este proceso lo colocaremos dentro de una condicional if, la cual será ejecutada cada 200 milisegundos

void loop() {
  if (millis() - lastTime >= sampleTime){
    lastTime = millis();

    // Obtenemos la lectura de temperatura y humedad
    temperatura = dht.readTemperature();
    humedad = dht.readHumidity();

    // Imprimimos los valores obtenidos
    Serial.println(temperatura);
    Serial.println(humedad);
    
  }
  
}

Instalación de librerías en Python

Para lograr la comunicación serial entre Arduino y Python, además de la correcta gráfica de nuestros datos en tiempo real, necesitamos instalar los siguientes paquetes desde nuestra terminal preferida, en este caso, se utiliza el CMD de Windows y el comando pip.

  • pip install pyserial.
  • pip install collections.
  • pip install matplotlib.
  • pip install numpy.

Ejemplo:

Código en Python

# -*- coding: utf-8 -*-
"""
 * Envío de datos de Arduino a Python
 * Carlos Andrés Saldaña Amézquita
 * 
 * ▬▬▬▬▬▬▬▬▬ SÍGUEME TODOMAKER ▬▬▬▬▬▬▬▬▬▬
 * Sitio web: https://todomaker.com/
 * Instagram: https://bit.ly/3v1NmXp
 * Facebook: https://bit.ly/34IWbuH
 * YouTube: https://bit.ly/3LJRtx6
"""
#----- Incluímos las librerías a emplear -----
import serial # Permite realizar la comunicación serial
import time # Proporciona funciones relacionadas con el tiempo
import collections # Implementa tipos de datos de contendores especializados
import matplotlib.pyplot as plt # Permite realizar gráficos
import matplotlib.animation as animation # Permite animar las gráficas
from matplotlib.lines import Line2D
import numpy as np # Permite trabajar con vectores y matrices
#---------------------------------------------

def getSerialData(self, Samples, numData, serialConnection, lines):
    # Obtenemos la lectura de cada uno de los sensores
    for i in range(numData):
        value = float(serialConnection.readline().strip())
        data[i].append(value)
        # Actualizamos la gráfica mediante nuevas líneas
        lines[i].set_data(range(Samples), data[i])
        
SerialPort = "COM7" # Puerto serial de Arduino
baudRate = 9600 # Velocidad de baudios

# Inicializamos nuestro objeto Serial con los parámetros declarados
try:
    serialConnection = serial.Serial(SerialPort, baudRate)
except:
    print("No se logró la conexión con el puerto")
    
Samples = 200 # Número de muestras
sampleTime = 100 # Tiempo de muestreo
numData = 2 # Número de sensores

# Límites de los ejes para nuestra gráfica
xmin = 0
xmax = Samples

ymin = [-50, 0]
ymax = [50, 100]
lines = []
data = []

for i in range(numData):
    # Lista donde almacenamos las lecturas de nuestro sensor
    data.append(collections.deque([0] * Samples, maxlen = Samples))
    # Empleamos líneas en 2D para la gráfica de datos
    lines.append(Line2D([], [], color = "blue"))

# Creamos la 1ra figura
fig = plt.figure()
# Agregar la 1ra gráfica dentro de la figura
ax1 = fig.add_subplot(1, 2, 1, xlim = (xmin, xmax), ylim = (ymin[0], ymax[0]))
ax1.title.set_text("Temperatura")
ax1.set_xlabel("Número de muestras")
ax1.set_ylabel("Valor(C°)")
ax1.add_line(lines[0])

# Agregar la 2da gráfica dentro de la figura
ax2 = fig.add_subplot(1, 2, 2, xlim = (xmin, xmax), ylim = (ymin[1], ymax[1]))
ax2.title.set_text("Humedad")
ax2.set_xlabel("Número de muestras")
ax2.set_ylabel("Valor(%)")
ax2.add_line(lines[1])

# Animamos nuestra gráfica
anim = animation.FuncAnimation(fig, getSerialData, fargs = (Samples, numData, serialConnection, lines), interval = sampleTime)
plt.show() # Mostramos la gráfica

# Cerramos el puerto serial
serialConnection.close()

          

Explicación del código en Python

Iniciamos incluyendo todas las librerías a emplear.

import serial # Permite realizar la comunicación serial
import time # Proporciona funciones relacionadas con el tiempo
import collections # Implementa tipos de datos de contendores especializados
import matplotlib.pyplot as plt # Permite realizar gráficos
import matplotlib.animation as animation # Permite animar las gráficas
from matplotlib.lines import Line2D
import numpy as np # Permite trabajar con vectores y matrices

Ahora definimos la función getSerialData que nos permitirá obtener la lectura de nuestro sensor DHT11, tomando en cuenta ciertos parámetros que se explicarán más adelante.

Definimos el puerto serial de Arduino y la velocidad de baudios a emplear, ambos datos los almacenamos en las variables SerialPort y baudRate, respectivamente. Para luego pasar a inicializar nuestro objeto Serial con los parámetros mencionados.

def getSerialData(self, Samples, numData, serialConnection, lines):
    # Obtenemos la lectura de cada uno de los sensores
    for i in range(numData):
        value = float(serialConnection.readline().strip())
        data[i].append(value)
        # Actualizamos la gráfica mediante nuevas líneas
        lines[i].set_data(range(Samples), data[i])
        
SerialPort = "COM7" # Puerto serial de Arduino
baudRate = 9600 # Velocidad de baudios

# Inicializamos nuestro objeto Serial con los parámetros declarados
try:
    serialConnection = serial.Serial(SerialPort, baudRate)
except:
    print("No se logró la conexión con el puerto")

Aquí encontramos los parámetros empleados por la función mencionada anteriormente.

  • Samples: Número de muestras.
  • sampleTime: Tiempo de muestreo.
  • numData: Número de sensores a emplear.

También se definen los límites mínimos y máximos para los ejes de nuestra gráfica, así como 2 vectores vacíos (lines y data) para almacenar la información entrante.

Samples = 200 # Número de muestras
sampleTime = 100 # Tiempo de muestreo
numData = 2 # Número de sensores

# Límites de los ejes para nuestra gráfica
xmin = 0
xmax = Samples

ymin = [-50, 0]
ymax = [50, 100]
lines = []
data = []

Pasamos a realizar nuestras gráficas para lo cual creamos 2 figuras, explicaré las características de la 1ra figura, ya que el 2do caso es análogo. Así que tenemos lo siguiente:

  • ax1.title.set_text(“Temperatura”): Define el título de nuestra gráfica.
  • ax1.set_xlabel(“Número de muestras”): Define el nombre de nuestro eje x.
  • ax1.set_ylabel(“Valor(C°)”): Define el nombre de nuestro eje y.
  • ax1.add_line(lines[0]): Define una línea 2D en nuestros ejes.
# Creamos la 1ra figura
fig = plt.figure()
# Agregar la 1ra gráfica dentro de la figura
ax1 = fig.add_subplot(2, 2, 1, xlim = (xmin, xmax), ylim = (ymin[0], ymax[0]))
ax1.title.set_text("First plot")
ax1.set_xlabel("Samples")
ax1.set_ylabel("Volts")
ax1.add_line(lines[0])

# Agregar la 2da gráfica dentro de la figura
ax2 = fig.add_subplot(2, 2, 2, xlim = (xmin, xmax), ylim = (ymin[1], ymax[1]))
ax2.title.set_text("Second plot")
ax2.set_xlabel("Samples")
ax2.set_ylabel("Volts")
ax2.add_line(lines[1])

Finalmente pasamos a la animación de nuestra gráfica y a mostrar lo obtenido mediante el comando: plt.show().

Terminamos cerrando el puerto serial con el comando: serialConnection.close().

anim = animation.FuncAnimation(fig, getSerialData, fargs = (Samples, numData, serialConnection, lines), interval = sampleTime)
plt.show()

serialConnection.close()

Resultados

Conclusiones

Trabajar con Arduino y Python te abre un mundo de posibilidades y te permite realizar proyectos profesionales. Respecto a las placas Arduino, éstas son de muy bajo costo y relativamente sencillas de programar, por otro lado Python es un lenguaje de programación muy potente que en este y futuros proyectos se empleará para aplicar algoritmos de análisis, Machine Learning e Inteligencia Artificial a toda la información que pueda ser recogida por los sensores conectados a nuestra placa Arduino.

Mantente al pendiente de nuestras publicaciones y síguenos en nuestras redes sociales, estoy seguro que encontrarán mucha información de su interés. Si desean aprender algo en concreto referente a estas tecnologías lo pueden dejar en los comentarios.

Te invitamos a tomar el curso de Introducción al ESP32: Introducción al ESP32 | TodoMaker’s School

Previous Post
Next Post