Wie ich eine voll funktionsfähige Arduino-Wetterstation gemacht habe

Veröffentlicht: 2022-03-11

UPDATE: Die Arbeit an unserer Arduino-Wetterstation wurde nach der Veröffentlichung dieses Artikels fortgesetzt und gipfelte in der Veröffentlichung der Open Weather Station (OWS). Überprüfen Sie es auf zusätzliche Updates, Ressourcen sowie Code und neue Tutorials.

Worum geht es?

Kitesurfen ist eine der süchtig machendsten Sportarten der Welt. Alles, was es braucht, ist ein Kiteboard, ein Gewässer und ein paar Accessoires. Es ist eine großartige Möglichkeit, mit der Natur in Kontakt zu kommen, Ihren Geist zu befreien und sich zu bewegen. Außerdem kann man damit wirklich verrückt werden.

Also, was ist das Problem?

Oh, ich habe eine wesentliche Voraussetzung vergessen: Wind. Und da haben wir unser Problem: Man weiß nie, ob es Wind gibt oder nicht, es sei denn, man wohnt direkt an seinem Lieblingsspot zum Kitesurfen.

Ich lebe in Cordoba, Argentinien, ungefähr 130 Kilometer von dem See entfernt, an dem ich kitesurfe. Das sind ungefähr zwei Stunden Fahrt, die ich bewältigen kann. Aber ich kann nicht damit umgehen, dass Wettervorhersagen ungenau sind. Und wo ich wohne, halten gute Windverhältnisse nur ein paar Stunden an. Das Letzte, was Sie tun möchten, ist, Ihren Montagsplan aufzuräumen, um Kitesurfen zu gehen und nach zwei Stunden Fahrt die Götter auf einem windstillen See zu verfluchen.

Ich musste die Windverhältnisse an meinem Lieblings-Kitesurf-Spot kennen – in Echtzeit. Also beschloss ich, meine eigene Wetterstation zu bauen.

Wettermessung in Echtzeit – in einer feindlichen Umgebung

Ziel war es, Echtzeit-Wetterdaten an den Browser zu Hause zu liefern:

Gesamtprozess für die Arduino-Wetterstation

Bevor ich auf die Einzelheiten eingehe, nehmen wir uns einen Moment Zeit, um die wichtigsten Fragen und Vorbehalte zu betrachten, die mit einem Projekt wie diesem verbunden sind:

  • Wie kann ich eine Wetterstation erstellen, die für einen Dieb weder wertvoll noch attraktiv ist?
  • Wie kann ich Hardwarekosten und Entwicklungszeit auf ein Minimum reduzieren?
  • Wie kann ich Wetterdaten in Echtzeit messen, abrufen und sinnvoll darstellen?
    • Erforderliche Messungen: Wind und Windböen, Windrichtung, Regen, Luftdruck, Temperatur, Luftfeuchtigkeit
    • Station mit dem Internet verbinden
    • Lokale Wetterdaten speichern und abrufen
    • Kommunikation zwischen Wetterstation und Server
  • Wie kann ich den Wartungsaufwand auf (fast) null reduzieren?
    • Verwalten Sie das Aufhängen von Software
    • Konnektivitätsverlust verwalten
    • Bewältigen Sie den Verlust der Energieversorgung

Sag hallo zu meinem kleinen Freund!

Datei

Sie denken vielleicht, dass der Handschuh dazu da ist, den Bahnhof freundlicher erscheinen zu lassen; aber es wird tatsächlich verwendet, um den barometrischen Sensor zu testen (der Handschuhdruck steigt im aufgeblasenen Handschuh). Rechts sehen Sie die Station an ihrem endgültigen Standort auf einem nahe gelegenen Turm.

Ich habe auch eine Website über Kitesurfen entworfen und programmiert, die eine Echtzeit-Darstellung der Messungen der Station enthält, um der Kitesurf-Community zu helfen. Schließlich habe ich eine Kitesurf-Gruppe auf Facebook erstellt.

Datei

Das ist großartig! Wie hast du es gemacht?

Nun, ich werde jeden Punkt der Reihe nach ansprechen:

„Wie kann ich eine Wetterstation erstellen, die für einen Dieb weder wertvoll noch attraktiv ist?“

Dies war ein kritischer Faktor und beeinflusste in vielerlei Hinsicht den Rest des Designprozesses. Die meisten vorgefertigten Stationen unter der 2000-Dollar-Grenze erforderten eine USB-Verbindung zu einem Computer. Wenn ein Dieb erkennen würde, dass neben der Station ein PC steht, wäre die Sache erledigt, da die Kosten für den Austausch des Computers und der Station mein persönliches Budget übersteigen würden. Daher habe ich mich entschieden, mehrere Hardwareplattformen zu testen, um die Station von Grund auf zu geringeren Kosten zu implementieren.

„Wie kann ich die Hardwarekosten und die Entwicklungszeit so gering wie möglich halten?“

Ich allein habe die Kosten für dieses Nebenprojekt getragen und die ganze Arbeit in meiner Freizeit gemacht, also war das natürlich eine große Sorge. Ich begann mit dem beliebten PIC32 und einigen vormontierten Mikrochip-Ethernet-Modulen, aber die Kosten waren nicht so niedrig, wie ich erwartet hatte, und es war viel zu viel Overhead mit der Hardware-Montage und -Erweiterung verbunden. Dann fing ich an, mich mit Arduino zu befassen: einer Open-Source-Hardware und -Software für das Prototyping von Elektronik in C-Sprache. Das war genau das, was ich wollte, und ich konnte Module auf DealeXtreme kaufen. Ich konnte mit nur 15 $ Ausgaben und zwei Tagen meiner Zeit anfangen, herumzuspielen.

Natürlich hat auch der Arduino seine Grenzen: nur 2 KByte RAM und 32 KByte für meine kompilierte Software – das lässt nicht viel Platz für schicke Strings oder nutzlose Variablen 1 .

„Wie kann ich Wetterdaten in Echtzeit messen, abrufen und sinnvoll darstellen?“

Derzeit kann meine Station messen: Windgeschwindigkeit, Windböe, Windrichtung, Temperatur, Luftfeuchtigkeit, Regen und Luftdruck. Temperatur, Feuchtigkeit und Druck werden von ein paar Bibliotheken gehandhabt, was das Leben viel einfacher macht.

Das Messen von Windgeschwindigkeit und Regen war ein bisschen chaotisch. Die Sensoren werden durch Öffnen und Schließen eines Schalters (Reed-Schalter) betätigt. Daher musste ich Hardware-Interrupts implementieren, um den Sensor zu fangen, sobald er den Eingang auslöst. Das heißt, ich musste eine Methode aufrufen:

 attachInterrupt(RAINGAUGE_PIN, countRainCycles, FALLING);

Dieser Interrupt würde die normale Codeausführung unterbrechen und die Funktion countAnemometerCycles oder countRainCycles aufrufen, sobald der Schalter eine fallende Flanke erfährt, die durch Schließen oder Öffnen des Stromkreises erzeugt wird. Einige Variablen werden bei jedem Auslösen des Schalters inkrementiert. (Später gewichten Sie diese Variablen, um Einheitenumrechnungen zu berücksichtigen.)

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

Aber nicht so schnell! Dieser Prozess erzeugt Hunderte von falschen Triggern als Ergebnis des Switch-Bounce-Effekts, der jedem Hardware-Switch innewohnt. Glücklicherweise gibt es sowohl Hardware- als auch Softwarelösungen für dieses Problem.

Über den Prelleffekt

Der Prelleffekt tritt auf, wenn der Schalter seine „Kontakte“ physisch öffnet oder schließt, die den Kontakt mit dem Rest des Stromkreises herstellen. Wenn die Kontakte beginnen, sich zu trennen (Öffnen des Schalters) oder zu vereinen (Schließen des Schalters), können einige kleine Lichtbögen sowie eine mechanische Elastizität im Stromkreis erzeugt werden, die den Stromkreis für einige Millisekunden ein- und ausschalten. Wenn Sie einen Lichtschalter umlegen, ist dieser Effekt nicht sichtbar; Wenn Sie jedoch einen Interrupt an die fallende Flanke eines Signals anhängen, löst dieser springende Effekt eine Menge Interrupts aus. Mehr hier.

Schaltkreisentprellung

Ich habe sowohl eine Hardware-Entprellschaltung als auch eine ähnliche Version in Software implementiert. Aber wie genau implementiert man eine Software-Entprellung? Leicht! Nachdem der erste erwartete Trigger auftritt, „warten“ Sie genügend Zeit, bis sich der Rücksprung beruhigt hat, bevor Sie anfangen, auf neue Interrupts zu warten. Dies kann in ein paar Zeilen von C erreicht werden:

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

Die Funktion millis() gibt die aktuelle Ausführungszeit in Millisekunden seit dem Einschalten des Arduino zurück. Es ist auch erwähnenswert, dass diese Variablen als flüchtig definiert werden müssen, um den Compiler anzuweisen, die Ausführung nicht zu optimieren und daher ungenaue Werte während der Hardware-Interrupts zu vermeiden.

Irgendwie brauchte ich die Station, um die gesammelten Daten zu speichern und diese Messungen regelmäßig an eine MySQL-Datenbank zu senden. Also habe ich ein Ethernet-Modul mit einem SD-Steckplatz hinzugefügt, um die Werte zu protokollieren und abzurufen, wenn ein Benutzer (der Server) eine Verbindung zur Station herstellt. Beim Testen zu Hause mit ADSL-Konnektivität funktionierte dies erstaunlich gut – aber ich verlor fast meine Haare, als ich dies „im Feld“ mit 3G-Internet (unter Verwendung eines 3G-Modems) testete, da sich die Station zufällig selbst zurücksetzte, als ich versuchte, das abzurufen Messungen! Nach umfangreichen Tests stellte ich schließlich fest, dass die im gesamten Internet bereitgestellten Beispiele, die das „Serving“ von Daten an einen verbundenen Client beschreiben, nicht berücksichtigten, dass die Verbindung möglicherweise so schlecht ist, dass die Verbindung zum Client während der Paketübertragung unterbrochen werden könnte, was dazu führen würde Ausgabepuffer würde überlaufen. Aber warum sollte eine unterbrochene Verbindung einen Pufferüberlauf verursachen? Angenommen, die Übertragungssitzung beginnt und die Station beginnt, den Ausgangspuffer mit Daten zu füllen. Im Idealfall verbraucht der Client diesen Puffer dann schneller, als er gefüllt wird. Bei einer Verbindung mit einem 3G-Modem war dies jedoch nicht der Fall! Die Verbindung zum Client war viel zu schlecht, sodass sich der Puffer schneller füllte als verbraucht wurde, was sowohl zu einem Pufferüberlauf als auch zu einem plötzlichen Neustart der Station führte.

Um das Problem zu lösen, musste ich der Ethernet-Bibliothek, die mit dem Arduino bereitgestellt wird, eine Funktion hinzufügen, die ungefähr so ​​​​lief:

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

Dann konnte ich überprüfen, ob der Client etwas Platz im Puffer hatte, bevor ich versuchte, ihn mit mehr Daten zu füllen:

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

Übrigens, wenn Sie daran interessiert sind, einen Arduino zu programmieren, finden Sie hier eine großartige Anleitung.

Eine weitere interessante Aufgabe war die Implementierung eines LIFO-Logs. Warum war das notwendig? Nun, wenn ich Messungen in einer bestimmten Datei speichere, ist der Ansatz normalerweise einfach: Öffnen Sie die Datei, hängen Sie die neuen Proben an das Ende und schließen Sie die Datei. Angenommen, ich möchte die letzten 1000 Messungen chronologisch sortiert abrufen. Diese Messungen befinden sich am Ende der Datei; also sollte ich die Datei öffnen, den Cursor an das Ende bewegen, die letzten Messungen ausgeben, dann den Datei-Cursor zurück zur vorherigen Messung bringen und diese ausgeben, indem ich ein Beispieltrennzeichen suche, um zu erkennen, wo ich anfangen und aufhören soll. Der Arduino hat weder genug RAM noch Prozessorleistung, um diesen Prozess schnell auszuführen, also brauchte ich einen anderen Ansatz. Stattdessen habe ich mich entschieden, die Datei in umgekehrter Reihenfolge an den Server auszugeben und dann die Zeichenfolgenliterale auf der Serverseite zurückzusetzen:

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

Mit jeder Erfahrung als PHP-Entwickler ist es einfach, die neuesten Beispiele mit den Zeichen in der richtigen Reihenfolge zu erhalten:

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

Auf der Serverseite richte ich dann einen Cron-Prozess ein, um alle zwei Minuten die neuesten Messungen abzurufen und die Daten in eine MySQL-Engine einzufügen. Um die Daten anzuzeigen, habe ich www.kitesurfcordoba.com.ar erstellt und jQuery verwendet, um die Diagramme automatisch zu aktualisieren (die selbst mit pChart v2.0, einer großartigen Open-Source-Bibliothek, generiert werden).

Es waren eine Menge anderer Tricks notwendig, um die Dinge zum Laufen zu bringen, sowohl im Zusammenhang mit der Software- als auch mit der Hardwareentwicklung, aber ich habe mich lange genug hingezogen – reden wir also über die Minimierung der Wartung.

„Wie kann ich den Wartungsaufwand auf (fast) null reduzieren?“

Das war ein großes Problem, denn es ist sicherlich nicht einfach für mich, die Station zu erreichen – wenn ich bereit gewesen wäre, zwei Stunden weg zu fahren, nur um eine kleine Störung zu beheben, dann hätte ich sie gar nicht erst reinbringen müssen (I habe das vorher nicht erwähnt, aber nach allem, was wir durchgemacht haben, ist die Station eigentlich eine „sie“, und ihr Name ist Dorothy).

Über welche Art von Fehlern sprechen wir hier? Nun, zum Beispiel: Die Software könnte hängen bleiben, das Netzwerk könnte die Konnektivität verlieren, die Energieversorgung könnte ausfallen (und das tut sie) usw.

Im Wesentlichen muss die Station so viel Selbstwiederherstellung wie möglich durchführen. Deshalb habe ich sowohl weiche als auch harte Watchdogs verwendet. Für diejenigen, die sich nicht auskennen, ein Watchdog ist eine Software oder Hardware, die überprüft, ob ein System ordnungsgemäß funktioniert, und falls nicht, versucht, es wieder zum Leben zu erwecken. Der Arduino hat einen eingebetteten Watchdog, den Sie verwenden können. Ich habe es so eingestellt, dass es 8 Sekunden wartet: Wenn ein Anruf länger als dieses Zeitlimit dauert, setzt der Software-Watchdog das Board zurück.

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

Ich liebe diese Funktion. Es gibt jedoch Zeiten, in denen das Board zurückgesetzt wird und das Ethernet-Modul nicht. Warum? Nun, dies ist ein relativ erschwingliches Prototyping-Board, kein sehr teures, ausfallsicheres Gerät (Sie sollten sicherlich keinen Herzschrittmacher damit bauen). Um diesen Nachteil zu überwinden, musste ich den Arduino hacken, indem ich einen Hardware-Reset-Eingang mit einem digitalen Ausgang auf der Platine selbst verdrahtete. Um eine Reset-Schleife zu vermeiden, müssen auch ein paar Codezeilen hinzugefügt werden:

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

Danach konnte ich einen Hardware-Reset für den Arduino und alle darauf befindlichen Module (einschließlich des Ethernet-Moduls) durchführen, indem ich einfach digitalWrite(RESET_ARDUINO_PIN, LOW) , was Dorothy nach ein paar Sekunden wieder zum Leben erweckte.

Darüber hinaus startet das Board nach einem Energieverlust automatisch neu. Und wenn die Internetverbindung ausfällt, nutzen wir die Speicherkapazitäten der SD-Karte (Daten können über eine Woche auf der Karte gespeichert werden, und der Server kann alte Daten abrufen, um fehlende Samples wiederherzustellen). Durch die Kombination all dieser Funktionen erhalten wir eine äußerst robuste Wetterstation, die die feindlichen Bedingungen überstehen kann, für deren Überwachung sie gebaut wurde. Insgesamt hat mich das Ding knapp 300€ gekostet.

Kreisdiagramm-Grafik

Und am Ende

Die Station funktioniert seit Dezember 2012. Bis heute ist sie nicht ausgefallen (oder wenn doch, hat sich die Station schnell genug erholt, dass die Kitesurf-Community und ich es nicht bemerkt haben). Es gibt etwa 500 Kitesurfer, die regelmäßig die Wetterstation überprüfen, bevor sie zum Spot reisen. Abgesehen von der Belohnung für das Lösen einiger harter technischer Herausforderungen hatte ich auch die Gelegenheit, einer Gruppe von Leuten ein angenehmeres Kitesurf-Erlebnis zu bieten.

1 Anfangs habe ich einen Arduino Uno verwendet. Später wechselte ich aufgrund des Bedarfs an mehr RAM und Flash-Speicher zu einem Arduino Mega.

Verwandt: Arbeiten mit ESP32 Audio Sampling