ENIB 2026 : Girouette : Différence entre versions
(→Introduction) |
(→Mettre du code Arduino) |
||
| Ligne 24 : | Ligne 24 : | ||
===Mettre du code Arduino=== | ===Mettre du code Arduino=== | ||
<syntaxhighlight lang="Arduino" line> | <syntaxhighlight lang="Arduino" line> | ||
| − | # | + | |
| − | #include < | + | #include <WiFi.h> |
| + | #include <HTTPClient.h> | ||
| + | #include <ArduinoJson.h> | ||
| + | #include <ESP32Servo.h> | ||
| + | |||
| + | // ------------------- VOS PARAMETRES WIFI ------------------- | ||
| + | const char* ssid = "FABLAB 2.4"; | ||
| + | const char* password = "MonPetitPonant"; | ||
| + | |||
| + | // ------------------- VOTRE LOCALISATION (Ex: Brest) ------------------- | ||
| + | // Trouvez les vôtres sur Google Maps (clic droit sur la carte) | ||
| + | const float latitude = 48.3904; | ||
| + | const float longitude = -4.4861; | ||
| + | |||
| + | // ------------------- PINS DE BRANCHEMENT ------------------- | ||
| + | const int servoPin = 13; // Fil Orange du servo | ||
| + | const int buttonPin = 12; // Un côté du bouton (l'autre au GND) | ||
| + | |||
| + | // ------------------- OBJETS ET VARIABLES ------------------- | ||
| + | Servo windServo; | ||
| + | |||
| + | // Timer pour ne pas bloquer l'API (Mise à jour toutes les 15 minutes) | ||
| + | unsigned long lastTime = 0; | ||
| + | unsigned long timerDelay = 900000; // 15 minutes en millisecondes | ||
void setup() { | void setup() { | ||
| − | + | Serial.begin(115200); | |
| + | Serial.println("Test"); | ||
| + | // 1. Configuration du Servo (ESP32Servo) | ||
| + | windServo.setPeriodHertz(50); // Standard 50hz servo | ||
| + | windServo.attach(servoPin, 500, 2400); // Plage d'impulsion standard pour ESP32 | ||
| + | |||
| + | // Test de démarrage : Balayage rapide pour montrer qu'il est vivant | ||
| + | windServo.write(0); delay(500); | ||
| + | |||
| + | // 2. Configuration du Bouton | ||
| + | pinMode(buttonPin, INPUT_PULLUP); | ||
| + | |||
| + | // 3. Connexion WiFi | ||
| + | WiFi.begin(ssid, password); | ||
| + | Serial.print("Connexion au WiFi"); | ||
| + | while (WiFi.status() != WL_CONNECTED) { | ||
| + | delay(500); | ||
| + | Serial.print("."); | ||
| + | } | ||
| + | |||
| + | Serial.print("\nConnected to Wi-Fi network with IP Address: "); | ||
| + | Serial.println(WiFi.localIP()); | ||
| + | |||
| + | // Première mise à jour immédiate | ||
| + | getAndDisplayWind(); | ||
} | } | ||
void loop() { | void loop() { | ||
| − | // | + | // Vérification du timer (Automatique) |
| + | if ((millis() - lastTime) > timerDelay) { | ||
| + | getAndDisplayWind(); | ||
| + | } | ||
| + | |||
| + | // Vérification du bouton (Manuel) | ||
| + | // Si on appuie, on force la mise à jour | ||
| + | if (digitalRead(buttonPin) == LOW) { | ||
| + | Serial.println("Bouton pressé -> Mise à jour..."); | ||
| + | getAndDisplayWind(); | ||
| + | delay(1000); // Anti-rebond (attendre un peu) | ||
| + | } | ||
| + | } | ||
| + | |||
| + | // Fonction principale qui fait tout le travail | ||
| + | void getAndDisplayWind() { | ||
| + | if(WiFi.status() == WL_CONNECTED) { | ||
| + | HTTPClient http; | ||
| + | |||
| + | // Construction de l'URL Open-Meteo | ||
| + | String serverPath = "https://api.open-meteo.com/v1/meteofrance?latitude=" + String(latitude) + | ||
| + | "&longitude=" + String(longitude) + | ||
| + | "¤t=wind_direction_50m"; | ||
| + | |||
| + | Serial.println("Requete API en cours..."); | ||
| + | http.begin(serverPath); | ||
| + | int httpResponseCode = http.GET(); | ||
| + | |||
| + | if (httpResponseCode > 0) { | ||
| + | String payload = http.getString(); | ||
| + | |||
| + | // Analyse du JSON (Parsing) | ||
| + | DynamicJsonDocument doc(1024); | ||
| + | DeserializationError error = deserializeJson(doc, payload); | ||
| + | |||
| + | if (!error) { | ||
| + | // Lecture de la direction (0 à 360°) | ||
| + | float windDir360 = doc["current"]["wind_direction_50m"]; | ||
| + | |||
| + | Serial.print("Direction Vent Réelle : "); | ||
| + | Serial.print(windDir360); | ||
| + | Serial.println(" degrés"); | ||
| + | |||
| + | // Conversion pour le servo (360 -> 180) | ||
| + | moveServoToWind(windDir360); | ||
| + | |||
| + | } else { | ||
| + | Serial.print("Erreur JSON: "); | ||
| + | Serial.println(error.c_str()); | ||
| + | } | ||
| + | } else { | ||
| + | Serial.print("Erreur HTTP: "); | ||
| + | Serial.println(httpResponseCode); | ||
| + | } | ||
| + | http.end(); | ||
| + | lastTime = millis(); // Reset du timer | ||
| + | } else { | ||
| + | Serial.println("Erreur : WiFi coupé !"); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | void moveServoToWind(float angle360) { | ||
| + | // C'est ici que la "magie" opère. | ||
| + | // La fonction map(valeur, min_in, max_in, min_out, max_out) | ||
| + | // transforme l'échelle 0-360 en 0-180. | ||
| + | |||
| + | int servoAngle = map((long)angle360, 0, 360, 0, 180); | ||
| + | |||
| + | // Sécurité pour ne pas forcer le moteur | ||
| + | if (servoAngle < 0) servoAngle = 0; | ||
| + | if (servoAngle > 180) servoAngle = 180; | ||
| + | |||
| + | Serial.print("Position Servo : "); | ||
| + | Serial.println(servoAngle); | ||
| + | windServo.write(servoAngle); | ||
} | } | ||
Version du 20 janvier 2026 à 15:47
Titre de la fiche expérience :
Sommaire
description (résumé)
Introduction
L’objectif de ce projet est de concevoir un dispositif simple mêlant électronique, programmation et fabrication manuelle. La girouette est commandée par un servomoteur, lui-même piloté par une carte ESP32. Ce projet nous a permis de découvrir les contraintes liées au choix du matériel, à la compatibilité des bibliothèques logicielles et au prototypage rapide.
outil et matériel
Un servomoteur 180°
Un bouton poussoir
Une carte ESP32 Wroom-32
Du carton
Du scotch
fichiers à joindre
code, ficher d'impression 3D, de découpe laser ou vinyle, ...
Mettre du code Arduino
1
2
3 #include <WiFi.h>
4 #include <HTTPClient.h>
5 #include <ArduinoJson.h>
6 #include <ESP32Servo.h>
7
8 // ------------------- VOS PARAMETRES WIFI -------------------
9 const char* ssid = "FABLAB 2.4";
10 const char* password = "MonPetitPonant";
11
12 // ------------------- VOTRE LOCALISATION (Ex: Brest) -------------------
13 // Trouvez les vôtres sur Google Maps (clic droit sur la carte)
14 const float latitude = 48.3904;
15 const float longitude = -4.4861;
16
17 // ------------------- PINS DE BRANCHEMENT -------------------
18 const int servoPin = 13; // Fil Orange du servo
19 const int buttonPin = 12; // Un côté du bouton (l'autre au GND)
20
21 // ------------------- OBJETS ET VARIABLES -------------------
22 Servo windServo;
23
24 // Timer pour ne pas bloquer l'API (Mise à jour toutes les 15 minutes)
25 unsigned long lastTime = 0;
26 unsigned long timerDelay = 900000; // 15 minutes en millisecondes
27
28 void setup() {
29 Serial.begin(115200);
30 Serial.println("Test");
31
32 // 1. Configuration du Servo (ESP32Servo)
33 windServo.setPeriodHertz(50); // Standard 50hz servo
34 windServo.attach(servoPin, 500, 2400); // Plage d'impulsion standard pour ESP32
35
36 // Test de démarrage : Balayage rapide pour montrer qu'il est vivant
37 windServo.write(0); delay(500);
38
39 // 2. Configuration du Bouton
40 pinMode(buttonPin, INPUT_PULLUP);
41
42 // 3. Connexion WiFi
43 WiFi.begin(ssid, password);
44 Serial.print("Connexion au WiFi");
45 while (WiFi.status() != WL_CONNECTED) {
46 delay(500);
47 Serial.print(".");
48 }
49
50 Serial.print("\nConnected to Wi-Fi network with IP Address: ");
51 Serial.println(WiFi.localIP());
52
53 // Première mise à jour immédiate
54 getAndDisplayWind();
55 }
56
57 void loop() {
58 // Vérification du timer (Automatique)
59 if ((millis() - lastTime) > timerDelay) {
60 getAndDisplayWind();
61 }
62
63 // Vérification du bouton (Manuel)
64 // Si on appuie, on force la mise à jour
65 if (digitalRead(buttonPin) == LOW) {
66 Serial.println("Bouton pressé -> Mise à jour...");
67 getAndDisplayWind();
68 delay(1000); // Anti-rebond (attendre un peu)
69 }
70 }
71
72 // Fonction principale qui fait tout le travail
73 void getAndDisplayWind() {
74 if(WiFi.status() == WL_CONNECTED) {
75 HTTPClient http;
76
77 // Construction de l'URL Open-Meteo
78 String serverPath = "https://api.open-meteo.com/v1/meteofrance?latitude=" + String(latitude) +
79 "&longitude=" + String(longitude) +
80 "¤t=wind_direction_50m";
81
82 Serial.println("Requete API en cours...");
83 http.begin(serverPath);
84 int httpResponseCode = http.GET();
85
86 if (httpResponseCode > 0) {
87 String payload = http.getString();
88
89 // Analyse du JSON (Parsing)
90 DynamicJsonDocument doc(1024);
91 DeserializationError error = deserializeJson(doc, payload);
92
93 if (!error) {
94 // Lecture de la direction (0 à 360°)
95 float windDir360 = doc["current"]["wind_direction_50m"];
96
97 Serial.print("Direction Vent Réelle : ");
98 Serial.print(windDir360);
99 Serial.println(" degrés");
100
101 // Conversion pour le servo (360 -> 180)
102 moveServoToWind(windDir360);
103
104 } else {
105 Serial.print("Erreur JSON: ");
106 Serial.println(error.c_str());
107 }
108 } else {
109 Serial.print("Erreur HTTP: ");
110 Serial.println(httpResponseCode);
111 }
112 http.end();
113 lastTime = millis(); // Reset du timer
114 } else {
115 Serial.println("Erreur : WiFi coupé !");
116 }
117 }
118
119 void moveServoToWind(float angle360) {
120 // C'est ici que la "magie" opère.
121 // La fonction map(valeur, min_in, max_in, min_out, max_out)
122 // transforme l'échelle 0-360 en 0-180.
123
124 int servoAngle = map((long)angle360, 0, 360, 0, 180);
125
126 // Sécurité pour ne pas forcer le moteur
127 if (servoAngle < 0) servoAngle = 0;
128 if (servoAngle > 180) servoAngle = 180;
129
130 Serial.print("Position Servo : ");
131 Serial.println(servoAngle);
132
133 windServo.write(servoAngle);
134 }
étapes de fabrication
indiquer autant d'étape que nécessaire, chacune illustrée par des images (photo, dessins, ...)
étape 1 : Test des servomoteurs
Nous avons commencé par tester les servomoteurs à l’aide de codes fournis sur le wiki des Débrouillards. Cependant, ces codes ne fonctionnaient pas avec les versions de la carte que nous utilisions. Cela nous a amenés à utiliser une intelligence artificielle comme aide ponctuelle : nous lui avons fourni le code du site et demandé d’utiliser une autre librairie compatible.
Au départ, nous avons utilisé un servomoteur 360°. Ce type de servomoteur ne permet pas de définir une position précise, seulement de commander une rotation ou un arrêt. Pour cette raison, nous sommes finalement passés à un servomoteur 180°, capable de connaître et atteindre une position angulaire précise.
étape 2 : Conception du prototype
Nous avons ensuite conçu le prototype physique en découpant du carton afin de créer la structure de la girouette. Les différents composants (ESP32, servomoteur, bouton poussoir) ont été positionnés et fixés à l’aide de scotch pour permettre des ajustements rapides.
étape 3 : Assemblage et tests
Une fois le prototype assemblé, nous avons procédé à des tests de fonctionnement pour vérifier la rotation du servomoteur, la réaction au bouton poussoir et la stabilité de l’ensemble.
Troubleshouting
Plusieurs difficultés ont été rencontrées au cours du projet :
Compatibilité logicielle : les codes existants ne fonctionnaient pas avec la version de la carte utilisée. Solution : adaptation du code et changement de librairie.
Choix du servomoteur : le servomoteur 360° ne permettait pas un contrôle précis de la position. Solution : remplacement par un servomoteur 180°.
Téléversement du programme : il a fallu débrancher l’ensemble du montage pour réussir à téléverser le code. Cela peut être dû au fait que l’ESP32 est tactile et potentiellement mis en sécurité par le carton, ou à un mauvais câblage. De plus, le bouton poussoir possède une polarité qui peut provoquer des dysfonctionnements s’il est mal branché.
Connexion au Wifi : la carte ne voulait pas se connecter au Wifi. Il a fallu changer de carte et de code. Trucs et astuces :
Tester le code avec un montage minimal avant l’assemblage final
Vérifier attentivement le câblage du bouton poussoir
Débrancher les éléments non indispensables lors du téléversement
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