Cum am realizat o stație meteo Arduino complet funcțională

Publicat: 2022-03-11

UPDATE: Lucrările la stația noastră meteo Arduino au continuat după publicarea acestui articol, culminând cu lansarea Open Weather Station (OWS). Consultați-l pentru actualizări suplimentare, resurse, împreună cu cod și tutoriale noi.

Despre ce este vorba?

Kitesurfingul este unul dintre cele mai dependente sporturi din lume. Tot ce are nevoie este un kiteboard, un corp de apă și câteva accesorii. Este o modalitate grozavă de a intra în contact cu natura, de a-ți elibera mintea și de a face mișcare. În plus, poți să înnebunești cu el.

Deci care este problema?

Oh, am uitat o cerință esențială: vântul. Și aici avem problema noastră: nu știi niciodată dacă va fi sau nu vânt decât dacă locuiești chiar lângă locul tău preferat de kitesurfing.

Locuiesc în Cordoba, Argentina, la aproximativ 130 de kilometri (~80 mile) distanță de lacul unde fac kitesurf. Este un drum de aproximativ două ore cu mașina, cu care mă pot descurca. Dar nu pot face față faptului că prognozele meteo sunt inexacte. Și acolo unde locuiesc, condițiile bune de vânt durează doar câteva ore. Ultimul lucru pe care vrei să-l faci este să-ți clarifice programul de luni pentru a merge la kitesurfing și a te trezi că înjurând zeii pe un lac fără vânt după două ore de condus.

Aveam nevoie să știu condițiile vântului din locul meu preferat de kitesurfing — în timp real. Așa că am decis să-mi construiesc propria stație meteo.

Măsurarea vremii în timp real — într-un mediu ostil

Scopul a fost de a furniza date meteo în timp real către browserul de acasă:

Procesul general pentru stația meteo arduino

Înainte de a intra în detalii, să luăm un moment în considerare întrebările cheie și avertismentele implicate într-un proiect ca acesta:

  • Cum pot crea o stație meteo care să nu fie nici valoroasă, nici atractivă pentru un hoț?
  • Cum pot menține costurile hardware și timpul de dezvoltare la minimum?
  • Cum pot măsura și accesa datele meteo în timp real și le pot afișa într-un mod util?
    • Măsurători necesare: vânt și rafale de vânt, direcția vântului, ploaie, presiune atmosferică, temperatură, umiditate
    • Conectați stația la Internet
    • Stocați și preluați datele meteo locale
    • Comunicați între stația meteo și server
  • Cum pot reduce întreținerea la (aproape) zero?
    • Gestionați suspendarea software-ului
    • Gestionați pierderea conectivității
    • Gestionați pierderea aprovizionării cu energie

Salută-l pe micul meu prieten!

fişier

S-ar putea să credeți că mănușa este acolo pentru a face stația să pară mai prietenoasă; dar de fapt este folosit pentru a testa senzorul barometric (presiunea mănușii crește în interiorul mănușii umflate). În dreapta, puteți vedea gara în locația sa finală, cocoțată în vârful unui turn din apropiere.

De asemenea, am proiectat și programat un site web despre kitesurfing, care include o diagramă în timp real a măsurătorilor stației pentru a ajuta comunitatea de kitesurfing. În cele din urmă, am creat un grup de kitesurfing pe Facebook.

fişier

Asta-i grozav! Deci cum ai făcut-o?

Ei bine, voi aborda fiecare punct pe rând:

„Cum pot crea o stație meteo care să nu fie nici valoroasă, nici atractivă pentru un hoț?”

Acesta a fost un factor critic și, în multe privințe, a condus restul procesului de proiectare. Majoritatea posturilor prefabricate sub linia de 2000 USD necesitau o conexiune USB la un computer. Dacă un hoț ar recunoaște că stația are un PC lângă ea, asta ar fi sfârșitul, deoarece costul înlocuirii computerului și a stației ar fi peste bugetul meu personal. Prin urmare, am decis să testez mai multe platforme hardware pentru implementarea stației de la zero, la un cost mai mic.

„Cum pot menține costurile hardware și timpul de dezvoltare la minimum?”

Eu singur suportam costurile acestui proiect secundar și făceam toată munca în timpul meu liber, așa că, desigur, aceasta a fost o mare îngrijorare. Am început cu popularul PIC32 și câteva module Ethernet microcip pre-asamblate, dar costurile nu au fost atât de mici pe cât mă așteptam și a fost mult prea multă suprasarcină implicată în asamblarea și extinderea hardware-ului. Apoi, am început să caut Arduino: un hardware și software open source pentru prototiparea electronică folosind limbajul C. Este exact ceea ce îmi doream și puteam achiziționa module de pe DealeXtreme. Am putut să încep să mă joc cu doar 15 USD de cheltuieli și două zile din timpul meu.

Desigur, Arduino are și limitările sale: doar 2KBytes de RAM și 32Kbytes pentru software-ul meu compilat — care nu lasă mult loc pentru șiruri de caractere fanteziste sau variabile inutile 1 .

„Cum pot măsura și accesa datele meteo în timp real și să le afișez într-un mod util?”

În prezent, stația mea poate măsura: viteza vântului, rafala vântului, direcția vântului, temperatura, umiditatea, ploaia și presiunea atmosferică. Temperatura, umiditatea și presiunea sunt gestionate de câteva biblioteci, ceea ce a făcut viața mult mai ușoară.

Măsurarea vitezei vântului și a ploii a fost puțin dezordonată. Senzorii acționează prin deschiderea și închiderea unui întrerupător (comutator lamelă). Astfel, a trebuit să implementez întreruperi hardware pentru a prinde senzorul imediat ce declanșează intrarea. Adică trebuia să apelez la o metodă:

 attachInterrupt(RAINGAUGE_PIN, countRainCycles, FALLING);

Această întrerupere ar întrerupe execuția normală a codului și ar apela funcția countAnemometerCycles sau countRainCycles de îndată ce comutatorul experimentează o margine de scădere, produsă de închiderea sau deschiderea circuitului. Câteva variabile sunt incrementate la fiecare declanșare al comutatorului. (Mai târziu, cântăriți aceste variabile pentru a ține cont de conversiile de unități.)

 void countRainCycles() { rainCyclesCounter++; // This is easy! And it actually works. }

Dar nu atât de repede! Acest proces generează sute de declanșări false ca urmare a efectului de respingere a comutatorului inerent oricărui comutator hardware. Din fericire, există atât soluții hardware cât și software pentru această problemă.

Despre efectul de săritură

Efectul de respingere apare ca urmare a deschiderii sau închiderii fizice a comutatorului a „contactelor”, care stabilesc contactul cu restul circuitului. Când contactele încep să se separe (deschiderea comutatorului) sau să se unească (închiderea întrerupătorului), pot fi generate niște arcuri electrice mici, precum și o elasticitate mecanică în circuit care va declanșa circuitul pornit și oprit pentru câteva milisecunde. Când apăsați un comutator de lumină, acest efect nu este evident; dar atunci când atașați o întrerupere la marginea de cădere a unui semnal, acest efect de sărituri declanșează o mulțime de întreruperi. Mai multe aici.

Deboulaj circuit

Am implementat atât un circuit de deboucere hardware, cât și o versiune similară în software. Dar cum implementezi mai exact un software de debounce? Uşor! După ce apare primul declanșator așteptat, „așteptați” suficient timp pentru ca săritura să se stabilească înainte de a începe să ascultați noi întreruperi. Acest lucru poate fi realizat în câteva rânduri de C:

 void countRainCycles() { if (nextTimeRainIterrupt == 0 || nextTimeRainIterrupt < millis()) { rainCyclesCounter++; // The interrupts counter nextTimeRainIterrupt = millis() + 100; // Wait 100msecs before next trigger } }

Funcția millis() returnează timpul de execuție curent în milisecunde de când a fost pornit Arduino. De asemenea, este de remarcat faptul că aceste variabile trebuie definite ca volatile pentru a instrui compilatorul să nu optimizeze execuția și, prin urmare, să evite valorile inexacte în timpul întreruperilor hardware.

Cumva, aveam nevoie de stație să stocheze datele acumulate și să trimită periodic aceste măsurători la o bază de date MySQL. Așa că am adăugat un modul Ethernet cu un slot SD pentru a înregistra valorile și a le prelua ori de câte ori un utilizator (serverul) se conectează la stație. În timpul testării acasă cu conectivitate ADSL, acest lucru a funcționat uimitor de bine, dar aproape că mi-am pierdut părul când am testat acest lucru „pe teren” cu Internet 3G (folosind un modem 3G), deoarece stația se reseta la întâmplare când încercam să recuperez măsurători! După teste semnificative, am descoperit în sfârșit că exemplele furnizate pe tot Internetul care descriu „servirea” de date către un client conectat nu au considerat că conexiunea ar putea fi atât de slabă încât conexiunea la client s-ar putea pierde transmisia la mijlocul pachetului, cauzând tamponul de ieșire ar depăși. Dar de ce o conexiune întreruptă ar cauza o depășire a tamponului? Ei bine, spuneți că începe sesiunea de transmisie și stația începe să umple bufferul de ieșire cu date. În mod ideal, clientul consumă apoi acest tampon mai repede decât este umplut. Cu toate acestea, la conectarea cu un modem 3G, acesta nu a fost cazul! Conexiunea la client a fost mult prea slabă, așa că buffer-ul s-a umplut mai repede decât a fost consumat, ceea ce a cauzat atât o depășire a memoriei tampon, cât și o repornire bruscă a stației.

Pentru a rezolva problema, trebuia să adaug o funcție la Biblioteca Ethernet furnizată cu Arduino, care mergea cam așa:

 int EthernetClient::free() { if (_sock != MAX_SOCK_NUM) return W5100.getTXFreeSize(_sock); return 0; }

Apoi, am putut verifica dacă clientul avea ceva spațiu în buffer înainte de a încerca să-l umple cu mai multe date:

 while (file.available() > 0) { if (client.free() > 0) { // This was key to solving the issue c = file.read(); client.print((char)c); } else { // No free buffer? Ok, I'll wait a couple of millis... delay(50); } } file.close();

Apropo, dacă sunteți interesat să programați un Arduino, iată un ghid grozav.

O altă sarcină interesantă a fost implementarea unui jurnal LIFO. De ce a fost acest lucru necesar? Ei bine, de obicei, când salvez măsurătorile într-un anumit fișier, abordarea este simplă: deschideți fișierul, adăugați noile mostre la sfârșit și închideți fișierul. Dar să spunem că vreau să aduc cele mai recente 1000 de măsurători, sortate cronologic. Aceste măsurători sunt la sfârșitul fișierului; așa că ar trebui să deschid fișierul, să muți cursorul la sfârșit, să scot cele mai recente măsurători, apoi să aduc cursorul fișierului înapoi la măsurarea anterioară și să-l scot prin căutarea unui delimitator de probă pentru a detecta de unde să înceapă și să se oprească. Arduino nu are suficientă memorie RAM și nici putere de procesor pentru a executa rapid acest proces, așa că aveam nevoie de o altă abordare. În schimb, am decis să scot fișierul în ordine inversă către server și apoi să revin literalele șir înapoi pe partea serverului:

 unsigned long filePosition = file.size(); file.seek(filePosition); while (filePosition >= 0) { if (client.free() > 0){ file.seek(filePosition); c = file.peek(); if (c != -1) { client.print((char)c); } if (filePosition <= 0) { break; } filePosition--; } }

Cu orice experiență ca dezvoltator PHP, este ușor să obțineți cele mai recente mostre cu caracterele în ordinea corectă:

 // $output has the reversed string measures, each sample is delimited by ; $rows = split(";", trim($output)); array_walk_recursive($rows, 'reverseString'); if (strlen($rows[0]) == 0) { array_shift($rows); // Remove the first line if empty } function reverseString(&$row, $key) { $row = trim(strrev($row)); } // $rows is now the array of the latest samples :)

Pe partea de server, am configurat apoi un proces cron pentru a prelua cele mai recente măsurători la fiecare două minute și pentru a introduce datele într-un motor MySQL. Pentru a afișa datele, am creat www.kitesurfcordoba.com.ar și am folosit jQuery pentru a actualiza automat graficele (care sunt ele însele generate folosind pChart v2.0, o bibliotecă open-source grozavă).

Au fost o grămadă de alte trucuri necesare pentru ca lucrurile să funcționeze, legate atât de ingineria software, cât și de hardware, dar m-am târât destul de mult – așa că hai să vorbim despre minimizarea întreținerii.

„Cum pot reduce întreținerea la (aproape) zero?”

Aceasta a fost o preocupare majoră, deoarece cu siguranță nu este ușor pentru mine să ajung la gară — dacă aș fi fost dispus să conduc două ore distanță doar pentru a remedia o defecțiune minoră, atunci nu aș fi fost nevoit să o oblig în primul rând (eu nu am menționat asta înainte, dar după tot ce am trecut, postul este de fapt o „ea”, iar numele ei este Dorothy).

Deci despre ce fel de erori vorbim aici? Ei bine, de exemplu: software-ul s-ar putea bloca, rețeaua s-ar putea pierde conectivitatea, alimentarea cu energie s-ar putea eșua (și se întâmplă), etc.

În esență, stația trebuie să efectueze cât mai multă auto-recuperare posibil. De aceea am folosit atât câini de pază moi, cât și cei tari. Pentru cei care nu sunt familiarizați, un watchdog este o piesă de software sau hardware care verifică dacă un sistem funcționează corect și, dacă nu, încearcă să-l readucă la viață. Arduino are un watchdog încorporat pe care îl puteți folosi. L-am setat să aștepte 8 secunde: dacă un apel durează mai mult decât această limită de timp, software-ul watchdog va reseta placa.

 wdt_enable(WDTO_8S); // "wdt" stands for "watchdog timer"

Îmi place această funcție. Cu toate acestea, există momente când placa se resetează și modulul Ethernet nu. De ce? Ei bine, aceasta este o placă de prototipare relativ accesibilă, nu un dispozitiv foarte scump, rezistent la eșec (cu siguranță nu ar trebui să construiți un stimulator cardiac cu ea). Pentru a depăși acest dezavantaj, a trebuit să piratam Arduino prin cablarea încrucișată a unei intrări de resetare hardware la o ieșire digitală de pe placa în sine. Pentru a evita o buclă de resetare, trebuie adăugate și câteva linii de cod:

 void setup() { digitalWrite(RESET_ARDUINO_PIN, HIGH); // Set it to HIGH immediately on boot pinMode(RESET_ARDUINO_PIN, OUTPUT); // We declare it an output ONLY AFTER it's HIGH digitalWrite(RESET_ARDUINO_PIN, HIGH); // Default to HIGH, set to LOW to HARD RESET ...

După aceea, am putut emite o resetare hardware a Arduino și a tuturor modulelor de deasupra acestuia (inclusiv modulul Ethernet) apelând pur și simplu digitalWrite(RESET_ARDUINO_PIN, LOW) , ceea ce a readus-o la viață pe Dorothy după câteva secunde.

În plus, placa se repornește automat după o pierdere de energie. Și dacă conexiunea la internet eșuează, exploatăm capacitățile de stocare ale cardului SD (datele pot fi stocate pe card timp de peste o săptămână, iar serverul poate extrage date vechi pentru a recupera eventualele mostre lipsă). Combinarea tuturor acestor caracteristici ne oferă o stație meteo extrem de robustă, care poate supraviețui condițiilor ostile pentru care a fost construită pentru a le monitoriza. În total, chestia asta m-a costat aproximativ 300 de dolari.

Grafic cu diagramă circulară

Si in sfarsit

Stația funcționează din decembrie 2012. Până în prezent, nu a eșuat (sau dacă a făcut-o, stația și-a revenit suficient de repede încât comunitatea de kitesurfing și cu mine nu am observat). Există aproximativ 500 de kitesurferi care verifică în mod regulat stația meteo înainte de a călători la fața locului. Așa că, pe lângă recompensa pentru rezolvarea unor provocări tehnice grele, am avut și oportunitatea de a oferi o mulțime de oameni cu o experiență de kitesurfing mai plăcută.

1 Inițial, foloseam un Arduino Uno. Mai târziu, am trecut la un Arduino Mega din cauza nevoii de memorie RAM și memorie flash crescută.

Înrudit : Lucrul cu ESP32 Audio Sampling