Il y a quelques semaine, mon père a construit un nichoir pour les oiseaux :
Je lui ai alors proposé d’installer une caméra à l’intérieur pour voir ce qu’il s’y passe. Le cahier des charges du projet est le suivant :
- Alimentation 12 à 24 V DC,
- Connexion au réseau Wi-Fi de la maison,
- Une caméra avec microphone pour capturer la vidéo avec le son,
- Une barrière optique pour détecter le passage des oiseaux à travers le trou,
- Un éclairage infrarouge pour illuminer l’intérieur sans les déranger,
- Flux audio/vidéo disponible en direct,
- Enregistrement de la vidéo lorsqu’un oiseau entre ou sort,
- Possibilité d’être notifié par SMS de la disponibilité d’une nouvelle vidéo.
Partie matérielle
Caméra
Pour ce projet, j’étais initialement parti d’un module ESP32-CAM qui possède, comme son nom l’indique, un microcontrôleur 32 bits ESP32 associé à une caméra 2 mégapixels Omnivision OV2640. Malheureusement, aussi performant soit l’ESP32, il est quand même un peu limite pour traiter un flux vidéo complet. De plus, le module ne possède pas de microphone.
Je me tourne donc vers un Raspberry Pi Zero associé à une webcam USB, qui je pense permettra d’obtenir une meilleure fiabilité. La caméra de récupération est une Logitech Quickcam Fusion :
La première étape est de la démonter afin de retirer le filtre infrarouge présent sous l’objectif. En effet, la plupart des caméras qui ne sont pas expressément conçues pour réaliser de la vision nocturne sont équipées d’un filtre qui permet de rendre le capteur quasiment insensible à ces longueurs d’onde. Comme dans notre cas, le nichoir sera la plupart du temps plongé dans le noir et éclairé seulement en IR, cela serait problématique.
Il faut donc démonter la caméra et dévisser l’objectif. En bas à droite, on le voit bien avec son reflet violet, caractéristique de la présence du filtre :
Le filtre lui-même ressemble à un petit disque en verre d’un peu moins d’un millimètre d’épaisseur. Il faut le retirer en passant dessous une lame de cutter :
Comme la mise au point est réalisée en vissant ou en dévissant légèrement l’objectif, il ne faut pas oublier de l’ajuster après le remontage sous peine d’avoir une image floue. Il n’y a pas d’auto-focus sur cette caméra.
Puisque le Raspberry Pi Zero utilise un port micro-USB, j’en ai profité pour remplacer le câble USB-A d’origine par une version micro-B afin d’éviter d’avoir à utiliser un adaptateur. Sur cette photo de la caméra une fois modifiée, on observe qu’il n’y a plus les reflets violets sur la lentille depuis que le filtre IR a été supprimé :
Barrière optique
Pour détecter quand un oiseau entre (ou sort) du nichoir, le plus simple est d’installer une barrière optique. Un émetteur et un récepteur infrarouge sont placés de part et d’autre de l’entrée et lorsqu’un oiseau passe le trou, il coupe le faisceau.
Pour cela, une LED infrarouge est utilisée comme émetteur (à gauche) et un récepteur de télécommande type TSOPxxxx est placé en face (à droite) :
Pour canaliser un peu mieux la lumière, les composants sont recouverts d’un morceau de tube IRO coupé en deux dans le sens de la longueur :
La LED IR est pilotée avec un signal à 38 kHz et un rapport cyclique de 50% grâce à la fonction PWM du Raspberry Pi. Malheureusement, les essais n’ont pas été concluants pour deux raisons :
- Le récepteur de télécommande est fait pour recevoir ponctuellement des trames et ne supporte pas de recevoir en permanence une porteuse, ce qui est le cas ici lorsque la barrière n’est pas coupée.
- Il possède un contrôle automatique du gain très efficace pour recevoir les signaux même lorsque le signal émis par la télécommande est fortement atténué. Par conséquent, même lorsque le faisceau était bloqué, des fuites de lumière ou des réflexions arrivaient quand même à lui faire recevoir le signal.
Après avoir essayé un certain nombre de contournements logiciels, j’ai dû accepter que cette solution ne serait jamais fiable. Du coup, j’ai retiré ce système pour installer une cellule optique industrielle à la place (pas de photo, désolé).
Circuit imprimé
Le Raspberry Pi Zero est monté sur un morceau de circuit imprimé équipé des composants suivants :
- Des LEDs infrarouge pour l’éclairage,
- Un régulateur de tension 5V pour l’alimenter,
- Des connecteurs pour l’alimentation électrique et la connexion de la barrière optique.
Voilà le résultat :
Assemblage final
Il ne reste plus qu’à installer le tout à l’intérieur du nichoir. Il n’y a pas de difficulté particulière :
Et voilà le nichoir une fois installée ! L’alimentation électrique 24V est prélevée dans la cabane à droite :
La réalisation matérielle est maintenant terminée !
Partie logicielle
Diffusion de la vidéo
Pour diffuser la vidéo, VLC tourne en tâche de fond :
cvlc v4l2:///dev/video0:chroma=mjpg:width=640:height=480:fps=15 :input-slave=alsa://hw:1,0 --sout '#transcode{acodec=mpga,ab=128,channels=2,samplerate=44100,threads=1,audio-sync=1}:standard{access=http,mux=ts,mime=video/ts,dst=:8099}' &
Cette commande réalise un certain nombre d’actions :
- Elle récupère le flux vidéo MJPEG en provenance de la caméra, de dimensions 640×480 pixels à 15 images par seconde,
- Elle le combine au flux audio du microphone,
- Ce flux audio est compressé dans le format MPEG Audio,
- Le flux combiné audio + vidéo est intégré dans le conteneur MPEG Transport Stream (TS),
- Enfin, ce conteneur est mis à disposition via HTTP.
Le codec vidéo MJPEG n’est pas forcément le plus adapté à la diffusion sur Internet, mais la webcam, relativement ancienne, ne délivre que ce format-là (elle n’est pas capable de réaliser elle-même une compression type h264, contrairement aux caméras plus récentes). Comme le Raspberry Pi Zero n’est pas suffisamment performant pour réaliser celle-ci à la volée, on s’en contentera.
Accès aux entrées-sorties
Pour lire et écrire les entrées-sorties du Raspberry Pi, je vais pour une fois faire simple en utilisant le programme gpio fourni avec la bibliothèque WiringPi. En particulier, pour la lecture de l’état de la barrière IR, le mode « Wait for Interrupt » permet d’attendre un front (montant ou descendant) sur une broche quelconque sans consommer de ressources processeur.
Puisque j’ai remplacé la barrière optique à LED + récepteur de télécommande par la cellule industrielle, il n’est plus nécessaire de générer un signal modulé pour la LED et de filtrer le signal reçu en retour. Par conséquent, cette solution convient très bien.
Enregistrement lors de la rupture du faisceau
L’enregistrement de la vidéo lorsqu’un oiseau est détecté est à nouveau réalisé avec VLC. Le fichier est d’abord stocké sur la carte SD du Raspberry Pi puis copié sur un NAS du réseau local, préalablement monté avec le protocole cifs (protocole utilisé par les partages réseau de Windows).
Après avoir eu du mal à limiter la durée d’enregistrement avec VLC lui-même, je suis tombé sur le programme timeout qui permet de contourner le problème.
DATE_HEURE=`date +"(%Y-%m-%d_%H-%M-%S)"|tr -d "\n"`
timeout 30 cvlc http://127.0.0.1:8099 --sout "#transcode{acodec=mpga,ab=128,channels=2,samplerate=44100,threads=1,audio-sync=1}:standard{access=file,mux=ts,mime=video/ts,dst=/home/pi/videos/${DATE_HEURE}_nichoir.ts}}"
echo $DATE_HEURE "Fin enregistrement, début copie fichier"
mv /home/pi/videos/* /mnt/NAS/Nichoir
L’avantage de transférer les vidéos sur le NAS après leur capture permet d’y accéder par la suite sans être limité par la vitesse de la connexion Wi-Fi du Raspberry Pi, qui plafonne à guère plus de 2 Mo/s.
Envoi de SMS
Pour envoyer les SMS, j’utilise la passerelle SMS (bientôt un article à ce sujet !) que j’ai mise en place il y a un moment déjà. En résumé, il s’agit d’un module GPRS installé sur un autre Raspberry Pi associé à une API maison pour les envoyer grâce à une simple requête HTTP.
En ligne de commande, c’est donc cURL qui fait tout le travail :
/usr/bin/curl "https://mon_api/?numero=0601020304" -G --data-urlencode "texte=COUCOU"
Code complet
Pour résumer, le code complet est ci-dessous :
#!/bin/bash
# Damien FAVRE, mars 2021
# Script pour diffuser en streaming la vidéo d'une caméra placée dans le nichoir
# Basé sur https://stackoverflow.com/questions/49846400/raspberry-pi-use-vlc-to-stream-webcam-logitech-c920-h264-video-without-tran
#
# Lorsque la barrière IR est coupée, un enregistrement est lancé puis copié sur le NAS.
NUM_GPIO_BARRIERE=26 # GPIO du récepteur de la barrière IR
NUM_GPIO_ECLAIRAGE=4 # GPIO de l'éclairage infrarouge de la webcam
DUREE_ENREGISTREMENT="50s" # durée de l'enregistrement sous la forme "30s"
REPERTOIRE_TMP=/home/pi/videos # ne pas terminer par /
REPERTOIRE_ENREGISTREMENTS=Nichoir # ne pas terminer par /
POINT_MONTAGE=/mnt/NAS # ne pas terminer par /
###############################################
# Création d'une fonction pour envoyer un SMS #
###############################################
sms() {
/usr/bin/curl "https://mon_api/?numero=0601020304" -G --data-urlencode "texte=$1"
}
###################################
# CONFIGURATION DE L'ECLAIRAGE IR #
###################################
gpio -g mode $NUM_GPIO_ECLAIRAGE out # gpio en sortie
gpio -g write $NUM_GPIO_ECLAIRAGE 1 # pour l'instant on ne s'embête pas et on le laisse tout le temps allumé
###################################
# CONFIGURATION DE LA BARRIERE IR #
###################################
# Config de l'entrée logique
gpio -g mode $NUM_GPIO_BARRIERE up # mode entrée avec pull-up
####################################
# DEMARRAGE DU STREAM DE LA WEBCAM #
####################################
cvlc v4l2:///dev/video0:chroma=mjpg:width=640:height=480:fps=15 :input-slave=alsa://hw:1,0 --sout '#transcode{acodec=mpga,ab=128,channels=2,samplerate=44100,threads=1,audio-sync=1}:standard{access=http,mux=ts,mime=video/ts,dst=:8099}' &
###############################
# GESTION DES ENREGISTREMENTS #
###############################
while :
do
# on vérifie que le NAS est bien monté, sinon on le monte
if mountpoint $POINT_MONTAGE; then
echo "It's mounted."
else
echo "It's not mounted."
mount -t cifs //192.168.1.100/portail -o guest,file_mode=0666,dir_mode=0777,iocharset=iso8859-1,nounix,noserverino $POINT_MONTAGE
fi
# on attend la rupture de la barrière IR
gpio -g wfi $NUM_GPIO_BARRIERE falling
# on démarre l'enregistrement
DATE_HEURE=`date +"(%Y-%m-%d_%H-%M-%S)"|tr -d "\n"`
echo $DATE_HEURE "Démarrage enregistrement"
sms "$DATE_HEURE cui-cui" # SMS de notification
timeout $DUREE_ENREGISTREMENT cvlc http://127.0.0.1:8099 --sout "#transcode{acodec=mpga,ab=128,channels=2,samplerate=44100,threads=1,audio-sync=1}:standard{access=file,mux=ts,mime=video/ts,dst=$REPERTOIRE_TMP/${DATE_HEURE}_nichoir.ts}}"
echo $DATE_HEURE "Fin enregistrement, début copie fichier"
mv $REPERTOIRE_TMP/* $POINT_MONTAGE/$REPERTOIRE_ENREGISTREMENTS/
echo $DATE_HEURE "Fin copie fichier"
done
#############################
# LIBERATION DES RESSOURCES #
#############################
killall vlc
echo "Fin du script. Appuyez sur une touche pour terminer"
read
Serveur relais
Actuellement, cela fonctionne, mais un problème se pose : le débit de la liaison Wi-Fi ne permet pas de diffuser la vidéo à plus d’une personne à la fois.
Pour contourner ce problème, une seconde machine, connectée en Ethernet au réseau, joue le rôle de serveur de retransmission.
Concrètement, il s’agit du même serveur de streaming que le premier, sauf que la source vidéo n’est plus la caméra elle-même mais le flux émis par le premier serveur. Ainsi, une seule connexion est établie entre les deux machines, quel que soit le nombre de clients connectés sur la seconde. Il faut pour cela exécuter la commande suivante :
cvlc http://ip_du_raspberrypi:8099 --sout '#standard{access=http,mux=ts,mime=video/ts,dst=:8099}'
Diffusion sur YouTube
Le format vidéo généré par VLC est assez exotique et seul ce même logiciel semble capable de le re-lire. Cela ne me dérangeait pas au départ car j’imaginais que cela ne regardait que moi.
En en parlant autour de moi, j’ai été agréablement surpris par l’intérêt porté par les gens sur cette vidéo. On m’a conseillé de diffuser la vidéo sur YouTube pour toucher un plus large public, et c’est ce que j’ai fait.
YouTube attend un flux vidéo compressé avec le codec h264 pour la vidéo et aac ou mp3 pour l’audio. Comme je n’ai pas réussi à faire faire au Rasperry Pi lui-même la compression vidéo, j’utilise mon serveur pour cela. Encore une fois, c’est VLC qui fait tout le travail :
cvlc http://ip_du_nichoir:8099 --sout '#transcode{vcodec=h264,vb=3000,scale=Auto,width=640,height=480,acodec=mp3,ab=128,channels=2,samplerate=44100}:std{access=rtmp,mux=ffmpeg{mux=flv},dst=rtmp://adresse_fournie_par_youtube}'
Cette commande réalise un transcodage grâce aux paramètres suivants :
- vcodec=h264 permet de sélectionner le codec vidéo,
- vb=3000 permet de choisir le débit du flux vidéo, ici 3000 kbits/s
- scale=Auto,width=640,height=480 permet de rester dans la définiton d’image d’origine
- De même, acodec=mp3,ab=128,channels=2,samplerate=44100 permet de sélectionner le codec audio mp3 avec un débit audio de 128 kbits/s, stéréo, échantillonné à 44,1 kHz.
Pour information, ce transcodage vidéo utilise à 100% un peu plus de deux cœurs sur les 4 du processeur de mon serveur (Intel N2930).
Résultat
Voici le rendu quand le nichoir était vide :
A l’heure où j’écris ces lignes, les oiseaux se le sont déjà approprié et le nid commence à être rempli :
J’ai créé une chaîne YouTube et la vidéo en direct est normalement disponible ici (si tout fonctionne bien) :
http://youtube.com/channel/UCtutTyk42s9UFSisnZK8t_Q/live
Quelques vidéos pour le plaisir :
Bravo Damien !! 👏. Bisous
Merci !!
Magnifique !!
Super projet bien documenté !
Incroyable cette idée,
Prochaine étape la création d’une chaîne youtube et upload automatique des vidéos ?
Il y a de quoi devenir millionnaire si tu arrives à filmer l’éclosion etc… !
Et voilà, c’est fait ! http://youtube.com/channel/UCtutTyk42s9UFSisnZK8t_Q/live
Félicitation Damien pour toutes tes trouvailles. Tu as du génie 🙂 ! Bisous.
Bravo Damien pour cette réalisation, et aussi à Bernard pour le nichoir.
Je trouve tout cela particulièrement intéressant, à la fois pour la réalisation électronique, et aussi pour l’observation des mésanges. Et on constate sur la vidéo qu’elles portent bien leur nom puisqu’elles vont souvent au « charbon » pour nourrir la nichée…