Ejercicio 02 — Medir la distancia a un objeto con el ultrasonidos HC-SR04 y…
Dificultad: amarillo · Módulo 06 (Sensores comunes)
Enunciado
Medir la distancia a un objeto con el ultrasonidos HC-SR04 y mostrarla por Serial.
Montaje (Arduino UNO)
HC-SR04 (VCC→5V, TRIG→pin 9, ECHO→pin 10, GND→GND) Librería: ninguna (medimos el eco con pulseIn)
Cómo se resuelve
Este sensor no mide distancia: mide tiempo. La distancia la calculas tú. El HC-SR04 emite un chasquido de ultrasonido, ese sonido rebota en el primer objeto que encuentra y vuelve, y el sensor cronometra el viaje completo. Todo el ejercicio consiste en pedirle que dispare, cronometrar y convertir microsegundos en centímetros.
Y fíjate en lo primero de la cabecera: no hay librería. El HC-SR04 no habla ningún protocolo raro, solo maneja dos pines digitales, así que se resuelve entero con funciones que Arduino ya trae. Compáralo con el ejercicio anterior: la librería no es un requisito de “los sensores”, es un requisito de los sensores que hablan en clave.
Los dos pines tienen papeles opuestos y por eso se configuran distinto:
const int TRIG = 9; // salida: por aquí ordenamos disparar
const int ECHO = 10; // entrada: por aquí vuelve el ecoEn setup(), TRIG va a OUTPUT y ECHO a INPUT, además del Serial.begin(9600) de siempre. Que uno sea salida y otro entrada es justo la razón por la que cruzarlos es tan fácil y tan silencioso: si intercambias los cables el programa compila, sube y se ejecuta sin una sola queja, pero las lecturas salen 0 o disparatadas. Cuando un ultrasonidos da 0 cm sin parar, revisa que TRIG esté en el pin 9 y ECHO en el 10 antes de tocar el código.
El disparo es la parte que parece ritual y no lo es:
digitalWrite(TRIG, LOW);
delayMicroseconds(2);
digitalWrite(TRIG, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG, LOW);Lo que el sensor espera es un pulso en HIGH de 10 microsegundos en TRIG. Los dos microsegundos en LOW de antes son limpieza: garantizan que la línea parte de un estado bajo conocido, para que el flanco de subida siguiente sea nítido y no dependa de en qué estado quedara el pin en la vuelta anterior del bucle. Aquí aparece delayMicroseconds en vez de delay simplemente porque delay trabaja en milisegundos, y un milisegundo son mil microsegundos: la unidad más pequeña que sabe manejar es cien veces más larga que el pulso que necesitamos.
Después viene la medida:
long duracion = pulseIn(ECHO, HIGH);pulseIn se planta a mirar el pin ECHO y espera. El sensor pone ese pin en HIGH en el instante en que emite el chasquido y lo devuelve a LOW cuando recibe el eco, así que la duración de ese HIGH es exactamente el tiempo de vuelo. pulseIn la devuelve en microsegundos, y por eso la variable es long y no int: los microsegundos se acumulan rápido y un int en el UNO se queda sin sitio pasados 32767, que son apenas 33 milisegundos.
Ahora la fórmula, que conviene deducir en vez de copiar:
float distancia = duracion * 0.034 / 2;El sonido viaja a unos 340 metros por segundo. Pasado a las unidades de aquí, 340 m/s son 34000 cm/s, y como en un segundo hay un millón de microsegundos, salen 0,034 cm por microsegundo. Multiplicar los microsegundos medidos por 0,034 da los centímetros que recorrió el sonido. Pero ese recorrido es el de ida y vuelta: el sonido hizo dos veces el camino hasta el objeto. De ahí el /2.
Olvidar esa división es un error precioso porque el programa sigue pareciendo correcto: acercas la mano y el número baja, la alejas y sube, todo coherente. Solo que todas las medidas valen exactamente el doble. Es un fallo que ninguna prueba de “¿reacciona?” detecta y que solo aparece cuando comparas con una regla de verdad. Vale la pena que lo compruebes: mide algo a 20 cm y comprueba que el sensor dice 20 y no 40.
La distancia se guarda en float porque la división produce decimales y queremos conservarlos. Si fuera int perderías la parte fraccionaria en cada lectura.
El bloque de impresión es el patrón habitual, Serial.print para la etiqueta y el valor y Serial.println(" cm") para cerrar la línea. Y el loop() termina con delay(500), que aquí no es una restricción del sensor como lo eran los dos segundos del DHT22, sino una decisión de comodidad: sin ella el Monitor Serie se llenaría de líneas más rápido de lo que puedes leerlas. Dos lecturas por segundo se siguen bien con la vista. Puedes cambiarlo sin miedo; el HC-SR04 admite medir mucho más a menudo.
Una última cosa que el código no dice y conviene saber. pulseIn es bloqueante: mientras espera el eco, la placa no puede hacer absolutamente nada más. Y si no llega ningún eco, porque no hay nada delante o el objeto está demasiado lejos, pulseIn acaba rindiéndose y devuelve 0, lo que se traduce en una distancia de 0 cm que en realidad significa lo contrario, “infinito”. Es la ambigüedad que la pregunta de la teoría te propone resolver, y es un buen recordatorio de que un valor numérico correcto no siempre es un valor con sentido.
Para practicar — cópialo y complétalo
Pega este esqueleto y completa los TODO. Es la mejor forma de aprender: inténtalo antes de mirar la solución.
/*
* Curso de Arduino — Módulo 06: Sensores comunes
* Ejercicio 02 — PRÁCTICA (rellena los TODO)
* Enunciado: Medir la distancia a un objeto con el ultrasonidos HC-SR04 y mostrarla por Serial.
* Dificultad: amarillo
* Placa: Arduino UNO Montaje: HC-SR04 (VCC->5V, TRIG->pin 9, ECHO->pin 10, GND->GND)
* Librería: ninguna (medimos el eco con pulseIn)
* Correr: Arduino IDE / Wokwi (wokwi/ej02) / arduino-cli (ver README)
*/
const int TRIG = 9;
const int ECHO = 10;
void setup() {
// TODO: abre el serie a 9600
// TODO: configura TRIG como OUTPUT y ECHO como INPUT
}
void loop() {
// 1) Disparar el pulso por TRIG:
// TODO: TRIG en LOW, delayMicroseconds(2)
// TODO: TRIG en HIGH, delayMicroseconds(10)
// TODO: TRIG en LOW
// 2) Medir el eco:
// TODO: long duracion = pulseIn(ECHO, HIGH);
// 3) Calcular la distancia (en cm):
// TODO: float distancia = duracion * 0.034 / 2;
// TODO: imprime "Distancia: <valor> cm" por Serial
delay(500);
}Solución — cópiala y ejecútala
/*
* Curso de Arduino — Módulo 06: Sensores comunes
* Ejercicio 02 — MODELO (resuelto)
* Enunciado: Medir la distancia a un objeto con el ultrasonidos HC-SR04 y mostrarla por Serial.
* Dificultad: amarillo
* Placa: Arduino UNO Montaje: HC-SR04 (VCC->5V, TRIG->pin 9, ECHO->pin 10, GND->GND)
* Librería: ninguna (medimos el eco con pulseIn)
* Correr: Arduino IDE / Wokwi (wokwi/ej02) / arduino-cli (ver README)
*/
const int TRIG = 9; // disparamos el pulso de ultrasonido por aquí
const int ECHO = 10; // aquí llega de vuelta el eco
void setup() {
Serial.begin(9600);
pinMode(TRIG, OUTPUT);
pinMode(ECHO, INPUT);
}
void loop() {
// 1) Lanzar un pulso de 10 µs por TRIG
digitalWrite(TRIG, LOW);
delayMicroseconds(2);
digitalWrite(TRIG, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG, LOW);
// 2) Medir cuánto tarda ECHO en estar en HIGH = tiempo de ida y vuelta (en µs)
long duracion = pulseIn(ECHO, HIGH);
// 3) distancia = tiempo * velocidad_sonido / 2
// 0.034 cm/µs es la velocidad del sonido; /2 porque el sonido va y vuelve
float distancia = duracion * 0.034 / 2;
Serial.print("Distancia: ");
Serial.print(distancia);
Serial.println(" cm");
delay(500);
}Cómo ejecutar la simulación
Sin instalar nada, en el navegador
- Abre wokwi.com y crea un proyecto nuevo de la placa que pide el ejercicio.
- Pega la solución (o tu intento) en la pestaña
sketch.ino. - Abre la pestaña
diagram.json, borra lo que haya y pega el circuito de aquí abajo. - Dale al play. Verás el circuito funcionando: LEDs, pantallas y monitor serie.
Circuito del ejercicio (diagram.json)
{
"version": 1,
"author": "ESIBot",
"editor": "wokwi",
"parts": [
{ "type": "wokwi-arduino-uno", "id": "uno", "top": 0, "left": 0, "attrs": {} },
{ "type": "wokwi-hc-sr04", "id": "ultra", "top": -120, "left": 180, "attrs": {} }
],
"connections": [
[ "ultra:VCC", "uno:5V", "red", [ "v0" ] ],
[ "ultra:GND", "uno:GND.1", "black", [ "v0" ] ],
[ "ultra:TRIG", "uno:9", "green", [ "v0" ] ],
[ "ultra:ECHO", "uno:10", "blue", [ "v0" ] ]
],
"dependencies": {}
}En VS Code, con el repo del curso
El paquete de simulación de este ejercicio está en practica/06-sensores-comunes/wokwi/ej02/. Con la extensión Wokwi instalada y la licencia activada (lo cuenta el onboarding del curso):
make sim EJ=06-sensores-comunes/ej02y después, en VS Code, Ctrl+Shift+P → Wokwi: Start Simulator. La extensión no compila: simula un firmware ya compilado, y de compilarlo se encarga ese make.
Cómo usarlo
Con placa: abre el .ino en el Arduino IDE, elige placa y puerto y pulsa Subir. Sin placa: simulalo en Wokwi con cualquiera de las dos vias de arriba. Antes de mirar la solucion, intenta completar tu el esqueleto: es la mejor forma de aprender.