Ci-dessous, les différences entre deux révisions de la page.
Prochaine révision | Révision précédente | ||
wiki:flossmanuals:capacitif-plante-son-video:accueil [2021/05/31 17:26] 127.0.0.1 modification externe |
wiki:flossmanuals:capacitif-plante-son-video:accueil [2022/04/30 18:00] (Version actuelle) damien.muti [À Télécharger] |
||
---|---|---|---|
Ligne 12: | Ligne 12: | ||
---- | ---- | ||
+ | {{: | ||
+ | {{: | ||
- | ====== Intentions | + | ===== Intentions |
- | Dans le cadre d' | + | |
- | ====== | + | Dans le cadre de mon Macro-projet |
+ | |||
+ | ===== Objectifs | ||
+ | |||
+ | L’objectif de mon expérimentation est d’intégrer la part du vivant dans mes réalisations quelle soit humaine ou végétale. Pour ce faire, j’ai souhaité confectionner une table de mixage qui produit du son et envoie de la vidéo par des interactions avec la main. Cette table de mixage | ||
+ | |||
+ | ===== Références | ||
+ | |||
+ | Pour ce projet je me suis inspirée de Jean Thoby un pépiniériste qui voue une véritable passion pour le monde végétale. Jean Thoby avec l’aide d’ingénieurs, | ||
+ | |||
+ | ===== Protocole pour 8 plantes: ===== | ||
+ | {{: | ||
+ | |||
+ | ===== Installation: | ||
+ | {{: | ||
+ | Une fois les câbles bien branchés sur la BreadBoard, insérer les trois autres fils dans les plantes. Vérifiez bien que la terre est assez humide pour que les plantes puissent être conductrices. | ||
+ | {{: | ||
+ | |||
+ | {{ : | ||
+ | |||
+ | ===== À Télécharger | ||
+ | **Ensemble des programmes Processing | ||
+ | * {{ : | ||
+ | |||
+ | **Télécharger et installer les librairies Processing sur l'IDE :** | ||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | * [[https:// | ||
+ | |||
+ | **Problèmes récurrents :** | ||
+ | * Vérifier si c'est bien le bon port série. | ||
+ | * Si vous utilisez un mac laissez charger le programme pendant plusieurs minutes. | ||
+ | * Attention aux vidéos et musiques trop lourdes. | ||
+ | * Et si le programme ne marche toujours pas, vérifiez l' | ||
+ | ===== Code ===== | ||
+ | **1** => **Processing :** __test_7plantes_sonores > Gestion_interactivite.pde__ | ||
- | ====== Programmes ====== | ||
- | ===== Arduino ===== | ||
- | Le montage Arduino et le programme associé a pour but de mesurer les valeurs de plusieurs potentiomètres et sliders, d'un bouton et d'un capteur de distance à ultrason et de les envoyer au programme Processing pour traitement. | ||
- | Le code est le suivant : {{ : | ||
< | < | ||
+ | /** Plante sonore - Justine Gendreau | ||
+ | | ||
+ | /// librairies | ||
+ | import processing.sound.*; | ||
+ | import processing.video.*; | ||
+ | import processing.serial.*; | ||
- | #include " | ||
- | Ultrasonic ultrasonic(7); | ||
- | int Slider1 = 0; | + | // variables globales |
- | byte Slider1Pin = A0; | + | PImage im; // une image |
- | byte Slider2Pin = A1; // Slider 2 : yPerso | + | SoundFile[] son; // un son - un seul lecteur CD audio |
- | int Potentiometre1 = 0; // Potentiomètre 1 : ChoixPerso | + | Movie vid; // une vidéo |
- | byte Potentiometre1Pin = A2; | + | |
- | int Potentiometre2 = 0; | + | |
- | byte Potentiometre2Pin = A3; | + | |
- | int ChoixMesureDistance = 0; // Bouton poussoir | + | |
- | byte boutonPoussoirPin = 2; // broche de lecture du bouton poussoir | + | |
- | int Distance = 0; // distance lue sur le capteur de distance | + | // bouton image active ? // est-ce que l' |
- | int inByte | + | boolean animation_active |
- | byte ledPin | + | // bouton son actif ? |
+ | boolean son_actif | ||
+ | float tempsDebutSon = 0; // temps du début | ||
+ | // bouton videos active ? | ||
+ | boolean video_active[]; | ||
- | byte etat_bouton = 0; //La variable « etat_bouton » mémorise l’état HIGH ou LOW de la pate d’entrée | + | /// dialogue avec la carte Arduino |
- | byte old_etat_bouton = 0; //La variable « old_etat_bouton » mémorise l’ancien état de la variable « etat_bouton » | + | Serial myPort; // Create object from Serial class |
- | byte etat_led = 0; //La variable « etat_led » mémorise l’état 1 (allumée) ou 0 (éteinte) | + | int inBuffer; // Data received from the serial port |
+ | int donneePortSerie; | ||
- | boolean debug = false; | + | // seuil de détection |
- | boolean debug_Com_Serial | + | float seuil = 300; |
+ | // port serie | ||
+ | int nPlantes = 8;///////////////////// | ||
+ | int[] serialInArray = new int[nPlantes]; | ||
+ | int serialCount = 0; // A count of how many bytes we receive | ||
+ | int[] plante; | ||
+ | boolean firstContact = false; | ||
- | void setup() { | + | // média associés aux plantes |
- | | + | String[] nomSonPlante; |
- | | + | String[] nomvideosPlante; |
- | while (!Serial) { | + | |
- | | + | |
- | } | + | |
- | pinMode(boutonPoussoirPin, | ||
- | pinMode(ledPin, | ||
- | if (!debug) { | ||
- | establishContact(); | ||
- | } | ||
- | } | ||
- | void loop() { | + | void setup() { // initialisation des paramètres d' |
- | | + | |
+ | noStroke(); | ||
+ | background(0); | ||
- | // Si une donnée arrive dans le port série venant de processing = LIre les nouvelles valeurs | + | // initialisation |
- | | + | |
- | if (Serial.available() > 0) { | + | |
- | // lecture de la donnée sur le port série : lettre A | + | |
- | inByte = Serial.read(); | + | |
- | if (inByte == ' | + | |
- | // mesure sur les différents capteurs | + | |
- | gestionCapteurs(); | + | |
- | // Envoi des valeurs lues sur les différents capteurs vers Processing | + | |
- | | + | |
- | if (debug_Com_Serial) { ///// Debug | + | |
- | | + | |
- | } | + | for (int i=0; i< |
- | } | + | |
- | | + | |
} | } | ||
- | else { // mode debug | + | |
- | // mesure sur les différents capteurs | + | |
- | | + | |
- | // Envoi des valeurs lues sur les différents capteurs | + | |
- | | + | // |
- | | + | //} |
+ | nomSonPlante[0]= " | ||
+ | nomSonPlante[1]= " | ||
+ | nomSonPlante[2]= " | ||
+ | nomSonPlante[3]= " | ||
+ | nomSonPlante[4]= " | ||
+ | nomSonPlante[5]= " | ||
+ | nomSonPlante[6]= " | ||
+ | nomSonPlante[7]= " | ||
+ | |||
+ | // chargement | ||
+ | son =new SoundFile[nPlantes]; | ||
+ | for (int i=0; i< | ||
+ | | ||
} | } | ||
- | } | ||
- | void establishContact() { | + | // videos des plantes |
- | | + | |
- | | + | nomvideosPlante[0]= " |
- | delay(300); | + | |
+ | nomvideosPlante[2]= " | ||
+ | nomvideosPlante[3]= " | ||
+ | | ||
+ | nomvideosPlante[5]= " | ||
+ | nomvideosPlante[6]= " | ||
+ | nomvideosPlante[7]= " | ||
+ | |||
+ | video_active = new boolean[nPlantes]; | ||
+ | for (int i=0; i< | ||
+ | video_active[i]=false; | ||
} | } | ||
- | } | ||
- | void gestionBouton() { | ||
- | // mesure de l' | ||
- | etat_bouton = digitalRead(boutonPoussoirPin); | ||
- | if ((etat_bouton == LOW) && (old_etat_bouton == HIGH)) { | ||
- | // si l’entrée 2 est à l’état LOW (bouton appuyé) et que juste précédemment le bouton est ouvert | ||
- | etat_led = 1 - etat_led ; // inverse l’état de la led | ||
- | delay(10); // patienter 10ms pour éviter les rebonds avant d’allumer la led | ||
- | } | ||
- | old_etat_bouton = etat_bouton; | ||
- | ChoixMesureDistance = etat_led ; // choix du capteur de distance Ultrason ou du Slider | ||
- | if (etat_led == 1) {//si la led doit être allumée | ||
- | digitalWrite(ledPin, | ||
- | } | ||
- | else { // si la led est éteinte | ||
- | digitalWrite(ledPin, | ||
- | } | ||
- | } | ||
- | void gestionCapteurs() { | + | |
- | | + | |
- | Potentiometre1 = map(analogRead(Potentiometre1Pin), | + | |
- | // delay 10ms to let the ADC recover: | + | |
- | delay(10); | + | |
- | | + | // chargement de la videos |
- | // delay 10ms to let the ADC recover: | + | |
- | delay(10); | + | |
- | | + | /// Port série |
- | // delay 10ms to let the ADC recover: | + | // Print a list of the serial ports, for debugging purposes: |
- | | + | |
- | | + | |
- | if (ChoixMesureDistance | + | |
- | Distance = map(ultrasonic.MeasureInCentimeters(), 0, 400, 0, 255); // mesure de la distanceentre 0 et 400cm et ramener cette valeur entre 0 et 255 | + | |
- | | + | |
- | else { | + | |
- | Distance | + | |
- | } | + | |
} | } | ||
- | void envoiMesureVersProcessing() { | + | void draw() { |
- | Serial.write(Potentiometre1); | + | |
- | Serial.write(Potentiometre2); | + | |
- | Serial.write(Slider1); | + | |
- | Serial.write(Distance);// | + | |
- | } | + | |
- | void envoiMesureSurPortSerial() { | ||
- | Serial.println("" | ||
- | Serial.print(" | ||
- | Serial.print(etat_led); | ||
- | Serial.print(" | ||
- | Serial.print(Potentiometre1); | ||
- | Serial.print(" | ||
- | Serial.print(Potentiometre2); | ||
- | Serial.print(" | ||
- | Serial.print(Slider1); | ||
- | Serial.print(" | ||
- | Serial.print(Distance);// | ||
- | Serial.println("" | ||
- | } | ||
- | </ | ||
- | ===== Processing ===== | ||
- | ==== Programme initial ==== | ||
- | Le programme Processing a pour but de récupérer les différentes données envoyées par la carte Arduino. Chaque donnée constitue un paramètre d' | ||
- | Le rendu est le suivant | + | // print the values (for debugging purposes only): |
- | {{ : | + | |
+ | + " | ||
+ | + " | ||
- | Le programme est le suivant : {{ : | + | // |
+ | // | ||
- | <code> | + | ///////////////////////// |
- | import processing.serial.*; | + | for (int i=0; i<nPlantes; i++) { // pour chacune des plantes |
+ | | ||
+ | gestionVideoPlante(i, | ||
+ | } | ||
- | int bgcolor; | + | //// affichage de la vidéo si la vidéo i est active ////////////////////////// |
- | int fgcolor=255; | + | boolean |
- | Serial myPort; | + | for (int i=0; i< |
- | int NbData = 4; // nombre de données à récupérer de la carte Arduino | + | |
- | int[] serialInArray = new int[NbData]; | + | } |
- | int serialCount = 0; // A count of how many bytes we receive | + | |
- | int xPerso, yPerso, ChoixPerso, CouleurPerso, | + | |
- | boolean | + | |
- | PImage loubon; | + | |
- | PImage bouvier; | + | |
+ | if (une_video_active) { | ||
+ | image(vid, 0, 0, width, height); | ||
+ | } else { | ||
+ | background(0); | ||
+ | } | ||
- | void setup() { | ||
- | size(1000, | ||
- | noStroke(); | ||
- | colorMode(HSB); | ||
- | // Initialisation des variables | ||
- | ChoixPerso=0; | ||
- | CouleurPerso = 0; // | ||
- | xPerso = width/2; // Slider 1 | ||
- | yPerso = height/2; // Slider 2 - Distance | ||
- | sPerso = 250; //Taille du personnage | ||
- | bouvier = loadImage(" | ||
- | loubon= loadImage(" | ||
- | // Print a list of the serial ports, for debugging purposes: | ||
- | printArray(Serial.list()); | ||
- | // I know that the first port in the serial list on my mac | + | // affichage de l' |
- | // is always my FTDI adaptor, so I open Serial.list()[0]. | + | //if (animation_active) { |
- | // On Windows machines, this generally opens COM1. | + | // |
- | // Open whatever port is the one you're using. | + | |
- | String portName = Serial.list()[0]; | + | |
- | | + | |
} | } | ||
+ | </ | ||
- | void draw() { /////////////////////////////////////// | + | **2** => **Processing :** __ test_7plantes_sonores > test_7plantes_sonores.pde__ |
- | | + | < |
- | //fill(fgcolor); | + | ///////////////////////////////// |
- | | + | void gestionSonPlante(int i){ |
- | | + | |
+ | if (plante[i]==255 | ||
+ | // lancer le son associé à la plante i en boucle | ||
+ | son[i].loop(); | ||
+ | | ||
+ | | ||
+ | son[i].stop(); | ||
+ | } | ||
+ | // animation de la plante i | ||
+ | |||
+ | } | ||
- | | + | //////////////////////////////////////////////// |
- | | + | void gestionVideoPlante(int i, String nomVideo) { |
+ | | ||
+ | | ||
+ | // lancement du son | ||
+ | lancerVideo(i, nomVideo); | ||
+ | } else if (plante[i]==0 && video_active[i]) { //si la distance est supérieure au seuil ET que la video joue : arrêter la video | ||
+ | vid.stop(); | ||
+ | clear(); | ||
+ | video_active[i] = false; | ||
} | } | ||
- | | + | } |
- | bouvier | + | void lancerVideo(int i, String nomVideo) { |
+ | | ||
+ | // chargement de la video 1 | ||
+ | | ||
+ | vid.loop(); | ||
+ | video_active[i] = true; | ||
} | } | ||
- | if (ChoixPerso == 2){ | + | } |
- | bouvier = loadImage(" | + | //////////////////////////////////////////////// |
+ | void gestionAnimation() { | ||
+ | | ||
+ | animation_active = true; | ||
+ | } else { | ||
+ | animation_active = false; | ||
} | } | ||
- | | + | } |
+ | void lancerAnimation() { | ||
+ | float x = 30 + random(-20, 20); // random sur la position | ||
+ | float y = 30 + random(-20, 20); | ||
+ | | ||
+ | } | ||
+ | |||
+ | |||
+ | ////////////////////////////////////// | ||
+ | void movieEvent(Movie movie) { //// gestion de la vidéo | ||
+ | vid.read(); | ||
} | } | ||
- | //for (int i = 0; i < img.pixels.length; | + | </code> |
- | // img.pixels[i] | + | **3** => **Processing :** __test_7plantes_sonores > SerialEvent.pde__ |
- | //} | + | < |
- | void serialEvent(Serial myPort) { // gestion des données envoyées par la carte | + | void serialEvent(Serial myPort) { |
// read a byte from the serial port: | // read a byte from the serial port: | ||
int inByte = myPort.read(); | int inByte = myPort.read(); | ||
Ligne 253: | Ligne 280: | ||
serialCount++; | serialCount++; | ||
- | // If we have NbData | + | // If we have 3 bytes: |
- | if (serialCount > NbData-1) { | + | if (serialCount > nPlantes-1 ) { |
- | | + | |
- | | + | plante[i] |
- | | + | |
- | | + | // |
- | | + | |
- | | + | |
+ | | ||
+ | | ||
+ | | ||
+ | //plante[6] = serialInArray[6]; | ||
+ | //plante[7] = serialInArray[7]; | ||
// print the values (for debugging purposes only): | // print the values (for debugging purposes only): | ||
- | println(ChoixPerso + "\t" + CouleurPerso | + | |
- | + | ||
- | // Send a capital A to request new sensor readings: | + | // Send a capital A to request new sensor readings: |
myPort.write(' | myPort.write(' | ||
// Reset serialCount: | // Reset serialCount: | ||
Ligne 273: | Ligne 306: | ||
</ | </ | ||
- | ==== Programme de test de couleur sur des images en PNG ==== | ||
- | De manière connexe, des tests sur la manière de modifier la couleur d'un contour SVG/PNG ont été effectués. L' | ||
- | Le rendu est le suivant : | + | </ |
- | {{ :wiki: | + | **4** => **Arduino** |
+ | < | ||
+ | //Import a library from the Arduino folder | ||
+ | #include < | ||
+ | /////////////////////////////// | ||
+ | byte Ncapteurs = 8; | ||
- | Le programme Processing est le suivant : {{ : | + | //Select the two pins that will act as a capacitor |
- | < | + | CapacitiveSensor |
- | /** | + | CapacitiveSensor(2, |
- | * Create Image. | + | CapacitiveSensor(2, |
- | * | + | CapacitiveSensor(2, |
- | * The createImage() function provides | + | CapacitiveSensor(2, |
- | * This example creates an image gradient. | + | CapacitiveSensor(2, 8),// 10M resistor between pins 2 & 11, pin 8 is sensor pin, add a wire and or foil |
- | */ | + | CapacitiveSensor(2, |
+ | CapacitiveSensor(2, | ||
+ | }; | ||
+ | long* capSensorVal ; // mémorise la valeur lue sur chaque capteurs | ||
- | PImage img, imgIntiale; | + | //Insert the minimum value provided by the sensor to detect the touch |
- | color c =color(# | + | int seuilDetection = 500; // seuil de détection sur la valeur donné par le capteur capacitif |
- | int r = 25, g = 42, b=118; | + | const int ledPin |
- | // Arbre : 2480*2480 | + | |
+ | int* plante ; | ||
+ | |||
+ | // port série | ||
+ | int inByte | ||
+ | |||
+ | ///////////////////// | ||
+ | boolean debug1 | ||
+ | //////////////////////////////////////////// | ||
void setup() { | void setup() { | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
+ | | ||
- | | + | |
+ | capSensorVal = malloc(Ncapteurs * sizeof(long)); | ||
+ | plante = malloc(Ncapteurs * sizeof(int)); | ||
+ | // initialisation des tableaux | ||
+ | for (int i = 0; i < Ncapteurs; i++) { | ||
+ | capSensorVal[i] = 0; | ||
+ | plante[i] = 0; | ||
+ | } | ||
+ | |||
+ | pinMode(ledPin, | ||
+ | // init des capteurs capacitifs | ||
+ | cs_2[0].set_CS_AutocaL_Millis(0xFFFFFFFF); // turn off autocalibrate on channel 1 - just as an example | ||
- | | + | |
- | //img.pixels[i] = color(0, 153, 204, a); | + | |
} | } | ||
- | void draw() { | + | void loop() { |
- | | + | |
- | | + | |
+ | // get incoming byte: | ||
+ | inByte = Serial.read(); | ||
- | | + | long start = millis(); |
- | int r_i = (imgIntiale.pixels[i] >> 16) & 0xFF; // Faster way of getting red(argb) | + | |
- | int g_i = (imgIntiale.pixels[i] >> 8) & 0xFF; // Faster way of getting green(argb) | + | |
- | int b_i= imgIntiale.pixels[i] & 0xFF; // Faster way of getting blue(argb) | + | |
- | | + | |
- | float h = map(mouseX, 0, width, 0, 255); | + | |
- | //float h = 128; | + | |
- | float s = saturation(imgIntiale.pixels[i]); | + | |
- | float b = brightness(imgIntiale.pixels[i]); | + | |
- | | + | if (debug1) { |
+ | Serial.print(millis() - start); | ||
+ | Serial.print("\t" | ||
- | | + | |
+ | Serial.print(capSensorVal[i]); // print sensor output 1 | ||
+ | Serial.print(" | ||
+ | } | ||
+ | Serial.println("" | ||
} | } | ||
- | img.updatePixels(); | ||
- | } | ||
- | image(img, 260, 260, 250, 250); | + | |
+ | // test des valeurs des capteurs | ||
+ | for (int i = 0; i < Ncapteurs; i++) { | ||
+ | plante[i] = testCapteur(capSensorVal[i], seuilDetection); | ||
+ | } | ||
+ | if (debug2) { | ||
+ | for (int i = 0; i < Ncapteurs; i++) { | ||
+ | Serial.print(plante[i]); | ||
+ | Serial.print(" | ||
+ | } | ||
+ | Serial.println("" | ||
+ | } | ||
+ | else { | ||
+ | // send sensor values: on envoie à Processing l' | ||
+ | for (int i = 0; i < Ncapteurs; i++) { | ||
+ | Serial.write(plante[i]); | ||
+ | } | ||
+ | } | ||
+ | } | ||
} | } | ||
- | </ | ||
+ | void establishContact() { | ||
+ | while (Serial.available() <= 0) { | ||
+ | Serial.print(' | ||
+ | delay(300); | ||
+ | } | ||
+ | } | ||
- | ====== Réalisation de la maquette ====== | + | int testCapteur(long sensorVal, long seuilDetection) { |
- | vidéos, photos | + | // sensorVal : valeur |
+ | // seuilDetection : seuil de détection | ||
+ | if (sensorVal > seuilDetection ) { | ||
+ | //Turn on the led | ||
+ | digitalWrite(ledPin, | ||
+ | // plante i activée | ||
+ | return 255; | ||
+ | } | ||
+ | //Touch undetected | ||
+ | else { | ||
+ | //Turn off the led | ||
+ | digitalWrite(ledPin, | ||
+ | // plante i inactivée | ||
+ | return 0; | ||
+ | } | ||
+ | |||
+ | } | ||
+ | </ |