miércoles, 14 de agosto de 2013

Videocámara de seguridad motorizada

... aglutinando superpoderes

Hola de nuevo!. Como ya adelantaba en el post anterior, voy a explicar como instalar Motion para que además de hacer de cámara de seguridad, la mueva persiguiendo al evento de alarma. Previamente necesitamos:
- Raspicam
- Streaming desde la Raspicam
- Mutt
- Pi-blaster
- 2 Servos
- Brazo pan-tilt (puede ser suprimido con un poco de talento).

Lo primero aclarar, que esto es más una idea, que un proyecto completo. Funcionar funciona, pero cierto es que puede mejorarse. Lo ideal sería usar OpenCV, pero resulta que no tengo ni idea, lo he intentado pero no he conseguido nada aceptable. Si buscáis en youtube veréis gente que lo ha conseguido, pero sigo sus tutoriales y no funcionan.
Empecemos, antes de nada insisto:
- Raspicam funcionando (o una cámara con mjpeg encoding compatible).
- Mjpg-stgreamer en funcionamiento.
- 2 Servos y pi-blaster.
- Mutt para el envío de las alertas por mail.
- Tener al gatete controlado.

Arranque de la captura y el streaming

Antes de instalar, vamos a dejar la camera board en marcha:
sesion=$(date +%s)
mkdir /tmp/$sesion/
screen -dmS raspistil raspistill -w 640 -h 480 -q 10 -o /tmp/$sesion/pic.jpg -tl 100 -t 9999999 -th 0:0:0
screen -dmS streamer /usr/src/mjpg-streamer/mjpg-streamer/mjpg_streamer -i "/usr/src/mjpg-streamer/mjpg-streamer/input_file.so -f /tmp/$sesion/" -o "/usr/src/mjpg-streamer/mjpg-streamer/output_http.so -w /usr/src/mjpg-streamer/mjpg-streamer/www/"

Instalación de motion

Motion es el programa que nos permite generar alarmas y configurar las cámaras que tendrá nuestro sistema de seguridad. Para instalarlo no puede ser más fácil:
apt-get update
apt-get install motion
Configuraciones de Motion hay millones, os cuento la que me ha funcionado. Le hacemos una copia de seguridad al archivo /etc/motion/motion.conf y lo dejamos así:
daemon off
process_id_file /var/run/motion/motion.pid 
setup_mode off
v4l2_palette 8
input 8
norm 0
frequency 0
rotate 0
width 640
height 480 
framerate 10
minimum_frame_time 0
netcam_url value http://127.0.0.1:8080/?action=stream
netcam_tolerant_check off
auto_brightness off
brightness 0
contrast 0
saturation 0
hue 0
roundrobin_frames 1
roundrobin_skip 1
switchfilter off
threshold 1500
threshold_tune off
noise_level 32
noise_tune on
despeckle EedDl
smart_mask_speed 0
lightswitch 0
minimum_motion_frames 1
pre_capture 0
post_capture 0
gap 1
max_mpeg_time 0
output_all off
output_normal on
output_motion off
quality 90
ppm off
ffmpeg_cap_new off
ffmpeg_cap_motion off
ffmpeg_timelapse 0
ffmpeg_timelapse_mode daily
ffmpeg_bps 500000
ffmpeg_variable_bitrate 0
ffmpeg_deinterlace off
snapshot_interval 0
locate off
text_right %Y-%m-%d\n%T-%q
text_changes off
text_event %Y%m%d%H%M%S
text_double off
target_dir /tmp/motion
snapshot_filename %v-%Y%m%d%H%M%S-snapshot
jpeg_filename %v-%Y%m%d%H%M%S-%q
movie_filename %v-%Y%m%d%H%M%S
timelapse_filename %Y%m%d-timelapse
webcam_port 0
webcam_quality 50
webcam_motion off
webcam_maxrate 1
webcam_localhost on
webcam_limit 0
control_port 0
control_localhost on
control_html_output on
track_type 0
track_auto off
track_motorx 0
track_motory 0
track_maxx 0
track_maxy 0
track_iomojo_id 0
track_step_angle_x 10
track_step_angle_y 10
track_move_wait 10
track_speed 255
track_stepsize 40
quiet on
on_event_end /bin/bash /usr/local/bin/torreta.sh centro
on_picture_save /bin/bash /usr/local/bin/camara.sh aviso %f
on_motion_detected /bin/bash /usr/local/bin/camara.sh mover %i %J %K %L
sql_log_image on
sql_log_snapshot on
sql_log_mpeg off
sql_log_timelapse off
sql_query insert into security(camera, filename, frame, file_type, time_stamp, event_time_stamp) values('%t', '%f', '%q', '%n', '%Y-%m-%d %T', '%C')
Son casi todas las opciones por defecto, con unos pocos cambios. Fíjate bien, no te dejes ninguno. Presta especial atención a los scripts de los eventos, ya que son estos los que nos enviarán el email y moverán la cámara.

Control de servos

Como te habrás imaginado, Motion tiene sus propias configuraciones para mover las cámaras de seguridad, pero claro, sólo para modelos compatibles, no para modelos "yo me lo guiso, yo me lo como". En la configuración de Motion, usamos el script /usr/local/bin/torreta.sh es este:
#!/bin/bash
# programado por Juanmol para http://rsppi.blogpost.com
servo_horizontal=1
servo_pan=1
servo_vertical=0
servo_tilt=0
estado_pan=/tmp/estado_pan.log
estado_tilt=/tmp/estado_tilt.log
min=0.045
max=0.25
med=0$(echo 'scale=3;('$min'+'$max')/2'|bc)
salto=0.01
dev=/dev/pi-blaster

if [ -e /tmp/estado_pan.log ];
then
 pan=$(cat $estado_pan);
 tilt=$(cat $estado_tilt);
 case $1 in
  izquierda)
   if (( $(echo "$pan < 0.257" | bc -l) ));
   then
    pan=0$(echo 'scale=3;'$pan'+'$salto''|bc);
    echo $pan > $estado_pan;
   fi
  ;;
  derecha)
   if (( $(echo "$pan > 0.047" | bc -l) ));
   then
    pan=0$(echo 'scale=3;'$pan'-'$salto''|bc);
    echo $pan > $estado_pan;
   fi
  ;;
  arriba)
   if (( $(echo "$tilt > 0.067" | bc -l) ));
   then
    tilt=0$(echo 'scale=3;'$tilt'-'$salto''|bc);
    echo $tilt > $estado_tilt;
   fi
  ;;
  abajo)
   if (( $(echo "$tilt < 0.217" | bc -l) ));
   then
    tilt=0$(echo 'scale=3;'$tilt'+'$salto''|bc);
    echo $tilt > $estado_tilt;
   fi
  ;;
  centro)
   pan=$med
   tilt=$med
   echo $tilt > $estado_tilt
   echo $pan > $estado_pan
  ;;
 esac
else
 echo $med > $estado_tilt;
 echo $med > $estado_pan;
fi

#mover
pan=$(cat $estado_pan)
tilt=$(cat $estado_tilt)
echo $servo_pan=$pan > $dev
echo $servo_tilt=$tilt > $dev
Podemos usarlo así:
./torreta.sh arriba
./torreta.sh derecha
./torreta.sh izquierda
./torreta.sh abajo
./torreta.sh centro
Insisto que estas configuraciones son para mis servos, que son perrísimos, tendrás que comprobar cuales son los máximos y mínimos de los tuyos (son 30 segundos, no te asustes).

Control de alarmas

Motion es un poco tosco a la hora de generar los eventos, no permite hacer ajustes muy finos, pero si que devuelve mucha información. En la configuración de Motion llamamos al script /usr/local/bin/camara.sh que es este:
#!/bin/bash
# programado por Juanmol para http://rsppi.blogpost.com
echo se recibe $@ >> /tmp/prueba.log
area=$(echo $2*$3 | bc)
areamax=200000
ancho=640
alto=480
moversh=/usr/local/bin/torreta.sh
destinomail=EMAIL_DESTINO@gmail.com

case $1 in
 mover)
  if [ "$area" -lt "$areamax" ];
  then
   if [ "$4" -lt "$(echo $ancho/2 | bc)" ];
   then
    $moversh izquierda &
   else
    $moversh derecha &
  fi

   if [ "$5" -lt "$(echo $alto/2 | bc)" ];
   then
    $moversh arriba &
   else
    $moversh abajo &
   fi
  fi
 ;;
 aviso)
                if [ "$area" -lt "$areamax" ];
                then
   echo "$(date)" | mutt -s "Alarma detectada" $destinomail -a $2
  fi
 ;;
esac
¡¡OJO!! esos valores son para trabajar con la camera board con resolución 640x480, si quieres usar 1080p tendrás que reajustar un poco.
La idea del script es descartar aquellos eventos en los que la cantidad de píxeles que han provocado la alarma sea muy grande. Esto tiene sentido cuando tenemos la cámara en interior y hay cambios en la iluminación. Además ten en cuenta que cuando la cámara se mueve, la imagen que captura es 100% distinta, por lo que tampoco nos interesa que nos genere una alarma por eso.

Resultado

Por si no te queda claro para que es todo esto, te pongo un vídeo (lo siento de nuevo por la calidad):

Tendrás mucho mejor resultado si cámara está en el techo o al menos a altura humana. Y por supuesto a cierta distancia de la posible alarma.
Finalmente puedes hacer un script que lo ejecute todo /usr/local/bin/seguridad.sh
#!/bin/bash
# programado por Juanmol para http://rsppi.blogspot.com
sesion=$(date +%s)
mkdir /tmp/$sesion/
screen -dmS raspistil raspistill -w 640 -h 480 -q 10 -o /tmp/$sesion/pic.jpg -tl 100 -t 9999999 -th 0:0:0
screen -dmS streamer /usr/src/mjpg-streamer/mjpg-streamer/mjpg_streamer -i "/usr/src/mjpg-streamer/mjpg-streamer/input_file.so -f /tmp/$sesion/" -o "/usr/src/mjpg-streamer/mjpg-streamer/output_http.so -w /usr/src/mjpg-streamer/mjpg-streamer/www/"
screen -dmS motion motion

Bonus: ¡¡cuidado con el gatete!!

Cuando los servos se mueven, hacen ruido ... un poco. Cabe la posibilidad de que a tu gato le llame la atención el ruido ...
... puede que el gatete sea un poco curioso ...
... puede que se aburra ...
... puede incluso que sea un gato ninja! ...
... el mio además de curioso y ninja ... no le gusta la cámara ...
... y no paró hasta que la tiró al suelo ...

26 comentarios:

  1. No consigo que motion me vaya bien, me manda mil falsas alarmas por el cambio de luz.

    ResponderEliminar
    Respuestas
    1. eso es tuneable, como todo el motion. Hay un parametro que configuras entre 0 y 99 que te controla eso, es el lightswitch, ve subiendolo hasta que no te envie los falsos positivos. Creo que era ese parametro.

      Eliminar
  2. Aun cambiando el lightswitch a 99 sigo teniendo muchas falsas alarmas. Como podría adaptar tus script para que segun el area detecta envie simplemente un mail con la captura?

    ResponderEliminar
    Respuestas
    1. ahora que lo veo de nuevo creo que tiene unos fallitos ... si, si que lo tiene, tengo que haber mezclado pruebas. Para que te resulte más facil, deja todo igual y cambia en el script camara.sh la parte del aviso:
      aviso)
      echo "$(date)" | mutt -s "Alarma detectada" $destinomail -a $2
      ;;
      No se como se ha colado el otro condicional o_O

      Eliminar
    2. no tengo muy claro como hay que dejarlo, asi?:

      case $1 in
      mover)
      if [ "$area" -lt "$areamax" ];
      then
      if [ "$4" -lt "$(echo $ancho/2 | bc)" ];
      then
      $moversh izquierda &
      else
      $moversh derecha &
      fi

      if [ "$5" -lt "$(echo $alto/2 | bc)" ];
      then
      $moversh arriba &
      else
      $moversh abajo &
      fi
      fi
      ;;
      aviso)
      if [ "$area" -lt "$areamax" ];
      then
      echo "$(date)" | mutt -s "Alarma detectada" $destinomail -a $2
      fi
      ;;
      esac

      Eliminar
    3. De esa manera me da el error "se esperaba una expresion entera".

      Eliminar
    4. no no, toca solo el case aviso) déjale solo la linea del mutt, olvídate del if:
      aviso)
      echo "$(date)" | mutt -s "Alarma detectada" $destinomail -a $2
      ;;

      Eliminar
    5. Tampoco me funciona, no manda alarma alguna

      Eliminar
    6. la línea:
      echo se recibe $@ >> /tmp/prueba.log
      ¿que te genera en el log?

      Eliminar
    7. log:
      se recibe /media/HDEX/Documentos/189-20130827130952-00.jpg
      es la carpeta donde se guardan las capturas

      Eliminar
    8. pues esta bien ¿as probado enviar correos desde la consola? sin el script.

      Eliminar
    9. Si, funciona perfectamente

      Eliminar
    10. o_O y si esa misma prueba que haces desde la consola la pones en el script?
      aviso)
      aqui la prueba que haces en la consola
      ;;

      Eliminar
    11. No me funciona. Pero aunq funcionara no le veo utilidad, simplemente pongo el comando en la configuracion del motion y listo. Lo que interesa es poder usar el tema de area detectada que usas para mover la camara con el mail, para que no salten falsas alarmas por luz.

      Eliminar
    12. es que verás ... yo tengo el lightswitch muy bajo y lo que hago para descartar falsas alarmas es descartar aquellas cuya cantidad de pixeles modificados en la imagen es superior a cierto valor, en torno al 90% del ANCHOxALTO de la imagen, pero esto lo hago desde el script, en la parte de mover. Tambien es cierto que esto esta calibrado para la raspicam, no se cual usas tu, lo mismo es demasiado sensible a la luz o se recalibra en cada captura, lo cual fastidia el invento.
      Lo principal es tener el área modificada en un script y la captura en si misma en otro script, o como tengo puesto yo, un único script y ejecutas cada parte segun el primer parámetro que le llega. Si no te es urgente, puedes esperar un poquin que tengo preparados otros post con motion, a ver si lo ves más claro.

      Eliminar
    13. ok, espero pues, a ver si le puedo sacar punta

      Eliminar
  3. He probado al pie de la letra pero en algun paso o algo he metido la pata, me sale que no encuentra /dev/video0, tengo la camara oficial de raspberry influye eso?

    un saludo

    ResponderEliminar
    Respuestas
    1. Hola ... permíteme que dude de eso de "al pie de la letra", algún paso te as saltado, porque yo tambien uso la raspicam y desgraciadamente no hay /dev/video0 con este dispositivo :-/

      Eliminar
    2. lo único que varia en mi proceso es que he descargado mjpge desde otro sitio ya que cuando intento bajar con la url que pusiste se ve que ha cambiado de dirección y la bajé de la oficial pero con otra url .... igual es eso
      te juro que en cuanto me funcione todo a la perfección hago un script de autoinstalación asi no dará lugar a fallos jejeje
      por cierto yo también probé openVC pero la verdad es que para derección de caras por ejemplo debe ser en blanco y negro y no me hace gracia perder el color en pleno siglo 21 jeje voy a hacer pruebas a ver que tal a ver si consigo que rule :) por cierto... los servos no te van a saltos?? a mi me tiemblan muchísimo, también son malos, del deal extreme

      Eliminar
  4. Hola buenas tardes, he intentado emular tu proyecto con mi raspberry y mi nueva camara pi que he comprado y despues de todo el timglado me da un error de que no puede abrir el dispositivo
    mientras ejecuto motion sale esto
    [0] Processing thread 0 - config file /etc/motion/motion.conf
    [0] Motion 3.2.12 Started
    [0] ffmpeg LIBAVCODEC_BUILD 3482368 LIBAVFORMAT_BUILD 3478785
    [0] Thread 1 is from /etc/motion/motion.conf
    [1] Thread 1 started
    [1] connect returned error: Operation now in progress
    [1] Failed to open camera - check your config and that netcamera is online
    [1] Failed to read first camera header - giving up for now
    [1] Could not fetch initial image from camera
    [1] Motion continues using width and height from config file(s)
    [1] Resizing pre_capture buffer to 1 items
    [1] Started stream webcam server in port 8001
    [1] Retrying until successful connection with camera
    [1] Error reading first header - re-trying
    [1] Error reading first header - re-trying
    [1] Failed to read first camera header - giving up for now
    [1] Retrying until successful connection with camera
    y asi sucesivamente....
    puedes ayudarme o mejor subeme una imagen de tu sd ya compiladito todo ajajajjaja
    a ver si rula en casa jejejee

    ResponderEliminar
  5. hay no perdona es que tengo todos los post tuyos abiertos para seguir el orden
    es de este Videocámara de seguridad motorizada
    te lo pregunto esta vez en el post correcto

    Hola que tal? estoy siguiendo tu tutorial para montar la camara pi oficial con el pan tilt por ahora tengo los servos que funcionan y tal pero tengo una duda dices que hay que graduarlos los tuyos a 30... no entiendo bien eso me lo puedes explicar??? gracias yo me compre los servos y y pan tilt en un pack del dealextreme.
    Por otro lado he intentado hacer la guia de mjpg-stremer pero la url ha cambiado y los paquetes tambien por lo que al seguir esa guia no llego a buen puerto, supongo que es por que ha cambiado todo el escenario del mjpg no?
    gracias y a ver si me puedes tirar un cable que estoy a medias :)

    ResponderEliminar
    Respuestas
    1. creo que ya te entiendo, te refieres a lo de:
      "Insisto que estas configuraciones son para mis servos, que son perrísimos, tendrás que comprobar cuales son los máximos y mínimos de los tuyos (son 30 segundos, no te asustes)."
      ¿verdad? lo que vengo a decir es que tienes que ver cuales son los valores maximos y minimos que puede recibir un servo, que tardas 30 segundos en comprobarlo :)

      en mi caso son las variables:
      min=0.045
      max=0.25
      ¿como lo he probado? facil, le vas dando valores a un servo con (del post anterior):
      echo "0=0.045" > /dev/pi-blaster
      movemos el servo 0 a la posicion 0.045, si ahora ejecutas:
      echo "0=0.040" > /dev/pi-blaster
      en mi caso, no se mueve, por lo tanto 0.045 es el valor MINIMO que admite mi servo. Hacemos lo mismo para el máximo.
      Me imagino que tienes un servo de los buenos, de estos que se usan para coches de RC, tendras unos valores muy distintos, por eso hay que "calibrar" el código.
      ¿era esa tu pregunta?

      Eliminar
    2. Si exacto! eso es, vale pues voy a probar a ver si tengo los valores correctos o igual no, supongo que tendré que empezar por los bajos y ir probando si se mueve si no se mueve ir algo mas alto y asi hasta que rule..
      mil gracias tio me hace mucha ilusión :)

      Eliminar
  6. Hola a todos! yo soy muy muy nuevo en esto. A mi el fallo que me da es que no reconoce el comando bc.
    Muchas gracias Juan Mol por tu trabajo!

    ResponderEliminar
    Respuestas
    1. bc es una calculadora en linea de comandos, tienes que instalarla:
      apt-get install bc
      así de fácil ;)

      Eliminar
  7. q tal, te cuento q tengo un problema con el script de camara cuando lo ejecuto me da: (standard_in) 1: syntax error

    ResponderEliminar