arduino-radar-ultrasonidos-processing

Cómo construir un sonar de barrido con Arduino y Processing

  • 7 min

Todos hemos visto esa imagen clásica en las películas de submarinos: una pantalla verde, una línea que gira y un punto brillante (“blip”) que indica dónde está el enemigo.

Hoy vamos a construir exactamente eso: un radar de ultrasonidos con Arduino.

Este proyecto conecta dos mundos. Por un lado, el Hardware (Arduino moviendo un sensor y midiendo distancias). Por otro, el Software de PC (Processing), que recogerá esos datos y dibujará una interfaz gráfica en tiempo real.

De coordenadas polares a cartesianas

Tenemos un sensor de ultrasonidos montado sobre un servo.

  • El servo nos dice hacia dónde miramos: el Ángulo ().
  • El sensor nos dice cuán lejos está el objeto: el Radio (r).

Esto es un sistema de coordenadas polares . Sin embargo, para dibujar un punto en la pantalla de nuestro ordenador (que es una rejilla de píxeles), necesitamos coordenadas cartesianas .

Aquí es donde la trigonometría se convierte en nuestra mejor amiga:

El ordenador recibirá el par (ángulo, distancia) a través del cable USB, aplicará estas fórmulas y pintará un punto verde en la posición calculada.

Componentes

  • [1x|blue] Arduino Uno | El cerebro del proyecto
  • [1x|orange] Sensor Ultrasónico HC-SR04 | Mide distancias
  • [1x|green] Micro Servomotor (SG90) | Barrido del sensor
  • [1x|gray] Soporte para montar sensor sobre servo | Impresión 3D o cinta
  • [Varios|gray] Protoboard y cables | Conexiones flexibles para el sensor

Esquema de conexión

El montaje es sencillo, pero debemos asegurarnos de que los cables del sensor sean lo suficientemente largos o flexibles para permitir el movimiento de barrido del servo sin tiranteces.

Servo de barrido

El servo mueve el sensor de lado a lado. Si lo alimentas con fuente externa, une su GND con el de Arduino.

[ { “from”: “Servo Rojo (VCC)”, “to”: “Fuente externa regulada de 5V”, “color”: “red” }, { “from”: “Servo Marrón (GND)”, “to”: “GND Arduino”, “color”: “black” }, { “from”: “Servo Naranja (Señal)”, “to”: “Pin 12”, “color”: “green” } ]

Sensor HC-SR04

El sensor mide la distancia en cada posición angular del servo.

[ { “from”: “HC-SR04 VCC”, “to”: “5V Arduino”, “color”: “red” }, { “from”: “HC-SR04 GND”, “to”: “GND Arduino”, “color”: “black” }, { “from”: “HC-SR04 Trig”, “to”: “Pin 10”, “color”: “orange”, “note”: “Salida del Arduino” }, { “from”: “HC-SR04 Echo”, “to”: “Pin 11”, “color”: “yellow”, “note”: “Entrada al Arduino” } ]

Firmware de Arduino

El trabajo de Arduino es simple: Mover -> Medir -> Enviar. No va a calcular nada complejo, solo va a escupir datos crudos por el Puerto Serie.

El formato de envío es importante. Necesitamos que Processing entienda dónde acaba cada lectura. Usaremos una línea CSV por muestra: ángulo,distancia.

#include <Servo.h>

const int trigPin = 10;
const int echoPin = 11;
const int servoPin = 12;

Servo miServo;

void setup() {
  Serial.begin(9600); // Iniciamos comunicación Serie
  pinMode(trigPin, OUTPUT);
  pinMode(echoPin, INPUT);
  miServo.attach(servoPin);
}

void loop() {
  // Barrido de ida (de 15º a 165º)
  // Evitamos 0º y 180º porque el servo a veces tiembla en los extremos
  for(int i = 15; i <= 165; i++){  
    miServo.write(i);
    delay(30); // Damos tiempo al servo para llegar y estabilizarse
    
    int distancia = calcularDistancia();
    
    // Enviamos al PC: "angulo,distancia\n"
    Serial.print(i);
    Serial.print(",");
    Serial.println(distancia);
  }
  
  // Barrido de vuelta (de 165º a 15º)
  for(int i = 165; i > 15; i--){  
    miServo.write(i);
    delay(30);
    int distancia = calcularDistancia();
    
    Serial.print(i);
    Serial.print(",");
    Serial.println(distancia);
  }
}

int calcularDistancia(){ 
  digitalWrite(trigPin, LOW); 
  delayMicroseconds(2);
  digitalWrite(trigPin, HIGH); 
  delayMicroseconds(10);
  digitalWrite(trigPin, LOW);
  
  unsigned long duracion = pulseIn(echoPin, HIGH, 30000UL);

  // Sin eco dentro del tiempo máximo: fuera del rango visual
  if (duracion == 0) return 41;

  int distancia = duracion * 0.0343 / 2;
  
  // Limitamos la distancia máxima a 40cm para que se vea bien en pantalla
  // Si mide más, lo recortamos
  if (distancia > 40) distancia = 41;
  
  return distancia;
}
Copied!

Visualización con Processing

La visualización la haremos con Processing, un entorno creativo basado en Java y con una estructura parecida a la del IDE de Arduino.

  1. Descarga e instala Processing.
  2. Copia el siguiente código.

Este sketch lee el puerto serie, extrae el ángulo y la distancia, y dibuja una línea verde que se desvanece (estela) simulando el fósforo de los radares antiguos.

import processing.serial.*; // Importar librería Serie
import java.awt.event.KeyEvent; 
import java.io.IOException;

Serial myPort; 

String angle="";
String distance="";
String data="";

int iAngle, iDistance;
int index1=0;

void setup() {
  size(1200, 700); // Tamaño de la ventana
  smooth();
  // Busca tu puerto Arduino (normalmente es el primero o segundo de la lista)
  // Cambia el [0] si no te conecta
  myPort = new Serial(this, Serial.list()[0], 9600); 
  myPort.bufferUntil('\n'); // Una muestra por línea
}

void draw() {
  fill(0,4); // Relleno negro semitransparente para crear el efecto de desvanecimiento (trail)
  rect(0, 0, width, height);
  
  fill(98,245,31); // Color Verde Radar

  // Trasladamos el origen (0,0) al centro-abajo de la pantalla
  translate(width/2, height); 
  
  // --- DIBUJAR LÍNEAS DEL RADAR (ESTÉTICA) ---
  strokeWeight(2);
  stroke(98,245,31); // Verde
  noFill();
  // Arcos de distancia (10cm, 20cm, 30cm, 40cm)
  // Multiplicamos por ratio para escalar a la pantalla
  float pixelsPorCm = 15; 
  arc(0,0, 20*pixelsPorCm, 20*pixelsPorCm, PI, TWO_PI);
  arc(0,0, 40*pixelsPorCm, 40*pixelsPorCm, PI, TWO_PI);
  arc(0,0, 60*pixelsPorCm, 60*pixelsPorCm, PI, TWO_PI);
  arc(0,0, 80*pixelsPorCm, 80*pixelsPorCm, PI, TWO_PI);
  
  // --- DIBUJAR EL OBJETO DETECTADO ---
  // Convertimos coordenadas Polares a Cartesianas
  float pixDistance = iDistance * pixelsPorCm;
  
  // OJO: Processing usa radianes. Y el servo va de 15 a 165.
  // También invertimos el sentido porque Processing dibuja Y hacia abajo por defecto
  // pero hemos hecho translate/rotate. Simplifiquémoslo:
  
  float rads = radians(iAngle);
  
  // Si la distancia es menor de 40 (rango máximo), pintamos objeto
  if(iDistance < 40){
    // Matemáticas polares:
    // x = r * cos(theta)
    // y = r * sin(theta) -> Negativo porque en Processing Y crece hacia abajo
    float x = pixDistance * cos(rads);
    float y = -pixDistance * sin(rads); 
    
    strokeWeight(9);
    stroke(255,10,10); // Rojo para el objeto
    point(x, y);
  }
  
  // Línea de barrido (Scanner)
  strokeWeight(3);
  stroke(30,250,60);
  line(0,0, 40*pixelsPorCm * cos(rads), -40*pixelsPorCm * sin(rads));
}

// Evento que se ejecuta cuando llega una línea por USB
void serialEvent (Serial myPort) { 
  try {
    String linea = myPort.readStringUntil('\n');
    if (linea == null) return;
    data = trim(linea);
    
    // Buscamos la coma
    index1 = data.indexOf(",");
    
    // Partimos el string
    angle = data.substring(0, index1);
    distance = data.substring(index1 + 1, data.length());
    
    // Convertimos a enteros
    iAngle = int(angle);
    iDistance = int(distance);
    
    // Corregir la orientación del servo para que coincida con la pantalla
    // (Depende de cómo hayas montado el motor)
    iAngle = 180 - iAngle; 
    
  } catch (Exception e) {
    // Si llega basura por el puerto, la ignoramos
  }
}
Copied!

Cómo funciona la estela

Cuando ejecutes el programa, verás algo fascinante:

  1. La función draw() en Processing se ejecuta en bucle (como el loop de Arduino).
  2. Al poner fill(0, 4) y dibujar un rectángulo negro sobre toda la pantalla al principio de cada frame, lo que hacemos es “oscurecer un poquito” lo que había dibujado antes.
  3. Esto crea el efecto de estela. La línea verde del barrido actual brilla fuerte, pero la línea de hace 1 segundo se ve tenue.

Esto no es solo estético; nos permite ver la “historia” del barrido, tal y como lo hace el fósforo de una pantalla CRT de radar real.

Desafíos y mejoras

¿Te ha funcionado? Ahora te reto a mejorarlo:

  1. Reducir el campo de detección: El HC-SR04 integra ecos dentro de un haz relativamente ancho. Puedes probar un sensor óptico de tiempo de vuelo como el VL53L0X, teniendo en cuenta que mide de otra forma y también tiene límites de alcance y reflectividad.
  2. Detección de intrusos: Programa Processing para que si detecta algo a menos de 10cm, reproduzca un sonido de alarma (.wav) usando la librería de sonido.
  3. Radar 360: Modifica la mecánica para usar un anillo rozante (slip ring) y permitir giros completos, mapeando los 360 grados en la pantalla.