C'est le printemps ! Fleur.gif

Passerelle.Infini 2025 : MOUMOUNAN

De Les Fabriques du Ponant
Aller à : navigation, rechercher

LOGO MOUMOUNA copie.jpg

résumé du projet

MOUMOUNA - dérivé du mot câliner "moumounan" en breton - est un objet interactif distributeur de câlins à distance. A l'échelle de notre prototype celui-ci peut être déployé dans l'espace familial ou à taille humaine disposé dans l'espace public.

Le principe : Enlacer cet objet textile afin de faire baisser son anxiété ou trouver du réconfort. La pression contre son corps active Moumouna qui émet une douce vibration et s'illumine. Cet étreinte envoie un signal au deuxième "moumouna" disposé dans un autre espace ou une autre ville, qui s'illumine en attendant un câlin en réponse. Les vibrations annoncent que deux personnes s'enlacent par Moumouna interposé.

Un QR code est imprimé sur les deux objets qui vous renvoie vers un bande sonore (bruits de vagues) à télécharger pour renforcer l'expérience du câlin.

Action technique.jpg Moumouna Distributeur de câlins.png MOUMOUNA ACTIVE.jpgNotice moumouna.jpg

Le bouton pression sur le moumouna A envoie un signal lumineux au moumouna B, qui si il est enlacé (pression déclencheur) renvoie un signal qui déclenche une vibration! Les vibrations simultanées indiquent un câlin en résonance!

membres du projet

Equipe au travail.jpg Equipe.jpg


Aude Mouillot - Catherine Huve - Mélissa Rosingana

Bibliographie et webographie sur le projet

Mettre ici des exemples trouvés sur web de projets qui ressemblent et des technologies qui s'en rapprochent ou qui servent d'inspiration.

  1. calinothérapie

https://www.24heures.ch/les-bienfaits-de-la-calinotherapie-expliques-par-une-experte-803631900339

pistes explorée, abandonnées ou fertiles

CROQUIS / PREMIERES IDEES Croquis 1 moumounan.jpg Idée 1 moumounan.jpg Moumounan projet calin.jpg Proto-moumounan-esquisse.jpg


Inspiration Oeuvre de Catherine Huve " LE GRAND HUG " textiles, mixtes - Dimensions: 40x70cm, 2024

 LE GRAND HUG Catherine Huve.jpg

prototype qu'on souhaite réaliser

PROTOTYPE EN MOUSSE DES DEUX MOUMOUNA

  Prototype moumounan mousse.jpgPrototype en mousse moumounan.jpg

PROTOTYPE TISSUS

 Coussin tissus proto moumounan.jpg

COUTURE DU PROTOTYPE FINAL

 Catherine couture coussin 2.jpg  Catherine couture main coussin.jpg Aude couture housse.jpg Aude couture housse 2.jpg 

REMPLISSAGE AVEC COPEAUX DE BOIS ET COTON

 Cath remplissage moumouna.jpg Copeaux bois.jpg Remplissage moumouna.jpg

COLORATION DU TISSUS Premier proto tissus moumounan.jpg Peinture bombe.jpg Couleur bombe.jpg

BOITE NUMERIQUE

 Boite numerique.jpg Boite numerique 2.jpg  Bande LED Programmation boite moumouna.jpg Vibreur Vibreur moumouna.jpg  
 Programmation.jpg En action.jpg

ASSEMBLAGE DE NOS PROTOTYPES

Decoupe prototype.jpg  Proto details.jpg

PROTOTYPE FINAL

MOUMOUNA-rose.jpg  MOUMOUNA ACTIVE.jpg  Moumouna2.jpg  Calin moumouna.jpg Calindemoumouna.jpg
  Logo moumouna serigraphie.jpg

code

  1  
  2 /////////////////////////////
  3 //      Moumouna      //
  4 /////////////////////////////
  5 /*
  6  * Un projet imaginé et réalisé au Hackathon Passerelle.Infini organisé avec les petits débrouillards au centre d'art Passerelle à Brest les 20 et 21 mars 2025.
  7  * moumouna : https://wiki.lesfabriquesduponant.net/index.php?title=Passerelle.Infini_2025_:_MOUMOUNAN
  8  * 
  9  * Ce programme s'apuie sur le programme POCL Poke (imaginé et réalisé au Hackathon POCL à l'édulab Rennes 2 les 9 et 10 décembre 2021).
 10  * POCL Poke : https://wiki.lesfabriquesduponant.net/index.php?title=POCL_:_Poke
 11  * 
 12  * Configurez le logiciel Arduino pour gérer la carte D1 mini (ESP8266).
 13  * Intégrer les biobliothèues requises par le projet :
 14  ** #include <MQTT.h> -> pour gérer le protocole de communication, c'est la bibliothèque MQTT de Joël Gähwiler : https://github.com/256dpi/arduino-mqtt
 15  ** #include <Adafruit_NeoPixel.h> -> pour gérer les rubans de led
 16  ** #include <WiFiManager.h> -> Bibliothèque WiFiManager pour configurer automatiquement le réseau wifi et le mot de passe.
 17  * 
 18  *                                   BROCHAGE                            
 19                                 _________________                        
 20                                /     D1 mini     \                       
 21                            -  |[ ]RST        TX[ ]| -                    
 22                            -  |[ ]A0  -GPIO  RX[ ]| -                    
 23                               |[ ]D0-16    5-D1[ ]| -                    
 24                               |[ ]D5-14    4-D2[ ]| -                    
 25                     Bouton -  |[X]D6-12    0-D3[X]| - ruban de leds             
 26                            -  |[ ]D7-13    2-D4[ ]| LED_BUILTIN          
 27                            -  |[ ]D8-15     GND[X]| - GND (Boutons, ruban de leds)             
 28                            -  |[ ]3V3 .      5V[X]| - ruban de Led        
 29                               |       +---+       |                     
 30                               |_______|USB|_______|                      
 31 
 32 Matériel :
 33 - des fils dupont.
 34 - un ruban de led RGB WS28B12
 35 - D1 mini (Wemos, LOLIN,...)
 36 - bouton poussoir
 37 - une alimentation 5V
 38 */
 39 /*
 40  * Un travail d'équipe de :
 41  * Alma Oskouei
 42  * Gaëlle Bescond
 43  * Tony Vanpoucke
 44  * Wing-Anh Luy
 45  * Antony Le Goïc-Auffret
 46    ___
 47  / ___ \
 48 |_|   | |
 49      /_/ 
 50      _   ___   _ 
 51     |_| |___|_| |_
 52          ___|_   _|
 53         |___| |_|
 54 Les petits Débrouillards - mars 2025 CC-By-Sa http://creativecommons.org/licenses/by-nc-sa/3.0/
 55 // Programme nourri de https://randomnerdtutorials.com/esp32-esp8266-rgb-led-strip-web-server/
 56 // Programme inspiré de celui par Joël Gähwiler
 57 // https://github.com/256dpi/arduino-mqtt
 58 
 59 Améliorations :
 60 reboot en cas de déconnexion MQTT
 61 
 62 */
 63 #include <ESP8266WiFi.h>
 64 #include <MQTT.h> // Bibliothèque MQTT par Joël Gaehwiler
 65 #include <Adafruit_NeoPixel.h> // Bibliothèque NeoPixel d'Adafruit
 66 #include <WiFiManager.h> // Bibliothèque WiFiManager pour configurer automatiquement le réseau wifi et le mot de passe.
 67 #include <ESP_EEPROM.h>
 68 
 69 WiFiClient net; //on crée l'objet WiFiClient "Net"
 70 WiFiServer serveurPOCL(80);
 71 MQTTClient clientMQTT;
 72 #define BROKER_IP "debrouillards.ddns.net" //IP du serveur sur lequel est installé le Broker MQTT
 73 
 74 unsigned long lastMillis = 0;
 75 
 76 char nomPOCL[25];         // variable de stockage du nom unique du POCL
 77 
 78 
 79 //==============Vibreur======================
 80 const int vib = D2; // broche vibreur
 81 //=============Eléments pour le ruban de led et le bouton===============
 82 
 83 // Broche de connexion du ruban de LED
 84 #define PIN D3 // Il faudra changer en D2 (broche plus adpatée).
 85 
 86 int brocheBouton = 12; //GPIO de la broche D6
 87 int rouge = 0;
 88 int bleu = 255;
 89 int vert = 0;
 90 
 91 // Nombre de Led RDGB dans votre ruban
 92 #define NUMPIXELS 6 
 93 
 94 // on configurer un riban nommé "pixels"
 95 Adafruit_NeoPixel pixels(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);
 96 
 97 #define T 1 // temps pour gérer le fade du ruban
 98 //==============================================================
 99 
100 //===============Eléments pour le choix de la couleur du Ruban===============
101 // Pour décoder les valeurs de HTTP GET
102 String redString = "0";
103 String greenString = "0";
104 String blueString = "0";
105 int pos1 = 0;
106 int pos2 = 0;
107 int pos3 = 0;
108 int pos4 = 0;
109 
110 // Variable to store the HTTP req  uest
111 String header;
112 
113 // Setting PWM bit resolution
114 // const int resolution = 256;
115 
116 // Current time
117 unsigned long currentTime = millis();
118 // Previous time
119 unsigned long previousTime = 0; 
120 // Define timeout time in milliseconds (example: 2000ms = 2s)
121 const long timeoutTime = 2000;
122 
123 //==============================================================================
124 void connect() {
125   Serial.print("Vérification de la connexion Wifi...");
126   while (WiFi.status() != WL_CONNECTED) {
127     Serial.print(".");
128     delay(1000);
129   }
130   Serial.println("\nPOCL Connecté au Wifi :-) ");
131   Serial.print("\nconnexion au serveur MQTT en cours ");
132   //connection au serveur MQTT : identifiant, User, mot de passe
133   while (!clientMQTT.connect(nomPOCL, "poclpokou", "pokou")) {
134     Serial.println(".");
135     delay(300);
136   }
137 
138   Serial.println("\nconnecté à MQTT !");
139 
140 // on s'abonne au sujet (topic) "/mou" 
141   clientMQTT.subscribe("/mou"); // Attention à la casse !! La casse c'est maj ou minuscule
142   Serial.println("Abonné à /mou");
143   // client.unsubscribe("/mou");// Pour se désinscrire
144 }
145 
146 void messageReceived(String &topic, String &payload) {
147   digitalWrite(LED_BUILTIN, HIGH);
148   fade();
149   Serial.println("incoming: " + topic + " - " + payload);
150   if (payload == "calin"){
151     Serial.println("clic !");
152     digitalWrite(LED_BUILTIN, LOW);
153     delay(100);
154     digitalWrite(LED_BUILTIN, HIGH);
155   }
156 }
157 
158 void fade() {
159   EEPROM.get(0, rouge); Serial.print("Valeur de rouge EEPROM = "); Serial.println(rouge);
160   EEPROM.get(4, vert); Serial.print("Valeur de vert EEPROM = "); Serial.println(vert);
161   EEPROM.get(8, bleu); Serial.print("Valeur de bleu EEPROM = "); Serial.println(bleu);
162   
163   for (int sig=0; sig<3; sig++){
164   for (int b=0; b<255; b++){
165   pixels.setBrightness(b);
166   
167   for(int i=0; i<NUMPIXELS; i++) {
168     pixels.setPixelColor(i, pixels.Color(rouge, vert, bleu));
169   }
170   pixels.show();   // On allume les rubans
171   delay(T);
172   }
173 
174   for (int b=255; b>1; b--){ //boucle de gestion de la brillance
175   pixels.setBrightness(b);
176   
177   // n'oubliez pas que le premier pixel porte le Numéro 0
178   for(int i=0; i<NUMPIXELS; i++) { // Pour chaque pixel...
179 
180     // pixels.Color() prends les valeurs RGB de 0,0,0 jusqu'à 255,255,255
181     pixels.setPixelColor(i, pixels.Color(rouge, vert, bleu));
182   }
183   pixels.show();   // on affiche les pixels
184   delay(T);
185   }
186   }
187 }
188 
189 void testEEPROM(){ // On test si la mémoire de l'ESP contient déjà des infos d'une configuration précédente
190    if(EEPROM.percentUsed()>=0) { // Si il y en a on ne fait rien
191     Serial.println("Il y a des infos dans la mémoire");
192     Serial.print(EEPROM.percentUsed());
193     Serial.println("% de l'espace mémoire flash de l'ESP flash actuellement utilisé.");
194     EEPROM.get(0, rouge); Serial.print("Valeur de rouge EEPROM = "); Serial.println(rouge);
195     EEPROM.get(4, vert); Serial.print("Valeur de vert EEPROM = "); Serial.println(vert);
196     EEPROM.get(8, bleu); Serial.print("Valeur de bleu EEPROM = "); Serial.println(bleu);
197   } else {       // Si il n'y en a pas on stocke la couleur pas défaut
198     EEPROM.put(0, rouge);
199     EEPROM.put(4, vert);
200     EEPROM.put(8, bleu);
201     boolean ok = EEPROM.commit();
202     Serial.println((ok) ? "Commit initialisation couleur OK" : "Commit initialisation couleur raté");  
203   }
204 }
205 void choixCouleur(){
206   WiFiClient client = serveurPOCL.available(); // On écoute si il y a des connexions sur le site web du POCL (des clients)
207 
208   if (client) {                                // Si il y a une nouvelle connexion,
209     currentTime = millis();
210     previousTime = currentTime;
211     Serial.println("Nouveau client connecté");          // print a message out in the serial port
212     String currentLine = "";                // créer une chaîne pour contenir les données entrantes du client
213     while (client.connected() && currentTime - previousTime <= timeoutTime) {            // Boucle "while", tant que le client est connecté
214       currentTime = millis();
215       if (client.available()) {             // if there's bytes to read from the client,
216         char c = client.read();             // read a byte, then
217         Serial.write(c);                    // print it out the serial monitor
218         header += c;
219         if (c == '\n') {                    // if the byte is a newline character
220           // if the current line is blank, you got two newline characters in a row.
221           // that's the end of the client HTTP request, so send a response:
222           if (currentLine.length() == 0) {
223             // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
224             // and a content-type so the client knows what's coming, then a blank line:
225             client.println("HTTP/1.1 200 OK");
226             client.println("Content-type:text/html");
227             client.println("Connection: close");
228             client.println();
229                    
230             // Affiche la page web
231             client.println("<!DOCTYPE html><html>");
232             client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">");
233             client.println("<link rel=\"icon\" href=\"data:,\">");
234             client.println("<link rel=\"stylesheet\" href=\"https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css\">");
235             client.println("<script src=\"https://cdnjs.cloudflare.com/ajax/libs/jscolor/2.0.4/jscolor.min.js\"></script>");
236             client.println("</head><body><div class=\"container\"><div class=\"row\"><h1>Choisi la couleur de ton POCL</h1></div>");
237             client.println("<a class=\"btn btn-primary btn-lg\" href=\"#\" id=\"change_color\" role=\"button\">Change de Couleur</a> ");
238             client.println("<input class=\"jscolor {onFineChange:'update(this)'}\" id=\"rgb\"></div>");
239             client.println("<script>function update(picker) {document.getElementById('rgb').innerHTML = Math.round(picker.rgb[0]) + ', ' +  Math.round(picker.rgb[1]) + ', ' + Math.round(picker.rgb[2]);");
240             client.println("document.getElementById(\"change_color\").href=\"?r\" + Math.round(picker.rgb[0]) + \"g\" +  Math.round(picker.rgb[1]) + \"b\" + Math.round(picker.rgb[2]) + \"&\";}</script></body></html>");
241             // The HTTP response ends with another blank line
242             client.println();
243 
244             // Request sample: /?r201g32b255&
245             // Red = 201 | Green = 32 | Blue = 255
246             if(header.indexOf("GET /?r") >= 0) {
247               pos1 = header.indexOf('r'); // pos1 est la position du caractère r dans la chaine de caractères.
248               pos2 = header.indexOf('g'); // idem
249               pos3 = header.indexOf('b');
250               pos4 = header.indexOf('&');
251               redString = header.substring(pos1+1, pos2); // la chaine de caractère juste après pos1 et jusqu'à pos2 est placée dans la variable redString.
252               greenString = header.substring(pos2+1, pos3); // ...
253               blueString = header.substring(pos3+1, pos4);
254               Serial.println(redString.toInt()); // je publie sur le moniteur série
255               Serial.println(greenString.toInt());
256               Serial.println(blueString.toInt());
257               rouge = redString.toInt(); // je transforme la chaine de caractère en nombre entier que je met dans la variable rouge
258               vert = greenString.toInt();
259               bleu = blueString.toInt();
260               // Je stocke la configuration dans la mémoire du D1 mini
261               EEPROM.put(0, rouge);
262               EEPROM.put(4, vert);
263               EEPROM.put(8, bleu);
264               boolean ok1 = EEPROM.commit();
265               Serial.println((ok1) ? "Commit couleur OK" : "Commit couleur raté");
266             }
267             // On sort ("break") de la boucle "while"
268             break;
269           } else { // if you got a newline, then clear currentLine
270             currentLine = "";
271           }
272         } else if (c != '\r') {  // if you got anything else but a carriage return character,
273           currentLine += c;      // add it to the end of the currentLine
274         }
275       }
276     }
277     // Clear the header variable
278     header = "";
279      fade();
280     // Close the connection
281     client.stop();
282     Serial.println("Client disconnected.");
283     Serial.println("");
284   }
285 }
286 
287 void setup() {
288   Serial.begin(115200); // Ouverture de communication série
289 
290   uint32_t chipid=ESP.getChipId();
291   snprintf(nomPOCL,25,"MouMouNa - %08X",chipid);
292   Serial.print("Je suis le MouMouNa "); 
293   Serial.println(nomPOCL);
294   
295   EEPROM.begin(16);
296   testEEPROM(); 
297   
298   WiFi.mode(WIFI_STA); // la carte D1 mini est mise en mode STATION
299   WiFiManager MonReseauWifi; // on crée l'objet "MonReseauWifi"
300    
301   bool res;
302   res = MonReseauWifi.autoConnect("MouMouNa"); // le POCL diffuse un réseau wifi en accès libre nommé "MouMouNa"
303      
304   if(!res) {
305     Serial.println("La connexion n'a pas fonctionnée...");
306     } 
307   else {
308     Serial.println("Vous êtes connecté au Wifi... :-)");
309   
310     // Print local IP address and start web server
311     Serial.println("");
312     Serial.println("WiFi connected.");
313     Serial.println("IP address : ");
314     Serial.println(WiFi.localIP());
315     serveurPOCL.begin(); //démarrage du serveur Web du POCL
316     }
317   
318   pixels.begin(); //on initialise le ruban "pixels"
319   pinMode(brocheBouton,INPUT_PULLUP);
320   pinMode(PIN,OUTPUT);
321   
322   pinMode(LED_BUILTIN, OUTPUT);
323   digitalWrite(LED_BUILTIN, HIGH);
324   
325   // préparation de la connexion au serveur MQTT
326   clientMQTT.begin(BROKER_IP, 1883, net); // (IP, port, Client Wifi défini plus haut)
327   clientMQTT.onMessage(messageReceived); // Si on reçoit un message MQTT, la fonction "messageReceived" est appelée.
328 
329   connect(); // On se connecte
330   Serial.println("Programme MouMouNa V1 en date du 24 mars 2025");
331 }
332 
333 void loop() {
334   pixels.clear(); // éteint tout les pixels
335   pixels.show(); // affiches pixels
336   
337   clientMQTT.loop();
338   delay(10);  // <- fixes some issues with WiFi stability
339 
340   if (!clientMQTT.connected()) {
341     Serial.print("MouMouNa ");
342     Serial.print(nomPOCL);
343     Serial.println(" est déconnecté du serveur MQTT");   
344     connect();
345   }
346 
347   // Si on appuie sur le bouton, on envoie un messagge MQTT "calin", sur le topic "/mou"
348   if ( digitalRead(brocheBouton) == LOW ){
349   Serial.println("Appuis Bouton"); 
350   clientMQTT.publish("/mou", "calin");
351   delay(250); // Filtre anti-rebond du bouton
352   }
353 
354   choixCouleur(); // appel de la fonction qui génère la page web de configuration de la couler du POCL
355 }

ne pas toucher en dessous de ce paragraphe