Projets:Perso:2016:Lepton Websocket

=Streaming web pour caméra thermique FLIR Lepton sur Raspberry Pi=

'''Les caméras thermiques FLIR Lepton sont relativement peu chères (150€) et se branchent directement sur Raspberry Pi. Je présente ici un serveur que j'ai codé, qui tourne sur Raspberry, et qui permet de visualiser l'image thermique en direct depuis le réseau, et ce en n'utilisant qu'un simple navigateur web.'''

Rayonnement thermique
Tout objet à température non nulle émet un rayonnement électromagnétique (de la lumière). Le spectre (la 'couleur') et l'intensité de ce rayonnement dépendent de certaines propriétés intrinsèques au matériau, et surtout de sa température.

En règle générale, plus la température d'un objet augmente, plus l'intensité du rayonnement qu'il émet est élevée, et son spectre se décale légèrement vers des fréquences plus élevées. Le rayonnement thermique d'un matériau idéal est modélisé sous le nom de "corps noir".

Ainsi, un métal typique à 25°C émet surtout dans l'infrarouge lointan, rayonnement invisible à l'oeil. En revanche, lorsque le métal est suffisamment chaud, le rayonnement qu'il émet devient plus intense, et se déplace légèrement vers le rouge. Il nous apparait alors 'chauffé au rouge'. En continuant à augmenter sa température, son spectre finit par couvrir tout le domaine visible et est très intense : c'est le principe d'une ampoule à incandescence.

Fonctionnement du module
Ce module fonctionne comme une caméra noir et blanc normale dans le sens où il dispose d'une matrice de capteurs qui mesurent l'intensité de la lumière reçue pour former les pixels de l'image. Cependant, ce module utilise des microbolomètres en guise de capteurs-pixel. Ces microbolomètres sont constitutés d'un matériau spécial qui absorbe dans une gamme de longueurs d'ondes dans le lointain infrarouge, et se comporte comme un miroir en dehors de cette gamme. Lorsqu'une radiation est absorbée, la résistance du matériau change, et sa valeur est traitée numériquement pour donner l'intensité du pixel correspondant.



Ce module permet donc de détecter l'intensité du rayonnement infrarouge lointain des objets, qui est lié à leur température. Il est alors possible de discerner les êtres vivants à sang chaud, et même de voir dans le noir total.

Branchement au Raspberry Pi
Attention : le module Lepton est sensible aux décharges électrostatiques. Manipulez-le avec précaution.

Le module comporte 10 pins : CS, MOSI, MISO, CLK, GND, VIN, SDA, SCL. Les pins CS, MOSI, MISO et CLK correspondent à une interface SPI à travers laquelle sont transmises les images. VIN est l'alimentation du module. À connecter à 3.3V. GND est la masse. SDA et SCL sont correspondent à une interface I2C qui permet de lire des propriétés du module, et d'en contrôler certaines fonctions. L'interface I2C est optionnelle car la camera envoie déjà par défaut les images avec des paramètres préconfigurés sur le port SPI.

Pour raccorder le module au Raspberry Pi, suivez ce schéma :

Une fois branché ça ressemble à ça :



Configuration du Raspberry Pi
Il faut à présent activer le port SPI, et optionnellement le port I2C sur le raspberry que je suppose tourner sous Raspbian. Sur le raspberry, exécutez la commande suivante :

sudo raspi-config


 * allez dans Advanced Options puis SPI
 * suivez les instructions et activez le chargement du module SPI au démarrage
 * si vous avez branché l'I2C, il faut aussi activer son module de la même manière
 * quittez ensuite raspi-config en cliquant sur . Acceptez le redémarrage.

Installation du software
Software requis : gcc supportant C++11, libpoco 1.7.3 ou plus

Telechargez le soft : ZIP

Mettez le contenu du zip dans votre raspberry puis compilez et lancez le programme :

cd emplacement_des_fichiers ./compile.sh ./run.sh

Ceci lance le serveur web. Il suffit alors d'aller sur http://ip_du_raspberry depuis un navigateur pour regarder la camera en live.

Visualisation
Pour regarder la caméra en stream temps réel, il vous suffit alors d'aller sur http://[ip du raspberry] avec votre navigateur depuis n'importe quel ordi pouvant se connecter à votre raspberry.

Le résultat ressemble à ceci, mais en live avec une fréquence de rafraichissement d'environ 10Hz :



Fonctionnement du software
Voici une petite description de la manière dont j'ai codé le software serveur.

Le software est composé de deux parties :
 * une clase lepton qui lit en permanence les images de la caméra
 * un serveur web qui fournit une interface et envoie les images au navigateur.

La classe lepton lit en permanence une nouvelle image à travers le port SPI, dans un thread séparé pour ne pas bloquer le reste du programme. L'image est encodée en niveaux de gris avec 2 octets par pixel. Deux buffers alloués au lancement du programme sont utilisés pour stocker l'image et sont pointés par deux pointeurs A et B. Chaque nouvelle image est lue dans A puis, lorsqu'elle est disponible, les pointeurs A et B sont intervertis et un compteur indiquant le numéro de l'image disponible est incrémenté, le tout atomiquement. B est maintenant disponible à la lecture tandis qu'une nouvelle image commence à être lue dans A. Ce système permet de ne jamais faire de copies mémoire ni d'allocations dynamiques, et maximise les performances. Enfin, une méthode grab_image permet à n'importe quel autre thread de lire la dernière image disponible. Cette méthode prend aussi en paramètre le numéro de la dernière image que ce thread a obtenue et dispose d'un système de condition_variable pour attendre que la prochaine image soit disponible et de ne pas lire plusieurs fois la même.

Le serveur web écoute par défaut sur le port 80 du raspberry et fournit une interface HTTP qui affiche une page web contenue dans le fichier resp.html. Cette page est écrite en HTML5/javascript et s'affiche dans le navigateur du client. Le code javascript de la page demande alors au navigateur de se connecter au serveur du raspberry pi à travers le protocole websocket et garde la connexion ouverte, la rouvrant si elle se perd. Le serveur détecte cette demande, ouvre une connexion upgradée websocket et attend de recevoir un paquet. Le client javascript envoie alors le numéro de la dernière image qu'il a reçue (0 si c'est la première). Le serveur reçoit ce numéro et appelle lepton.grab_image qui attend qu'une image différente soit disponible et la renvoie en données binaires brutes avec son numéro. Le client javascript reçoit l'image, détecte l'intensité maximale et minimale des pixels, ramène cette échelle de 0 à 255 pour former une image en niveaux de gris qu'elle agrandit et affiche sur un contexte de dessin canvas dans le navigateur. Ensuite, le client javascript renvoie le numéro de l'image obtenue pour demander l'image suivante, et la procédure recommence. Cette procédure réduit un peu le débit d'images mais permet au serveur de ne maintenir aucune information d'état sur le client (on parle de service web RESTful), ce qui simplifie la mise en ouevre et augmente les performances du raspberry. L'affichage est d'environ 10 images par seconde en bonnes conditions de connexion. Pour minimiser la latence, je désactive le buffering du serveur websocket avec WebSocket.setNoDelay(true).

Le serveur est codé en C++11, et utilise la librairie poco C++ pour gérer les connexions HTTP/Websocket. Enfin, comme la page HTML5 utilise des technologies web récentes, un navigateur à jour est nécessaire pour la visualiser (évitez Internet Explorer).