Tomo 9: Viendo con Sonido - Sensor Ultrasónico HC-SR04

¡¡Saludos, equipo de innovadores! Hoy vamos a darle a nuestro Arduino un súper poder digno de un murciélago o un submarino: la ecolocalización. No sólo mediremos distancias con el sensor ultrasónico HC-SR04, sino que también visualizaremos esos datos en tiempo real en una pantalla LCD, crearemos una respuesta física moviendo un servomotor, y mostraremos la proximidad en una barra de 8 LEDs que se llena y se vacía. ¡Construiremos un radar visual completo!

🧠 Protagonista de Hoy: El Sensor Ultrasónico HC-SR04

Este sensor es un pequeño sonar. Funciona emitiendo un pulso de sonido a una frecuencia tan alta que los humanos no podemos oírla (ultrasonido). Luego, espera y escucha el "eco" de ese sonido rebotando en un objeto de la siguiente manera:

¿Cómo funciona el viaje del sonido?

  1. Nosotros le ordenamos al pin Trig (Trigger o Disparador) que envíe un pulso de sonido corto.
  2. El sensor emite el pulso ultrasónico y, al mismo tiempo, pone en HIGH su pin Echo (Eco).
  3. El pin Echo se mantiene en HIGH hasta que el eco del sonido regresa al sensor tras rebotar con el obstáculo.
  4. El tiempo que el pin Echo estuvo en HIGH es exactamente el tiempo que tardó el sonido en ir y volver.

🔬 La Física del Asunto

Sabemos que el sonido viaja por el aire a una velocidad aproximada de 343 m/s (que equivale a 0.0343 cm/µs). Como el tiempo medido por el pin Echo contempla el viaje de ida y vuelta, debemos dividir el resultado entre 2 utilizando la siguiente ecuación fundamental:

Distancia (cm) = (Tiempo en HIGH (µs) × 0.0343) ÷ 2

🔌 El Circuito: Radar Visual Completo

Componentes Necesarios:

📝 Instrucciones de Conexión:

  1. Sensor HC-SR04: Conecta VCC a 5V, Trig al Pin Digital 3, Echo al Pin Digital 2 y GND a GND.
  2. Pantalla LCD (I2C): Conecta GND a GND, VCC a 5V, SDA al pin analógico A4 y SCL al pin analógico A5.
  3. Servomotor SG90: Cable café o negro a GND, cable rojo a 5V y el cable naranja o amarillo de señal al Pin Digital 5.
  4. Barra de 8 LEDs:
    • Coloca los 8 LEDs en fila sobre la protoboard.
    • Conecta la pata corta (Cátodo, $-$) de TODOS los LEDs al riel de GND común.
    • Conecta una resistencia de 220Ω a la pata larga (Ánodo, $+$) de cada uno de los LEDs.
    • Desde el otro extremo libre de cada resistencia, conecta un cable hacia los pines digitales de tu Arduino respetando de forma estricta este orden posicional:
      • LED 1 ➜ Pin 6
      • LED 2 ➜ Pin 7
      • LED 3 ➜ Pin 8
      • LED 4 ➜ Pin 9
      • LED 5 ➜ Pin 10
      • LED 6 ➜ Pin 11
      • LED 7 ➜ Pin 12
      • LED 8 ➜ Pin 13

⚡ Diagrama de armado

Diagrama Fritzing del Radar Visual Completo uniendo HC-SR04, LCD I2C, Servo SG90 y Barra de 8 LEDs

🧠 El Código: El Cerebro del Radar Visual

Este código integra todos los periféricos simultáneamente. Nota cómo la función matemática map() nos ayuda a transformar la distancia física de forma proporcional tanto para el ángulo del servo como para la cantidad de LEDs que se deben encender.

Código Arduino

/*
 * Tomo 9: Radar Visual de Proximidad
 * Descripción: Mide distancia, la muestra en LCD de manera estable, mueve un servo 
 * y controla una barra de 8 LEDs de forma proporcional e inversa.
 * Por: Profe Campos
 * CECyTEM 05 Guacamayas
*/

// --- LIBRERÍAS ---
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <Servo.h>

// --- PINES ---
const int pinTrig = 3;
const int pinEcho = 2;
const int pinServo = 5;
// Array para indexar los pines de los 8 LEDs secuenciales
const int pinesLeds[] = {6, 7, 8, 9, 10, 11, 12, 13};
const int numLeds = 8;

// --- OBJETOS ---
LiquidCrystal_I2C lcd(0x27, 16, 2);
Servo miServo;

// --- VARIABLES ---
long duracion;
int distancia;
int angulo;

void setup() {
  Serial.begin(9600);
  
  pinMode(pinTrig, OUTPUT);
  pinMode(pinEcho, INPUT);
  
  // Configurar automáticamente todos los pines de la barra de LEDs como salidas
  for (int i = 0; i < numLeds; i++) {
    pinMode(pinesLeds[i], OUTPUT);
  }
  
  miServo.attach(pinServo);
  
  lcd.init();
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print(" Radar Activado ");
  lcd.setCursor(0, 1);
  lcd.print("   CECyTEM 05   ");
  delay(1500);
  lcd.clear();
}

void loop() {
  // --- PASO 1: EMISIÓN Y RECEPCIÓN DEL PULSO ULTRASÓNICO ---
  digitalWrite(pinTrig, LOW);
  delayMicroseconds(2);
  digitalWrite(pinTrig, HIGH);
  delayMicroseconds(10); // Pulso de disparo obligatorio de 10 microsegundos
  digitalWrite(pinTrig, LOW);
  
  duracion = pulseIn(pinEcho, HIGH);  // Mide el tiempo en microsegundos que tarda en volver
  distancia = duracion * 0.0343 / 2;  // Conversión física a centímetros

  // --- PASO 2: DESPLIEGUE EN MONITOR SERIE Y LCD (SIN PARPADEO) ---
  Serial.print("Distancia: ");
  Serial.print(distancia);
  Serial.println(" cm");
  
  lcd.setCursor(0, 0);
  lcd.print("Radar de Control");
  lcd.setCursor(0, 1);
  lcd.print("Dist: ");
  lcd.print(distancia);
  lcd.print(" cm    "); // Espacios vacíos al final limpian caracteres fantasmas antiguos

  // --- PASO 3: CONTROL DE POSICIÓN DEL SERVO ---
  // Mapeamos distancias de 4 a 50 cm a un barrido angular de 0 a 180 grados
  angulo = map(distancia, 4, 50, 0, 180);
  angulo = constrain(angulo, 0, 180); // Asegura que el servo no reciba datos fuera de rango
  miServo.write(angulo);

  // --- PASO 4: CONTROL DE LA BARRA DE LEDS PROPORCIONAL ---
  // Mapeamos de forma inversa: a menor distancia (4cm), más LEDs encendidos (8)
  int ledsEncendidos = map(distancia, 50, 4, 0, numLeds);
  ledsEncendidos = constrain(ledsEncendidos, 0, numLeds);

  // Ciclo para prender o apagar cada LED de la barra según corresponda
  for (int i = 0; i < numLeds; i++) {
    if (i < ledsEncendidos) {
      digitalWrite(pinesLeds[i], HIGH); // Enciende si el índice entra en el rango de proximidad
    } else {
      digitalWrite(pinesLeds[i], LOW);  // Apaga los LEDs restantes
    }
  }

  delay(100); // Muestreo rápido cada 100 milisegundos para actualización ágil del radar
}

🚀 ¡Inténtalo Tú Mismo! (Retos)