====== 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. {{ :failomatonbeta1.mp4 |Version de test}} ==== A faire ==== * Un bouton de redémarrage du programme * La gestion du manque de papier * Monnayeur ===== Conception du distributeur de photos ===== {{:pieces_2d.png?200|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 [[https://texttospeechrobot.com/text-to-speech-old/?variant=m1&rate=100&rate=50&rate=180&rate=0|ce site]] Voici les réglages : {{:reglages_tts.png?400|}} ===== Matériel ===== === Monnayeur === HX-916 {{:cablage_monnayeur.png?400|Monnayeur}} ==== Carte son ==== [[https://fr.aliexpress.com/item/33056020608.html|Carte son externe USB 7.1 adaptateur 5HV2]] ===== 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 Order allow,deny # Restrict access to the admin pages... Order allow,deny # Restrict access to configuration files... AuthType Default Require user @SYSTEM Order allow,deny Pour qu'elle ressemble à ceci : # Restrict access to the server... Order allow,deny Allow all # Restrict access to the admin pages... Order allow,deny Allow all # Restrict access to configuration files... AuthType Default Require user @SYSTEM Order allow,deny Allow all 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 : {{:parametres_cp1300.png?200|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 #include #include #include #include #include #include #include #include #include #include #include #include #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 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 #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 ===== [[https://trevilly.com/photomaton-a-base-de-raspberry-pi-choix-1-ou-4-ou-8-photos-et-impression-directe/|Photomaton avec une Raspberry Pi]] [[https://gitlab.com/Kerial/photobooth|Autre photomaton]] ==== Imprimante ==== [[https://doc.ubuntu-fr.org/hplip|Imprimantes HP|]] [[https://trevilly.com/installer-une-imprimante-sur-raspberry-pi/|Installation d'une imprimante sur une Raspberry Pi]] [[https://raspberrytips.fr/installer-imprimante-raspberry-pi/|CUPS sur RPI]] [[https://www.cups.org/doc/options.html|Page d'option de CUOPS]] ==== Monnayeur ==== [[https://www.artcab.fr/portes-monnayeurs/194-monnayeur-comparatif-en-facade.html|Achat du monnayeur]] [[https://www.amazon.fr/multifonctionnelle-intelligente-monnayeurs-multifonctions-commutateurs/dp/B07VL8YFG4|Achat Amazon]] [[https://www.youtube.com/watch?v=XAKo4OBGjEM|Vidéo d'initialization du monnayeur]] [[https://m.youtube.com/watch?v=kGDuOuqduQU&pp=ygUJTW9ubmF5ZXVy|Cablage du monnayeur]] [[https://www.instructables.com/How-to-Control-CH-926-Coin-Acceptor-With-Arduino/|TUtoriel Arduino]] [[https://blog.adopisoft.com/article/enable-disable-coinslot-without-relay|Enable/Disable pin]] ==== Caméra ==== [[https://github.com/jeffmachyo/Raspberry-Pi-Camera-C-and-CPP|Programme en C pour la caméra Raspi]] [[https://www.raspberrypi.com/documentation/accessories/camera.html|Document sur la caméra]] [[https://magazines-attachments.raspberrypi.org/books/full_pdfs/000/000/036/original/Camera-Guide.pdf|Guide officiel de la caméra]] [[https://www.raspberrypi.com/documentation/computers/camera_software.html|Documentation des logiciels]] [[https://projects.raspberrypi.org/en/projects/infrared-bird-box/6|Mise au point module V2]] [[https://www.raspberrypi.com/news/raspberry-pi-camera-module-still-image-capture/|Déclenchement par signal]] [[https://www.framboise314.fr/test-des-nouvelles-cameras-raspberry-pi-v3-et-hq/|Pour la version 3]] [[https://blog.devmobile.co.nz/2022/01/24/libcamera-jpeg-on-raspberry-pi-os-bullseye-duration/|Liste des options]] ==== Synthèse vocale en ligne ==== [[https://ttsreader.com/fr/|Simple d'utilisation]] [[https://texttospeechrobot.com/text-to-speech-old/?variant=m1&rate=100&rate=50&rate=180&rate=0|Voix de synthèse]] [[https://github.com/mattingalls/Soundflower/releases/tag/2.0b2|Permet à un Mac d'enregistrer les sons internes de l'ordinateur]] ==== Programmation ==== === wiringPi === [[http://wiringpi.com|Site officiel]] === Lire fichier audio === [[https://mplayerhq.hu/DOCS/man/en/mplayer.1.html#CONFIGURATION%20FILES|mplayer configuration]] === Autres === [[https://github.com/jeffmachyo/Raspberry-Pi-Camera-C-and-CPP|Utilisation caméra]] [[https://mtodorovic.developpez.com/linux/programmation-avancee/?page=page_3|Processus]] {{tag> raspberry_pi C++ sylvain}}