// CÓDIGO FEITO E COMENTADOR POR LUCAS SIQUEIRA
// Os valores de pesagem (como 60g e 120g) são placeholders
// Valores reais serão colocados quando a maquete estiver funcionando
// ==============================================================
// | 0️⃣ Importações e criação de variáveis
// ==============================================================
// Inclusões de bibliotecas
#include <Ultrasonic.h> // Biblioteca para os sensores ultrassônicos
#include "HX711.h" // Biblioteca para o conversor analógico-digital HX711
// Criação das variáveis
int blocks[3] = {0, 0, 0}; // Variáveis que guardam o valor dos sensores ultrassônicos de bloqueio
bool blocked[3] = {false, false, false}; // Variáveis que guardam se a rodovia tal está bloqueada
float weight[3] = {0, 0, 0}; // Variáveis que guardam o peso das balanças
bool passing[3] = {false, false, false}; // Variáveis que guardam se algum veículo quer passar em tal rodovia
// Instanciação de objetos da biblioteca do sensor ultrassônico
Ultrasonic sensors[3] = {
Ultrasonic(13, 34), // Sensor rodovia #1
Ultrasonic(25, 36), // Sensor rodovia #2
Ultrasonic(27, 32) // Sensor rodovia #3
};
// Instanciação de objetos da biblioteca do conversor analógico-digital HX711
HX711 weightConversors[3];
// ==============================================================
// | 1️⃣ Criação de funções auxiliares
// ==============================================================
// Função que configura as células de carga (mais especificamente os seus conversores)
void setupLoadCells() {
// Inicia os conversores usando a biblioteca importada
weightConversors[0].begin(18, 19);
weightConversors[1].begin(2, 5);
weightConversors[2].begin(21, 22);
delay(500); // Espera um pouco, para que tudo seja carregado e iniciado corretamente
// Configura a escala dos conversores
// O "set_scale" serve para converter os valores ADCs brutos para uma leitura humana (gramas, quilos...)
// Neste caso, ele retorna em gramas
// Pelo fato de estarmos em um simulador, todas as células são iguais, então as escalas são idênticas
// Quando for o definitivo, teremos que encontrar a escala certa para cada um usando a fórmula:
// "w1.get_value(10) / 200" -> o get_value(10) pega 10 amostras e o 200 é o peso base que queremos
weightConversors[0].set_scale(10.5);
weightConversors[1].set_scale(10.5);
weightConversors[2].set_scale(10.5);
}
// Função que verifica se há algum bloqueio nas rodovias
void verifyBlocks() {
// Cria um loop para pecorrer todos itens do Array de bloqueios
for (int i = 0; i < 3; i++) {
blocks[i] = sensors[i].read(); // Lê o valor do bloqueio e atualiza no Array
if (blocks[i] < 100 && !blocked[i]) { // Se o valor do bloqueio for menor que 100...
// Quer dizer que tem bloqueio, então avisa
Serial.println("Too close. There's an interdiction!");
Serial.print("Making an request to block highway #");
Serial.println(i + 1);
Serial.println();
// Nessa parte aqui, faremos uma requisição para nossa API
// Essa requisição mudará no nosso banco de dados que a rodovia tal está interditada
blocked[i] = true; // Muda no Array que essa rodovia está bloqueada
delay(100);
} else if (blocks[i] >= 130) { // Se ainda estiver meio longe...
blocked[i] = false; // Muda no Array que essa rodovia está liberada
}
}
}
// Função que verifica se há algum veículo tentando passar nas rodovias (usando o peso)
void verifyPassing() {
// Cria um loop para pecorrer todos itens do Array de bloqueios
for (int i = 0; i < 3; i++) {
weight[i] = weightConversors[i].get_units(); // Lê o valor do bloqueio e atualiza no Array
// Se o peso for menor que 10...
if (weight[i] <= 10) {
// Quer dizer que não tem nada na balança (intervalo de filtragem e segurança)
passing[i] = false; // Fala que não tem nada tentando passar naquela rodovia
} else if (weight[i] > 60 && !passing[i]) { // Se for maior que 60...
// Mostra o peso para aquela rodovia
Serial.print("Weight #");
Serial.print(i + 1);
Serial.print(": ");
Serial.print(weight[i]);
Serial.println("g");
if (weight[i] > 120) { // Vê se é mais que 120...
// Se for, é um caminhão tentando passar, então mostramos isso
Serial.print("There's a TRUCK trying to pass at highway #");
Serial.println(i + 1);
Serial.println("Making an request...");
Serial.println("");
// Aqui a gente fará uma requisição para nossa API
// Essa requisição muda no banco de dados, falando que tem um caminhão tentando passar nessa rodovia
} else if (weight[i] > 60) { // Se for menor que 120, vê se é maior que 60...
// Se for, é um carro tentando passar, então mostramos isso
Serial.print("There's a CAR trying to pass at highway #");
Serial.println(i + 1);
Serial.println("Making an request...");
Serial.println("");
// Aqui a gente fará uma requisição para nossa API
// Essa requisição muda no banco de dados, falando que tem um carro tentando passar nessa rodovia
}
passing[i] = true; // Fala que algum veículo quer passar na rodovia tal
delay(100);
}
}
}
// ==============================================================
// | 2️⃣ Uso das funções nativas do microcontrolador (setup e loop)
// ==============================================================
// Função que roda assim que o ESP32 receber energia
void setup() {
// Configura o monitor serial
Serial.begin(9600); // O 9600 é a taxa de transimissão (quanto maior, mais rápida)
setupLoadCells(); // Chama a função de configurar as células de carga
}
// Função que roda até o microcontrolador ficar sem energia
void loop() {
verifyBlocks(); // Verifica se há bloqueios, usando a função
if (weightConversors[0].is_ready() && weightConversors[1].is_ready() && weightConversors[2].is_ready()) { // Se todos os conversores estiverem prontos...
verifyPassing(); // Verifica o peso e se algum veículo quer passar
}
}