{{tag>impression_3D animatronique marionnette raspberry-pi electronique em}} ====== 🆕 Tête de marionnette animatronique ====== (**Cette tête fait partie du projet [[projets:barbichette:start|Barbichette]]**) Fabrication d'une tête animatronique. Le projet original est diffusé sous licence libre par [[https://bechele.de/|Rolf Jethon]] et se compose d'une partie hardware : mécanique (pièces à imprimer, visserie, etc), électronique (raspberry pi ou orange pi, contrôleur de servomoteurs, servomoteurs, etc.) et d'une partie software développée par l'auteur (en perl!), les README donne des infos sur l'articulation du système logiciel. Le système permet de synchroniser des mouvements de servomoteurs pré-enregistrés avec des fichiers audio MP3 et de les rejouer. 16 servomoteurs sont controlables grâce au driver PCA9685, l'audio est joué sur la sortie audio du Raspberry Pi. Les mouvements de servo sont enregistrés sur une base de temps de 50ms. * Site du projet : https://bechele.de/?page_id=70 * Bouche et sourcils : https://www.thingiverse.com/thing:2863069 * Paire d'yeux indépendants : https://www.thingiverse.com/thing:2781756 * Paire d'yeux améliorée : https://www.thingiverse.com/thing:4058084 * Software : https://bechele.de/?page_id=73 * README du software : https://bechele.de/?page_id=188 Le projet est aussi présenté en détail sur ce blog https://zappedmyself.com/animatronics/bechele2-info/ ===== Réglages particuliers ===== Avec le filament PLA Unite blanc, quelques pièces ont eu des difficultés d'impression : couche trop fragile au niveau des trous horizontaux. Quelques réglages d'impression adaptés : se baser sur le profil **fine 0.1mm**, changer : **couche d'impression 0.12mm, vitesse d'impression 40mm, flow 110%** ===== Yeux ===== Les fichiers sont [[https://www.thingiverse.com/thing:4058084|fournis en stl sur thingiverse]], je les ai réunis en 6 lots pour faciliter l'impression. \\ Le montage est expliqué, étape par étape dans cette vidéo : https://www.youtube.com/watch?v=U1c4R2EB83A ==== Impression ==== **Différentes pièces** : {{:openatelier:projet:tete_animatronique:yeux_animatroniques_pieces_lot_couleur.png?direct&1000|}} Les fichiers sont slicés avec [[https://lesporteslogiques.net/wiki/ressource/impression3d#utilisation_de_cura|Cura]] pour [[outil:imprimante_3d_creality_ender_3:start|Ender 3]] avec une épaisseur de couches de 0.12mm **Durée d'impression**\\ * lot 1 : 40 minutes * lot 2 : 20 minutes * lot 3 : 2h20 * lot 4 : 2h50 * lot 5 : 2h10 * lot 6 : 3h05 (avec eyeball-for-iris, mais pas eyeball) Un peu de casse au montage nécessite de nouveaux lots à imprimer * lot 7 : 1h00 (eyeball hinge et hinge frame, 1 de chaque) ===== Tête ===== Les fichiers pour la tête sont disponibles sur thingiverse, en revanche pas de vidéo cette fois pour aider au montage... ==== Impression ==== {{:openatelier:projet:tete_animatronique:tete_animatronique_pieces_lot_couleur.png?direct&1000|}} **Durée d'impression** \\ * lot 1 : 2h21 * lot 2 : 1h10 * lot 3 : 3h23 * lot 4 : 1h55 * lot 5 : 1h46 * lot 6 : 1h39 * lot 7 : 0h09 (oubli... connecting-levers) ===== Yeux 2 ===== Ce sont les yeux animés qui vont avec la tête / fichiers [[https://www.thingiverse.com/thing:2781756|fournis en stl sur thingiverse]], réunis en 4 lots. \\ {{:openatelier:projet:tete_animatronique:2781756_eye_mechanics_parts.png?direct&1000|}} ==== Impression ==== **Durée d'impression** \\ Sur la carte uSD : série de fichiers bechele_oeyes_X.gcode \\ * lot 1 : 1h31 * lot 2 : 0h30 * lot 3 : 3h02 * lot 4 : 2h12 * lot 5 : 0h11 **Durée d'impression avec les réglages qui compensent le problème d'impression** (série b) \\ Sur la carte uSD : série de fichiers bechele_oeyes_Xb.gcode \\ * 1 : 3h29 * 2 : 0h38 * 3 : 4h20 * 4 : 3h56 * 5 : 0h16 ===== Composants et visserie ===== {{:openatelier:projet:tete_animatronique:vis.png?direct|}} * un guide bien utile pour se repérer dans le monde merveilleux de la visserie : https://micro-modele.fr/img/cms/MICRO_VISSERIE/visserie_doc.pdf **Électronique** * Raspberry Pi 3 ou 4 * module électronique driver 16 canaux pour servo, à base de PCA9685 (différents possibles, exemple : [[https://www.joom.com/en/products/5cd4d3318b2c370101468089|HW-170]] ou [[https://www.joy-it.net/en/products/RB-Moto3|MotoPi]]) * yeux améliorés : 7 servomoteurs miniatures, on utilise des [[https://www.dfrobot.com/product-1970.html|DMS-MG90-A]] de DFRobot, avec une amplitude de 270° * yeux d'origine : 5 servomoteurs * tête : 5 servomoteurs * alimentation 5V à x ampères : récupération d'une alim de PC **Quincaillerie** ===== Test des servomoteurs avec arduino ===== Test de 4 servomoteurs avec du matériel grove et une alimentation de 550 mA (ancien chargeur de téléphone). L'alimentation est largement sous-dimensionnée pour utiliser 5 servomoteurs. En lisant la [[https://www.dfrobot.com/product-1970.html|datasheet du servomoteur]], on voit que son courant de décrochage (//stall currrent//) est de 800±30 mA à 4.8V et 1100±30 mA à 6V, on peut donc dimensionner 900mA pour alimenter chaque moteur ([[https://forum.arduino.cc/t/how-much-power-supply-do-i-need-for-controlling-5-sg90-9g-microservo/627666|source]])... Une alim de PC de récupération pourrait fournir largement ce qu'il faut. /* Test servomoteurs avec seeeduino lotus + module grove PCA9685 16-Chan I2C PWM driver arduino 1.8.5 @ Kirin, pierre@lesporteslogiques.net / 23 nov. 2022 + lib. Seeed PCA9685 library, https://github.com/Seeed-Studio/Seeed_PCA9685 Grove PCA9685 : https://wiki.seeedstudio.com/Grove-16-Channel_PWM_Driver-PCA9685 Servo MG90 à 270° (DMS-MG90-A) https://www.dfrobot.com/product-1970.html */ #include "PCA9685.h" #include ServoDriver servo; void setup() { Wire.begin(); // join I2C bus Serial.begin(9600); servo.init(0x7f); } void loop() { // Test avec 4 servos for (int i = 1; i < 5; i++) { servo.setAngle(i, 0); delay(1000); servo.setAngle(i, 90); delay(1000); } } Le sketch ci-dessous est utile pour mettre les servo en position centrale avant de les inclure dans le montage : /* Test / Remise à zéro de servomoteurs servomoteurs avec seeeduino lotus + module grove PCA9685 16-Chan I2C PWM driver pour programmer la lotus, choisir arduino uno dans l'IDE arduino 1.8.5 @ Kirin, pierre@lesporteslogiques.net / 7 déc. 2022 + lib. Seeed PCA9685 library, https://github.com/Seeed-Studio/Seeed_PCA9685 Grove PCA9685 : https://wiki.seeedstudio.com/Grove-16-Channel_PWM_Driver-PCA9685 Servo MG90 à 270° (DMS-MG90-A) https://www.dfrobot.com/product-1970.html On peut relancer la procédure en faisant un reset de la carte */ #include "PCA9685.h" #include ServoDriver servo; boolean centerdone = false; void setup() { Wire.begin(); // join I2C bus Serial.begin(9600); servo.init(0x7f); } void loop() { // Remettre les servos au centre if (!centerdone) { for (int i = 1; i < 6; i++) { servo.setAngle(i, 45); delay(2000); servo.setAngle(i, 135); delay(3000); servo.setAngle(i, 90); delay(2000); } centerdone = true; } else { delay(100); } } À noter : les servos ont une amplitude de 270°, la fonction [[https://www.arduino.cc/reference/en/libraries/servo/write/|servo.write()]] d'arduino prend en argument des valeurs entre 0 et 180. Dans le fichier [[https://github.com/arduino-libraries/Servo/blob/master/src/Servo.h|Servo.h]] de la librairie servo, on peut trouver les valeurs extrèmes utilisées (ci-dessous), dont dans notre cas 0 correspond à -135° et 180 correspond à +135°... (Ce modèle de servo fonctionne entre 500 et 2500, mais je garde les valeurs prédéfinies, les servos n'auront pas besoin de parcourir toute leur amplitude) #define MIN_PULSE_WIDTH 544 // the shortest pulse sent to a servo #define MAX_PULSE_WIDTH 2400 // the longest pulse sent to a servo #define DEFAULT_PULSE_WIDTH 1500 // default pulse width when servo is attached ===== Joystick ===== Pour enregistrer les mouvements des servos Possible d'utiliser un de ces modèles en ajoutant les boutons * https://www.thingiverse.com/thing:3250017 * https://www.thingiverse.com/thing:1276108 * https://www.thingiverse.com/thing:700346 On utilise une boite de dérivation électrique avec un joystick analogique (voir photo en bas de page) [{{:openatelier:projet:tete_animatronique:bechele2-joystick.jpg?direct&600||Schéma de [[https://zappedmyself.com/animatronics/bechele2-info/|PacketBob]]}}] // Bechele2 Joystick Code V2.1 Sept 2021 // // Arduino code for the joystick used for programming servo movements in Bechele2 animatronic software: // http://bechele.de/pages/english/72-0.html // // Based on original code written by Rolf Jethon: // http://bechele.de/pages/english/77-0.html // // For more info on building this joystck: // https://zappedmyself.com/animatronics/bechele2-info/ // // This code sends the Joystick X & Y values and the button status to the Raspberry Pi // Each time the number 4 (ASCII value 52) is received from Raspberry Pi the data is sent // // Can run on any Arduino variant (I used a NANO clone) // - Cleaned up comments and naming // - Added code internal pullups to simplify wiring // - Changed the joystick averaging code to get better range of ADC values //***PIN ASSIGNMENTS***// #define Y_PIN A0 // Analog input pin that the X axis pot is connected to #define X_PIN A1 // Analog input pin that the Y axis pot is connected to #define BUTTON1_PIN 2 // Digital input pin the START button is connected to #define BUTTON2_PIN 3 // Digital input pin the STOP button is connected to //***CUSTOMIZE VALUES***// #define BAUD_RATE 19200 // Baud rate for serial port #define ALPHA_VALUE 0.9 // Averaging factor (0.1 - 1.0) higher value = faster averaging //***VARIABLE DECLARATION***// int xAxisValue = 496; // set X value to middle of possible range int yAxisValue = 496; // set Y value to middle of possible range int xAxisMax = 1022; int yAxisMax = 1022; int xVal; int yVal; int inByte = 0; // incoming serial byte float alphaFactor = ALPHA_VALUE; // set to defined value //***MICROCONTROLLER CONFIGURATION***// void setup() { pinMode(BUTTON1_PIN, INPUT_PULLUP); pinMode(BUTTON2_PIN, INPUT_PULLUP); Serial.begin(BAUD_RATE); // Setup serial port speed } //***START OF MAIN LOOP***// void loop() { xAxisValue = alphaFactor * analogRead(X_PIN) + (1 - alphaFactor) * xAxisValue; // Get Xaxis value and average it delay(3); yAxisValue = alphaFactor * analogRead(Y_PIN) + (1 - alphaFactor) * yAxisValue; // Get Yaxis value and average it int button1State = digitalRead(BUTTON1_PIN); // Get Button 1 state int button2State = digitalRead(BUTTON2_PIN); // Get Button 2 state xVal = xAxisMax - xAxisValue; yVal = yAxisMax - yAxisValue; // Test /* Serial.print(xVal); Serial.print(" "); Serial.print(yVal); Serial.print(" "); Serial.print(button1State); Serial.print(" "); Serial.println(button2State); */ // Test 2 (graphique) Serial.print(xVal); Serial.print(","); Serial.print(yVal); Serial.print(","); Serial.print(button1State * 1000); Serial.print(","); Serial.println(button2State * 1000); delay(50); /* if (Serial.available() > 0) { // Check to see if serial data request has been received inByte = Serial.read(); // Store serial data if (inByte == 52) { // Send data values if ASCII '4' is received Serial.print(xAxisValue); Serial.print(" "); Serial.print(yAxisValue); Serial.print(" "); Serial.print(button1State); Serial.print(" "); Serial.println(button2State); } inByte = 0; // Clear inByte value for next command }*/ } ===== Utilisation du module MotoPi RB-Moto3 ===== {{:openatelier:projet:tete_animatronique:rb-moto3.jpg?direct&300|}} Module pour Raspberry Pi : [[https://lesporteslogiques.net/materiel/__MODULES/servo_driver_16channels_joy-it_motopi_RB-Moto3/|documentation]] / [[https://www.joy-it.net/en/products/RB-Moto3|lien fabricant]] En fait, je ne sais pas si ça peut marcher avec le montage, ce module fonctionne avec une librairie python, se connecte en I2C alors que le code du projet «Bechele» est en perl... ===== Arduino + PCA9685 ===== Un module multiplexeur à base de PCA9685 permet de commander jusqu'à 16 servomoteurs, on peut chaîner plusieurs module pour commander encore plus de servomoteurs. La communication avec arduino se fait en I2C. Le condensateur électrochimique du module PCA9685 est adapté au nombre de servomoteurs utilisés : compter 100 µF par moteur [{{:openatelier:projet:tete_animatronique:arduino_servo_pca9685.jpg?direct&800|Photo [[https://learn.adafruit.com/16-channel-pwm-servo-driver/hooking-it-up|Adafruit]]}}] Code d'exemple avec la lib. [[https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library|Adafruit PWM Servo]]: /* Test servo arduino 1.8.5 @ Kirin, pierre@lesporteslogiques.net / 27 mars 2023 + lib. Adafruit PWM Servo https://github.com/adafruit/Adafruit-PWM-Servo-Driver-Library Réglages de la carte PCA9685 Testé avec Grove Beginner Kit (vu Comme Arduino Genuino/Uno) Sans réglage, ça fonctionne corectement à l'adresse I2C : 0x40 */ #include #include // called this way, it uses the default address 0x40 Adafruit_PWMServoDriver pwm = Adafruit_PWMServoDriver(); // Depending on your servo make, the pulse width min and max may vary, you // want these to be as small/large as possible without hitting the hard stop // for max range. You'll have to tweak them as necessary to match the servos you // have! #define SERVOMIN 150 // This is the 'minimum' pulse length count (out of 4096) #define SERVOMAX 600 // This is the 'maximum' pulse length count (out of 4096) #define USMIN 600 // This is the rounded 'minimum' microsecond length based on the minimum pulse of 150 #define USMAX 2400 // This is the rounded 'maximum' microsecond length based on the maximum pulse of 600 #define SERVO_FREQ 50 // Analog servos run at ~50 Hz updates // our servo # counter uint8_t servonum = 0; uint8_t servonum_max = 1; void setup() { Serial.begin(9600); Serial.println("8 channel Servo test!"); pwm.begin(); /* * In theory the internal oscillator (clock) is 25MHz but it really isn't * that precise. You can 'calibrate' this by tweaking this number until * you get the PWM update frequency you're expecting! * The int.osc. for the PCA9685 chip is a range between about 23-27MHz and * is used for calculating things like writeMicroseconds() * Analog servos run at ~50 Hz updates, It is importaint to use an * oscilloscope in setting the int.osc frequency for the I2C PCA9685 chip. * 1) Attach the oscilloscope to one of the PWM signal pins and ground on * the I2C PCA9685 chip you are setting the value for. * 2) Adjust setOscillatorFrequency() until the PWM update frequency is the * expected value (50Hz for most ESCs) * Setting the value here is specific to each individual I2C PCA9685 chip and * affects the calculations for the PWM update frequency. * Failure to correctly set the int.osc value will cause unexpected PWM results */ pwm.setOscillatorFrequency(27000000); pwm.setPWMFreq(SERVO_FREQ); // Analog servos run at ~50 Hz updates delay(10); } // You can use this function if you'd like to set the pulse length in seconds // e.g. setServoPulse(0, 0.001) is a ~1 millisecond pulse width. It's not precise! void setServoPulse(uint8_t n, double pulse) { double pulselength; pulselength = 1000000; // 1,000,000 us per second pulselength /= SERVO_FREQ; // Analog servos run at ~60 Hz updates Serial.print(pulselength); Serial.println(" us per period"); pulselength /= 4096; // 12 bits of resolution Serial.print(pulselength); Serial.println(" us per bit"); pulse *= 1000000; // convert input seconds to us pulse /= pulselength; Serial.println(pulse); pwm.setPWM(n, 0, pulse); } void loop() { // Drive each servo one at a time using setPWM() Serial.println(servonum); for (uint16_t pulselen = SERVOMIN; pulselen < SERVOMAX; pulselen++) { pwm.setPWM(servonum, 0, pulselen); } delay(500); for (uint16_t pulselen = SERVOMAX; pulselen > SERVOMIN; pulselen--) { pwm.setPWM(servonum, 0, pulselen); } delay(500); // Drive each servo one at a time using writeMicroseconds(), it's not precise due to calculation rounding! // The writeMicroseconds() function is used to mimic the Arduino Servo library writeMicroseconds() behavior. for (uint16_t microsec = USMIN; microsec < USMAX; microsec++) { pwm.writeMicroseconds(servonum, microsec); } delay(500); for (uint16_t microsec = USMAX; microsec > USMIN; microsec--) { pwm.writeMicroseconds(servonum, microsec); } delay(500); servonum++; if (servonum > servonum_max) servonum = 0; // Testing the first 8 servo channels } ===== Rpi + Python + PCA9685 ===== Le montage se compose d'un Raspberry Pi qui communique, via I2C sur ses broches GPIO, à un contrôleur de 16 servos basé sur la puce PCA9685. Les servosmoteurs sont reliés à ce circuit. ==== Multiplexeur PCA9685 ==== {{:openatelier:projet:tete_animatronique:16-channel-pwm-controller-pca9685-module-overview.jpg?direct&600|}} ==== Montage ==== {{:openatelier:projet:tete_animatronique:adafruit_raspi_pca9685_i2c_with_servo.png?direct&600|}} Source du schéma : https://learn.adafruit.com/adafruit-16-channel-servo-driver-with-raspberry-pi/hooking-it-up Pour le brochage du Raspberry Pi 4, voir : https://lesporteslogiques.net/wiki/materiel/raspberry_pi/start#raspberry_pi_4_model_b === Préparation du Raspberry Pi pour I2C === Installation de paquets sudo apt-get install -y python-smbus # support d'I2C dans python sudo apt-get install -y i2c-tools # entre autre pour scanner le port I2C Configurer le support par le kernel sudo raspi-config # choisir interface options/I2C/activer l'interface Puis redémarrer sudo reboot Ensuite on peut tester que le module PCA9685 est bien branché sudo i2cdetect -y 1 # Le port I2C numéro 1 est utilisé sur les rpi > 512 MB de RAM Ce qui devrait afficher (les adresses des ports utilisés sont indiquées) {{:openatelier:projet:tete_animatronique:i2cdetect_resultat.png|}} ==== Circuit complet ==== [{{:openatelier:projet:tete_animatronique:barbichette_schema_general_bechele_proto1.png?direct&600|Schéma de [[https://bechele.de/|Rolf Jethon]] }}] ==== Communication I2C vers les servomoteurs ==== En utilisant Adafruit Servokit Library : https://docs.circuitpython.org/projects/servokit/en/latest/ * https://github.com/adafruit/Adafruit_CircuitPython_Bundle * https://github.com/adafruit/Adafruit_CircuitPython_ServoKit Installation sudo pip3 install adafruit-circuitpython-servokit python3.7 -m pip install adafruit-circuitpython-servokit (Dans l'IDE geany, penser à changer les chemins vers l'exécutable de python, menu "construire" > "définir les outils de construction") import time from adafruit_servokit import ServoKit # Set channels to the number of servo channels on your kit. # 8 for FeatherWing, 16 for Shield/HAT/Bonnet. kit = ServoKit(channels=16) kit.servo[0].angle = 180 #kit.continuous_servo[1].throttle = 1 time.sleep(1) #kit.continuous_servo[1].throttle = -1 time.sleep(1) kit.servo[0].angle = 0 #kit.continuous_servo[1].throttle = 0 ==== Test des servomoteurs ==== Définir sur quelles broches sont reliés les servomoteurs, fixer minimum et maximum pour chacun. import time from adafruit_servokit import ServoKit # Set channels to the number of servo channels on your kit. # 8 for FeatherWing, 16 for Shield/HAT/Bonnet. kit = ServoKit(channels=16) # Correspondances (gauche/droite pour la tête) # commands du côté droit inversées # 0 : sourcil gauche (50, 135) # 1 : sourcil droit (inv) (135, 50) # 2 : machoire basse (?, ?) # 3 : oeil gauche (50, 130) # 4 : oeil droit (50, 130) # 5 : paupière gauche () PROBLEME # 6 : paupière droite () PROBLEME # 7 : bouche gauche (50, 110) PROB : refaire mécanisme # 8 : bouche droite (inv) (110, 50) PROB : refaire mécanisme # 9 : yeux (50, 130) for boucle in range(0, 3) : kit.servo[0].angle = 135 kit.servo[1].angle = 50 kit.servo[2].angle = 50 kit.servo[3].angle = 130 kit.servo[4].angle = 130 # ~ kit.servo[5].angle = 80 # ~ kit.servo[6].angle = 80 kit.servo[7].angle = 50 kit.servo[8].angle = 110 kit.servo[9].angle = 50 time.sleep(1) kit.servo[0].angle = 50 kit.servo[1].angle = 135 kit.servo[2].angle = 120 kit.servo[3].angle = 50 kit.servo[4].angle = 50 # ~ kit.servo[5].angle = 100 # ~ kit.servo[6].angle = 100 kit.servo[7].angle = 110 kit.servo[8].angle = 50 kit.servo[9].angle = 130 time.sleep(1) kit.servo[0].angle = 90 kit.servo[1].angle = 90 kit.servo[2].angle = 90 kit.servo[3].angle = 90 kit.servo[4].angle = 90 # ~ kit.servo[5].angle = 90 # ~ kit.servo[6].angle = 90 kit.servo[7].angle = 90 kit.servo[8].angle = 90 kit.servo[9].angle = 90 time.sleep(2) ==== Expressions ==== Test de quelques expressions du visage animatronique import time from adafruit_servokit import ServoKit # Set channels to the number of servo channels on your kit. # 8 for FeatherWing, 16 for Shield/HAT/Bonnet. kit = ServoKit(channels=16) # Correspondances (gauche/droite pour la tête) # commands du côté droit inversées # 0 : sourcil gauche (50, 135) # 1 : sourcil droit (inv) (135, 50) # 2 : machoire basse (?, ?) # 3 : oeil gauche (50, 130) # 4 : oeil droit (50, 130) # 5 : paupière gauche () PROBLEME # 6 : paupière droite () PROBLEME # 7 : bouche gauche (50, 110) PROB : refaire mécanisme # 8 : bouche droite (inv) (110, 50) PROB : refaire mécanisme # 9 : yeux (50, 130) def moue(): kit.servo[0].angle = 50 kit.servo[1].angle = 135 kit.servo[2].angle = 120 kit.servo[3].angle = 70 kit.servo[4].angle = 110 # ~ kit.servo[5].angle = 100 # ~ kit.servo[6].angle = 100 kit.servo[7].angle = 110 kit.servo[8].angle = 50 kit.servo[9].angle = 130 time.sleep(2) def sleep(): kit.servo[0].angle = 90 kit.servo[1].angle = 90 kit.servo[2].angle = 90 kit.servo[3].angle = 90 kit.servo[4].angle = 90 # ~ kit.servo[5].angle = 90 # ~ kit.servo[6].angle = 90 kit.servo[7].angle = 90 kit.servo[8].angle = 90 kit.servo[9].angle = 90 time.sleep(2) def louche(): kit.servo[0].angle = 135 kit.servo[1].angle = 50 kit.servo[2].angle = 120 kit.servo[3].angle = 130 kit.servo[4].angle = 50 # ~ kit.servo[5].angle = 100 # ~ kit.servo[6].angle = 100 kit.servo[7].angle = 110 kit.servo[8].angle = 50 kit.servo[9].angle = 130 time.sleep(2) louche() moue() sleep() louche() sleep() ==== Réception OSC ==== Trouver l'adresse IP du RPi hostname -I Pour tester la réception OSC : écouter le traffic sur le port UDP 12345 nc -l -u 12345 Version du système/kernel installé hostnamectl Installer python OSC : pip3 install python-osc ==== Communication série avec le joystick arduino ==== **Attention aux niveaux de tension si connexion directe aux broches GPIO 3V3 != 5V)** Dans le joystick, un arduino envoie des informations sur le port USB-série vers le raspberry pi, à 19200 bps \\ On peut vérifier que le port série est bien reconnu avec ''lsusb'' \\ Et utiliser ''ls /dev/tty*'' pour voir si le port utilisable Penser aussi à ajouter l'utilisateur au groupe ''dialout'' : sudo adduser pi dialout python3 -m pip install pyserial # installer les bibliothèques Ensuite ce sketch arduino : #!/usr/bin/env python3 # source : https://roboticsbackend.com/raspberry-pi-arduino-serial-communication/ # arduino relié à /dev/ttyUSB0 (pour trouver le port : ls /dev/tty*) # baud rate à 19200, correspond à celui défini dans arduino # timeout : durée allouée à la lecture série # readline() : lit jusqu'au caractère de fin de ligne # decode('utf- 8') : transforme les bytes réçues dans le type souhaité # rstrip() : retire les caractères de fin de ligne import serial if __name__ == '__main__': ser = serial.Serial('/dev/ttyUSB0', 19200, timeout=1) # vider le buffer série en début de communication ser.reset_input_buffer() while True: # y a t'il des données en attente ? if ser.in_waiting > 0: line = ser.readline().decode('utf-8').rstrip() print(line) Voir aussi : https://www.aranacorp.com/fr/communication-serie-entre-raspberry-pi-et-arduino/ Pour adapter les niveaux logiques, voir : * https://www.okdo.com/project/level-shifting/?ok_ts=1680009581943 * https://raspberrypi.stackexchange.com/questions/77176/raspberry-pi-gpio-input-voltage-limit ===== Alimentation ===== A base d'une alimentation d'ordinateur ATX à 24 broches : https://en.wikipedia.org/wiki/ATX#Power_supply ===== Montage ===== Pour le montage du mécanisme des yeux, se reférer à cette vidéo : https://www.youtube.com/watch?v=U1c4R2EB83A Il est nécessaire de percer et tarauder les pièces avant le montage : {{:openatelier:projet:tete_animatronique:yeux_plan_de_percements.png?direct&1000|}} {{:openatelier:projet:tete_animatronique:yeux_plan_de_taraudage.png?direct&1000|}} ===== Impression résine ===== On imprime des pièces en résine avec la [[outil:imprimante_3d_anycubic_photon_mono_4k:start|anycubic photon mono 4K]] (Ces pièces sont trop fragiles en impression 3D PLA). Deux plateaux sont préparés pour l'impression. {{:openatelier:projet:tete_animatronique:plateau_1.png?direct&600|}} {{:openatelier:projet:tete_animatronique:plateau_2.png?direct&600|}} Et comme ça marche plutôt bien, on en fait 2 autres! {{:openatelier:projet:tete_animatronique:plateau_3.png?direct&600|}} {{:openatelier:projet:tete_animatronique:plateau_4.png?direct&600|}} Et un petit dernier. (nb: ça aurait été plus malin de grouper les pièces par catégorie sur chaque plateau) {{:openatelier:projet:tete_animatronique:plateau_5.png?direct&600|}} ===== Installation du raspberry pi ===== Le projet est fourni avec une image pour raspberry pi 3 mais vu que c'est difficile de se procurer ce genre de carte en ce moment, on part sur une installation manuelle sur un raspberry pi 4 Version du Pi 4 : Raspbian 10 buster (lsb_release -a) téléchargement du fichier https://bechele.de/wp-content/uploads/2022/07/bechele2.tar.gz (depuis https://bechele.de/?page_id=80) **Installation des bibliothèques nécessaires** sudo apt update sudo apt install cpanminus sudo apt install wiringpi sudo apt install alsa-utils sudo apt install mpg123 sudo apt install i2c-tools sudo apt install perl5 # déjà installé sudo apt install perl-device-serialport # ne fonctionne pas sudo apt install libdevice-serialport-perl sudo cpanm strict sudo cpanm Device::SerialPort sudo apt install ncurses-base ncurses-bin sudo apt install libncurses5-dev libncursesw5 libncursesw5-dev sudo cpanm Curses::UI sudo cpanm WiringPi::API sudo cpanm File::Find::Rule sudo cpanm Device::PWMGenerator::PCA9685 sudo cpanm Audio::Play::MPG123 sudo cpanm Time::HR **Installation des scripts** les fichiers téléchargés sont dans le dossier /home/pi/bechele, on les copie dans les bons dossiers de /usr avec sudo. sudo cp /home/pi/bechele/usr/lib/systemd/system/runlive.service /usr/lib/systemd/system/ sudo cp -R /home/pi/bechele/usr/local/bin/* /usr/local/bin/ Les fichiers à copier dans /home sont copiés manuellement. **Configuration du Raspberry Pi** Il faut activer la communication I2C, pour cela sudo raspi-config # choisir dans le menu : interface, puis I2C ==== Test pour commander les moteurs en python ==== Une fois le PCA9685 relié à 2 moteurs et au rpi, le rpi configuré pour communiquer en I2C, un premier test en python ===== Journal ===== Journal partiel, pour poster quelques photos sur des étapes importantes **7 décembre 2022** : pour le software : A. teste les capacités du client léger pour voir s'il est capable de traiter de l'image vidéo en CV, plutôt oui! L'install. d'OpenFrameworks + CV n'est pas triviale mais à la fin ça fonctionne plutôt bien... pour le hardware : pas mal de petite quincaillerie pour laquelle il manque toujours une pièce, aujourd'hui c'était de tige filetée de 3mm, les moteurs sont installés, le prototype prend forme, ça mérite une photo. {{:openatelier:projet:tete_animatronique:20221207_proto_en_construction.jpg?direct&600|}} **4 janvier 2023** : en continuant le montage, je casse une pièce fragile, à réimprimer donc... c'est compliqué de trouver des vis DIN915 mais on ne peut pas vraiment s'en passer (trouvées finalement sur la boutique en ligne d'un vendeur du marketplace d'amazon). **18 janvier 2023** : la reconnaissance de visage fonctionne bien sur le client léger qu'on envisageait! A. a écrit du code pour lisser les mouvements et différencier différents types de sourires. Montage du joystick pour piloter les yeux et enregistrer les séquences. {{:openatelier:projet:tete_animatronique:barbichette_montage_joystick.jpg?direct&1200|}} {{:projets:barbichette_application.jpg?direct&1200|}} **2 mars 2023** : **TODO** photos des prototypes d'animatronique, l'impression 3D en PLA est trop fragile, il va falloir penser à tout refaire en résine... {{:openatelier:projet:tete_animatronique:20230302_barbichette.jpg?direct&1200|}} **14 juin 2023** : électronique ok, prototype construit et actionné par script python depuis le raspberry, une vidéo des premiers essais d'expression {{:openatelier:projet:tete_animatronique:barbichette_20230614_175450.jpg?direct&800|}}{{:openatelier:projet:tete_animatronique:20230614_barbichette_prototype.mp4|}} **15 juin 2023** scripts (à renommer en .gz) {{ :openatelier:projet:tete_animatronique:20230615_scripts_barbichette.gz.txt |}} ==== Prototype 1 ==== **16 juin 2023** scripts : {{ :openatelier:projet:tete_animatronique:20230616_scripts.gz.txt |}} (à renommer en .gz) Quelques détails : **ui_servo_expressions.py** contrôle par interface graphique (sliders, etc.) des servomoteurs de la tête animatronique **osc_envoi_simulation.py** simulation d'envoi OSC (utile si l'ordi de détection n'est pas relié) **osc_reception_test.py** vérification que les messages OSC sont bien reçus (pas d'action sur les servos) **osc_reception_tracking_visage.py** script principal, reçoit les messages envoyés par l'ordi de détection et agit sur les servos en conséquence **serie_read_test.py** réception des messages série d'arduino **servo_expressions.py** (obsolète) quelques tests d'expressions **servo_paupieres_test.py** (test seulement) **servo_pca9685_test.py** (test seulement, I2C) Parfois une erreur 121 dans I2C / Rpi / Python * bus overloadé * fils trop longs (30cm max pour I2C, capacitance maximum de 400 pF dépassée) * pull ups trop forts (il y a déjà des pull-ups dans les broches GPIO du Pi) -> supprimer ceux de la carte * cf. https://raspberrypi.stackexchange.com/questions/124453/error-121-remote-i-o-error-in-smbus-py-call Et quelques notes * TODO / code : ajouter la bouche dans le script ui_servo_expressions.py * TODO / code : contrôle des mouvements par pure data (pratique pour séquencer) * TODO / install : solidariser caméra et robot /!\ captation audio et moteurs * TODO / install : enceinte derrière le robot * TODO / tête : refixer paupière, limer quelques pièces * TODO / install : mode veille ? **Nécessite un réseau local dans cette version!** ===== Ressources ===== Sur l'animatronique : https://zappedmyself.com/animatronics/animatronic-projects/ \\ Une autre paire d'yeux : https://www.instructables.com/DIY-Compact-3D-Printed-Animatronic-Eye-Mechanism/ \\