Merjenje temperature in vlage ter prikaz na grafu

Slika 1: Grafični prikaz spreminjanja vrednosti temperature in relativne vlažnosti zraka, merjeni s senzornem DHT22.

Za merjenje temperature in relativne vlažnosti zraka bomo uporabili senzor DHT22, znan tudi po imenu AM2302. Je naslednjik senzorja DHT11 in je preciznejši. Senzor DHT22 je tovarniško kalibriran in ne zahteva dodatnih komponent, tako da ga lahko takoj uporabimo za merjenje. Vsebuje kapacitivni senzor vlažnosti zraka, termistor za merjenje temperature in elektroniko za komunikacijo z mikrokontrolerjem, v našem primeru z razvojno ploščo Arduino Uno. Deluje v območju od -40 °C do +80 °C in od 0 % do 100 % relativne vlažnosti zraka. Njegova natančnost znaša +/- 0,5 °C in +/- 2 % relativne vlažnosti zraka. Od razvojne plošče Arduino Uno je lahko oddaljen največ 20 m. Njegov odzivni čas na temperaturne spremembe in spremembe vlažnosti zraka znaša 2 s, kar je dokaj veliko.

Slika 2: Senzor DHT22 (vir: https://www.fasttech.com/product/1451806-dht22-am2302-digital-temperature-humidity-sensor)

Za senzor DHT22 je narejena knjižnica, ki jo moramo vključiti v naš program. Ker je med privzetimi knjižnicami ni, jo moramo najprej uvoziti v programsko okolje Arduino (Računalnik > Lokalni disk C > Programske datoteke x86 > Arduino > libraries). Spodaj v prilogi je ustrezna knjižnica DHT.rar, ki jo prenesemo, razširimo ter mapo z imenom DHT vstavimo v libraries. Po ponovnem zagonu okolja Arduino je knjižnica že na voljo za uporabo.

Slika 3: Vezava senzorja na razvojno ploščo Arduino Uno.

Podatkovni pin senzorja DHT22 je preko upora 10 kΩ povezan na napetost 5 V. Pina NC (not connected) nikamor ne priključimo. Proizvajalec priporoča še priključitev kondenzatorja 100 nF med maso in +5 V za odpravljanje motenj.

Poglejmo najprej delovanje senzorja, prikaz temperature in vlažnosti zraka samo v okolju Arduino.

Program:

  /*

  Uporaba senzorja DHT22.

  Prikaz izmerjene temperature in vlažnosti zraka na serijskem monitorju.

  Avtor: Milan Ivič

  Julij 2015

 */

 #include "DHT.h"

 #define DHTTYPE DHT22           // DHT 22  (oznaka na senzorju: AM2302).

 #define DHTPIN 2                      //Podatkovni izhod senzorja priključimo na pin 2

 DHT dht(DHTPIN, DHTTYPE);     //Inicializacija DHT senzorja, tip, 16 MHz (Arduino Uno)

 float temperaturaC;

 float temperaturaF;

 float vlaznost;

 void setup()

 {

   Serial.begin(9600);

   Serial.println("Meritve");

   dht.begin();

 }

 void loop()

 {

   //Presledek med meritvami 2 sekundi:

   delay(2000); 

   //Izmerjeni podatki so stari okoli 2 sekundi. Je počasni senzor.

 

   temperaturaC = dht.readTemperature();    //Branje temperature v °C.

   temperaturaF = temperaturaC*1.8 + 32.;  //Pretvorba v °F

   vlaznost = dht.readHumidity();                 //Branje vlažnosti zraka.

 

   //Izpisi besedila in vrednosti spremenljivk na serijski monitor:

   Serial.print("Temparetura: ");

   Serial.print(temperaturaC);

   Serial.print(" stopinj C,");

   Serial.print("    Vlaznost: ");

   Serial.print(vlaznost);

   Serial.println(" %");

 }

Temperaturo v Fahrenheit-ih lahko izračunamo po opisani formuli v programu ( temperaturaF = temperaturaC*1.8 + 32), če pogledamo v knjižnico pa vidimo, da lahko uporabimo namesto tega izračuna kar temperaturaF = dth.readTemperature(true).

Slika 4: Izpis meritev na serijskem monitorju.

Za komunikacijo s Python in grafični prikaz podatkov, bomo spremenili prikaz podatkov, ki jih Arduino pošilja na COM port. Potrebujemo le vrednosti izmerjenih temperatur in vrednosti izmerjene relativne vlažnosti zraka, ki jih ločimo z vejico. Za takšen izpis podatkov na COM port, program za izpis sedaj izgleda:

 //Izpisi vrednosti spremenljivk na serijski monitor:  

   Serial.print(temperaturaC);

   Serial.print(" , ");  

   Serial.println(vlaznost);  

Izbrišemo tudi vrstico v  void setup() funkciji, ki prikazuje izpis Meritve na serijskem monitorju, Serial.println("Meritve");

Če hočemo grafično opazovati merive temperature in vlažnosti zraka z uporabo okolja Python, moramo instalirati še dva programa. Kako to naredimo, je prikazano v nadaljevanju.

1. Pythonov upravitelj paketov je pip. Uporabljamo ga za namestitev in upravljanje programskih paketov, napisanih v Pythonu.

;C:\Python27;C:\Python27\Scripts

2. Instaliramo še grafično orodje matplotlib:

Če hočemo da bo matplotlib deloval, moramo imeti instalirano knjižnico numpy. V prejšnji vaji (Arduino in Python, Instalacija programske opreme in prva vaja) smo instalirali VPython, tako da imamo knjižnico numpy že naloženo.

Instalacija matplotlib:

V brskalnik vpišemo https://github.com/matplotlib/matplotlib/downloads/ in na strani, ki se odpre izberemo (kliknemo) matplotlib-1.2.0.win32-py2.7.exe. Po prenosu program zaženemo in ga instaliramo na računalnik.

Preizkisimo, če je grafično orodje pravilno nameščeno:

Sedaj se lahko vrnemo na našo vajo merjenja in prikazovanja temperature in relativne vlažnosti zraka s senzorjem DHT22. Najprej napišimo program, nato ga bomo komentirali in razložili. Napisan mora biti tako, kot je prikazano spodaj. Odmiki vrstic so pomembni, saj nam bo v nasprotnem primeru program javil napako. Program shranimo pod izbranim imenom, ki mu dodamo končnico .py

Program Python:

import serial                              #Če želimo brati iz serijskega porta, moramo uvoziti knjižnico serial.

import numpy                            #numpy omogoča matamatične operacije tudi med večdimenzionalnimi polji.

import matplotlib.pyplot as plt     #matplotlib knjižnica je namenjena risanju grafov.

from drawnow import *                #drawnow skrbi za posodabljanje grafa. Uvozimo vse iz knjižnice drawnow.

tempC = []                                #Kreiranje polja za podatke o temperaturah.

vlaznost =  []                             #Kreiranje polja za podatke o relativnih vlažnostih zraka.

arduinoPodatki = serial.Serial('COM10', 115200)     #Kreiranje serijskega objekta z imenom arduinoPodatki.

plt.ion()                                                               #Povemo matplotlib-u, da želimo interaktivni način sprejemanja tekočih podatkov in samodejno pripravo grafa.

cnt = 0    #Štetje je enako 0                                  #Števec postavimo na 0.

def NarediGraf():                                                                           #Kreiranje funkcije za želeni prikaz izgleda grafa.   

    plt.ylim(10,30)                                                                           #Določitev min. in max. vrednosti po y osi.

    plt.title('Prikaz temperature in relativne vlage, senzorja DHT22')      #Naslov grafa.

    plt.grid(color='b',linewidth=2)                                                       #Vključitev mreže.

    plt.ylabel('temperatura (C)')

    plt.plot(tempC, 'ro-', label = 'stopinje C', linewidth=2.1)

    plt.legend(loc = 'upper left')    

    plt2 = plt.twinx()                                                                         #Kreiranje druge y osi (desna y os).

    plt.ylim(45,120)

    plt2.plot(vlaznost, 'yo-', label = 'vlaznost (%)', linewidth=2.1)

    plt2.set_ylabel('vlaz. zraka (%)')

    plt2.legend(loc = 'upper right')

while True:                                                     #Neskončna zanka.

    while (arduinoPodatki.inWaiting()==0):             #Dokler ni podatkov od Arduina, jih ne beremo. Takrat ne stori ničesar (pass).

        pass                                                         #Ti dve vrstici se ponavljata, če ni nobenih podatkov na COM portu od Arduina.

    arduinoString = arduinoPodatki.readline()     #So podatki na COM portu, preberi jih. Prebere vrstico besedila iz serijskega porta, niz.   

    print arduinoString                                      #Podatke o temperaturi in vlažnosti zraka izpisuje v oknu Python Shell.

    dataArray = arduinoString.split(',')                #Loči podatke v polju z imenom dataArray. Vejica loči podatke o temperaturi s podatki o vlažnosti.   

    temperatura = float(dataArray[0])                 #Pretvori prvi element polja, ki je niz znakov v decimalno število (tip float). Prvi elementi polja so temperature.

    vlaga = float(dataArray[1])                           #Pretvori drugi element polja, ki je niz znakov v decimalno število (tip float). Drugi elementi polja so vlažnosti.

    tempC.append(temperatura)                        #Posodabljaj polje tempC z dodajanjem temperaturnih odčitkov.

    vlaznost.append(vlaga)                                #posodabljaj polje vlaznost z dodajanjem odčitkov relativne vlažnosti zraka.

    drawnow(NarediGraf)                                 #Pokliči drawnow za osvežitev grafa.

    plt.pause(0.2)                                            #Pavza 200 ms.

    cnt = cnt + 1

    if(cnt > 20):

        tempC.pop(0)                                         #Vidimo samo zadnjih 20 merilnih točk.

        vlaznost.pop(0)

Razlaga:

Podatki, ki prihajajo na COM port od Arduina, so znakovni nizi. V Arduino programu najprej pošljemo na COM port podatek o temperaturi nato pa podatek o vlažnosti. Podatka smo ločili z vejico (,). V Python-u najprej ločimo podatke, ki jih ločuje vejica in jih shranjujemo v polje, imenovano dataArrray. Posamezna elementa polja, prvi element je temperatura, drugi pa vlaga, pretvorimo iz znakovnega niza v realno število (število z decimalno vejico). Rezultat so prikazane vrednosti polja, kot prikazuje slika 5.

Slika 5: Prikaz vrednosti polja dataArray.

Kreiramo dva polja, prvo polje za podatke o izmerjenih temperaturah (tempC = [ ]), drugo pa za podatke o izmerjenih relativnih vlažnostih zraka (vlaznost = [ ]). V prvo polje bomo vpisovali (prilepili, append) prvi element polja dataArray, ki je iz znakovnega niza pretvorjen v realno število, v drugo polje pa bomo vpisovali (prilepili, append) drugi element polja dataArray. Izpišimo podatke prvega polja. Če Python zaženemo (Run), vidimo elemente polja, ki se z vsako meritvijo povečujejo (Slika 6). S časoma bi bilo teh elementov ogromno, zato jih bomo omejili na 20, tako vidimo zadnjih dvajset meritev oziroma merilnih točk.

Slika 6: Elementi polja tempC se povečujejo z vsako meritvijo.

Za prikazovanje merilnih podatkov na grafu moramo kreirati funkcijo. Kreirajmo funkcijo def NarediGraf(). Vse, kar je z zamikom zamaknjeno pod tem zapisom, spada k tej funkciji. Zato moramo paziti na pravilne zamike naslednjih vrstic. Želimo da nam graf izrisuje potek temperature, zato napišemo v funkcijski blok plt.plot(tempC, 'ro-' ). Oznake ro- pomenijo naj bo graf povezana črta (-) rdeče barve (r), merilne točke pa naj bodo označene s pikami (o). Za drugačne parametre glej spletno stran. V glavni zanki z ukazom drawnow in parametrom NarediGraf poskrbimo za osveževanje grafa, osvežuje pa naj se vsakih 200 ms.

Slika 7: Graf poteka temperature z merilnimi točkami.

Po y osi z ukazom plt.ylim in parametroma 10, 30 (plt.ylim(10,30)) omejimo (limitiramo) temperaturno območje prikazovanja od 10 °C do 30 °C. Če tega ne storimo, Python avtomatsko določi razpon prikazovanja temperature po y osi. Z ukazom plt.title in parametrom Prikaz temperature in relativne vlage, senzor DHT22 določimo naslov oziroma ime grafa, ki je prikazan nad grafom. Določimo še prikaz mreže v grafu, njeno obliko in barvo. Če hočemo v graf napisati legendo, moramo najprej poimenovati prikaz po y osi (plt.ylabel('temperatura (C) '), nato pa določiti, kje naj bo legenda prikazana s plt.legend(loc = 'upper left'), če hočemo da je postavljena zgoraj levo.

Slika 8: Graf poteka temperature z merilnimi točkami, ime y osi, legenda in naslov grafa.

Podobno storimo še za graf prikazovanja relativne vlažnosti zraka, kar je razvidno iz celotnega programa.

Izdelajmo še 3D prikaz merjenja temperature in relativne vlažnosti zraka. Opis programa Python je v komentarjih programa. Program shranimo pod izbranim imenom, ki mu dodamo končnico .py

Program Python:

import serial                 #Uvoz knjižnice za serijsko komunikacijo.

from visual import *       #Uvoz vseh vPython knjižnic.

MojeOkno = display(title = 'Prikaz merjenja temperature in relativne vlage')

MojeOkno.width = 600           #600 pixlov.

MojeOkno.height = 500          #500 pixlov.

MojeOkno.autoscale = False          #Povemo vPython-u da ne razširja okna.

MojeOkno.range = (70,70,70)         #Delovna površina okna.

#Načrtovanje pozicije skale za temperaturo:

mybox = box(pos=(-43,-3,10), length=56,axis=(0,15,0), height=0.1, width=1,material=materials.bricks)

mybox3 = box(pos=(-43,-4,10), length=5,axis=(15,0,0), height=0.2)

mybox1 = box(pos=(-43,-22,10), length=5,axis=(15,0,0), height=0.1)

mybox4 = box(pos=(-43,5,10), length=5,axis=(15,0,0), height=0.1)

mybox5 = box(pos=(-43,14,10), length=5,axis=(15,0,0), height=0.1)

mybox2 = box(pos=(-43,-13,10), length=5,axis=(15,0,0), height=0.1)

mybox6 = box(pos=(-43,23,10), length=5,axis=(15,0,0), height=0.1)

#Načrtovanje pozicije skale za vlažnost:

myboxV = box(pos=(32,-3,10), length=56,axis=(0,15,0), height=0.2, width=1,material=materials.earth)

myboxV1 = box(pos=(32,-22,10), length=5,axis=(15,0,0), height=0.1)

myboxV2 = box(pos=(32,-13,10), length=5,axis=(15,0,0), height=0.1)

myboxV3 = box(pos=(32,-4,10), length=5,axis=(15,0,0), height=0.2)

myboxV4 = box(pos=(32,5,10), length=5,axis=(15,0,0), height=0.1)

myboxV5 = box(pos=(32,14,10), length=5,axis=(15,0,0), height=0.1)

myboxV6 = box(pos=(32,23,10), length=5,axis=(15,0,0), height=0.1)

#Barva, pozicija, usmerjenost in velikost cilindra za temperaturo. Ta je ozadje:

Ozadje=cylinder(color=color.white, pos=(-25,-30,0),axis=(0,5,0), radius=8, length=55)

PrikazTemp=cylinder(color=color.red, pos=(-25,-30,0),axis=(0,5,0), radius=8, length=5)    #Na istem mestu je enak cilinder rdeče barve.

#Barva, pozicija, usmerjenost in velikost cilindra za vlažnost. Ta je ozadje:

Ozadje1=cylinder(color=color.white, pos=(10,-30,0),axis=(0,5,0), radius=8, length=55)

PrikazVlage=cylinder(color=color.blue, pos=(10,-30,0),axis=(0,5,0), radius=8, length=5)    #Na istem mestu je enak cilinder modre barve.

#Kreiranje objekta za branje iz serijskega porta:

arduinoPodatki = serial.Serial('com10', 115200)        #Podatki od Arduino razvojne plošče, v tem primeru je COM 10.

ZapisTemp=label(text='Temp: ', pos=(-5,38,0), height=12, depth=-0.3)    #Napis nad cilindroma.

#Pozicije in ostale lastnosti napisov ob temperaturni skali:

Skala1=label(text='0 C', pos=(-37,-22,10), height=10, depth=-0.3, box = false)

Skala2=label(text='10 C', pos=(-37,-13,10), height=10, depth=-0.3, box = false)

Skala3=label(text='20 C', pos=(-37,-4,10), height=10, depth=-0.3, box = false)

Skala4=label(text='30 C', pos=(-37,5,10), height=10, depth=-0.3, box = false)

Skala5=label(text='40 C', pos=(-37,14,10), height=10, depth=-0.3, box = false)

Skala6=label(text='50 C', pos=(-37,23,10), height=10, depth=-0.3, box = false)

#Pozicije in ostale lastnosti napisov ob skali za vlažnost:

SkalaV1=label(text='0 %', pos=(25,-22,10), height=10, depth=-0.3, box = false)

SkalaV2=label(text='20 %', pos=(25,-13,10), height=10, depth=-0.3, box = false)

SkalaV3=label(text='40 %', pos=(25,-4,10), height=10, depth=-0.3, box = false)

SkalaV4=label(text='60 %', pos=(25,5,10), height=10, depth=-0.3, box = false)

SkalaV5=label(text='80 %', pos=(25,14,10), height=10, depth=-0.3, box = false)

SkalaV6=label(text='100 %', pos=(25,23,10), height=10, depth=-0.3, box = false)

while (1==1):   #Zanka ki se neprestano ponavlja (1 je vedno enako 1).

    rate(20)       #Ponovi zanko while 20 krat na sekundo.

    while(arduinoPodatki.inWaiting()==0):                       #Dokler ni podatka iz serijskega porta

        pass                                                                  #ne naredi ničesar.

    if(arduinoPodatki.inWaiting()>0):                               #Ali je prišel podatek na serijski port? Če je, potem izvedi naslednje korake.

        arduinoString = arduinoPodatki.readline()               #Prebere vrstico besedila iz serijskega porta, niz.

        dataArray = arduinoString.split(',')                          #Loči podatke o temperaturi s podatki o vlažnosti (kar je na vsaki strani vejice loči).

        Temp = float(dataArray[0])                                     #Niz znakov pretvori v spremenljivko tipa float (realno število).

        Vlaga = float(dataArray[1])        

        Zapis='Temperatura (C),  Relativna vlaga (%):  ' + arduinoString    #Poleg napisa pripiše vrednosti temperature in vlažnosti zraka.

        ZapisTemp.text=Zapis

        PrikazTemp.length = (5+Temp)                              #Od začetne vrednosti (5) spreminja dolžino cilindra v odvisnosti od vrednosti temperature (Temp).

        PrikazVlage.length = (5+Vlaga/2)                          #Vrednost vlage delimo z 2, zaradi preglednosti prikaza.