PolaroHeat : un appareil photo à impression thermique

Un temps éclipsé par l'arrivée de la photographie numérique, l'appareil photographique instantané inventé par la firme Polaroid à la fin des années 1940 connaît aujourd’hui un regain d'intérêt, porté par une vague de nostalgie et de fétichisme liée aux emblèmes culturels des années 1970-80. Sa rapidité de tirage et sa simplicité d'utilisation expliquent son succès initial chez les photographes amateurs, mais parfois aussi chez les photographes professionnels comme appareil d'appoint (1). Le Polaroid utilise un film spécial contenant la chimie nécessaire au développement et au tirage photographique, après exposition du support lors de la prise de vue, qui repose sur un système optique optimisé et très élaboré. Le développement de l'électronique grand public et de plateformes de prototypage a permis l'apparition de projets basés sur des technologies numériques qui imitent le fonctionnement des appareils photographiques instantanés, du plus simple au plus élaboré. Le PolaroHeat en est une version intermédiaire.

PolaroHeat - vue extérieure

Le PolaroHeat se base sur la plateforme de prototypage open source Raspberry Pi (dans sa version Zero) de la fondation éponyme, qui possède de nombreux atouts. Il s'agit d'un ordinateur monocarte très documenté par une importante communauté d'utilisateurs et qui bénéficie d'un large écosystème d'extensions matérielles dédiées. Il possède en outre un grand nombre d'interfaces d'entrée et de sortie (USB, ports série, ports GPIO…) et il est capable d’exécuter un système d'exploitation complet. Enfin, sa petite taille et son coût modique en font un candidat intéressant pour les projets embarqués qui nécessitent du calcul logiciel dépassant les capacités d'un microcontrôleur. Dans le tutoriel proposé par Adafruit, le Raspberry Pi est accompagné d'un module de caméra 5 Mégapixels (développé par la fondation) qui constitue le dispositif optique et d'une imprimante thermique comme périphérique de sortie. Le montage est complété par un bouton de déclenchement, un bouton d'extinction du système et une LED d'état du système reliés aux ports GPIO du Raspberry Pi Zero. Le système d'exploitation dédié RaspberryPiOS Lite et le serveur d'impression CUPS sont installés sur l'ordinateur. Les fichiers supplémentaires nécessaires au traitement logiciel sont téléchargés depuis le dépôt en ligne d'Adafruit.

Le principe de fonctionnement est le suivant. Le script camera.sh lancé au démarrage du système surveille l'état du déclencheur et, lors de l'appui, commande la capture d'une image aux dimensions du papier thermique par la caméra (commande raspistill). La capture est ensuite envoyée au serveur d'impression CUPS via la commande lp , qui cache en fait une routine complexe. À la réception de cette commande, CUPS se charge de transformer l'image en langage interprétable par l'imprimante en s'appuyant sur le filtre ou pilote rastertozj.c. On passe ainsi d'un fichier image encodé au format JPEG, soit une matrice de quantités de lumière et de couleurs codées sous forme numérique, à un flux de données brutes formaté selon le langage de description de page ESC/P (2). CUPS livre enfin les données à l'imprimante et exécute la séquence d'impression décrite dans le fichier rastertozj.c : initialisation et chargement des caractéristiques de l'imprimante (contenues dans le fichier de description ZJ-58.ppd ), exécution de l'impression, arrêt et réinitialisation du matériel.

PolaroHeat - schéma

Ce prototype de « Polaroid numérique » est fonctionnel, mais contrairement à son modèle argentique qui permettait d'ajuster les paramètres optiques aux conditions lumineuses, il ne permet aucun réglage esthétique, ni à la prise de vue, ni à l'impression. Deux améliorations ont donc été apportées au code d'origine. La première (et la plus importante) introduit la possibilité de régler les paramètres de chauffe de l'imprimante thermique. En effet, la tête d'impression de ce type d'imprimantes est constituée de minuscules résistances (points d'impression) qui convertissent l'énergie électrique reçue en chaleur. Le papier thermique contient des agents chimiques qui y sont sensibles et s'assombrissent plus ou moins au passage sous la tête d'impression. Ici, l'imprimante est utilisée sous une tension de 5 volts au lieu des 9 volts recommandés, avec comme conséquence une moindre quantité de chaleur émise par les résistances et donc un faible contraste à l'impression. L'ajout d'une commande qui modifie les paramètres de chauffe (3) dans la séquence d'impression permet d'augmenter le temps de chauffe des résistances, et donc le contraste, au détriment du temps d'impression. La seconde modification du code concerne la commande raspistill responsable de la prise de vue et qui accepte de nombreuses options. Il est ainsi possible de paramétrer finement les réglages de la prise de vue (contraste, exposition…), voire même d'appliquer des effets artistiques (croquis, négatif…).

L'intégration dans un boîtier de Polaroid original s'est avérée particulièrement ardue. Comme le note l'auteur du blog Mixtela.com, le Polaroid ne contient aucune vis, les différents éléments originaux étant fixés par emboîtement les uns aux autres. Toutes les pièces intérieures ont donc été retirées et remplacées par le nouveau circuit, hormis le viseur qui a été conservé tel quel, ainsi que l'objectif qui a été fixé à la colle. Par manque de place, l'accumulateur 5V a été déporté dans une pochette fixée sous le boîtier (4). Ce subterfuge permet néanmoins de changer d'alimentation USB simplement et de garder un œil sur le témoin de charge, le Raspberry Pi Zero supportant mal les extinctions brutales. L'apparence extérieure a été préservée autant que possible ; seules deux vis ont été ajoutées pour servir d'axe pour le rouleau de papier thermique. L'absence d'élément de compensation de la friction et la faible puissance du moteur miniature ont par ailleurs tendance à entraver le déroulement fluide du papier, avec pour conséquence des défauts visuels d'impression. L'obtention d'un rendu correct et régulier a été de ce point de vue particulièrement difficile. Enfin, comme pour la quasi totalité des projets présentés sur le site, les différents éléments du circuit (cartes, modules...) ont été fixés de manière à pouvoir être retirés et réutilisés plus tard. Cette démarche permet de relativiser le coût élevé du projet (environ 130€) et d'envisager la récupération des éléments pour de futurs montages.

PolaroHeat - rendu des prises de vue

PolaroHeat - Rendu approximatif

Le PolaroHeat mobilise de nombreux concepts et savoirs-faire liées à l'informatique et à l'image numérique, notamment :

Fichiers

Notes

1. On peut en voir l'utilisation faite par Alfred Seiland dans la série de documentaires L'héritage de Rome diffusée surt Arte en 2018 (non éditée). Le photographe teste l'exposition à l'aide d'un tirage Polaroid avant de prendre une photographie définitive à la chambre.

2. Voir l'article Wikipedia en anglais. Les commandes de ce langage sont constituées d'une suite de caractères codés sous forme numérique selon la norme ASCII. La mémoire de l'imprimante contient une table de correspondance de caractères qui lui permet d'interpréter les commandes.

3. Le fonctionnement de la commande est détaillé ci-dessous.

4. En fait, le choix a été fait de réutiliser l'accumulateur de l'ESPion pour limiter l'achat et l'utilisation de multiples batteries Li-ion pour des objets qui ne servent qu'occasionnellement.

5. Le Raspberry Pi Zero utilisé dans ce projet, vendu aux alentours de 5€, est souvent en rupture de stock et nécessite un adaptateur µUSB/Ethernet relativement cher s'il est acheté exprès. Il a donc été remplacé par sa version WH, plus chère, mais qui dispose du Wifi.


Instructions

Toutes les commandes doivent être exécutées en tant que superutilisateur. Le code indiqué entre chevrons < > est à remplacer par la valeur correspondante. Le code suivant un double slash / / est un commentaire.

N.B.: la majeure partie de la marche à suivre est tirée de ce tutoriel provenant d'Adafruit.

Matériel

Coût de revient estimé : 134,74€. Le coût est calculé à partir des catalogues RS Components (composants), Gotronic (composants, cartes et modules) et Boulanger (batterie). Les prix relevés sont ceux des composants à l'unité ou vendus en petites quantités.

Ressources

Concernant la caméra :

Concernant l'imprimante thermique :

Principe de fonctionnement

Le script camera.sh, lancé au démarrage du système, gère l'écoute des ports GPIO (état du déclencheur et du bouton d'extinction du système) et la capture d'une image par la caméra au déclenchement (commande raspistill). La capture est envoyée au serveur d'impression CUPS (commande lp). Le principe de fonctionnement de CUPS est décrit sur la page Wikipédia dédiée :

  1. les applications envoient les documents à imprimer à un gestionnaire de tâche sur le serveur CUPS ;
  2. ce gestionnaire passe le document à travers un filtre pour le convertir dans un langage que l'imprimante peut comprendre ;
  3. le document ainsi transformé est livré à un module de transport qui se charge de transmettre les données d'impression à un périphérique local ou une connexion réseau.

Le fichier raster capturé par la caméra est ensuite transformé en matrice d'octets interprétable par l'imprimante grâce au filtre (driver) rastertozj.c qui a été compilé et installé (commandes make et ./install). Le fichier est enfin livré à l'imprimante thermique qui a été configurée (commande lpadmin) et définie par défaut (commande lpotions).

Préparation logicielle

raspi-config
stty -F /dev/serial0 9600 // Régler la vitesse de communication avec l'imprimante montée sur /dev/serial0 à 9600 bauds
echo -e "Ceci est un test.\\n\\n\\n" > /dev/serial0 // Envoyer la phrase de test à l'imprimante
apt-get update
apt-get install git cups wiringpi build-essential libcups2-dev libcupsimage2-dev python3-serial python-pil python-unidecode
git clone https://github.com/adafruit/zj-58

Paramétrage de l'impression

N.B.: un contributeur a proposé une autre solution sur le dépôt GitHub du pilote de l'imprimante, mais elle n'a pas encore été intégrée à la branche principale.

cd zj-58
nano rastertozj.c

Les lignes suivantes sont ajoutées (ligne 44 du fichier rastertozj.c original) :

// define control parameter command
static const struct command controlParameterCommand =
{5,(char[5]){0x1b,0x37,0x4,0x78,0x2}};

// define sleep parameter command
static const struct command sleepParameterCommand =
{3,(char[3]){0x1b,0x38,0x14}};

// define wake up command
static const struct command wakeUpCommand =
{1,(char[1]){0xff}};

Trois commandes sont initialisées (contrôle des paramètres de chauffe, mise en veille de l'imprimante et réveil de l'imprimante). Chaque commande est constituée d'un ou plusieurs octets écrits sous forme brute (voir https://lwp.interglacial.com/appf_01.htm pour la conversion décimal/hexadécimal/ascii/encodage brut). La valeur de certains octets est définie, d'autres correspondent à des paramètres modifiables d'après la documentation (voir pages 22/23 : https://cdn-shop.adafruit.com/datasheets/A2-user+manual.pdf).

Détail des commandes

Commande controlParameterCommand

Syntaxe : 0x1b,0x37,n1,n2,n3

Ici, n1 a été fixée à 4 (4+18 = 40 points), ce qui diminue la consommation électrique de l'imprimante et lui permet de fonctionner correctement sous 5V. n2 a été fixée à 120 (12010 = 1200µs ou 1,2ms) pour obtenir une image suffisamment contrastée. La valeur par défaut de n3 (2, c'est-à-dire 2*10 = 20µs) a été conservée (pas de gain de détail observé).

Commandes sleepParameterCommand et wakeUpCommand

Syntaxe : 0x1b,0x38,n1

n1 peut prendre une valeur entre 0 et 255 (à convertir sous forme brute). Cette valeur correspond au temps d'attente en secondes entre la fin de la dernière impression et la mise en veille. Valeur par défaut : 0 (pas de mise en veille). Cette commande permet de diminuer la consommation électrique de l'imprimante.

Ici, n1 a été fixée arbitrairement à 20.

Lorsque l'imprimante est en veille, l'envoi d'un octet (0xff) permet de la réveiller. C'est le rôle de la commande wakeUpCommand.

Les commandes wakeUpCommand et controlParameterCommand sont intégrées à la déclaration de fonction jobSetup() (ligne 148 du fichier rastertozj.c original). Cette fonction est appelée avant chaque impression.

// sent on the beginning of print job
void jobSetup()
{
        outputCommand(wakeUpCommand);
        sleep(0.05);
        if ( settings.cashDrawer1==1 )
                outputCommand(cashDrawerEject[0]);
        if ( settings.cashDrawer2==1 )
                outputCommand(cashDrawerEject[1]);
        outputCommand(printerInitializeCommand);
        outputCommand(controlParameterCommand);
}

La commande sleepParameterCommand est intégrée à la déclaration de fonction ShutDown() (ligne 158 du fichier rastertozj.c original). Cette fonction est appelée à la fin de chaque impression.

// sent at the very end of print job
void ShutDown()
{
        if ( settings.cashDrawer1==2 )
                outputCommand(cashDrawerEject[0]);
        if ( settings.cashDrawer2==2 )
                outputCommand(cashDrawerEject[1]);
        outputCommand(printerInitializeCommand);
        outputCommand(sleepParameterCommand);
}

Installation du pilote et finalisation

make
./install

N.B.: le programme doit être recompilé à chaque nouvelle modification du fichier rastertozj.c.

lpadmin -p ZJ-58 -E -v serial:/dev/serial0?baud=9600 -m zjiang/ZJ-58.ppd
lpoptions -d ZJ-58
reboot
raspistill -n -t 200 -w 512 -h 384 --contrast 15 -o - | lp

Les paramètres et les options sont détaillés ici : https://www.raspberrypi.org/documentation/raspbian/applications/camera.md

nano /etc/rc.local
sh /home/pi/zj-58/extras/camera.sh

Boîtier

Plusieurs stratégies ont été nécessaires pour réussir l'intégration :

Optimisation de la consommation électrique

Quelques pistes (non testées) :