Neste quinto e último post da série sobre o desenvolvimento do Controle de Fluxo de Água com Arduino vamos mostrar o que foi alcançado e um pouco do código fonte desenvolvido.
Vídeo demonstrativo
Um pouco sobre o código fonte
O programa de controle foi desenvolvido na IDE do Arduino utilizando algumas bibliotecas para facilitar a vida :D.
Começando pelos includes. Foram utilizadas duas bibliotecas. A TM1637Display e a RotaryEncoder.
A primeira com o propósito de facilitar a escrita dos números nos display de 7 segmentos. A segunda biblioteca é utilizada para leitura do encoder rotatorio. Ambas foram adicionadas pelo link direto do Github que está no código fonte disponibilizado.
#include <TM1637Display.h>
#include <RotaryEncoder.h>
Eu costumo utilizar em meus projetos a ideia de maquina de estados. Para este pensei em 2 estados . O estado de espera e um estado para liberar a contagem do fluxo. Para ambos criei um #define para simplificar o uso.
#define ESPERA 0
#define LIBERA_CONTA 1
Após essas definições algumas variáveis globais foram declaradas incluindo a display, que instancia a classe TM1637Display fornecida pela biblioteca do display, e a encoder, que instancia a classe RotaryEncoder fornecida pela biblioteca do encoder rotatorio. Não entrarei em detalhes sobre as outras variáveis. Qualquer dúvida pode deixar um comentário.
Na função main foi preciso incializar os modos dos pinos e algumas configurações iniciais do display e do encoder.
void setup() {
Serial.begin(9600);
pinMode(LED, OUTPUT);
pinMode(BZR, OUTPUT);
pinMode(SOLENOIDE, OUTPUT);
pinMode(ADJ, INPUT);
pinMode(SW, INPUT);
display.setBrightness(0x0f);
display.showNumberDec(0);
initFlowSensor();
Serial.println("INICIALIZA");
Serial.println("ESTADO -> ESPERA");
}
O ideia de utilizar estados é manter o código simples e fácil de alterar ou corrigir. Consequência disto é que a função loop fica bem pequena. Ele tem apenas um switch que troca qual é o estado atual do sistema e executa uma função específica para o estado.
void loop() {
switch (currentState) {
case ESPERA: {
executarEspera();
break;
}
case LIBERA_CONTA: {
executarLiberaConta();
break;
}
}
}
A função executarEspera é mostrada a seguir. Basicamente ela se mantém executando uma outra função, a runEncoder. No entando é nesta função que é verificado se o botão foi pressionado e caso isso ocorra o fluxo é liberado mudando a variável currentState. Um comportamento que adicionei a esta função é a liberação do fluxo enquanto o valor definido no display for zero e o botão se mantiver pressionado. Futuramente vou realizar uma refatoração deste código para que esta parte seja um novo estado e a função cumpra um único propósito.
void executarEspera() {
adj = analogRead(ADJ);
int pressed = digitalRead(SW);
if (!pressed) {
while(digitalRead(SW) == 0) {
if (currentMls == 0) {
freeFlow = true;
checkFlow();
digitalWrite (SOLENOIDE, HIGH);
display.showNumberDec(totalMilliLitres);
}
}
Serial.println("ESTADO -> LIBERA_CONTA");
digitalWrite (SOLENOIDE, LOW);
currentState = LIBERA_CONTA;
}
runEncoder();
}
A função runEncoder trata da leitura do encoder e da exibição do número no display.
void runEncoder() {
static int encoderPosition = 0;
encoder.tick();
int newPos = encoder.getPosition();
if (encoderPosition != newPos) {
encoderPosition = newPos;
if (encoderPosition * -1 >= 0) {
currentMls = -1 * encoderPosition * 10;
} else {
encoder.setPosition(0);
}
display.showNumberDec(currentMls);
}
}
A função executarLiberarConta executa do estado LIBERA_CONTA. É nela que, após o fluxo ser liberado, o número do display fica sendo atualizado. Caso o botão seja pressionado há um cancelamento do fluxo mesmo que não tenha finalizado para o caso de o usuário passar do ponto na escolha da quantidade.
void executarLiberaConta() {
unsigned int delta = currentMls - totalMilliLitres;
digitalWrite (SOLENOIDE, HIGH);
Serial.println("LIBERA SOLENOIDE");
while (currentMls > totalMilliLitres) {
checkFlow();
int parcial = currentMls - totalMilliLitres;
if (parcial < 0) {
parcial = 0;
}
display.showNumberDec(parcial);
int pressed = digitalRead(SW);
if (!pressed) {
while(digitalRead(SW) == 0) {}
currentMls = 0;
}
}
encoder.setPosition(0);
currentMls = 0;
totalMilliLitres = 0;
display.showNumberDec(0);
digitalWrite (SOLENOIDE, LOW);
if (!freeFlow) {
tone(BZR, 300, 500);
delay(1000);
tone(BZR, 300, 500);
delay(1000);
tone(BZR, 300, 500);
delay(1000);
}
Serial.println("ESTADO -> ESPERA");
freeFlow = false;
currentState = ESPERA;
}
O código fonte completo você encontra em https://github.com/ricardoteix/purific_control.
Com este post concluo a apresentação deste projeto. Espero que você tenho gostado. Deixem suas dúvidas, dicas ou sugestões de melhoria.
boa noite parabens pelo belo trabalho , sou iniciante com arduino e vendo seu sketch fiquei com 2 duas duvidas e desde ja agradeco pela sua atencao ao ler este comentario bom vamos la
duvida n 1 ( vc disse sobre o ecoder ter botao , nao entendi se o botao ja vem no ecoder ou vc colocou o botao pusch button)
Duvida n 2, o que siguinifica (ADJ = A0; )procurei e confesso que nao consegui achar este ADJ desde ja vlw pela atencao
O encoder já tem um botão acoplado. Similar ao R3 da manopla de joysticks como o do Playstation. Só pressionar ele mesmo que dá pra sentir o clique.
O ADJ é uma constante que criei para acessar o A0 (pino de entrada analógica 0). Poderia usar diretamente o A0, mas prefiro colocar desta forma. O ADJ é de adjust (ajustar). É uma forma de ajustar, ou calibrar, o projeto usando a entrada analófica pra definir uma compensação caso deja necessário.
Olá Ricardo, bom dia!
Gostei muito do sei projeto de Controle de Fluxo de Água, o meu filho tentou montar e não conseguiu, aliás eu também não! Rsrsrs
Eu acho que o erro esta em conectar os fios em lugar errado, por acaso você tem um desenho mais simples ou alguma outra maneira mais simples que uma pessoa leiga consiga montar?
Abraços e parabéns pelo projeto!
Olá Alexandre.
Que bom que gostou do projeto. Eu tentei detalhar o projeto ao máximo nos 5 posts relacionados aqui no site.
Pra ajudar mais eu precisaria saber como vocês estão fazendo com mais detalhes. Sobre o erro estar ao conectar os fios, sobre quais fios você se refere?
Muito obrigado pelo seu retorno e vou tentar verificar o que aconteceu com detalhe, mas eu acho que RotaryEncoder que nos ligamos errado!
Abraços
Boa noite, estou desenvolvendo um projeto e queria saber se esse seu sistema ele é capaz de controlar a água, imaginando um cenário que ela teria que ir liberando aos poucos, por exemplo começa saindo 10mL e com o tempo chegando a 50mL.
Olá, Leonardo.
Em tese sim, porém o sensor utilizado neste projeto (YF-S201) não tem uma precisão tão boa para sua necessidade. Nas especificações dele temos que suporta 1~30L/min, mas não diz qual a precisão, ou seja, qual é a menor medição possível para uma dada pressão. O sensor YF-S401 tem um fluxo de 1-5L/min, mas mesmo ele não consigo afirmar se atenderia para sua necessidade. Eu observei que essa precisão depende da pressão do líquido, eu testaria o YF-S201 para definir qual seria a precisão dele na pressão que você necessita. Caso não sirva, tem que buscar outro sensor de fluxo adequado.