Come ho realizzato una stazione meteorologica Arduino completamente funzionale

Pubblicato: 2022-03-11

AGGIORNAMENTO: il lavoro sulla nostra stazione meteorologica Arduino è proseguito dopo la pubblicazione di questo articolo, culminato nel rilascio di Open Weather Station (OWS). Dai un'occhiata per ulteriori aggiornamenti, risorse, codice e nuovi tutorial.

Che cosa è questa storia?

Il kitesurf è uno degli sport più avvincenti al mondo. Tutto ciò che serve è una tavola da kite, uno specchio d'acqua e alcuni accessori. È un ottimo modo per entrare in contatto con la natura, liberare la mente e fare esercizio. Inoltre, puoi davvero impazzire con esso.

Allora, qual'è il problema?

Oh, dimenticavo un requisito essenziale: il vento. Ed è qui che abbiamo il nostro problema: non sai mai se ci sarà vento o meno a meno che tu non viva proprio vicino al tuo spot preferito per il kitesurf.

Vivo a Cordoba, in Argentina, a circa 130 chilometri (~80 miglia) dal lago dove faccio kitesurf. Sono circa due ore di macchina, che posso affrontare. Ma non posso affrontare il fatto che le previsioni del tempo siano imprecise. E dove vivo, le buone condizioni del vento durano solo un paio d'ore. L'ultima cosa che vuoi fare è chiarire il tuo programma del lunedì per fare kitesurf e ritrovarti a maledire gli dei su un lago senza vento dopo due ore di guida.

Avevo bisogno di conoscere le condizioni del vento del mio spot preferito per il kitesurf, in tempo reale. Così ho deciso di costruire la mia stazione meteorologica.

Misurare il tempo in tempo reale, in un ambiente ostile

L'obiettivo era fornire dati meteo in tempo reale al browser di casa:

Processo generale per la stazione meteorologica arduino

Prima di entrare nei dettagli, prendiamoci un momento per considerare le domande chiave e gli avvertimenti coinvolti in un progetto come questo:

  • Come posso creare una stazione meteorologica che non sia né preziosa né attraente per un ladro?
  • Come posso ridurre al minimo i costi hardware e i tempi di sviluppo?
  • Come posso misurare e accedere ai dati meteorologici in tempo reale e visualizzarli in modo utile?
    • Misure richieste: vento e raffiche di vento, direzione del vento, pioggia, pressione atmosferica, temperatura, umidità
    • Connetti la stazione a Internet
    • Archivia e recupera i dati meteorologici locali
    • Comunicare tra stazione meteo e server
  • Come posso ridurre la manutenzione a (quasi) zero?
    • Gestire la sospensione del software
    • Gestire la perdita di connettività
    • Gestire la perdita di approvvigionamento energetico

Saluta il mio piccolo amico!

file

Potresti pensare che il guanto sia lì per far sembrare la stazione più amichevole; ma in realtà viene utilizzato per testare il sensore barometrico (la pressione del guanto aumenta all'interno del guanto gonfio). Sulla destra, puoi vedere la stazione nella sua posizione finale, arroccata su una torre vicina.

Ho anche progettato e programmato un sito web sul kitesurf, che include un grafico in tempo reale delle misurazioni della stazione per aiutare la comunità del kitesurf. Infine, ho creato un gruppo di kitesurf su Facebook.

file

È fantastico! Allora come hai fatto?

Bene, affronterò ogni punto a turno:

"Come posso creare una stazione meteorologica che non sia né preziosa né attraente per un ladro?"

Questo è stato un fattore critico e, in molti modi, ha guidato il resto del processo di progettazione. La maggior parte delle stazioni premade al di sotto della linea di $ 2000 richiedeva una connessione USB a un computer. Se un ladro riconoscesse che la stazione aveva un PC accanto, sarebbe la fine delle cose, poiché il costo per sostituire il computer e la stazione sarebbe superiore al mio budget personale. Pertanto, ho deciso di testare diverse piattaforme hardware per implementare la stazione da zero, a un costo inferiore.

"Come posso ridurre al minimo i costi hardware e i tempi di sviluppo?"

Solo io sostenevo i costi di questo progetto collaterale e facevo tutto il lavoro nel mio tempo libero, quindi ovviamente questa era una grande preoccupazione. Ho iniziato con il popolare PIC32 e alcuni moduli Ethernet microchip preassemblati, ma i costi non erano bassi come mi aspettavo e c'erano troppi costi generali coinvolti nell'assemblaggio e nell'estensione dell'hardware. Quindi, ho iniziato a studiare Arduino: un hardware e un software open source per la prototipazione elettronica utilizzando il linguaggio C. Questo era esattamente quello che volevo e potevo acquistare moduli su DealeXtreme. Sono stato in grado di iniziare a giocare con soli $ 15 di spese e due giorni del mio tempo.

Naturalmente, Arduino ha anche i suoi limiti: solo 2KByte di RAM e 32Kbyte per il mio software compilato, che non lascia molto spazio per stringhe fantasiose o variabili inutili 1 .

"Come posso misurare e accedere ai dati meteorologici in tempo reale e visualizzarli in modo utile?"

Attualmente, la mia stazione può misurare: velocità del vento, raffiche di vento, direzione del vento, temperatura, umidità, pioggia e pressione atmosferica. Temperatura, umidità e pressione sono gestite da un paio di librerie, il che ha reso la vita molto più semplice.

La misurazione della velocità del vento e della pioggia è stata un po' disordinata. I sensori funzionano aprendo e chiudendo un interruttore (interruttore reed). Pertanto, avevo bisogno di implementare gli interrupt hardware per catturare il sensore non appena attiva l'input. Cioè, avevo bisogno di chiamare un metodo:

 attachInterrupt(RAINGAUGE_PIN, countRainCycles, FALLING);

Questo interrupt interromperebbe la normale esecuzione del codice e chiamerebbe la funzione countAnemometerCycles o countRainCycles non appena l'interruttore subisce un fronte di discesa, prodotto dalla chiusura o dall'apertura del circuito. Alcune variabili vengono incrementate su ciascun trigger dell'interruttore. (In seguito, pesi queste variabili per tenere conto delle conversioni di unità.)

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

Ma non così in fretta! Questo processo genera centinaia di falsi trigger come risultato dell'effetto di rimbalzo dello switch inerente a qualsiasi switch hardware. Fortunatamente, ci sono soluzioni hardware e software a questo problema.

Informazioni sull'effetto rimbalzo

L'effetto rimbalzo si verifica come conseguenza dell'apertura o chiusura fisica dell'interruttore dei suoi "contatti", che stabiliscono un contatto con il resto del circuito. Quando i contatti iniziano a separarsi (aprendo l'interruttore) o unendosi (chiudendo l'interruttore), possono essere generati alcuni piccoli archi elettrici, nonché un'elasticità meccanica nel circuito che attiverà e disattiverà il circuito per un paio di millisecondi. Quando si preme un interruttore della luce, questo effetto non è evidente; ma quando si collega un'interruzione al fronte di discesa di un segnale, questo effetto di rimbalzo attiva un sacco di interruzioni. Altro qui.

Rimbalzo del circuito

Ho implementato sia un circuito antirimbalzo hardware che una versione simile nel software. Ma come si implementa esattamente un antirimbalzo del software? Facile! Dopo che si è verificato il primo trigger previsto, "aspetta" il tempo necessario affinché il rimbalzo si stabilizzi prima di iniziare ad ascoltare nuovi interrupt. Questo può essere ottenuto in un paio di righe di C:

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

La funzione millis() restituisce il tempo di esecuzione corrente in millisecondi dall'accensione di Arduino. Vale anche la pena notare che queste variabili devono essere definite come volatili per istruire il compilatore a non ottimizzare l'esecuzione e quindi evitare valori imprecisi durante gli interrupt hardware.

In qualche modo, avevo bisogno che la stazione memorizzasse i dati accumulati e inviasse periodicamente queste misurazioni a un database MySQL. Quindi ho aggiunto un modulo Ethernet con uno slot SD per registrare i valori e recuperarli ogni volta che un utente (il server) si connette alla stazione. Durante i test a casa con la connettività ADSL ha funzionato straordinariamente bene, ma ho quasi perso i capelli quando l'ho testato "sul campo" con Internet 3G (utilizzando un modem 3G), poiché la stazione si ripristinava casualmente quando cercavo di recuperare il misure! Dopo test significativi, ho finalmente scoperto che gli esempi forniti su Internet che descrivono il "servire" i dati a un client connesso non consideravano che la connessione potesse essere così scarsa che la connessione al client potrebbe andare persa durante la trasmissione del pacchetto, causando il il buffer di output traboccherebbe. Ma perché una connessione interrotta dovrebbe causare un overflow del buffer? Bene, supponiamo che la sessione di trasmissione inizi e la stazione inizi a riempire il buffer di output con i dati. Idealmente, il client consuma quindi questo buffer più velocemente di quanto non venga riempito. Tuttavia, quando ci si connetteva con un modem 3G, non era così! La connessione al client era troppo scarsa, quindi il buffer si è riempito più velocemente di quanto fosse consumato, causando sia un overflow del buffer che un riavvio improvviso della stazione.

Per risolvere il problema, dovevo aggiungere una funzione alla libreria Ethernet fornita con Arduino che funzionasse in questo modo:

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

Quindi, sono stato in grado di verificare se il client aveva spazio nel buffer prima di provare a riempirlo con più dati:

 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();

A proposito, se sei interessato a programmare un Arduino, ecco un'ottima guida.

Un altro compito interessante è stata l'implementazione di un registro LIFO. Perché era necessario? Bene, in genere, quando salvo le misurazioni in un determinato file, l'approccio è semplice: aprire il file, aggiungere i nuovi campioni alla fine e chiudere il file. Ma diciamo che voglio recuperare le ultime 1000 misurazioni, ordinate cronologicamente. Tali misurazioni sono alla fine del file; quindi dovrei aprire il file, spostare il cursore alla fine, emettere le ultime misurazioni, quindi riportare il cursore del file sulla misurazione precedente e inviarlo cercando un delimitatore del campione per rilevare dove iniziare e fermarsi. L'Arduino non ha né RAM né potenza del processore sufficienti per eseguire rapidamente questo processo, quindi avevo bisogno di un altro approccio. Invece, ho deciso di inviare il file in ordine inverso al server, quindi ripristinare le stringhe letterali sul lato server:

 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--; } }

Con qualsiasi esperienza come sviluppatore PHP, è facile ottenere gli ultimi campioni con i caratteri nell'ordine corretto:

 // $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 :)

Sul lato server, ho quindi impostato un processo cron per recuperare le ultime misurazioni ogni due minuti e inserire i dati in un motore MySQL. Per visualizzare i dati, ho creato www.kitesurfcordoba.com.ar e ho usato jQuery per aggiornare automaticamente i grafici (che sono essi stessi generati usando pChart v2.0, una grande libreria open-source).

C'erano un sacco di altri trucchi necessari per far funzionare le cose, relative sia all'ingegneria del software che dell'hardware, ma mi sono trascinato abbastanza a lungo, quindi parliamo di ridurre al minimo la manutenzione.

"Come posso ridurre la manutenzione a (quasi) zero?"

Questa era una delle principali preoccupazioni perché per me non è certamente facile raggiungere la stazione: se fossi stato disposto a guidare per due ore solo per riparare un piccolo malfunzionamento, non avrei dovuto farla entrare in primo luogo (io non l'ho menzionato prima, ma dopo tutto quello che abbiamo passato, la stazione è in realtà una "lei" e il suo nome è Dorothy).

Quindi di che tipo di errori stiamo parlando qui? Bene, ad esempio: il software potrebbe bloccarsi, la rete potrebbe perdere la connettività, l'alimentazione elettrica potrebbe non funzionare (e lo fa), ecc.

In sostanza, la stazione deve eseguire quanto più possibile il ripristino automatico. Ecco perché ho utilizzato sia watchdog morbidi che rigidi. Per coloro che non hanno familiarità, un watchdog è un pezzo di software o hardware che controlla se un sistema funziona correttamente e, in caso contrario, tenta di riportarlo in vita. Arduino ha un watchdog integrato che puoi usare. L'ho impostato per attendere 8 secondi: se una chiamata impiega più tempo di quel limite di tempo, il watchdog del software ripristinerà la scheda.

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

Adoro questa funzione. Tuttavia, ci sono momenti in cui la scheda si ripristina e il modulo Ethernet no. Come mai? Bene, questa è una scheda di prototipazione relativamente economica, non un dispositivo molto costoso e a prova di errore (certamente non dovresti costruirci un pacemaker). Per superare questo inconveniente, ho dovuto hackerare Arduino collegando in modo incrociato un ingresso di ripristino hardware a un'uscita digitale sulla scheda stessa. Per evitare un ciclo di reset, è necessario aggiungere anche un paio di righe di codice:

 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 ...

Successivamente, sono stato in grado di eseguire un ripristino hardware su Arduino e su tutti i moduli su di esso (incluso il modulo Ethernet) semplicemente chiamando digitalWrite(RESET_ARDUINO_PIN, LOW) , che ha riportato in vita Dorothy dopo un paio di secondi.

Inoltre, la scheda si riavvia automaticamente dopo una perdita di energia. E se la connettività Internet fallisce, sfruttiamo le capacità di archiviazione della scheda SD (i dati possono essere archiviati sulla scheda per oltre una settimana e il server può recuperare i vecchi dati per recuperare eventuali campioni mancanti). La combinazione di tutte queste caratteristiche ci offre una stazione meteorologica estremamente robusta in grado di sopravvivere alle condizioni ostili per la quale è stata costruita. In totale, questa cosa mi è costata circa $ 300.

Grafico a torta

E alla fine

La stazione è in funzione da dicembre 2012. Ad oggi, non ha fallito (o se lo ha fatto, la stazione si è ripresa abbastanza velocemente che io e la comunità di kitesurf non ce ne siamo accorti). Ci sono circa 500 kitesurfisti che controllano regolarmente la stazione meteorologica prima di raggiungere lo spot. Quindi, oltre alla ricompensa per aver risolto alcune difficili sfide tecniche, ho anche avuto l'opportunità di fornire a un gruppo di persone un'esperienza di kitesurf più piacevole.

1 Inizialmente, stavo usando un Arduino Uno. Successivamente, sono passato a un Arduino Mega a causa della necessità di aumentare la RAM e la memoria flash.

Correlati: Utilizzo del campionamento audio ESP32