ENIB 2026 : Le vent du Globe : Différence entre versions
(Page créée avec « Titre de la fiche expérience : ==description (résumé)== éventuelle photo de l'équipe 200px ==Introduction== éventu... ») |
(Ajout code actuel) |
||
| (18 révisions intermédiaires par 2 utilisateurs non affichées) | |||
| Ligne 1 : | Ligne 1 : | ||
Titre de la fiche expérience : | Titre de la fiche expérience : | ||
==description (résumé)== | ==description (résumé)== | ||
| − | éventuelle photo de l'équipe | + | éventuelle photo de l'équipe <br> |
| + | Le projet est créé à l'occasion du Hackathon ENIB 2026 par des élèves de l' '''ENIB''' ('''E'''cole '''N'''ationale d' '''I'''ngénieur de '''B'''rest)[https://www.enib.fr/].Celui-ci consiste à créer un '''POCL'''([https://wiki.lesfabriquesduponant.net/index.php?title=Petits_Objets_Connect%C3%A9s_Ludiques| <b>P</b>etits <b>O</b>bjets <b>C</b>onnectés <b>L</b>udique]).L'objet est passé par plusieurs étapes de conceptions, modélisation, de programmation afin d'arriver à une version rendue. Le but de l'objet est de montrer la direction du vent et sa force ainsi que l'état de la marée. | ||
| − | |||
==Introduction== | ==Introduction== | ||
| + | [[Fichier:Vent-du-globe maquette.jpg|200px|thumb|right|Maquette du projet]] | ||
| + | Le vent du globe est un projet créé a l'occasion du [https://wiki.lesfabriquesduponant.net/index.php?title=Hackathon_ENIB_2026_:_Hack_the_POCL| Hackathon ENIB 2026]. | ||
| + | Son nom est inspiré du Vendée Globe[https://www.vendeeglobe.org/cest-quoi-le-vendee-globe] | ||
| + | L'objet a pour but via un bateau de montrer la direction du vent à un endroit donné ainsi que sa force. La direction du vent est montré à travers la pointe avant du bateau par rapport au marquage de la boîte. L'inclinaison du bateau montre si la marée est montante ou descendante. Des leds sur le côté permettent d'indiquer la force du vent. | ||
| + | Les informations nécessaires sont récupérées sur internet via différents APIs[https://fr.wikipedia.org/wiki/Interface_de_programmation]. | ||
| + | <br> | ||
| + | éventuelle vidéo | ||
| − | |||
==outil et matériel== | ==outil et matériel== | ||
| + | Une [https://www.wikidebrouillard.org/wiki/Utiliser_l%27ESP32_avec_le_logiciel_Arduino|Carte Arduino ESP32] est utilisée comme outil principal [https://wiki.lesfabriquesduponant.net/index.php?title=Hackathon_ENIB_2026_:_Hack_the_POCL#Contenu_de_votre_Kit| <em>(voir : Contenu_de_votre_Kit)</em>] | ||
==fichiers à joindre== | ==fichiers à joindre== | ||
| Ligne 14 : | Ligne 21 : | ||
===Mettre du code Arduino=== | ===Mettre du code Arduino=== | ||
<syntaxhighlight lang="Arduino" line> | <syntaxhighlight lang="Arduino" line> | ||
| − | # | + | /* HACKATON ENIB 2026 - LE VENT DU GLOBE |
| − | #include < | + | * |
| + | */ | ||
| + | |||
| + | |||
| + | // Librairies par défaut : | ||
| + | #include <WiFi.h> | ||
| + | #include <WiFiClientSecure.h> | ||
| + | #include <HTTPClient.h> | ||
| + | // Librairies additionnelles : | ||
| + | #include <ArduinoJson.h> | ||
| + | #include <Stepper.h> | ||
| + | |||
| + | |||
| + | // Constantes | ||
| + | const int PIN_BUTTON = 34; | ||
| + | |||
| + | const int PIN_LED_1 = 32; | ||
| + | const int PIN_LED_2 = 33; | ||
| + | const int PIN_LED_3 = 14; | ||
| + | const int PIN_LED_4 = 26; | ||
| + | const int PIN_LED_5 = 27; | ||
| + | const int PIN_LEDS[5] = { | ||
| + | PIN_LED_1, | ||
| + | PIN_LED_2, | ||
| + | PIN_LED_3, | ||
| + | PIN_LED_4, | ||
| + | PIN_LED_5 | ||
| + | }; | ||
| + | |||
| + | const int PIN_STEPPER_1 = 4; | ||
| + | const int PIN_STEPPER_2 = 0; | ||
| + | const int PIN_STEPPER_3 = 2; | ||
| + | const int PIN_STEPPER_4 = 15; | ||
| + | |||
| + | |||
| + | const long ITER_INTERVAL = 500; | ||
| + | |||
| + | const char* SSID = "Formation"; | ||
| + | const char* PSWD = "Apdgo29200!"; | ||
| + | |||
| + | const double SPEEDS[5] = { | ||
| + | 5.0, 25.0, 45.0, 65.0, 90.0 | ||
| + | }; | ||
| + | |||
| + | // Variables | ||
| + | unsigned long previous_millis = 0; | ||
| + | uint iter_count = 0; | ||
| + | |||
| + | bool leds_states[5] = { | ||
| + | false, false, false, false, false | ||
| + | }; | ||
| + | |||
| + | Stepper stepper = Stepper(2028, PIN_STEPPER_1, PIN_STEPPER_2, PIN_STEPPER_3, PIN_STEPPER_4); | ||
| + | double stepper_pos = 0.0; | ||
| + | |||
| + | double lat = 0.0; | ||
| + | double lon = 0.0; | ||
| − | + | double wind_speed = 0.0; | |
| − | + | double wind_gusts = 0.0; | |
| + | double wind_direction = 0.0; | ||
| + | |||
| + | // Fonctions | ||
| + | StaticJsonDocument<200> json_parse(String json) { | ||
| + | StaticJsonDocument<200> doc; | ||
| + | |||
| + | // Deserialize the JSON document | ||
| + | DeserializationError error = deserializeJson(doc, json); | ||
| + | |||
| + | // Test if parsing succeeds. | ||
| + | if (error) { | ||
| + | Serial.print(F("deserializeJson() failed: ")); | ||
| + | Serial.println(error.f_str()); | ||
| + | } | ||
| + | |||
| + | return doc; | ||
} | } | ||
| + | |||
| + | |||
| + | void wifi_setup() { | ||
| + | WiFi.begin(SSID, PSWD); | ||
| + | Serial.print("\nConnecting"); | ||
| + | |||
| + | while(WiFi.status() != WL_CONNECTED) { | ||
| + | Serial.print("."); | ||
| + | delay(500); | ||
| + | } | ||
| + | |||
| + | Serial.println("\nConnected to the WiFi network"); | ||
| + | Serial.print("Local ESP32 IP: "); | ||
| + | Serial.println(WiFi.localIP()); | ||
| + | } | ||
| + | |||
| + | |||
| + | String get_http_string(String url) { | ||
| + | HTTPClient http; | ||
| + | http.begin(url); | ||
| + | String str = "{}"; | ||
| + | if (http.GET() == HTTP_CODE_OK) { | ||
| + | str = http.getString(); | ||
| + | } else { | ||
| + | Serial.println("HTTP ERROR"); | ||
| + | } | ||
| + | http.end(); | ||
| + | return str; | ||
| + | } | ||
| + | |||
| + | |||
| + | void setup(){ | ||
| + | // Setup pins | ||
| + | pinMode(PIN_BUTTON, INPUT); | ||
| + | |||
| + | pinMode(PIN_LED_1, OUTPUT); | ||
| + | pinMode(PIN_LED_2, OUTPUT); | ||
| + | pinMode(PIN_LED_3, OUTPUT); | ||
| + | pinMode(PIN_LED_4, OUTPUT); | ||
| + | pinMode(PIN_LED_5, OUTPUT); | ||
| + | |||
| + | pinMode(PIN_STEPPER_1, OUTPUT); | ||
| + | pinMode(PIN_STEPPER_2, OUTPUT); | ||
| + | pinMode(PIN_STEPPER_3, OUTPUT); | ||
| + | pinMode(PIN_STEPPER_4, OUTPUT); | ||
| + | |||
| + | // Setup pas-a-pas | ||
| + | stepper.setSpeed(12); | ||
| + | |||
| + | // Setup serie | ||
| + | Serial.begin(115200); | ||
| + | |||
| + | // Setup WiFi | ||
| + | wifi_setup(); | ||
| + | String json_loc = get_http_string("http://ip-api.com/json/"); | ||
| + | StaticJsonDocument loc_data = json_parse(json_loc); | ||
| + | lat = loc_data["lat"] | 0.0; | ||
| + | lon = loc_data["lon"] | 0.0; | ||
| + | } | ||
| + | |||
void loop() { | void loop() { | ||
| − | // | + | unsigned long current_millis = millis(); |
| + | if (digitalRead(PIN_BUTTON)) { | ||
| + | stepper.step(5); | ||
| + | stepper_pos = 0; | ||
| + | } else if ((current_millis - previous_millis) > ITER_INTERVAL) { | ||
| + | if (iter_count == 0) { | ||
| + | // Mise à jour des données | ||
| + | String api_url = "http://api.open-meteo.com/v1/forecast?latitude=" + String(lat) + "&longitude=" + String(lon) + "¤t=wind_gusts_10m,wind_direction_10m,wind_speed_10m"; | ||
| + | String json_weather = get_http_string(api_url); | ||
| + | StaticJsonDocument weather_data = json_parse(json_weather); | ||
| + | |||
| + | wind_speed = weather_data["current"]["wind_speed_10m"] | 0.0; | ||
| + | wind_gusts = weather_data["current"]["wind_gusts_10m"] | 0.0; | ||
| + | wind_direction = weather_data["current"]["wind_direction_10m"] |0.0; | ||
| + | } | ||
| + | |||
| + | // Controle LEDs (vitesse du vent) | ||
| + | for (int i = 0; i<5; i++) { | ||
| + | if (wind_speed > SPEEDS[i]) { | ||
| + | leds_states[i] = true; | ||
| + | } else if (wind_gusts > SPEEDS[i]) { | ||
| + | leds_states[i] = !leds_states[i]; | ||
| + | } else { | ||
| + | leds_states[i] = false; | ||
| + | } | ||
| + | digitalWrite(PIN_LEDS[i], leds_states[i]); | ||
| + | } | ||
| + | |||
| + | // Controle stepper | ||
| + | stepper.step(int((wind_direction-stepper_pos)*4096.0/360.0)); | ||
| + | stepper_pos = wind_direction; | ||
| + | // Fin d'itération | ||
| + | iter_count = (iter_count + 1) % 20; | ||
| + | previous_millis = current_millis; | ||
| + | } | ||
} | } | ||
| Ligne 32 : | Ligne 205 : | ||
indiquer autant d'étape que nécessaire, chacune illustrée par des images (photo, dessins, ...) | indiquer autant d'étape que nécessaire, chacune illustrée par des images (photo, dessins, ...) | ||
| − | ===étape 1=== | + | ===étape 1 : Conception de l'objet=== |
| − | ===étape 2=== | + | [[Fichier:LeVentDuGlobeConceptCroquis.jpg|200px]] |
| + | [[Fichier:VentDesGlobes_MesuresBateauCarton.png|200px]] | ||
| + | ===étape 2 : Modélisation de l'objet=== | ||
| + | [[Fichier:Vent-du-globe maquette vue-dessus.jpg|200px]] | ||
===étape ...=== | ===étape ...=== | ||
===Troubleshouting=== | ===Troubleshouting=== | ||
Version actuelle datée du 20 janvier 2026 à 16:05
Titre de la fiche expérience :
Sommaire
description (résumé)
éventuelle photo de l'équipe
Le projet est créé à l'occasion du Hackathon ENIB 2026 par des élèves de l' ENIB (Ecole Nationale d' Ingénieur de Brest)[1].Celui-ci consiste à créer un POCL(Petits Objets Connectés Ludique).L'objet est passé par plusieurs étapes de conceptions, modélisation, de programmation afin d'arriver à une version rendue. Le but de l'objet est de montrer la direction du vent et sa force ainsi que l'état de la marée.
Introduction
Le vent du globe est un projet créé a l'occasion du Hackathon ENIB 2026.
Son nom est inspiré du Vendée Globe[2]
L'objet a pour but via un bateau de montrer la direction du vent à un endroit donné ainsi que sa force. La direction du vent est montré à travers la pointe avant du bateau par rapport au marquage de la boîte. L'inclinaison du bateau montre si la marée est montante ou descendante. Des leds sur le côté permettent d'indiquer la force du vent.
Les informations nécessaires sont récupérées sur internet via différents APIs[3].
éventuelle vidéo
outil et matériel
Une Arduino ESP32 est utilisée comme outil principal (voir : Contenu_de_votre_Kit)
fichiers à joindre
code, ficher d'impression 3D, de découpe laser ou vinyle, ...
Mettre du code Arduino
1
2 /* HACKATON ENIB 2026 - LE VENT DU GLOBE
3 *
4 */
5
6
7 // Librairies par défaut :
8 #include <WiFi.h>
9 #include <WiFiClientSecure.h>
10 #include <HTTPClient.h>
11 // Librairies additionnelles :
12 #include <ArduinoJson.h>
13 #include <Stepper.h>
14
15
16 // Constantes
17 const int PIN_BUTTON = 34;
18
19 const int PIN_LED_1 = 32;
20 const int PIN_LED_2 = 33;
21 const int PIN_LED_3 = 14;
22 const int PIN_LED_4 = 26;
23 const int PIN_LED_5 = 27;
24 const int PIN_LEDS[5] = {
25 PIN_LED_1,
26 PIN_LED_2,
27 PIN_LED_3,
28 PIN_LED_4,
29 PIN_LED_5
30 };
31
32 const int PIN_STEPPER_1 = 4;
33 const int PIN_STEPPER_2 = 0;
34 const int PIN_STEPPER_3 = 2;
35 const int PIN_STEPPER_4 = 15;
36
37
38 const long ITER_INTERVAL = 500;
39
40 const char* SSID = "Formation";
41 const char* PSWD = "Apdgo29200!";
42
43 const double SPEEDS[5] = {
44 5.0, 25.0, 45.0, 65.0, 90.0
45 };
46
47 // Variables
48 unsigned long previous_millis = 0;
49 uint iter_count = 0;
50
51 bool leds_states[5] = {
52 false, false, false, false, false
53 };
54
55 Stepper stepper = Stepper(2028, PIN_STEPPER_1, PIN_STEPPER_2, PIN_STEPPER_3, PIN_STEPPER_4);
56 double stepper_pos = 0.0;
57
58 double lat = 0.0;
59 double lon = 0.0;
60
61 double wind_speed = 0.0;
62 double wind_gusts = 0.0;
63 double wind_direction = 0.0;
64
65
66 // Fonctions
67 StaticJsonDocument<200> json_parse(String json) {
68 StaticJsonDocument<200> doc;
69
70 // Deserialize the JSON document
71 DeserializationError error = deserializeJson(doc, json);
72
73 // Test if parsing succeeds.
74 if (error) {
75 Serial.print(F("deserializeJson() failed: "));
76 Serial.println(error.f_str());
77 }
78
79 return doc;
80 }
81
82
83 void wifi_setup() {
84 WiFi.begin(SSID, PSWD);
85 Serial.print("\nConnecting");
86
87 while(WiFi.status() != WL_CONNECTED) {
88 Serial.print(".");
89 delay(500);
90 }
91
92 Serial.println("\nConnected to the WiFi network");
93 Serial.print("Local ESP32 IP: ");
94 Serial.println(WiFi.localIP());
95 }
96
97
98 String get_http_string(String url) {
99 HTTPClient http;
100 http.begin(url);
101 String str = "{}";
102 if (http.GET() == HTTP_CODE_OK) {
103 str = http.getString();
104 } else {
105 Serial.println("HTTP ERROR");
106 }
107 http.end();
108 return str;
109 }
110
111
112 void setup(){
113 // Setup pins
114 pinMode(PIN_BUTTON, INPUT);
115
116 pinMode(PIN_LED_1, OUTPUT);
117 pinMode(PIN_LED_2, OUTPUT);
118 pinMode(PIN_LED_3, OUTPUT);
119 pinMode(PIN_LED_4, OUTPUT);
120 pinMode(PIN_LED_5, OUTPUT);
121
122 pinMode(PIN_STEPPER_1, OUTPUT);
123 pinMode(PIN_STEPPER_2, OUTPUT);
124 pinMode(PIN_STEPPER_3, OUTPUT);
125 pinMode(PIN_STEPPER_4, OUTPUT);
126
127 // Setup pas-a-pas
128 stepper.setSpeed(12);
129
130 // Setup serie
131 Serial.begin(115200);
132
133 // Setup WiFi
134 wifi_setup();
135 String json_loc = get_http_string("http://ip-api.com/json/");
136 StaticJsonDocument loc_data = json_parse(json_loc);
137 lat = loc_data["lat"] | 0.0;
138 lon = loc_data["lon"] | 0.0;
139 }
140
141
142 void loop() {
143 unsigned long current_millis = millis();
144 if (digitalRead(PIN_BUTTON)) {
145 stepper.step(5);
146 stepper_pos = 0;
147 } else if ((current_millis - previous_millis) > ITER_INTERVAL) {
148 if (iter_count == 0) {
149 // Mise à jour des données
150 String api_url = "http://api.open-meteo.com/v1/forecast?latitude=" + String(lat) + "&longitude=" + String(lon) + "¤t=wind_gusts_10m,wind_direction_10m,wind_speed_10m";
151 String json_weather = get_http_string(api_url);
152 StaticJsonDocument weather_data = json_parse(json_weather);
153
154 wind_speed = weather_data["current"]["wind_speed_10m"] | 0.0;
155 wind_gusts = weather_data["current"]["wind_gusts_10m"] | 0.0;
156 wind_direction = weather_data["current"]["wind_direction_10m"] |0.0;
157 }
158
159 // Controle LEDs (vitesse du vent)
160 for (int i = 0; i<5; i++) {
161 if (wind_speed > SPEEDS[i]) {
162 leds_states[i] = true;
163 } else if (wind_gusts > SPEEDS[i]) {
164 leds_states[i] = !leds_states[i];
165 } else {
166 leds_states[i] = false;
167 }
168 digitalWrite(PIN_LEDS[i], leds_states[i]);
169 }
170
171 // Controle stepper
172 stepper.step(int((wind_direction-stepper_pos)*4096.0/360.0));
173 stepper_pos = wind_direction;
174
175 // Fin d'itération
176 iter_count = (iter_count + 1) % 20;
177 previous_millis = current_millis;
178 }
179 }
étapes de fabrication
indiquer autant d'étape que nécessaire, chacune illustrée par des images (photo, dessins, ...)
étape 1 : Conception de l'objet
étape 2 : Modélisation de l'objet
étape ...
Troubleshouting
Quelles sont difficultés, les problèmes, quelles sont les solutions, les trucs et astuces pour que ça marche ?
Sources et documentation complémentaire
- Rédаctiоn et illustratiоn :
Pоur tоus vоs trаvauх, qu'ils sоient écrits оu visuels, l'utilisatiоn de l'intеlligеnce artificiеllе générativе, que сe sоit pоur le teхte оu les images, n'еst pas conseillé.
- Prоgrammаtiоn :
En сe qui cоncernе la prоgrаmmatiоn, il est еssentiеl de ne pаs faire dе l'IA vоtrе prеmier rеcоurs. Cоncеntrеz-vоus d'abоrd sur vоtre prоpre lоgiquе, votre experience еt lеs ressоurcеs disponibles.
- Transpаrence et dосumеntatiоn :
Si vоus utilisеz l'IA pоur déblоquer оu améliоrеr une pаrtiе de vоtre cоdе, il est cruciаl de l'indiquеr сlairеmеnt dans vоtre dосumentatiоn tеchniquе.
- Traçabilité :
Chаque ехtrait de cоde généré avес l'аidе de l'IA dоit êtrе accоmpagné de la sоurce, ainsi que du prоmpt eхact qui a été utilisé pоur sа créatiоn, afin d'аssurеr une évaluatiоn clаire dе vоtre prоcessus.
Elément de présentation
je met ici le document de présentation de mon projet