Un sensor de aparcamiento es un sistema que mide la distancia a un obstáculo y avisa de su proximidad mediante señales luminosas o acústicas.
Si en el proyecto del semáforo aprendimos a controlar tiempos, aquí vamos a aprender a medir el mundo físico. No nos limitaremos a encender una luz; nuestro Arduino tendrá que enviar una señal, esperar a que rebote y, basándose en el tiempo que ha tardado, calcular con precisión la distancia a un obstáculo.
Este proyecto es la introducción perfecta a la física de ondas y al uso de sensores de tiempo de vuelo (Time of Flight), principios que se usan desde en submarinos (sonar) hasta en los sensores LiDAR más avanzados.
Cómo medimos la distancia con sonido
Para este proyecto usaremos el omnipresente sensor HC-SR04. Este componente es, en esencia, un pequeño murciélago electrónico.
Su funcionamiento se basa en la ecolocalización. El sensor tiene dos “ojos” (que en realidad son transductores):
- Emisor (Trig): Emite una ráfaga de ultrasonidos a 40 kHz (inaudible para el ser humano).
- Receptor (Echo): Escucha y espera a recibir el rebote de esa onda.
El principio físico es la cinemática básica. Sabemos que la velocidad es espacio partido por tiempo (v = e / t). Como conocemos la velocidad del sonido en el aire y podemos medir el tiempo, despejamos la distancia.
¿Por qué dividimos entre 2? ¡Crucial! El sonido tiene que ir hasta el obstáculo y volver al sensor. El tiempo que medimos es el del viaje de ida y vuelta. Si no dividimos entre 2, estaríamos calculando el doble de la distancia real.
La velocidad del sonido es aproximadamente 343 m/s (a 20°C).
Para facilitar los cálculos en el microcontrolador (que trabaja en microsegundos,
Componentes
Vamos a construir un sistema completo: medición (sensor) y aviso (zumbador + LEDs).
- [1x|blue] Arduino Uno | El cerebro del proyecto
- [1x|orange] Sensor Ultrasónico HC-SR04 | Mide distancias por ultrasonidos
- [1x|purple] Zumbador (buzzer) activo | Aviso acústico
- [1x|green] LED Verde | Zona segura
- [1x|yellow] LED Amarillo | Precaución
- [1x|red] LED Rojo | Peligro inminente
- [3x|gray] Resistencia 220Ω | Limitan corriente de LEDs
- [Varios|gray] Protoboard y cables | Conexiones
Esquema de conexión
El HC-SR04 tiene 4 pines: VCC, Trig, Echo y GND.
Sensor HC-SR04
El sensor necesita alimentación a 5V y dos señales: Trig para lanzar el pulso, y Echo para medir cuánto tarda en volver.
[ { “from”: “HC-SR04 VCC”, “to”: “5V Arduino”, “color”: “red” }, { “from”: “HC-SR04 GND”, “to”: “GND Arduino”, “color”: “black” }, { “from”: “HC-SR04 Trig”, “to”: “Pin 9”, “color”: “orange”, “note”: “Salida del Arduino” }, { “from”: “HC-SR04 Echo”, “to”: “Pin 10”, “color”: “yellow”, “note”: “Entrada al Arduino” } ]
Buzzer de aviso
El buzzer se activa con los pitidos de proximidad.
[ { “from”: “Buzzer (+)”, “to”: “Pin 6”, “color”: “purple” }, { “from”: “Buzzer (-)”, “to”: “GND Arduino”, “color”: “black” } ]
LEDs indicadores
Los LEDs hacen de semáforo visual para distancia segura, precaución y peligro.
[ { “from”: “LED Rojo + 220Ω”, “to”: “Pin 3”, “color”: “red” }, { “from”: “LED Amarillo + 220Ω”, “to”: “Pin 4”, “color”: “yellow” }, { “from”: “LED Verde + 220Ω”, “to”: “Pin 5”, “color”: “green” }, { “from”: “Cátodos LED”, “to”: “GND Arduino”, “color”: “black” } ]
El código
Vamos a dividir el código en dos partes lógicas: la función que mide y la lógica que avisa.
Para medir el pulso, usaremos la función nativa pulseIn(), que espera a que un pin cambie de estado y cuenta cuánto tiempo ha pasado en microsegundos.
// --- Configuración de Hardware ---
const int pinTrig = 9;
const int pinEcho = 10;
const int pinBuzzer = 6;
// Pines para los LEDs (opcionales, pero recomendados)
const int pinLedVerde = 5;
const int pinLedAmarillo = 4;
const int pinLedRojo = 3;
// Constantes físicas
// Velocidad sonido / 2 = 0.0343 / 2 = 0.01715
const float VELOCIDAD_SONIDO = 0.01715;
void setup() {
Serial.begin(9600); // Para depurar por pantalla
// Configuración de pines
pinMode(pinTrig, OUTPUT);
pinMode(pinEcho, INPUT);
pinMode(pinBuzzer, OUTPUT);
pinMode(pinLedVerde, OUTPUT);
pinMode(pinLedAmarillo, OUTPUT);
pinMode(pinLedRojo, OUTPUT);
// Iniciamos con el Trigger apagado
digitalWrite(pinTrig, LOW);
}
El bucle principal y la lógica de aviso
En el loop, tomamos la medida. Según la distancia, haremos que el buzzer suene con diferentes frecuencias (como en un coche real: más cerca = pitidos más rápidos).
void loop() {
// 1. OBTENER DISTANCIA
long distancia = medirDistancia();
// Imprimimos para depurar (Debug)
Serial.print("Distancia: ");
Serial.print(distancia);
Serial.println(" cm");
// 2. LÓGICA DE AVISO (El "Beep Beep")
// Definimos umbrales de distancia
if (distancia < 10) {
// PELIGRO INMINENTE (< 10cm)
// Pitido continuo y luz roja
digitalWrite(pinBuzzer, HIGH); // Sonido continuo
encenderSemaforo(true, false, false); // Solo rojo
}
else if (distancia < 30) {
// PRECAUCIÓN (< 30cm)
// Pitidos rápidos y luz amarilla
alertaIntermitente(100); // Beep rápido
encenderSemaforo(false, true, false); // Solo amarillo
}
else if (distancia < 60) {
// ATENCIÓN (< 60cm)
// Pitidos lentos y luz verde
alertaIntermitente(300); // Beep lento
encenderSemaforo(false, false, true); // Solo verde
}
else {
// ZONA SEGURA (> 60cm)
digitalWrite(pinBuzzer, LOW); // Silencio
apagartodo();
}
delay(50); // Pequeña pausa para estabilidad
}
Funciones auxiliares
Aquí es donde encapsulamos la complejidad. La función medirDistancia realiza la secuencia estricta que requiere el sensor HC-SR04 para funcionar.
- Mandar un pulso de 10 microsegundos por el pin Trig.
- Escuchar el pin Echo.
- Aplicar la fórmula.
long medirDistancia() {
// 1. Generar pulso de disparo (Trigger)
digitalWrite(pinTrig, LOW);
delayMicroseconds(2);
digitalWrite(pinTrig, HIGH);
delayMicroseconds(10); // El pulso debe durar al menos 10us
digitalWrite(pinTrig, LOW);
// 2. Medir el tiempo del eco
// pulseIn espera a que el pin se ponga HIGH y cuenta hasta que baja a LOW
unsigned long duracion = pulseIn(pinEcho, HIGH, 30000UL);
// 3. Convertir a distancia
// Si duracion es 0, es que no ha rebotado (fuera de rango)
if (duracion == 0) return 999;
return duracion * VELOCIDAD_SONIDO;
}
// Función para hacer el "Beep-Beep"
void alertaIntermitente(int velocidad) {
digitalWrite(pinBuzzer, HIGH);
delay(velocidad);
digitalWrite(pinBuzzer, LOW);
delay(velocidad);
}
// Helper para gestionar los LEDs limpiamente
void encenderSemaforo(bool r, bool a, bool v) {
digitalWrite(pinLedRojo, r ? HIGH : LOW);
digitalWrite(pinLedAmarillo, a ? HIGH : LOW);
digitalWrite(pinLedVerde, v ? HIGH : LOW);
}
void apagartodo() {
digitalWrite(pinLedRojo, LOW);
digitalWrite(pinLedAmarillo, LOW);
digitalWrite(pinLedVerde, LOW);
}
Análisis de problemas comunes
Es probable que al montar esto os encontréis con lecturas extrañas. Es normal, estamos trabajando con sonido en el mundo real.
- Rebotes falsos: Si el sensor apunta a una superficie blanda (como tela o una esponja), el sonido no rebota bien y el sensor “no ve” nada.
- Ángulos: Si la superficie está muy inclinada respecto al sensor, el sonido rebota hacia otro lado y nunca vuelve al receptor (como una bola de billar contra una banda).
- El bloqueo del código: La función
alertaIntermitenteusadelay. Esto significa que mientras pita, no mide. En un montaje más reactivo usaríamosmillis()para pitar y medir sin bloquear el procesador. - El tiempo de espera del eco: El tercer parámetro de
pulseIn()limita la espera a 30 ms. Sin este límite, una medición sin eco podría bloquear el programa durante mucho más tiempo.
Siguientes pasos
Este proyecto es la base de la robótica móvil. Un robot que no choca es, básicamente, este código montado sobre ruedas.
¿Te atreves a mejorarlo?
- Sustituye los LEDs por una Pantalla LCD que muestre la distancia exacta en centímetros.
- Usa la función
tone()en el buzzer para que el sonido sea más agudo cuanto más cerca esté el objeto, en lugar de solo cambiar la velocidad del pitido. - Intenta implementar la librería NewPing, que optimiza mucho la lectura y evita bloqueos si el sensor no recibe respuesta.