Medir distancia con Arduino y sensor de ultrasonidos HC-SR04

En esta entrada vamos a ver cómo utilizar el sensor de ultrasonidos HC-SR04 para medir distancias con un error de medida inferior a 0.5cm orientado a estimar la altitud de vuelo de nuestro drone, aunque sirve para cualquier aplicación. A continuación, os explico cómo utilizar este sensor para estimar la altitud de vuelo. El sensor que he utilizado es el siguiente:

Comprar sensor HC-SR04 en Amazon

Si habéis logrado construir el drone y hacerlo volar de forma estable, os habréis dado cuenta de que controlar el throttle no es tan fácil como parece. El propio control de estabilidad del drone decide que motores acelerar/decelerar para mantenerlo estable en todo momento, por lo que si no controlamos el throttle adecuadamente la altitud de vuelo del drone puede oscilar bastante. Para solucionar esto vamos a implementar la solución de altitude hold o control de altitud, añadiendo un nuevo controlador PID que controle la altitud de vuelo en todo momento y ajuste el throttle de forma automática para mantener el drone a una altura constante y sin oscilaciones. Para obtener lecturas de la altitud de vuelo en tiempo real vamos a utilizar el sensor HC-SR04.

El sensor HC-SR04

El principio de funcionamiento del sensor el muy simple. El sensor dispone de dos transductores, básicamente, un altavoz y un micrófono. Cuando recibe una orden de disparo, el ‘altavoz’ envía un impulso sonoro de alta frecuencia (ultrasonidos) que rebota con cualquier objeto que se encuentre en el camino. El eco de este impulso es captado nuevamente por el sensor (por el micrófono). Finalmente, el sensor que genera a la salida un pulso proporcional al tiempo que ha tardado el impulso en rebotar con el obstáculo y volver.

Curiosidad: nuestro oído, que no deja de ser un sensor que capta ondulaciones en el aire, es capaz de percibir impulsos sonoros de entre 20Hz y 20Kz (aunque a medida que nos hacemos mayores esta franja se hace más estrecha). De ahí que la ráfaga de 40kHz que envía el sensor de ultrasonidos no podamos escucharla. Los perros en cambio pueden captar sonidos de hasta 67kHz, por lo que ellos si escucharán los impulsos enviados por el sensor.

El sensor dispone de 4 pines para su conexionado. Vcc/GND para la alimentación, Trg (entrada) donde ordenaremos al sensor que envié un impulso sonoro, y Echo (salida) donde el sensor generará una señal proporcional a la distancia recorrida (ida y vuelta).

Según el datasheet del sensor de ultrasonidos, para lanzar un impulso sonoro tendremos que generar un pulso de al menos 10uS en la entrada Trg sensor HC-SR04. Tras recibir esta orden, el sensor enviará una ráfaga de 8 pulsos sonoros de 40 kilohercios (de ahí que sean ultrasonidos) que serán los que rebotarán en los objetos que haya en el camino y regresarán al sensor. Finalmente, el sensor genera un impulso en su salida Echo proporcional al tiempo que a tardado el sonido en hacer el viaje de ida y vuelta. Bastará con medir la duración de este pulso (dividirla entre dos) y calcular la distancia al objeto a partir de la velocidad del sonido.

La fórmula para calcular la distancia al obstáculo quedaría como se muestra a continuación. Utilizaremos la velocidad del sonido en el vacío (343m/s) para calcular la distancia recorrida en un tiempo determinado:

distancia al obstáculo (m) = 343 m/s * tiempo transcurrido (s) / 2

A efectos, la ecuación que tendremos que utilizar para programar en Arduino será la siguiente. El factor 0.01715 se calcula fácilmente cambiando las unidades a centímetros y microsegundos:

distancia al obstáculo (cm) = Duración pulso Echo (us) * 0.01715

HC-SR04 con Arduino

Como hemos visto en la entrada dedicada al Mando RC y su programación, necesitamos ejecutar loop principal de forma constante cada 6ms para mantener el drone estable. Esto hace que no sea posible utilizar la función PulseIn() que incorpora Arduino por tardar demasiado en hacer la lectura. Recordad que utilizando esta función Arduino quedará parado ahí, el tiempo que haga falta, a la espera de recibir el impulso y sin hacer nada más antes de continuar con la siguiente línea de código. Por ello, igual que en el caso del Mando RC, vamos a recurrir a las interrupciones hardware para detectar y medir el impulso recibido por el sensor, mientras seguimos ejecutando el loop principal en paralelo y sin interferir con el control de estabilidad.

El hardware y el conexionado necesario se muestran a continuación:

El código necesario para medir la altitud utilizando el sensor HC-SR04 e interrupciones hardware es el siguiente. Como veis, es bastante simple. Solo tened en cuenta que, para no causar interferencias ni errores de medida, no podemos enviar un impulso hasta que no hayamos recibido el eco del anterior. El datasheet del sensor recomiendo dejar una separación de 60ms entre impulsos para no crear interferencias, pero nosotros lo haremos de forma más eficiente, detectando cuando hemos recibido el eco del impulso anterior para enviar el siguiente. Para ello utilizaremos la variable initHC:

float altura, alturaFilt;
long loop_timer;
bool initHC = true;

// Interrupcion hardware para medir la duración del pulso Echo
volatile float PulsoAlt;
volatile long contAltInit;
void INTalt() {
  if (digitalRead(2) == HIGH) contAltInit = micros();
  if (digitalRead(2) == LOW) {
    PulsoAlt = micros() - contAltInit;
    initHC = true;
  }
}

void setup() {
  pinMode(2, INPUT_PULLUP); // Echo
  pinMode(A3, OUTPUT);      // Trg
  attachInterrupt(digitalPinToInterrupt(2), INTalt, CHANGE);
  Serial.begin(115200);
}

void loop() {
  while (micros() - loop_timer < 6000);
  loop_timer = micros();
  HCSR04();
  Serial.println(alturaFilt);
}

void HCSR04() {
  if (initHC == true) {
    alturaFilt = PulsoAlt * 0.01715; // Calcular distancia en función del ancho de pulso
    alturaFilt = alturaFilt * 0.8 + PulsoAlt * 0.01715 * 0.2;  // Filtro complementario
    analogWrite(A3, 255);  // Ponemos la salida A3 HIGH
    delayMicroseconds(10); // Esperamos 10us
    analogWrite(A3, 0);    // Ponemos la salida A3 LOW
    initHC = false;        
  }
}

Como veis, todo se hace de forma cíclica cada 6ms, igual que en control principal. He utilizado una salida analógica para enviar los pulsos por no tener entradas digitales disponibles en el drone, pero se puede hacer perfectamente con una salida digital.

Por último, es importante mencionar que estos sensores no pueden medir distancias superiores a 4m de forma precisa. A pesar de que el fabricante garantiza un rango de medida de hasta 4m, en la realidad es difícil obtener mediciones precisas a tanta distancia. Comprobad cual es el rango de medida de vuestro sensor haciendo pruebas con objetos a diferentes distancias.


Sin quieres saber como hacer un drone con Arduino paso a paso y desde cero, aquí os dejo todo lo necesario 🙂

Indice ‘Drone con Arduino desde cero’:

  1. Conceptos generales sobre drones
  2. Material necesario y montaje de los componentes hardware
  3. Mando RC y receptor. Programación en Arduino
  4. MPU6050 y su programación en Arduino
  5. Batería LiPo
  6. Control de estabilidad y PID
  7. Motores, ESC y su programación en Arduino
  8. Calibración de hélices y motores
  9. Software completo y esquema detallado
  10. Probando el software completo antes de volar
  11. Como leer variables de Arduino en Matlab
5/5 - (1 voto)

Añadir un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *