Después del parón del verano volvemos con un proyecto pequeñito. Después de añadir movimiento (Añadiendo movimiento: servos) descubrimos que podemos orientar la cámara en una habitación (Una cámara móvil), pero casi nunca vemos nada interesante (es difícil encontrar el momento adecuado).
Sentía curiosidad por ver cómo funcionaría un sensor de movimiento y decidí comprar un par de HC-SR04, que funcionan con ultrasonidos.
El objetivo es disparar una fotografía cuando alguien pase por delante de la cámara: para ello medimos la distancia al obstáculo que haya enfrente del sensor y cuando cambie tenemos que suponer que hay alguien o algo en la trayectoria.
Tras unas primeras pruebas con la Raspi el resultado no era satisfactorio: se obtienen medidas aproximadas (y relativamente sencillas de filtrar, eliminando los valores desvidados) pero que no resultaban apropiados para lo que teníamos pensado.
Se puede ver, por ejemplo, un tutorial en HC-SR04 Ultrasonic Range Sensor on the Raspberry Pi.
La conexión del sensor a nuestra raspi.
Parece que el problema de precisión tiene que ver con la medición del tiempo (que es lo que se usa para medir la distancia con este tipo de sensores: el tiempo que tarda en ir y volver hasta el obstáculo un frente de ondas sonoras), que no es muy preciso en la Raspberry con su GNU/Linux.
Afortunamdamente, teníamos a mano un Arduino y decidimos probar si era más adecuado. Esto nos permitiría:
– Medir distancias de manera más precisa.
– Aprender a comunicar la Raspberry y el Arduino.
Y, seguramente, abrir la puerta a nuevos proyectos.
El arduino conectado al sensor:
Siguiendo las pistas de HC-SR04 Ultrasonic Sensor fue fácil preparar el programita (sketch) de arduino y hacer las conexiones (se puede ver en sketch.ino en su versión actual, puede haber cambios después).
Efectivamente, la medición era mucho más precisa: de vez en cuando, manteniendo fijo el sistema hay una variación de un centímetro o dos. Pero eso no es un problema cuando tratamos de detectar la presencia de un objeto más o menos grande (como una persona) en la trayectoria porque debería haber una modificación de más de 20 cm.
Ahora había que comunicar el arduino con la Raspberry (para reaprovechar código existente y no tener que empezar de cero en el nuevo aparatito).
Parece que hay varias formas de comunicarlos: mediante un puerto serie sobre USB (Connect Raspberry Pi and Arduino with Serial USB Cable), mediante I2C (Raspberry Pi and Arduino Connected Using I2C) y mediante GPIO (Raspberry Pi and Arduino Connected Over Serial GPIO).
Elegí la primera porque me pareció la más sencilla de poner en funcionamiento (aunque no descarto probar las otras).
Lo que envía el arduino se puede leer fácilmente en la Raspberry como una entrada de texto y sólo tenemos que procesar adecuadamente:
distAnt=0
...
while 1:
distAnt = dist
dist = int(ser.readline().strip().strip())
if abs(distAnt-dist)>10:
print "Alert!!"
Esto es: conservamos la medición anterior (distAnt), obtenemos una nueva (dist = …) y si la diferencia es mayor que diez, lanzamos una alerta.
Como lo que queríamos hacer era una fotografía justo en ese momento, hemos reutilizado código de Una cámara en la Raspberry Pi y, siguiendo viejas costumbres, la envíamos por correo (Enviar una imagen por correo en Python).
El código puede verse en serialPicture.py.
Por la forma de enviar el mensaje esto dejaba el sistema inutilizado mucho tiempo: no podemos evitar el tiempo que consume la cámara (que no es despreciable tampoco) porque no queremos poner más de una; pero sí que podemos evitar la espera de la conexión al servidor de correo, y el envío de la imagen.
Esto lo conseguimos mediante la creación de un subproceso (ver multiprocessing) que se ocupa del envío.
camera(name,cam)
p = Process(target=mail, args=(name,who))
p.start()
Esto es, tomamos la foto y lanzamos un proceso hijo que se ocupa del envío.
No tenía experiencia con esta parte de Python y no estoy seguro de si hace falta terminar el proceso de alguna forma, pero como no hay que hacer sincronizaciones ni esperar a que termine para hacer otras cosas, parece que funciona razonablemente.
Para terminar: ninguno de los procesos es muy rápido; que nadie espere poder utilizar esto como ‘trampa’ para capturar el paso de un ave volando (o incluso un niño corriendo).
¿Qué podemos hacer ahora?
Podríamos embarcar el sensor de distancia en uno de nuestros motores (como en Una cámara móvil) y con ello hacer un ‘mapa’ de la habitación: se me ocurre que serviría para detectar cambios de otra forma diferente.
Otra cosa que se me ocurre es que, una vez que alguien o algo ha cruzado la ‘barrera’ podríamos hacer un barrido con la cámara móvil y tomar varias imágenes (o incluso grabar un vídeo; me está dando pereza, pero es algo que hay que probar).
Y, por supuesto, escuchar ideas de quien lea esto o buscarlas por ahí.
Todavía hay otro problema y es que el sensor funciona aunque no haya luz; tal vez podríamos añadir un sensor de luminosidad para evitar el disparo cuando sabemos que no se va a poder tomar una imagen (o, tal vez, iluminar la escena de alguna forma).