Industrielle Fertigung
Industrielles Internet der Dinge | Industrielle Materialien | Gerätewartung und Reparatur | Industrielle Programmierung |
home  MfgRobots >> Industrielle Fertigung >  >> Manufacturing Technology >> Herstellungsprozess

DIY-Regenvorhersage mit Arduino, Python und Keras

Komponenten und Verbrauchsmaterialien

Kleine Plastikbox mit abnehmbarem Deckel (meine hat Schrauben)
× 1
drei AAA-Batteriehalter
× 1
drei wiederaufladbare AAA-Batterien
× 1
Kleines 6-V-Solarmodul
× 1
SparkFun Arduino Pro Mini 328 - 5V/16MHz
× 1
1N4004 Diode
× 1
Allzwecktransistor NPN
× 1
ein Regensensor
× 1
Serielles Kommunikationsmodul HC-12
× 1
HC-12 serielles USB-Modul
× 1
SparkFun Atmospheric Sensor Breakout - BME280
× 1
BH1750
× 1
Leiterplatte, Drähte, Lötzinn, KF301-2P-Schraubsteckverbinder , männliche und weibliche Leiterplattenverbinder, Kleber
× 1
3,3-V-Regler
× 1

Notwendige Werkzeuge und Maschinen

USB-auf-Seriell-FTDI-Adapter FT232RL
Drill
Lötkolben (generisch)
Schraubendreher

Über dieses Projekt

Zuerst ein paar Worte zu diesem Projekt, der Motivation, den verwendeten Technologien und dem Endprodukt, das wir bauen werden.

Das große Ziel hier ist also natürlich, den Regen in der Zukunft vorherzusagen (wir versuchen es mit 6 Stunden). Die Vorhersage ist ein Ja oder Nein (Boolean in Programmiersprache). Ich habe in Tutorials zu diesem Thema gesucht und keines gefunden, das in jeder Hinsicht vollständig ist. Meiner wird dies also zu einem ganz neuen Ansatz führen und jeden Aspekt davon beleuchten. Dafür werden wir:

  • Bauen die Wetterstation selbst. Die Station sollte mit einem Solarpanel und einem extrem stromsparenden Modus (einige Dutzend Mikroamperestunden) vollständig netzunabhängig sein.
  • Programm die Station, damit sie Daten sammelt und alle zehn Minuten an eine Basisstation überträgt
  • sammeln die Daten auf der Basisstation und speichern (in einer Datenbank)
  • mit neuronalen Netzwerken (Keras-Bibliothek) und andere Python-Bibliotheken wie Pandas filtern, bereinigen und verarbeiten die Daten und speisen sie dann in ein neuronales Netzwerk ein, um ein "Modell" für die Vorhersage zu trainieren, dass es regnen soll oder nicht
  • endlich vorhersagen ob es in den nächsten 6 Stunden regnen wird oder nicht und die Benutzer per E-Mail benachrichtigen

Ich habe diese Wetterstation persönlich verwendet, um Daten zu sammeln (Sie können die Daten in den nächsten Schritten herunterladen, wenn Sie möchten). Mit nur etwa 600 Tagen Wetterdaten kann das System eine Vorhersage treffen, ob es in den nächsten 6 Stunden mit einer Genauigkeit von etwa 80% je nach Parametern regnen wird oder nicht, was nicht so schlecht ist.

In diesem Tutorial führen wir Sie durch alle notwendigen Schritte, um Regenfälle von Grund auf vorherzusagen. Wir erstellen ein Endprodukt, das einen praktischen Job macht, ohne externe Wetter- oder Machine-Learning-APIs zu verwenden. Wir lernen nebenbei, wie man eine praktische Wetterstation baut (mit geringem Stromverbrauch und netzunabhängig), die wirklich Daten über lange Zeiträume ohne Wartung sammelt. Danach lernen Sie, wie Sie es mit der Arduino IDE programmieren. So sammeln Sie Daten in einer Datenbank auf einer Basisstation (Server). Und wie man die Daten verarbeitet (Pandas) und neuronale Netze (Keras) anwendet und dann den Niederschlag vorhersagt.

Schritt 1:Teile und Werkzeuge zum Bau der Station

Teile:

1. Kleine Plastikbox mit abnehmbaren Deckeln (meine hat Schrauben). Die Boxgröße sollte groß genug sein, um die kleinen Komponenten und Batterien aufzunehmen. Meine Box hat 11 x 7 x 5 cm

2. drei AAA-Batteriehalter

3. drei wiederaufladbare AAA-Batterien

4. 6V kleines Solarpanel

5. Arduino Pro Mini 328p

6. eine Diode, 1N4004 (um Rückstrom von den Batterien zum Panel zu verhindern)

7. ein kleiner NPN-Transistor und 1k-Widerstand (zum Ein- und Ausschalten der Stromversorgung der Komponenten)

8. ein Regensensor

9. HC-12 serielles Kommunikationsmodul

10. HC-12 USB-Seriell-Modul (für die Basisstation)

11. Bosch Sensormodul BME280 (für Feuchtigkeit, Temperatur, Druck)

12. BH1750 Lichtsensormodul

13. PCB, Drähte, Lötzinn, KF301-2P-Stecker in Schraubverbindung, männliche und weibliche Leiterplattensteckverbinder, Kleber

14. 3.3V-Regler

15. eine Basisstation:ein PC oder ein ständig laufendes Entwicklungsboard. Seine Rolle ist es, Daten zu sammeln, das Regenvorhersagemodell zu trainieren und Vorhersagen zu treffen

Tools:

1. USB-zu-Seriell-FTDI-Adapter FT232RL zum Programmieren des Arduino Pro Mini

2. Arduino-IDE

3. Bohren

4. Feinsägeblatt

5. Schraubendreher

6. Lötkolben

7. Drahtschneider

Fähigkeiten:

1. Löten, sehen Sie sich dieses Tutorial an

2. Grundlegende Arduino-Programmierung

3. Linux-Dienstkonfiguration, Paketinstallation

4. Einige Programmierkenntnisse

Schritt 2:Aufbau der Wetterstation

Die Wetterstation besteht aus folgenden Komponentensätzen:

1. die Box mit dem darauf geklebten Solarpanel

2 . die Platine mit der Elektronik im Inneren

3. der Batteriehalter auch innen

4. BME280 und Licht- und Regensensor außen

1. Die Box benötigt 4 Löcher, eines für die Solarpaneldrähte, die anderen drei für die Sensoren, die außen platziert werden. Bohren Sie zuerst die Löcher, sie sollten groß genug sein, damit die männlich-weiblichen Drähte herausragen und zu den Sensoren gehen. Nachdem die Löcher gebohrt sind, kleben Sie die Platte auf eine Seite der Box und führen Sie die Drähte durch ein Loch im Inneren

2. Die Platine hält Arduino, HC-12, 3.3V-Regler, Diode, Transistor, Widerstand und zwei KF301-2P

  • Löten Sie zuerst die beiden Leiterplattenbuchsen auf der Leiterplatte für das Arduino, löten Sie die Leiterplattenstecker auf das Arduino und platzieren Sie das Arduino auf der Leiterplatte
  • Die Arduino-LED sollte entfernt werden oder mindestens einer ihrer Pins. das ist sehr wichtig weil die LED viel Strom verbraucht. Achten Sie darauf, keine anderen Komponenten zu beschädigen
  • Löten Sie den Transistor, den Widerstand und den 3,3-V-Regler an
  • löten Sie die beiden KF301-2P. Einer für das Solarpanel, der andere für den Batteriehalter
  • Drei Buchsenbuchsen anlöten:für Lichtsensor, BME280 und Regensensor
  • Löten Sie kleine Drähte, um alle PCB-Komponenten zu verbinden (überprüfen Sie die Bilder und die Fritzing-Schema)

3. Legen Sie 3 geladene AAA-NiMH-Batterien in den Halter und legen Sie ihn in die Box, indem Sie die Drähte in den KF301-2P-Anschluss stecken

4. Schließen Sie das BME280 und die Lichtsensoren von außerhalb der Box an die entsprechenden Stecker an

Für den Regensensor löten Sie drei Drähte (Gnd, Vcc, Signal) an ihn und an die andere Seite löten Sie die Steckerstifte, die in die Box gehen, an die entsprechenden Stecker

Das letzte, was es wäre, die Station an ihre endgültige Position zu bringen. Ich habe einen vor Regen und Schnee geschützten Standort gewählt. Ich habe für den Regensensor längere Kabel gewählt und ihn separat im Regen auf eine stabile Unterlage gelegt. Für die Hauptbox habe ich ein spezielles Klebeband gewählt (siehe Bilder), aber alles, was die Box hält, reicht.

skizze.fzz

Schritt 3:Arduino-Code

In diesem Schritt erfahren Sie, welche externen Bibliotheken benötigt werden, wir geben einen Überblick über den Code und seine Funktionsweise und können ihn natürlich herunterladen oder in die Arduino IDE kopieren und in die Wetterstation hochladen.

Die Aufgabe der Wetterstation besteht darin, alle 10 Minuten Daten über ihre Sensoren an eine Basisstation zu übertragen.

Lassen Sie uns zunächst beschreiben, was das Wetterstationsprogramm macht:

1. Sensordaten lesen (Feuchtigkeit, Temperatur, Druck, Regen, Licht, Spannung)

2. überträgt die codierten Daten über eine zweite serielle Softwareleitung.

Die codierten Daten sehen so aus:

H1:78|T1:12|PS1:1022|L1:500|R1:0|V1:4010|  

Die obige Aussage bedeutet:Luftfeuchtigkeit von Station "1" beträgt 78 Prozent, Temperatur von Station 1 beträgt 12 Grad, Druck beträgt 1022 bar, Lichtstärke 500 Lux, Regen 0 und Spannung 4010 Millivolt

3. Schalten Sie die Zusatzkomponenten aus:Sensoren und Kommunikationsgerät

4. versetzt das Arduino für 10 Minuten in den Schlafmodus (dadurch verbraucht es weniger 50 Mikroampere)

5. schalten Sie die Komponenten ein und wiederholen Sie die Schritte 1 - 4

Eine kleine zusätzliche Optimierung hier, wenn der Spannungspegel über 4,2 V liegt, verwendet das Arduino die normale Schlaffunktion "Verzögerung (Millisekunden)". Dadurch wird der Stromverbrauch stark erhöht und die Spannung schnell gesenkt. Dies verhindert effektiv, dass das Solarpanel die Batterien überlädt.

Den Code aus meinem Github-Repository erhalten Sie hier:https://github.com/danionescu0/home-automation/tre...

Oder kopiere es von unten, so oder so Entferne einfach die Zeile mit "transmitSenzorData("V", Sensoren.Voltage);"

#include "LowPower.h"
#include "SoftwareSerial.h"#include "Wire.h"#include "Adafruit_Sensor.h"#include "Adafruit_BME280.h"#include "BH1750.h "SoftwareSerial serialComm(4, 5); // RX, TXAdafruit_BME280 bme; BH1750 lightMeter;const byte rainPin =A0;byte SensorenCode =1;/** * Spannungspegel, der den Mikrocontroller in den Tiefschlaf statt in den regulären Ruhezustand versetzt */int voltageDeepSleepThreshold =4200; const byte peripherialsPowerPin =6;char buffer[] ={' ',' ',' ',' ',' ',' ',' '};struct sensorData { byte Feuchte; int-Temperatur; Byte-Regen; int-Druck; lange Spannung; int Licht; };sensorData-Sensoren;void setup () { Serial.begin (9600); serialComm.begin(9600); pinMode (PeripheriegerätePowerPin, AUSGANG); digitalWrite (PeripheriegerätePowerPin, HIGH); Verzögerung (500); if (! bme.begin ()) { Serial.println ( "Konnte keinen gültigen BME280-Sensor finden, Verkabelung überprüfen!"); Während (1) { customSleep (100); } } Serial.println ( "Initialisierung erfolgreich abgeschlossen"); Verzögerung (50); digitalWrite (peripherialsPowerPin, HIGH);}void loop () { updateSenzors (); Daten übermitteln(); benutzerdefinierterSchlaf(75); }void updateSenzors() { bme.begin(); lightMeter.begin(); Verzögerung (300); sensoren.temperature =bme.readTemperature(); Sensoren.Druck =bme.readPressure() / 100.0F; sensor.humidity =bme.readHumidity(); sensor.light =lightMeter.readLightLevel(); Sensoren.Spannung =readVcc(); sensor.rain =readRain();}void transmitData(){ emptyIncommingSerialBuffer(); Serial.print ("Temp:"); Serial.println (sensors.temperature); Serial.print ("Feuchte:"); Serial.println (sensors.humidity); Serial.print ("Druck:"); Serial.println (sensors.pressure); Serial.print ("Light:"); Serial.println (sensors.light); Serial.print("Spannung:");Serial.println(Sensoren.Spannung); Serial.print ("Regen:"); Serial.println (sensors.rain); sendSenzorData("T", Sensoren.Temperatur); transmitSenzorData("H", sensor.humidity); sendSenzorData("PS", Sensoren.Druck); sendSenzorData("L", sensor.light); sendSenzorData("V", Sensoren.Spannung); transmitSenzorData("R", sensor.rain);}void emptyIncommingSerialBuffer(){ while (serialComm.available()> 0) { serialComm.read(); Verzögerung(5); }}void transmitSenzorData (String-Typ, Int-Wert) { serialComm.print (Typ); serialComm.print (Sensorcode); serialComm.print(":"); serialComm.print (Wert); serialComm.print("|"); delay (50);}void customSleep (lange achtSecondCycles) { if (sensors.voltage> voltageDeepSleepThreshold) { Verzögerung (achtSecondCycles * 8000); Rückkehr; } digitalWrite (peripherialsPowerPin, LOW); for (int i =0; i

Laden Sie vor dem Hochladen des Codes die folgenden Arduino-Bibliotheken herunter und installieren Sie sie:

* BH1750-Bibliothek:https://github.com/claws/BH1750 * LowPower-Bibliothek:https://github.com/rocketscream/Low-Power

* Adafruit Sensor-Bibliothek:https://github.com/adafruit/Adafruit_Sensor

* Adafruit BME280-Bibliothek:https://github.com/adafruit/Adafruit_Sensor

Wenn Sie nicht wissen, wie das geht, sehen Sie sich dieses Tutorial an.

Schritt 4:Vorbereiten der Basisstation

Die Basisstation besteht aus einem Linux-Computer (Desktop, Laptop oder Entwicklungsboard) mit dem HC-12 USB Modul angebracht. Der Computer muss immer eingeschaltet bleiben, um alle 10 Minuten Daten von der Station zu sammeln.

Ich habe meinen Laptop mit Ubuntu 18 verwendet.

Die Installationsschritte:

1. Anakonda installieren. Anaconda ist ein Python-Paketmanager, der es uns leicht macht, mit denselben Abhängigkeiten zu arbeiten. Wir werden in der Lage sein, die Python-Version und jede Paketversion zu kontrollieren

Wenn Sie nicht wissen, wie man es installiert, sehen Sie sich dieses Tutorial an:https://www.digitalocean.com/community/tutorials/h... und folgen Sie den Schritten 1 - 8

2. Installieren Sie mongoDB. MongoDb wird unsere Hauptdatenbank für dieses Projekt sein. Es speichert Daten über alle Zeitreihen der Sensoren. Es ist schemalos und für unsere Zwecke einfach zu bedienen.

Für Installationsschritte besuchen Sie ihre Seite:https://docs.mongodb.com/v3.4/tutorial/install-mon...

Ich habe eine ältere Version von mongoDb 3.4.6 verwendet, wenn Sie dem obigen Tutorial folgen, erhalten Sie genau das. Im Prinzip sollte es mit der neuesten Version funktionieren.

[Optional] füge einen Index zum Datumsfeld hinzu:

Mungous-Wetter db.weather_station.createIndex({"date" :1}) 

3. Laden Sie das Projekt hier herunter:https://github.com/danionescu0/home-automation. Wir verwenden den Wetter-Vorhersage-Ordner

sudo apt-get install gitgit clone https://github.com/danionescu0/home-automation.gi... 

4. Anaconda-Umgebung erstellen und konfigurieren:

cd weather-predict # erstelle eine Anaconda-Umgebung namens "Weather" mit Python 3.6.2conda create --name weather python=3.6.2 # aktiviere Environmentconda aktiviere Weather# installiere alle Pakete pip install -r Requirements.txt  

Dadurch wird eine neue Anaconda-Umgebung erstellt und die benötigten Pakete installiert. Einige der Pakete sind:

Keras (hochrangige neuronale Netzwerkschicht, mit dieser Bibliothek machen wir alle unsere neuronalen Netzwerkvorhersagen)

Pandas (nützliches Werkzeug, das Daten manipuliert, wir werden es intensiv verwenden)

pymongo (Python mongoDb-Treiber)

sklearn (Data-Mining- und Datenanalyse-Tools)

Projekt konfigurieren

Die Konfigurationsdatei befindet sich im Weather-Predict-Ordner und heißt config.py

1. Wenn Sie MongoDb remote oder auf einem anderen Port installieren, ändern Sie den "Host" oder "Port" in der

mongodb ={ 'host':'localhost', 'port':27017}... 

2. Jetzt müssen wir den seriellen USB-Adapter HC-12 anschließen. Vor dem Lauf:

ls -l /dev/tty* 

und Sie sollten eine Liste der gemounteten Geräte erhalten.

Stecken Sie nun den HC-12 in einen USB-Port und führen Sie den gleichen Befehl erneut aus. Es sollte ein neuer Eintrag in dieser Liste sein, unser serieller Adapter. Ändern Sie nun ggf. den Adapterport in der Config

seriell ={ 'port':'/dev/ttyUSB0', 'baud_rate':9600} 

Die anderen Konfigurationseinträge sind einige Datei-Standardpfade, keine Notwendigkeit für eine Änderung.

Schritt 5:Verwenden Sie die Wetterstation in der Praxis

Hier besprechen wir grundlegende Dinge zum Importieren meiner Testdaten, Ausführen einiger Tests damit, Einrichten Ihrer eigenen Daten, Anzeigen einiger Grafiken und Einrichten einer E-Mail mit Vorhersagen für die nächsten Stunden.

Wenn Sie mehr darüber erfahren möchten, wie es funktioniert, lesen Sie den nächsten Schritt "Wie funktioniert es"

Meine bereits gesammelten Daten importieren

MongoDb wird mit einem CLI-Befehl zum Importieren von Daten aus json geliefert:

mongoimport -d weather -c weather_station --file sample_data/weather_station.json 

Dadurch wird die Datei aus den Beispieldaten in die "Wetter"-Datenbank und die "Datenpunkte"-Sammlung importiert

Eine Warnung hier, wenn Sie meine gesammelten Daten verwenden und sie mit Ihren neuen lokalen Daten kombinieren, kann die Genauigkeit aufgrund der kleinen Unterschiede in der Hardware (Sensoren) und lokalen Wettermustern sinken.

Neue Daten sammeln

Eine der Aufgaben der Basisstation besteht darin, eingehende Daten von der Wetterstation zur späteren Verarbeitung in der Datenbank zu speichern. Um den Prozess zu starten, der den seriellen Port überwacht und in der Datenbank speichert, führen Sie einfach Folgendes aus:

conda active weatherpython serial_listener.py# alle 10 Minuten sollten Sie Daten von der Wetterstation sehen sehen:[Sensor:type(temperature), value(14.3)][Sensor:type(pressure), value( 1056.0)]... 

Generieren des Vorhersagemodells

Ich gehe davon aus, dass Sie meine Daten importiert haben oder "das Skript einige Jahre lang ausgeführt haben", um Ihre personenbezogenen Daten zu sammeln. In diesem Schritt verarbeiten wir die Daten, um ein Modell zu erstellen, das verwendet wird, um zukünftigen Regen vorherzusagen.

conda aktivieren Weatherpython train.py --days_behind 600 --test-file-percent 10 --datapoints-behind 8 --hour-granularity 6 

* Der erste Parameter --days_behind gibt an, wie viele Daten in die Vergangenheit das Skript verarbeiten soll. Es wird in Tagen gemessen

* --test-file-percent gibt an, wie viele Daten für Testzwecke berücksichtigt werden sollen. Dies ist ein regelmäßiger Schritt in einem maschinellen Lernalgorithmus

* --hour-granularity bedeutet im Grunde, wie viele Stunden in der Zukunft wir die Vorhersage haben wollen

* --datapoints-behind dieser Parameter wird im nächsten Abschnitt behandelt

Einige Datendiagramme mit allen Sensoren der Wetterstation anzeigen

Sagen wir für die letzten 10 Tage:

conda aktivieren Wetter-Python-Diagramme --days-behind 10 

Vorhersagen, ob es in der nächsten Zeit regnen wird

Wir sagen voraus, ob es regnen wird und senden eine Benachrichtigungs-E-Mail

conda wetter python aktivieren predict.py --datapoints-behind 8 --hour-granularity 6 --from-addr a_gmail_address --from-password gmail_password --to-addr a_email_destination 

Führen Sie eine Batch-Vorhersage für die Testdaten aus:

python Predict_batch.py ​​-f sample_data/test_data.csv 

Es ist wichtig, dieselben Parameter wie im obigen Train-Skript zu verwenden.

Damit die E-Mail-Benachrichtigung funktioniert, melden Sie sich bei Ihrem Google Mail-Konto an und schalten Sie Weniger sichere Apps zulassen auf EIN. Beachten Sie, dass dies anderen den Zugriff auf Ihr Konto erleichtert.

Du benötigst zwei E-Mail-Adressen, eine Google Mail-Adresse mit aktivierter obiger Option und eine andere Adresse, an die du deine Benachrichtigung erhältst.

Wenn Sie stündlich Benachrichtigungen erhalten möchten, legen Sie das Skript in crontab

Um zu sehen, wie all dies möglich ist, überprüfen Sie den nächsten Schritt

Schritt 6:Wie funktioniert es?

In diesem letzten Schritt werden wir mehrere Aspekte der Architektur dieses Projekts besprechen:

1. Projektübersicht, wir besprechen die allgemeine Architektur und die beteiligten Technologien

2. Grundkonzepte des maschinellen Lernens

3. Wie die Daten aufbereitet werden (der wichtigste Schritt)

4. So funktioniert die eigentliche Wrapper-API für neuronale Netzwerke (Keras)

5. Zukünftige Verbesserungen

Ich werde versuchen, hier einige Codebeispiele zu geben, aber bedenken Sie, dass es nicht 100% der Code aus dem Projekt ist. Im Projekt selbst ist der Code etwas komplizierter mit Klassen und einer Struktur

1. Projektübersicht, wir besprechen die allgemeine Architektur und die beteiligten Technologien

Wie bereits erwähnt, besteht das Projekt aus zwei separaten Teilen. Die Wetterstation selbst, deren einzige Funktion darin besteht, Daten zu sammeln und zu übertragen. Und die Basisstation, an der das gesamte Sammlungstraining und die Vorhersagen stattfinden.

Vorteile der Trennung der Wetterstation und der Basisstation:

  • Strombedarf, wenn die Wetterstation die Daten auch verarbeiten könnte, würde sie viel Strom benötigen, vielleicht große Sonnenkollektoren oder eine permanente Stromquelle
  • Portabilität, aufgrund ihrer geringen Größe kann die Wetterstation Daten aus einigen hundert Metern Entfernung sammeln und Sie können ihren Standort bei Bedarf leicht ändern
  • Skalierbarkeit, Sie können die Vorhersagegenauigkeit erhöhen, indem Sie mehr als eine Wetterstation bauen und diese auf einige hundert Meter verteilen
  • niedrige Kosten, da es sich um ein billiges Gerät handelt, das Sie leicht nachbauen können, falls eines verloren geht oder gestohlen wird

Die Datenbankauswahl . Ich habe mongoDb gewählt, weil es nette Funktionen bietet:schemalose, kostenlose und einfach zu verwendende API

Jedes Mal, wenn Sensordaten empfangen werden, werden die Daten in der Datenbank gespeichert, und die Dateneingabe sieht ungefähr so ​​​​aus:

{ "_id" :"04_27_2017_06_17", "humidity" :65, "date" :ISODate("2017-04-27T06:17:18Z"), "pressure" :1007, "temperature" :9, "Regen" :0, "Licht" :15} 

Die Datenbank speichert Daten im BSON-Format (ähnlich JSON), sodass sie leicht zu lesen und leicht zu bearbeiten sind. Ich habe die Daten unter einem Bezeichner zusammengefasst, der das Datum als Zeichenfolge in Minuten formatiert enthält, daher ist die kleinste Gruppierung hier eine Minute.

Die Wetterstation sendet (bei ordnungsgemäßer Funktion) alle 10 Minuten einen Datenpunkt. Ein Datenpunkt ist eine Sammlung von "Datum", "Feuchtigkeit", "Druck", "Temperatur", "Regen" und "Licht".

Die Datenverarbeitung und das neuronale Netzwerk Technologiewahl

Ich habe Python für das Backend gewählt, weil viele wichtige Neuerungen in neuronalen Netzen in Python zu finden sind. Eine wachsende Community mit vielen Github-Repositorys, Tutorial-Blogs und Büchern hilft dabei.

* Für die Datenverarbeitung habe ich Pandas verwendet (https://pandas.pydata.org/ ) . Pandas erleichtern die Arbeit mit Daten. Sie können Tabellen aus CSV-, Excel-, Python-Datenstrukturen laden und neu anordnen, Spalten löschen, Spalten hinzufügen, nach einer Spalte indizieren und viele andere Transformationen.

* Für die Arbeit mit neuronalen Netzen habe ich Keras gewählt (https://keras.io/). Keras ist ein neuronaler Netzwerk-Wrapper auf hoher Ebene über APIs auf niedrigerer Ebene wie Tensorflow, und man kann ein neuronales Netzwerk mit mehreren Ebenen mit einem Dutzend Codezeilen oder so erstellen. Dies ist ein großer Vorteil, da wir auf der großartigen Arbeit anderer Menschen etwas Nützliches aufbauen können. Nun, das ist die Grundausstattung der Programmierung, baut auf anderen kleineren Bausteinen auf.

2. Grundkonzepte des maschinellen Lernens

Der Zweck dieses Tutorials besteht nicht darin, maschinelles Lernen zu lehren, sondern lediglich einen seiner möglichen Anwendungsfälle zu skizzieren und wie wir es praktisch auf diesen Anwendungsfall anwenden können.

Neuronale Netze sind Datenstrukturen, die Gehirnzellen ähneln, die Neuronen genannt werden. Die Wissenschaft hat entdeckt, dass ein Gehirn spezielle Zellen hat, die Neuronen genannt werden, die mit anderen Neuronen durch elektrische Impulse über "Linien", die Axone genannt werden, kommunizieren. Bei ausreichender Stimulation (von vielen anderen Neuronen) werden die Neuronen einen weiter entfernten elektrischen Impuls in diesem "Netzwerk" auslösen, der andere Neuronen stimuliert. Dies ist natürlich eine zu starke Vereinfachung des Prozesses, aber im Grunde versuchen Computeralgorithmen, diesen biologischen Prozess zu replizieren.

In neuronalen Computernetzen hat jedes Neuron einen "Triggerpunkt", an dem es, wenn es über diesen Punkt stimuliert wird, die Stimulation nach vorne ausbreitet, andernfalls nicht. Dafür hat jedes simulierte Neuron einen Bias und jedes Axon ein Gewicht. Nach einer zufälligen Initialisierung dieser Werte startet ein Prozess namens "Lernen", dh in einer Schleife führt ein Algorithmus diese Schritte aus:

  • stimulieren Sie die Eingabeneuronen
  • verbreiten Sie die Signale durch die Netzwerkschichten, bis die Ausgabeneuronen
  • Lesen Sie die Ausgabeneuronen und vergleichen Sie die Ergebnisse mit den gewünschten Ergebnissen
  • passen Sie die Axongewichte an, um beim nächsten Mal ein besseres Ergebnis zu erzielen
  • neu starten, bis die Anzahl der Schleifen erreicht ist

Wenn Sie mehr Details zu diesem Prozess erfahren möchten, können Sie diesen Artikel lesen:https://mattmazur.com/2015/03/17/a-step-by-step-ba.... Es gibt auch zahlreiche Bücher und Tutorials da draußen.

Eine weitere Sache, hier verwenden wir eine überwachte Lernmethode. Das bedeutet, dass wir dem Algorithmus auch die Eingaben und die Ausgaben beibringen, damit er bei einem neuen Satz von Eingaben die Ausgabe vorhersagen kann.

3. Wie die Daten aufbereitet werden (der wichtigste Schritt)

Bei vielen Problemen mit maschinellem Lernen und neuronalen Netzwerken ist die Datenaufbereitung ein sehr wichtiger Teil und deckt Folgendes ab:

  • die Rohdaten abrufen
  • Datenbereinigung:Dies bedeutet das Entfernen von verwaisten Werten, Aberrationen oder anderen Anomalien
  • Datengruppierung:Viele Datenpunkte nehmen und in einen aggregierten Datenpunkt umwandeln
  • Datenverbesserung:Hinzufügen anderer Aspekte der Daten, die aus eigenen Daten oder aus externen Quellen stammen
  • Aufteilen der Daten in Zug- und Testdaten
  • teilen Sie jeden der Zug- und Testdaten in Eingaben und Ausgaben auf. Normalerweise hat ein Problem viele Eingänge und wenige Ausgänge
  • Skalieren Sie die Daten neu, sodass sie zwischen 0 und 1 liegen (dies hilft dem Netzwerk dabei, Verzerrungen mit hohen/niedrigen Werten zu beseitigen)

Rohdaten abrufen

In unserem Fall ist es wirklich einfach, Daten für MongoDb in Python zu erhalten. Angesichts unserer Datenpunktsammlung reichen nur diese Codezeilen

client =MongoClient(host, port).weather.datapoints cursor =client.find( {'$and' :[ {'date' :{'$gte' :start_date}}, {'date' :{'$lte' :end_date}} ]} )data =list(cursor).. 

Datenbereinigung

Die leeren Werte im Datenrahmen werden gelöscht

dataframe =dataframe.dropna() 

Datengruppierung und Datenverbesserung

This is a very important step, the many small datapoins will be grouped into intervals of 6 hours. For each group several metrics will be calculated on each of the sensors (humidity, rain, temperature, light, pressure)

  • min value
  • max value
  • mean
  • 70, 90, 30, 10 percentiles
  • nr of times there has been a rise in a sensor
  • nr of times there has been a fall in a sensor
  • nr of times there has been steady values in a sensor

All of these things will give the network information for a datapoint, so for each of the 6 hours intervals these things will be known.

From a dataframe that looks like this:

_id date humidity light pressure rain temperature 04_27_2017_03_08 2017-04-27 03:08:36 67.0 0.0 1007.0 0.0 11.004_27_2017_03_19 2017-04-27 03:19:05 66.0 0.0 1007.0 0.0 11.004_27_2017_03_29 2017-04-27 03:29:34 66.0 0.0 1007.0 0.0 11.0  

And the transformation will be:"

_id date humidity_10percentile humidity_30percentile humidity_70percentile humidity_90percentile humidity_avg ... temperature_avg temperature_fall temperature_max temperature_min temperature_rise temperature_steady ... 04_27_2017_0 2017-04-27 03:08:36 59.6 60.8 63.2 66.0 62.294118 ... 10.058824 2 11.0 9.0 1 1404_27_2017_1 2017-04-27 06:06:50 40.3 42.0 60.0 62.0 50.735294 ... 14.647059 3 26.0 9.0 11 2004_27_2017_2 2017-04-27 12:00:59 36.0 37.0 39.8 42.0 38.314286 ... 22.114286 1 24.0 20.0 5 29  

After this a new column named "has_rain" will be added. This will be the output (our predicted variable). Has rain will be 0 or 1 depending if the rain average is above a threshold (0.1). With pandas it's as simple as:

dataframe.insert(loc=1, column='has_rain', value=numpy.where(dataframe['rain_avg']> 0.1, 1, 0)) 

Data cleanup (again)

- we'll drop the date column because it's no use to us, and also remove datapoints where the minimum temperature is below 0 because our weather station it doesn't have a snow sensor, so we won't be able to measure if it snowed

dataframe =dataframe.drop(['date'], axis=1)dataframe =dataframe[dataframe['temperature_min']>=0] 

Data enhancing

Because data in the past might influence our prediction of the rain, we need for each of the dataframe rows to add columns reference to the past rows. This is because each of the row will serve as a training point, and if we want the prediction of the rain to take into account previous datapoints that's exactly what we should do:add more columns for datapoints in the past ex:

_id has_rain humidity_10percentile humidity_30percentile humidity_70percentile humidity_90percentile ... temperature_steady_4 temperature_steady_5 temperature_steady_6 temperature_steady_7 temperature_steady_8 ... 04_27_2017_3 0 36.0 44.8 61.0 63.0 ... NaN NaN NaN NaN NaN04_28_2017_0 0 68.0 70.0 74.0 75.0 ... 14.0 NaN NaN NaN NaN04_28_2017_1 0 40.0 45.0 63.2 69.0 ... 20.0 14.0 NaN NaN NaN04_28_2017_2 0 34.0 35.9 40.0 41.0 ... 29.0 20.0 14.0 NaN NaN04_28_2017_3 0 36.1 40.6 52.0 54.0 ... 19.0 29.0 20.0 14.0 NaN04_29_2017_0 0 52.0 54.0 56.0 58.0 ... 26.0 19.0 29.0 20.0 14.004_29_2017_1 0 39.4 43.2 54.6 57.0 ... 18.0 26.0 19.0 29.0 20.004_29_2017_2 1 41.0 42.0 44.2 47.0 ... 28.0 18.0 26.0 19.0 29.0  

So you see that for every sensor let's say temperature the following rows will be added:"temperature_1", "temperature_2".. meaning temperature on the previous datapoint, temperature on the previous two datapoints etc. I've experimented with this and I found that a optimum number for our 6 hour groupings in 8. That means 8 datapoints in the past (48 hours). So our network learned the best from datapoins spanning 48 hours in the past.

Data cleanup (again)

As you see, the first few columns has "NaN" values because there is nothing in front of them so they should be removed because they are incomplete.

Also data about current datapoint should be dropped, the only exception is "has_rain". the idea is that the system should be able to predict "has_rain" without knowing anything but previous data.

Splitting the data in train and test data

This is very easy due to Sklearn package:

from sklearn.model_selection import train_test_split ...main_data, test_data =train_test_split(dataframe, test_size=percent_test_data) ... 

This will split the data randomly into two different sets

Split each of the train and test data into inputs and outputs

Presuming that our "has_rain" interest column is located first

X =main_data.iloc[:, 1:].valuesy =main_data.iloc[:, 0].values  

Rescale the data so it's between 0 and 1

Again fairly easy because of sklearn

from sklearn.preprocessing import StandardScalerfrom sklearn.externals import joblib..scaler =StandardScaler()X =scaler.fit_transform(X) ...# of course we should be careful to save the scaled model for later reusejoblib.dump(scaler, 'model_file_name.save')  

4. How the actual neural network wrapper API works (Keras)

Building a multi layer neural network with Keras is very easy:

from keras.models import Sequentialfrom keras.layers import Densefrom keras.layers import Dropout ...input_dimensions =X.shape[1] optimizer ='rmsprop'dropout =0.05model =Sequential()inner_nodes =int(input_dimensions / 2)model.add(Dense(inner_nodes, kernel_initializer='uniform', activation='relu', input_dim=input_dimensions))model.add(Dropout(rate=dropout))model.add(Dense(inner_nodes, kernel_initializer='uniform', activation='relu'))model.add(Dropout(rate=dropout))model.add(Dense(1, kernel_initializer='uniform', activation='sigmoid'))model.compile(optimizer=optimizer, loss='mean_absolute_error', metrics=['accuracy']) model.fit(X, y, batch_size=1, epochs=50)...# save the model for later useclassifier.save('file_model_name') 

So what does this code mean? Here we're building a sequential model, that means sequentially all the layers will be evaluated.

a) we declare the input layer (Dense), here all the inputs from our dataset will be initializedm so the "input_dim" parameter must be equal to the row length

b) a Dropout layer is added. To understand the Dropout first we must understand what "overfitting" means:it's a state in which the network has learned too much particularities for a specific dataset and will perform badly when confronted to a new dataset. The dropout layer will disconnect randomly neurons at each iteration so the network won't overfit.

c) another layer of Dense is added

d) another Dropout

e) the last layer is added with one output dimension (it will predict only yes/no)

f) the model is "fitted" that means the learning process will begin, and the model will learn

Other parameters here:

  • activation functions (sigmoid, relu). This are functions that dictate when the neuron will transmit it's impulse further in the network. There are many, but sigmoid and relu are the most common. Check out this link for more details:https://towardsdatascience.com/activation-function...
  • kernel_initializer function (uniform). This means that all the weights are initialized with random uniform values
  • loss function (mean_absolute_error). This function measures the error comparing the network predicted result versus the ground truth. There are many alternatives:https://keras.io/losses/
  • metrics function (accuracy). It measures the performance of the model
  • optimiser functions (rmsprop). It optimizes how the model learn through backpropagation.
  • batch_size. Number of datapoints to take once by Keras before applying optimizer function
  • epochs:how many times the process it's started from 0 (to learn better)

There is no best configuration for any network or dataset, all these parameters can an should be tuned for optimal performance and will make a big difference in prediction success.

5. Future improvements

Let's start from the weather station , I can see a lot of improving work to be done here:

  • add a wind speed / direction sensor. This could be a very important sensor that i'm missing in my model
  • experiment with UV rays, gas and particle sensors
  • add at least two stations in the zone for better data (make some better averages)
  • collect a few more years of data, i've experimented with just a year and a half

Some processing improvements:

  • try to incorporate data from other sources into the model. You can start to import wind speed data and combine with the local station data for a better model. This website offers historical data:https://www.wunderground.com/history/
  • optimize the Keras model better by adjusting:layers, nr of neurons in layers, dropout percents, metrics functions, optimiser functions, loss functions, batch size, learning epochs
  • try other model architectures, for example i've experimented with LSTM (long short term memory) but it gived slightly poorer results)

To try different parameters on the learning model you can use

python train.py --days_behind 600 --test-file-percent 10 --datapoints-behind 6 --hour-granularity 6 --grid-search 

This will search through different "batch_size", "epoch", "optimizer" and "dropout" values, evaluate all and print out the best combination for your data.

If you have some feedback on my work please share it, thanks for staying till the end of the tutorial!

Step 7:Bonus:Using an Official Weather Dataset

I was wondering if I can get better results with a more reliable weather station, so i've searched a bit, and i've came across "Darksky AP I" (https://darksky.net/dev), this is a great tool that provides current and historical weather data with many more sensor data:

  • temperature
  • humidity
  • pressure
  • wind speed
  • wind gust
  • ub index
  • visibilitySo this beeing data from an official weather station, and having more parameters I thought it should perform better so i've gave it a try. To replicate my findings:

1.Download the data from darsky or import my MongoDb collection:

a) Download

  • to download your self, first create an account in darsky and get the API key
  • replace the API key in download_import/config.py
  • also in the config replace the geographic coordonates for the location you want to predict the rain
  • in a console activate "weather" anaconda environment and run:
python download_import/darksky.py -d 1000 

- the free version of the API is limited to 1000 requests per day so if you want more data you need to wait for a longer time

b) Import my downloaded data for Bucharest city

- in a console run

mongoimport -d weather -c darksky --file sample_data/darksky.json  

2. When you train the model specify that it should run on "darksy" dataset

python train.py -d 2000 -p 20 -dp 4 -hg 6 --data-source darksky 

3. To see the results run predict batch script as before

python predict_batch.py -f sample_data/test_data.csv 

You'll see that the overall prediction percent has gone from about 80% to 90%. Also the prediction accuracy when accounting only rainy days has gone up.

So yes, the dataset really matters.

Code

  • Code-Snippet 2
  • Code-Snippet Nr. 5
  • Code snippet #6
  • Code snippet #10
  • Code snippet #15
  • Code snippet #16
  • Code snippet #18
  • Code snippet #22
  • Code snippet #23
  • Code snippet #25
  • Code snippet #26
Code-Snippet #2Klartext
#include "LowPower.h"
#include "SoftwareSerial.h"#include "Wire.h"#include "Adafruit_Sensor.h"#include "Adafruit_BME280.h"#include "BH1750.h"SoftwareSerial serialComm(4, 5); // RX, TXAdafruit_BME280 bme; BH1750 lightMeter;const byte rainPin =A0;byte sensorsCode =1;/** * voltage level that will pun the microcontroller in deep sleep instead of regular sleep */int voltageDeepSleepThreshold =4200; const byte peripherialsPowerPin =6;char buffer[] ={' ',' ',' ',' ',' ',' ',' '};struct sensorData { byte humidity; int temperature; byte rain; int pressure; long voltage; int light; };sensorData sensors;void setup() { Serial.begin(9600); serialComm.begin(9600); pinMode(peripherialsPowerPin, OUTPUT); digitalWrite(peripherialsPowerPin, HIGH); Verzögerung (500); if (!bme.begin()) { Serial.println("Could not find a valid BME280 sensor, check wiring!"); while (1) { customSleep(100); } } Serial.println("Initialization finished succesfully"); delay(50); digitalWrite(peripherialsPowerPin, HIGH);}void loop() { updateSenzors(); transmitData(); customSleep(75); }void updateSenzors() { bme.begin(); lightMeter.begin(); Verzögerung (300); sensors.temperature =bme.readTemperature(); sensors.pressure =bme.readPressure() / 100.0F; sensors.humidity =bme.readHumidity(); sensors.light =lightMeter.readLightLevel(); sensors.voltage =readVcc(); sensors.rain =readRain();}void transmitData(){ emptyIncommingSerialBuffer(); Serial.print("Temp:");Serial.println(sensors.temperature); Serial.print("Humid:");Serial.println(sensors.humidity); Serial.print("Pressure:");Serial.println(sensors.pressure); Serial.print("Light:");Serial.println(sensors.light); Serial.print("Voltage:");Serial.println(sensors.voltage); Serial.print("Rain:");Serial.println(sensors.rain); transmitSenzorData("T", sensors.temperature); transmitSenzorData("H", sensors.humidity); transmitSenzorData("PS", sensors.pressure); transmitSenzorData("L", sensors.light); transmitSenzorData("V", sensors.voltage); transmitSenzorData("R", sensors.rain);}void emptyIncommingSerialBuffer(){ while (serialComm.available()> 0) { serialComm.read(); Verzögerung(5); }}void transmitSenzorData(String type, int value){ serialComm.print(type); serialComm.print(sensorsCode); serialComm.print(":"); serialComm.print(value); serialComm.print("|"); delay(50);}void customSleep(long eightSecondCycles){ if (sensors.voltage> voltageDeepSleepThreshold) { delay(eightSecondCycles * 8000); Rückkehr; } digitalWrite(peripherialsPowerPin, LOW); for (int i =0; i
Code-Snippet #5Klartext
cd weather-predict # create anaconda environment named "weather" with python 3.6.2conda create --name weather python=3.6.2 # activate environmentconda activate weather# install all packages pip install -r requirements.txt 
Code snippet #6Plain text
mongodb ={ 'host':'localhost', 'port':27017}...
Code snippet #10Plain text
conda activate weatherpython serial_listener.py# every 10 minutes you should see data from the weather station coming in :[Sensor:type(temperature), value(14.3)][Sensor:type(pressure), value(1056.0)]...
Code snippet #15Plain text
{ "_id" :"04_27_2017_06_17", "humidity" :65, "date" :ISODate("2017-04-27T06:17:18Z"), "pressure" :1007, "temperature" :9, "rain" :0, "light" :15}
Code snippet #16Plain text
client =MongoClient(host, port).weather.datapoints cursor =client.find( {'$and' :[ {'date' :{'$gte' :start_date}}, {'date' :{'$lte' :end_date}} ]} )data =list(cursor)..
Code snippet #18Plain text
_id date humidity light pressure rain temperature 04_27_2017_03_08 2017-04-27 03:08:36 67.0 0.0 1007.0 0.0 11.004_27_2017_03_19 2017-04-27 03:19:05 66.0 0.0 1007.0 0.0 11.004_27_2017_03_29 2017-04-27 03:29:34 66.0 0.0 1007.0 0.0 11.0 
Code snippet #22Plain text
_id has_rain humidity_10percentile humidity_30percentile humidity_70percentile humidity_90percentile ... temperature_steady_4 temperature_steady_5 temperature_steady_6 temperature_steady_7 temperature_steady_8 ... 04_27_2017_3 0 36.0 44.8 61.0 63.0 ... NaN NaN NaN NaN NaN04_28_2017_0 0 68.0 70.0 74.0 75.0 ... 14.0 NaN NaN NaN NaN04_28_2017_1 0 40.0 45.0 63.2 69.0 ... 20.0 14.0 NaN NaN NaN04_28_2017_2 0 34.0 35.9 40.0 41.0 ... 29.0 20.0 14.0 NaN NaN04_28_2017_3 0 36.1 40.6 52.0 54.0 ... 19.0 29.0 20.0 14.0 NaN04_29_2017_0 0 52.0 54.0 56.0 58.0 ... 26.0 19.0 29.0 20.0 14.004_29_2017_1 0 39.4 43.2 54.6 57.0 ... 18.0 26.0 19.0 29.0 20.004_29_2017_2 1 41.0 42.0 44.2 47.0 ... 28.0 18.0 26.0 19.0 29.0 
Code snippet #23Plain text
from sklearn.model_selection import train_test_split ...main_data, test_data =train_test_split(dataframe, test_size=percent_test_data) ...
Code snippet #25Plain text
from sklearn.preprocessing import StandardScalerfrom sklearn.externals import joblib..scaler =StandardScaler()X =scaler.fit_transform(X) ...# of course we should be careful to save the scaled model for later reusejoblib.dump(scaler, 'model_file_name.save') 
Code snippet #26Plain text
from keras.models import Sequentialfrom keras.layers import Densefrom keras.layers import Dropout ...input_dimensions =X.shape[1] optimizer ='rmsprop'dropout =0.05model =Sequential()inner_nodes =int(input_dimensions / 2)model.add(Dense(inner_nodes, kernel_initializer='uniform', activation='relu', input_dim=input_dimensions))model.add(Dropout(rate=dropout))model.add(Dense(inner_nodes, kernel_initializer='uniform', activation='relu'))model.add(Dropout(rate=dropout))model.add(Dense(1, kernel_initializer='uniform', activation='sigmoid'))model.compile(optimizer=optimizer, loss='mean_absolute_error', metrics=['accuracy']) model.fit(X, y, batch_size=1, epochs=50)...# save the model for later useclassifier.save('file_model_name')
Github
https://github.com/claws/BH1750https://github.com/claws/BH1750
Github
https://github.com/rocketscream/Low-Powerhttps://github.com/rocketscream/Low-Power
Github
https://github.com/adafruit/Adafruit_Sensorhttps://github.com/adafruit/Adafruit_Sensor
Github
https://github.com/adafruit/Adafruit_BME280_Libraryhttps://github.com/adafruit/Adafruit_BME280_Library
Github
https://github.com/danionescu0/home-automationhttps://github.com/danionescu0/home-automation

Schaltpläne

sketch_KAtDa2VReF.fzz
Weather station arduino sketch
https://github.com/danionescu0/home-automation/tree/master/arduino-sketches/weatherStation

Herstellungsprozess

  1. Python- und Raspberry Pi-Temperatursensor
  2. DIY Photoshop-Bearbeitungskonsole mit Arduino Nano RP 2040
  3. Python-Datei und -Verzeichnis mit os.rename() umbenennen
  4. Anwesenheitssystem mit Arduino und RFID mit Python
  5. Universelle Fernbedienung mit Arduino, 1Sheeld und Android
  6. DIY-Voltmeter mit Arduino und Smartphone
  7. DIY Infrarot-Herzschlagsensor mit Arduino
  8. Frequenz- und Duty-Cycle-Messung mit Arduino
  9. DIY Voltmeter mit Arduino und einem Nokia 5110 Display
  10. Sonar mit Arduino und Anzeige bei der Verarbeitung von IDE