Fabrication industrielle
Internet des objets industriel | Matériaux industriels | Entretien et réparation d'équipement | Programmation industrielle |
home  MfgRobots >> Fabrication industrielle >  >> Manufacturing Technology >> Processus de fabrication

ArduFarmBot - Partie 2 :Station distante et implémentation IoT

Composants et fournitures

Arduino Nano R3
× 1
Espressif ESP8266 ESP-01
× 1
Capteur de température DHT22
× 1
ky18
× 1
hydromètre
× 1
Relais (générique)
× 2
lcd 4X20
× 1
Interrupteur à bouton-poussoir SparkFun 12mm
× 3
LED (générique)
× 3

Applications et services en ligne

API ThingSpeak

À propos de ce projet

Ce didacticiel est une continuation d'ArduFarmBot : contrôler une ferme domestique de tomates à l'aide d'Arduino et de l'IoT

Dans la première partie, nous créons une station de contrôle locale, capturant les informations d'une plantation de tomates, telles que la température, l'humidité relative de l'air, la luminosité et l'humidité du sol. Sur la base de ces données, l'ArduFarmBot a décidé automatiquement la bonne quantité (et quand) la plantation devrait recevoir de la chaleur et de l'eau. La station locale développée sur la partie 1, permettait également l'intervention manuelle d'un opérateur afin de contrôler la pompe à eau et la lampe électrique. Sur cette partie 2, nous mettrons en place une approche IoT où cette « intervention manuelle » sera également possible à distance via Internet. Le schéma fonctionnel montre comment nous allons procéder.

Notez que les données capturées seront envoyées à un "service Cloud Storage" (dans notre cas Thinkspeak.com). Également un site Web dédié, la "Page de contrôle à distance" surveillera et affichera ces données en temps presque réel. Cette page Web permettra également l'activation à distance de la pompe et de la lampe.

Étape 1 :Nomenclature

  • Arduino Nano - (7,50 $)
  • Capteur de température et d'humidité DHT22 ou DHT11 - (3,66 $)
  • Capteur de luminosité - AD-018 Module photorésistance. ou tout équivalent - (0,71 $)
  • Capteur d'humidité du sol 2X - (1,99 $) (en option, peut être bricolé)
  • LCD I2C 20X4 (13,99 $)
  • LED (1X) (0,20 $)
  • Module émetteur-récepteur sans fil série Esp8266 Esp-01 - (5,96 $)
  • Sonnerie active - Ky-12 ou équivalent (0,60 $)
  • Module relais 2 X 5v (11,60 $)
  • Câbles de saut (S1.00)
  • Résistance 10KOhms - (0,03 $)
  • Résistance 2,2K Ohms - (0,03 $)
  • Résistance 1,0K Ohms - (0,03 $)
  • Résistance de 220 Ohms - (0,03 $)
  • Arduino Nano Shield ("Funduino") - (7,28 $)
  • Clavier à membrane (4 touches) - (6,65 $)
  • Boîte en plastique

Étape 2 :Compléter le matériel

À partir de la station locale développée sur la partie 1, le seul matériel supplémentaire nécessaire est l'ESP8266. Le schéma fonctionnel ci-dessus montre toutes les connexions PIN de l'Arduino et des composants principaux. Le seul soin que vous devez avoir est lié au niveau de tension. L'ESP8266 fonctionne avec 3.3V, donc la broche Rx qui ne doit pas être connectée directement à la broche Nano Tx (D3). Un niveau de tension doit être utilisé. Dans notre cas, nous allons construire un diviseur de tension à utiliser comme convertisseur de niveau de tension. Les schémas ci-dessus montrent plus en détail comment connecter l'ESP8266. Si vous souhaitez en savoir plus sur l'ESP8266, veuillez consulter mes tutoriels :

  • L'ESP8266 Partie 3 - Déclenchement des LED Arduino à distance
  • L'ESP8266 Partie 1 - Module WIFI série pour Arduino
  • L'ESP8266 Partie 2 - Serveur Web Arduino

Notez que nous utilisons l'ESP8266 connecté à Nano Pin 2 (Tx) et Pin 3 (Rx), en utilisant la bibliothèque SoftSerial. Si vous souhaitez "libérer" ces broches numériques, vous pouvez utiliser alternativement les broches Nano Serial 0 et 1. N'oubliez pas que vous devez les déconnecter lors du téléchargement du code sur Nano.

REMARQUE :Si vous souhaitez connecter le BUZZER, vous devez le faire à la broche D17 (identique à la broche A3). Il est bon d'avoir un son quand vous avez une erreur de communication. Je l'ai utilisé pendant la phase de test, en laissant de côté le projet final (le matériel, mais le code est préparé pour cela). C'est à vous de l'avoir ou non.

Vous pouvez utiliser le code ci-dessous pour tester et/ou configurer votre ESP8266 :

FC9DBPKIT682FY7.ino

Étape 3 :La connexion ESP8266

Pour connecter l'ArduFarmBot à Internet, nous utiliserons l'ESP8266, un module simple, bon marché et facile à programmer pour les projets IoT. Une fois le module installé, la première chose à faire est d'appliquer un "Reset" sur sa broche CH-PD.

/************************************************ ********* Réinitialiser la fonction pour accepter la communication************************************ **************/void reset8266(void){ pinMode(CH_PD, OUTPUT); digitalWrite(CH_PD, LOW); retard (300); digitalWrite(CH_PD, HAUT); Serial.print ("8266 réinitialiser OK"); lcd.clear(); lcd.println("8266 réinitialiser OK ");}

Après la réinitialisation, connectons-le à votre réseau local à l'aide de vos identifiants (dans le code, modifiez :USERNAME et PASSWORD) et pour lancer le module en tant que « STA :Station Mode » (CWMODE =1) :

/************************************************ ********* Connexion Wi-Fi****************************************** *************/void connectWiFi(void){ sendData("AT+RST\r\n", 2000, DEBUG); // réinitialiser sendData("AT+CWJAP=\"USERNAME\",\"PASSWORD\"\r\n", 2000, DEBUG); //Connecter le délai réseau (3000); sendData("AT+CWMODE=1\r\n", 1000, DEBUG); sendData("AT+CIFSR\r\n", 1000, DEBUG); // Afficher l'adresse IP lcd.clear(); lcd.print("8266 Connecté"); Serial.println("8266 Connecté");}

Pour envoyer des données à ESP8266, la fonction sendData() a été utilisé :

/************************************************ ********* Envoyer des commandes AT au module************************************ ****************/String sendData(String command, const int timeout, boolean debug){ String response =""; esp8266.print(commande); long int temps =millis(); while ( (time + timeout)> millis()) { while (esp8266.available()) { // L'esp a des données donc affiche sa sortie dans la fenêtre série char c =esp8266.read(); // lit le caractère suivant. réponse +=c; } } if (debug) { Serial.print(response); } renvoyer la réponse ;}

Les fonctions ci-dessus seront appelées pendant la « Phase de configuration » de notre Code. Si tout a été fait correctement, vous devriez voir sur Serial Monitor des messages similaires à ceux ci-dessus.

Étape 4 : Données de stockage dans le cloud : The ThinkSpeak.com

Toutes les données capturées par l'ArduFarmBot seront téléchargées sur le cloud, en utilisant le service gratuit de "ThinkSpeak.com".

À la fonction "Loop()" (après avoir capturé les données avec readSensors() ), nous appellerons une fonction spécifique pour télécharger les données capturées :updateDataThingSpeak();

/************************************************ ******* Transmettre des données à Thingspeak.com ************************************* *******************/void updateDataThingSpeak(void){ startThingSpeakCmd (); cmd =msg; cmd +="&field1="; //champ 1 pour la température DHT cmd +=tempDHT; cmd +="&field2="; //champ 2 pour l'humidité DHT cmd +=humDHT; cmd +="&field3="; //champ 3 pour la luminosité LDR cmd +=lumen; cmd +="&field4="; //champ 4 pour les données d'humidité du sol cmd +=soilMoist; cmd +="&field5="; //champ 5 pour PUMP Status cmd +=pumpStatus; cmd +="&field6="; //champ 6 pour LAMP Status cmd +=lampStatus; cmd +="\r\n" ; sendThingSpeakCmd();}

Afin d'envoyer ces données, la première chose à faire est de démarrer la communication avec ThingSpeak. Nous allons le faire, en utilisant la fonction :startThingSpeakCmd ();

/************************************************ ******* Commencer la communication avec ThingSpeak.com************************************ *******************/void startThingSpeakCmd(void){ cmd ="AT+CIPSTART=\"TCP\",\""; cmd +=IP; cmd +=" \",80"; esp8266.println(cmd); retard (2000); if(esp8266.find("Error")) { Serial.println("ESP8266 START ERROR"); retourner; } Serial.println("Thinkspeak Comm a démarré"); cmd ="";}

Une fois que le canal est ouvert avec ThingSpeak et que la chaîne "cmd" est assemblée avec les données, il est temps de télécharger le tout sur le canal correspondant sur ThingSpeak en utilisant la fonction :sendThingSpeakCmd();

/************************************************ ******** * Mettre à jour le canal 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); retard (500); Chaîne messageBody ="" ; while (esp8266.available()) { Ligne de chaîne =esp8266.readStringUntil('\n'); if (line.length() ==1) { //le contenu réel commence après une ligne vide (qui a une longueur de 1) messageBody =esp8266.readStringUntil('\n'); Serial.print("Message reçu :"); Serial.println(messageBody); } } return messageBody; } else{ esp8266.println("AT+CIPCLOSE"); Serial.println("ESP8266 CIPSEND ERROR:RENENDING"); //Renvoyer... erreur=1; renvoie "erreur" ; }}

Les fonctions ci-dessus étaient basées sur un excellent didacticiel détaillé développé par Michalis Vasilakis. Pour plus de détails, veuillez consulter son tutoriel :Arduino IOT :Température et humidité (avec ESP8266 WiFi).

La photo montre le canal ArduFarmBot sur ThingSpeak.com.

Étape 5 :Commande des actionneurs depuis le Web

En ce moment, nous téléchargeons toutes les données collectées et les stockons dans le cloud. C'est très bien et utile pour une surveillance à distance, mais que se passe-t-il si, sur la base de ces données, nous voulons également allumer la pompe ou la lampe, indépendamment du programme automatique local ? Pour ce faire, nous devrons également « Télécharger » les données du Cloud et ordonner au contrôleur d'agir en fonction de ces commandes.

Nous allons créer des champs spécifiques sur notre canal ThinkSpeak pour commander les actionneurs :

Champ 7 :

  • Data =1 ==> PUMP doit être activé
  • Données =0 ==> LA POMPE doit être éteinte

Champ 8 :

  • Data =1 ==> LA LAMPE doit être allumée
  • Données =0 ==> LA LAMPE doit être éteinte

D'accord, mais comment configurer ces champs directement sur ThingSpeak ? Nous pouvons le faire, par exemple en écrivant un "PlugIn" directement sur ThinksPeak, ou nous pouvons utiliser un site Web externe pour le faire (ce sera notre choix). Quoi qu'il en soit, dans les deux cas, vous devez utiliser une commande comme :

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

Avec la commande ci-dessus, par exemple (et en utilisant votre clé d'écriture de canal), vous écrirez "1" au niveau 7, ce qui signifie que la POMPE doit être allumée. Vous pouvez facilement le tester en écrivant la ligne de commande ci-dessus sur votre navigateur, le champ correspondant sur votre canal sera modifié. En retour, le navigateur affichera une page blanche avec un seul numéro dans le coin supérieur gauche, correspondant à la saisie séquentielle des données dans votre chaîne.

50% du travail est fait, maintenant vous devez lire cette "commande" (données sur le terrain), en bas à la station ArduFarmBot locale.

La commande pour ce faire est indiquée ci-dessous. Il obtiendra les dernières données qui ont été écrites dans le champ spécifique (qui dans notre cas sera une "commande".

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

De la même manière que nous l'avons fait auparavant, vous pouvez tester la ligne de commande à l'aide de votre navigateur Web. Dans ce cas, le navigateur vous montrera les données sur ce champ spécifique. Voir la photo ci-dessus.

De retour sur "terre", écrivons une fonction qui lira ce "dernier champ" :

/************************************************ ********* Lire les données de field7 de thingspeak.com ********************************* *******************/int readLastDataField7(){ startThingSpeakCmd (); // "GET /channels/CHANNEL_ID/fields/7/last" ; cmd =msgReadLastDataField7; cmd +="\r\n" ; Chaîne messageDown =sendThingSpeakCmd(); Serial.print("Commande reçue :"); Serial.println(messageDown[7]); commande int =messageDown[7]-48 ; commande de retour ;}

La fonction ci-dessus renverra les données du champ 7 ("1" ou "0"). Une fonction similaire doit être écrite pour le champ 8.

Une fois que nous avons le contenu des deux champs, nous devons les utiliser sur une fonction qui commandera les actionneurs de la même manière que nous l'avons fait avec la "fonction de commande manuelle" :

/************************************************ ********* Recevoir des commandes de 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(); } retard (500); field8Data =readLastDataField8(); if (field8Data ==1) { digitalWrite(LAMP_PIN, HIGH); lampStatus =1 ; showDataLCD(); } if (field8Data ==0) { digitalWrite(LAMP_PIN, LOW); lampStatus =0; showDataLCD(); } retard (500); }

Ainsi, à partir de maintenant, vous pouvez utiliser la ligne de commande de votre navigateur pour allumer/éteindre la pompe et la lampe à distance. La photo ci-dessus montre comment la commande reçue apparaîtra sur votre moniteur série.

Une autre considération importante est la "coordination" entre la commande locale et la commande à distance. Il faut changer la fonction readLocalCmd() pour mettre également à jour les Thinkspeak Field 7 et 8 respectivement avec l'état de la pompe et de la lampe (sur leur "instruction IF" correspondante). Voir le code complet à la fin de ce tutoriel) :

field7Data =pumpStatus;field8Data =lampStatus; 

Désormais, "filed7Data" et "field8Data" sont synchronisés avec les commandes de la page Web et également avec les actions des commandes locales lorsque vous appuyez sur un bouton. Alors, mettons à jour le aplyCmd() fonction, c'est-à-dire celle qui est chargée d'allumer/éteindre les actionneurs :

/************************************************ ********* Recevoir des commandes et agir sur les actionneurs************************************ *******************/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);}

Lorsque vous démarrez vos tests, vous vous rendrez compte que toute commande que vous effectuez manuellement en local ou via le Web sera surmontée par les actions automatiques définies par la fonction autoControlPlantation() ; À ce stade, vous devriez considérer qui sera le « boss », ayant le dernier mot ! Dans notre cas, nous définirons ici les éléments suivants :

  • A chaque cycle de boucle, que ce soit presque "toujours", on regardera si on appuie sur un bouton
  • Environ chaque minute, nous devrions faire un « pooling » chez ThingSpeak et voir si nous avons reçu une commande de là-bas.
  • Environ toutes les 10 minutes, nous lirons les capteurs, mettrons à jour les données sur ThingSpeak et, plus important encore, prendrons les mesures automatiques. Ces actions seront effectuées indépendamment de celles qui ont été sélectionnées manuellement et seront celles qui seront conservées.

Vous pouvez le changer, comme vous le souhaitez. C'est l'avantage d'utiliser un processeur programmable pour contrôler les choses !

Du coup, 2 timers vont être utilisés maintenant, un pour mutualiser les commandes à distance et un autre pour lire les capteurs (le même que celui que nous avons utilisé auparavant :

long sampleTimingSeconds =75 ; // ==> ******** Définir le temps d'échantillonnage en secondes pour lire les capteurs *********int reverseElapsedTimeSeconds =0;long startTiming =0;long elapsedTime =0;long poolingRemoteCmdSeconds =20; // ==> ******** Définir le temps de mise en pool en secondes pour les nouvelles commandes ThingSpeak *********long startRemoteCmdTiming =0; long elapsedRemoteCmdTime =0; 

Donc, la boucle() la fonction doit maintenant être réécrite comme ci-dessous :

void loop() { elapsedRemoteCmdTime =millis()-startRemoteCmdTiming ; // Démarrer le minuteur pour le regroupement des commandes à distance elapsedTime =millis()-startTiming; // Démarrer la minuterie pour les mesures reverseElapsedTimeSeconds =round (sampleTimingSeconds - elapsedTime/1000); readLocalCmd(); //Lire l'état du bouton local showDataLCD(); if (elapsedRemoteCmdTime> (poolingRemoteCmdSeconds*1000)) { receiveCommands(); updateDataThingSpeak(); startRemoteCmdTiming =millis(); } if (elapsedTime> (sampleTimingSeconds*1000)) { readSensors(); autoControlPlantation(); updateDataThingSpeak(); startTiming =millis(); }} 

Étape 6 :Implémentation d'une page Web dédiée

À ce stade, notre ArduFarmBot est opérationnel et peut être contrôlé depuis le Web. Vous pouvez surveiller les données sur le site Thinkspeak et aussi envoyer des commandes à l'aide d'un navigateur, mais bien sûr cette "solution web" ne peut pas être considérée comme une "élégante" ! La meilleure façon de mettre en œuvre une solution IoT complète est de développer une page Web complète qui affichera toutes les données, comportant également des boutons pour activer les actionneurs.

J'ai choisi le Byethost, un hébergeur gratuit, très facile et simple pour gérer vos pages. J'ai également profité de l'occasion pour postuler à ce projet, ce que j'ai appris dans une fantastique spécialisation en ligne à Coursera/Université du Michigan :Apprendre à concevoir et créer des sites Web (Créer un portefeuille Web réactif et accessible à l'aide de HTML5, CSS3 et JavaScript ).

Je n'entrerai pas dans les détails comment développer une telle page, une fois que ce n'est pas le but central de ce tutoriel, mais j'inclurai ici les codes sources HTML, CSS et JavaScript. Et une fois que quelqu'un s'intéresse à la façon dont j'ai obtenu les résultats, nous pouvons en discuter en utilisant le tableau des commentaires à la fin du projet.

Il est important de souligner que cette page ne fonctionne pas directement avec la station de contrôle locale ArduFarmBot. Ce qu'il fait vraiment, c'est d'interagir avec le canal ThinkSpeak comme ci-dessous :

  • Lecture des données des capteurs sur les champs 1, 2, 3, 4
  • Lecture de l'état de l'actionneur sur les champs 5 et 6
  • Écriture des données sur les champs 7 et 8
  • Lecture des données météo locales des services Yahoo

L'élément 4 ci-dessus n'est pas vraiment crucial pour le projet, mais des données supplémentaires sont toujours disponibles au cas où vous voudriez prendre des mesures à distance indépendamment de ce qui se passe localement avec votre plantation de tomates. Une autre considération est que vous pouvez, par exemple, stocker ces données sur un autre canal ThingSpeak et les télécharger sur votre Arduino, en affichant les données météorologiques sur l'écran LCD local (j'ai développé cela sur un autre projet sympa qui a bien fonctionné ! Je le laisse ici comme suggestion pour vous).

FQOK9ENIT653YX5.zip

Étape 7 :Retournez au cerveau. Une approche Matrice Capteur-Actionneur :

Dans la première partie de ce projet, nous avons défini quelques considérations préliminaires sur la façon dont les actionneurs devraient agir en fonction de la lecture des capteurs. Nous n'avons fait qu'un choix simple, mais que se passera-t-il si nous avons une situation plus complexe ? Plusieurs conditions différentes ? Ce que nous allons développer est une « Approche matricielle Capteur - Actionneur ».

Sur une matrice ont été définis pour chaque capteur, son état et comment doit être la sortie des actionneurs. Le résultat peut être vu sur la feuille de calcul Excel incluse ci-dessous. Sur le fichier Excel, il y a deux feuilles de calcul. Le tableau avec un filtre et une version où vous pouvez sélectionner plusieurs conditions de capteur et voir comment les actionneurs fonctionneront grâce à cette sélection.

Une fois la matrice définie, nous devons la traduire dans notre code. Un tableau de 18 lignes et 10 colonnes a été créé pour "copier" les conditions de la matrice capteur-actionneur :

 // +---SOIL----+-LIGHT-+---TEMP---+---ACTUAT----+ // SL SM SH LL LH TL TM TH Pompe 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 }, }; 

Pour travailler avec la matrice, nous créons une fonction defSensorStatus () . Cette fonction teste pour chaque ligne si la condition des 8 premières colonnes est VRAI. Si Oui, la condition des 2 dernières colonnes est exécutée.

Par exemple :

if (1 et 0 et 0 et 0 et 1 et 0 et 0 et 1) { pumpStatus =1; lampStatus =0} else if (1 et 0 et 0 et 0 et 1 et 0 et 1 et 0) { pumpStatus =1 ; lampStatus =0} 

et ainsi de suite.

Dans la fonction ci-dessus, un autre tableau est créé avec l'état de chaque lecture de capteur :

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

Ce tableau de variables sera également utilisé pour le registre LOG.

F2HWXBYITA8WIN1.xlsx

Étape 8 :Optimisation du code

Au cours du processus de développement de l'ArduFarmBot, nous réalisons que certaines modifications par rapport à la spécification d'origine doivent être apportées :

Affichage :

L'écran LCD doit être éteint par défaut et chaque fois qu'une lecture des capteurs est nécessaire, nous pouvons l'allumer manuellement. Cette condition a été implémentée sur le code et le bouton "Sensors Read" doit être utilisé comme en mode "toggle" pour allumer/éteindre l'écran LCD à tout moment. Allumer ou éteindre l'affichage mettra à jour les lectures des capteurs pour l'affichage, mais n'est pas utilisé par ArduFarmBot sur ses fonctions régulières.

Configuration initiale :

Lorsque l'ArduFarmBot est allumé (ou réinitialisé), l'écran LCD affiche la « configuration initiale ». Pour lancer l'exécution du programme, il faut appuyer sur le bouton "Capteurs". Les informations initiales (voir la photo ci-dessus) affichées sont :

  • Température FROIDE (c'est-à-dire 12oC)
  • Humidité du sol SEC (c'est-à-dire 30 %)
  • Humidité du sol HUMIDE (c'est-à-dire 60 %)
  • Lumière FONCÉE (c'est-à-dire 40 %)
  • P_ON Le temps de la pompe doit être activé (c'est-à-dire 10 s)
  • SCAN Temps de lecture des capteurs (c'est-à-dire 600 s)
  • SW_Vertion (c'est-à-dire 4.1)

Enregistrement du journal :

À des fins d'audit, nous avons créé un LOG avec les lectures et les actionnements de notre ArduFarmBot. A chaque cycle de lecture, la fonction :storeDataLogEEPROM() est exécuté.

/************************************************ ********* Stockage des données de journal sur Arduino EEPROM************************************ ******************/void storeDataLogEEPROM(void){ for (int i =0; i<8; i++) { logData =logData + (snsSts[i])<<1 ; } EEPROM.write (memoAddr, logData); mémoAddr++ ; logDonnées =0 ; logData =logData + pumpStatus ; logData =logData <<1; logData =logData + lampStatus ; EEPROM.write (memoAddr, logData); EEPROM.write (0, memoAddr+1); logDonnées =0 ; si ((MemoAddr+1) ==1023) memoAddr=1; else memoAddr++;}

Comme commenté dans la dernière étape, ce qui sera stocké dans l'EEPROM Arduino est le contenu, un peu du tableau snsSts[] plus l'état de la pompe et de la lampe. Ci-dessus, vous pouvez voir le LOG sur Serial Monitor.

Tout le code ArduFarmBot a été divisé en différents fichiers pour être plus facile à comprendre. A noter que 2 nouveaux fichiers ont été ajoutés sur cette seconde partie :

  • communication.ino (Fonctions spécifiques à ThingSpeak et ESP8266)
  • stationCredentials.h (ID de canal ThingSpeak et clés spécifiques pour l'écriture sur le canal)

Enfin, une fois le code terminé avec une taille raisonnable, nous avons décidé de stocker les données constantes dans la mémoire flash (programme) au lieu de la SRAM. Pour cela, nous utilisons le mot clé PROGMEM qui est un modificateur de variable. Par exemple, au lieu d'utiliser :

#define DHTPIN 5 

Nous avons utilisé :

const PROGMEM octet DHTPIN =5 ; 

Le mot-clé PROGMEN indique au compilateur de "mettre ces informations dans la mémoire flash", au lieu de la SRAM, où elles devraient normalement aller. Vous devez également inclure la bibliothèque avr/pgmspace.h dans le fichier principal de votre code.

Une autre bonne procédure pour réduire l'utilisation de la SRAM consiste à commenter (ou supprimer) toutes les lignes Serial.Print () que vous avez utilisées pour le débogage pendant le développement. Vous vous rendrez compte que le code utilisé par exemple pour afficher le LOG sur Serial Monitor sera commenté sur les fichiers ci-dessous.

Vous trouverez ci-dessous le code ArduFarmBot Arduino complet. N'oubliez pas de modifier les données factices sur credentials.h avec votre identifiant de chaîne et votre clé d'écriture. Également sur communication.ino, utilisez votre vrai nom d'utilisateur et mot de passe pour connecter l'ESP 8266 à Internet.

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

Étape 9 :La ferme familiale MJRovai

Les photos ci-dessous montrent des photos séquentielles d'ArduFarmBot contrôlant ma première plantation de tomates.

La séquence photo ci-dessous, montre l'évolution de ma 2ème plantation depuis la plantation de graines jusqu'au moment de sélectionner les meilleures plantes (environ 45 jours) et les transplantations des 6 meilleures plantes.

Étape 10 : Conclusion

C'est tout les gens ! ...Pour l'instant !

Comme toujours, j'espère que ce projet pourra aider d'autres personnes à trouver leur chemin dans le monde passionnant de l'électronique, de l'IoT et de la robotique !

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

  • Extrait de code n° 1
  • Extrait de code 2
  • Extrait de code 3
  • Code snippet #4
  • Extrait de code n°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
Extrait de code n°1Texte brut
/**************************************************** Reset funtion to accept communication****************************************************/void reset8266(void){ pinMode(CH_PD, OUTPUT); digitalWrite(CH_PD, LOW); retard (300); digitalWrite(CH_PD, HIGH); Serial.print("8266 reset OK"); lcd.clear(); lcd.println("8266 reset OK ");}
Extrait de code #2Texte brut
/**************************************************** 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");}
Extrait de code n°3Texte brut
/**************************************************** 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 #4Plain 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();}
Extrait de code n°5Texte brut
/**************************************************** Start communication with ThingSpeak.com****************************************************/void startThingSpeakCmd(void){ cmd ="AT+CIPSTART=\"TCP\",\""; cmd +=IP; cmd +="\",80"; esp8266.println(cmd); retard (2000); if(esp8266.find("Error")) { Serial.println("ESP8266 START ERROR"); retourner; } 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); retard (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 #11Plain text
/**************************************************** 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

Schémas

ardufarmbot_qpNcBDX6Jr.fzz

Processus de fabrication

  1. Tendances de mise en œuvre de l'IoT
  2. 6-Shooter :Station de mélange de boissons Arduino
  3. Capteur de température multiple
  4. MotionSense
  5. Sécurité incendie des imprimantes 3D
  6. Jauge IoT avec Arduino, Yaler et IFTTT
  7. Lévitation électromagnétique répulsive Arduino
  8. bot de préhension de la télécommande
  9. CoroFence - Détecteur thermique🖖