Outils pour utilisateurs

Outils du site


failomaton

Failomaton

Le projet est de réaliser un photomaton qui vous rate le portrait consciencieusement. Un bijou de technologie pour un résultat décevant.

A faire

* Un bouton de redémarrage du programme * La gestion du manque de papier * Monnayeur

Conception du distributeur de photos

Pièces 2D

$fn = 200;
 
// Épaisseur CP 10mm
 
cote();
translate([350, 145]) rotate(180) cote();
translate([290, 165]) rotate(90) support();
 
translate([305, 155]) rotate(90) mirror([0, 1, 0]) glissiere();
translate([330, 470]) rotate(180) glissiere();
 
translate([15, 600]) rotate(-90) trapeze();
translate([123, 558]) mirror([0, 1, 0]) trapeze();
 
// Épaisseur CP 15mm
 
translate([-120, 50]) renfort1();
translate([-10, 50]) mirror([1, 0, 0]) renfort1();
 
translate([-260, 0]) rotate(-30) ecarteur();
translate([-30, 30]) rotate(150) ecarteur();
 
module cote() {
    difference() {
        union() {
            square([290, 150]);
            translate([90, -10]) square([30, 10]);
        }
        square([55, 6]); // Encoche rabat
        translate([290, 0]) rotate(-30) translate([-400, 0]) square([400, 200]);
        translate([0, 80]) rotate(-30) translate([-100, 0]) square([100, 100]);
        translate([265, 0]) rotate(-30) square([100, 100]); // Petite pointe
        translate([0, 80]) rotate(-30) translate([-100, 0]) square([100, 100]); 
        // Encoches glissieres
        translate([290,0]) rotate(-30) translate([-131.6, -10]) square([50, 11]); 
        translate([290,0]) rotate(-30) translate([-231.6, -10]) square([50, 11]);
    }
}
 
module support() {
    difference() {
        square([236, 290]);
        translate([49.9, 34.9]) square([10.2, 30.2]);
        translate([175.9, 34.9]) square([10.2, 30.2]);
        translate([16.9, 84.9]) square([16.2,15.2]);
        translate([202.9, 84.9]) square([16.2,15.2]);
    }
}
 
module glissiere() {
    difference() {
        square([331.6, 60]);
        square([60.1, 10]);
        translate([109.9, 0]) square([50.2, 10]);
        translate([209.9, 0]) square([150, 35]);
    }
}
 
module trapeze() {
    difference() {
        square([135 * cos(30) + 40, 135 * sin(30)]);
        rotate(30) square([200, 200]);
        translate([0, 2]) difference() {
            translate([0, 58]) resize([320, 116]) circle(d=100);
            translate([0, 58]) resize([315.3, 111.5]) circle(d=100);
            translate([0, 58]) square([200, 100]);
        }
    }
    difference() {
        rotate(30) translate([-20, 0]) square([200, 30]);
        translate([0, 135 * sin(30)]) square([200, 100]);
    }
    translate([135 * cos(30) + 39.9,0]) square([0.1, 135 * sin(30)]); // Fil pour créer une poche pour la CNC
}
 
module ecarteur() {
    difference() {
        rotate(30) translate([-20, 0]) square([200, 30]);
        translate([0, 135 * sin(30)]) square([200, 100]);
    }  
}
 
module renfort1() {
    difference() {
        square([49.9, 50]);
        translate([-15, 0]) rotate(45) square([100, 100]);
    }
    translate([17, -10]) square([16, 10]);
}

Installation de ImageMagick

Installation du paquet

sudo apt-get install imagemagick

Vérifier la bonne installation de ImageMagick

identify -version

Pour tester le bon fonctionnement en convertissant un fichier .jpg en .png

convert photo.jpg photo.png

Voici la méthode pour recadrer la photo afin qu'elle corresponde aux dimensions du papier hagaki :

convert -crop 3836x2592+386+0 photo.jpg photo1.jpg

La méthode pour modifier l'orientation de l'image :

convert -rotate -90 photo.jpg photo1.jpg

Installation de mplayer

sudo apt-get install mplayer

Vérifier la bonne installation avec

mplayer --version 

Afin d'optimiser le lecteur il faut éditer le fichier de configuration :

sudo nano ~/.mplayer/config

A la fin du fichier ajouter cette ligne qui indique que nous n'avons pas besoin de télécommande

lirc=no

Pour lancer un fichier audio

mplayer /home/pi/Audio/audio01.wav

Le son sort par le mini-jack de la Raspberry Pi

Réalisation de la voix de synthèse

La réalisation des différentes instructions par des voix de synthèse a été faite à travers ce site

Voici les réglages :

Matériel

Monnayeur

HX-916

Monnayeur

Carte son

Installation de wiringPi

Attention la librairie WiringPi ne fonctionne que sous Raspbian 32bits et pour un modèle 4B au maximum.

cd /tmp
wget https://project-downloads.drogon.net/wiringpi-latest.deb
sudo dpkg -i wiringpi-latest.deb

Vérifier l'installation avec

gpio -v

La version doit être la 2.52

Installation de l'imprimante

Mise en route de l'imprimante

Suivre les instructions du mode d'emploi pour installer l'imprimante.

La seule configuration nécessaire est de désactiver l'extinction automatique

Avec les flèches aller sur le menu configuration (L'image des outils), puis appuyer sur OK

Aller sur Réglage de l'imprimante puis OK

Aller avec la flèche du bas sur Extinction auto, OK

Sélectionner Désac. puis Ok

Puis appuyer sur Home

Installation de CUPS

Sur une image de Raspberry fraichement installée et mise à jour. Installer CUPS :

sudo apt-get install cups

Puis

sudo usermod -a -G lpadmin pi

Ici, l'utilisateur est celui par défaut pi, vous pouvez le changer si vous avez initialisé un autre nom d'utilisateur.

sudo /etc/init.d/cups restart

Pour redémarrer le service afin que les changements aient bien été pris en compte.

Si vous êtes avec une Raspberry Pi sans écran et connectée en ssh, vous pouvez accéder à la page de configuration des imprimantes si vous suivez ces instructions :

Éditer le fichier de configuration de CUPS :

sudo nano /etc/cups/cupsd.conf

Ajouter les ligne. suivantes au début du fichier :

# Efface l'historiq<ue des tâches 
PreserveJobHistory No

Modifier la section suivante :

# Only listen for connections from the local machine.
Listen localhost:631
Listen /var/run/cups/cups.sock

Afin qu'elle ressemble à celle-ci :

# Only listen for connections from the local machine.
Port 631
Listen /var/run/cups/cups.sock

Puis modifier cette section :

# Restrict access to the server...
<Location />
  Order allow,deny
</Location>

# Restrict access to the admin pages...
<Location /admin>
  Order allow,deny
</Location>

# Restrict access to configuration files...
<Location /admin/conf>
  AuthType Default
  Require user @SYSTEM
  Order allow,deny
</Location>

Pour qu'elle ressemble à ceci :

# Restrict access to the server...
<Location />
  Order allow,deny
  Allow all
</Location>

# Restrict access to the admin pages...
<Location /admin>
  Order allow,deny
  Allow all
</Location>

# Restrict access to configuration files...
<Location /admin/conf>
  AuthType Default
  Require user @SYSTEM
  Order allow,deny
  Allow all
</Location>

Redémarrer ensuite CUPS :

sudo /etc/init.d/cups restart

Ajouter une nouvelle imprimante

Configuration de CUPS

Dès à présent, vous pouvez ouvrir un navigateur et accéder à la page de configuration à cette adresse :

https://failomaton.local:631/admin

Si vous changez la configuration, il faudra vous identifier avec les éléments de CUPS

L'imprimante n'apparaît pas dans les imprimantes locales mais juste dans les imprimantes réseaux. Cliquer sur le bouton puis [Continuer]

Sur la page Ajouter une imprimante cliquer juste sur continuer

Sur la page suivante sélectionner dans le menu Canon SELPHY CP1300, driverless, cups-filters 1.28.17 (en), puis cliquer sur [Ajouter une imprimante]

Sur la page Définir les options de l’imprimante Vérifier que les paramètres par défaut sont bien cela :

Paramètre du papier CP1300

Cliquer sur [Définir les options par défaut]

Impression d'une page test

Cliquer sur [Imprimantes]

Cliquer sur [Canon_SELPHY_CP1300]

Maintenance > Imprimer une page test

Impression d'une photo

Dans un fenêtre du terminal : Lister les imprimantes disponibles

lpstat -p -d

Définir l'imprimante comme imprimante par défaut

lpoptions -d Canon_SELPHY_CP1300

Pour imprimer une photo

lp -d Canon_SELPHY_CP1300 photo1.jpg

Installation complémentaire

Reconnaissance de la clef

Nous souhaitons mettre les fichiers audios sur une clef USB, afin que leurs modifications soient plus aisées et que les photos prises soient aussi sauvegardées sur la clef.

Les clefs sont gérées par des fichiers situés dans le répertoire /dev. Afin de connaitre le nom du fichier. Avant d'insérer la clef, tapez :

ls /dev

Une fois insérée tapez de nouveau :

ls /dev

Vous noterez des noms qui apparaîssent du style sdX et sdX Y. X prenant la forme d'une lettre (a, b, c, d, …) et Y d'un chiffre indiquant le numéro de partition de la clef.

Ici, apparaissent sda et sda 1

Montage de la clef

Avant de procéder au montage proprement dit, il faut créer un répertoire qui permettra de naviguer dedans.

mkdir /media/usb

Ensuite ouvrir le fichier mtab

sudo nano /etc/mtab

Observer le fichier aucune ligne ne doit commencer par : /dev/sda1 /media/usb Ctrl + X pour quitter Monter le la partition de la clef :

sudo mount -t vfat /dev/sda1 /media/usb -o rw,users,umask=0

Ouvrez de nouveau mtab

sudo nano /etc/mtab

La dernière ligne commence par : /dev/sda1 /media/usb Copier cette ligne Ctrl + x pour quitter Ouvrez le fichier fstab

sudo nano /etc/fstab

Coller la ligne à la fin du fichier. Ctrl + o, Ctrl + x pour enregistrer et quitter

sudo reboot

Pour que tout soit bien intégrer.

Code

A tester :

cat file.wav > /dev/audio

Fichier de configuration de la caméra

Placer un fichier config.txt dans le répertoire où est placé le fichier en C

sudo nano config.txt

Copier et coller ces éléments dans le fichier :

timeout=2
verbose=0

Ctrl O pour enregistrer puis valide puis Ctrl X pour quitter.

Code C pour la Raspberry Pi

// g++ -Wall -o test `cups-config --cflags` test.c `cups-config --libs` -lwiringPi
 
#include <dirent.h>
#include <stdio.h>
#include <unistd.h>
#include <wiringPi.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <time.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <cups/cups.h>
 
#include <string>
#include <iostream>
 
#define boutonPhoto 26 // Fil rouge
#define vibrationArduino 27 // Fil vert
#define declenchementArduino 28 // Fil jaune
#define monnayeur 29 // Fil blanc
 
int nbPhotos = 0;
time_t compteurTemps;
static pid_t pidAttente = 0;
static pid_t pidProcedure = 0;
static pid_t pidPhoto = 0;
static pid_t pidAssistance = 0;
 
int attente = 0;
int procedure = 0;
 
void reverse(char s[])
 {
     int i, j;
     char c;
 
     for (i = 0, j = strlen(s)-1; i<j; i++, j--) {
         c = s[i];
         s[i] = s[j];
         s[j] = c;
     }
}
 
void itoa(int n, char s[])
 {
     int i, sign;
 
     if ((sign = n) < 0)  /* record sign */
         n = -n;          /* make n positive */
     i = 0;
     do {       /* generate digits in reverse order */
         s[i++] = n % 10 + '0';   /* get next digit */
     } while ((n /= 10) > 0);     /* delete it */
     if (sign < 0)
         s[i++] = '-';
     s[i] = '\0';
     reverse(s);
}
 
void photo() {
    time_t temps = time(NULL);
    if (difftime(temps, compteurTemps) > 5) // Permet d'éliminer les rebonds de l'interrupteur
    {
        compteurTemps = temps;
        if (procedure == 0) {
            procedure = 1;
            kill(pidAttente, SIGTERM);
            printf("Procedure\n");
            if((pidProcedure = fork()) == 0)
            {
                execl("/usr/bin/mplayer",
                    "/usr/bin/mplayer",
                    "-really-quiet",
                    "-loop", "0",
                    "/media/usb/Audio/Procedure.wav",
                    NULL);
            }
            sleep(13);
                digitalWrite(vibrationArduino, HIGH);
            sleep(1);
                digitalWrite(vibrationArduino, LOW);
         } else {
            kill(pidProcedure, SIGTERM);
            printf("Photo\n");
            if((pidPhoto = fork()) == 0)
            {
                execl("/usr/bin/mplayer",
                    "/usr/bin/mplayer",
                    "-really-quiet",
                    "-loop", "0",
                    "/media/usb/Audio/Photo.wav",
                    NULL);
            }
            sleep(5);
            char buffer [6];
            itoa(nbPhotos, buffer);
            char src[40] = "/media/usb/Photos/photo_" ;
            strcat(src, buffer);
            strcat(src, ".jpg");
            printf("%s\n",src);
            nbPhotos++;
            digitalWrite(declenchementArduino, HIGH);
            static pid_t pid = 0;
            if ((pid = fork()) == 0)
            {
                // libcamera-jpeg -o photo_0.jpg -c config.txt
                execl("/usr/bin/libcamera-jpeg",
                    "",
                    "-o", src,
		"--shutter", "800000",
                    "-c", "config.txt",
                    NULL);
            }
            sleep(1);
            digitalWrite(declenchementArduino, LOW);
            FILE * fichier ;
            do
            {
                fichier = fopen(src, "r");
            } while  (fichier == NULL);
            fclose(fichier);
            static pid_t pid1 = 0;
            if ((pid1 = fork()) == 0)
            {
                // convert -crop 3836x2592+386+0 -rotate -90 Photos/photo_0.jpg Photos/photo1.jpg
                execl(
                    "/usr/bin/convert",
                    "",
                    "-crop",
                    "3836x2592+386+0",
                    "-rotate", "90",
                    src, src,
                    NULL);
            }
            sleep(2);
            //const char *filename = "photo.jpg";
 
            // Impression de la photo
            http_t *http;
            ipp_t *request, *response;
 
            static const char * const requested_attributes[] =
            {
                "printer-description",
                "job-template",
                "media-col-database"
            };
            http = httpConnect2("localhost", 631, NULL, AF_UNSPEC, HTTP_ENCRYPTION_IF_REQUESTED, 1, 30000, NULL);
 
            request = ippNewRequest(IPP_OP_PRINT_JOB);
            ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, "ipp://localhost/printers/Canon_SELPHY_CP1300");
            ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, "pi");
            ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, "image/jpeg");
            ippAddString(request, IPP_TAG_JOB, IPP_TAG_KEYWORD, "media", NULL, "jpn_hagaki_100x148mm");
            ippDelete(cupsDoFileRequest(http, request, "/ipp/print", src));
            sleep(17);
            kill(pidPhoto, SIGTERM);
 
            // Test si il manque du papier
            ipp_attribute_t *attr;
            char value[2048];
            // Procedure
            uint8_t erreur;
            uint8_t assistance = 0;
            do {
                erreur = 0;
                request = ippNewRequest(IPP_OP_GET_PRINTER_ATTRIBUTES);
                ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL, "ipp://localhost/printers/Canon_SELPHY_CP1300");
                ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_MIMETYPE, "document-format", NULL, "image/pwg-raster");
                ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes", (int)(sizeof(requested_attributes) / sizeof(requested_attributes[0])), NULL, requested_attributes);
 
                response = cupsDoRequest(http, request, "/ipp/print");
                for (attr = ippFirstAttribute(response); attr; attr = ippNextAttribute(response))
                {
                    if (strcmp(ippGetName(attr), "printer-state-reasons") == 0)
                    {
                        ippAttributeString(attr, value, sizeof(value));
                        std::string valeur(value);
                        std::size_t erreurCartouche = valeur.find("marker-supply-empty-error");
                        std::size_t erreurPapier = valeur.find("media-empty-error");
                        if (erreurCartouche <= 2048)
                        {
                            // Plus d'encre
                            erreur = 1;
                            if (assistance == 0) {
                                printf("Assistance\n");
 
                                assistance = 1;
                                if((pidAssistance = fork()) == 0)
                                {
                                    execl("/usr/bin/mplayer",
                                    "/usr/bin/mplayer",
                                    "-really-quiet",
                                    "-loop", "0",
                                    "/media/usb/Audio/AssistanceCartouche.wav",
                                    NULL);
                                }
                            }
                        }
                        if (erreurPapier <= 2048)
                        {
                            // Plus de papier
                            erreur = 2;
                            if (assistance == 0) {
                                printf("Assistance\n");
 
                                assistance = 1;
 
                                if((pidAssistance = fork()) == 0)
                                {
                                    execl("/usr/bin/mplayer",
                                    "/usr/bin/mplayer",
                                    "-really-quiet",
                                    "-loop", "0",
                                    "/media/usb/Audio/AssistancePapier.wav",
                                    NULL);
                                }
                            }
                        }
                    }
                }
                sleep(3);
            } while (erreur != 0);
 
            if (assistance != 0) {
		kill(pidAssistance, SIGTERM);
       	}
            printf("Fin Photo\n");
            procedure = 0;
            attente = 0;
        }
    }
}
 
int main()
{
    wiringPiSetup();
    pinMode (boutonPhoto, INPUT); // Pin de l'interrupteur
    pullUpDnControl(boutonPhoto, PUD_UP);
    pinMode (monnayeur, INPUT); // Pin du monnayeur
    pullUpDnControl(monnayeur, PUD_UP);
 
    //   wiringPiISR (25, INT_EDGE_FALLING, &monnayeur);
    pinMode (declenchementArduino, OUTPUT); // Pin de déclenchement de l'arduino
    pinMode (vibrationArduino, OUTPUT); // Pin de déclenchement de l'arduino
    compteurTemps = time(NULL);
 
    // Comptage des fichiers
    struct dirent *dir;
    DIR *d = opendir("/media/usb/Photos/");
    if (d)
    {
        while ((dir = readdir(d)) != NULL)
        {
            if (dir->d_name[0] != '.')
            {
                nbPhotos++;
            }
        }
        //printf("%i\n", nbPhotos);
        closedir(d);
    }
    // Efface tous les travaux d'impression en cours
    system("cancel -a -x");
    while(1) {
        if (attente == 0)
        {
            attente = 1;
            printf("Invitation\n");
            // Message d'attente
            if ((pidAttente = fork()) == 0)
            {
                execl("/usr/bin/mplayer",
                    "/usr/bin/mplayer",
                    "-really-quiet",
                    "-loop", "0",
                    "/media/usb/Audio/Attente.wav",
                    NULL);
            }
        }
        if ((digitalRead(monnayeur) == 0) && (attente == 1) &&  (procedure == 0)) {
             photo();
        }
        if ((digitalRead(boutonPhoto) == 0) && (attente == 1) &&  (procedure == 1)) {
             photo();
        }
    }
    return 0;
}

Code Arduino

#include <Servo.h>
 
#define declencheur 2
#define posFermeVerrou 0
#define posOuvertVerrou 90
#define posBrasLeve 137
#define posBrasBaisse 65
#define posVibHaut 0
#define posVibBas 30
 
Servo verrou;
Servo bras;
 
void setup() {
  pinMode(declencheur, INPUT);
  pinMode(8, INPUT);
  pinMode(13, OUTPUT);
 
  bras.attach(6);
  verrou.attach(5);
  sequence();
}
 
void loop() {
  if (digitalRead(declencheur) == HIGH) {
    sequence();
  }
  if (digitalRead(8) == HIGH){
    vibration();
  }
}
 
void vibration() {
  for (int i = 0; i < 10; i++) {
    verrou.write(posVibBas);
    delay(150);
    verrou.write(posVibHaut);
    delay(150);
  }
 
}
void sequence() {
  delay(760);
  verrou.write(posOuvertVerrou);
  delay(1500);
  bras.write(posBrasLeve);
  delay(1000);
  verrou.write(posFermeVerrou);
  delay(500);
  bras.write(posBrasBaisse);
  delay(500);
}

Démarrage automatique

sudo nano /etc/systemd/system/failomaton.service
[Unit]
Description=Met en route l'installation Failomaton

[Service]
Type=simple
WorkingDirectory=/home/pi/  
ExecStart=/home/pi/./test  
Restart=on-failure
RestartSec=1 
User=pi
Group=pi

[Install]
WantedBy=multi-user.target
sudo systemctl enable failomaton.service
sudo systemctl status failomaton.service

Ressources en ligne

Imprimante

Monnayeur

Caméra

Synthèse vocale en ligne

Programmation

wiringPi

Lire fichier audio

Autres

failomaton.txt · Dernière modification : 2024/04/06 00:16 de Mushussu