====== 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}}