ArduFarmBot: Controlando um tomateiro com a ajuda de um Arduino e Internet das coisas (IoT)

O objectivo deste projecto criado a 4 mãos juntamente com meu amigo Maurício Pinto, é o de se conseguir uma plantação de tomates totalmente automatizada, onde também se pode monitorar pela internet informações tais como temperatura, humidade do solo, luminosidade, etc.

(A versão em inglês desse post pode ser encontrada aqui em meu blog: ArduFamBot ou em sua versão original no site do Instructables.com)

img_0508Neste tutorial desenvolveremos um controlador eletrônico (o “ArduFarmBot”) que a partir da captura de dados provenientes de uma plantação de tomates (vulgo tomateiro), tais como temperatura, umidade relativa do ar, luminosidade e umidade do solo, decidirá autonomamente a quantidade certa (e quando) o plantio deve receber calor e irrigação (água + nutrientes). Além disso, o ArduFarmBot permitirá a intervenção manual de um operador (tanto de forma local quanto remotamente via Internet), a fim de controlar o acionamento de uma bomba de água e de uma lâmpada elétrica (esta última para ser usada na geração de calor para as plantas).

Em suma, o ArduFarmBot receberá como entrada:

  • Sensores (dados analógicos):
    • Temperatura
    • Umidade do ar
    • Luminosidade
    • Umidade do solo

E fornecerá como saídas:

  • Atuadores:
    • Relé para controle de bomba
    • Relé para controlo da lâmpada
  • Sinalização (dados digitais):
    • Visual e sonoro para indicação de status / erro
    • Visual de Estado da bomba
    • Visual para o estado da lâmpada
  • Display dos dados
    • Todos os dados analógicos e digitais devem estar disponíveis para avaliação instantânea
  • Armazenamento de dados
    • Dados históricos deve ser de armazenamento remotamente na internet e opcionalmente também localmente (via cartão de memória).

O diagrama de blocos abaixo mostra os principais componentes do projeto.

NewBlockDiagram

O vídeo abaixo descreve os principais elementos utilizados no primeiro protótipo de laboratório usado para testes:

Neste segundo vídeo, mostramos como os comandos funcionarão em modo local e remotamente via Web page:

PARTE 1 – ESTAÇÃO LOCAL

O projeto será dividido em 3 partes:

  1. Estação local
  2. Estação Remota ( ESP8266, Thingspeak, criação da página web em HTML/CSS/JS, etc)
  3. Uso e Acompanhamento do ArduFarmBot em uma plantação real. 

Aqui nesta primeira parte, vamos explorar a estação local, desenvolvendo o HW e o SW para trabalhar com os sensores, atuadores, aprendendo como exibir dados, etc.

Abaixo o diagrama em blocos simplificado da versão 1 da estação local:

LocalStationBlockDiagram

1.1: Lista de Materiais

fullComponents

Os principais componentes para o ArduFarmBot são (valores em USD):

Itens gerais (cerca de $ 37,00):

Opção 1 com Nano Shield (em torno de US $ 15,00):

Opção 2  sem o Shield para o  Nano- (cerca de US $ 4,00):

1.2: Instalação, programação e teste dos sensores

Sensor de Temperatura e Humidade: DHT 22 (or DHT11)

O primeiro sensor a ser testado e instalado é o DHT 22, um sensor digital de humidade relativa do ar e temperatura. Ele usa internamente um sensor capacitivo de humidade e um termistor para medir o ar circundante, gerando um sinal digital em sua saída de dados. 

De acordo com a sua folha de dados(Datasheet), o sensor deve ser alimentado entre 3.3V e 5V (algumas especificações falam em até 6V max). Ele trabalha a partir de -40  a + 80 graus centígraods (algumas especs falam em + 125 ° C) com uma precisão de +/- 0,5 ° C de temperatura e +/-2% de umidade relativa. É importante ter em mente que o seu (“sencing period”) é em média de dois segundo (tempo mínimo entre leituras).

O site da Adafruit fornece uma série de informações sobre ambos, DHT22 e seu irmão DHT11. Para mais detalhes, visite a página:  Tutorial DHT22 / 11 .

O DHT22 tem 4 pinos (de frente para o sensor, o pino 1 é o mais esquerda):

  1. VCC (3 a 5V)
  2. saída de dados
  3. Não conectado
  4. GND (Terra)

Uma vez que normalmente você usará o sensor em distâncias inferiores a 20m, um resistor de 10K deve ser conectado entre os pinos de dados e o VCC. O pino de saída deve ser conectado ao pino D5 do Arduino (veja o diagrama acima).

Uma vez que o sensor é instalado fisicamente no Arduino, baixe a biblioteca DHT a partir do repositório de programas:  Adafruit github e a instale junto as outras  bibliotecas de seu IDE (ambiente de desenvolvimento de programas do Arduino).

Uma vez que você recarregue o IDE, a biblioteca para o  sensor de DHT deverá aparecer como instalada. Execute o código abaixo para verificar se tudo está funcionando OK:

 
/****************************************************************
 * DHT Sensor - Setup and Test
 * Based on the original code written by ladyada, public domain
 * MJRoBot 21Aug16
 ****************************************************************/
// Include DHT Library
#include 

// Sensor defiitions
#define DHTPIN 5        // DHT data pin connected to Arduino pin 5
#define DHTTYPE DHT22   // DHT 22 (if your sensor is the DHT 11, only change this line by: #define DHTTYPE DHT11) 

// Variables to be used by Sensor
float tempDHT; // on the final program we will use int insteady of float. No need for high precision measurements 
float humDHT;
float hic; // only used here for testing purposes

// Initialize the DHT sensor
DHT dht(DHTPIN, DHTTYPE); 

void setup() 
{
  Serial.begin(9600); 
  Serial.println("DHT 22 Setup & Test");
  dht.begin();
}

void loop() 
{
  // Wait a few seconds between measurements.
  delay(2000);
  
  //Read temperature and humidity values from DHT sensor:
  tempDHT = dht.readTemperature();   
  humDHT = dht.readHumidity();

  // Check if any reads failed and exit early (to try again).
  if (isnan(humDHT) || isnan(tempDHT)) 
  {
    Serial.println("Failed to read from DHT sensor!");
    return;
  }

  // Compute heat index in Celsius (isFahreheit = false)
  float hic = dht.computeHeatIndex(tempDHT, humDHT, false);
  
  // Show measurements at Serial monitor:
  Serial.print("   Temp DHT ==> ");
  Serial.print(tempDHT);
  Serial.print("oC  Hum DHT ==> ");
  Serial.print(humDHT);
  Serial.print("%  Heat index: ");
  Serial.print(hic);
  Serial.println(" oC ");
}

Sensor de Luminosidade (LDR)

Com o DHT funcionando, é hora de  instalar e testar o sensor de luminosidade. Para isso, podemos usar um simples LDR (Resistor variável com luz). Basicamente, o que se deve fazer é criar um divisor de tensão, onde um dos resistores é o LDR e o outro um fixo, sendo o “ponto médio do divisor” conectado a uma entrada analógica do Arduino. Desta forma, variando-se a luz, a resistência LDR variará proporcionalmente e por conseguinte , a tensão no ponto do meio do divisor também vai variar.

Em nosso projeto, por facilidade de instalação, usaremos um módulo LDR barato (KY18) o qual já possui o divisor de tensão integrado. O módulo tem 3 pinos ( “S” para dados; “+” para VCC e “-” para GND). O pino “S” será ligado ao pino analógico Ao do Arduino.  O “+” e “-” pinos devem ser ligadas, respectivamente, a 5 V e GND. Se o consumo de energia é uma preocupação, o “+” pode ser conectado a uma das saídas digitais do Arduino,  que deverá  ser colocada em “HIGH” alguns milésimos de segundo antes de se ler a tensão no pino A0, retornando para “LOW” depois disso.

A função getLumen (LDR_PIN) lerá algumas vezes a saída do sensor (poderia ser de 3, 10 ou mais, você decide o que é melhor para o seu caso) calculando a média dessas leituras (isso para diminuir o risco que uma uma única leitura seja na verdade um ruído). Além disso, uma vez que a saída do conversor analógico digital (ADC) interno do Arduino será um número de 0 a 1023, deveremos “mapear” esses valores, a fim de obter os seguintes resultados como porcentagens:

  • “Dark Full” ==> saída ADC: 1023 ==> 0%
  • “Full Light” ==>  saída ADC: 0 ==> 100%

Abaixo a função em C++:

int getLumen(int anaPin)
{
  int anaValue = 0;
  for(int i = 0; i < 10; i++) // read sensor 10X ang get the average   
  {     
    anaValue += analogRead(anaPin);        
    delay(50);   
  }      
  anaValue = anaValue/10; //Light under 300; Dark over 800   
  anaValue = map(anaValue, 1023, 0, 0, 100); //LDRDark:0  ==> light 100%

  return anaValue;  
}

Sensor de Humidade de solo (Higrômetro)

Um sensor para testar a umidade do solo (ou higrômetro) é muito simples. Ele possui o mesmo princípio de funcionamento que o sensor de luminosidade. Um divisor de tensão será usado como ponto de entrada de uma das portas analógicas do Arduino, mas em vez de um resistor que varie com luz, usaremos um que varie com a humidade do solo. O circuito básico é muito simples e pode ser visto abaixo.

Picture of Installing, programing and testing the sensors

Infelizmente, a realidade é um pouco mais complexa do que isso (mas não muito). Um simples sensor como o descrito funcionaría bem, mas não por muito tempo. O problema é que ter uma corrente constante fluindo através dos eletrodos em uma única direção gerará corrosão sobre eles, devido ao efeito de eletrólise. Uma maneira de resolver isso é conectar-se os eletrodos não diretamente ao VCC e terra, mas à portas digitais do Arduino (por exemplo VCC a D7 e GND a D6 como mostrado acima). Ao fazer isso, em primeiro lugar o sensor seria “energizado” apenas quando a leitura realmente ocorresse e a direção da corrente sobre as sondas poderia ser alternada, eliminando o efeito da eletrólise.

Abaixo um código de teste simples,  baseada no post “How to: Soil Moisture Measurement?” :

/**************************************************** 
Soil Moisture Sensor Test
****************************************************/
#define SOIL_MOIST_PIN 1 // used for Soil Moisture Sensor Input
#define SMS_VCC 7
#define SMS_GND 6

int soilMoist; // analogical value obtained from sensor

void setup () 
{
  Serial.begin(9600);
  pinMode(SMS_VCC,OUTPUT);
  pinMode(SMS_GND,OUTPUT);

}

void loop (void) 
{
  soilMoist = getSoilMoisture(); 
  Serial.print("Soil Moisture: ")
  Serial.print(soilMoist)
  Serial.println(" %")
}

/***************************************************
* Capture soil Moisture data
****************************************************/
int getSoilMoisture()
{
  int anaValue;
  
  digitalWrite(SMS_VCC,LOW);   // drive a current through the divider in one direction
  digitalWrite(SMS_GND,HIGH);
  delay(1000);   // wait a moment for capacitance effects to settle
  anaValue=analogRead(SOIL_MOIST_PIN);
  
  digitalWrite(SMS_VCC,HIGH);   // reverse the current
  digitalWrite(SMS_GND,LOW);
  delay(1000);   // give as much time in 'reverse' as in 'forward'
  digitalWrite(SMS_VCC,LOW);   // stop the current
  
  anaValue = map(anaValue, 1023, 0, 0, 100);
  return anaValue;
}


Nos testes preliminares para o desenvolvimento do SW, usaremos um  potenciômetro de 10K ohms entre + 5V e GND, simulando a saída analógica do sensor de umidade. Por agora isso será suficiente, uma vez que iremos discutir este sensor mais profundamente no capítulo 1.5.

Agora que todas as rotinas para os sensores estão prontas e testadas individualmente, criaremos uma função específica onde todos os sensores serão lidos ao mesmo tempo:

void readSensors(void)
{
  tempDHT = dht.readTemperature();   //Read temperature and humidity values from DHT sensor:
  humDHT = dht.readHumidity();
  lumen = getLumen(LDR_PIN);
  soilMoist = getSoilMoist();
}

Procure fazer alguns testes com os sensores, como cobrir o LDR com um pano ou a mão, colocar o dedo diretamente no DHT, etc. , e veja o  range de variação dos dados  Use o Serial Monitor como saída para leitura dos dados. 

Sensors Output Serial

Abaixo o código completo:

1.3: Adicionando um Display LCD para monitoramento local

É claro que nem sempre será possível usar o monitor serial para analisar a leitura de nossos sensores. Assim, para monitorização local, será adicionado um LCD ao projecto. A escolha ficou com um módulo LCD de 4 linhas de 20 caracteres cada, que permite configuração de contraste através de um potenciômetro instalado em sua parte traseira e comunicação I2C.

fzxwqolirxthf88-smallPara comunicação serial do tipo I2C com o Arduino, o LCD possui 4 pinos:

  • GND
  • VCC
  • SDA
  • SCL

O pino SDA será ligado em nosso caso a entrada A4 do Arduino e o pino SCL ao  A5, como mostrado no diagrama acima.

Uma vez que os 4 fios são conectados, a próxima coisa a fazer é baixar e instalar a biblioteca I2C para o seu display LCD, a qual pode ser usada tanto  para um display do tipo 20 x 4 quanto para o  16 x 2 (2 linhas de 16 caracteres):

https://github.com/fdebrabander/Arduino-LiquidCrys…

Execute em seu Arduino o programa exemplo “Hello World” que vem incluído com a biblioteca, mudando o  set-up padrão (16 × 2) para o nosso 20 x 4. O  endereço default “0x27” funcionou bem em meu caso:

#include  
#include 

// Set the LCD address to 0x27 for a 20 chars and 4 line display
LiquidCrystal_I2C lcd(0x27, 20, 4);

void setup()
{
    // initialize the LCD
    lcd.begin();

    // Turn on the blacklight and print a message.
    lcd.backlight();
    lcd.print("Hello, world!");
}

void loop()
{
    // Do nothing here...
}

Nota: Se você não tem certeza sobre o seu endereço I2C de seu LCD, uma simples varredura em seu HW irá mostrar se existem dispositivos I2C conectados, se estão funcionando corretamente e em qual seu endereço. O código para fazer o scanner pode ser encontrado aqui: http://playground.arduino.cc/Main/I2cScanner

57ba02f2deafa4839d00151e.jpeg

Como exemplo, em meu caso ao executar o programa obtive no Monitor Serial :

   Scanning..

   I2C device found at address 0x27 !

  done

Vamos incorporar as funções, definições específicas, etc. referentes ao display em nosso último código, para que possamos assim ver as leituras de sensores em LCD:

1.4: Atuadores e botões para controle local

Atuadores

Até agora, pudemos obter os dados gerados pelos sensores e exibi-los no monitor serial e no LCD. É hora de fazer alguma coisa com esses dados. Vamos pensar sobre os atuadores!

Como discutido na introdução, nosso objetivo final aqui é cuidar de uma plantação de tomate. Com os dados fornecidos por sensores, saberemos a temperatura e umidade do ar, a luminosidade e o mais importante quão “seco” se encontra o solo onde está a plantação. Com esses dados em mãos, o nosso programa deverá decidir se seria necessário irrigar a plantação, ligando uma bomba elétrica para bombear água  ou  uma lâmpada elétrica para fornecer o calor necessário para a cultura. Para isso, usaremos pequenos Módulos de %V para relés para a ativação da bomba e lâmpada. O diagrama do Módulo de Relé pode ser visto abaixo.

Picture of Actuators and buttons for local control

Módulos de relés podem apresentar várias nomenclaturas para seus pinos de entrada, tais como: “G”, “V”, “S” ou “S”, “-“, “+” ou “In”, “Vcc”, ” GND “, etc.

Olhando para o diagrama, dependendo do seu módulo de relé, é necessário conectar:

  • Arduino 5V ==> “V” ou “+” ou “Vcc”
  • Arduino GND ==> “G” ou “-” ou “GND”
  • Arduino OUT ==> “S” ou “In” (em nosso caso o “Arduino OUT” deve ser D10 para Bomba e D8 para Lamp)

Normalmente você vai encontrará como saída, 3 pinos: “NA” (ou NO), “Ref”, e “NF ” (ou NC), que são:” Normal Open ou Aberto”, Referência e” Normal Closed ou Fechado “. Nós usaremos o par: NA e Ref (centro). No diagrama acima, “NA” é o terminal para conectar-se ao positivo da fonte de alimentação (12 ou 9VDC para Bomba e 127 ou 220VAC para a lâmpada, conforme seu caso). O “Ref” será conectado à bomba ou da lâmpada, como mostrado na figura acima. Para saber mais sobre relés, visite: “ Controlling Power with Arduino “.

Juntamente com os relés, opcionalmente 2 LEDs podem ser utilizados para mostrar se os relés estão ligados ou desligados:

  • LED vermelho: Bomba
  • LED verde: Lâmpada

Para o teste é ótimo se ter os LEDs instalados em seu BreadBord, mas para o projeto final você pode eliminar-los, reduzindo a carga na saída do pino do Arduino (mesmo porque os módulos de relés em geral possuem um pequeno LED vermelho incorporado). Trabalhando juntos, eles “puxarão” uma quantidade razoável de corrente do Arduino (você poderá perceber uma redução no brilho no LCD). Outra alternativa é utilizar saídas digitais diferentes para os LEDs e relés, o que claro reduz a disponibilidade de pinos para outros usos. 

 57bb216d4936d4e847000021.jpeg

Botões

Com base nas leituras dos sensores, um operador poderia decidir controlar manualmente a bomba e / ou lâmpada. Para isso, dois botões do tipo “push-button” serão incorporados ao projeto. Eles vão trabalhar em um modo de “alternância” (“Toggle”): Se um atuador está “ON”, pressionando-se o botão, ele passa a “OFF” e vice-versa. A lógica do botão será “normalmente fechada”, o que significa que a entrada do Arduino estará constantemente em “HIGH” (será usado um resistor de pull-up interno do Arduino). Pressionando-se o botão, uma estado “LOW” será aplicada ao pino do Arduino.

Da mesma maneira que fizemos com os sensores, a toda vez que executemos o loop () , uma função readLocalCmd () será executada. Esta função lerá o estado dos botões, atualizando o status de variáveis correspondentes aos atuadores (pumpSatus e lampStatus). Note que a função debounce(pin) é chamado ao invés de um digitalRead (PIN). Isso é para evitar falsas leituras do botão. Se você quiser saber mais sobre debouncing, consulte:  Debouncing Tutorial.

/****************************************************************
* Read local commands (Pump and Lamp buttons are normally "HIGH"):
****************************************************************/
void readLocalCmd() 
{  
  int digiValue = debounce(PUMP_ON);
  if (!digiValue) 
  {
    pumpStatus = !pumpStatus;
    showDataLCD();
    aplyCmd();
  }

  digiValue = debounce(LAMP_ON);
  if (!digiValue) 
  {
    lampStatus = !lampStatus;
    showDataLCD();
    aplyCmd();
  }
}

No caso em que um botão é pressionado, uma outra função será chamada: aplyCmd () . E como o nome diz, ela aplicará o comando correspondente, ligando ou desligando os atuadores:

/***************************************************
* Receive Commands and act on actuators
****************************************************/
void aplyCmd()
{
    if (pumpStatus == 1) digitalWrite(PUMP_PIN, HIGH);
    if (pumpStatus == 0) digitalWrite(PUMP_PIN, LOW);
  
    if (lampStatus == 1) digitalWrite(LAMP_PIN, HIGH);
    if (lampStatus == 0) digitalWrite(LAMP_PIN, LOW);
}

Considerações sobre o “Timming” do programa

Quando pensamos sobre as tarefas a serem executadas, podemos agrupar-las em: 

  1. Ler sensores
  2. ler botões (comando local)
  3. Atuar sobre Bomba / Lâmpada
  4. Exibir todos os dados

Percebemos que o “timming” de quando deveríamos realizar tais tarefas não são necessariamente os mesmos. Por exemplo, para ler os dados de temperatura e de umidade do DHT 22, temos de esperar pelo menos 2 segundos entre medidas, mas diferenças em minutos não farão grandes diferenças. Para o sensor de umidade do solo, quanto menos medições fizermos, melhor (evita corrosão das pontas de prova devido a electrolise) e por último mas não menos importante, a luz do dia não vai variar instantaneamente. Mas quando pensamos sobre os atuadores, logo que se pressione um botão, gostaríamos (e possivelmente precisaríamos) de uma reacção rápida.

Assim, a última instrução antes do final do setup () será a inicialização de um temporizador principal usando a função” millis () ” em vez de espalhar um monte de delays()’s pelo código:

startTiming = millis ();  // Iniciar o “relógio do programa”

Durante o loop(), a primeira instrução será a de incrementar a variável startTiming com uma temporização real.

elapsedTime = millis () – startTiming ;

Depois disso, leremos o estado dos botões usando a função readLocalCmd ( ). Esta leitura irá acontecer toda a vez que o programa execute o loop ().

readLocalCmd (); // Ler estado dos botões locais

Em relação aos sensores, fazemos a leitura a cada 5 segundos, por exemplo, e não em cada loop:

if (elapsedTime > (5000))

{

   readSensors();

   printData();

   startTiming = millis();

}

Abaixo o código completo para testar a nossa “Estação local”:

1.5: Aprofundando com o sensor de humidade do solo

Você poderá pular esta etapa se quiser, mas acho que seria interessante aprofundar-nos um pouco mais no estudo deste simples, mas crítico componente para o projeto. Como brevemente explicado anteriormente, o “Soil Moisture Sensor”, ou higrômetro, é um simples “divisor de tensão resistivo”.

Sabendo disso, podemos construir um sensor muito simples usando duas sondas metálicas como pregos galvanizados, pinos ou parafusos. Abaixo você poderá ver o que criei utilizando-se de materiais simples: dois parafusos ligados a dois fios (preto / vermelho). Depois em um segundo sensor, foram adicionados um terceiro fio e um resistor.

Picture of Playing with a real Soil Moisture Sensor

Conforme descrito no item 1.2, “R1” é a “resistência do solo” (não é o melhor termo científico, mas está OK). Utilizando-se de 3 amostras de solo em diferentes estados de umidade, podemos medir o valor esse valor R1 utilisando-se de um multímetro comum e corrente, como mostrado na foto abaixo:

SMS setup

  • Seco:         R1 =    >20 Kohm (aprox)
  • Húmido:  R1 =    4K para 6Kohm (aprox.) 
  • Molhado: R1 =    >1kohm (aprox)

    R2 é a resistência física usada para completar o Divisor de Tensão (Vamos começar com um potenciômetro 10K para set-up). Calculando o Vin na porta A1 do Arduino , proporcionalmente à VCC, chegaríamos a equação:

    Vin = R2 / (R1 + R2) * VCC ou Vin / VCC = 10K / (R1 + 10K) * 100 [%]

    Usando os valores reais medidos com o multímetro, podemos antecipar que os resultados devem ser:

  • Seco:         10K / 30K *100 ==>   <30%

  • Húmido:  10K / 15K * 100 ==>  ~ 67%
  • Molhado: 10K / 11K * 100 ==>  > 90%

SMS measuriments

Fazendo as conexões com o Arduino e executando o código desenvolvido até agora, teremos como resultado:

  • Seco:       13%
  • Húmido: 62%
  • Molhado: 85%

Obviamente devido a que mudei a posição dos sensores na terra R1 mudará um pouco, além de que o VCC também não é exatamente 5V, os valores práticos são um pouco diversos do teórico. Mas como o que realmente importa é o intervalo de variação e não o valor absoluto, o resultado foi muito satisfatório.

O sensor será utilizado em 3 estados distintos:

  • Molhado (Wet): Mais de 60% (não ligaremos a bomba de maneira nenhuma)
  • Húmido: Entre 40 e 60% (Onde queremos trabalhar)  e
  • Seco: Abaixo de 30% (precisaremos ligar a bomba para aumentar a umidade)

Como você pode observar, utilizando-se R2 como 10K ohm funcionou bem, o que nos leva a substituir o potenciômetro por um resistor fixo em nosso “Soil Moisture Sensor”.

Outra coisa que se percebe quando testamos os sensores, é que ao fazer as medições vai se acumulando um pequeno erro nas leituras. Isto porque o sensor também se comportará como um “capacitor”.  Ao se “energizar” o sensor para uma única captura de dados  precisamos esperar um tempo razoável, mesmo depois de cortar o fornecimento de energia para que o mesmo possa se “descarregar “. Revertendo a corrente ajudará, mas não é suficiente.

SoilMoisture Sensor Readings Comp

Os gráficos acima mostram 2 conjuntos de medições:

  1. Linha azul : Um ciclo de 10 medições a cada 1 segundo entre amostras e com 1 minuto entre os ciclos
  2. Linha Laranja : Um ciclo de 10 medições a cada 1 segundo entre amostras e com 5 minutos entre ciclos

Com intervalos de 1 segundo, cada nova amostra será aumentado significativamente. Esperar 1 minuto após desligar a energia irá diminuir o “efeito de tensão de armazenamento”, mas não vai eliminá-la por completo sendo que um valor residual será adicionado à próxima medição. O aumento do intervalo de ciclos para 5 minutos, por exemplo, praticamente eliminará o erro.

Com base nos resultados acima, o código final não deve tomar amostras com uma frequência de menos do que 10 min.

O vídeo abaixo, mostra os testes efetuados com o sensor:

1.6: Compatibilizando as operações automática e manual 

 ardufarmbot_local_station_eletr_diagram

Como pudemos ver na última etapa, precisaremos esperar tempos maiores entre as medições do sensor de umidade, por exemplo: 10minutos. Isto  está Ok para as nossas necessidades automáticas, mas para a operação manual não vamos querer “esperar” dezenas de minutos olhando para o ArduFarmBot para saber se um valor medido pelo sensor mudou. Para solucionar o problema, introduziremos um terceiro botão de controle em nosso projeto, o qual será usado para exibir os dados reais e instantâneos dos sensores a qualquer momento, independente das programações de leituras automáticas.

Picture of Changing the code to accommodate real measurements and final HW

Para o Push-Button, usaremos o pino digital D17  (o mesmo que está compartilhado com a entrada analógica A3). Introduziremos também um “LED de aviso” (o amarelo na foto) conectada ao pino 13. Este LED acenderá toda a vez em que os sensores estão sendo atualizados. Abaixo a nova função readLocalCmd() :

/****************************************************************
* Read local commands (Pump and Lamp buttons are normally "HIGH"):
****************************************************************/
void readLocalCmd() 
{  
  int digiValue = debounce(PUMP_ON);
  if (!digiValue) 
  {
    pumpStatus = !pumpStatus;
    showDataLCD();
    aplyCmd();
  }

  digiValue = debounce(LAMP_ON);
  if (!digiValue) 
  {
    lampStatus = !lampStatus;
    showDataLCD();
    aplyCmd();
  }

  digiValue = debounce(SENSORS_READ);
  if (!digiValue) 
  {
    digitalWrite(YELLOW_LED, HIGH); 
    lcd.setCursor (0,0);
    lcd.print("< Updating Sensors >");
    readSensors();
    digitalWrite(YELLOW_LED, LOW); 
  }
}

Outro ponto a considerar, é a introdução de um segundo “Soil Moisture Sensor” (higrômetro). Em nosso projeto final utilizaremos 2 sensores em pontos diferentes da plantação.  Nós usaremos a média das leitura para decidir quando se deve ligar a bomba, por exemplo.

O “VCC e GND” dos sensores serão o mesmo (D7 e D6 respectivamente) e usaremos a entrada A2 do Arduino para o segundo sensor. Se a area da plantação é pequena não justificando 2 sensores, somente o valor lido em A1 será considerado pelo SW. (Isto deve ser informado na variável correspondente na area de set-up do SW). 

// to be used by SM Sensor
int soilMoist;
int soilMoistAlert = 0;
int DRY_SOIL = 30;
int WET_SOIL = 60;
int numSM = 1; // “numSM” defines number of moisture sensors that are connected
int numSamplesSMS = 1; // “numSamplesSMS” defines number of samples of each reading cycle

O número de amostras de cada ciclo também será definido por uma variável específica: “numSamplesSMS”. Em princípio apenas uma leitura é suficiente, levando-se em consideração que as leituras que fazemos em um curto espaço de tempo introduzirão erros devido ao efeito de capacitância. Se você começar a ver erros na leitura, talvez sejam necessárias tomar amostras extras.

Abaixo a nova função para o  “Soil Moisture Sensor”:

/***************************************************
* Capture soil Moisture data
****************************************************/
int getSoilMoist()
{
  int i = 0;
  int anaValue1 = 0;
  int anaValue2 = 0;
  for(i = 0; i < numSamplesSMS; i++) // "numSamplesSMS" defines number of samples of each reading cycle
  {
    digitalWrite(SMS_VCC,LOW);   // drive a current through the divider in one direction
    digitalWrite(SMS_GND,HIGH);
    delay(500);   // wait a moment for capacitance effects to settle
    anaValue1 += analogRead(SOIL_MOIST_1_PIN);
    delay(500);   // wait a moment for ADC settle-up
    anaValue2 += analogRead(SOIL_MOIST_2_PIN);
    
    digitalWrite(SMS_VCC,HIGH);   // reverse the current
    digitalWrite(SMS_GND,LOW);
    delay(1000);   // give as much time in 'reverse' as in 'forward'
    digitalWrite(SMS_VCC,LOW);   // stop the current
  }

O diagrama abaixo mostra as conexões completas para a estação local de controle

ardufarmbot_local_pin_diagram

1.7: It’s show time!

Picture of It's show time!

Neste ponto, já temos todo o HW no lugar e quase todos os elementos de SW desenvolvidos. O que falta agora é a “inteligência”,  que permitirá ao nosso sistema realmente executar a tarefa de irrigar a plantação automaticamente! Para isto, precisaremos adicionar alguns “neurônios” ao nosso cérebro!

Como discutido anteriormente, definiremos o intervalo inicial onde os sensores irão trabalhar. Esses valores deverão ser alterados mais tarde a partir de resultados de testes reias na plantação:

Umidade do solo:

  • Molhado (Wet): Mais de 60% (não ligaremos a bomba de maneira nenhuma)
  • Húmido: Entre 40 e 60% (Onde queremos trabalhar)  e
  • Seco: Abaixo de 30% (precisaremos ligar a bomba para aumentar a umidade)

Temperatura:

  • Frio: Abaixo de 15oC (Ligar Luz / Calor *)
  • Confortável: entre 20 oC e 25 oC
  • Calor: Mais que 25 ° C (não vire-a luz / calor)

Leve:

  • Escuro (noite): Abaixo de 40% (não ligar bomba)
  • Luz (dia): Mais de 40%

(*) Você poderá opcionalmente testar aqui as novas luzes LED para vegetais hidropônicos . Estas lâmpadas de LED podem ser utilizadas tanto para ajudar o crescimento mais rápido devido a  luzes de frequências especiais como também para fornecer calor em caso de baixa temperatura.

Você deverá ter em mente que cada tipo de semente possui uma faixa ideal de temperatura na qual ela crescerá mais rápidamente. Por exemplo, para os Tomates o tempo mínimo para as sementes germinarem será de 6 dias em temperaturas entre 20 e 25 oC, aumentando para temperaturas superiores ou inferiores a esta faixa:

  • Temperatura: graus (oC):             10    15   20  25  30  35
  • Tempo para germinação (dias):  43   14    8     6    6   9

Você pode verificar mais informações sobre esta relação (temp / dias de germinação) aqui: O efeito da temperatura do solo na germinação de sementes

Tendo em mãos estas 4 leitura (temperatura, umidade, Soil Moisture and luz), podemos criar uma matriz que definirá como queremos que os nossos tomates crescem:

Então, tomemos nossas variáveis e definamos algumas novas valores:

Para ser utilizado pelo sensor DHT:

  • int tempDHT;
  • int HOT_TEMP = 25;
  • int COLD_TEMP = 15;

Para ser usado por sensor LDR:

  • lumen int;
  • int DARK_LIGHT = 40;

Para ser usado pelo higrômetro:

  • int soilMoist;
  • int DRY_SOIL = 40;
  • int WET_SOIL = 60;

Com base nas definições acima, pensemos sobre algumas premissas-chave:

  1. Se é durante o dia (lumen  > DARK_LIGHT) e o solo está SECO (soilMoist < DRY_SOIL) ==>  BOMBA = ON 
  2. Se é durante a noite (lumen < DARK_LIGHT) e o solo está SECO (soilMoist < DRY_SOIL) ==>  BOMBA = OFF  (Tomates não gostam de receber água durante a noite)
  3. Se estiver frio (tempDHT <COLD_TEMP)  ==> LAMPADA = ON
  4. Se estiver frio (tempDHT <COLD_TEMP) e solo muito húmido (soilMoist > WET_SOIL) ==> LAMP = OFF (para proteger a raiz)

Nesta primeira parte do projeto, vamos mantê-lo simples e não exploraremos todas as combinações possíveis e o papel da humidade do ar na equação. Explorar uma combinação mais complexa de sensores na 3º parte deste projeto, quando aplicaremos o ArduFarmBot em uma plantação real.

O Código :

Criaremos uma nova função, que baseado na leitura dos sensores, lidará automaticamente com os atuadores (ligar / desligar a bomba e lâmpada): AutoControlPlantation (). Esta função mostrada abaixo, será chamada em cada ciclo de leituras dos sensores:

void loop() 
{
  // Start timer for measurements
  elapsedTime = millis()-startTiming; 

  readLocalCmd(); //Read local button status
  showDataLCD();
  
  if (elapsedTime > (sampleTimingSeconds*1000)) 
  {
    readSensors();
    autoControlPlantation();
    startTiming = millis();
  }
}

A função terá 2 tarefas principais:

  • Controle de bomba
  • Controle da lâmpada

O segmento de controle da bomba utilizará uma nova variável: ” soilMoistAlert “.

//--------------------------------- PUMP ------//
  if (soilMoist < DRY_SOIL && lumen > DARK_LIGHT) 
  {
    if (soilMoistAlert == HIGH)
    {
      soilMoistAlert = LOW; 
      turnPumpOn();
    }
    else soilMoistAlert = HIGH;
  }
  else soilMoistAlert = LOW;

Esta variável será utilizada para evitar um “falso verdadeiro”. Então por exemplo, se tivermos um verdadeiro no resultado do teste: soilMoist <DRY_SOIL e que não seja durante a noite (lumen> DARK_LIGHT), não ligaremos imediatamente na bomba, mas ao invés disso, esperaremos o próximo ciclo verificando se o ” solo está muito seco “. Se o resultado for um “sim” (obtendo um “verdadeiro” como resposta duas vezes), somente aí a função turnPumpOn() será chamada:

/***************************************************
* TurnPumOn 
****************************************************/
void turnPumpOn()
{
  digitalWrite(PUMP_PIN, HIGH);
  pumpStatus = 1;
  showDataLCD();
  delay (timePumpOn*1000);
  digitalWrite(PUMP_PIN, LOW);
  pumpStatus = 0;
  showDataLCD();
}

A bomba deverá permanecer ligada por um determinado período de tempo, definido pela variável: ” timePumpOn” em segundos.

Note que também mudaremos a função que exibe dados no LCD criando um 3o. estado:

  • “0”: Bomba OFF (pumpStatus = 0; e soilMoistAlert = 0;)
  • “X”: Bomba em alerta (pumpStatus = 0; e soilMoistAlert = 1;)
  • “1”: Bomba ON (pumpStatus = 1; e soilMoistAlert = 0;)
  lcd.print("Pump: ");
  if (soilMoistAlert  == 1) lcd.print ("X");
  else lcd.print(pumpStatus);

O mesmo princípio será aplicado ao controle da lâmpada, onde uma “baixa temperatura” será o “trigger” para acionar a lâmpada desde que o solo não esteja muito molhado”. Abaixoa função completa: autoControlPlantation ():

/***************************************************
* Automatically Control the Plantation based on sensors reading
****************************************************/
void autoControlPlantation()
{ 
//--------------------------------- PUMP ------//
  if (soilMoist < DRY_SOIL && lumen > DARK_LIGHT) 
  {
    if (soilMoistAlert == HIGH)
    {
      soilMoistAlert = LOW; 
      turnPumpOn();
    }
    else soilMoistAlert = HIGH;
  }
  else soilMoistAlert = LOW;

//--------------------------------- HEAT ------//
  if (tempDHT < COLD_TEMP && soilMoist < WET_SOIL) 
  {
    if (tempLowAlert == HIGH)
    {
      tempLowAlert = LOW; 
      digitalWrite(LAMP_PIN, HIGH);
      lampStatus = 1;
    }
    else tempLowAlert = HIGH;
  }
  else 
  {
    tempLowAlert = LOW;
    digitalWrite(LAMP_PIN, LOW);
    lampStatus = 0; 
  }
}

Neste ponto, o ArduFarmBot esta totalmente funcional em termos de HW e SW e já poderia ser instalado em uma plantação para testes. O código completo pode ser encontrado abaixo:

1.8: Small Form Factor (colocando tudo na “caixinha”)

FullSizeRender 20.jpg

Uma vez que possuímos nosso protótipo funcional, vamos montar-lo de uma forma melhor, usando-se um “Shield” para o Arduino Nano (no caso, um fabricado pela  “Funduino”) e uma caixa plástica, o que ajudará nos testes externos. A grande vantagem de se usar um shield para o Nano,  é que cada componente fica melhor montado reduzindo os maus contatos e ruídos, além da facilidade de se ter todos os componentes principais reunidos em uma pequena caixa de plástico.

IMG_4781.JPG

Se você estiver usando o DHT isolado (sem ser em um módulo), você adicione um resistor de 10K entre VCC e Signal. Se você estiver usando um módulo sensor, a resistência já se encontra incluído. Para este novo teste usarei o módulo DHT11 que tenho disponível. O resultado para o nosso propósito é o mesmo (apenas não se esqueça de alterar a linha no código para definir o sensor apropriado que você irá usar: #define DHTTYPE DHT11).

57c1b7c767400c7912000c37.jpeg

Faça 4 furos na caixa de plástico para a instalação do LCD (eu o deixei dentro da caixa).

Faça 57c1b7a045bcebf5270006ab.jpegfuros laterais na caixa para que que você possa acessar os sensores, ter acesso ao Nano (seja para a fonte de alimentação externa ou atualizações de SW) e ligar os atuadores (Bomba / Lampada) nas saídas de relés

Picture of Changing to a Small Form Factor

Note que para os botões de controle, usei aqui um teclado do tipo membrana de 4 teclas “1 × 4 Key Matrix Membrane Switch”. 

IMG_4788.JPG

Você pode decidir a melhor maneira de fixar os componentes na caixa. Eu pessoalmente, gosto desse fixador removível da 3M para facilitar a instalação (veja as foto).

1.9: Testes funcionais em laboratório

Uma vez que tudo está fixada em seu devido lugar e o SW carregado, vamos fazer alguns testes funcionais que simulem diferentes condições de sensores, a fim de se verificar que tudo esteja bem ligado:

Com luz  e temperatura normais, introduzir o higrômetro em um copo com amostra de solo húmido. Observe a foto 1 (Temp é 22oC;. Soil Hum é de 85% e luz é de 80%). Nada deve acontecer. Pump e Lamp devem ser OFF ( “0”).

Picture of Funcional tests

Mantendo-se a mesma luz e temperatura, passemos a sonda para o copo com amostra de solo seco. Na foto 2, você pode observar que a bomba foi ligada (Primeiro aparecerá o “X” e depois o “1” durante algum tempo, tal como definido no programa).

57c1e6574fbadef414000d35.jpeg

Agora, como mostrado na foto 3, o LDR foi coberto com um pano preto e a luminosidade decresceu para 19%. Neste caso, apesar do fato de que o solo esteja seco, a bomba não ligará, porque o ArduFarmBot entenderá que é à noite.

57c1e71ddeafa41a5b0007af.jpeg

Na foto 4, colocaremos gelo no fundo da nossa caixa, junto ao sensor DHT. A temperatura desceu a 12oC e a lâmpada foi ligada.

57c1e801deafa41a5b0007b5.jpeg

E por último, na foto 5 manteremos o gelo, mas mudaremos a sonda novamente para a amostra de solo húmido. Neste caso apesar do fato de estar frio, de acordo com a matriz, a lâmpada permanece desligada.

57c1e8f84fbadef21e00044f.jpeg

1.10: “Test Drive”: Regando um tomateiro com o ArduFarmBot

Picture of

Para os primeiros testes reias, liguei uma bomba elétrica que tinha disponível (no projeto final a bomba será uma pequena bomba DC de 9V). Este primeiro teste é só para ver como o projeto vai funcionar, então não se preocupam com as gotas que você vai ver no vídeo ao lado).

1.11: O ArduFarmBot em acção

Com base em tudo o que nós aprendemos aqui, o passo agora será colocar o ArduFarmBot para controlar sua plantação verdadeira de tomate. Com base nesta experiência real, calibraremos e definiremos melhor os sensores e parâmetros do projeto. As fotos aqui dão uma idéia da sequência da preparação da terra e a introdução das sementes. Essa parte do projeto está a cargo de nosso “Chef” Maurício! Todos os detalhes dos testes reais serão explorados em na 3a. e última parte do projeto.

MauFarmColagem

O filme abaixo mostra o ArduFarmBot em ação:

Agora é só torcer para que tudo de certo e possamos ter uma grande salada no final do projeto!!!! Salut! 😉

1.12: Parte 1 Conclusão

MJRoBot and ArduFarmBotSe você gostou do projeto, não deixe de ver a segunda parte de nosso projeto: ArduFarmBot: Part 2 – “Estação Remota” – IoT, que mostrará a conexão com a internet e sua aplicação na plantação de tomate.

Os arquivos e documentos podem ser encontrados aqui : ArduFarmBot GitHub

Como sempre, espero que este projeto ajude outras pessoas a encontrar seu caminho no apaixonante mundo da eletrônica, do IoT e dos robôs!

Não deixe de visitar e seguir minha página: MJRoBot.org no Facebookcapa-ardufarmbot

Este projeto também está disponível em formato Kindle:

 

Saludos desde el sur del mundo! 😉

Um abraço e até o próximo post!

Obrigado

Marcelo e Maurício

Anúncios

Autor: Marcelo Rovai

Engineer, writer and forever student. Passionate to share knowledge of electronics with focus on IoT and robotics.

5 comentários em “ArduFarmBot: Controlando um tomateiro com a ajuda de um Arduino e Internet das coisas (IoT)”

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s