Manufactura industrial
Internet industrial de las cosas | Materiales industriales | Mantenimiento y reparación de equipos | Programación industrial |
home  MfgRobots >> Manufactura industrial >  >> Manufacturing Technology >> Proceso de manufactura

ArduFarmBot - Parte 2:Estación remota e implementación de IoT

Componentes y suministros

Arduino Nano R3
× 1
Espressif ESP8266 ESP-01
× 1
Sensor de temperatura DHT22
× 1
ky18
× 1
hidrómetro
× 1
Retransmisión (genérico)
× 2
lcd 4X20
× 1
Interruptor de botón SparkFun de 12 mm
× 3
LED (genérico)
× 3

Aplicaciones y servicios en línea

API ThingSpeak

Acerca de este proyecto

Este tutorial es una continuación de ArduFarmBot:Control de una granja de tomates usando Arduino e IoT

En la primera parte creamos una estación de control local, capturando información de una plantación de tomate, como temperatura, humedad relativa del aire, luminosidad y humedad del suelo. Con base en esos datos, ArduFarmBot decidió automáticamente la cantidad correcta (y cuándo) la plantación debería recibir calor y agua. La estación local desarrollada en la Parte 1, también permitió la intervención manual de un operador para controlar la bomba de agua y la lámpara eléctrica. En esta Parte 2, implementaremos un enfoque de IoT en el que esta "intervención manual" también será posible de forma remota a través de Internet. El diagrama de bloques muestra cómo haremos esto.

Tenga en cuenta que los datos capturados se enviarán a un "servicio de almacenamiento en la nube" (en nuestro caso, Thinkspeak.com). También un sitio web dedicado, la "Página de control remoto" monitoreará y mostrará esos datos casi en tiempo real. Esta página web también permitirá la activación remota de la bomba y la lámpara.

Paso 1:lista de materiales

  • Arduino Nano - ($ 7.50)
  • Sensor de temperatura y humedad DHT22 o DHT11 - ($ 3.66)
  • Sensor de luminosidad - Módulo de fotorresistencia AD-018. o cualquier equivalente - ($ 0,71)
  • Sensor de humedad del suelo 2X - ($ 1.99) (opcional, puede ser de bricolaje)
  • LCD I2C 20X4 ($ 13,99)
  • LED (1X) ($ 0.20)
  • Módulo Transceptor Inalámbrico Wifi Serial Esp8266 Esp-01 - ($ 5.96)
  • Buzzer activo:Ky-12 o equivalente ($ 0.60)
  • Módulo de relé de 2 x 5v ($ 11.60)
  • Saltar cables (S1.00)
  • Resistencia de 10KOhms - ($ 0.03)
  • Resistencia de 2.2K ohmios - ($ 0.03)
  • Resistencia de 1.0K ohmios - ($ 0.03)
  • Resistencia de 220 ohmios - ($ 0.03)
  • Arduino Nano Shield ("Funduino") - ($ 7.28)
  • Teclado de membrana (4 teclas) - ($ 6.65)
  • Caja de plástico

Paso 2:completar el hardware

A partir de la estación local desarrollada en la Parte 1, el único hardware adicional necesario es el ESP8266. El diagrama de bloques anterior muestra todas las conexiones PIN de Arduino y los componentes principales. El único cuidado que debe tener está relacionado con el nivel de voltaje. El ESP8266 funciona con 3.3V, por lo que el Pin Rx no debe conectarse directamente al Pin Nano Tx (D3). Debe usarse un nivel de voltaje. En nuestro caso, construiremos un divisor de voltaje para usarlo como convertidor de nivel de voltaje. Los diagramas anteriores muestran con más detalle cómo conectar el ESP8266. Si desea saber más sobre el ESP8266, consulte mis tutoriales:

  • El ESP8266 Parte 3:Activación remota de LED Arduino
  • El ESP8266 Parte 1 - Módulo WIFI en serie para Arduino
  • El ESP8266 Parte 2 - Servidor web Arduino

Tenga en cuenta que estamos usando el ESP8266 conectado a Nano Pin 2 (Tx) y Pin 3 (Rx), usando la biblioteca SoftSerial. Si desea "liberar" esos pines digitales, puede utilizar alternativamente los pines 0 y 1 del Nano Serial. Solo recuerde que debe desconectarlos cuando cargue el código en Nano.

NOTA:Si desea conectar el BUZZER, debe hacerlo en el pin D17 (igual que el pin A3). Es bueno tener un sonido cuando tiene un error de comunicación. Lo usé durante la fase de prueba, dejándolo afuera en el proyecto final (el hw, pero el código está preparado para eso). Depende de usted tenerlo o no.

Puede usar el siguiente código para probar y / o configurar su ESP8266:

FC9DBPKIT682FY7.ino

Paso 3:la conexión ESP8266

Para conectar el ArduFarmBot a Internet usaremos el ESP8266, un módulo simple, económico y fácil de programar para proyectos de IoT. Una vez que el módulo está instalado, lo primero que se debe hacer es aplicar un "Reset" en su Pin CH-PD.

  / **************************************** ********* Restablecer la función para aceptar la comunicación ********************************** **************** / void reset8266 (void) {pinMode (CH_PD, SALIDA); digitalWrite (CH_PD, BAJO); retraso (300); escritura digital (CH_PD, ALTA); Serial.print ("8266 reset OK"); lcd.clear (); lcd.println ("8266 restablecer OK");}  

Después de reiniciar, conéctelo a su red local usando sus credenciales (en el código, cambie:NOMBRE DE USUARIO y CONTRASEÑA) y para iniciar el módulo como un "STA:Modo de estación" (CWMODE =1):

  / **************************************** ********* Conectar WiFi ************************************* ************* / void connectWiFi (void) {sendData ("AT + RST \ r \ n", 2000, DEBUG); // restablecer sendData ("AT + CWJAP =\" NOMBRE DE USUARIO \ ", \" CONTRASEÑA \ "\ r \ n", 2000, DEBUG); // Retardo de conexión de red (3000); sendData ("AT + CWMODE =1 \ r \ n", 1000, DEBUG); sendData ("AT + CIFSR \ r \ n", 1000, DEBUG); // Mostrar dirección IP lcd.clear (); lcd.print ("8266 conectado"); Serial.println ("8266 conectado");}  

Para enviar datos a ESP8266, la función sendData () se utilizó:

  / **************************************** ********* Enviar comandos AT al módulo ********************************* **************** / String sendData (comando String, tiempo de espera de int constante, depuración booleana) {String response =""; esp8266.print (comando); tiempo int largo =millis (); while ((tiempo + tiempo de espera)> millis ()) {while (esp8266.available ()) {// El esp tiene datos, así que muestra su salida en la ventana serial char c =esp8266.read (); // lee el siguiente carácter. respuesta + =c; }} if (debug) {Serial.print (respuesta); } respuesta de retorno;}  

Las funciones anteriores se llamarán durante la "Fase de configuración" de nuestro Código. Si todo se hizo correctamente, debería ver en Serial Monitor mensajes similares a los anteriores.

Paso 4:Datos de almacenamiento en la nube:ThinkSpeak.com

Todos los datos capturados por ArduFarmBot se cargarán en la nube, utilizando el servicio gratuito de "ThinkSpeak.com".

En la función "Loop ()" (después de capturar datos con readSensors () ), llamaremos a una función específica para cargar los datos capturados: updateDataThingSpeak ();

  / **************************************** ********* Transmitir datos a thingspeak.com ********************************* ***************** / void updateDataThingSpeak (void) {startThingSpeakCmd (); cmd =msg; cmd + ="&campo1 ="; // campo 1 para temperatura DHT cmd + =tempDHT; cmd + ="&campo2 ="; // campo 2 para humedad DHT cmd + =humDHT; cmd + ="&campo3 ="; // campo 3 para luminosidad LDR cmd + =lumen; cmd + ="&campo4 ="; // campo 4 para datos de humedad del suelo cmd + =sueloMoist; cmd + ="&campo5 ="; // campo 5 para el estado de la BOMBA cmd + =pumpStatus; cmd + ="&campo6 ="; // campo 6 para Estado de LÁMPARA cmd + =estado de lámpara; cmd + ="\ r \ n"; sendThingSpeakCmd ();}  

Para enviar esos datos, lo primero que debe hacer es iniciar la comunicación con ThingSpeak. Haremos esto, usando la función: startThingSpeakCmd ();

  / **************************************** ********* Iniciar comunicación con ThingSpeak.com ********************************* ***************** / void startThingSpeakCmd (void) {cmd ="AT + CIPSTART =\" TCP \ ", \" "; cmd + =IP; cmd + =" \ ", 80"; esp8266.println (cmd); retraso (2000); if (esp8266.find ("Error")) {Serial.println ("ESP8266 START ERROR"); regreso; } Serial.println ("Comm Thinkspeak iniciada"); cmd ="";}  

Una vez que el canal está abierto con ThingSpeak y la cadena "cmd" está ensamblada con los datos, es hora de cargar todo el canal correspondiente en ThingSpeak usando la función: sendThingSpeakCmd ();

  / **************************************** ******** * Actualizar 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); retraso (500); String messageBody =""; while (esp8266.available ()) {String line =esp8266.readStringUntil ('\ n'); if (line.length () ==1) {// el contenido real comienza después de la línea vacía (que tiene una longitud de 1) messageBody =esp8266.readStringUntil ('\ n'); Serial.print ("Mensaje recibido:"); Serial.println (messageBody); }} return messageBody; } else {esp8266.println ("AT + CIPCLOSE"); Serial.println ("ESP8266 CIPSEND ERROR:RESENDING"); // Reenviar ... error =1; devolver "error"; }}  

Las funciones anteriores se basaron en un gran y detallado tutorial desarrollado por Michalis Vasilakis. Para obtener más detalles, consulte su tutorial:Arduino IOT:temperatura y humedad (con ESP8266 WiFi).

La foto muestra el canal ArduFarmBot en ThingSpeak.com.

Paso 5:comando de los actuadores desde la web

En este momento estamos cargando todos los datos recopilados y almacenándolos en la nube. Esto es muy bueno y útil para una monitorización remota, pero ¿qué pasa si en base a esos datos también queremos encender la Bomba o la Lámpara, independientemente del programa automático local? Para hacer eso, también necesitaremos "Descargar" datos de la Nube y ordenar al controlador que actúe en base a esos comandos.

Crearemos campos específicos en nuestro canal ThinkSpeak para controlar los actuadores:

Campo 7:

  • Data =1 ==> BOMBA debe estar ENCENDIDO
  • Data =0 ==> BOMBA debe estar APAGADO

Campo 8:

  • Data =1 ==> LAMP debe estar ENCENDIDO
  • Data =0 ==> LAMP debe estar APAGADO

Bien, pero ¿cómo configurar esos campos directamente en ThingSpeak? Podemos hacerlo, por ejemplo escribiendo un "PlugIn" directamente en ThinksPeak, o podemos usar un sitio web externo para hacerlo (esta será nuestra elección). De todos modos, en ambos casos deberías usar un comando como:

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

Con el comando anterior, por ejemplo (y usando la clave de escritura de su canal), escribirá "1" en el campo 7, lo que significa que la BOMBA debe estar encendida. Puede probarlo fácilmente, escribiendo la línea de comandos anterior en su navegador, se cambiará el campo correspondiente en su canal. Como retorno, el navegador mostrará una página en blanco con un solo número en la esquina superior izquierda, correspondiente a la entrada de datos secuenciales en su canal.

El 50% del trabajo está hecho, ahora debe leer este "comando" (datos en el campo), en la estación ArduFarmBot local.

El comando para hacer esto se muestra a continuación. Obtendrá los últimos datos que se escribieron en el campo específico (que en nuestro caso será un "comando".

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

De la misma manera que lo hicimos antes, puede probar la línea de comandos utilizando su navegador web. En este caso, el navegador le mostrará los datos en ese campo específico. Vea la foto de arriba.

Regrese a "tierra", escribamos una función que lea este "último campo":

  / **************************************** ********* Leer datos del campo 7 de thingspeak.com ******************************* ******************* / int readLastDataField7 () {startThingSpeakCmd (); // "OBTENER / canales / ID_CANAL / campos / 7 / último"; cmd =msgReadLastDataField7; cmd + ="\ r \ n"; Cadena messageDown =sendThingSpeakCmd (); Serial.print ("Comando recibido:"); Serial.println (messageDown [7]); int comando =messageDown [7] -48; comando de retorno;}  

La función anterior devolverá los datos del campo 7 ("1" o "0"). Se debe escribir una función similar para el campo 8.

Una vez que tengamos el contenido de ambos campos, deberíamos usarlos en una función que comandará los actuadores de manera similar a como lo hicimos con la "función de comando manual":

  / **************************************** ********* Recibir comandos 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 (); } retraso (500); field8Data =readLastDataField8 (); if (field8Data ==1) {digitalWrite (LAMP_PIN, HIGH); lampStatus =1; showDataLCD (); } if (field8Data ==0) {digitalWrite (LAMP_PIN, LOW); lampStatus =0; showDataLCD (); } retraso (500); }  

Entonces, a partir de ahora puede usar la línea de comandos en su navegador para encender / apagar la bomba y la lámpara de forma remota. La foto de arriba muestra cómo aparecerá el comando recibido en su monitor serial.

Otra consideración importante es la "coordinación" entre el mando local y remoto. Debemos cambiar la función readLocalCmd () para actualizar también Thinkspeak Field 7 y 8 respectivamente con el estado de la bomba y la lámpara (en su "declaración IF" correspondiente. Consulte el código completo al final de este tutorial):

  field7Data =pumpStatus; field8Data =lampStatus;  

Ahora, "field8Data" y "field8Data" están sincronizados con los comandos de la página web y también con las acciones de los comandos locales cuando presiona un botón. Entonces, actualice aplyCmd () función, que es la encargada de encender / apagar los actuadores:

  / **************************************** ********* Recibir comandos y actuar sobre los actuadores ********************************* ***************** / 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);}  

Cuando inicies tus pruebas te darás cuenta de que cualquier comando que hagas manualmente en local o vía web será superado por las acciones automáticas definidas por la función autoControlPlantation () ; En este punto, debe considerar quién será el "jefe", ¡teniendo la última palabra! En nuestro caso aquí definiremos lo siguiente:

  • En cada ciclo de bucle, que es casi "siempre", veremos si se presiona un botón
  • Aproximadamente cada minuto, deberíamos hacer una "agrupación" en ThingSpeak y ver si hemos recibido un pedido desde allí.
  • Aproximadamente cada 10 minutos, leeremos los sensores, actualizaremos los datos en ThingSpeak y, lo que es más importante, tomaremos las acciones automáticas. Esas acciones se tomarán independientemente de las seleccionadas manualmente y serán las que se mantendrán.

Puedes cambiarlo, de la forma que quieras. ¡Eso es lo bueno de usar un procesador programable para controlar las cosas!

Entonces, ahora se usarán 2 temporizadores, uno para agrupar los comandos remotos y otro para leer los sensores (el mismo que hemos usado antes:

  long sampleTimingSeconds =75; // ==> ******** Definir el tiempo de muestra en segundos para leer los sensores ********* int reverseElapsedTimeSeconds =0; long startTiming =0; long elapsedTime =0; long poolingRemoteCmdSeconds =20; // ==> ******** Definir el tiempo de agrupación en segundos para los nuevos comandos ThingSpeak ********* long startRemoteCmdTiming =0; long elapsedRemoteCmdTime =0;  

Entonces, el loop () La función ahora debería reescribirse como se muestra a continuación:

  void loop () {elapsedRemoteCmdTime =millis () - startRemoteCmdTiming; // Iniciar el temporizador para agrupar los comandos remotos elapsedTime =millis () - startTiming; // Iniciar temporizador para mediciones reverseElapsedTimeSeconds =round (sampleTimingSeconds - elapsedTime / 1000); readLocalCmd (); // Leer el estado del botón local showDataLCD (); if (elapsedRemoteCmdTime> (poolingRemoteCmdSeconds * 1000)) {recibirComandos (); updateDataThingSpeak (); startRemoteCmdTiming =millis (); } if (tiempo transcurrido> (sampleTimingSeconds * 1000)) {readSensors (); autoControlPlantation (); updateDataThingSpeak (); startTiming =millis (); }}  

Paso 6:implementación de una página web dedicada

En este punto, nuestro ArduFarmBot está operativo y se puede controlar desde la web. Puede monitorear los datos en el sitio Thinkspeak y también enviar comandos usando un navegador, pero, por supuesto, esta "solución web" no puede considerarse una "elegante". La mejor manera de implementar una solución completa de IoT es desarrollar una página web completa que muestre todos los datos, además de tener botones para activar los actuadores.

Elijo Byethost, un alojamiento web gratuito, muy fácil y simple de manejar sus páginas. También aproveché la oportunidad para postularme en este proyecto, lo que he aprendido en una fantástica especialización en línea en Coursera / Universidad de Michigan:aprender a diseñar y crear sitios web (construir un portafolio web receptivo y accesible usando HTML5, CSS3 y JavaScript ).

No entraré en detalles sobre cómo desarrollar dicha página, una vez que este no sea el propósito central de este tutorial, pero incluiré aquí los códigos fuente HTML, CSS y JavaScript. Y una vez que alguien esté interesado en cómo obtuve los resultados, podemos discutirlo a un lado usando el Tablero de Comentarios al final del proyecto.

Es importante recalcar que esta página no funciona directamente con la estación de control local ArduFarmBot. Lo que realmente está haciendo es interactuar con el canal ThinkSpeak como se muestra a continuación:

  • Leer datos del sensor en los campos 1, 2, 3, 4
  • Leer el estado del actuador en los campos 5 y 6
  • Escribir datos en los campos 7 y 8
  • Leer datos meteorológicos locales de los servicios de Yahoo

El punto 4 anterior no es realmente crucial para el proyecto, pero siempre hay datos adicionales disponibles en caso de que desee tomar algunas acciones remotas independientemente de lo que esté sucediendo localmente con su plantación de tomates. Otra consideración es que puede, por ejemplo, almacenar esos datos en otro canal ThingSpeak y descargarlos a su Arduino, mostrando los datos meteorológicos en la pantalla LCD local (¡desarrollé esto en otro proyecto genial que funcionó bien! Lo dejo aquí como una sugerencia para usted).

FQOK9ENIT653YX5.zip

Paso 7:Regrese al cerebro. Un enfoque de matriz de sensor-actuador:

En la primera parte de este proyecto, hemos definido algunas consideraciones preliminares sobre cómo deben actuar los actuadores en función de la lectura de los sensores. Solo hicimos una elección simple, pero ¿qué pasará si tenemos una situación más compleja? ¿Varias condiciones diferentes? Lo que desarrollaremos es un "enfoque de matriz sensor - actuador".

En una matriz se definieron para cada sensor, su condición y cómo debe ser la salida de los actuadores. El resultado se puede ver en la hoja de cálculo de Excel que se incluye a continuación. En el archivo de Excel hay dos hojas de cálculo. La tabla con un filtro y una versión donde puede seleccionar múltiples condiciones de sensor y ver cómo funcionarán los actuadores debido a esta selección.

Una vez definida la Matriz, debemos traducirla a nuestro código. Se creó una matriz de 18 líneas y 10 columnas para "copiar" las condiciones de la matriz sensor-actuador:

  // + --- SUELO ---- + - LUZ - + --- TEMP --- + --- ACTUAT ---- + // SL SM SH LL LH TL TM TH Bomba 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},};  

Para trabajar con Matrix, creamos una función defSensorStatus () . Esta función prueba para cada línea si la condición de las 8 primeras columnas es VERDADERA. En caso afirmativo, se ejecuta la condición de las últimas 2 columnas.

Por ejemplo:

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

y así sucesivamente.

Dentro de la función anterior se crea otra matriz con el estado de cada lectura de sensor:

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

Esta matriz de variables también se utilizará para el registro LOG.

F2HWXBYITA8WIN1.xlsx

Paso 8:Optimización del código

Durante el proceso de desarrollo de ArduFarmBot, nos damos cuenta de que se deben realizar algunos cambios en la especificación original:

Pantalla:

La pantalla LCD debe estar APAGADA por defecto y cada vez que se necesite una lectura de los sensores, podemos "ENCENDER" manualmente. Esta condición se implementó en el código y el botón "Lectura de sensores" debe usarse como en el modo "alternar" para ENCENDER / APAGAR la pantalla LCD en cualquier momento. Encienda o apague la pantalla actualizará las lecturas de los sensores para mostrar, pero ArduFarmBot no las usa en sus funciones regulares.

Configuración inicial:

Cuando el ArduFarmBot se enciende (o se reinicia), la pantalla LCD mostrará la "Configuración inicial". Para iniciar la ejecución del programa, se debe presionar el botón "Sensores". La información inicial (ver la foto de arriba) que se muestra es:

  • Temperatura FRÍA (es decir, 12oC)
  • Humedad del suelo SECO (es decir, 30%)
  • Humedad del suelo HÚMEDO (es decir, 60%)
  • Luz OSCURA (es decir, 40%)
  • P_ON El tiempo de la bomba está ENCENDIDO (es decir, 10 s)
  • SCAN Tiempo para leer sensores (es decir, 600 s)
  • SW_Vertion (es decir, 4.1)

Registro de registro:

Para fines de auditoría, hemos creado un LOG con las lecturas y actuaciones de nuestro ArduFarmBot. En cada ciclo de lectura, la función: storeDataLogEEPROM () es ejecutado.

  / **************************************** ********* Almacenamiento de datos de registro en 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 ++;}  

Como se comentó en el último paso, lo que se almacenará en la EEPROM de Arduino es el contenido, un poco de la matriz snsSts [] más el estado de la bomba y la lámpara. Arriba puede ver el LOG en Serial Monitor.

Todo el código de ArduFarmBot se dividió en diferentes archivos para que sea más fácil de entender. Tenga en cuenta que se agregaron 2 archivos nuevos en esta segunda parte:

  • comunicación.ino (Funciones específicas de ThingSpeak y ESP8266)
  • stationCredentials.h (ID del canal ThingSpeak y claves específicas para escribir en el canal)

Por último, pero no menos importante, una vez que el código terminó con un tamaño razonable, decidimos almacenar los datos constantes en la memoria flash (programa) en lugar de SRAM. Para eso, usamos la palabra clave PROGMEM que es un modificador de variable. Por ejemplo, en lugar de usar:

  #define DHTPIN 5  

Usamos:

  const PROGMEM byte DHTPIN =5;  

La palabra clave PROGMEN le dice al compilador "ponga esta información en la memoria flash", en lugar de en SRAM, donde normalmente iría. También debe incluir la biblioteca avr / pgmspace.h en el archivo principal de su código.

Otro buen procedimiento para reducir el uso de SRAM es comentar (o eliminar) todas las líneas Serial.Print () que usó para depurar durante el desarrollo. Se dará cuenta de que el código utilizado, por ejemplo, para mostrar el LOG en Serial Monitor se comentará en los archivos siguientes.

A continuación puede encontrar el código completo de ArduFarmBot Arduino. No olvide cambiar los datos ficticios en credentials.h con su ID de canal y clave de escritura. También en communication.ino, use su nombre de usuario y contraseña reales para conectar el ESP 8266 a Internet.

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

Paso 9:Granja de MJRovai

Las siguientes fotos muestran fotos secuenciales de ArduFarmBot controlando mi primera plantación de tomates.

La siguiente secuencia de fotos muestra la evolución de mi segunda plantación desde la plantación de semillas hasta el momento de seleccionar las mejores plantas (alrededor de 45 días) y los trasplantes de las mejores 6 plantas.

Paso 10:Conclusión

¡Eso es todo amigos! ... ¡Por ahora!

Como siempre, espero que este proyecto pueda ayudar a otros a encontrar su camino en el apasionante mundo de la electrónica, la IoT y la robótica.

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

Código

  • Fragmento de código n. ° 1
  • Fragmento de código n. ° 2
  • Fragmento de código n. ° 3
  • Fragmento de código n. ° 4
  • Code snippet #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
Fragmento de código n. ° 1 Texto sin formato
/**************************************************** 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 ");}
Fragmento de código n. ° 2 Texto sin formato
/**************************************************** 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");}
Fragmento de código n. ° 3 Texto sin formato
/**************************************************** 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;}
Fragmento de código n.º 4 Texto sin formato
/**************************************************** 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 #5Plain text
/**************************************************** Start communication with ThingSpeak.com****************************************************/void startThingSpeakCmd(void){ cmd ="AT+CIPSTART=\"TCP\",\""; cmd +=IP; cmd +="\",80"; esp8266.println(cmd); retraso (2000); if(esp8266.find("Error")) { Serial.println("ESP8266 START ERROR"); regreso; } 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); retraso (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

Esquemas

ardufarmbot_qpNcBDX6Jr.fzz

Proceso de manufactura

  1. Tendencias de implementación de IoT
  2. 6-Shooter:Arduino Drink Mixing Station
  3. Sensor de temperatura múltiple
  4. MotionSense
  5. Seguridad contra incendios de la impresora 3D
  6. Medidor de IoT con Arduino, Yaler e IFTTT
  7. Levitación electromagnética repulsiva Arduino
  8. Bot de agarre de control remoto
  9. Registrador de datos de globos meteorológicos con tecnología Arduino
  10. $ 10 Estación meteorológica portátil Arduino (AWS)
  11. CoroFence - Detector térmico🖖