====== Images Saisonnières ====== * Porteur du projet : Floriane Robert de Latour * Date : 26/01/2015 * Contexte : Macro projet DSAA 1 * [[wiki:projets:seeds:seeds|Macro Projet 2]] * espace d'échange : partout ====== Description ====== Images Saisonnières est un projet dont le point de départ est un sketch très simple récupéré sur open processing (lien). Une première étape a consisté en la duplication et la modification de ce sketch, en modifiant très peu de lignes de codes. Une deuxième étape a porté le projet plus loin en réunissant ces sketchs, dont le thème commun est la météorologie, et en les faisant réagir à des capteurs. La troisième étape doit permettre l'articulation entre l'image générée, leur code source, et leur généalogie (à savoir la provenance des différents éléments du code); à savoir les trois éléments dont sont composés une image numérique. Ce projet est donc à la fois un observatoire de phénomènes naturels et de la création d'images. Être graphiste à l'ère du numérique nécessite de pouvoir agir sur le code source des formes s'il on veut avoir une maîtrise de son travail. Cela nécessite aussi de savoir se servir des ressources que l'on peut avoir à sa disposition. Le code est une activité nécessairement participative, qui convoque quelque chose qui appartient à tout le monde, comme la pluie ou la neige. Ce travail permet de repérer les moments dans la création où la propriété intellectuelle est remise en cause. Si toutes les ressources dont je me suis servie pour ce projet avaient été propriétaires, tant au niveau du code emprunté que des programmes utilisés, il n'aurait jamais vu le jour.4 ====== Généalogie ====== lien à venir ====== Matériel ====== * un ordinateur * une carte Arduino avec une breadbord * 2 potentiomètres (idéalement remplacés par un capteur de température et un capteur de flexion) * 2 résistances 10kOhm * un rétro-projecteur * logiciels : arduino et processing ====== Images ====== (à venir) //(ACC) : vous n'avez pas prévu de lieu d'échanges avec le lecteur (est-ce un vieux réflexe propriétaire?) du coup je me mets où je peux : John Maeda, évoqué par Annick Lantenois, a créé un dispositif simple de corrélation entre un visuel et le code source permettant de l'obtenir. Vous pouvez peut-être réfléchir à de tels dispositifs. Qu'arrive-t-il si le code est fourni avec le produit?// [[http://www.maedastudio.com/2005/xmas/index.php?category=all&next=2005/cartier&prev=1993/illustrandom&this=xmas|Lien externe]] ====== Montage ====== {{:wiki:projets:saisons:images_saisonnieres_bb.jpg?nolink|}} ====== Code ====== **Arduino** int firstSensor = 0; // first analog sensor int secondSensor = 0; // second analog sensor int thirdSensor = 0; // digital sensor int inByte = 0; // incoming serial byte void setup() { // start serial port at 9600 bps: Serial.begin(9600); while (!Serial) { ; // wait for serial port to connect. Needed for Leonardo only } pinMode(2, INPUT); // digital sensor is on digital pin 2 establishContact(); // send a byte to establish contact until receiver responds } void loop() { // if we get a valid byte, read analog ins: if (Serial.available() > 0) { // get incoming byte: inByte = Serial.read(); // read first analog input, divide by 4 to make the range 0-255: firstSensor = analogRead(A0)/4; // delay 10ms to let the ADC recover: delay(10); // read second analog input, divide by 4 to make the range 0-255: secondSensor = analogRead(A1)/4; // read switch, map it to 0 or 255L thirdSensor = map(digitalRead(2), 0, 1, 0, 255); // send sensor values: Serial.write(firstSensor); Serial.write(secondSensor); Serial.write(thirdSensor); } } void establishContact() { while (Serial.available() <= 0) { Serial.print('A'); // send a capital A delay(300); } } **Processing** import processing.serial.*; // importer la librairie sérial float fgcolor; Serial myPort; // Le port de série float[] serialInArray = new float[3]; // Tableau pour stocker les données reçues int serialCount = 0; // Initialisation du compteur de bytes boolean firstContact = false; // Si oui ou non il y a contact avec le microcontrolleur //les coordonnées à changer float etoiles; //variable concernant les particules, en rapport avec le premier capteur float angleChng; //variable concernant leur direction, en rapport avec le deuxième capteur //variables d'effacements int contrainte01 = 0; //variable de limite d'effacement pour les étoiles filantes int contrainte02 = 700; // variable de limite d'effacement pour la neige int contrainte03a = 400; //variables de limite d'effacement pour la pluie int contrainte03b = 400; //tableaux : étoiles filantes float[] xCoord = new float[250]; //coordonnées X float[] yCoord = new float[250]; //coordonnées Y float[] speed = new float[250]; //vitesse de chute float[] angle = new float[250]; //angle de chute //tableaux : neige float[] xCoord02 = new float[700]; //coordonnées X float[] yCoord02 = new float[700]; //coordonnées Y float[] speed02 = new float[700]; //vitesse de chute //tableaux : pluie int[] xCoord03 = new int[400]; //coordonnées X int[] yCoord03 = new int[400]; //coordonnées Y float[] speed03 = new float[400]; //vitesse de chute float[] angle03 = new float[400]; //angle de chute //INITIALISATION void setup() { frameRate(40); //nombre d'images par seconde size(300,650); //taille de la fenêtre ((javax.swing.JFrame) frame).getContentPane().setBackground(new java.awt.Color(0,0,0)); //pour changer la couleur d'arrière plan autour du sketch en mode "present" colorMode(HSB); //mode de couleur : teinte, saturation, luminosité background(255,0,10); //couleur de l'arrière plan //initialisation des étoiles filantes avec une boucle int for (int i = 0; i < xCoord.length; i++) { xCoord[i] = i*width/(250); //il y a 250 étoiles filantes réparties sur la largeur de la fenêtre yCoord[i] = (int)random(-height, 0); //les etoiles sont créées aléatoirement entre 0 et l'inverse de la hauteur //pour apparaître au fur et à mesure quand le sketch est lancé (à confirmer ?) speed[i] = random(1,5)/2; //la vitesse est différente pour chaque étoile angle[i] = noise(2)*2.5; //l'angle est différent pour chaque étoile } //initialisation de la neige avec une boucle int for (int j = 0; j < xCoord02.length; j++) { xCoord02[j] = j*width/400; //il y a 400 flocons de neige répartis sur la largeur de la fenêtre yCoord02[j] = (int)random(-height, 0);// même chose que précédemment speed02[j] = random(1,4); //la vitesse est différente pour chaque flocon } //initialisation de la pluie avec une boucle int for (int k = 0; k < xCoord03.length; k++) { xCoord03[k] = k*width/400;//il y a 400 gouttes de pluie réparties sur la largeur de la fenêtre yCoord03[k] = (int)random(-height, 0);//même chose que ci-dessus speed03[k] = random(10,14); //la vitesse est différente pour chaque goutte de pluie angle03[k] = random(2,3); //l'angle est différent pour chaque goutte de pluie } // Imprimer une liste des ports de série, pour debugger printArray(Serial.list()); // Ouverture du port de série (ici COM1) String portName = Serial.list()[0]; myPort = new Serial(this, portName, 9600); } //MISE A JOUR DU SKETCH void draw() { //ajustement des variables de contrainte d'effacement grâce à de savants calculs. //ces variables déterminent à quel moment les particules d'un tableau s'effacent ou apparaissent //de manière à ce que ça soit progressif //elles exprimées en fonction de la variable "etoiles", qui est en rapport avec le 1er capteur //les valeurs sont contraintes entre 0 et le maximum qu'elles doivent avoir. int contrainte01 = constrain(int(xCoord.length - etoiles*2.5), 0, 250); //les étoiles filantes int contrainte02 = constrain(int(xCoord02.length - etoiles*5.70 + 730),0,700); //la neige int contrainte03a = constrain(int(xCoord03.length - etoiles*5.71 + 18), 0, 400); //la pluie int contrainte03b = constrain(int(xCoord03.length - etoiles*4 + 400), 0, 400); //opRect : variable concernant l'opacité du rectangle noir derrière les particules //exprimé lui aussi en fonction de "etoiles" //l'opacité change quand on passe de la neige à la pluie et vice versa float valOp = constrain(etoiles, 130, 150); //seuls les variations entre etoile=130 et etoiles=150 nous intéressent float opRect = 10 + (valOp-130)*12.25; //si etoiles=130, alors l'opacité est de 10. si etoiles = 150, alors l'opacité est de 255. //pour débugguer //println(contrainte01 + "\t" + contrainte02 + "\t" + contrainte03a + "\t" + contrainte03b); //println(etoiles); //rectangle d'arrière plan des particules, permet d'avoir un effet de traînée pushMatrix(); noStroke(); //pas de contours fill(255,0,10, opRect); //couleur du rectangle, avec opacité variable rect(0,0, width, height); //le rectangle fait la taille de la fenêtre popMatrix(); //création des etoiles filantes grâce à une boucle int for (int i = 0; i < contrainte01 ; i++) { //la boucle est limitée par la variable contrainte01. //en changeant celle ci permet d'effacer ou de révéler les etoiles filantes pushMatrix(); stroke(40, 255, 255); //couleur des contours strokeWeight(1); //épaisseur des contours point(xCoord[i], yCoord[i]); //création des étoiles popMatrix(); xCoord[i] += angle[i]*angleChng; //déplacement en X, grâce à l'angle (variable déterminée par le capteur*variable aléatoire) yCoord[i] += speed[i]; //déplacement en y, grâce à la vitesse //quand l'étoile filante atteint le bas de la fenêtre, elle réapparaît en haut if(yCoord[i] > height){ yCoord[i] = 0; } //quand l'étoile filante atteint le bord droit de la fenêtre, elle réapparaît à gauche if(xCoord[i]>width){ xCoord[i]=0; } } //création de la neige grâce à une boucle int for (int j = contrainte02; j < xCoord02.length; j++) {//la boucle est limitée par la variable contrainte02 //en changeant celle ci permet d'effacer ou de révéler des flocons de neige stroke(255, 0, 255);//couleur des contours strokeWeight(5); //épaisseur des contours point(xCoord02[j], yCoord02[j]); //création de la neige xCoord02[j] += random(-5, 5) + pow(angleChng, 2);//déplacement en X, grâce à l'angle // ajout d'une variable aléatoire (pour l'effet de vibration) et d'une variable déterminée par le 2ème capteur (pow = exposant) yCoord02[j] += speed02[j];//déplacement en y, grâce à la vitesse //quand le flocon de neige atteint le bas de la fenêtre, il réapparaît en haut if(yCoord02[j] > height){ yCoord02[j] = 0; } //quand le flocon de neige atteint le bord droit de la fenêtre, il réapparaît à gauche if(xCoord02[j]>width){ xCoord02[j]=0; } } //création de la pluie grâce à une boucle int for (int k = contrainte03a; k < contrainte03b; k++) {//la boucle est limitée par les variables contrainte03a et contrainte03b //en changeant celles ci permettent d'effacer ou de révéler des gouttes de pluie stroke(130, random(155,255), random(155,255)); //couleur des contours strokeWeight(2); //épaisseur des contours point(xCoord03[k], yCoord03[k]); //création de la pluie yCoord03[k] += speed03[k];//déplacement en y, grâce à la vitesse xCoord03[k] += 0.5*angle03[k] + pow(angleChng, 3); //déplacement en X, grâce à l'angle //quand la goutte de pluie atteint le bas de la fenêtre, elle réapparaît en haut if(yCoord03[k] > height){ yCoord03[k] = 0; } //quand la goutte de pluie atteint le bord droit de la fenêtre, elle réapparaît à gauche if(xCoord03[k]>width){ xCoord03[k]=0; } } } //} void serialEvent(Serial myPort) { // lire un byte du port de série: int inByte = myPort.read(); // si c'est le premier byte reçu, et que c'est un A, // effacer le serial buffer et noter // que l'on a eu un premier contact avec le microcontrolleur. // Sinon, ajouter le byte entrant byte dans le tableau: if (firstContact == false) { if (inByte == 'A') { myPort.clear(); // effacer le serial buffer firstContact = true; // premier contact avec le microcontrolleur myPort.write('A'); // demander plus } } else { // Ajouter le dernier byte du port de série au tableau: serialInArray[serialCount] = inByte; serialCount++; // Si on a 3 bytess: if (serialCount > 2 ) { etoiles = serialInArray[0]; //valeur provenant du premier capteur angleChng = serialInArray[1]/125; //valeur provenant du second capteur fgcolor = serialInArray[2]; //valeur provenant du 3ème capteur // print the values (for debugging purposes only): //println(etoiles + "\t" + fgcolor); // Envoyer "A" pour demander plus de valeurs des capteurs: myPort.write('A'); // Remettre à 0 serialCount: serialCount = 0; } } } ====== Problèmes ====== * capteur de température : je n'ai jamais réussi à le faire fonctionner, je le branchait à l'envers au début et du coup il m'a brûlé la main. il est peut être grillé. quoiqu'il en soit, après l'avoir remis dans le bon sens, je me suis aperçue que le capteur de température et le potentiomètre se perturbaient l'un l'autre, à savoir que quand j'actionnais le potentiomètre, la valeur du capteur de température bougeait aussi. * capteur de flexion : je l'attends toujours. * en fait le choix de ces deux capteurs est à reconsidérer. en ce qui concerne le capteur de température, il place le spectateur dans une position passive par rapport aux images générées par le programme, puisqu'il ne peux pas décider de la température qu'il fait.