Construya un Telémetro Arduino y Nivel Digital – Guía Paso a Paso Fácil
En este tutorial aprenderemos a hacer un medidor de distancia Arduino y un nivel de burbuja digital. Puede ver el video siguiente o leer el tutorial escrito a continuación.
Resumen
El dispositivo incluye un sensor ultrasónico para medir distancia al objeto más cercano, un acelerómetro para medir ángulo respecto al suelo, una pantalla LCD para mostrar resultados y un PCB de diseño personalizado donde se conectan todos los componentes.
Se opera con un solo botón. Al encender, hay que seleccionar la unidad de medida.

Pulsando el botón cambiamos de unidad; manteniéndolo pulsado entramos en el primer programa: medición de distancia con capacidad de guardar las dos últimas mediciones.

Para el segundo programa, otra pulsación larga: medición de área cuadrada tomando dos distancias perpendiculares.

El tercer programa es el nivel digital: medición de ángulo respecto al suelo.

Con el botón alternamos entre los dos ejes (Pitch o Roll).
Esquema de Circuito del Telémetro Arduino

Tengo tutoriales detallados de cada módulo: Sensor ultrasónico, LCD, Acelerómetro MEMS.
Componentes necesarios:
- Sensor Ultrasónico HC-SR04
- Acelerómetro Giroscopio 3 Ejes MPU6050
- LCD Caracteres 16×2
- Arduino Nano
PCB de Diseño Personalizado
Según el esquema diseñé PCB personalizado en EasyEDA (software gratuito online).

Exportamos archivo Gerber para fabricación. Archivos del proyecto EasyEDA aquí.
Pedimos PCB a JLCPCB (patrocinador).

Subimos Gerber, revisamos en visor, seleccionamos propiedades y pedimos. Primer pedido: hasta 10 PCBs por $2.

Montaje del Dispositivo
Tras unos días llegaron los PCBs. Calidad excelente, todo coincide con el diseño.

Empecé soldando pines header en PCB para conectar/desconectar fácilmente.

Soldé tres resistencias: dos para divisor de tensión de contraste LCD (1k en R1, 220 ohm en R2), tercera pull-up para botón.
Hice la carcasa con acrílico transparente de 5 mm (tenía de proyecto anterior) para ver la electrónica. Sierra circular para cortar a medida.

Hice abertura para LCD en tapa superior (4 mm para mejor ajuste): dos agujeros con taladro, sierra de calar para abrir grosso, lima para líneas finas y ajuste perfecto.

Con broca Forstner hice huecos para interruptor alimentación, botón control y sensor ultrasónico.

Ensamblé con epoxi 5 min. Para la tapa, puse dos tornillos por donde se inserta panel superior y se asegura con tuercas.

Soldé headers al LCD, y jumpers a interruptor, botón y conector batería.

Montaje final: sensor ultrasónico en PCB y por huecos laterales; Arduino, acelerómetro, conector batería.

En tapa superior: LCD, interruptor, botón, conectados al PCB. Por último, batería 9V en conector y aseguré tapa con tuercas.

¡El proyecto telémetro Arduino y nivel digital está listo! Queda explicar el código.
Código Fuente: Telémetro Arduino y Nivel Digital
Al ser largo, publicaré en secciones con descripción. Al final, código completo.
Primero incluimos Wire.h (I2C acelerómetro) y LiquidCrystal.h (control LCD). Definimos LCD, dirección I2C MPU6050 (0x68), pines ultrasónico, y variables.
#include <Wire.h>
#include <LiquidCrystal.h>
LiquidCrystal lcd(7, 6, 5, 4, 3, 2); // (rs, enable, d4, d5, d6, d7)
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, d1 = 0, d2 = 0, area = 0;
int axis = 0, angle = 0;
int unitSelect = 0;
String unit = "cm";
En setup() inicializamos I2C del acelerómetro y LCD, y modos de pin.
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);
}
En loop() usamos switch para cambiar entre programas.
Caso 0: Seleccionar unidad de medida
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;
La variable unitSelect actúa en la función getDistance() para convertir la unidad base (cm) a la seleccionada.
// Conversión unidades en getDistance()
if (unitSelect == 1) { distance = distance; unit = "cm"; } // cm
else if (unitSelect == 2) { distance *= 0.393701; unit = "in"; } // pulgadas
else if (unitSelect == 3) { distance *= 0.01; unit = "m"; } // metros
else if (unitSelect == 0) { distance *= 0.0328; unit = "ft"; } // pies
Mantener botón >0,5s cambia a programa 1.
Caso 1: Programa medición distancia
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);
// Guardar distancia 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); }
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;
Función getDistance():
float getDistance() {
digitalWrite(trigPin, LOW);
digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW);
duration = pulseIn(echoPin, HIGH);
distance = duration * 0.034 / 2; // cm
// Conversión unidades (ver arriba)
return distance;
}
El sensor genera onda ultrasónica por pin trigger; pin echo mide tiempo de ida y vuelta con pulseIn(). Con velocidad del sonido y tiempo calculamos distancia. Mostramos en LCD y con botón guardamos últimas 2 mediciones.
Caso 2: Programa medición área
Tomamos dos mediciones perpendiculares y las multiplicamos para obtener área del rectángulo formado.
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;
Caso 3: Programa medición ángulo (Nivel digital)
Leemos datos del acelerómetro (fuerza gravedad en 3 ejes X,Y,Z). Cada eje usa 2 registros → leemos 6 registros y combinamos.
case 3:
Wire.beginTransmission(MPU);
Wire.write(0x3B); // Registro ACCEL_XOUT_H
Wire.endTransmission(false);
Wire.requestFrom(MPU, 6, true); // Leer 6 registros
AcX = Wire.read()<<8 | Wire.read();
AcY = Wire.read()<<8 | Wire.read();
AcZ = Wire.read()<<8 | Wire.read();
if (axis == 0) {
// Pitch (rotación eje Y)
angle = atan(-1 * AcX / sqrt(pow(AcY,2) + pow(AcZ,2))) * 180 / PI;
lcd.setCursor(0,0); lcd.print("Pitch");
} else {
// Roll (rotación eje 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);
// Cambiar eje con botón
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;
Con valores X,Y,Z calculamos Pitch (rotación eje Y) y Roll (rotación eje X) usando ecuaciones trigonométricas. Detalles en Freescale Semiconductor application note: Tilt Sensing Using a Three-Axis Accelerometer. Mostramos en LCD y con botón alternamos Pitch/Roll.
Código Completo
/* 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, d1 = 0, d2 = 0, area = 0;
int axis = 0, 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 { 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*=0.393701; unit="in"; }
else if (unitSelect==3) { distance*=0.01; unit="m"; }
else if (unitSelect==0) { distance*=0.0328; unit="ft"; }
return distance;
}
¡Eso es todo! Espero que hayan disfrutado este proyecto Arduino y aprendido algo nuevo. Pregunten en los comentarios.
Proceso de manufactura
- Central DCC Digital para Ferrocarril Modelo con Arduino y App Android Gratuita
- Proyecto Dados Digitales Arduino: Construye tu Propio Generador de Números Aleatorios con LCD
- Crea Animaciones y Juegos en LCD 16×2 con Arduino UNO
- Detector de frecuencia de audio con Arduino – Mide los picos de sonido más intensos
- Construye tu Propio Tamagotchi con Arduino: Mascota Digital DIY
- Tres en raya con Arduino, matriz LED MAX7219 y carcasa de cartón
- Construye un voltímetro DIY con Arduino y pantalla Nokia 5110 – Guía paso a paso
- Construye un Temporizador Regresivo Fiable con Arduino y Pantalla de 7 Segmentos SparkFun
- Control Arduino UNO desde Python 3 – Envío de Comandos y Demo LED
- Construye una Radio FM Compacta con Arduino Nano y RDA5807M
- Monitor de nivel de sumidero DIY con Arduino Nano, MPXV5010DP y pantalla OLED