Boîtier Interactif : Apprendre la profondeur dans un tableau

Porteur(s) du projet : Lise Irmann (DNMADE DG2), Damien MUTI DESGROUAS (Prof. de Numérique)

Date : 03/2021

Contexte : projet “Mallette pédagogique” au Musée des Beaux Arts - 2021

Fichiers :

Lien :

Capteurs/Actionneurs :

1 Capteur de distance Ultrasonic Grove (mettre le lien...)

2 Potentiomètres Grove

2 Sliders (potentiomètres) Grove

1 bouton poussoir Grove

1 module LED Grove

1 LED

Intentions : explication du projet et objectifs

Dans le cadre d'un projet avec le musée des Beaux Arts, l'objectif de ce projet est de créer un boîtier interactif permettant de faciliter la compréhension de la perspective dans un tableau.

Plans et schémas de fonctionnement

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 : boitier_interactif_arduino.zip

#include "Ultrasonic.h"
Ultrasonic ultrasonic(7); // capteur de distance
int Slider1 = 0; // Slider 1 : xPerso
byte Slider1Pin = A0;
byte Slider2Pin = A1; // Slider 2 : yPerso
int Potentiometre1 = 0; // Potentiomètre 1 : ChoixPerso
byte Potentiometre1Pin = A2;
int Potentiometre2 = 0; // Potentiomètre 2 : CouleurPerso
byte Potentiometre2Pin = A3;
int ChoixMesureDistance = 0; // Bouton poussoir - 0 : mesure de distance par slider 2 (yPerso). 1 : Mesure de distance par le capteur de distance
byte boutonPoussoirPin = 2; // broche de lecture du bouton poussoir
int Distance = 0; // distance lue sur le capteur de distance // Attention MeasureInCentimeters() renvoie un type "long"
int inByte = 0; // incoming serial byte
byte ledPin = 8; // broche de commande de la LED
byte etat_bouton = 0; //La variable « etat_bouton » mémorise l’état HIGH ou LOW de la pate d’entrée
byte old_etat_bouton = 0; //La variable « old_etat_bouton » mémorise l’ancien état de la variable « etat_bouton »
byte etat_led = 0; //La variable « etat_led » mémorise l’état 1 (allumée) ou 0 (éteinte) de la led.
boolean debug = false;
boolean debug_Com_Serial = false;
void setup() {
// start serial port at 9600 bps:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
pinMode(boutonPoussoirPin, INPUT); // digital sensor is on digital pin D2
pinMode(ledPin, OUTPUT); // LED sur D7
if (!debug) {
establishContact(); // send a byte to establish contact until receiver responds
}
}
void loop() {
gestionBouton();
// Si une donnée arrive dans le port série venant de processing = LIre les nouvelles valeurs des différents capteurs
if (!debug) { // mode normal
if (Serial.available() > 0) {
// lecture de la donnée sur le port série : lettre A
inByte = Serial.read();
if (inByte == 'A') { // vérification du caractère envoyé par Processing
// mesure sur les différents capteurs
gestionCapteurs();
// Envoi des valeurs lues sur les différents capteurs vers Processing
envoiMesureVersProcessing();
if (debug_Com_Serial) { ///// Debug
envoiMesureSurPortSerial();
}
}
}
}
else { // mode debug
// mesure sur les différents capteurs
gestionCapteurs();
// Envoi des valeurs lues sur les différents capteurs
envoiMesureSurPortSerial();
delay(500);
}
}
void establishContact() {
while (Serial.available() <= 0) {
Serial.print('A'); // send a capital A
delay(300);
}
}
void gestionBouton() {
// mesure de l'état du bouton
etat_bouton = digitalRead(boutonPoussoirPin); // lit et mémorise l’état en entrée de la pate 2
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; // sauvegarde la nouvelle valeur
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, HIGH); // allumer la LED
}
else { // si la led est éteinte
digitalWrite(ledPin, LOW); // éteindre la LED
}
}
void gestionCapteurs() {
// lecture des données sur les différents capteurs. On divise par 4 pour ramener la valeur entre 0 et 255
Potentiometre1 = map(analogRead(Potentiometre1Pin), 0, 1023, 0, 3.5); //ChoixPerso : 0, 1, 2 (3 personnages). Attention : on a mis 3.5 car sinon, le déclenchement du 2ième personage s'effectuer trop tardivement
// delay 10ms to let the ADC recover:
delay(10);
Potentiometre2 = analogRead(Potentiometre2Pin) / 4; //CouleurPerso
// delay 10ms to let the ADC recover:
delay(10);
Slider1 = analogRead(Slider1Pin) / 4; // xPerso
// delay 10ms to let the ADC recover:
delay(10);
// lecture de la distance avec le capteur ultrason ou le Slider 2
if (ChoixMesureDistance == 1) { // Capteur de distance ultrason
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 = analogRead(Slider2Pin) / 4; //yPerso lu sur Slider 2
}
}
void envoiMesureVersProcessing() {
Serial.write(Potentiometre1); //ChoixPerso
Serial.write(Potentiometre2); //CouleurPerso
Serial.write(Slider1); // xPerso
Serial.write(Distance);//distance - y Perso
}
void envoiMesureSurPortSerial() {
Serial.println("");
Serial.print("etat_led = ");
Serial.print(etat_led); //etat_led
Serial.print(" ChoixPerso = ");
Serial.print(Potentiometre1); //ChoixPerso
Serial.print(" CouleurPerso = ");
Serial.print(Potentiometre2); //CouleurPerso
Serial.print(" xPerso = ");
Serial.print(Slider1); // xPerso
Serial.print(" yPerso = ");
Serial.print(Distance);//distance - yPerso
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'affichage permettant de sélectionner un personnage, modifier sa position et sa taille dans une image.

Le programme est le suivant : boitier_interactifprocessing_2.zip

import processing.serial.*;
int bgcolor;	// Background color
int fgcolor=255;	// Fill color
Serial myPort; // The serial port
int NbData = 4; // nombre de données à récupérer de la carte Arduino
int[] serialInArray = new int[NbData]; // Where we'll put what we receive
int serialCount = 0; // A count of how many bytes we receive
int xPerso, yPerso, ChoixPerso, CouleurPerso, ChoixMesureDistance, Distance, sPerso;	// Starting position of the ball
boolean firstContact = false; // Whether we've heard from the microcontroller
PImage loubon;
PImage bouvier;
void setup() {
size(1000,570); // Stage size
noStroke(); // No border on the next thing drawn
colorMode(HSB);
// Initialisation des variables
ChoixPerso=0; // Potentiomètre 1
CouleurPerso = 0; //Potentiomètre 2
xPerso = width/2; // Slider 1
yPerso = height/2; // Slider 2 - Distance
sPerso = 250; //Taille du personnage
bouvier = loadImage("Images/Bouviercarre.png"); //Image du personnage
loubon= loadImage("Images/Loubon_-_Vue_de_Marseille.jpg"); // Image du fond
// 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
// is always my FTDI adaptor, so I open Serial.list()[0].
// On Windows machines, this generally opens COM1.
// Open whatever port is the one you're using.
String portName = Serial.list()[0];
myPort = new Serial(this, portName, 9600);
}
void draw() { /////////////////////////////////////// r@Lise : ajouter le graphisme...
background(loubon);
//fill(fgcolor);
// Draw the shape
//ellipse(xPerso, yPerso, 20, 20);
if (ChoixPerso == 0) {
bouvier = loadImage("Images/Bouviercarre.png");
}
if (ChoixPerso == 1){
bouvier = loadImage("Images/Arbrecarre.png");
}
if (ChoixPerso == 2){
bouvier = loadImage("Images/Vachecarre.png");
}
image(bouvier, xPerso, yPerso, sPerso, sPerso);
}
//for (int i = 0; i < img.pixels.length; i++) {
// img.pixels[i] = color(0, 90, 102, i % img.width * 2);
//}
void serialEvent(Serial myPort) { // gestion des données envoyées par la carte
// read a byte from the serial port:
int inByte = myPort.read();
// if this is the first byte received, and it's an A,
// clear the serial buffer and note that you've
// had first contact from the microcontroller.
// Otherwise, add the incoming byte to the array:
if (firstContact == false) {
if (inByte == 'A') {
myPort.clear(); // clear the serial port buffer
firstContact = true; // you've had first contact from the microcontroller
myPort.write('A'); // ask for more
}
} else {
// Add the latest byte from the serial port to array:
serialInArray[serialCount] = inByte;
serialCount++;
// If we have NbData bytes:
if (serialCount > NbData-1) {
ChoixPerso=serialInArray[0];
CouleurPerso = serialInArray[1]; //rouge
xPerso = serialInArray[2]*3-50;
yPerso = serialInArray[3]+100;
sPerso = serialInArray[3]*2+100;
// print the values (for debugging purposes only):
println(ChoixPerso + "\t" + CouleurPerso + "\t" + xPerso + "\t" + yPerso);
// Send a capital A to request new sensor readings: Envoie d'une letter "A" pour signifier à la carte Arduino de renvoyer des données
myPort.write('A');
// Reset serialCount:
serialCount = 0;
}
}
}

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'objectif est de pouvoir modifier la couleur d'un contour en jouant sur un potentiomètre, oui ici, avec la sourie. Le programme Processing est le suivant : test_png_3.zip

/**
* Create Image.
*
* The createImage() function provides a fresh buffer of pixels to play with.
* This example creates an image gradient.
*/
PImage img, imgIntiale;
color c =color(#192A76);
int r = 25, g = 42, b=118;
// Arbre : 2480*2480
void setup() {
size(1000, 570);
background(255);
imgIntiale = loadImage("Arbrecarre.png");
img = createImage(imgIntiale.width, imgIntiale.width, ARGB);
colorMode(HSB);
//float a = map(i, 0, img.pixels.length, 255, 0);
//img.pixels[i] = color(0, 153, 204, a);
}
void draw() {
background(255);
image(imgIntiale, 0, 0, 250, 250);
for (int i = 0; i < imgIntiale.pixels.length; i++) {
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)
if (r_i == r && g_i == g && b_i == b) {
float h = map(mouseX, 0, width, 0, 255);
//float h = 128;
float s = saturation(imgIntiale.pixels[i]);
float b = brightness(imgIntiale.pixels[i]);
//println("h =" + h + " s=" + s + " b=" +b);
img.pixels[i] = color(h, s, b);
}
img.updatePixels();
}
image(img, 260, 260, 250, 250);
}

Réalisation de la maquette

vidéos, photos du making of...