Programação do Dispenser de Líquidos com Arduino

Introdução
A movimentação de líquidos é algo essencial para alguns projetos, mas pode ser difícil de integrar essa funcionalidade com microcontroladores e alguns modelos de bombas. As bombas peristálticas, por sua vez, são bem simples e fáceis de serem integradas em projetos, já que são compostas de um motor DC.
Este tutorial é um complemento do tutorial Montagem do Dispenser Automático de Líquidos, onde aprendemos a montar o Kit Faça-Você-Mesmo: Dispenser Automático de Líquidos. A seguir você conhecerá melhor o programa que é usado no dispenser.
Lista de Materiais
Programação
Se você adquiriu o Kit Faça-Você-Mesmo: Dispenser Automático de Líquidos, a BlackBoard que você recebeu no kit está pronta para uso, pois ela foi previamente programada com o código deste tutorial. No entanto, se você quer entender como o seu dispenser automático funciona ou quer adicionar as suas melhorias no projeto, siga adiante para ver o código que está por trás do kit.
Biblioteca
Para o código deste projeto, é necessário instalar a biblioteca "Ultrasonic", que pode ser baixada através do botão abaixo. Caso não saiba como instalar bibliotecas na Arduino IDE, siga este tutorial.
Download da Biblioteca "Ultrasonic"Código
Agora que o circuito está montado e a biblioteca instalada, carregue o código a seguir para sua placa.
/*******************************************************************************
Projeto Dispenser de Alcool Gel (v2.0)
Codigo fonte do Kit Dispenser de Alcool em Gel
(https://www.robocore.net/produtos/kit-faca-voce-mesmo-dispenser-automatico-liquidos)
Assim que voce colocar sua mao abaixo do sensor ultrassonico a bomba
peristaltica sera acionada para despejar alcool gel, assim voce podera
higienizar a sua mao sem ter de tocar na garrafa.
Copyright <2023> RoboCore.
Escrito por @LENZ (25/08/2022).
Atualizado por @Luan.F (17/04/2023).
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version (<https://www.gnu.org/licenses/>).
*******************************************************************************/
// Adiciona a biblioteca ao codigo
#include "Ultrasonic.h"
unsigned long timeout;
// Declaracao dos pinos conectados ao sensor ultrassonico
const int PINO_ECHO = 13;
const int PINO_TRIGGER = 12;
const int PINO_VCC = 11;
// Cria o objeto "sensor" para a biblioteca "Ultrassonic"
// de acordo com os pinos conectados ao "trigger" e "echo" do sensor
HC_SR04 sensor(PINO_TRIGGER, PINO_ECHO);
// Declaracao da variavel que armazena o pino conectado ao rele
int PINO_RELE = A0;
// Declaracao da variavel auxiliar "mao" com o valor inicial "false"
boolean mao = false;
// Declaracao das variaveis auxiliares para a leitura do sensor e acionamento da bomba
int distancia = 0; // Recebe a leitura do sensor
const int DISTANCIA_MIN_ACIONAR = 13; // Distancia minima para o acionamento
const int DISTANCIA_MAX = 18; // Distancia maxima de leitura do sensor
const int TEMPO_ACIONAMENTO = 5000; // Duracao do acionamento da bomba (milissegundos)
void setup()
{
// Inicializacao do monitor serial
Serial.begin(9600);
Serial.println("Iniciando...");
// Configura o pino conectado ao rele como uma saida e com o nivel logico baixo inicial
pinMode(PINO_RELE, OUTPUT);
digitalWrite(PINO_RELE, LOW);
// Configura o pino conectado ao VCC do sensor como uma saida e com o nivel logico alto (HIGH), para ligar o sensor
//(so podemos fazer isso porque a corrente de consumo do sensor eh muito baixa)
pinMode(PINO_VCC, OUTPUT);
digitalWrite(PINO_VCC, HIGH);
}
void loop()
{
// Verifica se o valor retornado pela funcao "checaDistancia" eh menor que a distancia minima para acionamento, e se a variavel "mao" eh falsa ("false")
if (checaDistancia() <= DISTANCIA_MIN_ACIONAR && mao == false)
{
delay(200); // Debounce
if (checaDistancia() <= DISTANCIA_MIN_ACIONAR)
{
// Inverte o estado da variavel "mao" e aciona a bomba
mao = true;
digitalWrite(PINO_RELE, HIGH);
Serial.println("Bomba ligada");
timeout = millis() + TEMPO_ACIONAMENTO;
// Serve para pausar o codigo até a mao sair de embaixo do sensor e/ou o tempo de acionamento ("TEMPO_ACIONAMENTO") acabar
while ((checaDistancia() <= DISTANCIA_MIN_ACIONAR) && (timeout > millis()))
{
// Nada a fazer aqui
}
Serial.println("Bomba desligada");
digitalWrite(PINO_RELE, LOW);
}
}
// Caso contrario, verifica se o valor retornado pela funcao "checaDistancia" eh maior que a distancia minima de acionamento e se a variavel "mao" eh verdadeira ("true")
else if (checaDistancia() > DISTANCIA_MIN_ACIONAR && mao == true)
{
delay(500); // Debounce
// Se for verdadeiro
if (checaDistancia() > DISTANCIA_MIN_ACIONAR)
{
mao = false; // Inverte o estado da variavel "mao"
}
}
delay(150); // Aguarda 150 milissegundos para nova leitura
}
int checaDistancia()
{
// Atribui a leitura do sensor a variavel "distancia"
distancia = sensor.distance();
Serial.print("Distancia: ");
Serial.print(distancia);
Serial.print(" cm");
// Verifica se a leitura do sensor eh maior que a distancia de leitura maxima
while (distancia > DISTANCIA_MAX)
{ // Se for verdadeiro
Serial.println(" -> Distancia invalida!");
delay(200);
// Atualiza a leitura do sensor
distancia = sensor.distance();
Serial.print("Distancia: ");
Serial.print(distancia);
Serial.print(" cm");
} // Caso contrario
Serial.println(" -> Distancia OK!");
delay(100);
return distancia; // Retorna o valor lido para o codigo
}
Entendendo o Código
O código inicia com a adição da biblioteca "Ultrasonic", que foi instalada anteriormente na Arduino IDE. Em seguida, temos a declaração das variáveis constantes PINO_ECHO
, PINO_TRIGGER
e PINO_VCC
, que armazenam os pinos conectados aos terminais "echo", "trigger" e "VCC", respectivamente, do sensor ultrassônico. Com isso, criamos o objeto sensor
para a instância "HC_SR04" (modelo do sensor ultrassônico) da biblioteca, de acordo com os pinos configurados nas variáveis PINO_TRIGGER
e PINO_ECHO
.
xxxxxxxxxx
// Adiciona a biblioteca ao codigo
#include "Ultrasonic.h"
// Declaracao dos pinos conectados ao sensor ultrassonico
const int PINO_ECHO = 13;
const int PINO_TRIGGER = 12;
const int PINO_VCC = 11;
// Cria o objeto "sensor" para a biblioteca "Ultrassonic"
// de acordo com os pinos conectados ao "trigger" e "echo" do sensor
HC_SR04 sensor(PINO_TRIGGER, PINO_ECHO);
Feito isso, declaramos a variável que armazena o pino conectado ao relé (PINO_RELE
), juntamente com a variável mao
, que é uma variável auxiliar para o acionamento da bomba. A variável distancia
também é declarada no início do código, e irá receber as leituras de distância do sensor. Para finalizar as declarações globais do código, temos as declarações das variáveis constantes DISTANCIA_MIN_ACIONAR
, DISTANCIA_MAX
e TEMPO_ACIONAMENTO
, que definem a distância mínima que a sua mão deve ter do sensor para o acionamento da bomba, a distância máxima que o sensor poderá considerar, e o tempo de acionamento da bomba, respectivamente.
xxxxxxxxxx
// Declaracao da variavel que armazena o pino conectado ao rele
int PINO_RELE = A0;
// Declaracao da variavel auxiliar "mao" com o valor inicial "false"
boolean mao = false;
// Declaracao das variaveis auxiliares para a leitura do sensor e acionamento da bomba
int distancia = 0; // Recebe a leitura do sensor
const int DISTANCIA_MIN_ACIONAR = 13; // Distancia minima para o acionamento
const int DISTANCIA_MAX = 18; // Distancia maxima de leitura do sensor
const int TEMPO_ACIONAMENTO = 5000; // Duracao do acionamento da bomba (milissegundos)
Já na configuração do código, iniciamos o monitor serial e configuramos os pinos conectados ao relé e ao terminal "VCC" do sensor ultrassônico como saídas do sistema ("OUTPUT"). Entretanto, o pino conectado ao relé é iniciado com um nível lógico baixo ("LOW"), enquanto o pino conectado ao "VCC" do sensor é iniciado com um nível lógico alto ("HIGH"), para ligar o sensor. Vale lembrar que só podemos alimentar o sensor diretamente pelo pino digital da placa porque ele possui um consumo de corrente menor do que a corrente máxima que o pino digital da placa é capaz de fornecer.
xxxxxxxxxx
// Inicializacao do monitor serial
Serial.begin(9600);
Serial.println("Iniciando...");
// Configura o pino conectado ao rele como uma saida e com o nivel logico baixo inicial
pinMode(PINO_RELE, OUTPUT);
digitalWrite(PINO_RELE, LOW);
// Configura o pino conectado ao VCC do sensor como uma saida e com o nivel logico alto (HIGH), para ligar o sensor
// (so podemos fazer isso porque a corrente de consumo do sensor eh muito baixa)
pinMode(PINO_VCC, OUTPUT);
digitalWrite(PINO_VCC, HIGH);
Na repetição do código, verificamos através da condição if (checaDistancia() <= DISTANCIA_MIN_ACIONAR && mao == false)
se a distância retornada pela função checaDistancia()
, que será explicada posteriormente, é menor ou igual ao valor configurado na variável DISTANCIA_MIN_ACIONAR
, e se a variável mao
é falsa ("false"). Se essa condição for verdadeira, verificamos novamente se o valor retornado pela função checaDistancia()
é menor que o valor configurado na variável DISTANCIA_MIN_ACIONAR
, após um "debounce" (delay(200)
). Isso é necessário para evitar acionamentos indesejados da bomba. Se essa condição for verdadeira mesmo após o "debounce", é sinal que há uma mão, ou objeto, presente embaixo do sensor, portanto a variável mao
tem seu estado invertido (de "false" para "true"), e o relé é então acionado durante o tempo configurado na variável TEMPO_ACIONAMENTO
. A condição while()
do bloco é usada para manter a bomba acionada enquanto a mão estiver sob o sensor e o tempo de acionamento for menor do que o tempo limite (armazenado na variável timeout
).
xxxxxxxxxx
// Verifica se o valor retornado pela funcao "checaDistancia" eh menor que a distancia minima para acionamento, e se a variavel "mao" eh falsa ("false")
if (checaDistancia() <= DISTANCIA_MIN_ACIONAR && mao == false)
{
delay(200); // Debounce
if (checaDistancia() <= DISTANCIA_MIN_ACIONAR)
{
// Inverte o estado da variavel "mao" e aciona a bomba
mao = true;
digitalWrite(PINO_RELE, HIGH);
Serial.println("Bomba ligada");
timeout = millis() + TEMPO_ACIONAMENTO;
// Serve para pausar o codigo até a mao sair de embaixo do sensor e/ou o tempo de acionamento ("TEMPO_ACIONAMENTO") acabar
while ((checaDistancia() <= DISTANCIA_MIN_ACIONAR) && (timeout > millis()))
{
// Nada a fazer aqui
}
Serial.println("Bomba desligada");
digitalWrite(PINO_RELE, LOW);
}
}
Caso a condição anterior seja falsa, é verificado através da condição else if (checaDistancia() > DISTANCIA_MIN_ACIONAR && mao == true)
se o valor retornado pela função checaDistancia()
é maior que o valor configurado na variável DISTANCIA_MIN_ACIONAR
, e se a variável mao
é verdadeira ("true"). Se essa condição for verdadeira, é verificado novamente se a distância retornada pela função checaDistancia()
é maior que o valor configurado na variável DISTANCIA_MIN_ACIONAR
, após um "debounce" (delay(500)
). Se essa condição for verdadeira mesmo após o "debounce", é sinal que não há mais uma mão, ou objeto, embaixo do sensor, portanto a variável mao
inverte de estado novamente (de "true" para "false"). Para finalizar, temos uma pausa no código de 100 milissegundos antes de realizar uma nova leitura.
xxxxxxxxxx
//Caso contrario, verifica se o valor retornado pela funcao "checaDistancia" eh maior que a distancia minima de acionamento, e se a variavel "mao" eh verdadeira ("true")
else if (checaDistancia() > DISTANCIA_MIN_ACIONAR && mao == true) {
delay(500); //Debounce
if (checaDistancia() > DISTANCIA_MIN_ACIONAR) { //Se for verdadeiro
mao = false; //Inverte o estado da variavel "mao"
}
}
delay(150); //Aguarda 150 milissegundos para nova leitura
Ao final do código, temos a função checaDistancia()
, que é iniciada com a atribuição da leitura feita pelo sensor à variável distancia
através do comando distancia = sensor.distance()
. Em seguida, é verificado pela condição while(distancia > DISTANCIA_MAX)
se a distância recebida na variável distancia
é maior que o valor configurado na variável DISTANCIA_MAX
. Enquanto essa condição for verdadeira, o valor da variável distancia
é atualizado (distancia = sensor.distance()
) a cada 200 milissegundos. Assim que a distância armazenada na variável distancia
for válida, ou seja, menor que o valor configurado na variável DISTANCIA_MAX
, esse valor é retornado para o código através do comando return distancia
após uma breve espera de 100 milissegundos.
xxxxxxxxxx
int checaDistancia() {
// Atribui a leitura do sensor a variavel "distancia"
distancia = sensor.distance();
Serial.print("Distancia: ");
Serial.print(distancia);
Serial.print(" cm");
// Verifica se a leitura do sensor eh maior que a distancia de leitura maxima
while(distancia > DISTANCIA_MAX){ //Se for verdadeiro
Serial.println(" -> Distancia invalida!");
delay(200);
// Atualiza a leitura do sensor
distancia = sensor.distance();
Serial.print("Distancia: ");
Serial.print(distancia);
Serial.print(" cm");
} // Caso contrario
Serial.println(" -> Distancia OK!");
delay(100);
return distancia; // Retorna o valor lido para o codigo
}
O Que Deve Acontecer
Assim que o código estiver carregado para a sua placa, alimente-a com a fonte de 12 V e 5 A do kit. Então basta aproximar sua mão, ou um objeto, embaixo do sensor ultrassônico para que o dispenser despeje um pouco do liquído desejado sobre a sua mão, ou objeto, como no GIF a seguir.
Conclusão
Neste tutorial conhecemos e entendemos o código do Kit Faça-Você-Mesmo: Dispenser Automático de Líquidos.