Projeto irrigação - dúvidas, sugestões e soluções.

Olá, pessoal!

Estou abrindo esse tópico pra compartilhar com vcs a minha experiência (em andamento) com a construção desse projeto. Se trata de um Arduíno controlando uma solenóide (12V, 500mA) pra molhar 7 fruteiras aqui do meu quintal.

Sou iniciante em eletrônica e programação. Tenho estado fascinado com o espírito colaborativo da comunidade e com o mundo de possibilidades tecnológicas que está se abrindo!

Seguem aí as etapas de elaboração, algumas soluções e, no fim, minhas dúvidas do momento:

v 0.1 - Primeiros testes
Arduíno Nano, protoboard, fonte 9v, fonte 12v e código usando Delay()
-> Acionamento com um Mosfet IRF640N e um Optoisolador 4n25
(http://www.pighixxx.com/test/portfolio-items/connect-a-solenoid/ - esse site é excelente!)

v 0.2 - Proteção e eliminação da fonte 9V [e treino de solda.. rs..]
Protoboard substituída por uma placa ilhada 10x10 numa marmita de plástico (da Spoleto.. rs)
-> Regulador de voltagem 5v com LM7805
(http://www.pighixxx.com/test/portfolio-items/simple-5v-power-supply/)

Em implementação..
v 0.3 - Baixar o custo ($) e abrir a possibilidade de outras entradas e saídas
Usar um "Arduíno Pro Mini" e código sem Delay()

Desafio de ontem (solucionado): Programar o "Arduíno Pro Mini" com adaptador "USB to TTL D-SUN". O "segredo": ficar com o dedo pronto no reset, quando a luz azul piscar, aperte rapidamente o reset.

Desafio de hoje (sem solução): Pq o "If" não redireciona pro seu "else"? Teste lógico furado? Estrutura errada?

Abraços!

/* Baseado no "Blink without Delay"  created 2005  by David A. Mellis  modified 8 Feb 2010  by Paul Stoffregen modified 11 Nov 2013 by Scott Fitzgerald
 
Controlador de irrigação
em Arduino Pro Mini

1. LED da saída 13 pisca nos segundos iniciais para permitir conexão dos fios
2. A solenoide funciona com LOW no pino 10
3. Funciona pela quantidade de horas definidas em "tempIrri"

Futuras melhorias:
A. Evitar reinício após falta de luz
B. Evitar falta d'água
C. RTC

This example code is in the public domain.
*/


// constants won't change. Used here to set a pin number :
const int ledPin =  13;      // the number of the LED pin
const int solePino =  10;    //pino que comanda a solenoide

// Variables will change :
int ledState = LOW;             // ledState used to set the LED
int solenoideEstado = HIGH;



unsigned long previousMillis = 0;        // will store last time LED was updated

// constants won't change :
const long interval = 500;           // interval at which to blink (milliseconds)
// const long tempIrri = 1000*60*60*5; // horas
const long tempIrri = 1000*60; // segundos (teste)


void setup() {
  // set the digital pins as output:
  pinMode(ledPin, OUTPUT);      
  pinMode(solePino, OUTPUT);      
  digitalWrite(solePino, HIGH); // garante a solenoide fechada no início
}

void loop()
{
  
 unsigned long currentMillis = millis();

/* LED pisca durante conexão dos fios. Funciona bem.
 if(currentMillis <= (1000*15)) {
 
   
   if(currentMillis - previousMillis >= interval) {
    // save the last time you blinked the LED 
    previousMillis = currentMillis;   

    // if the LED is off turn it on and vice-versa:
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;

    // set the LED with the ledState of the variable:
    digitalWrite(ledPin, ledState);
     }

 }

*/

  if((currentMillis > (1000*20)) && (currentMillis < (1000*60))) {  //AQUI ESTÁ MEU PROBLEMA: TESTE LOGICO OU ESTRUTURA DO "ELSE"???
    digitalWrite(solePino, LOW);
    
    /* para debug somente
    digitalWrite(9, HIGH); 
    delay(500);
    digitalWrite(9, LOW);
    */

  }
    else 
    {
      digitalWrite(solePino, HIGH);
    }
 
 /* para debug somente 
 digitalWrite(11, HIGH);
 delay(500);
 digitalWrite(11, LOW);
 */
 
 
 }

O conceito desse 'if' está errado (só vai funcionar 1 vez). Os parêntesis não estão certos. Não gosto desses cálculos dentro do 'if'.

Viva-

No codigo.. nao falo, nao sou la grande expert para dar boas dicas.
Em relacao ao hardware, ai posso dar algumas sugestões-

O 7805 é de banir, é um glutao, transforma a voltagem em calor e perdes muito power disponível da pilha para calor e nao na duração temporal da alimentação.
Conselho: um DC-DC steep down converter baseado em lm2596 ou google "Step down Power Supply Module replace LM2596s" outro modelo de steep down.
Melhor ainda: um pequeno painel solar uma bateria e um regulador/carregador solar:

Obrigado, Luisilva e Arssant, pelo retorno e pelas dicas!

Luisilva, os cálculos no meio do "If" já eram o desespero.. rs Tava na tentativa e erro procurando descobrir pq não funcionava. Não consegui resolver aquele código. Fiz outro com variáveis booleanas. Não consegui fazer mesmo o "If" funcionar comparando aqueles intervalos de valor (tipo: tempo início < x > tempo fim).

Quanto a funcionar uma vez, não sei se foi o que quis dizer, mas tenho mesmo ligado e desligado o Arduíno todo dia. Vou implementar, em breve, um reset automático diário (pino rst?) ou uma subtração proporcional na variável de tempo... Idéias?

Arssant, muito legal esse conceito de "step down" não conhecia. Também me preocupo com eficiência e com a durabilidade dos componentes. Assim podemos fazer nossos próprios equipamentos fora da atual lógica do descartável da industria.

Ainda não tive problema pq estou usando o LM7805 só pra alimentar o Arduino e ligado na tomada, não com bateria. Mas no meu próximo regulador de voltagem vou experimentar o LM2596.

A idéia do painel solar/bateria/regulador/carregador também é muito boa! Nesse projeto de irrigação seria bem legal! Me permitiria manobrar a distância uns registros (válvulas) nas mangueiras do quintal. Vamos implementar com o tempo também!

Esses dias (cansado de apertar "reset" no pro mini.. rs) acabei descobrindo um site muito legal: Versa Connector (TNDCI DEV) 0.0.1 - Sign On . Ele permite simular o arduino, fazer circuitos com outros componentes eletrônicos e ainda permite debugar o código linha por linha! É só fazer um cadastro e usar. É gratuito.

/* Baseado no "Blink without Delay"  created 2005  by David A. Mellis  modified 8 Feb 2010  by Paul Stoffregen modified 11 Nov 2013 by Scott Fitzgerald
 
 
Controlador de irrigação
em Arduino Pro Mini

1. LED da saída 13 pisca nos segundos iniciais para permitir conexão dos fios
2. A solenoide funciona com LOW no pino 10
3. Funciona pela quantidade de horas definidas em "tempIrri"

Futuras melhorias:
A. Evitar reinício após falta de luz
B. Evitar falta d'água
C. RTC

This example code is in the public domain.
*/


void setup() {
  // inicializar pinos a serem usadospinMode(10, OUTPUT);
  //pinMode(8, OUTPUT); // reset - testar
  pinMode(10, OUTPUT); // solenoide
  pinMode(13, OUTPUT); // led
  
  // digitalWrite(8, HIGH); // reset testar
}


// the loop routine runs over and over again forever:
void loop() {
  //sintaxe (pino, momento inicio pisca, momento fim pisca, quantas piscadas)
  piscaalert(13,1000,4990,3);   // led alerta ligar fios
  
  //sintaxe (pino, momento inicio ação, momento fim ação, ordem: liga-desliga ou desliga-liga)
  acaoTemp(10,5000,10000,1);   // solenoide
  
  //reset pelo pino - testar
  //acaoTemp(8,10000,12000,0); // reset 24 horas - testar
 

}
  

  void acaoTemp (int Pin, int liga, int desliga, boolean ordem)
  {
    unsigned long tempAtual = millis();
    boolean templiga = false;
    boolean tempdesliga = true; 
    
     
  if(tempAtual >= liga)
    {
    templiga = true;
    }
  
  if (tempAtual >= desliga)
    {
    tempdesliga = false;
    }

  if(templiga == true && tempdesliga == true)
   {
    digitalWrite(Pin, ordem);  
   }
  else
   {
    digitalWrite(Pin, !ordem);
   }



}


void  piscaalert (int Pin, int liga, int desliga, int piscadas)
  {
    unsigned long tempAtual = millis();
    boolean templiga = false;
    boolean tempdesliga = true; 
    
  
  unsigned long intervalo = 0;
  intervalo = (desliga-liga)/piscadas/2;
     
  if(tempAtual >= liga)
    {
    templiga = true;
    }
  
  if (tempAtual >= desliga)
    {
    tempdesliga = false;
    }

  if(templiga == true && tempdesliga == true)
   {
   
  for (int i=1; i <= piscadas; i++)
      {
      digitalWrite(Pin, HIGH);
      delay(intervalo);
      digitalWrite(Pin, LOW);
      delay(intervalo);
      }
  
    }
  else
   {
   digitalWrite(Pin, LOW);
   }

  }

Os calculos no meio do if podem facilmente tornar-se na causa do desespero... mas adiante.

Acho que tens de revisitar o conceito de variaveis e tambem de funcoes. Sempre que chamas uma dessas funcoes no loop, acabas por deitar abaixo o que a chamada anterior da funcao pos em andamento.

Experimenta apagar as funcoes e escrever o codigo todo dentro da funcao loop. Tenta fazer algo funcional e feio primeiro para depois veres as implicacoes das alteracoes que fazes para tornares tudo bonito.

Obrigado, Bubulindo, pelo retorno e pela sugestão!

Não percebi que estava reiniciando sem necessidade, principalmente, a variável de tempo decorrido.

Corrigindo isso o "Blink without delay" é possível novamente e, melhor, já é mais fácil vislumbrar ciclos diários sem a necessidade de dar reset (que era minha idéia inicial).

Mas fora o tempo, os outros elementos eu poderia voltar pra dentro de funções, certo?

Ainda deve ter variáveis mal colocadas, mas melhorei meu entendimento sobre o escopo delas.
(https://www.arduino.cc/en/Tutorial/Variables)

Vou carregar esse código amanhã no "Pro Mini" pra liberar o meu "Nano". Já estou com saudade de por uns leds pra piscar sem precisar ficar apertando "reset"... rs

E vamos seguindo com as melhorias no projeto.. =)

Abraços!

/* Baseado no "Blink without Delay"  created 2005  by David A. Mellis  modified 8 Feb 2010  by Paul Stoffregen modified 11 Nov 2013 by Scott Fitzgerald
 
 
Controlador de irrigação
em Arduino Pro Mini

1. LED da saída 13 pisca nos segundos iniciais para permitir conexão dos fios
2. A solenoide funciona com LOW no pino 10
3. Funciona pela quantidade de tempo definido em "liga" e "desliga" (em ms)

Futuras melhorias:
A. Evitar reinício após falta de luz
B. Evitar falta d'água
C. RTC

This example code is in the public domain.
*/

int pinIrri = 10; // define o numero do pino da solenoide
int pinLED = 13; // define o pino do led

int ledState = LOW; // variavel do blink without delay 
unsigned long previousMillis = 0; // variavel do blink without delay 



void setup() {
 
  // inicializar pinos a serem usados
  pinMode(pinIrri, OUTPUT); // solenoide
  pinMode(pinLED, OUTPUT); // led
  
  digitalWrite(pinIrri, HIGH); //garante solenoide fechada no inicio
  }


// the loop routine runs over and over again forever:
void loop() {

  unsigned long tempAtual = millis();
  
  //variaveis do LED alerta 
  int ligaLED = 200; // quando a sinalização de alerta se inicia
  int desligaLED = 5200;  // quando a sinalização de alerta termmina
  boolean templigaLED = false; //status temporário de início
  boolean tempdesligaLED = true; //status temporário de fim
  const long interval = 500;
  
   
  //variaveis da irrigação
   int liga = 10000; // aqui o momento do inicio da irrigação
   int desliga = 20000; // aqui o momento do fim da irrigação
   boolean templiga = false; //status temporário liga
   boolean tempdesliga = true; //status temporário desliga  
  
  
  //inicio controle do led alerta
  if(tempAtual >= ligaLED)
    {
    templigaLED = true;
    }
  
  if (tempAtual >= desligaLED)
    {
    tempdesligaLED = false;
    }

 if(templigaLED == true && tempdesligaLED == true)
   {
   
  //blink sem delay    
  if(tempAtual - previousMillis >= interval) 
     {
      previousMillis = tempAtual;   

      if (ledState == LOW)
      ledState = HIGH;
      else
      ledState = LOW;

      digitalWrite(pinLED, ledState);
    
       } 
     }
  
 else
   {
   digitalWrite(pinLED, LOW);
   }

  
    
  // inicio do controle da solenoide (LOW = valvula aberta)
  if(tempAtual >= liga)
    {
    templiga = true;
    }
  
  if (tempAtual >= desliga)
    {
    tempdesliga = false;
    }

  if(templiga == true && tempdesliga == true)
   {
   digitalWrite(pinIrri, LOW);  
   }
  else
   {
   digitalWrite(pinIrri, HIGH);
   }
  
      
}

Salve, pessoal!

Depois de um breve problema com o código, a versão 0.3 do irrigador automático está funcionando bem no "arduíno pro mini". Não tinha me dado conta que o tipo da variável (INT) que eu estava usando para os testes do contador de tempo estouraria depois de pouco mais de 4 minutos... :grinning:

Agora o desafio pra versão 0.4 é deixar o arduíno ligado direto (24 horas, 7 dias por semana). Até então eu venho ligando e desligando ele todo dia.

Pra isso queria a opinião de vcs sobre duas coisas:

  1. o código: tentei implementar uma subtração de 86400000 milisegundos por dia pra viabilizar o funcionamento (código abaixo). Está certo?

  2. bateria backup contra falta de luz: como todo código está baseado no millis() precisava garantir que não perderei seu valor com cada falta de luz (aqui falta muita luz). Estou pensando em colocar dois diodos em paralelo, um ligado ao 12V que vem do transformador/fonte da parede e outro numa pilha 9V ligados circuito do LM7805. Encontrei essa solução sugerida em outro tópico (em inglês) pelo usuário "majenko"(Arduino backup battery power (UPS behavior) ? - General Electronics - Arduino Forum). E aí o que me dizem? Funciona tão bem quanto parece? =P E esse diodo, poderia ser um 1N4007?

Valeu!

Abraços!

/* Baseado no "Blink without Delay"  created 2005  by David A. Mellis  modified 8 Feb 2010  by Paul Stoffregen modified 11 Nov 2013 by Scott Fitzgerald
 
 
Controlador de irrigação
em Arduino Pro Mini

1. LED da saída 13 pisca nos segundos iniciais para permitir conexão dos fios
2. A solenoide funciona com LOW no pino 10
3. Funciona pela quantidade de tempo definido em "liga" e "desliga" (em ms)

Futuras melhorias:
A. Evitar reinício após falta de luz
B. Evitar falta d'água
C. RTC

This example code is in the public domain.
*/

int pinIrri = 9; // define o numero do pino da solenoide
int pinLED = 13; // define o pino do led

int ledState = LOW; // variavel do blink without delay 
unsigned long previousMillis = 0; // variavel do blink without delay 

//variaveis do LED alerta 
  unsigned long ligaLED = 200; // quando a sinalização de alerta se inicia
  unsigned long desligaLED = 10200;  // quando a sinalização de alerta termmina
  const long interval = 500;
  
//variaveis da irrigação
  unsigned long liga = 13000; // aqui o momento do inicio da irrigação
  unsigned long desliga = 18000000; // AQUI o momento do fim da irrigação


void setup() {
 
  // inicializar pinos a serem usados
  pinMode(pinIrri, OUTPUT); // solenoide
  pinMode(pinLED, OUTPUT); // led
  
  digitalWrite(pinIrri, HIGH); //garante solenoide fechada no início
  }


// the loop routine runs over and over again forever:
void loop() {

  unsigned long tempAtual = millis();
    
  
  //variaveis do LED alerta 
  boolean templigaLED = false; //status temporário de início led
  boolean tempdesligaLED = true; //status temporário de fim led
  
    
   //variaveis da irrigação
   boolean templiga = false; //status temporário liga
   boolean tempdesliga = true; //status temporário desliga  
  
  // AQUI EM BAIXO reiniciar o contador de tempo a cada 24 horas - V0.4 testar
   if( tempAtual >= 86400000)
     {
    int numCiclos = tempAtual/86400000;
    tempAtual = tempAtual - (86400000*numCiclos); 
     }
  // AQUI EM CIMA 
  
  
  
  //inicio controle do led alerta
  if(tempAtual >= ligaLED)
    {
    templigaLED = true;
    }
  
  if (tempAtual >= desligaLED)
    {
    tempdesligaLED = false;
    }

 if(templigaLED == true && tempdesligaLED == true)
   {
   
  //blink sem delay    
  if(tempAtual - previousMillis >= interval) 
     {
      previousMillis = tempAtual;   

      if (ledState == LOW)
      ledState = HIGH;
      else
      ledState = LOW;

      digitalWrite(pinLED, ledState);
    
       } 
     }
  
 else
   {
   digitalWrite(pinLED, LOW);
   }

  
    
  // inicio do controle da solenoide (LOW = valvula aberta)
  if(tempAtual >= liga)
    {
    templiga = true;
    }
  
  if (tempAtual >= desliga)
    {
    tempdesliga = false;
    }

  if(templiga == true && tempdesliga == true)
   {
   digitalWrite(pinIrri, LOW);  
   }
  else
   {
   digitalWrite(pinIrri, HIGH);
   }
  
      
}

Viva.

A teoria dos dois diodos esta correcta. Mas o tipo de diodo a utilizar, como referido no post do crossroards mais abaixo, aconselha a serie 1N5817, 1N5818.
Dois diodos devem "desenrascar", o ideal era um circuito um pouco mais complexo se pretendes utilizar no futuro baterias recargáveis. Mas para a tua pilha de 9vts deve servir o circuito com esses 2 diodos. Alias um google "arduino power backup " encontraras vários circuitos similares. E em alguns deles até referem o 1n4007.

Viva!

Vou procurar diodos dessa série. Não sou bom em ler datasheets ainda. Entedi que o "CrossRoards" se referiu a diferença de tensão entre as fontes, mas não sei nem de onde ele tirou isso... hehehe

Quero, sim, evoluir para os circuitos recarregáveis. Especialmente os solares. Vivo aos 2º Norte, aqui sol não falta! hehehe Mas por enquanto esses circuitos ainda são muito complexos pra mim... mas estou estudando e logo eles vão ser o caminho pra expandir o irrigador automático para longe do domínio das tomadas. =)

EDIT: Algumas horas, uns sites e um aplicativo depois.. estou entendendo melhor os circuitos recarregáveis e os datasheets dos diodos. A questão dos diodos é a voltagem de ativação ("forward voltage"), que varia com a corrente, certo? Não estava entendendo pq os datasheets referenciavam a uma corrente de 1A. Muito maior que os valores dos circuitos com Arduíno. O gráfico no final do datasheet (forward current x forward voltage) que ajuda a entender as diferenças de voltagem que valem pra gente 0,7V a 0,45V .

Deixo aqui a dica de um link (em inglês =/) que me ajudou de forma simples a entender melhor o diodo e um circuito recarregável solar: lessons:solar:06lampcircuitdesign:2.draft [PEN wiki]

E a dica de um aplicativo pra simular circuitos que estou testando chamado "EveryCircuit". É bem fácil de montar os circuitos, alterar as propriedades do componentes e ver na hora a mudança na corrente e voltagem em cada parte do circuito. Bom, pra vcs pode ser fácil fazer contas, mas eu sou de humanas e tenho um capacidade formidável de errar contas.. hehehe

Valeu! Abraços!

Para algo deste genero, nao vale a pena andares a tentar fazer isto com os timers do Arduino.

A solucao e um RTC para poderes fazer as coisas como deve ser e garantir o minimo de precisao.

Bubulindo, pq diz isso?

Até penso em implementar um RTC futuramente no projeto, mas não como controlador primário do tempo decorrido. Não confio nos RTC's que conheço. Já perdi dois módulos RTC em poucos dias, apenas testando-os e aprendendo a usá-los. Já li muito relatos semelhantes. Acho que se fosse hoje tentaria montar um numa protoboard, pra ir substituindo só o que desse problema (parece que é "bendito" cristal que queima, né?) e, ao menos, reduzir o desperdício. Tem alguma dica ou palavra chave pra eu pesquisar mais sobre RTC´s?

Valeu!

Abraço!

Já experimentaste o DS3231?

O problema é a acumulação de tempo... e do erro. Usar os timers do arduino para temporizar um ou dois segundos não tem mail. Fazê-lo para minutos ou horas é que é o problema.

Ainda não. Estava olhando aqui, o cristal é interno, né? Vou pedir um para testar. Vou aproveitar e vou pedir um módulo step-down com LM2596 que o Arrsant recomendou pra testar também.

Valeu!

Abraços!