{{tag>arduino audio séquenceur optique em}} Page créée le 9 septembre 2020 ====== Platine séquenceur ====== Transformation d'une platine disque en séquenceur optique : des capteurs posés le long du bras de la platine mesurent la lumière qu'ils reçoivent. Le disque est en carton/papier sur lequel sont tracées des formes au feutre. ===== Platine disque ===== La platine est une Pioneer PL-X11Z. Elle est conçu pour être alimentée en étant connectée à la chaine hifi par un mini-jack, en 12V. Elle fonctionne mais il manque la courroie. Dans un premier temps, on remplace la courroie manquante par un élastique assez grand, à section carrée. {{:openatelier:projet:platine_sequenceur:prototype_001_dessous.jpg?direct&600|}} **Petits calculs** Un tour complet du plateau s'effectue en 1333.33 millisecondes (en position 45 tours/minute) et 1818 millisecondes en position 33 tours/minute Avec un disque de 30 cm, la circonférence extérieure est de 94 cm ( 2 * pi * r) En 33 tours / minute : \\ Si on divise le disque en 4 parties égales, chacune occupe 454 millisecondes soit un tempo de 132 [[https://fr.wikipedia.org/wiki/Battement_par_minute|BPM]] (60 / 0.454ms), en deux parties égales : BPM 66, etc. En 45 tours minute : \\ 4 parties : chacune 333.33 ms soit un BPM de 180 / 2 parties = BPM de 90 ===== Système ===== bras de la platine avec capteur -> multiplexeur -> arduino -(usb-série)-> ordi avec patch pure data ===== Premier prototype ===== {{:openatelier:projet:platine_sequenceur:prototype_001_vue_generale.jpg?direct&600|}} {{:openatelier:projet:platine_sequenceur:prototype_001_bras_lecteur.jpg?direct&600|}} Le premier montage utilise 8 photorésistances, à chacune d'entre elle est associée une led pour fournir un éclairage homogène. \\ Problème : les photorésistances sont un peu lentes \\ ==== Schéma ==== {{:openatelier:projet:platine_sequenceur:prototype_001_circuit.png?direct&600|}} ===== Second prototype ===== Dans cette version, les photorésistances sont remplacées par des phototransistors pour augmenter la vitesse de détection, le circuit électronique est adapté en conséquence. Deux pièces en impression 3D sont utilisées : la première pour maintenir le bras (dont le mécanisme de retour automatique a été désactivé) et la seconde pour fixer les composants. \\ A l'origine la platine est alimentée en 12V par la chaîne hifi, après modification nous avons installé une alimentation directe par bloc secteur / transfo 12V et un interrupteur de marche-arrêt. {{:openatelier:projet:platine_sequenceur:prototype_002_vue_generale.jpg?direct&600|}} ==== Schéma ==== Dans cette version, 6 phototransistors sont utilisés, sans multiplexeur. A chaque phototransistor est associé deux résistances (en reprenant les valeurs définies dans le projet de Yunchi Luo et Mengliang Yu de l'université Cornell, voir sources en bas de page) **/!\ dans le montage, le ruban de leds est alimenté séparément pour éviter les parasites** {{:openatelier:projet:platine_sequenceur:prototype_002_circuit.png?direct&800|}} ==== Pièces ==== === Repose-bras (ou quelque chose comme ça) === {{:openatelier:projet:platine_sequenceur:platine_sequenceur_porte_bras.png?direct&600|}} {{ :openatelier:projet:platine_sequenceur:platine_sequenceur_porte_bras.stl |}} /* Élément pour la platine séquenceur Quimper, La Baleine, 23 septembre 2020 OpenSCAD version 2019.05 @ kirin / Debian 9.5 */ difference() { union() { cylinder(h=6, r=5, center=true, $fn=36); translate([0,0,-3]) cylinder(h=1.5, r=12, center=true, $fn=72); translate([-5,0,1]) cube(size=[10,19,2]); translate([-5,4.7,1]) cube(size=[10,2,7]); translate([-5,17,1]) cube(size=[10,2,7]); } translate([0,0,-0.4]) cylinder(h=7, r=3.9, center=true, $fn=36); } === Adaptateur pour les capteurs === {{:openatelier:projet:platine_sequenceur:platine_sequenceur_bras_porte_capteur.png?direct&600|}} {{ :openatelier:projet:platine_sequenceur:platine_sequenceur_bras_porte_capteur.stl |}} /* Élément pour la platine séquenceur bras porte capteur Quimper, La Baleine, 23 septembre 2020 OpenSCAD version 2019.05 @ kirin / Debian 9.5 */ difference() { color("Yellow") { difference() { translate([-10,-7.5,0]) cube(size=[12,15,100]); #union() { translate([0,0,10]) cube(size=[30,30,10], center=true); translate([0,0,25]) cube(size=[30,30,10], center=true); translate([0,0,40]) cube(size=[30,30,10], center=true); translate([0,0,55]) cube(size=[30,30,10], center=true); translate([0,0,70]) cube(size=[30,30,10], center=true); translate([0,0,85]) cube(size=[30,30,10], center=true); } } translate([-12,-7.5,-70]) cube(size=[3,15,170]); color("Lime") translate([-12,-7.5,0]) cube(size=[13.5,3,100]); color("Lime") translate([-12,4.5,0]) cube(size=[13.5,3,100]); } # color("Cyan") { translate([0,0,-1]) cylinder(h=102, r=4.5, center=false, $fn=36); translate([0,-4.5,-1]) cube(size=[9,9,102]); } } color("Blue") translate([-12,-9.49,-56]) cube(size=[12,2,8]); color("Blue") translate([-12,7.49,-56]) cube(size=[12,2,8]); * color("Green") translate([0,4.5,0]) rotate([0, 0, -45]) translate([0, 1, 0]) cube(size=[1,10,80]); * color("Green") translate([0.5,-3.5,0]) rotate([0, 0, -135]) cube(size=[1,13,100]); /* barre sans trou color("Red") translate([3.25,-10.4,50]) rotate([0, 0, 30]) cube(size=[1,13,100],center=true); */ color("Red") translate([6.5,-16.85,0]) rotate([0, 0, 30]) plaque_phototransistor(); color("Red") translate([3.25,10.4,50])rotate([0, 0, 150]) cube(size=[1,13,100],center=true); module plaque_phototransistor() { difference() { cube(size=[1,13,100],center=false); #union() { rotate([0,90,0]) translate([-6,5,0]) cylinder(h=3, r=0.6, center=true, $fn=8); rotate([0,90,0]) translate([-6,8,0]) cylinder(h=3, r=0.6, center=true, $fn=8); rotate([0,90,0]) translate([-22.5,5,0]) cylinder(h=3, r=0.6, center=true, $fn=8); rotate([0,90,0]) translate([-22.5,8,0]) cylinder(h=3, r=0.6, center=true, $fn=8); rotate([0,90,0]) translate([-39,5,0]) cylinder(h=3, r=0.6, center=true, $fn=8); rotate([0,90,0]) translate([-39,8,0]) cylinder(h=3, r=0.6, center=true, $fn=8); rotate([0,90,0]) translate([-55.5,5,0]) cylinder(h=3, r=0.6, center=true, $fn=8); rotate([0,90,0]) translate([-55.5,8,0]) cylinder(h=3, r=0.6, center=true, $fn=8); rotate([0,90,0]) translate([-72,5,0]) cylinder(h=3, r=0.6, center=true, $fn=8); rotate([0,90,0]) translate([-72,8,0]) cylinder(h=3, r=0.6, center=true, $fn=8); rotate([0,90,0]) translate([-89,5,0]) cylinder(h=3, r=0.6, center=true, $fn=8); rotate([0,90,0]) translate([-89,8,0]) cylinder(h=3, r=0.6, center=true, $fn=8); } } } ==== Code d'envoi ==== Le code arduino comprend : une phase de calibration, la mesure des capteurs et l'envoi des données vers l'ordinateur, en série /* * Platine sequenceur / prototype 002 * http://lesporteslogiques.net/wiki/openatelier/projet/platine_sequenceur * Quimper, La baleine, 24 sept 2020 * Debian 9.5 @ kirin / arduino 1.8.5 * + library Adafruit NeoPixel 1.1.3 https://github.com/adafruit/Adafruit_NeoPixel * * CIRCUIT * - 6 phototransistors reliés aux entrées analogiques * - ruban de 8 leds RGB * * MODES DE FONCTIONNEMENT (à régler dans le code) * Mode de réception des données (les données envoyées ne sont pas formatées de la même manière) * 0 pour le mode de test (traceur serie de l'arduino IDE) * 1 pour le mode de réception dans pure data * * VERSIONS * 001 : (prototype 001, photorésistances) envoi de valeurs brutes en série * 002 : (prototype 001, photorésistances) ajout des leds + calibration * 003 : (prototype 002, phototransistors) * * TODO * ajouter un bouton de calibration * ajouter un switch de mode 0 ou 1 * ajouter une led (clignote = calibration, éteinte mode 0, allumée mode 1) * * RESSOURCES * - traitements de lissage des données : https://www.openprocessing.org/sketch/686436 */ int MODE = 0; // Inclure les bibliothèques de fonction (libraries) nécessaires #include #ifdef __AVR__ #include #endif #define BROCHE_PT1 A1 // Broche reliée au phototransistor 1 #define BROCHE_PT2 A2 // Broche reliée au phototransistor 2 #define BROCHE_PT3 A3 // Broche reliée au phototransistor 3 #define BROCHE_PT4 A4 // Broche reliée au phototransistor 4 #define BROCHE_PT5 A5 // Broche reliée au phototransistor 5 #define BROCHE_PT6 A6 // Broche reliée au phototransistor 6 #define BROCHE_LED 5 // A quelle broche est relié le ruban de LEDs ? #define NUMPIXELS 6 // Combien de LEDs sur le ruban ? // Créer l'objet correspondant au ruban de LEDs Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, BROCHE_LED, NEO_RGB + NEO_KHZ800); int luminosite = 255; int v1b, v2b, v3b, v4b, v5b, v6b; // valeurs brutes int v1l, v2l, v3l, v4l, v5l, v6l; // valeurs lissées int v1c, v2c, v3c, v4c, v5c, v6c; // valeurs calibrées boolean CALIBRATION = true; long v1s, v2s, v3s, v4s, v5s, v6s; // sommes utilisées pour la calibration int v1i, v2i, v3i, v4i, v5i, v6i; // valeurs d'initialisation définies pendant la phase de calibration int calibration_start; // démarrage de la calibration à cette milliseconde! int calibration_compteur = 0; // utlisé pour le calcul réactualisé des moyennes void setup() { pixels.begin(); // Initialiser l'objet du ruban de leds Serial.begin(57600); // Fixer la luminosité pour l'ensemble du ruban pixels.setBrightness(luminosite); // Définir une couleur identique pour chaque LED, la LED 0 est la plus proche des broches for (int i = 0; i < 6; i++) { pixels.setPixelColor(i, pixels.Color( 255, 255, 255 )); } pixels.show(); delay(500); calibration_start = millis(); } void loop () { if (CALIBRATION) { calibration_compteur ++; if (millis() - calibration_start > 3000) { // L'étape de calibration dure 3 secondes CALIBRATION = false; v1i = (int)(v1s / (calibration_compteur - 1) ); v2i = (int)(v2s / (calibration_compteur - 1) ); v3i = (int)(v3s / (calibration_compteur - 1) ); v4i = (int)(v4s / (calibration_compteur - 1) ); v5i = (int)(v5s / (calibration_compteur - 1) ); v6i = (int)(v6s / (calibration_compteur - 1) ); v1l = v1i; v2l = v2i; v3l = v3i; v4l = v4i; v5l = v5i; v6l = v6i; } else { v1s += analogRead(BROCHE_PT1); delayMicroseconds(3); v2s += analogRead(BROCHE_PT2); delayMicroseconds(3); v3s += analogRead(BROCHE_PT3); delayMicroseconds(3); v4s += analogRead(BROCHE_PT4); delayMicroseconds(3); v5s += analogRead(BROCHE_PT5); delayMicroseconds(3); v6s += analogRead(BROCHE_PT6); delayMicroseconds(3); } } if (!CALIBRATION) { // Récupérer les valeurs actuelles v1b = analogRead(BROCHE_PT1); delayMicroseconds(3); v2b = analogRead(BROCHE_PT2); delayMicroseconds(3); v3b = analogRead(BROCHE_PT3); delayMicroseconds(3); v4b = analogRead(BROCHE_PT4); delayMicroseconds(3); v5b = analogRead(BROCHE_PT5); delayMicroseconds(3); v6b = analogRead(BROCHE_PT6); delayMicroseconds(3); v1l = (0.85 * v1l) + (0.15 * v1b) ; v2l = (0.85 * v2l) + (0.15 * v2b) ; v3l = (0.85 * v3l) + (0.15 * v3b) ; v4l = (0.85 * v4l) + (0.15 * v4b) ; v5l = (0.85 * v5l) + (0.15 * v5b) ; v6l = (0.85 * v6l) + (0.15 * v6b) ; v1c = (v1l - v1i) * -1; v2c = (v2l - v2i) * -1; v3c = (v3l - v3i) * -1; v4c = (v4l - v4i) * -1; v5c = (v5l - v5i) * -1; v6c = (v6l - v6i) * -1; if (MODE == 0) { Serial.print(v1c); Serial.print(","); Serial.print(v2c); Serial.print(","); Serial.print(v3c); Serial.print(","); Serial.print(v4c); Serial.print(","); Serial.print(v5c); Serial.print(","); Serial.println(v6c); //Serial.println(""); } if (MODE == 1) { Serial.print("photores "); Serial.print(v1c); Serial.print(" "); Serial.print(v2c); Serial.print(" "); Serial.print(v3c); Serial.print(" "); Serial.print(v4c); Serial.print(" "); Serial.print(v5c); Serial.print(" "); Serial.println(v6c); } delay(5); } } ==== Code réception ==== Le code pure data récupère les données série, et déclenche les sons en conséquence {{:openatelier:projet:platine_sequenceur:platine_sequenceur_004_puredata.png?direct&600|}} {{ :openatelier:projet:platine_sequenceur:platine_sequenceur_004_puredata.zip |}} ==== Disque ==== Un modèle de disque 33T à imprimer en A3, à l'échelle avec les 6 pistes correspondant à la position des capteurs. {{ :openatelier:projet:platine_sequenceur:modele_disque_gradue_a3_2.pdf |}} Les rythmes sont à dessiner dans le sens inverse des aiguilles d'une montre (lévogyre!), le disque tournant dans le sens des aiguilles (dextrogyre) Pour mémoire, distances des capteurs avec le centre du disque : 4,7 / 6,4 / 8,1 / 9,7 / 11,3 / 12,9 et les disques font 27,8 cm de diamètre (pour ne pas déborder du plateau, un vinyle format 33t fait 30 cm) ==== Problèmes, améliorations, etc. ==== Le signal des phototransistors est très parasité : \\ -> alimenter séparément les leds : **testé, et c'est beaucoup mieux** \\ -> utiliser la source de tension de référence 1.1V incluse dans l'arduino pour la capture analogique (plutôt que VCC) (pas testé) \\ -> traiter le signal (moyenne, etc) : **un lissage 85-15 est appliqué** (voir https://www.openprocessing.org/sketch/686436 ) \\ Autres améliorations possibles : \\ -> envoyer des messages série plus courts\\ -> mesurer les temps pour trouver un timing précis \\ -> tous les phototransistors ne réagissent pas de la même manière : **réglé en ajoutant des seuils définissables dans le patch pure data** \\ Ajouter quelques composants complémentaires (on verra plus tard) * un bouton pour lancer une calibration à n'importe quel moment * un switch pour basculer de mode "traceur série arduino" / "réception pure data" * une led pour indiquer tout ça ===== Sources et ressources ===== Datasheet du phototransistor Osram Opto SFH 309 : {{ :openatelier:projet:platine_sequenceur:phototransistor_osram-opto_sfh309.pdf |}}\\ Utilisation des phototransistors, un bon exemple : https://people.ece.cornell.edu/land/courses/ece4760/FinalProjects/s2010/yl477_my288/yl477_my288/index.html \\ Utilisation basique des phototransistors avec arduino : https://arduino103.blogspot.com/2017/12/comment-utiliser-un-photo-transistor.html \\ Groove Pizza : https://apps.musedlab.org/groovepizza/?museid=ucEbu-1J6& \\ Pocket Operations, a collection of drum patterns (pdf à télécharger sur https://shittyrecording.studio )\\ rhythm patterns : https://www.ethanhein.com/wp/2013/my-collection-of-transcribed-rhythm-patterns/ \\ Drum machine patterns : http://808.pixll.de/ \\ How to write beats : https://mccormick.cx/news/entries/how-to-write-beats.news \\