Integração Arduino - Python Leitura de sensor de umidade e temperatura Filipi Nascimento Silva, Luciano da Fontoura Costa Disciplina: Modelagem Matemático - Computacional Nesta prática, usaremos um programa python para se comunicar com um dispositivo Arduino através da conexão serial usando um cabo USB. Serão lidos valores provenientes de um sensor de umidade e temperatura conectado ao Arduino. Hardware necessário - Arduino - PC com windows ou linux, ou Mac. - Sensor de umidade e temperatura DHT22 Softwares necessários - Arduino IDE Python 2.x ou 3.x Biblioteca pySerial Biblioteca MatplotLib Biblioteca NumPy Sensor DHT22 Preparo do ambiente de desenvolvimento Inicialmente deve-se realizar o download da IDE do Arduino, disponível em: https://www.arduino.cc/en/Main/Software Após a instalação deve-se configurar a IDE com as informações do Arduino (que deverá estar conectado através da porta USB). A configuração é feita selecionando o tipo de dispositivo no menu Tools > Board. Também deve-se selecionar a porta de comunicação com o Arduino no menu Tools > Port. Recomenda-se testar o ambiente carregando o exemplo Blink através do menu File > Examples > 01.Basics > Blink. A interface de edição da IDE é simples. O botão com a marca de correto checa e compila o código, enquanto o botão com a seta envia o código para ser executado no Arduino. É importante alterar os valores de delay no código do exemplo Blink para verificar se realmente o dispositivo está executando o código fornecido. Dispositivos novos já vem com o exemplo blink pré-instalado. Preparo do ambiente Python O python pode ser instalado através de arquivos que podem ser obtidos no site: https://www.python.org/downloads/ Para Linux, verifique a disponibilidade do python através do gerenciador de pacotes disponível como apt-get ou port. Por padrão, junto ao python também é instalado o gerenciador de módulos pip. Este deverá ser usado para instalar o módulos necessários para a prática. Para instalar os módulos usados utilize os comandos: pip install matplotlib pip install numpy pip install pyserial Dependendo da versão do python o comando pip pode estar nomeado como pip3 ou pip2, neste caso utilize estes comandos ao invés de simplesmente pip. Preparo do sensor DHT22 O sensor DHT22 comunica-se através de um pino digital (serial) e possui 3 pinos (+: 5 ou 3.3 Volts, out: saída serial, -: Terra). A conexão com o Arduino é feita conectando-se os pinos + e - do sensor aos pinos Vcc (5V ou 3.3V) e GRD do Arduino, respectivamente. O pino out deve ser conectado a uma entrada/saída digital do Arduino. Nesta prática usamos a porta digital 2. Códigos para as práticas Os códigos usados para a prática encontram-se nesta pasta e estão comentados. O arquivo TemperatureHumidity.ino deve ser carregado no Arduino através da IDE. Ele é responsável por realizar a leitura do sensor e enviar os valores de umidade e temperatura, através da porta serial, para o computador. É possível testar este código observando o monitor de porta serial embutido na IDE do arduino, assim com através do plotter embutido. Ambos são acessíveis através do menu Tools. O arquivo TemperatureHumiditySimple.py lê os dados enviados pelo Arduino através da porta serial e os imprime no terminal. É necessário configurar, através da variável selectedPortIndex, qual porta serial deverá ser usada para a comunicação com o Arduino. O arquivo TemperatureHumidityPlot.py lê progressivamente os dados enviados pelo Arduino através da porta serial e construi um gráfico do tipo scatterplot com a história de valores no espaço Umidade x Temperatura. Também é necessário configurar, através da variável selectedPortIndex, qual porta serial deverá ser usada para a comunicação com o Arduino. Arquivos - TemperatureHumidity.ino //Incluindo a biblioteca de comunicação com o sensor de humidade e temperatura. #include "DHT.h" //Define o macro DHTPIN de acordo com o pino digital correspondente. #define DHTPIN 2 //Selecionando o tipo de sensor (no nosso caso, o DHT22) //#define DHTTYPE DHT11 // DHT 11 #define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321 //#define DHTTYPE DHT21 // DHT 21 (AM2301) //Cria e inicializa os dados do sensor. DHT dht(DHTPIN, DHTTYPE); double currentHumidity = 0.0; double currentTemperature = 0.0; // Função que executa uma vez para configurar // variáveis e parametros void setup() { // Inicializa a porta serial a uma velocidade de 57600bps Serial.begin(57600); //Envia um header pela porta serial. Serial.print("Humidity\tTemperature\n"); } //Inicializa o sensor. dht.begin(); // Esta função executa em loop indefinidamente após a execução da função setup // mas pode ser parado por certas funções e interrupções. void loop() { // Aguarda-se 250ms antes de realizar uma nova leitura do sensor. delay(250); currentHumidity = dht.readHumidity(); currentTemperature = dht.readTemperature(); // Checa se alguma das leituras falhou. if (isnan(currentHumidity) || isnan(currentTemperature)) { Serial.println("ERROR: Failed to read from DHT sensor!"); return; } } // Envia através da porta serial os valores de umidade e temperatura. Serial.print(currentHumidity); Serial.print("\t"); Serial.print(currentTemperature); Serial.print("\n"); - TemperatureHumiditySimple.py #!/usr/bin/python # -*- coding: utf-8 -*import serial from serial.tools import list_ports #Primeiramente precisamos determinar as portas seriais disponiveis na maquina # para isso, obtemos a lista de portas seriais e escolhemos manualmente # aquela com index 1. selectedPortIndex = 1; selectedDevice = ""; ports = list_ports.comports(); print("Avaiable ports:\n%s"%"\n".join(["\t%d: %s"% (portIndex,str(ports[portIndex])) for portIndex in range(len(ports))])); selectedDevice = ports[selectedPortIndex].device; print("Selected device: %s"%selectedDevice); ser = serial.Serial(selectedDevice, 57600); # Cada execução lê uma linha da porta serial # e separada os dois valores (umidade e temperatura) # imprimindo no prompt try: for line in ser: try: entry = line.decode("utf-8").split("\t"); humidity = float(entry[0]); temperature = float(entry[1]); print(u"T: %gºC H:%g%%"%(temperature,humidity)); except ValueError as e: print("E: %s"%line); except IndexError as e: print("E: %s"%line); except KeyboardInterrupt: # Ao abortar a execução do programa esta exception é chamada # deve-se então fechar a porta serial para novas comunicações ser.close(); except: #Caso seja um erro não especificado é importante fechar a porta # serial para permitir comunicação futura ser.close(); - TemperatureHumidityPlot.py #!/usr/bin/python # -*- coding: utf-8 -*import numpy as np; import serial; import matplotlib.pyplot as plt; import matplotlib.animation as animation; import time; from serial.tools import list_ports; #Primeiramente precisamos determinar as portas seriais disponiveis na maquina # para isso, obtemos a lista de portas seriais e escolhemos manualmente # aquela com index 1. selectedPortIndex = 1; selectedDevice = ""; ports = list_ports.comports(); print("Avaiable ports:\n%s"%"\n".join(["\t%d: %s"% (portIndex,str(ports[portIndex])) for portIndex in range(len(ports))])); selectedDevice = ports[selectedPortIndex].device; print("Selected device: %s"%selectedDevice); #Iniciando a porta serial à velocidade de 57600 bps ser = serial.Serial(selectedDevice, 57600); temperatureHistory = []; humidityHistory = []; fig = plt.figure(); l, = plt.plot([], [], '.-'); plt.xlabel('Temperatude (°C)'); plt.ylabel('Humidity (%)'); plt.title('Temperature vs Humidity'); # Criando uma funcao de animacao para o matplotlib def update_line(num, ser, temperatureHistory, humidityHistory, plt, line): try: #cada execução lê uma linha da porta serial # e separada os dois valores (umidade e temperatura) entryLine = ser.readline().decode("utf-8"); entry = entryLine.split("\t"); humidity = float(entry[0]); temperature = float(entry[1]); if( (len(temperatureHistory)==0 or len(humidityHistory)==0 or temperature!=temperatureHistory[-1] or humidity!=humidityHistory[-1] ) and temperature>0 and humidity>0): print(u"T: %g°C H:%g%%"%(temperature,humidity)); temperatureHistory.append(temperature); humidityHistory.append(humidity); minx = min(temperatureHistory) maxx = max(temperatureHistory) lenx = maxx-minx; miny = min(humidityHistory) maxy = max(humidityHistory) leny = maxy-miny; plt.xlim([minx-0.05*lenx,maxx+0.05*lenx]); plt.ylim([miny-0.05*leny,maxy+0.05*leny]); line.set_data(temperatureHistory, humidityHistory); except ValueError as e: #Em caso de erro apenas imprime o texto com erros no terminal. print("E: %s"%entryLine); except IndexError as e: print("E: %s"%entryLine); except: #Caso seja um erro não especificado é importante fechar a porta # serial para permitir comunicação futura ser.close(); raise; return line, #Ativa o modo animação do matplotlib com a função update_line line_ani = animation.FuncAnimation(fig, update_line, 1, fargs=(ser,temperatureHistory,humidityHistory,plt, l), interval=1, blit=False) plt.show() ser.close();