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

ArduFarmBot - Teil 2:Remote-Station und IoT-Implementierung

Komponenten und Verbrauchsmaterialien

Arduino Nano R3
× 1
Espressif ESP8266 ESP-01
× 1
DHT22-Temperatursensor
× 1
ky18
× 1
Hydrometer
× 1
Relais (generisch)
× 2
LCD 4X20
× 1
SparkFun Drucktastenschalter 12 mm
× 3
LED (generisch)
× 3

Apps und Onlinedienste

ThingSpeak API

Über dieses Projekt

Dieses Tutorial ist eine Fortsetzung von ArduFarmBot:Steuerung einer Tomaten-Home-Farm mit Arduino und IoT

Im ersten Teil erstellen wir eine lokale Kontrollstation, die Informationen von einer Tomatenplantage wie Temperatur, relative Luftfeuchtigkeit, Helligkeit und Bodenfeuchtigkeit erfasst. Basierend auf diesen Daten entschied der ArduFarmBot automatisch, wie viel (und wann) die Plantage Wärme und Wasser erhalten sollte. Die auf dem Teil 1 entwickelte Ortsstation ermöglichte auch das manuelle Eingreifen eines Bedieners, um die Wasserpumpe und die elektrische Lampe zu steuern. In diesem Teil 2 werden wir einen IoT-Ansatz implementieren, bei dem dieser „manuelle Eingriff“ auch aus der Ferne über das Internet möglich ist. Das Blockschaltbild zeigt, wie wir dies tun.

Beachten Sie, dass die erfassten Daten an einen „Cloud-Speicherdienst“ (in unserem Fall Thinkspeak.com) gesendet werden. Auch eine eigene Website, die "Remote Control Page", überwacht und zeigt diese Daten fast in Echtzeit an. Diese Webseite ermöglicht auch die Fernaktivierung der Pumpe und der Lampe.

Schritt 1:Stückliste

  • Arduino Nano - (7,50 $)
  • Temperatur- und Feuchtigkeitssensor DHT22 oder DHT11 - ($3,66)
  • Helligkeitssensor - AD-018 Fotowiderstandsmodul. oder ein Äquivalent - (0,71 $)
  • 2X Bodenfeuchtigkeitssensor - (1,99 $) (Optional, kann DIY sein)
  • LCD I2C 20X4 ($ 13,99)
  • LEDs (1X) (0,20 $)
  • Esp8266 Serielles Wifi-Wireless-Transceiver-Modul Esp-01 - (5,96 USD)
  • Aktiver Summer - Ky-12 oder gleichwertig (0,60 $)
  • 2 X 5V Relaismodul (11,60 $)
  • Sprungdrähte (S1.00)
  • 10KOhms Widerstand - ($0,03)
  • 2,2 K Ohm Widerstand - (0,03 $)
  • 1.0K Ohm Widerstand - ($0,03)
  • 220 Ohm Widerstand - ($0,03)
  • Arduino Nano Shield ("Funduino") - (7,28 $)
  • Membran-Tastatur (4 Tasten) - (6,65 $)
  • Kunststoffbox

Schritt 2:Fertigstellen der Hardware

Ausgehend von der in Teil 1 entwickelten Local Station ist die einzige zusätzliche benötigte HW der ESP8266. Das obige Blockdiagramm zeigt alle Arduino- und Hauptkomponenten-PIN-Verbindungen. Die einzige Sorgfalt, die Sie haben müssen, bezieht sich auf den Spannungspegel. Der ESP8266 arbeitet mit 3.3V, also dem Rx Pin, der nicht direkt mit Nano Tx Pin (D3) verbunden werden sollte. Es sollte ein Spannungspegel verwendet werden. In unserem Fall bauen wir einen Spannungsteiler, der als Spannungspegelwandler verwendet wird. Die obigen Diagramme zeigen detaillierter, wie der ESP8266 angeschlossen wird. Wenn Sie mehr über den ESP8266 erfahren möchten, lesen Sie bitte meine Tutorials:

  • Der ESP8266 Teil 3 - Arduino-LEDs aus der Ferne auslösen
  • Das ESP8266 Teil 1 - Serielles WIFI-Modul für Arduino
  • Der ESP8266 Teil 2 - Arduino-Webserver

Beachten Sie, dass wir den ESP8266 verwenden, der mit Nano Pin 2 (Tx) und Pin 3 (Rx) verbunden ist und die Bibliothek SoftSerial verwendet. Wenn Sie diese digitalen Pins "freigeben" möchten, können Sie alternativ die Nano Serial Pins 0 und 1 verwenden. Denken Sie nur daran, dass Sie diese beim Hochladen des Codes auf Nano trennen müssen.

HINWEIS:Wenn Sie den SUMMER anschließen möchten, sollten Sie dies an Pin D17 tun (wie an Pin A3). Es ist gut, einen Ton zu hören, wenn ein Kommunikationsfehler auftritt. Ich habe es während der Testphase verwendet und beim Abschlussprojekt weggelassen (die HW, aber der Code ist dafür vorbereitet). Es liegt an Ihnen, ob Sie es haben oder nicht.

Sie können den folgenden Code zum Testen und/oder Einrichten Ihres ESP8266 verwenden:

FC9DBPKIT682FY7.ino

Schritt 3:Die ESP8266-Verbindung

Um den ArduFarmBot mit dem Internet zu verbinden, verwenden wir den ESP8266, ein einfaches, kostengünstiges und leicht zu programmierendes Modul für IoT-Projekte. Sobald das Modul installiert ist, müssen Sie als erstes einen "Reset" auf seinen CH-PD-Pin anwenden.

/******************************************** ********* Reset-Funktion zum Akzeptieren der Kommunikation************************************ ****************/void reset8266 (void) {pinMode (CH_PD, OUTPUT); digitalWrite (CH_PD, LOW); Verzögerung (300); digitalWrite (CH_PD, HIGH); Serial.print ("8266 zurücksetzen OK"); lcd.clear(); lcd.println("8266 zurücksetzen OK");}  

Nach dem Zurücksetzen verbinden wir es mit Ihren Zugangsdaten (im Code ändern:USERNAME und PASSWORD) mit Ihrem lokalen Netzwerk und starten das Modul als "STA:Station Mode" (CWMODE =1):

/******************************************** ********* WLAN verbinden**************************************** *************/void connectWiFi(void){ sendData("AT+RST\r\n", 2000, DEBUG); // sendData zurücksetzen("AT+CWJAP=\"USERNAME\",\"PASSWORD\"\r\n", 2000, DEBUG); // Netzwerkverzögerung verbinden (3000); sendData("AT+CWMODE=1\r\n", 1000, DEBUG); sendData("AT+CIFSR\r\n", 1000, DEBUG); // IP-Adresse anzeigen lcd.clear(); lcd.print("8266 verbunden"); Serial.println("8266 Verbunden");} 

Um Daten an ESP8266 zu senden, die Funktion sendData() wurde verwendet:

/******************************************** ********* AT-Befehle an Modul senden************************************ ****************/String sendData (String-Befehl, const int timeout, boolesches Debug) { String response =""; esp8266.print (Befehl); lange int-Zeit =millis(); while ((time + timeout)> millis()) { while (esp8266.available()) {// Das esp hat Daten, also zeige seine Ausgabe im seriellen Fenster an char c =esp8266.read(); // Lesen Sie das nächste Zeichen. Antwort +=c; }} Wenn (Debug) {Serial.print (Antwort); } Antwort zurückgeben;} 

Die oben genannten Funktionen werden während der "Setup-Phase" unseres Codes aufgerufen. Wenn alles richtig gemacht wurde, sollten Sie bei Serial Monitor ähnliche Meldungen wie oben sehen.

Schritt 4:Cloud-Speicherdaten:ThinkSpeak.com

Alle vom ArduFarmBot erfassten Daten werden mit dem kostenlosen Service von "ThinkSpeak.com" in die Cloud hochgeladen.

Bei der Funktion "Loop()" (nachdem wir Daten mit readSensors() erfasst haben ), rufen wir eine spezielle Funktion auf, um die erfassten Daten hochzuladen:updateDataThingSpeak();

/******************************************** ********* Daten an thingspeak.com übertragen************************************ *****************/void updateDataThingSpeak (void) { startThingSpeakCmd (); cmd =Nachricht; cmd +="&field1="; // Feld 1 für DHT-Temperatur cmd +=tempDHT; cmd +="&field2="; // Feld 2 für DHT-Feuchtigkeit cmd +=humDHT; cmd +="&field3="; // Feld 3 für LDR-Leuchtkraft cmd +=Lumen; cmd +="&field4="; //Feld 4 für Bodenfeuchtigkeitsdaten cmd +=groundMoist; cmd +="&field5="; // Feld 5 für PUMP Status cmd +=pumpStatus; cmd +="&field6="; // Feld 6 für LAMP Status cmd +=Lampenstatus; cmd +="\r\n"; sendThingSpeakCmd();}  

Um diese Daten zu senden, müssen Sie zunächst die Kommunikation mit ThingSpeak starten. Wir tun dies mit der Funktion:startThingSpeakCmd();

/******************************************** ********* Kommunikation mit ThingSpeak.com starten************************************ *****************/void startThingSpeakCmd(void){ cmd ="AT+CIPSTART=\"TCP\",\""; cmd +=IP; cmd +=" ",80"; esp8266.println(cmd); Verzögerung (2000); if(esp8266.find("Fehler")) {Serial.println("ESP8266 STARTFEHLER"); Rückkehr; } Serial.println ("Thinkspeak Comm gestartet"); cmd ="";} 

Sobald der Kanal mit ThingSpeak geöffnet ist und die "cmd"-Zeichenfolge mit den Daten zusammengestellt ist, ist es an der Zeit, alles mit der Funktion sendThingSpeakCmd(); . auf den entsprechenden Kanal bei ThingSpeak hochzuladen

/******************************************** ******** * Kanal aktualisieren ThingSpeak.com************************************ ****************/String sendThingSpeakCmd(void){ esp8266.print("AT+CIPSEND="); esp8266.println(cmd.length()); if (esp8266.find(">")) {esp8266.print (cmd); Serial.println(""); Serial.println(""); Serial.println (cmd); Verzögerung (500); String messageBody =""; while (esp8266.available()) { String line =esp8266.readStringUntil('\n'); if (line.length() ==1) { //der eigentliche Inhalt beginnt nach einer leeren Zeile (die Länge 1 hat) messageBody =esp8266.readStringUntil('\n'); Serial.print ( "Nachricht erhalten:"); Serial.println (messageBody); } } return messageBody; aufrechtzuerhalten. Else{ esp8266.println("AT+CIPCLOSE"); Serial.println ("ESP8266 CIPSEND-FEHLER:ERNEUT SENDEN"); //Erneut senden... error=1; "Fehler" zurückgeben; }} 

Die oben genannten Funktionen basieren auf einem großartigen und detaillierten Tutorial, das von Michalis Vasilakis entwickelt wurde. Weitere Informationen finden Sie in seinem Tutorial:Arduino IOT:Temperature and Humidity (with ESP8266 WiFi).

Das Foto zeigt den ArduFarmBot-Kanal auf ThingSpeak.com.

Schritt 5:Befehlen der Aktoren aus dem Web

In diesem Moment laden wir alle gesammelten Daten hoch und speichern sie in der Cloud. Das ist sehr gut und nützlich für eine Fernüberwachung, aber was passiert, wenn wir auf Grundlage dieser Daten auch die Pumpe oder die Lampe einschalten wollen, unabhängig vom lokalen Automatikprogramm? Dazu müssen wir auch Daten aus der Cloud "herunterladen" und dem Controller befehlen, basierend auf diesen Befehlen zu handeln.

Wir werden in unserem ThinkSpeak-Kanal spezifische Felder erstellen, um die Aktoren zu befehlen:

Feld 7:

  • Daten =1 ==> PUMPE sollte eingeschaltet sein
  • Daten =0 ==> PUMP sollte AUS sein

Feld 8:

  • Daten =1 ==> LAMP sollte eingeschaltet sein
  • Daten =0 ==> LAMP sollte ausgeschaltet sein

OK, aber wie richtet man diese Felder direkt bei ThingSpeak ein? Wir können dies beispielsweise tun, indem wir direkt bei ThinksPeak ein "PlugIn" schreiben, oder wir können eine externe Website verwenden, um dies zu tun (dies ist unsere Wahl). Wie auch immer, in beiden Fällen sollten Sie einen Befehl wie den folgenden verwenden:

api.thingspeak.com/update?key=YOUR_WRITE_KEY&field7=1 

Mit dem obigen Befehl zum Beispiel (und mit Ihrem Kanal Write Key) schreiben Sie "1" in Feld 7, was bedeutet, dass die PUMP eingeschaltet sein sollte. Sie können es einfach testen, indem Sie die obige Befehlszeile in Ihrem Browser eingeben, das entsprechende Feld in Ihrem Kanal wird geändert. Als Gegenleistung zeigt der Browser eine weiße Seite mit einer einzelnen Zahl in der oberen linken Ecke an, die der sequentiellen Dateneingabe in deinem Kanal entspricht.

50% der Arbeit ist getan, jetzt müssen Sie diesen "Befehl" (Daten auf dem Feld) lesen, unten an der lokalen ArduFarmBot-Station.

Der Befehl dazu wird unten angezeigt. Es werden die letzten Daten abgerufen, die in das spezifische Feld geschrieben wurden (das ist in unserem Fall ein "Befehl".

api.thingspeak.com/channels/CHANNEL_ID/fields/7/last 

Auf die gleiche Weise wie zuvor können Sie die Befehlszeile mit Ihrem Webbrowser testen. In diesem Fall zeigt Ihnen der Browser die Daten zu diesem spezifischen Feld an. Siehe das Foto oben.

Kehren wir zu "Erde" zurück, schreiben wir eine Funktion, die dieses "letzte Feld" liest:

/******************************************** ******** Daten aus field7 von thingspeak.com lesen************************************ ******************/int readLastDataField7 () { startThingSpeakCmd (); // "GET /channels/CHANNEL_ID/fields/7/last"; cmd =msgReadLastDataField7; cmd +="\r\n"; String messageDown =sendThingSpeakCmd(); Serial.print ( "Befehl erhalten:"); Serial.println (messageDown[7]); int-Befehl =messageDown[7]-48; Befehl zurückgeben;} 

Die obige Funktion gibt die Daten in Feld 7 zurück ("1" oder "0"). Eine ähnliche Funktion sollte für Feld 8 geschrieben werden.

Sobald wir den Inhalt beider Felder haben, sollten wir sie für eine Funktion verwenden, die die Aktoren ähnlich wie bei der "manuellen Befehlsfunktion" befehligt:

/******************************************** ********* Befehle von thingSpeak.com empfangen************************************ *****************/void receiveCommands () { field7Data =readLastDataField7 (); if (field7Data ==1) { digitalWrite (PUMP_PIN, HIGH); Pumpenstatus =1; showDataLCD(); aufrechtzuerhalten. Wenn (field7Data ==0) { DigitalWrite (PUMP_PIN, LOW); Pumpenstatus =0; showDataLCD(); } Verzögerung (500); field8Data =readLastDataField8(); if (field8Data ==1) { digitalWrite (LAMP_PIN, HIGH); Lampenstatus =1; showDataLCD(); aufrechtzuerhalten. Wenn (field8Data ==0) { DigitalWrite (LAMP_PIN, LOW); Lampenstatus =0; showDataLCD(); } Verzögerung (500); } 

Von nun an können Sie die Befehlszeile in Ihrem Browser verwenden, um die Pumpe und die Lampe aus der Ferne ein- und auszuschalten. Das obige Foto zeigt, wie der empfangene Befehl auf Ihrem seriellen Monitor angezeigt wird.

Eine weitere wichtige Überlegung ist die "Koordination" zwischen lokalem und entferntem Befehl. Wir müssen die readLocalCmd()-Funktion ändern um auch Thinkspeak Field 7 bzw. 8 mit Pumpen- und Lampenstatus zu aktualisieren (auf ihrer entsprechenden "IF-Anweisung". Den vollständigen Code finden Sie am Ende dieses Tutorials):

field7Data =pumpStatus;field8Data =lampStatus; 

Jetzt sind "filed7Data" und "field8Data" synchron mit den Webseitenbefehlen und auch mit lokalen Befehlsaktionen, wenn Sie eine Taste drücken. Aktualisieren wir also aplyCmd() Funktion, die für das Ein- und Ausschalten der Aktoren verantwortlich ist:

/******************************************** ********* Befehle empfangen und auf Aktoren wirken************************************ *****************/void aplyCmd () { if (field7Data ==1) digitalWrite (PUMP_PIN, HIGH); if (field7Data ==0) digitalWrite(PUMP_PIN, LOW); if (field8Data ==1) digitalWrite (LAMP_PIN, HIGH); if (field8Data ==0) digitalWrite(LAMP_PIN, LOW);} 

Wenn Sie Ihre Tests starten, werden Sie feststellen, dass alle Befehle, die Sie manuell lokal oder über das Web ausführen, von den automatischen Aktionen überwunden werden, die durch die Funktion autoControlPlantation() defined definiert sind ; An dieser Stelle sollten Sie sich überlegen, wer der "Chef" sein wird, der das letzte Wort hat! In unserem Fall werden wir hier Folgendes definieren:

  • Bei jedem Schleifenzyklus, also fast "immer", schauen wir, ob eine Taste gedrückt wird
  • Ungefähr jede Minute sollten wir bei ThingSpeak ein "Pooling" durchführen und sehen, ob wir von dort eine Bestellung erhalten haben.
  • Ungefähr alle 10 Minuten werden wir die Sensoren auslesen, die Daten auf ThingSpeak aktualisieren und vor allem die automatischen Maßnahmen ergreifen. Diese Aktionen werden unabhängig davon durchgeführt, was manuell ausgewählt wurde, und werden beibehalten.

Sie können es ändern, wie Sie möchten. Das ist das Gute daran, einen programmierbaren Prozessor zum Steuern von Dingen zu verwenden!

Daher werden jetzt 2 Timer verwendet, einer zum Bündeln der Fernbedienungsbefehle und einer zum Lesen der Sensoren (derselbe, den wir zuvor verwendet haben:

long sampleTimingSeconds =75; // ==> ******** Definiere die Abtastzeit in Sekunden zum Lesen von Sensoren *********int reverseElapsedTimeSeconds =0;long startTiming =0;long elapsedTime =0;long poolingRemoteCmdSeconds =20; // ==> ******** Pooling-Zeit in Sekunden für neue ThingSpeak-Befehle definieren *********long startRemoteCmdTiming =0; long elapsedRemoteCmdTime =0; 

Also die Schleife() Funktion sollte nun wie folgt umgeschrieben werden:

void loop() { elapsedRemoteCmdTime =millis()-startRemoteCmdTiming; // Timer zum Poolen von Remote-Befehlen starten elapsedTime =millis()-startTiming; // Timer für Messungen starten reverseElapsedTimeSeconds =round (sampleTimingSeconds - elapsedTime/1000); readLocalCmd(); // Lokalen Schaltflächenstatus lesen showDataLCD (); if (elapsedRemoteCmdTime> (poolingRemoteCmdSeconds*1000)) { ReceiveCommands(); updateDataThingSpeak(); startRemoteCmdTiming =millis(); aufrechtzuerhalten. Wenn (elapsedTime> (sampleTimingSeconds*1000)) {readSensors(); autoControlPlantation(); updateDataThingSpeak(); startTiming =millis(); }} 

Schritt 6:Implementieren einer dedizierten Webseite

An diesem Punkt ist unser ArduFarmBot betriebsbereit und kann über das Internet gesteuert werden. Sie können die Daten auf der Thinkspeak-Site überwachen und auch Befehle mit einem Browser senden, aber diese "Weblösung" kann natürlich nicht als "elegant" angesehen werden! Der beste Weg, um eine vollständige IoT-Lösung zu implementieren, besteht darin, eine vollständige Webseite zu entwickeln, die alle Daten anzeigt und auch Schaltflächen zum Aktivieren der Aktoren enthält.

Ich wähle den Byethost, einen kostenlosen Webhost, sehr einfach und einfach, um Ihre Seiten zu verwalten. Ich habe auch die Gelegenheit genutzt, mich für dieses Projekt zu bewerben, was ich in einer fantastischen Online-Spezialisierung an Coursera/Universität Michigan gelernt habe:Lernen Sie, Websites zu entwerfen und zu erstellen (Erstellen eines reaktionsschnellen und zugänglichen Webportfolios mit HTML5, CSS3 und JavaScript ).

Ich werde nicht näher darauf eingehen, wie eine solche Seite entwickelt wird, da dies nicht der Hauptzweck dieses Tutorials ist, aber ich werde hier die HTML-, CSS- und JavaScript-Quellcodes einfügen. Und sobald jemand Interesse daran hat, wie ich zu den Ergebnissen gekommen bin, können wir es am Ende des Projekts über die Kommentartafel beiseite diskutieren.

Es ist wichtig zu betonen, dass diese Seite nicht direkt mit der ArduFarmBot Local Control Station funktioniert. Was es wirklich tut, ist die Interaktion mit dem ThinkSpeak-Kanal wie folgt:

  • Sensordaten zu den Feldern 1, 2, 3, 4 lesen
  • Aktuatorstatus in den Feldern 5 und 6 lesen
  • Daten in die Felder 7 und 8 schreiben
  • Lokale Wetterdaten von Yahoo-Diensten lesen

Der obige Punkt 4 ist für das Projekt nicht wirklich entscheidend, aber es stehen immer zusätzliche Daten zur Verfügung, falls Sie unabhängig von den lokalen Vorgängen auf Ihrer Tomatenplantage einige Remote-Aktionen durchführen möchten. Eine andere Überlegung ist, dass Sie diese Daten zum Beispiel auf einem anderen ThingSpeak-Kanal speichern und auf Ihr Arduino herunterladen können, um Wetterdaten auf einem lokalen LCD-Display anzuzeigen (ich habe dies in einem anderen coolen Projekt entwickelt, das gut funktioniert hat! Ich lasse es hier als Vorschlag für du).

FQOK9ENIT653YX5.zip

Schritt 7:Zurück zum Gehirn. Ein Sensor-Aktor-Matrix-Ansatz:

Im ersten Teil dieses Projekts haben wir einige Vorüberlegungen definiert, wie sich die Aktoren in Abhängigkeit vom Messwert der Sensoren verhalten sollen. Wir haben nur eine einfache Wahl getroffen, aber was passiert, wenn wir eine komplexere Situation haben? Mehrere unterschiedliche Bedingungen? Was wir entwickeln werden, ist ein „Sensor-Aktor-Matrix-Ansatz“.

Auf einer Matrix wurden für jeden Sensor sein Zustand und die Ausgabe der Aktoren definiert. Das Ergebnis ist in der unten beigefügten Excel-Tabelle zu sehen. In der Excel-Datei befinden sich zwei Tabellenkalkulationen. In der Tabelle mit einem Filter und einer Version können Sie mehrere Sensorbedingungen auswählen und sehen, wie die Aktoren aufgrund dieser Auswahl funktionieren.

Sobald die Matrix definiert ist, müssen wir sie in unseren Code übersetzen. Ein Array aus 18 Zeilen und 10 Spalten wurde erstellt, um die Bedingungen der Sensor-Aktor-Matrix zu "kopieren":

 // +---BODEN----+-LIGHT-+---TEMP---+---ACTUAT----+ // SL SM SH LL LH TL TM TH Pumpe Lampboolesches SDf [18] [10] ={{ 1, 0, 0, 0, 1, 0, 0, 1, 1, 0 }, { 1, 0, 0, 0, 1, 0, 1, 0, 1 , 0 }, { 1, 0, 0, 0, 1, 1, 0, 0, 1, 1 }, { 1, 0, 0, 1, 0, 0, 0, 1, 1, 0 }, { 1 , 0, 0, 1, 0, 0, 1, 0, 1, 0 }, { 1, 0, 0, 1, 0, 1, 0, 0, 0, 1 }, { 0, 1, 0, 0 , 1, 0, 0, 1, 0, 0 }, { 0, 1, 0, 0, 1, 0, 1, 0, 0, 0 }, { 0, 1, 0, 0, 1, 1, 0 , 0, 0, 1 }, { 0, 1, 0, 1, 0, 0, 0, 1, 0, 0 }, { 0, 1, 0, 1, 0, 0, 1, 0, 0, 1 }, { 0, 1, 0, 1, 0, 1, 0, 0, 0, 1 }, { 0, 0, 1, 0, 1, 0, 0, 1, 0, 0 }, { 0, 0 , 1, 0, 1, 0, 1, 0, 0, 0 }, { 0, 0, 1, 0, 1, 1, 0, 0, 0, 1 }, { 0, 0, 1, 1, 0 , 0, 0, 1, 0, 0 }, { 0, 0, 1, 1, 0, 0, 1, 0, 0, 1 }, { 0, 0, 1, 1, 0, 1, 0, 0 , 0, 1 }, }; 

Um mit der Matrix zu arbeiten, erstellen wir eine Funktion defSensorStatus() . Diese Funktion testet für jede Zeile, ob die Bedingung der ersten 8 Spalten WAHR ist. Wenn ja, wird die Bedingung der letzten 2 Spalten ausgeführt.

Zum Beispiel:

if (1 und 0 und 0 und 0 und 1 und 0 und 0 und 1) { pumpStatus =1; LampenStatus =0} Sonst wenn (1 und 0 und 0 und 0 und 1 und 0 und 1 und 0) { pumpStatus =1; Lampenstatus =0} 

und so weiter.

Innerhalb der obigen Funktion wird ein weiteres Array mit dem Status jedes Sensormesswertes erstellt:

boolean snsSts[8]={0, 0, 0, 0, 0, 0, 0, 0}; // SL, SM, SH, LL, LH, TL, TM, TH 

Dieses Variablenarray wird auch für das LOG-Register verwendet.

F2HWXBYITA8WIN1.xlsx

Schritt 8:Codeoptimierung

Während des Entwicklungsprozesses des ArduFarmBot stellen wir fest, dass einige Änderungen an der ursprünglichen Spezifikation vorgenommen werden sollten:

Anzeige:

Das LCD-Display sollte standardmäßig ausgeschaltet sein und jedes Mal, wenn ein Sensormesswert benötigt wird, können wir es manuell auf „ON“ schalten. Diese Bedingung wurde im Code implementiert und die Schaltfläche "Sensors Read" sollte wie im "Toggle"-Modus verwendet werden, um das LCD jederzeit ein- und auszuschalten. Durch Ein- oder Ausschalten des Displays werden die Sensormesswerte für die Anzeige aktualisiert, aber nicht von ArduFarmBot für seine regulären Funktionen verwendet.

Ersteinrichtung:

Wenn der ArduFarmBot eingeschaltet (oder zurückgesetzt) ​​wird, zeigt das LCD die "Initial Setup" an. Um das Programm zu starten, muss die Schaltfläche "Sensoren" gedrückt werden. Die angezeigten Anfangsinformationen (siehe obiges Foto) sind:

  • COLD Temperatur (d. h. 12 °C)
  • TROCKENE Bodenfeuchtigkeit (d. h. 30%)
  • NASS-Bodenfeuchtigkeit (d. h. 60%)
  • DUNKLES Licht (d. h. 40%)
  • P_ON Pumpenzeit EIN sein (d. h. 10s)
  • SCAN Zeit zum Auslesen der Sensoren (d. h. 600s)
  • SW_Version (d. h. 4.1)

Protokolldatensatz:

Zu Auditzwecken haben wir ein LOG mit den Messwerten und Betätigungen unseres ArduFarmBot erstellt. Bei jedem Lesezyklus die Funktion:storeDataLogEEPROM() ausgeführt wird.

/******************************************** ********* Speicherung von Logdaten im Arduino EEPROM************************************ ******************/void storeDataLogEEPROM(void){ for (int i =0; i<8; i++) { logData =logData + (snsSts[i])<<1; } EEPROM.write (memoAddr, logData); memoAddr++; logDaten =0; logData =logData + Pumpenstatus; logData =logData <<1; logData =logData + Lampenstatus; EEPROM.write (memoAddr, logData); EEPROM.write (0, memoAddr+1); logDaten =0; if ((MemoAddr+1) ==1023) MemoAddr=1; sonst memoAddr++;}  

Wie im letzten Schritt kommentiert, wird im Arduino EEPROM der Inhalt gespeichert, etwas aus dem Array snsSts[] plus Pumpen- und Lampenstatus. Oben sehen Sie das LOG auf Serial Monitor.

Der gesamte ArduFarmBot-Code wurde in verschiedene Dateien aufgeteilt, um das Verständnis zu erleichtern. Beachten Sie, dass in diesem zweiten Teil 2 neue Dateien hinzugefügt wurden:

  • communication.ino (ThingSpeak- und ESP8266-spezifische Funktionen)
  • stationCredentials.h (ThingSpeak-Kanal-ID und spezifische Tasten zum Schreiben auf dem Kanal)

Zu guter Letzt, sobald der Code mit einer angemessenen Größe endete, entschieden wir uns, die konstanten Daten im Flash-(Programm-)Speicher statt im SRAM zu speichern. Dazu verwenden wir das Schlüsselwort PROGMEM, das ein variabler Modifikator ist. Anstatt beispielsweise zu verwenden:

#define DHTPIN 5 

Wir haben verwendet:

const PROGMEM Byte DHTPIN =5; 

Das Schlüsselwort PROGMEN weist den Compiler an, diese Informationen in den Flash-Speicher zu legen, anstatt in den SRAM, wo sie normalerweise abgelegt würden. Sie müssen auch die Bibliothek avr/pgmspace.h in die Hauptdatei Ihres Codes einschließen.

Ein weiteres gutes Verfahren zur Reduzierung der SRAM-Nutzung ist das Kommentieren (oder Löschen) aller Serial.Print()-Zeilen, die Sie während der Entwicklung zum Debuggen verwendet haben. Sie werden feststellen, dass der Code, der beispielsweise verwendet wird, um das LOG auf dem Serial Monitor anzuzeigen, in den folgenden Dateien kommentiert wird.

Unten finden Sie den vollständigen ArduFarmBot Arduino-Code. Vergessen Sie nicht, die Dummy-Daten auf Credentials.h mit Ihrer Kanal-ID und Ihrem Schreibschlüssel zu ändern. Verwenden Sie auch auf communication.ino Ihren echten Benutzernamen und Ihr Passwort, um den ESP 8266 mit dem Internet zu verbinden.

FTUT5VIIT67U8ME.ino FWMIPSSIT67U8MG.ino FJPGZNKIT67U8MK.ino FQH3X9VIT67U8NA.ino F15MY4YIT67U8NB.ino FVU64X1IT67U8NC.h FZ057E3IT67U8P5.h

Schritt 9:Die MJRovai Home Farm

Die folgenden Fotos zeigen aufeinanderfolgende Fotos von ArduFarmBot, der meine erste Tomatenplantage kontrolliert.

Die folgende Fotosequenz zeigt meine zweite Plantagenentwicklung von der Samenplantage bis zur Auswahl der besten Pflanzen (ca. 45 Tage) und den Transplantationen der besten 6 Pflanzen.

Schritt 10:Fazit

Das war's Leute! ...Vorerst!

As always, I hope this project can help others find their way in the exciting world of electronics, IoT and Robotics!

Soon we probably will publish the third and last part of our project that I hope will be a very good recipe of a organic tomato sauce pasta.

By the way, on the above photo you can see the first sighs of life on Mauricio's plantation! And before you go, please give a look and the new ArduFarmBot, the book!, where I pack all project on a more friendly format:

ArduFarmBot, the Book!

"ArduFarmBot, the book" is also at Amazon.com! You can get it, by clicking hereThe book uses the electronic controller ArduFarmBot as a basis for teaching how to work in both HW and SW, with:

  • LCD and OLED type displays;
  • LEDs and buttons;
  • Activation of pumps and lamps via relays and
  • Sensors such as:DHT22 (temperature and relative air humidity), DS18B20 (soil temperature), YL69 (soil moisture) and LDR (luminosity).

All key stages of the project are documented in detail through explanatory texts, block diagrams, high-resolution color photos, electrical diagrams using Fritzing application, complete codes stored in GitHub and YouTube Videos.

Two versions of the electronic controller ArduFarmBot are developed in detail in the book. From capture of data coming from a garden, such as air and soil temperature, relative humidity, soil moisture and luminosity, the ArduFarmBot helps to control when a crop should receive heat and water. Control will happen automatically, locally and remotely via internet. The book is divided into 3 parts. In the first part, the Arduino Nano is the starting point for development of a local version of ArduFarmBot , that can be controlled both, manually and automatically.

In the second part, the book dives into automation design, introducing remote operation through the creation of a webpage. The ESP8266-01 is used for Wi-Fi connection, sending data to an important web service in the field of IoT, the ThingSpeak.com .

In the third part, a second version of ArduFarmBot is developed, introducing the NodeMCU ESP8266-12E , a powerful and versatile IoT device, which replaces both the Arduino Nano and the ESP8266-01 , used in the earlier parts of the book.

In this last part of the book, a new service platform of the IoT universe, the Blynk , is also explored.

Download the book, give it a review and please use the message board here to give us any comment, suggestion or critic!

For more projects, please visit my blog:MJRoBot.org

Saludos from the south of the world!

See you at my next project!

Thank you

Marcelo

Code

  • Code-Snippet Nr. 1
  • Code-Snippet 2
  • Code-Snippet #3
  • Code-Snippet Nr. 4
  • Code-Snippet Nr. 5
  • Code snippet #6
  • Code snippet #9
  • Code snippet #10
  • Code-Snippet #11
  • Code snippet #12
  • Code snippet #13
  • Code snippet #14
  • Code snippet #15
Code-Snippet Nr. 1Nur-Text
/**************************************************** Reset funtion to accept communication****************************************************/void reset8266(void){ pinMode(CH_PD, OUTPUT); digitalWrite(CH_PD, LOW); delay(300); digitalWrite(CH_PD, HIGH); Serial.print("8266 reset OK"); lcd.clear(); lcd.println("8266 reset OK ");}
Code-Snippet #2Klartext
/**************************************************** Connect WiFi****************************************************/void connectWiFi(void){ sendData("AT+RST\r\n", 2000, DEBUG); // reset sendData("AT+CWJAP=\"USERNAME\",\"PASSWORD\"\r\n", 2000, DEBUG); //Connect network delay(3000); sendData("AT+CWMODE=1\r\n", 1000, DEBUG); sendData("AT+CIFSR\r\n", 1000, DEBUG); // Show IP Adress lcd.clear(); lcd.print("8266 Connected"); Serial.println("8266 Connected");}
Code-Snippet #3Kurztext
/**************************************************** Send AT commands to module****************************************************/String sendData(String command, const int timeout, boolean debug){ String response =""; esp8266.print(command); long int time =millis(); while ( (time + timeout)> millis()) { while (esp8266.available()) { // The esp has data so display its output to the serial window char c =esp8266.read(); // read the next character. response +=c; } } if (debug) { Serial.print(response); } return response;}
Code-Snippet #4Nur-Text
/**************************************************** Transmit data to thingspeak.com****************************************************/void updateDataThingSpeak(void){ startThingSpeakCmd (); cmd =msg; cmd +="&field1="; //field 1 for DHT temperature cmd +=tempDHT; cmd +="&field2="; //field 2 for DHT humidity cmd +=humDHT; cmd +="&field3="; //field 3 for LDR luminosity cmd +=lumen; cmd +="&field4="; //field 4 for Soil Moisture data cmd +=soilMoist; cmd +="&field5="; //field 5 for PUMP Status cmd +=pumpStatus; cmd +="&field6="; //field 6 for LAMP Status cmd +=lampStatus; cmd +="\r\n"; sendThingSpeakCmd();}
Code-Snippet #5Klartext
/**************************************************** Start communication with ThingSpeak.com****************************************************/void startThingSpeakCmd(void){ cmd ="AT+CIPSTART=\"TCP\",\""; cmd +=IP; cmd +="\",80"; esp8266.println(cmd); Verzögerung (2000); if(esp8266.find("Error")) { Serial.println("ESP8266 START ERROR"); Rückkehr; } Serial.println("Thinkspeak Comm Started"); cmd ="";}
Code snippet #6Plain text
/*************************************************** * Update channel ThingSpeak.com****************************************************/String sendThingSpeakCmd(void){ esp8266.print("AT+CIPSEND="); esp8266.println(cmd.length()); if(esp8266.find(">")){ esp8266.print(cmd); Serial.println(""); Serial.println(""); Serial.println(cmd); Verzögerung (500); String messageBody =""; while (esp8266.available()) { String line =esp8266.readStringUntil('\n'); if (line.length() ==1) { //actual content starts after empty line (that has length 1) messageBody =esp8266.readStringUntil('\n'); Serial.print("Message received:"); Serial.println(messageBody); } } return messageBody; } else{ esp8266.println("AT+CIPCLOSE"); Serial.println("ESP8266 CIPSEND ERROR:RESENDING"); //Resend... error=1; return "error"; }}
Code snippet #9Plain text
/**************************************************** Read data from field7 of thingspeak.com****************************************************/int readLastDataField7(){ startThingSpeakCmd (); // "GET /channels/CHANNEL_ID/fields/7/last"; cmd =msgReadLastDataField7; cmd +="\r\n"; String messageDown =sendThingSpeakCmd(); Serial.print("Command received:"); Serial.println(messageDown[7]); int command =messageDown[7]-48; return command;}
Code snippet #10Plain text
/**************************************************** Receive Commands from thingSpeak.com****************************************************/void receiveCommands(){ field7Data =readLastDataField7(); if (field7Data ==1) { digitalWrite(PUMP_PIN, HIGH); pumpStatus =1; showDataLCD(); } if (field7Data ==0) { digitalWrite(PUMP_PIN, LOW); pumpStatus =0; showDataLCD(); } delay (500); field8Data =readLastDataField8(); if (field8Data ==1) { digitalWrite(LAMP_PIN, HIGH); lampStatus =1; showDataLCD(); } if (field8Data ==0) { digitalWrite(LAMP_PIN, LOW); lampStatus =0; showDataLCD(); } delay (500); }
Code-Snippet #11Kurztext
/**************************************************** Receive Commands and act on actuators****************************************************/void aplyCmd(){ if (field7Data ==1) digitalWrite(PUMP_PIN, HIGH); if (field7Data ==0) digitalWrite(PUMP_PIN, LOW); if (field8Data ==1) digitalWrite(LAMP_PIN, HIGH); if (field8Data ==0) digitalWrite(LAMP_PIN, LOW);}
Code snippet #12Plain text
long sampleTimingSeconds =75; // ==> ******** Define Sample time in seconds to read sensores *********int reverseElapsedTimeSeconds =0;long startTiming =0;long elapsedTime =0;long poolingRemoteCmdSeconds =20; // ==> ******** Define Pooling time in seconds for new ThingSpeak commands *********long startRemoteCmdTiming =0; long elapsedRemoteCmdTime =0;
Code snippet #13Plain text
void loop() { elapsedRemoteCmdTime =millis()-startRemoteCmdTiming; // Start timer for pooling remote commands elapsedTime =millis()-startTiming; // Start timer for measurements reverseElapsedTimeSeconds =round (sampleTimingSeconds - elapsedTime/1000); readLocalCmd(); //Read local button status showDataLCD(); if (elapsedRemoteCmdTime> (poolingRemoteCmdSeconds*1000)) { receiveCommands(); updateDataThingSpeak(); startRemoteCmdTiming =millis(); } if (elapsedTime> (sampleTimingSeconds*1000)) { readSensors(); autoControlPlantation(); updateDataThingSpeak(); startTiming =millis(); }}
Code snippet #14Plain text
 // +---SOIL----+-LIGHT-+---TEMP---+---ACTUAT----+ // SL SM SH LL LH TL TM TH Pump Lampboolean SDf [18] [10] ={{ 1, 0, 0, 0, 1, 0, 0, 1, 1, 0 }, { 1, 0, 0, 0, 1, 0, 1, 0, 1, 0 }, { 1, 0, 0, 0, 1, 1, 0, 0, 1, 1 }, { 1, 0, 0, 1, 0, 0, 0, 1, 1, 0 }, { 1, 0, 0, 1, 0, 0, 1, 0, 1, 0 }, { 1, 0, 0, 1, 0, 1, 0, 0, 0, 1 }, { 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 }, { 0, 1, 0, 0, 1, 0, 1, 0, 0, 0 }, { 0, 1, 0, 0, 1, 1, 0, 0, 0, 1 }, { 0, 1, 0, 1, 0, 0, 0, 1, 0, 0 }, { 0, 1, 0, 1, 0, 0, 1, 0, 0, 1 }, { 0, 1, 0, 1, 0, 1, 0, 0, 0, 1 }, { 0, 0, 1, 0, 1, 0, 0, 1, 0, 0 }, { 0, 0, 1, 0, 1, 0, 1, 0, 0, 0 }, { 0, 0, 1, 0, 1, 1, 0, 0, 0, 1 }, { 0, 0, 1, 1, 0, 0, 0, 1, 0, 0 }, { 0, 0, 1, 1, 0, 0, 1, 0, 0, 1 }, { 0, 0, 1, 1, 0, 1, 0, 0, 0, 1 }, };
Code snippet #15Plain text
/**************************************************** Storage of Log data at Arduino EEPROM****************************************************/void storeDataLogEEPROM(void){ for (int i =0; i<8; i++) { logData =logData + (snsSts[i])<<1; } EEPROM.write (memoAddr, logData); memoAddr++; logData =0; logData =logData + pumpStatus; logData =logData <<1; logData =logData + lampStatus; EEPROM.write (memoAddr, logData); EEPROM.write (0, memoAddr+1); logData =0; if ((memoAddr+1) ==1023) memoAddr=1; else memoAddr++;} 
ArduFarmBot GitHub
https://github.com/Mjrovai/ArduFarmBot

Schaltpläne

ardufarmbot_qpNcBDX6Jr.fzz

Herstellungsprozess

  1. IoT-Implementierungstrends
  2. 6-Shooter:Arduino-Getränkemischstation
  3. Multi-Temperatursensor
  4. MotionSense
  5. 3D-Drucker Brandschutz
  6. IoT-Messgerät mit Arduino, Yaler und IFTTT
  7. Arduino Repulsive Electromagnetic Levitation
  8. Greifer-Bot mit Fernbedienung
  9. Arduino-betriebener Wetterballon-Datenlogger
  10. CoroFence - Wärmedetektor🖖