Batsignal connecté

Je ne sais pas vous, mais personnellement, j’ai toujours rêvé d’avoir mon propre Batsignal.

J’ai donc décidé il y a quelques temps de m’en fabriquer un, mais quitte à faire ça, j’ai poussé l’idée un peu plus loin et j’en ai fait un objet connecté.

Le résultat du projet est donc un Batsignal contrôlable via une API REST pour l’allumer, l’éteindre et le faire clignoter.

Les fichiers 3D sont disponibles sur cults3d.
Le code du projet est disponible sur github.

Origine

Avant de parler du projet, on va faire un petit rappel de l’origine du Batsignal.

La première apparition de Batman date de 1939, dans le Detective-Comics numéro 27.

Le Batsignal apparaît quant à lui seulement quelques années plus tard, en février 1942, dans le Detective-Comics 60.

detective_comics_60

Sa forme est restée sensiblement la même au fil du temps : un gros projecteur illuminant le ciel nuageux de Gotham avec le logo emblématique de Batman, permettant à celui-ci de savoir que la ville a besoin de son aide.

Réalisation du projet

Modélisation 3D

La conception a été faite sur Fusion 360.
Le bat signal est composé de plusieurs parties, qui s’assemblent les unes aux autres.

Le projecteur en lui même dispose d’un emplacement pour y placer une led. Les bras qui tiennent les projecteurs sont creux afin de permettre aux fils de la led de passer à l’intérieur.

Ci-dessous, une vidéo de l’assemblage des différentes pièces sur Fusion 360 :

Assemblage, Peinture & Électronique

Une fois toutes les pièces imprimées, il faut les peindre et les assembler.
Mais avant ça, comme à chaque fois avec l’impression 3D, il faut traiter l’objet pour cacher les couches de matières.

J’ai essayé différentes techniques de lissage sur mes projets. Certaines fonctionnent mieux que d’autres.
Pour celui-ci j’ai utilisé du XTC-3D de smooth-on, de la résine epoxy spécialement prévue pour lisser les impressions 3D.

xtc-3d

On le trouve relativement facilement, sur des sites spécialisés ou Amazon.

C’est un produit qui fonctionne plutôt bien pour avoir un rendu lisse de l’impression, mais ajoute une couche plus ou moins épaisse de résine en fonction de la méthode d’application, il y a donc un risque de réduire le niveau de détail de l’impression.
De plus, comme il s’agit d’une résine epoxy issue d’un mélange, une fois celui-ci fait, le temps d’application est compté. J’ai déjà gâché beaucoup de produits, car pas assez rapide. Par ailleurs, si mal mélangé, ou mal dosé, la réaction ne se fera pas correctement, et la résine ne durcira jamais, rendant votre impression 3D inutilisable.

Attention : une fois mélangés, les deux composants de la résine provoquent une réaction exothermique pour que l’epoxy catalyse, ça chauffe donc beaucoup. 

Pour ce projet, ça fera l’affaire, mais je ne pense plus l’utiliser à l’avenir, d’autres méthodes seront détaillées dans de futurs articles.

Une fois la résine durcie on peut peindre le Batsignal. Je ne m’attarde pas trop là-dessus, il n’y a pas grand chose d’intéressant à ce sujet.

J’ai utilisé des peintures Citadel, pour les Warhammer, mais de la peinture acrylique générique aurait tout aussi bien fait l’affaire.

Pour les bandes jaunes, l’astuce est de couper des bandes de ruban de masquage pour faire un tracé net.

Pour le « weathering », j’ai tenté deux choses :

  • Marques d’usure métallique en faisant :
    • Des coups de pinceau aléatoire pour faire des traces.
    • Utilisation d’une vieille éponge pour tamponner à quelques endroits.
    • Brossage à sec pour ne pas laisser trop d’uniformité dans la peinture noire.
  • Un ombrage à l’encre noire pour « salir » l’objet.

Voila une photo du résultat :

Pour la vitre du projecteur, j’ai découpé un bout de plexiglass et j’ai collé dessus le logo. J’ai dû m’y prendre à deux fois, la première j’ai essayé de coller le logo avec de la Cyanoacrylate (de la Super Glue quoi), et les vapeurs de la colle ont commencées à faire fondre le plexi et ont laissées des traces blanches. Pour éviter cela, j’ai fixé le plexi avec de la colle chaude.

Rappel : NE PAS UTILISER DE CYNOACRYLATE AVEC DU PLEXIGLASS, OU SINON LE PLEXI EST FOUTU.

Pour en finir avec l’assemblage, parlons un peu de l’éclairage. J’ai mis une unique led blanche de 3mm, suffisamment puissante pour que le logo soit projeté au plafond. J’ai testé d’autres configurations et c’est celle qui m’a donné le meilleur résultat (avec le matériel et pièces dont je disposais, nul doutes qu’il y ait de meilleures façons de faire cela plus efficacement).

En tout cas ça projette bien !

La led est donc connectée à des fils électriques, qui passent dans les bras du projecteur, puis arrivent dans le socle et se branchent directement aux broches du Raspberry Pi qui est lui-même fixé au socle.

Configuration Raspberry Pi

Avant d’expliquer comment configurer le RPI, pourquoi j’en ai pris un, alors qu’un Arduino ou un ESP aurait largement suffit ?

C’est vrai que pour le coup, un RPI, c’est un peu overkill pour ce qu’on veut faire (pour rappel : allumer et éteindre la led via une API REST).

La raison est simple : j’avais un vieux Raspberry B+ de première génération qui prenait la poussière, et comme j’utilise tout le temps des Arduino pour mes projets, j’ai pensé que ça serait bien de changer pour une fois.

Choix de l’image et flash

Il faut choisir une image pour l’OS qui va tourner sur le RPI. Pour cela il faut prendre en compte plusieurs aspects :

  • Le Batsignal va se comporter comme un serveur REST.
  • Il n’y aura pas d’application avec interface graphique.
  • On utilise un vieux Raspberry.

On part donc sur une image de Raspbian Lite (au moment de la réalisation du projet, maintenant on parle de Raspberry Pi OS Lite).

Cette version n’a pas d’interface graphique, ce qui la rend plus légère (d’où le lite).

Pour le flash, c’est comme d’habitude :

  • On télécharge l’image.
  • On branche une carte SD à son PC.
  • On ouvre Etcher.
  • On choisit l’image.
  • On choisit la carte SD.
  • Et on flash.

Configuration

Comme on est sur une version lite, on va accéder au Raspberry en SSH, pour cela il y a un peu de configuration à faire.

On se munit d’un clavier et d’un écran pour les brancher au RPI, et on branche ce dernier à une alimentation.

Niveau configuration c’est rapide :

  • On lance la commande raspi-config.
  • On rentre les informations pour se connecter en wifi (facultatif si on branche le RPI en ethernet).
  • On autorise la connexion SSH.
  • On en profite pour mettre à jour la version de l’OS et les paquets déjà installés : sudo apt-get update puis sudo apt-get upgrade.
  • (Facultatif) Définir une adresse IP statique : sudo nano /etc/dhcpcd.conf ajouter sous la ligne #interface eth0 la ligne suivante : static ip_address=<IP_ADDRESS>/24 où IP_ADDRESS est l’ip statique que l’on définit.

Je n’ai pas détaillé toute la configuration ici, mais le détail complet est sur le github du projet.

Code

On va maintenant parler du code. Il est écrit en C++, au niveau de l’IDE j’utilise Visual Studio Community 2019 (pour le développement, au moment de l’écriture de l’article on est sur 2022). L’avantage de VS est qu’il permet de développer sur un PC Windows puis de déployer le code directement sur le RPI grâce à un mécanisme de cross-build. Cela permet de ne pas avoir à brancher un écran et un clavier sur le Raspberry, d’autant plus qu’en ayant choisi une image lite, en absence d’interface graphique, c’est plus pratique pour coder.

API REST

Comme évoqué au début de l’article, le Batsignal fonctionne comme un serveur construit autour d’un API REST. Cette API expose trois requêtes HTTP, pour ceux qui découvrent, il s’agit du même type de requête que celles que l’on fait dans un navigateur web. C’est à partir de ces requêtes qu’on pourra contrôler l’allumage du projecteur.

Avant de détailler les requêtes, qu’est-ce qu’une API REST ?

Pour faire simple : il s’agit d’une architecture définissant un ensemble de règle permettant de décrire le format d’une interface de communication dans le but de manipuler des ressources (Create, Read, Update, Delete => CRUD) sur une service web. Le web regorge de ressources sur le sujet si vous voulez plus d’informations.

Dans notre cas, la ressource est la led du Batsignal qu’on peut modifier en l’allumant ou en l’éteignant.

On a trois requêtes :

  • PUThttp://<RPI_IP>:80/batsignal/light/ : Allume et éteint la lumière, un paramètre de body permet de déterminer si on allume ou éteint la lumière.
  • GEThttp://<RPI_IP>:80/batsignal/light/ : Retourne l’état courant de la lumière.
  • PUThttp://<RPI_IP>:80//batsignal/batSignal/ : Fait clignoter la led 3 fois.

La librairie utilisée pour gérer le serveur et l’API REST est Cpp Rest, anciennement Casablanca. Développée par Microsoft sous licence MIT, elle est simple d’utilisation et bien documentée.

Attention : Il semble que depuis le développement du projet, la librairie ait été mise en maintenance par Microsoft, il n’est donc pas recommandé de l’utiliser.

Implémentation

La classe LedBatSignal contrôle directement la led via la librairie WiringPi. Il y a trois méthodes intéressantes :

  • turnTheLight : Allume ou éteint la led.
  • triggerSignal : Fait clignoter la led BLINK_COUNT fois, BLINK_COUNT étant une constante définie dans le header de la classe.
  • lightStatus : Retourne l’état courant de la led sous forme de bool (allumé = true ou éteint = false).
#include <wiringPi.h>

#include "LedBatSignal.h"

LedBatSignal::LedBatSignal()
{
    // Init wiringPi for accessing raspberry GPIOs.
    wiringPiSetupSys();
    pinMode(LED, OUTPUT);
}

void LedBatSignal::turnTheLight(bool state)
{
    digitalWrite(LED, state);
    batSignalState_ = state;
}

void LedBatSignal::triggerSignal()
{
    for (int i = 0; i < BLINK_COUNT; ++i)
    {
        digitalWrite(LED, HIGH);
        delay(BLINK_DURATION);
        digitalWrite(LED, LOW);
        delay(BLINK_DURATION);
    }
}

bool LedBatSignal::lightStatus() const
{
    return batSignalState_;
}

On remarque que les trois méthodes correspondent aux trois requêtes de l’API. Ça tombe bien, on a une classe abstraite, disons une interface, qui permet de traiter les actions HTTP : AbstractRestHandler. Il suffit juste de l’implémenter dans une classe spécifique pour le Batsignal, qui aura un pointeur vers une instance de LedBatSignal et qui pourra donc appeler les méthodes publiques de celle-ci, c’est à dire les trois méthodes présentées précédemment.

Exemple avec la méthode de traitement des messages GET :

void BatSignalRestHandler::get(web::http::http_request message)
{
    std::cout << "* get " << std::endl;
    std::cout << message.relative_uri().path() << "\n";
    auto paths = web::uri::split_path(web::uri::decode(message.relative_uri().path()));
    if (U("light") == paths[0])
    {
        std::cout << "light\n";
        State state = State();
        state.value = batSignal_->lightStatus();

        auto json = state.AsJSON();

        message.reply(web::http::status_codes::OK, json);
    }
    else
    {
        std::cout << "Bad Request\n";
        message.reply(web::http::status_codes::BadRequest);
    }
}

On vérifie d’abord que le path est correct (ici /light), puis on appelle la méthode de la classe de gestion du Batsignal pour créer notre réponse.

Pour finir la classe RestServer permet de créer un serveur HTTP et abonne les méthodes de la classe BatSignalRestHandler sur les listener du serveur afin d’appeler les bonnes callback sur reception des requêtes.

Détails d’une méthode de souscription :

void RestServer::addGetCallCallaback(std::function<void(web::http::http_request)> callback)
{
    std::cout << "* Add get callback.\n";
    listener_.support(web::http::methods::GET, callback);
}

Et ici en pratique dans le main du programme :

    // Create REST Server.
    RestServer server(addr);

    // Create LedBatSignal.
    std::shared_ptr<AbstractBatSignal> batSignal = std::make_shared<LedBatSignal>();

    // Create rest handler.
    BatSignalRestHandler batHandler = BatSignalRestHandler(batSignal);

    // Register methods.
    server.addPutCallCallaback(std::bind(&AbstractRestHandler::put, batHandler, std::placeholders::_1));
    server.addGetCallCallaback(std::bind(&AbstractRestHandler::get, batHandler, std::placeholders::_1));

Les deux dernières lignes sont un peu obscures. Pour faire simple, std::bind permet de récupérer la fonction correspondant au premier paramètre dans la classe du second.

Méthode de test

Comment tester les requêtes HTTP d’une API REST?

Il existe différentes façon de faire, relativement simple pour la plupart. Personnellement j’opte pour Postman.

Pour tester il faut saisir les requêtes dans l’interface de Postman, choisir de quel type il s’agit (GET, PUT, etc.), préciser dans les headers que le content-type est application/json et enfin dans le body ajouter les paramètres des requêtes, s’il y en a.

En exécutant les requêtes, on constate bien que le Batsignal s’allume et s’éteint en fonction des requêtes.

Un peu d’IoT

Maintenant que le Batsignal et son API REST sont fonctionnels, il serait pas mal d’automatiser cela.

Au départ je souhaitais utiliser IFTTT, mais les changements de politiques tarifaires m’ont fait bouger vers une solution open source, gratuite et offrant plus de libertés et possibilités : Node-RED.

Node-RED

Node-RED est un logiciel qui permet grâce à un système de programmation visuelle (oserais-je dire du NOCODE ?!) de faire interagir entre eux des appareils, des services, ou autres API. 

Je ne rentrerai pas ici dans le détail de l’installation de Node-RED, il y a déjà beaucoup de ressources sur le sujet sur le web.

L’idée ici est surtout de présenter une idée de « flow » Node-RED pour rendre le Batsignal connecté. L’objectif est de le faire clignoter lorsque j’ai des mails non lus.

Pour commencer on ajoute un nœud email in, il permet de faire une action sur réception d’un email. Il faut y configurer son adresse email et son mot de passe. Le champ Disposition permet de choisir l’action à faire sur les nouveaux mails. Je choisis l’option None afin de ne pas perturber le contenu de ma boite mails.

Il est également possible de changer la fréquence de rafraichissement du nœud. Pour la démo je mets 10 secondes.

On continue en connectant à la sortie du nœud email un nœud http request. On sélectionne le type de requête que l’on souhaite envoyer, ici PUT puis on ajoute l’URL de la requête et c’est bon.

J’ajoute un nœud de debug pour vérifier que tout fonctionne correctement et on déploie.

Ainsi lorsque que je reçois un nouveau mail, le Batsignal clignote et des messages de debug indiquent que cela fonctionne.

Les possibilités sont infinies, en utilisant par exemple les nœuds pour Twitter ou Instagram, le Batsignal peut réagir aux différentes notifications des réseaux sociaux.

Conclusion

Ainsi se termine cet article sur le Batsignal connecté, j’espère qu’il vous a plu.

C’est un projet complet, on a de la conception, de l’impression 3D, du code. On passe du hardware au software.

Je pensais en commençant ce projet qu’il serait rapide, mais au final il m’a pris plus de temps que prévu, mais ce fut enrichissant.

N’hésitez pas à réagir et donner votre avis dans les commentaires.

Je vous laisse avec quelques photos du Batsignal.

Laissez un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.

Commentaire sur “Batsignal connecté”