3 de julio de 2016

Midiendo distancias: el sensor ultrasónico

En esta entrada del blog veremos como usar la Raspberry Pi (RPi) junto con un sensor ultrasónico para medir la distancia a la que se encuentra algún objeto posicionado en frente de nuestro dispositivo.

El sensor ultrasónico que utilizaremos es el HC-SR04:

Sensor de distancia ultrasónico HC-SR04.

Este sensor es económico (tiene un precio comercial que oscila entre dos y cuatro dólares estadounidenses) pero bastante potente. Permite calcular distancias en un rango de 2 a 400 cm. y resulta relativamente fácil programarlo.

Un sensor ultrasónico funciona de manera similar a la capacidad de ecolocación que tienen ciertos animales tales como los murciélagos y delfines: el animal emite un sonido que rebota al encontrar un obstáculo; la distancia se estima a partir del tiempo que tarda en regresar el eco de la señal. El sonar que utilizan los submarinos para navegar en el océano está basado también en este mismo principio.

Ecolocación: el murciélago A genera un echo E que rebota
en la presa B generando una onda reflejada R. Con eso el
murciélago puede determinar la distancia d a su presa.
Imagen recuperada de: Wikimedia Commons.
 

Se dice que un sonido es ultrasónico cuando su onda tiene una frecuencia que se halla por arriba del espectro audible por el oído del ser humano, generalmente arriba de los veinte mil hertz.

El hardware

Además de un sensor HC-SR04 y una RPi (de cualquier generación) adecuadamente equipada y configurada, requeriremos los siguientes componentes de hardware:
  • Un protoboard
  • Dos resistencias R1 y R2 (ver discusión posterior)
  • Cables conectores

Vista esquemática del sensor HC-SR04.

El sensor HC-SR04 cuenta con cuatro pines:
  • VCC: Alimentación de 5 voltios
  • TRIG: Trigger o activador (entrada) del sensor
  • ECHO: Eco (salida) del sensor
  • GND: Tierra
Es importante mencionar que la señal de salida ECHO del HC-SR04 es de 5V. Esto hace que el sensor sea compatible con Arduino y otras plataformas de microcontroladores. Sin embargo, para la RPi los pines GPIO de entrada son de 3.3V. Si se envía una señal de 5V a un puerto desprotegido de entrada de 3.3V, éste puede resultar dañado, y eso es algo que definitivamente queremos evitar. Necesitaremos usar un circuito divisor resistivo para disminuir el voltaje de salida del sensor y así permitir que la RPi reciba la señal correspondiente sin problemas.

Un divisor resistivo consiste de dos resistencias (R1 y R2) en serie conectadas a un voltaje de entrada (Vin), el cual debe ser reducido a un voltaje de salida (Vout). En nuestro circuito, Vin corresponderá al pin ECHO, el cual requiere disminuir de 5V al Vout que necesitamos de 3.3V. El siguiente esquema muestra la disposición que deben tener las resistencias:


Un divisor resistivo se define a partir de la siguiente fórmula:


Sabemos que Vin = 5V y Vout = 3.3V. Por tanto lo que nos interesa calcular es:


Despejando tenemos:


Si conocemos el valor de la resistencia R2 podemos calcular directamente la resistencia R1. Por ejemplo, si R2 = 2kΩ, R1 tendría que ser igual a 1030.303Ω o algún otro valor cercano (por ejemplo 1kΩ).

La siguiente figura, elaborada en Fritzing, muestra la manera de conectar todos nuestros componentes:

Vista de protoboard Fritzing de un sensor HC-SR04 conectado a la RPi.

Las conexiones son las siguientes:
  • El pin VCC del sensor se conecta a cualquier pin de 5V de la RPi.
  • El pin TRIG del sensor se conecta al pin GPIO 23 de la RPi.
  • El pin GPIO 24 de la RPi se conecta a una pista disponible del protoboard. Un extremo de la resistencia R2 se conecta a esta pista, y el otro extremo se conecta a tierra (cualquiera de los pines GND de la RPi). Un extremo de la resistencia R1 se conecta también a esta pista, y el otro extremo se conecta al pin ECHO del sensor.
  • El pin GND del sensor se conecta a tierra (cualquiera de los pines GND de la RPi).

Vista física del sensor ultrasónico de distancias
colocado en el protoboard con sus respectivos
cables conectores.

El software

Para controlar el sensor y realizar las mediciones debemos efectuar lo siguiente:
  1. Poner TRIG en bajo durante dos segundos con el fin de estabilizarlo.
  2. Poner TRIG en alto por 10µs (diez microsegundos) y ponerlo inmediatamente después en bajo. En este momento el sensor envía 8 pulsos ultrasónicos de 40kHz y coloca ECHO en alto. Es necesario detectar cuando ocurre esto último para comenzar a medir el tiempo en ese preciso instante.
  3. ECHO se mantiene en alto hasta que reciba el eco reflejado por algún obstáculo. En ese momento ECHO se pone en bajo y significa que hay que terminar la medición del tiempo.
  4. A partir de la medición de tiempo obtenida ya podemos calcular la distancia como se discute a continuación.
Sabemos que la velocidad v es igual a distancia d entre tiempo t:


Despejando la distancia d, tenemos que ésta es igual a la velocidad v multiplicada por el tiempo t:


La velocidad que usaremos aquí es la del sonido, que es de 34,300 centímetros por segundo. Al final necesitamos dividir a la mitad el valor resultante debido a que nuestra medición corresponde al tiempo que tarda el pulso ultrasónico en llegar al obstáculo y regresar nuevamente al sensor.


En esta última fórmula, el tiempo t debe estar en segundos y la distancia resultante d en centímetros.

Con todo lo anterior tomado en cuenta, ya estamos en condiciones de escribir un programa en Python que controle un sensor ultrasónico HC-SR04. El código debe comenzar con las inicializaciones y configuraciones necesarias, similares a las que se explican detalladamente en la entrada titulada El LED parpadeante.

El programa completo en Python 2.7 se muestra a continuación:
# coding: utf-8

# Archivo: ultrasonico.py

# Importar las funciones necesarias de los módulos RPi,
# y time.
import RPi.GPIO as GPIO
import time

# Pin GPIO donde está conectado el activador (entrada) del
# sensor HC-SR04.
TRIG = 23

# Pin GPIO donde está conectado el eco (salida) del sensor
# HC-SR04.
ECHO = 24

# Indicar que se usa el esquema de numeración de pines
# de BCM (Broadcom SOC channel), es decir los números de
# pines GPIO (General-Purpose Input/Output).
GPIO.setmode(GPIO.BCM)

# Establecer que TRIG es un canal de salida.
GPIO.setup(TRIG, GPIO.OUT)

# Establecer que ECHO es un canal de entrada.
GPIO.setup(ECHO, GPIO.IN)

print "Medición de distancias en progreso"

try:
    # Ciclo infinito.
    # Para terminar el programa se debe presionar Ctrl-C.
    while True:

        # Apagar el pin activador y permitir un par de
        # segundos para que se estabilice.
        GPIO.output(TRIG, GPIO.LOW)
        print "Esperando a que el sensor se estabilice"
        time.sleep(2)

        # Prender el pin activador por 10 microsegundos
        # y después volverlo a apagar.
        GPIO.output(TRIG, GPIO.HIGH)
        time.sleep(0.00001)
        GPIO.output(TRIG, GPIO.LOW)

        # En este momento el sensor envía 8 pulsos
        # ultrasónicos de 40kHz y coloca su salida ECHO
        # en HIGH. Se debe detectar este evento e iniciar
        # la medición del tiempo.
        print "Iniciando eco"
        while True:
            pulso_inicio = time.time()
            if GPIO.input(ECHO) == GPIO.HIGH:
                break

        # La salida ECHO se mantendrá en HIGH hasta recibir
        # el eco reflejado por el obstáculo. En ese momento
        # el sensor pondrá ECHO en LOW y se debe terminar
        # la medición del tiempo.
        while True:
            pulso_fin = time.time()
            if GPIO.input(ECHO) == GPIO.LOW:
                break

        # La medición del tiempo es en segundos.
        duracion = pulso_fin - pulso_inicio

        # Calcular la distancia usando la velocidad del
        # sonido y considerando que la duración incluye
        # la ida y vuelta.
        distancia = (34300 * duracion) / 2

        # Imprimir resultado.
        print "Distancia: %.2f cm" % distancia

finally:
    # Reiniciar todos los canales de GPIO.
    GPIO.cleanup()
En una terminal necesitamos correr el siguiente comando para ejecutar nuestro programa:
sudo python ultrasonico.py
Mientras el programa se esté ejecutando se puede acercar y alejar algún objeto del sensor para ver si el programa funciona correctamente. Podemos usar una regla o cinta métrica para verificar los resultados. La salida del programa debe verse algo así:
Medición de distancias en progreso
Esperando a que el sensor se estabilice
Iniciando eco
Distancia: 79.30 cm
Esperando a que el sensor se estabilice
Iniciando eco
Distancia: 78.91 cm
Esperando a que el sensor se estabilice
Iniciando eco
Distancia: 79.70 cm
Esperando a que el sensor se estabilice
Iniciando eco
Distancia: 12.73 cm
Esperando a que el sensor se estabilice
Iniciando eco
Distancia: 12.49 cm
Esperando a que el sensor se estabilice
Iniciando eco
Distancia: 12.57 cm
Esperando a que el sensor se estabilice
Iniciando eco
Distancia: 78.82 cm
Esperando a que el sensor se estabilice
Es necesario presionar Ctrl-C para terminar el programa.