Lucas Tirand¶
Introduction¶
Dans le cadre de ma formation en première professionnelle CIEL, j’effectue un stage, réparti en deux périodes : du 20 avril au 13 mai 2026, puis du 15 juin au 26 juin 2026.
Pendant ce stage, je travaille sur un projet d’armoire de séchage pour filaments d’impression 3D. Ce projet consiste à réaliser un système permettant de contrôler la température et l’humidité afin de conserver les bobines dans de bonnes conditions.
Ce stage me permet de découvrir différents domaines comme l’électronique, la programmation et la modélisation 3D, en utilisant notamment des cartes Arduino et ESP32 ainsi que des capteurs.
Stage¶
Activités réalisées¶
Installation de Debian¶
J’ai installé Debian 13.4.0 sur un ordinateur à l’aide d’une clé USB bootable, puis j’ai configuré le système.
Recherches d'armoires de séchage pour filaments¶
J’ai ensuite effectué des recherches sur les armoires de séchage de filaments pour l’impression 3D. Voici les résultats de mes recherches :
Maintient la température autour de 35 °C et l’humidité entre 15 % et 20 %, contrôlées par un thermomètre d’intérieur.
Pour sécher les bobines, elle utilise un déshumidificateur de chambre, une tige de déshumidification et un déshydrateur alimentaire.
Le déshumidificateur et le déshydrateur sont placés en bas de l’armoire.
Utilise un déshumidificateur et des boîtes de déshydratation fixées au milieu de l’armoire pour garder le matériel sec.
Aucun contrôle de température n’est prévu.
Utilise 500 g de perles de silice placées en bas pour absorber l’humidité. Le dessicant doit être remplacé chaque mois.
La température est surveillée à l’aide d’un thermomètre d’intérieur placé en bas.
Maintient l’humidité grâce à un déshumidificateur placé à la même hauteur que les rouleaux, sur la droite.
Aucun contrôle de température n’est disponible.
Maintient automatiquement la température et l’humidité. Si ces paramètres sont trop élevés ou trop bas, l’armoire ajuste automatiquement.
Il est possible de choisir la température et l’humidité souhaitées via un écran numérique.
Montage prototype capteur de température¶
Montage Arduino et DHT22¶
J’ai réalisé un montage avec une carte Arduino et un capteur DHT22, qui mesure la température et l’humidité.
 |
|
| Légende |
Ce montage sert à mesurer la température et l’humidité avec un capteur DHT22 relié à une carte Arduino. Il est branché sur la broche D6 et partage le 5V et le GND avec l’Arduino. |
Voicimon code :mon code :
#include <DHT.h>
#define brocheDeBranchementDHT 6 // Le DHT22 est branché sur le pin D6
#define typeDeDHT DHT22
DHT dht(brocheDeBranchementDHT, typeDeDHT);
void setup() {
// Moniteur série
Serial.begin(9600);
dht.begin();
}
void loop() {
// Lecture des données
float tauxHumidite = dht.readHumidity(); // Lecture du taux d'humidité (en %)
float tauxTemperature = dht.readTemperature(); // Lecture de la température (en °C)
// Vérification des données
if (isnan(tauxHumidite) || isnan(tauxTemperature)) {
Serial.println("Problème DHT");
delay(2000);
return;
}
// Affichage sur le moniteur série
Serial.print(tauxHumidite);
Serial.print(",");
Serial.print(tauxTemperature);
Serial.println();
delay(2000);
}
Ce code permet de mesurer la température et l’humidité de l’air ambiant, puis d’envoyer les résultats sur le moniteur série et de les afficher sous forme de graphique.
 |
|
| Légende |
Ce graphique montre l’évolution de la température (rouge) et de l’humidité (bleu) mesurées par le capteur DHT22. Les données sont envoyées en temps réel par l’Arduino et affichées sous forme de courbes. |
J’ai eu des problèmes pour transférer le code sur la carte Arduino parce que l’IDE n’avait pas les permissions. J’ai donc donné les droits administrateur au compte.
Ajout d'un écran LCD¶
J’ai ajouté un écran LCD pour afficher les résultats directement sur le montage, au lieu d’utiliser le moniteur série.
 |
|
| Légende |
Ce montage permet d’afficher les valeurs de température et d’humidité mesurées par le capteur DHT sur un écran LCD. L’écran est relié à la carte Arduino sur les broches A4 et A5 pour la communication. |
Voicimon code :mon code :
#include <DHT.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define brocheDeBranchementDHT 6 // Le DHT22 est branché sur le pin D6
#define typeDeDHT DHT22
DHT dht(brocheDeBranchementDHT, typeDeDHT);
LiquidCrystal_I2C lcd(0x27, 16, 2); // Le LCD peut afficher 16 caractères par ligne sur 2 lignes
// Définition du caractère "°" sur le LCD (tableau 5x8 en binaire)
byte Degres[] = {
B00111,
B00101,
B00111,
B00000,
B00000,
B00000,
B00000,
B00000
};
void setup() {
lcd.init();
lcd.backlight();
lcd.createChar(0, Degres); // Création du caractère degrés
lcd.clear();
// Moniteur série
Serial.begin(9600);
dht.begin();
}
void loop() {
// Lecture des données
float tauxHumidite = dht.readHumidity(); // Lecture du taux d'humidité (en %)
float tauxTemperature = dht.readTemperature(); // Lecture de la température (en °C)
// Vérification des données
if (isnan(tauxHumidite) || isnan(tauxTemperature)) {
Serial.println("Problème dht");
delay(2000);
return;
}
// Affichage sur le LCD
lcd.setCursor(3, 0);
lcd.print(tauxHumidite);
lcd.print(" %RH");
lcd.setCursor(4, 1);
lcd.print(tauxTemperature);
lcd.print(" ");
lcd.write(0);
lcd.print("C");
delay(2000);
}
J’ai rencontré des difficultés pour afficher le symbole “°”, car il ne faisait pas partie des caractères acceptés par la bibliothèque. J’ai donc créé ma propre version avec du code binaire pour reproduire le signe des degrés.
Remplacement Arduino par ESP32¶
J’ai d’abord appris à utiliser un ESP32 et à connaître ses broches. Ensuite, comme mon code ne fonctionnait pas, j’ai fait quelques modifications demon code :mon code :
#define DHT1 4
Le DHT22 est branché sur le pin 4 et non pas sur le 6 car c'est un pin réserver au flash.
Wire.begin(21, 22);
SDA = 21, SCL = 22 (pins par défaut du LCD sur un ESP32).
Serial.begin(115200);
L'ESP32 communique à une vitesse de 115200 bauds car 9600 est trop bas.
Essai avec un deuxième DHT22¶
J’ai fait un essai en ajoutant un deuxième capteur DHT22 et j’ai modifiéle code :le code :
#include <DHT.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define DHT1 4 // Le premier DHT22 est branché sur le pin 4
#define DHT2 18 // Le deuxième DHT22 est branché sur le pin 18
#define typeDeDHT DHT22
DHT premierdht(DHT1, typeDeDHT);
DHT deuxiemedht(DHT2, typeDeDHT);
LiquidCrystal_I2C lcd(0x27, 16, 2); // Le LCD peut afficher 16 caractères par ligne sur 2 lignes
// Définition du caractère "°" sur le LCD (tableau 5x8 en binaire)
byte Degres[] = {
B00111,
B00101,
B00111,
B00000,
B00000,
B00000,
B00000,
B00000
};
void setup() {
Wire.begin(21, 22); // SDA = 21, SCL = 22 (pins par défaut du LCD sur ESP32)
lcd.init();
lcd.backlight();
lcd.createChar(0, Degres); // Création du caractère degrés
lcd.clear();
// Moniteur série
Serial.begin(92160);
premierdht.begin();
deuxiemedht.begin();
}
void loop() {
// Lecture des données
float tauxHumidite1 = premierdht.readHumidity(); // Lecture du taux d'humidité du premier DHT22 (en %)
float tauxTemperature1 = premierdht.readTemperature(); // Lecture de la température du premier DHT22 (en °C)
delay(200); // Attente de 0.2 seconde car sinon les données des deux capteurs se chevauchent
float tauxHumidite2 = deuxiemedht.readHumidity(); // Lecture du taux d'humidité du deuxième DHT22 (en %)
float tauxTemperature2 = deuxiemedht.readTemperature(); // Lecture de la température du deuxième DHT22 (en °C)
// Vérification des données du premier DHT
if (isnan(tauxHumidite1) || isnan(tauxTemperature1)) {
Serial.println("Problème DHT1");
delay(3000);
return;
}
// Vérification des données du deuxième DHT
if (isnan(tauxHumidite2) || isnan(tauxTemperature2)) {
Serial.println("Problème DHT2");
delay(3000);
return;
}
// Affichage sur le LCD
lcd.setCursor(0, 0);
lcd.print(tauxHumidite1);
lcd.print(";");
lcd.print(tauxHumidite2);
lcd.print(" %RH");
lcd.setCursor(1, 1);
lcd.print(tauxTemperature1);
lcd.print(";");
lcd.print(tauxTemperature2);
lcd.write(0);
lcd.print("C");
delay(3000);
}
Mes difficultés avec ce montage étaient :
- J’avais inversé les broches 5V et GND sur la carte.
- J’ai dû ajouter un petit délai entre la récupération des données des deux DHT22, sinon elles se chevauchaient et la lecture était impossible.
 |
|
| Légende |
Ce montage utilise un ESP32 pour relever la température et l’humidité à l’aide de deux capteurs DHT22. Les capteurs sont branchés sur les pins 4 et 18, et les valeurs sont affichées sur un écran LCD connecté aux pins 21 et 22. |
Ajout d'un ventilateur¶
J’ai ajouté un ventilateur au montage. Pour le moment, j’essaie simplement de programmer un ventilateur PWM de 12 V.
J’ai d’abord soudé un câble mâle sur l’alimentation 12 V, car l’un des câbles était dénudé. Ensuite, j’ai fait fonctionner le ventilateur directement sur la carte Arduino et l’alimentation 12 V.
J’ai rencontré des problèmes avec le câblage : j’ai essayé d’utiliser un MOSFET, une diode et des résistances, mais il a fallu changer de ventilateur, car le premier ne pouvait pas supporter le courant.
- Le premier ventilateur testé était le AFB0612L (4 broches).
- Le second ventilateur est le DS09225R12HP032 (4 broches).
Voicimon code de test :mon code de test :
int fanPin = 9; // Le ventilateur est branché sur le pin D9
// Définition du pin D9 comme sortie
void setup() {
pinMode(fanPin, OUTPUT);
}
// Le ventilateur fonctionne en boucle
void loop() {
for (int i = 0; i <= 255; i++) { // 0 correspond à aucun signal et 255 au maximum
analogWrite(fanPin, 10);
delay(1000);
analogWrite(fanPin, 100);
delay(1000);
analogWrite(fanPin, 175);
delay(1000);
analogWrite(fanPin, 255);
delay(2000);
analogWrite(fanPin, 175);
delay(1000);
analogWrite(fanPin, 100);
delay(1000);
analogWrite(fanPin, 10);
delay(1000);
}
}
Ce code permet de faire fonctionner le ventilateur en augmentant puis en diminuant sa puissance.
 |
|
| Légende |
Ce montage est un test de fonctionnement d’un ventilateur contrôlé par PWM via une carte Arduino. Le signal PWM est envoyé sur la broche D9, tandis que le ventilateur est alimenté en 12V avec une masse commune entre l’alimentation et l’Arduino. |
Ensuite, j'ai intégré ce ventilateur au montage. Pour commencer, j’ai repris le montage avec la carte Arduino, le DHT22 et le LCD. Mon objectif était de mettre le ventilateur en marche si le taux d’humidité devient trop élevé.
voicimon code:mon code:
#include <DHT.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#define brocheDeBranchementDHT 6 // Le DHT22 est branché sur le pin D6
#define typeDeDHT DHT22
DHT dht(brocheDeBranchementDHT, typeDeDHT);
int fanPin = 9; // Le ventilateur est branché sur le pin D9
int fanSpeed = 0; // La vitesse du ventilateur est 0 par définition
LiquidCrystal_I2C lcd(0x27, 16, 2); // Le LCD peut afficher 16 caractères par ligne sur 2 lignes
// Définition du caractère "°" sur le LCD (tableau 5x8 en binaire)
byte Degres[] = {
B00111,
B00101,
B00111,
B00000,
B00000,
B00000,
B00000,
B00000
};
// Variables pour gestion du temps
unsigned long dernierMajDHT = 0; // dernier moment où le DHT a été lu
const unsigned long IntervalleDHT = 2000; // Intervalle de lecture DHT en millisecondes
unsigned long dernierMajFan = 0; // Dernier moment où la vitesse du ventilateur a été mise à jour
const unsigned long IntervalleFan = 1000; // Intervalle de mise à jour du ventilateur en millisecondes
void setup() {
pinMode(fanPin, OUTPUT);
lcd.init();
lcd.backlight();
lcd.createChar(0, Degres); // Création du caractère degrés
lcd.clear();
// Moniteur série
Serial.begin(9600);
dht.begin();
}
void loop() {
unsigned long millisActuels = millis();
// Lecture DHT toutes les 2 sec
if (millisActuels - dernierMajDHT >= IntervalleDHT) {
dernierMajDHT = millisActuels;
// Lecture des données
float tauxHumidite = dht.readHumidity(); // Lecture du taux d'humidité (en %)
float tauxTemperature = dht.readTemperature(); // Lecture de la température (en °C)
// Vérification des données
if (isnan(tauxHumidite) || isnan(tauxTemperature)) {
Serial.println("Problème DHT");
return;
}
// Affichage sur le LCD
lcd.setCursor(3, 0);
lcd.print(tauxHumidite);
lcd.print(" %RH");
lcd.setCursor(4, 1);
lcd.print(tauxTemperature);
lcd.print(" ");
lcd.write(0);
lcd.print("C");
// Gestion ventilateur
if (tauxHumidite >= 30) { // Seuil pour activer le ventilateur (30% d'humidité)
// Augmentation progressive de la vitesse du ventilateur
if (millisActuels - dernierMajFan >= IntervalleFan) {
dernierMajFan = millisActuels;
if (fanSpeed < 255) {
fanSpeed += 100; // Augmentation de la vitesse par étapes de 100 (max 255 pour PWM)
if (fanSpeed > 255) fanSpeed = 255;
analogWrite(fanPin, fanSpeed);
}
}
} else {
fanSpeed = 0; // Humidité < 30%, ventilateur arrêté
analogWrite(fanPin, fanSpeed);
}
}
}
 |
|
| Légende |
Ce montage permet de mesurer la température et l’humidité avec un capteur DHT22, dont les valeurs sont affichées sur un écran LCD relié à l’Arduino. Un ventilateur est ajouté et contrôlé en PWM via la broche D9, avec une alimentation 12V et une masse commune entre l’alimentation et l’Arduino. |
J’ai eu des difficultés avec le câblage du ventilateur par rapport à l’Arduino et à l’alimentation 12 V.
Il suffisait simplement de relier tous les GND ensemble, de brancher le positif du ventilateur au positif de l’alimentation et de connecter le ventilateur sur la broche D9, car c’est une broche PWM.
J’ai également eu des difficultés pour coder le ventilateur en fonction du taux d’humidité.
J’ai remplacé la carte Arduino par un ESP32. Cela a nécessité quelques modifications de mon code (voir ce lien Lucas_Tirand pour en savoir plus).
Ajout du système PID¶
J’ai installé la librairie PID dans l’IDE Arduino.
J’ai ensuite appris ce qu’est le PID et comment le calculer, car je ne connaissais pas ce concept.
J’ai intégré ce système àmon code :mon code :
#include <DHT.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <PID_v1_bc.h>
#define brocheDeBranchementDHT 4 // Le DHT22 est branché sur le pin 4
#define typeDeDHT DHT22
DHT dht(brocheDeBranchementDHT, typeDeDHT);
int fanPin = 18; // Le ventilateur est branché sur le pin 18
LiquidCrystal_I2C lcd(0x27, 16, 2); // Le LCD peut afficher 16 caractères par ligne sur 2 lignes
// Définition du caractère "°" sur le LCD (tableau 5x8 en binaire)
byte Degres[] = {
B00111,
B00101,
B00111,
B00000,
B00000,
B00000,
B00000,
B00000
};
// Variables pour gestion du temps
unsigned long dernierMajDHT = 0; // dernier moment où le DHT a été lu
const unsigned long IntervalleDHT = 2000; // Intervalle de lecture DHT en millisecondes
unsigned long dernierMajPID = 0; // dernier moment où le PID a été lu
const unsigned long IntervallePID = 300; // Intervalle de lecture PID en millisecondes
// Variable PID
double Setpoint = 50; // Humidité ciblée
double Input;
double Output;
double Kp = 2.5; // Proportionnel
double Ki = 4.38; // Intégral
double Kd = 0.16; // Dérivé
PID pid(&Input, &Output, &Setpoint, Kp, Ki, Kd, REVERSE);
void setup() {
pinMode(fanPin, OUTPUT);
Wire.begin(21, 22); // SDA = 21, SCL = 22 (pins par défaut du LCD sur un ESP32)
lcd.init();
lcd.backlight();
lcd.createChar(0, Degres); // Création du caractère degrés
lcd.clear();
// Moniteur série
Serial.begin(115200);
dht.begin();
pid.SetMode(AUTOMATIC);
pid.SetOutputLimits(0, 255); // PMW correspond à une valeur entre 0 et 255
}
void loop() {
unsigned long millisActuels = millis();
// Lecture DHT toutes les 2 sec
if (millisActuels - dernierMajDHT >= IntervalleDHT) {
dernierMajDHT = millisActuels;
// Lecture des données
float tauxHumidite = dht.readHumidity(); // Lecture du taux d'humidité (en %)
float tauxTemperature = dht.readTemperature(); // Lecture de la température (en °C)
// Vérification des données
if (!isnan(tauxHumidite) && !isnan(tauxTemperature)) {
Input = tauxHumidite;
// Affichage sur le LCD
lcd.setCursor(3, 0);
lcd.print(tauxHumidite);
lcd.print(" %RH");
lcd.setCursor(4, 1);
lcd.print(tauxTemperature);
lcd.print(" ");
lcd.write(0);
lcd.print("C");
}
}
// Lecture PID toutes les 300 ms
if (millisActuels - dernierMajPID >= IntervallePID) {
dernierMajPID = millisActuels;
pid.Compute(); // Calcule PID
analogWrite(fanPin, (int)Output);
Serial.print("Vitesse du ventilateur : ");
Serial.println(Output);
}
}
Mes difficultés avec ce code étaient :
- Le réglage des trois variables du PID (Proportionnel, Intégral et Dérivé).
- Le ventilateur ne faisait qu’augmenter sa vitesse, au lieu d’être correctement régulé par le PID.
Ajout d'une page web¶
J’ai ajouté une page web via l’ESP32 pour afficher la température, l’humidité et la vitesse du ventilateur.
Pour commencer, j’ai créé une page web simple qui comptait le nombre de visiteurs. Chaque fois que la page était actualisée, le compteur augmentait de 1.
Voicimon code :mon code :
#include <WiFi.h>
#include <WebServer.h>
// Nom et mot de passe du Wifi
const char* ssid = "coh@bit";
const char* password = "lewifidecohabit";
WebServer server(80); // HTML correspond au port 80
int nombre_visite = 0;
void setup() {
Serial.begin(115200);
Serial.println("Connexion à ");
Serial.println(ssid);
// Connexion au Wifi local
WiFi.begin(ssid, password);
// Verification si le Wifi est connecté à internet
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println("");
Serial.println("Wifi Connecté");
Serial.print("IP : ");
Serial.println(WiFi.localIP());
server.on("/", handle_OnConnect);
server.onNotFound(handle_NotFound);
server.begin();
Serial.println("Server HTTP en marche");
}
void loop() {
server.handleClient();
}
void handle_OnConnect() {
nombre_visite++;
server.send(200, "text/html", createHTML());
}
//Création page d'erreur
void handle_NotFound() {
server.send(404, "text/plain", "Not found");
}
// Création page HTML
String createHTML() {
String html = "<!DOCTYPE html> <html>";
html += "<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=yes\">";
html += "<style>";
html += "body {font-family: Arial, sans-serif; color: #444; text-align: center;}";
html += ".title {font-size: 30px; font-weight: bold; letter-spacing: 2px; margin: 80px 0 55px;}";
html += ".nombre_visite {font-size: 80px; font-weight: 300; line-height: 1; margin: 0px; color: #4285f4;}";
html += "</style>";
html += "</head>";
html += "<body>";
html += "<h1 class=\"title\">NOMBRE DE VISITEUR</h1>";
html += "<div class=\"nombre_visite\">";
html += nombre_visite;
html += "</div>";
html += "</body>";
html += "</html>";
return html;
}
 |
|
| Légende |
Ce test permet de vérifier le fonctionnement du WiFi de l’ESP32. La page web affiche le nombre de visiteurs qui s’y sont connectés. |
Après, j'ai intégré cette page web au montage pour afficher les données en temps réel.
Voicimon code :mon code :
#include <WiFi.h>
#include <WebServer.h>
#include <DHT.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <PID_v1.h>
// Nom et mot de passe du Wifi
const char* ssid = "coh@bit";
const char* password = "lewifidecohabit";
WebServer server(80); // HTML correspond au port 80
#define brocheDeBranchementDHT 4 // Le DHT22 est branché sur le pin 4
#define typeDeDHT DHT22
DHT dht(brocheDeBranchementDHT, typeDeDHT);
float tauxHumidite = 0;
float tauxTemperature = 0;
float OutputRPM = 0;
int fanPin = 18; // Le ventilateur est branché sur le pin 18
LiquidCrystal_I2C lcd(0x27, 16, 2); // Le LCD peut afficher 16 caractères par ligne sur 2 lignes
// Définition du caractère "°" sur le LCD (tableau 5x8 en binaire)
byte Degres[] = {
B00111,
B00101,
B00111,
B00000,
B00000,
B00000,
B00000,
B00000
};
// Variables pour gestion du temps
unsigned long dernierMajDHT = 0; // dernier moment où le DHT a été lu
const unsigned long IntervalleDHT = 2000; // Intervalle de lecture DHT en millisecondes
unsigned long dernierMajPID = 0; // dernier moment où le PID a été lu
const unsigned long IntervallePID = 300; // Intervalle de lecture PID en millisecondes
// Variables PID
double Setpoint = 50; // Humidité ciblée
double Input;
double Output;
double Kp = 1.5; // Proportionnel
double Ki = 1; // Intégral
double Kd = 0.16; // Dérivé
PID pid(&Input, &Output, &Setpoint, Kp, Ki, Kd, REVERSE);
void setup() {
pinMode(fanPin, OUTPUT);
Wire.begin(21, 22); // SDA = 21, SCL = 22 (pins par défaut du LCD sur un ESP32)
lcd.init();
lcd.backlight();
lcd.createChar(0, Degres); // Création du caractère degrés
lcd.clear();
// Moniteur série
Serial.begin(921600);
dht.begin();
pid.SetMode(AUTOMATIC);
pid.SetOutputLimits(0, 255); // PMW correspond à une valeur entre 0 et 255
// Connexion au Wifi local
WiFi.begin(ssid, password);
// Verification de la connexion
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.print("IP de la carte : ");
Serial.println(WiFi.localIP());
// Message de communication client/serveur
server.on("/", connexion_Serveur);
server.on("/dataDHT", donnees_DHT);
server.on("/dataRPM", donnees_RPM);
server.on("/setHumidity", donnees_Set_Humidite);
server.onNotFound(echec_Connexion);
server.begin();
}
void loop() {
server.handleClient();
OutputRPM = (Output / 255.0) * 4500.0;
unsigned long millisActuels = millis();
// Lecture DHT toutes les 2 sec
if (millisActuels - dernierMajDHT >= IntervalleDHT) {
dernierMajDHT = millisActuels;
// Lecture des données
tauxHumidite = dht.readHumidity(); // Lecture du taux d'humidité (en %)
tauxTemperature = dht.readTemperature(); // Lecture de la température (en °C)
// Vérification des données
if (!isnan(tauxHumidite) && !isnan(tauxTemperature)) {
Input = tauxHumidite;
// Affichage sur le LCD
lcd.setCursor(3, 0);
lcd.print(tauxHumidite);
lcd.print(" %RH");
lcd.setCursor(4, 1);
lcd.print(tauxTemperature);
lcd.print(" ");
lcd.write(0);
lcd.print("C");
}
}
// Lecture PID toutes les 300 ms
if (millisActuels - dernierMajPID >= IntervallePID) {
dernierMajPID = millisActuels;
pid.Compute(); // Calcule PID
analogWrite(fanPin, (int)Output);
}
}
// Création page HTML
void connexion_Serveur() {
// Style du texte
String html = "<!DOCTYPE html><html>";
html += "<head><meta charset=\"UTF-8\">";
html += "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=yes\">";
html += "<style>";
html += "body {font-family: bauhaus 93, sans-serif; color: #000; text-align: center;}";
html += ".title {font-size: 30px; font-weight: bold; margin: 40px 0 30px;}";
html += ".temperature, .humidity, .vitesse {font-size: 40px; font-weight: 300; line-height: 1; margin-bottom: 20px;}";
html += ".temperature {color: #00b3ff;}";
html += ".humidity {color: #ff404d;}";
html += ".vitesse {color: #1eff1e;}";
html += ".unit {font-size: 20px; vertical-align: top;}";
// Style du slider et de la valeur
html += "#valeurHumidite {";
html += "font-size: 20px;";
html += "font-weight: bold;";
html += "margin-left: 10px;";
html += "color: #ff404d;";
html += "cursor: pointer;"; // valeur cliquable
html += "}";
html += "#sliderHumidite {";
html += "display: none;"; // Le slider est caché par défaut
html += "margin-top: 10px;";
html += "margin-left: 100px;";
html += "}";
html += "</style>";
html += "<script>";
// Température et humidité toutes les 2s
html += "setInterval(function(){";
html += "var xhttp = new XMLHttpRequest();";
html += "xhttp.onreadystatechange=function(){";
html += "if(this.readyState==4 && this.status==200){";
html += "document.getElementById('dht-container').innerHTML=this.responseText;";
html += "}};";
html += "xhttp.open('GET','/dataDHT',true);";
html += "xhttp.send();";
html += "},2000);";
// Vitesse ventilateur toutes les 300ms
html += "setInterval(function(){";
html += "var xhttp = new XMLHttpRequest();";
html += "xhttp.onreadystatechange=function(){";
html += "if(this.readyState==4 && this.status==200){";
html += "document.getElementById('rpm-container').innerHTML=this.responseText;";
html += "}};";
html += "xhttp.open('GET','/dataRPM',true);";
html += "xhttp.send();";
html += "},300);";
// Fonction pour mettre à jour l'humidité via le slider
html += "function updateHumidity() {";
html += "var humidity = document.getElementById('sliderHumidite').value;";
html += "document.getElementById('valeurHumidite').innerText = humidity + '%';"; // Mise à jour instantanée de l'affichage
html += "var xhttp = new XMLHttpRequest();";
html += "xhttp.open('GET', '/setHumidity?value=' + humidity, true);";
html += "xhttp.send();";
html += "}";
// Fonction pour basculer l'affichage du slider
html += "function toggleSlider() {";
html += "var slider = document.getElementById('sliderHumidite');";
html += "if (slider.style.display === 'none') {";
html += " slider.style.display = 'block';"; // Afficher le slider
html += "} else {";
html += " slider.style.display = 'none';"; // Cacher le slider
html += "}";
html += "}";
html += "</script>";
html += "</head><body>";
html += "<h1 class=\"title\">État de l'armoire</h1>";
html += "<div id='dht-container'></div>";
html += "<div id='rpm-container'></div>";
// Affichage de la valeur de l'humidité et du slider
html += "<div>";
html += "<label for='sliderHumidite'>Humidité cible: </label>";
html += "<span id='valeurHumidite' onclick='toggleSlider()'>" + String(Setpoint) + "%</span>";
html += "<input type='range' id='sliderHumidite' min='0' max='100' value='" + String(Setpoint) + "' oninput='updateHumidity()'>";
html += "</div>";
html += "</body></html>";
server.send(200, "text/html", html);
}
// Communication données DHT22 client/serveur
void donnees_DHT() {
String data = "<div class=\"temperature\">" + String(tauxTemperature, 1) + "<span class=\"unit\">°C</span></div>";
data += "<div class=\"humidity\">" + String(tauxHumidite, 1) + "<span class=\"unit\">%RH</span></div>";
server.send(200, "text/html", data);
}
// Communication données vitesse ventilateur client/serveur
void donnees_RPM() {
String data = "<div class=\"vitesse\">" + String(OutputRPM, 0) + "<span class=\"unit\">RPM</span></div>";
server.send(200, "text/html", data);
}
// Communication données humidité cible client/serveur
void donnees_Set_Humidite() {
if (server.hasArg("value")) {
Setpoint = server.arg("value").toDouble();
}
server.send(200, "text/plain", "Humidité cible mise à jour");
}
// Communication données page non trouvé client/serveur
void echec_Connexion() {
server.send(404, "text/plain", "Not found");
}
J’ai eu des difficultés pour mettre les valeurs à jour automatiquement sans avoir besoin d’actualiser la page.
Ajout d'un tachymètre¶
J'ai ajouté le tachymètre du ventilateur à mon code car, sur la page web, la vitesse indiquée est la vitesse théorique obtenue par un calcul. J'ai donc ajouté une ligne indiquant la valeur réelle de la vitesse de mon ventilateur.
Voicimon code :mon code :
#include <WiFi.h>
#include <WebServer.h>
#include <DHT.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <PID_v1.h>
// Nom et mot de passe du Wifi
const char* ssid = "coh@bit";
const char* password = "lewifidecohabit";
WebServer server(80); // HTML correspond au port 80
#define brocheDeBranchementDHT 4 // Le DHT22 est branché sur le pin 4
#define typeDeDHT DHT22
DHT dht(brocheDeBranchementDHT, typeDeDHT);
float tauxHumidite = 0;
float tauxTemperature = 0;
float OutputRPM = 0;
int fanPin = 18; // Le ventilateur est branché sur le pin 18
LiquidCrystal_I2C lcd(0x27, 16, 2); // Le LCD peut afficher 16 caractères par ligne sur 2 lignes
// Définition du caractère "°" sur le LCD (tableau 5x8 en binaire)
byte Degres[] = {
B00111,
B00101,
B00111,
B00000,
B00000,
B00000,
B00000,
B00000
};
// Variables pour gestion du temps
unsigned long dernierMajDHT = 0; // dernier moment où le DHT a été lu
const unsigned long IntervalleDHT = 2000; // Intervalle de lecture DHT en millisecondes
unsigned long dernierMajPID = 0; // dernier moment où le PID a été lu
const unsigned long IntervallePID = 300; // Intervalle de lecture PID en millisecondes
unsigned long dernierMajTach = 0; // dernier moment où le tachymètre a été lu
const unsigned long IntervalleTach = 300; // Intervalle de lecture tachymètre en millisecondes
// Variables PID
double Setpoint = 50; // Humidité ciblée
double Input;
double Output;
double Kp = 1.5; // Proportionnel
double Ki = 1; // Intégral
double Kd = 0.16; // Dérivé
PID pid(&Input, &Output, &Setpoint, Kp, Ki, Kd, REVERSE);
const int tachPin = 16; // Pin du tachymètre
volatile unsigned long compteImpulsionsTach = 0; // Compteur d'impulsions du tachymètre
double tachRPM = 0; // RPM mesuré par tachymètre
void IRAM_ATTR tachISR() {
compteImpulsionsTach++;
}
void setup() {
pinMode(fanPin, OUTPUT);
Wire.begin(21, 22); // SDA = 21, SCL = 22 (pins par défaut du LCD sur ESP32)
lcd.init();
lcd.backlight();
lcd.createChar(0, Degres); // Création du caractère degrés
lcd.clear();
// Moniteur série
Serial.begin(921600);
dht.begin();
pid.SetMode(AUTOMATIC);
pid.SetOutputLimits(0, 255); // PWM correspond à une valeur entre 0 et 255
// Connexion au Wifi local
WiFi.begin(ssid, password);
// Vérification de la connexion
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.print("IP de la carte : ");
Serial.println(WiFi.localIP());
// Message de communication client/serveur
server.on("/", connexion_Serveur);
server.on("/dataDHT", donnees_DHT);
server.on("/dataRPM", donnees_RPM);
server.on("/setHumidity", donnees_Set_Humidite);
server.onNotFound(echec_Connexion);
server.begin();
// Tachymètre
pinMode(tachPin, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(tachPin), tachISR, FALLING);
dernierMajTach = millis();
}
void loop() {
server.handleClient();
OutputRPM = (Output / 255.0) * 4500.0;
unsigned long millisActuels = millis();
// Lecture DHT toutes les 2 sec
if (millisActuels - dernierMajDHT >= IntervalleDHT) {
dernierMajDHT = millisActuels;
// Lecture des données
tauxHumidite = dht.readHumidity(); // Lecture du taux d'humidité (en %)
tauxTemperature = dht.readTemperature(); // Lecture de la température (en °C)
// Vérification des données
if (!isnan(tauxHumidite) && !isnan(tauxTemperature)) {
Input = tauxHumidite;
// Affichage sur le LCD
lcd.setCursor(3, 0);
lcd.print(tauxHumidite);
lcd.print(" %RH");
lcd.setCursor(4, 1);
lcd.print(tauxTemperature);
lcd.print(" ");
lcd.write(0);
lcd.print("C");
}
}
// Lecture PID toutes les 300 ms
if (millisActuels - dernierMajPID >= IntervallePID) {
dernierMajPID = millisActuels;
pid.Compute(); // Calcule PID
analogWrite(fanPin, (int)Output);
}
// Lecture Tachymètre toutes les 300 ms
if (millisActuels - dernierMajTach >= IntervalleTach) {
tachRPM = (compteImpulsionsTach * 60000UL) / (IntervalleTach * 2); // 2 implusions par révolution
compteImpulsionsTach = 0;
dernierMajTach = millisActuels;
}
}
// Création page HTML
void connexion_Serveur() {
// Style du texte
String html = "<!DOCTYPE html><html>";
html += "<head><meta charset=\"UTF-8\">";
html += "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=yes\">";
html += "<style>";
html += "body {font-family: bauhaus 93, sans-serif; color: #000; text-align: center;}";
html += ".title {font-size: 30px; font-weight: bold; margin: 40px 0 30px;}";
html += ".temperature, .humidity, .vitesse {font-size: 40px; font-weight: 300; line-height: 1; margin-bottom: 20px;}";
html += ".temperature {color: #00b3ff;}";
html += ".humidity {color: #ff404d;}";
html += ".vitesse {color: #1eff1e;}";
html += ".unit {font-size: 20px; vertical-align: top;}";
// Style du slider et de la valeur
html += "#valeurHumidite {";
html += "font-size: 20px;";
html += "font-weight: bold;";
html += "margin-left: 10px;";
html += "color: #ff404d;";
html += "cursor: pointer;"; // valeur cliquable
html += "}";
html += "#sliderHumidite {";
html += "display: none;"; // Le slider est caché par défaut
html += "margin-top: 10px;";
html += "margin-left: 100px;";
html += "}";
html += "</style>";
html += "<script>";
// Température et humidité toutes les 2s
html += "setInterval(function(){";
html += "var xhttp = new XMLHttpRequest();";
html += "xhttp.onreadystatechange=function(){";
html += "if(this.readyState==4 && this.status==200){";
html += "document.getElementById('dht-container').innerHTML=this.responseText;";
html += "}};";
html += "xhttp.open('GET','/dataDHT',true);";
html += "xhttp.send();";
html += "},2000);";
// Vitesse ventilateur toutes les 300ms
html += "setInterval(function(){";
html += "var xhttp = new XMLHttpRequest();";
html += "xhttp.onreadystatechange=function(){";
html += "if(this.readyState==4 && this.status==200){";
html += "document.getElementById('rpm-container').innerHTML=this.responseText;";
html += "}};";
html += "xhttp.open('GET','/dataRPM',true);";
html += "xhttp.send();";
html += "},300);";
// Fonction pour mettre à jour l'humidité via le slider
html += "function updateHumidity() {";
html += "var humidity = document.getElementById('sliderHumidite').value;";
html += "document.getElementById('valeurHumidite').innerText = humidity + '%';"; // Mise à jour instantanée de l'affichage
html += "var xhttp = new XMLHttpRequest();";
html += "xhttp.open('GET', '/setHumidity?value=' + humidity, true);";
html += "xhttp.send();";
html += "}";
// Fonction pour basculer l'affichage du slider
html += "function toggleSlider() {";
html += "var slider = document.getElementById('sliderHumidite');";
html += "if (slider.style.display === 'none') {";
html += " slider.style.display = 'block';"; // Afficher le slider
html += "} else {";
html += " slider.style.display = 'none';"; // Cacher le slider
html += "}";
html += "}";
html += "</script>";
html += "</head><body>";
html += "<h1 class=\"title\">État de l'armoire</h1>";
html += "<div id='dht-container'></div>";
html += "<div id='rpm-container'></div>";
// Affichage de la valeur de l'humidité et du slider
html += "<div>";
html += "<label for='sliderHumidite'>Humidité cible: </label>";
html += "<span id='valeurHumidite' onclick='toggleSlider()'>" + String(Setpoint) + "%</span>";
html += "<input type='range' id='sliderHumidite' min='0' max='100' value='" + String(Setpoint) + "' oninput='updateHumidity()'>";
html += "</div>";
html += "</body></html>";
server.send(200, "text/html", html);
}
// Communication données DHT22 client/serveur
void donnees_DHT() {
String data = "<div class=\"temperature\">" + String(tauxTemperature, 1) + "<span class=\"unit\">°C</span></div>";
data += "<div class=\"humidity\">" + String(tauxHumidite, 1) + "<span class=\"unit\">%RH</span></div>";
server.send(200, "text/html", data);
}
// Communication données vitesse ventilateur client/serveur
void donnees_RPM() {
String data = "<div class=\"vitesse\">" + String(tachRPM, 0) + "<span class=\"unit\">RPM</span></div>";
data += "<div style='font-size:16px;color:#000;'>Vitesse cible: <span style='font-size:20px;color:#1eff1e;'>" + String(OutputRPM,0) + " RPM</span></div>";
server.send(200, "text/html", data);
}
// Communication données humidité cible client/serveur
void donnees_Set_Humidite() {
if (server.hasArg("value")) {
Setpoint = server.arg("value").toDouble();
}
server.send(200, "text/plain", "Humidité cible mise à jour");
}
// Communication données page non trouvée client/serveur
void echec_Connexion() {
server.send(404, "text/plain", "Not found");
}
Mes difficultés sur ce code étaient :
- J'avais du mal à comprendre comment coder le tachymètre.
- J'ai inversé les noms des variables de la vitesse calculée et du tachymètre sur l'affichage sur la page web ce qui faisait que j'affichai deux fois la vitesse calculée au lieu d'afficher la vitesse réelle puis la vitesse calculée.
 |
 |
| Légende |
Ce montage présente un système basé sur un ESP32 permettant de mesurer la température et l’humidité avec un capteur DHT22 et d’afficher les valeurs sur un écran LCD. Le retour du tachymètre relié au pin 16 permet de mesurer précisément la vitesse réelle du ventilateur. L'ESP32 envoie les données sur une interface web qui affiche les valeurs de température, d’humidité et la vitesse du ventilateur en temps réel. De plus, elle permet aussi de modifier la consigne d’humidité via un slider en cliquant sur la valeur, puis de le masquer en recliquant dessus. |
Recherches de matériel pour l'armoire de séchage¶
Puis, j'ai effectué des recherches sur le materiel nécessaire pour l'armoire de séchage de filaments. Voici ce que j’ai trouvé :
Tension de 12V
Vitesse de rotation de 1500 tr/min
Dimension de 150mmx50mm
Puissance de 30W
Git¶
J'ai appris à me servir de Git. J'ai ensuite mis les fichiers du projet sur le Git du Fablab. Voir ce lien.
J'ai eu des difficultés pour apprendre à me servir de Git et pour créer le README car il faut l'écrire en langage Markdown.
Cadeau impression 3D¶
J'ai fait une impression 3D pour un cadeau de la fête des mères. J'ai fait le mot "I love You" avec un modèle trouvé " sur internet.
 |
Voici le lien que j'ai trouvé sur internet |
| Légende |
J'ai utilisé Orcaslicer pour le configurer et le rendre prêt à l'impression avec les paramètres suivants : Filament : PLA Machine : Prusa Core One Hauteur de couche : 0.2mm Temps d'impression : 1h 35min Tranchage : Orca Slicer |
Création 3D de l'armoire à filaments¶
J’ai commencé à modéliser l’armoire à filaments en 3D sur FreeCAD. Pour cela, j’ai d’abord pris le temps d’apprendre à utiliser le logiciel. Ensuite, je suis parti d’un cube pour créer la structure de l’armoire.
De plus j'ai commencé à utiliser la fonction paramétrique pour pouvoir modifier les tailles en changeant uniquement les variables. Cela pemet de gagner beaucoup de temps.
J’ai aussi modélisé les bobines de différentes couleurs ainsi que les portes vitrées.
 |
Lien vers le fichier |
| Légende |
Ce modèle 3D que j'ai réalisé sur FreeCAD représente une armoire de stockage pour bobines de filament. Les bobines sont disposées sur des barres de support à l’intérieur de plusieurs parties, et l’ensemble est fermé par des vitres transparentes équipées de poignées modélisées. |
J’ai également créé les charnières des portes.
J’ai rencontré quelques difficultés, notamment pour réaliser des charnières aux bonnes dimensions. Au début, j’avais fait une charnière très petite. Quand j’ai voulu l’agrandir avec l’outil « Mettre à l’échelle », toute la charnière s’est retrouvée déformée. J’ai donc dû la recommencer en définissant les bonnes dimensions dès le départ.
 |
Lien vers le fichier |
| Légende |
J’ai conçu ce modèle 3D sur FreeCAD afin de réaliser une charnière destinée à fixer les vitres de l’armoire. Elle permet d’assurer l’ouverture et la fermeture des vitres tout en maintenant leur alignement sur la structure. |
À un moment, j’ai accidentellement supprimé le fichier 3D de l’armoire. Heureusement, j’ai pu le récupérer grâce à une application de récupération de fichiers.
Ensuite, j’ai modélisé les équerres de maintien de l’armoire pour compléter le projet.
 |
 |
Lien vers le fichier FreeCAD |
| Légende |
J'ai imprimé une équerre en 3D à l'aide d'Orcaslicer pour le configurer avec les paramètres suivants : Filament : PLA Machine : Bambu Lab P1S Hauteur de couche : 0.2mm Temps d'impression : 43min 56s Tranchage : Orca Slicer J'ai ensuite réalisé un test sur l’équerre imprimée en 3D pour évaluer son comportement sous contrainte. Cette vérification permet de s’assurer que la pièce est suffisamment robuste pour son utilisation dans l’armoire. |
Lien vers le fichier export STEP |
J’ai aussi modélisé les composants électroniques et leurs boîtiers. J’ai trouvé sur Internet les fichiers 3D de l’ESP32, du DHT22 et de l’écran LCD, ainsi que les boîtiers de l’ESP32 et du DHT22, mais pas celui du LCD. J’ai donc créé moi-même un boîtier pour le LCD. J’ai essayé plusieurs tests jusqu’à trouver la bonne solution. Le plus difficile était de respecter les contraintes liées aux dimensions du LCD, tout en concevant un boîtier pouvant s’ouvrir et se fermer.
 |
 |
 |
 |
 |
| Modèle d'ESP32 avec boîtier trouvé sur internet |
Modèle de ventilateur trouvé sur internet |
J'ai conçu moi même le boîtier sur FreeCAD. Le modèle du LCD a été trouvé sur internet |
Modèle de DHT22 trouvé sur internet |
Modèle d'alimentation trouvé sur internet |
Placement des composants électroniques dans l’armoire 3D¶
J’ai ensuite commencé le placement des composants électroniques dans l’armoire sur FreeCAD :
- J’ai placé deux ventilateurs sur les côtés de l’armoire : un en haut à gauche et un en bas à droite.
 |
|
| Légende |
Ce système de ventilation est conçu pour favoriser l’évacuation de l’air humide à l’intérieur de l’armoire afin de protéger les bobines de filament. Les ventilateurs de 92 × 92 × 25 mm sont placés de manière à créer un flux d’air efficace dans l’ensemble du volume. |
L’idée est de créer un flux d’air en diagonale dans l’armoire, afin de mieux répartir la température et d’éviter les zones où l’air stagne.
- J’ai installé le DHT22 sur un support au centre de la paroi arrière.
 |
|
| Légende |
Le capteur DHT22 est fixé sur la paroi arrière afin d’obtenir des mesures représentatives de l’air de l’armoire. Un placement trop proche des ventilateurs peut fausser les valeurs à cause du flux d’air direct, tandis qu’un placement trop éloigné peut rendre les mesures moins représentatives. |
Je l’ai positionné à cet endroit pour obtenir des mesures plus représentatives, sans être trop influencé par le ventilateur ou une source de chaleur directe.
- Le LCD a été posé sur un support au-dessus de l’armoire.
 |
|
| Légende |
J’ai conçu ce support sur FreeCAD afin de fixer l’écran LCD sur la partie supérieure de l’armoire. Cette disposition permet d’obtenir une bonne visibilité des informations affichées tout en facilitant la consultation des mesures sans intervenir sur le système. |
Ça permet de lire rapidement les valeurs sans avoir à ouvrir ou manipuler le système, ce qui est plus pratique au quotidien.
- L’ESP32 a été placé en bas à l’avant de la planche gauche.
 |
|
| Légende |
J’ai conçu un support afin d’intégrer l’ESP32 à l’intérieur de l’armoire de stockage. Son positionnement en partie basse permet de simplifier le passage des câbles tout en conservant un accès facile à la carte pour sa programmation. |
Cet emplacement facilite le câblage et l’accès pour la programmation, tout en gardant une installation plus propre et organisée.
- J’ai ensuite ajouté une alimentation 12V à l’arrière de l’armoire, fixée sur la paroi.
 |
|
| Légende |
Cette alimentation 12V a été installée sur la paroi arrière de l’armoire afin d’alimenter les ventilateurs du système. Son emplacement permet de limiter l’encombrement à l’intérieur de l’armoire tout en restant discret pour ne pas gêner l’organisation des autres composants. |
Elle sert à alimenter les ventilateurs de l’armoire, tout en restant placée à l’arrière pour ne pas gêner l’organisation des autres composants.
h4.Création du Template de l'atelier TechDraw.
J'ai créé un template personnalisé pour l'atelier TechDraw de FreeCAD. J'ai configuré le format de la feuille, réalisé le cartouche et ajusté les paramètres de mise en page pour obtenir un modèle réutilisable et homogène pour les futurs plans techniques. Voici le fichier du Template : A3_LandscapeTD_Fablab_fr.svg