Construa um Medidor de Distância e Nível Digital com Arduino – Guia Passo a Passo
Neste tutorial, aprenderemos a fazer um medidor de distância Arduino e um nível digital (espírito). Você pode assistir ao vídeo a seguir ou ler o tutorial escrito abaixo.
Visão Geral
O dispositivo possui um sensor ultrassônico para medir a distância ao objeto mais próximo, um acelerômetro para medir o ângulo em relação ao solo, um display LCD para mostrar os resultados e um PCB personalizado no qual todos os componentes são conectados.
Podemos operar o dispositivo com apenas um único botão. Uma vez ligado o dispositivo, precisamos selecionar a unidade de medida.

Pressionando o botão, podemos alternar entre as unidades, e se pressionarmos e segurarmos o botão por um tempo, entraremos no primeiro programa. Aqui podemos medir a distância e também ter a capacidade de armazenar as últimas duas medições.

Para entrar no segundo programa, novamente temos que pressionar e segurar o botão por um tempo. Neste programa, podemos medir uma área quadrada fazendo duas medições de distância perpendiculares.

O próximo programa é o nível digital e aqui podemos medir o ângulo em relação ao solo.

Usando o botão, podemos alternar entre os dois eixos ou medir tanto o Pitch quanto o Roll.
Esquemático do Circuito do Medidor de Distância Arduino
Aqui está o esquemático do circuito deste projeto Arduino.

Note que já tenho tutoriais detalhados sobre como cada um destes módulos funciona, e você pode conferir nos seguintes links: Tutorial sensor ultrassônico, Tutorial LCD, Tutorial acelerômetro MEMS.
Você pode obter os componentes necessários para este projeto nos links abaixo:
- Sensor Ultrassônico HC-SR04
- MPU6050 Giroscópio Acelerômetro 3 Eixos
- LCD Caracter 16x2
- Arduino Nano
PCB Personalizado
De acordo com o esquemático do circuito, precisamos projetar o PCB personalizado e fiz isso usando o software gratuito de design de circuitos online EasyEDA.

Uma vez finalizado o design, podemos simplesmente exportar o arquivo Gerber usado para fabricação do PCB. Você pode conferir os arquivos do projeto EasyEDA deste projeto aqui.
Então podemos pedir nosso PCB na JLCPCB, que é na verdade o patrocinador deste projeto.

Aqui podemos simplesmente arrastar e soltar o arquivo Gerber. Uma vez carregado, podemos revisar nosso PCB no visualizador Gerber. Se tudo estiver certo, podemos prosseguir, selecionar as propriedades que queremos para nosso PCB, e então pedir nosso PCB a um preço razoável. Note que se for seu primeiro pedido na JLCPCB, você pode obter até 10 PCBs por apenas $2.

Montando o Dispositivo
Após alguns dias, os PCBs chegaram. A qualidade dos PCBs é ótima e tudo é exatamente igual ao design.

Ok, agora podemos começar a montar a eletrônica para este projeto. Comecei soldando headers de pinos no PCB. Dessa forma, podemos conectar e desconectar os componentes facilmente quando necessário.

Então inseri e soldei os três resistores. Dois deles são para o divisor de tensão para o contraste do LCD. O resistor de 1k deve ser colocado em R1 e o de 220 ohms em R2. O terceiro é um resistor pull-up para o botão.
Em seguida, passei a fazer o gabinete do dispositivo. Decidi usar acrílico transparente porque queria que a beleza de todos os componentes eletrônicos fosse visível. Tinha alguns acrílicos de 5mm de um projeto antigo e usei uma serra circular para cortar no tamanho certo.

Então tive que fazer uma abertura para o LCD no lado superior do gabinete, que na verdade é de 4mm porque se encaixa melhor com o LCD. Primeiro fiz dois furos com a furadeira e depois inseri uma serra de arco através deles. Usando a serra de arco, fiz a abertura aproximadamente e depois, usando uma lima, fiz linhas retas finas para que o LCD encaixasse firmemente.

Então, usando uma broca Forstner, fiz as aberturas para o interruptor de energia, o botão de controle e o sensor ultrassônico.

Uma vez que tinha todas as peças prontas, usei epóxi de 5 minutos para montar o gabinete. Quanto à tampa, inseri e colei dois parafusos através dos quais o painel superior pode ser inserido e fixado usando algumas porcas por cima.

O gabinete está pronto e então continuei soldando headers de pinos no LCD para poder anexá-lo facilmente ao PCB. Também soldei headers de pinos ou jumpers no interruptor de energia, no botão e no conector de bateria.

Finalmente, tinha tudo pronto para montar o dispositivo. Comecei inserindo o sensor ultrassônico no PCB e depois através dos furos no painel lateral. Em seguida, a placa Arduino, o módulo acelerômetro e o conector de bateria.

No painel superior, fixei o LCD, o interruptor de energia e o botão, e então os conectei ao PCB. Por fim, inseri a bateria 9V no conector e fixei o painel superior com as porcas.

E pronto, o projeto do medidor de distância Arduino está feito, mas o que resta neste vídeo é explicar como o programa funciona, então vamos dar uma olhada no código Arduino.
Código Fonte do Medidor de Distância e Nível Digital Arduino
Como o código é um pouco longo, para melhor entendimento, postarei o código-fonte do programa em seções com descrição para cada seção. E no final deste artigo postarei o código-fonte completo.
Primeiro, precisamos incluir a biblioteca Wire.h para comunicação I2C do acelerômetro, bem como a biblioteca LiquidCrystal.h para controlar o LCD. Então precisamos definir o LCD, o endereço I2C do módulo acelerômetro MPU6050, os pinos do sensor ultrassônico, bem como algumas variáveis necessárias para o programa abaixo.
#include <Wire.h> // Biblioteca de comunicação I2C
#include <LiquidCrystal.h> // Inclui a biblioteca LiquidCrystal
LiquidCrystal lcd(7, 6, 5, 4, 3, 2); // Cria objeto LCD. Parâmetros: (rs, enable, d4, d5, d6, d7)
const int MPU = 0x68; // Endereço I2C do acelerômetro MPU6050
#define trigPin 8
#define echoPin 9
#define selectButton 10
int16_t AcX, AcY, AcZ;
long duration;
float distance;
int program = 0;
float d = 0;
float d1 = 0;
float d2 = 0;
float area = 0;
int axis = 0;
int angle = 0;
int unitSelect = 0;
String unit = "cm";
Na seção setup(), precisamos inicializar tanto a interface I2C do acelerômetro quanto o display de cristal líquido, bem como definir os modos de pino para os pinos trigger e echo do sensor ultrassônico e o pino do botão.
void setup() {
// Inicializa interface para o MPU6050
Wire.begin();
Wire.beginTransmission(MPU);
Wire.write(0x6B);
Wire.write(0);
Wire.endTransmission(true);
lcd.begin(16, 2); // Inicializa a interface para a tela LCD
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
pinMode(selectButton, INPUT_PULLUP);
}
Na seção principal loop(), temos um statement switch através do qual podemos alternar entre os diferentes programas do nosso dispositivo. No primeiro, ou case número 0, selecionamos a unidade de medida. Usando a função lcd.print() imprimimos o texto no LCD e usando os statements if alternamos entre as quatro unidades de medida.
switch (program) {
case 0: // Seleciona unidade de medida
lcd.setCursor(0, 0);
lcd.print("Select Unit: ");
lcd.setCursor(13, 0);
lcd.print(unit);
lcd.print(" ");
delay(10);
// Se botão pressionado - muda unidade
if (digitalRead(selectButton) == 0) {
if (unitSelect == 0) { unit = "in"; unitSelect = 1; }
else if (unitSelect == 1) { unit = "m"; unitSelect = 2; }
else if (unitSelect == 2) { unit = "ft"; unitSelect = 3; }
else if (unitSelect == 3) { unit = "cm"; unitSelect = 0; }
// Se botão segurado por mais de meio segundo - muda programa
delay(500);
if (digitalRead(selectButton) == 0) {
program = 1;
lcd.clear();
delay(500);
}
}
break;
Devemos notar aqui que a variável unitSelect atua na função personalizada getDistance(), onde ela realmente diz para qual unidade devemos converter a unidade básica cm que obtemos do sensor ultrassônico.
// Convertendo as unidades
if (unitSelect == 1) { distance = distance; unit = "cm"; } // cm para cm
else if (unitSelect == 2) { distance = distance * 0.393701; unit = "in"; } // cm para in
else if (unitSelect == 3) { distance = distance * 0.01; unit = "m"; } // cm para m
else if (unitSelect == 0) { distance = distance * 0.0328; unit = "ft"; } // cm para ft
Para selecionar a unidade de medida e também entrar no primeiro programa do dispositivo, apenas temos que segurar o botão pressionado por mais de meio segundo.
// Se botão segurado por mais de meio segundo - muda programa
delay(500);
if (digitalRead(selectButton) == 0) {
program = 1;
lcd.clear();
delay(500);
}
break;
No case número 1 ou no programa de medição de distância, primeiro obtemos a distância ao objeto mais próximo usando a função personalizada getDistance().
case 1: // Programa de medição de distância
distance = getDistance(); // Distância ao objeto mais próximo
lcd.setCursor(0, 0);
lcd.print("Dist: ");
lcd.print(distance); // Imprime valor da distância do sensor
lcd.print(" ");
lcd.setCursor(14, 0);
lcd.print(unit);
delay(10);
lcd.setCursor(0, 1);
lcd.print("d:");
lcd.setCursor(8, 1);
lcd.print("d:");
delay(200);
// Salva distância 1
if (digitalRead(selectButton) == 0) {
if (d == 0) {
lcd.setCursor(0, 1);
lcd.print("d: ");
lcd.setCursor(2, 1);
lcd.print(distance);
d = 1;
delay(100);
}
// Salva distância 2
else if (d == 1) {
lcd.setCursor(8, 1);
lcd.print("d: ");
lcd.setCursor(10, 1);
lcd.print(distance);
d = 0;
delay(100);
}
// Se botão segurado por mais de meio segundo muda programa
delay(500);
if (digitalRead(selectButton) == 0) {
program = 2;
d = 0;
lcd.clear();
delay(500);
}
}
break;
Vamos ver como esta função funciona.
//===== getDistance - Função Personalizada
float getDistance() {
// Limpa o trigPin
digitalWrite(trigPin, LOW);
// Coloca o trigPin em HIGH por 10 microssegundos
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Lê o echoPin, retorna o tempo de viagem da onda sonora em microssegundos
duration = pulseIn(echoPin, HIGH);
// Calculando a distância
distance = duration * 0.034 / 2; // distância em cm
// Convertendo as unidades
if (unitSelect == 1) { distance = distance; unit = "cm"; }
else if (unitSelect == 2) { distance = distance * 0.393701; unit = "in"; }
else if (unitSelect == 3) { distance = distance * 0.01; unit = "m"; }
else if (unitSelect == 0) { distance = distance * 0.0328; unit = "ft"; }
return distance;
}
Aqui, usando o pino trigger, dizemos ao sensor para gerar uma onda sonora ultrassônica.

Então, usando o pino echo e a função pulseIn(), medimos a duração que a onda viajou do sensor ao objeto e de volta. Considerando a velocidade do som e o tempo de viagem, podemos calcular facilmente a distância. Então imprimimos a distância medida junto com algum texto no LCD e, usando os statements "if", se pressionarmos o botão, imprimimos ou salvamos as últimas duas medições.
O próximo é o programa para cálculo de área, no qual usamos métodos semelhantes. Precisamos fazer duas medições perpendiculares e simplesmente multiplicá-las para obter a área do quadrado que elas formam.
case 2: // Programa de medição de área
distance = getDistance();
lcd.setCursor(0, 0);
lcd.print("Area: ");
lcd.print(area); // Imprime a área calculada das duas medições
lcd.setCursor(12, 0);
lcd.print(unit); // Imprime a unidade selecionada e o sinal de quadrado abaixo
lcd.print("^2");
delay(200);
if ( d == 0) {
lcd.setCursor(0, 1);
lcd.print("d1: ");
lcd.setCursor(3, 1);
lcd.print(distance);
delay(200);
} else if (d == 1) {
lcd.setCursor(9, 1);
lcd.print("d2: ");
lcd.setCursor(12, 1);
lcd.print(distance);
delay(200);
} else if (d == 2) {
lcd.setCursor(6, 0);
lcd.print(area);
delay(200);
}
// Salva distância 1
if (digitalRead(selectButton) == 0) {
if (d == 0) {
lcd.setCursor(0, 1);
lcd.print("d1: ");
lcd.setCursor(3, 1);
lcd.print(distance);
d = 1;
d1 = distance;
delay(100);
}
// Salva distância 2
else if (d == 1) {
lcd.setCursor(9, 1);
lcd.print("d2: ");
lcd.setCursor(12, 1);
lcd.print(distance);
d = 2;
d2 = distance;
area = d1 * d2; // Calcula a área
delay(100);
} else if (d == 2) {
lcd.clear();
d = 0;
area = 0;
delay(100);
}
// Se botão segurado por mais de meio segundo muda programa
delay(500);
if (digitalRead(selectButton) == 0) {
program = 3;
d = 0;
lcd.clear();
delay(500);
}
}
break;
O último case é o programa de medição de ângulo. Aqui precisamos ler os dados do acelerômetro, que na verdade é a força do campo gravitacional da Terra em três eixos diferentes, X, Y e Z. O valor de cada eixo é armazenado em 2 registradores, então precisamos ler um total de 6 registradores e combiná-los para obter o valor correto.
case 3: // Programa de medição de ângulo
// Lê os dados do acelerômetro
Wire.beginTransmission(MPU);
Wire.write(0x3B); // Começa com registrador 0x3B (ACCEL_XOUT_H)
Wire.endTransmission(false);
Wire.requestFrom(MPU, 6, true); // Lê 6 registradores total, cada valor de eixo armazenado em 2 registradores
AcX = Wire.read() << 8 | Wire.read(); // Valor eixo X
AcY = Wire.read() << 8 | Wire.read(); // Valor eixo Y
AcZ = Wire.read() << 8 | Wire.read(); // Valor eixo Z
if ( axis == 0) {
// Calculando o ângulo Pitch (rotação em torno do eixo Y)
angle = atan(-1 * AcX / sqrt(pow(AcY, 2) + pow(AcZ, 2))) * 180 / PI;
lcd.setCursor(0, 0);
lcd.print("Pitch");
} else if (axis == 1) {
// Calculando o ângulo Roll (rotação em torno do eixo X)
angle = atan(-1 * AcY / sqrt(pow(AcX, 2) + pow(AcZ, 2))) * 180 / PI;
lcd.setCursor(0, 0);
lcd.print("Roll ");
}
lcd.setCursor(0, 1);
lcd.print("Angle: ");
lcd.print(abs(angle));
lcd.print(" ");
lcd.setCursor(10, 1);
lcd.print("deg");
delay(200);
// Muda eixo
if (digitalRead(selectButton) == 0) {
if (axis == 0) { axis = 1; delay(100); }
else if (axis == 1) { axis = 0; delay(100); }
// Se botão segurado por mais de meio segundo muda programa
delay(500);
if (digitalRead(selectButton) == 0) {
program = 0;
lcd.clear();
delay(500);
}
}
break;
}
Uma vez que temos os valores X, Y e Z do acelerômetro, podemos calcular o ângulo Pitch (rotação em torno do eixo Y) e o ângulo Roll (rotação em torno do eixo X) usando as duas equações. Você pode encontrar mais detalhes sobre estas equações na application note da Freescale Semiconductor, Tilt Sensing Using a Three-Axis Accelerometer. Então, após isso, imprimimos os valores junto com algum texto no LCD, e pressionando o botão mudamos o que mostramos no LCD, se o ângulo Pitch ou Roll.
Aqui está o código fonte completo para este projeto de medidor de distância e nível digital Arduino:
/* DIY Digital Range Measurer and Spirit Level
by Dejan Nedelkovski, www.HowToMechatronics.com */
#include <Wire.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(7, 6, 5, 4, 3, 2);
const int MPU = 0x68;
#define trigPin 8
#define echoPin 9
#define selectButton 10
int16_t AcX, AcY, AcZ;
long duration;
float distance;
int program = 0;
float d = 0;
float d1 = 0;
float d2 = 0;
float area = 0;
int axis = 0;
int angle = 0;
int unitSelect = 0;
String unit = "cm";
void setup() {
Wire.begin();
Wire.beginTransmission(MPU);
Wire.write(0x6B);
Wire.write(0);
Wire.endTransmission(true);
lcd.begin(16, 2);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
pinMode(selectButton, INPUT_PULLUP);
}
void loop() {
switch (program) {
case 0:
lcd.setCursor(0, 0);
lcd.print("Select Unit: ");
lcd.setCursor(13, 0);
lcd.print(unit);
lcd.print(" ");
delay(10);
if (digitalRead(selectButton) == 0) {
if (unitSelect == 0) { unit = "in"; unitSelect = 1; }
else if (unitSelect == 1) { unit = "m"; unitSelect = 2; }
else if (unitSelect == 2) { unit = "ft"; unitSelect = 3; }
else if (unitSelect == 3) { unit = "cm"; unitSelect = 0; }
delay(500);
if (digitalRead(selectButton) == 0) {
program = 1;
lcd.clear();
delay(500);
}
}
break;
case 1:
distance = getDistance();
lcd.setCursor(0, 0);
lcd.print("Dist: ");
lcd.print(distance);
lcd.print(" ");
lcd.setCursor(14, 0);
lcd.print(unit);
delay(10);
lcd.setCursor(0, 1);
lcd.print("d:");
lcd.setCursor(8, 1);
lcd.print("d:");
delay(200);
if (digitalRead(selectButton) == 0) {
if (d == 0) {
lcd.setCursor(0, 1);
lcd.print("d: ");
lcd.setCursor(2, 1);
lcd.print(distance);
d = 1;
delay(100);
}
else if (d == 1) {
lcd.setCursor(8, 1);
lcd.print("d: ");
lcd.setCursor(10, 1);
lcd.print(distance);
d = 0;
delay(100);
}
delay(500);
if (digitalRead(selectButton) == 0) {
program = 2;
d = 0;
lcd.clear();
delay(500);
}
}
break;
case 2:
distance = getDistance();
lcd.setCursor(0, 0);
lcd.print("Area: ");
lcd.print(area);
lcd.setCursor(12, 0);
lcd.print(unit);
lcd.print("^2");
delay(200);
if ( d == 0) {
lcd.setCursor(0, 1);
lcd.print("d1: ");
lcd.setCursor(3, 1);
lcd.print(distance);
delay(200);
} else if (d == 1) {
lcd.setCursor(9, 1);
lcd.print("d2: ");
lcd.setCursor(12, 1);
lcd.print(distance);
delay(200);
} else if (d == 2) {
lcd.setCursor(6, 0);
lcd.print(area);
delay(200);
}
if (digitalRead(selectButton) == 0) {
if (d == 0) {
lcd.setCursor(0, 1);
lcd.print("d1: ");
lcd.setCursor(3, 1);
lcd.print(distance);
d = 1;
d1 = distance;
delay(100);
}
else if (d == 1) {
lcd.setCursor(9, 1);
lcd.print("d2: ");
lcd.setCursor(12, 1);
lcd.print(distance);
d = 2;
d2 = distance;
area = d1 * d2;
delay(100);
}
else if (d == 2) {
lcd.clear();
d = 0;
area = 0;
delay(100);
}
delay(500);
if (digitalRead(selectButton) == 0) {
program = 3;
d = 0;
lcd.clear();
delay(500);
}
}
break;
case 3:
Wire.beginTransmission(MPU);
Wire.write(0x3B);
Wire.endTransmission(false);
Wire.requestFrom(MPU, 6, true);
AcX = Wire.read() << 8 | Wire.read();
AcY = Wire.read() << 8 | Wire.read();
AcZ = Wire.read() << 8 | Wire.read();
if ( axis == 0) {
angle = atan(-1 * AcX / sqrt(pow(AcY, 2) + pow(AcZ, 2))) * 180 / PI;
lcd.setCursor(0, 0);
lcd.print("Pitch");
} else if (axis == 1) {
angle = atan(-1 * AcY / sqrt(pow(AcX, 2) + pow(AcZ, 2))) * 180 / PI;
lcd.setCursor(0, 0);
lcd.print("Roll ");
}
lcd.setCursor(0, 1);
lcd.print("Angle: ");
lcd.print(abs(angle));
lcd.print(" ");
lcd.setCursor(10, 1);
lcd.print("deg");
delay(200);
if (digitalRead(selectButton) == 0) {
if (axis == 0) { axis = 1; delay(100); }
else if (axis == 1) { axis = 0; delay(100); }
delay(500);
if (digitalRead(selectButton) == 0) {
program = 0;
lcd.clear();
delay(500);
}
}
break;
}
}
float getDistance() {
digitalWrite(trigPin, LOW);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
distance = duration * 0.034 / 2;
if (unitSelect == 1) { distance = distance; unit = "cm"; }
else if (unitSelect == 2) { distance = distance * 0.393701; unit = "in"; }
else if (unitSelect == 3) { distance = distance * 0.01; unit = "m"; }
else if (unitSelect == 0) { distance = distance * 0.0328; unit = "ft"; }
return distance;
}
É isso, espero que você tenha gostado deste projeto Arduino e aprendido algo novo. Sinta-se à vontade para fazer qualquer pergunta na seção de comentários abaixo.
Processo de manufatura
- Construa uma Estação de Comando DCC Digital para Ferromodelismo com Arduino – App Gratuito Incluído
- Dados Digital com Arduino: Gere Números Aleatórios 1-6 em LCD 16x2
- Crie Animações e Jogos Envolventes em LCD com Arduino UNO
- Detector de Frequência de Áudio com Arduino – Meça Picos de Som com Módulo de Alta Sensibilidade
- Construa Seu Próprio Tamagotchi com Arduino: Projeto DIY de Pet Digital
- Jogo da Velha com Arduino, Matriz LED MAX7219 e Caixa de Papelão
- Construa um Voltímetro DIY com Arduino e Display Nokia 5110 – Guia Passo a Passo
- Construa um Temporizador Regressivo Confiável com Arduino e Display de 7 Segmentos SparkFun
- Python 3 para Arduino UNO: Controle de Comandos Fácil e Demo com LED
- Construa um Rádio FM Compacto com Arduino Nano e RDA5807M