Projet PEEP-River
Contexte :
Dans le cadre de l'UE FabLab, nous travaillons à réaliser un projet avec la chercheuse Pauline Delorme sur l'étude de l'érosion de berges de rivière
Problématique :
Objectifs :
L’objectif de ce projet est de fabriquer un capteur PEEP capable de quantifier l’érosion des berges des rivières au cours du temps
Les tâches et étapes :
- Lire la bibliographie
- Concevoir le montage électronique
- Penser l'enveloppe 3D
- Réaliser des tests (imperméabilité, seuil de luminosité détecté)
Répartition du travail :

Remplissage du Wiki, expérience (fixation des valeurs seuil de la LDR), Codage

Remplissage du wiki, expérience (fixation des valeurs seuil de la LDR), prototype de conception barrette 3D, Montage électronique, schéma tinkercad
Réflexions de départ sur les différents montages que l'on imagine :
PR = photo résistance

Montage 1 : Gérer le moniteur - Lecture d’intensité
Matériel : Une PR + une résistance reliée à Arduino (utilisation du serial monitor)
But : Mesure d’intensité de la lumière :
Intensité d'entrée 1 = forte - Intensité d'entrée 2 = moins forte
Résultat : Selon l'intensité lumineuse 1 ou 2 il y a une mesure du voltage (V out) par Arduino différente et avec le Serial Monitor on obtient une valeur d’intensité de sortie différente.

Montage 2 : Compteur intelligent
Matériel : 2 PR (+résistances) en parallèles reliées à Arduino + une diode
But : Création d'un montage plus complexe avec plusieurs photo résistances pour mimer l'effet de l'érosion. On souhaite montrer que si la PR 2 reçoit de la lumière et pas la PR 1 la donnée n'est pas fiable
Si diode s’allume = donnée reçue
Attentes :
- Si lumière sur PR 2 = diode ne s'allume pas
- Si lumière sur PR 1 = diode s’allume
- Si lumière sur PR 2 et Photo résistance 1 = diode s’allume

Montage 3 : Mesure de référence de l’intensité ambiante
Matériel : 2 PR (+résistances) en parallèles reliées à Arduino + une diode + une PR de ref
-> Ajout de la PR de ref qui est la mesure de luminosité ambiante de référence sous l’eau.
But : Elle permet de fixer une valeur seuil qui définit la luminosité sous l’eau pour pouvoir analyser les données par la suite :
- permet de savoir si c’est la nuit ou le jour
- permet de savoir que faible luminosité est due à une mauvaise météo
Séance 1 (30 Janv) :

Compréhension approfondie du projet avec notre responsable de projet et découverte de ARDUINO et premier montage.
La photorésistance (LDR) fonctionne en diminuant sa résistance électrique proportionnellement à l'intensité lumineuse qu'elle reçoit : + de lumière - de résistance = plus le courant circule // - de lumière = = de résistance = courant limité.
1er montage avec une PR LDR
Montage électronique basé sur une carte ARDUINO, intégrant une photorésistance (LDR) et une photodiode. L’objectif est que la photodiode s’allume lorsque la main est placée sur la LDR.


Lors de notre premier essai, nous avions défini un seuil de détection trop bas dans le code Arduino, ce qui faisait que la photodiode restait constamment allumée, même sans occultation.
Nous avons corrigé cela en augmentant ce seuil. Cet ajustement pose désormais une question clé pour l'optimisation de notre capteur PEEP : Quel seuil optimal définir pour les photorésistances de notre capteur afin d'assurer une bonne détection de la lumière dans l'eau ?
Quel seuil optimal définir pour les photorésistances de notre capteur afin d'assurer une bonne détection de la lumière dans l'eau ?
Séance 2 (6 Fev) :


- Séance lecteur intelligent : nous nous sommes lors de cette séance familiarisé avec le Serial Monitor.
- Expérience : lire les données de notre LDR.
Détails de l'expérience
Arduino uno : 0V => 0 CAN ; 5V => 1023 CAN Montage :
Utilisation du Serial Monitor pour lire les données de la LDR.
Pour avoir les valeurs lu par analogRead() il faut ouvrir le Serial Monitor
Séance 3 (13 Fev) :
Les LDRs sont branchés en analog in (A0,A1,...) : LDR donne une tension variable entre 0 et 5V. Les broches analogiques lisent ces tensions avec analogRead() et renvoient une valeur de 0 à 1023.
Les broches digitales ne lient que HIGH (1) ou LOW (0) : on branche les diodes dessus
Matériel utilisé
- Une carte Arduino.
- Deux LED (diodes lumineuses) : LED 1 et LED 2.
- Deux photorésistances (LDR) : LDR 1 et LDR 2.
- Des résistances pour les LDR et les LED (100 Ω ).


- Première expérience : Nous avons essayé de programmer le montage pour que la LED 1 s’allume quand on cache la LDR 1, et que la LED 2 s’allume uniquement quand on cache en même temps la LDR 1 et la LDR 2.
Détails de l'expérience 1
Objectif du programme au départ
Au début, nous voulions créer un comportement « combiné » avec les deux LDR :
- Quand on cache seulement la LDR 1, la LED 1 doit s’allumer.
- Quand on cache la LDR 1 ET la LDR 2 en même temps (main sur les deux), c’est la LED 2 qui doit s’allumer.
- Quand on cache seulement la LDR 2 sans cacher la LDR1, les diodes ne s'allument pas.
Autrement dit, la LED 2 devait dépendre d’une condition plus complexe, utilisant les deux capteurs ensemble (une sorte de « si LDR1 est cachée ET LDR2 est cachée alors allumer LED2 »).
Problèmes rencontrés
Nous n’avons pas réussi à faire fonctionner cette logique comme prévu.
Les difficultés venaient probablement de :
- La condition combinée avec les deux LDR en même temps.
- La structure des conditions dans le code (ordre des if, else if, etc.).
Nous n'avons pas réussis la 1ère expérience, on l'a donc simplifié
- Deuxième expérience : Nous avons simplifié le programme pour que, quand on cache la LDR 1, la LED 1 s’allume, et quand on cache la LDR 2, la LED 2 s’allume.
Détails de l'expérience 2
Modification du programme :
Vous avez choisi une logique beaucoup plus simple et directe :
- Quand on cache la LDR 1, la LED 1 s’allume.
- Quand on cache la LDR 2, la LED 2 s’allume.
Chaque photorésistance contrôle donc maintenant « sa » LED, indépendamment de l’autre capteur.
C
ode :



Montage :




![]()
![]()
Nous n'avons pas réussis à faire marcher notre 2ème expérience.
Séance 4 (20 Fev) :
Résistances en fonction de la couleur des diodes : Vert = 10 kΩ ; Rouge = 1kΩ ; Bleu = 220 Ω
Objectif du montage 1 : Ajouter un transistor NPN au circuit avec une seule LDR et une seule LED
Détail de l'expérience 1

"Pour résoudre le problème de la séance précédente : la deuxième LED ne s'allume pas, nous avons ajouté au circuit un transistor NPN

Base (3): Borne de commande du transistor
Collectionneur (2): Terminal où le courant entre
Émetteur (1): Terminal où sort le courant
Circuit réalisé :
Lorsque la lumière éclaire la LDR, sa résistance chute, ce qui fait monter la tension au point VX selon le principe du diviseur de tension. Dès que cette tension atteint un seuil d'environ 0,6 V, il y a détection de lumière à la LDR 1 et un courant rentre dans la base du transistor NPN pour le rendre "passant". Le transistor agit alors comme un interrupteur fermé qui laisse circuler le courant du collecteur vers l'émetteur, ce qui allume la diode.

Code :
Montage :




Objectif du montage 2 : Réaliser le montage de comportement « combiné » avec deux LDR, deux LED et deux transistors.
Séance 5 (27 Fev) :
Objectif du début de séance : Refaire pas à pas le montage 2 de la séance dernière pour le réussir.
Etape 1 : on a refait l'expérience 1 de la semaine dernière
Etape 2 : On duplique le circuit en ajoutant une deuxième LED et sa résistance, une deuxième LDR et sa résistance, un second transistor. Pour vérifier que tout marche bien on fait blink les deux LED.
Il faut deux transistors dans le circuit.
Détails de l'expérience 2

Code :


Montage :


Etape 3 : On code sur Arduino de façon à faire le montage de comportement « combiné » des deux LDR avec deux transistors.
Détail de l'expérience 3

Nouvel objectif : (EXP 3) Se rapprocher du but final de montage dans le tube
= enlever les LED et transistors et prendre les informations de la LDR directement.
Détail de l'expérience 4


Séance 6 (13 Mars) :
Il faut des résistances de 10Ω avec les transistors
Problématique : Le nombre de capteurs LDRs dépasse le nombre d'entrées analogiques disponibles sur le microcontrôleur. Pour lire individuellement chaque capteur sans multiplier les câbles et les entrées, nous avons mis en place une stratégie de lecture alternée.
Nous avons structuré les capteurs en deux groupes distincts, sur deux bordes différentes. Chaque broche analogique de l'Arduino est reliée à deux LDRs (la LDR A du groupe 1 et la LDR A du groupe 2).
Pour éviter que les deux capteurs n'envoient leur signal simultanément sur la même broche, l'alimentation est envoyée sélectivement. Le but étant pour cela d’utiliser les transistors en tant que interrupteur. Pour visualiser l'expérience nous avons ajouté des LEDs.
Détail de l'expérience


Séance 7 (20 Mars) :
1. Horodatage des données (RTC)
L'objectif est de passer d'une simple lecture de valeurs à un suivi environnemental exploitable. L'ajout d'une horloge RTC permet désormais d'associer chaque mesure d'érosion à une date et une heure précises.
-
Contrainte technique : Le module RTC utilise le protocole de communication I2C, ce qui mobilise impérativement les broches A4 (SDA) et A5 (SCL) de l'Arduino.
-
Impact sur le design : Ces broches ne sont plus disponibles pour la lecture analogique des LDR, ce qui confirme l'importance de notre stratégie de multiplexage sur les autres broches analogiques restantes.
2. Correction Transistors
Lors des tests précédents, les transistors ne jouaient pas leur rôle d'interrupteurs électroniques.
Le circuit a été revu pour s'assurer que le courant passe vraiment dans transistors. Ils servent désormais de verrous pour n'alimenter qu'une seule "borde" à la fois.
3. Nouvelle architecture des bordes
Le système est désormais segmenté en trois unités fonctionnelles :
-
Borde de Référence : Regroupe les éléments centraux (Module RTC, LDR de référence pour calibrer la luminosité ambiante, transistor)
-
Borde 1 & 2 : Unités de mesure déportées comprenant chacune une LDR de mesure, sa résistance et son transistor de pilotage.
Détail de l'expérience


Code utilisé

Explication du code :

LDR de référence (A0) : sert à détecter si on est en condition « jour » ou « nuit »
Module RTC DS1307 : connexions I2C (SDA, SCL)
La valeur du seuil : est choisi en fonction de nos observations.
Seuil 1 : est ici un placeholder qui simule, dans cette version initiale, le seuil dynamique qui sera issu de la LDR de référence dans la version aboutie du programme.
const int ldr1 = A1;
const int ldr2 = A2;
const int plaque1 = 2;
const int plaque2 = 3;
const int plaqueref = 4;
const int ldrREF = A0;
const int seuil1 = 300;
const int seuil = 300;
#include <Wire.h>
#include <I2C_RTC.h>
static DS1307 RTC;
void setup() {
Serial.begin(115200);
// vérification au démarrage (une seule fois)
while (!Serial); // Empêche le programme de commencer si le matériel est mal connecté dès le départ
RTC.begin();
Serial.println();
// --- Boucle tant que la RTC n'est PAS détectée ---
while (!RTC.isConnected())
{
Serial.println("⚠️ RTC non détectée — vérifiez les connexions !");
delay(1000);
}
// --------------------------------------------------
Serial.println("✅ RTC détectée !");
RTC.startClock();
// --- RÉGLAGE DE L’HEURE (UNE SEULE FOIS) ---
// RTC.setDateTime(__DATE__, __TIME__);
// -------------------------------------------
// --- CONFIGURATION DES CAPTEURS ---
pinMode(ldr1, INPUT);
pinMode(ldr2, INPUT);
pinMode (ldrREF,INPUT);
// --- CONFIGURATION DES SORTIES (mettre au cas ou même si pas necessaire normalement)
pinMode(plaque1,OUTPUT);
pinMode(plaque2, OUTPUT);
pinMode(plaqueref, OUTPUT);
// --- ÉTAT INITIAL ---
digitalWrite(plaque1, LOW);
digitalWrite(plaque2, LOW);
digitalWrite(plaqueref, HIGH);
}
void loop() {
// --- Boucle tant que la RTC EST détectée ---
if (RTC.isConnected()){
Serial.print(RTC.getDateTimeString());
Serial.print(", Unix Time: ");
Serial.println(RTC.getEpoch());
delay(10000);
}
// Si on sort de la boucle, c’est que la RTC a été débranchée
else {
Serial.println("⚠️ RTC déconnectée !");
delay(10000);
}
// CODE POUR LA LDR DE REF
if (RTC.isConnected()){
int valeurREF = analogRead(ldrREF);
if (valeurREF < seuil){
Serial.print("NUIT");
Serial.print("A0= ");
Serial.println(valeurREF);
}
else{
digitalWrite(plaque1, HIGH);
Serial.print("JOUR");
Serial.print("A1= ");
Serial.println(valeurREF);
int valeur1 = analogRead(ldr1);
if (valeur1 < seuil1){
Serial.print("ldr 1 caché");
Serial.print("A1= ");
Serial.println(valeur1);
}
else {
Serial.print("ldr 1 ON ");
Serial.print("A1= ");
Serial.println(valeur1);
digitalWrite(plaque1, LOW);
digitalWrite(plaque2, HIGH);
int valeur2 = analogRead(ldr2);
Serial.print("A2= ");
Serial.println(valeur2);
digitalWrite(plaque2, LOW);
}
delay(5000);
}
}
}
Séance 8 (27 Mars) :
1. Test de validation du prototype existant
La séance a débuté par un test de confirmation sur le montage de la semaine précédente (RTC + 2 Bordes + Transistors).
2. Évolution du Code
Explication du code
Utilisation de switch/case :
Plutôt qu'une succession de IF imbriqués, le code repose sur une machine à états finis. Six états sont définis dans un enum :
· Verif_RTC : vérification de la RTC et lecture de la LDR de référence
· NUIT : état passif, on relit simplement la LDR de référence
· Test_Bord_1 : test du premier bord avec LDR 1
· Test_Bord_2 : test du second bord avec LDR 2
· Erreur_FATALE : sécurité en cas de perte prolongée de la RTC
· Default : filet de sécurité si l'état devient incohérent
On change d’état via etatActuel.
La sécurité :
- Compteur d’erreurs RTC : A chaque déconnexion, on ajoute 1 à la variable erreursRTC. Lorsqu’on atteint 10 erreurs soit le MAX_ERREURS = 10, le système bascule en Erreur_FATALE. = On force l’extinction des plaques pour pas vider la batterie.
- Récupération automatique : si la RTC revient en ligne pendant l'état Erreur_FATALE, le compteur est remis à zéro et le système redémarre normalement.
- État default : si on obtiens une valeur incohérente dans la variable d'état, on retourne automatiquement à Verif_RTC après avoir coupé les plaques.
Le code
Nous avons mal utilisez le switch/case en modifiant la variable etat Actuel directement dans nos cases, nous restions donc bloqué dans le 1er case
#include <Wire.h> // Appel du protocole de communication
// Appel de la bibliothèque RTC
#include <I2C_RTC.h>
static DS1307 RTC; // déclaration du modèle de RTC
// --- Variables de Pins ---
const int ldr1 = A1;
const int ldr2 = A0;
const int plaque1 = 2;
const int plaque2 = 3;
const int plaqueref = 4;
const int ldrREF = A2;
const int seuil1 = 300;
const int seuil = 300;
int rythme = 30000;
enum {"Verif_RTC", "NUIT", "Test_Bord_1", "Test_Bord_2", "Test_LDR_REF", "Erreur_FATALE" } etatActuel = "Verif_RTC";
int erreursRTC = 0; // Compteur de déconnexions
const int MAX_ERREURS = 10; // Seuil avant blocage de sécurité
void setup() {
Serial.begin(115200);
// vérification au démarrage (une seule fois)
while (!Serial); // Empêche le programme de commencer si le matériel est mal connecté dès le départ
RTC.begin();
Serial.println();
// --- Boucle tant que la RTC n'est PAS détectée ---
while (!RTC.isConnected())
{
Serial.println("⚠️ RTC non détectée — vérifiez les connexions !");
delay(rythme);
}
// --------------------------------------------------
Serial.println("✅ RTC détectée !");
RTC.startClock();
// --- RÉGLAGE DE L’HEURE (UNE SEULE FOIS) ---
// RTC.setDateTime(__DATE__, __TIME__);
// -------------------------------------------
// --- CONFIGURATION DES CAPTEURS ---
pinMode(ldr1, INPUT);
pinMode(ldr2, INPUT);
pinMode(ldrREF,INPUT);
// --- CONFIGURATION DES SORTIES (mettre au cas ou même si pas necessaire normalement)
pinMode(plaque1,OUTPUT);
pinMode(plaque2, OUTPUT);
pinMode(plaqueref, OUTPUT);
// --- ÉTAT INITIAL ---
digitalWrite(plaque1, LOW);
digitalWrite(plaque2, LOW);
digitalWrite(plaqueref, HIGH);
}
void loop() {
switch (etatActuel){
case "Verif_RTC" :
// verification de la RTC
if (RTC.isConnected()){
Serial.println(RTC.getDateTimeString()); //lecture du temps de manière lisible : String
//Serial.print (",Unix Time: ");
//Serial.println (RTC.getEpoch()); // lecture pour la machine : Unix Timestamp
// vérification de la LDR de réference
int valeurREF = analogRead(ldrREF);
if (valeurREF < seuil){
etatActuel = NUIT;
Serial.print("NUIT");
Serial.println(valeurREF);
} else{
etatActuel = Test_Bord_1;
Serial.print("JOUR");
Serial.println(valeurREF);
}
} else {
erreursRTC++; // On incrémente le compteur d'erreur
Serial.print("⚠️ RTC absente ! Tentative : ");
Serial.println(erreursRTC);
if (erreursRTC >= MAX_ERREURS) {
etatActuel = Erreur_FATALE; // On coupe tout !
}
delay(rythme);
}
break; //important pour pas glisser dans l'action suivante sans vérifer celle la
case NUIT :
Serial.print ("NUIT | A2= ");
int valeurREF = analogRead(ldrREF);
Serial.println(valeurREF); // ou Serial.println(analogRead(ldrREF)); ?
etatActuel = Verif_RTC; // on revérifie la RTC et LDR REF
delay(rythme);
break ;
case Test_Bord_1 :
digitalWrite(plaque1, HIGH);
int valeur1 = analogRead(ldr1);
if (valeur1 < seuil1){
Serial.print("LDR 1 caché | A1= ");
Serial.println(valeur1);
etatActuel = Verif_RTC; // vérification de la RTC et de la LDR REF
} else {
Serial.print("LDR 1 ON | A1= ");
Serial.println(valeur1);
digitalWrite(plaque1, LOW);
etatActuel = Test_Bord_2;
// on test la bord 2 après avoir éteintla bord 1 car lumière
}
break;
case Test_Bord_2 :
digitalWrite(plaque2, HIGH);
int valeur2 = analogRead(ldr2);
if (valeur2 < seuil1){
Serial.print("LDR 2 caché | A0= ");
Serial.println(valeur2);
etatActuel = Verif_RTC; // vérification de la RTC et de la LDR REF
} else {
Serial.print("LDR 2 ON | A0= ");
Serial.println(valeur2);
// fin du cycle , on étaint et on recommence
digitalWrite(plaque2, LOW);
etatActuel = Verif_RTC; // on test la bord 2 après avoir éteintla bord 1 car lumière
delay(rythme);
break;
case Erreur_FATALE :
// Boucle de sécurité = on force extinction des plaques
digitalWrite(plaque1, LOW);
digitalWrite(plaque2, LOW);
Serial.println("❌ ERREUR CRITIQUE : RTC perdue. Système stoppé.");
// On vérifie quand même si la RTC revient toutes les 10 secondes
if (RTC.isConnected()) {
Serial.println("✅ RTC retrouvée ! Redémarrage...");
erreursRTC = 0;
etatActuel = Verif_RTC;
}
delay (rythme);
break;
default :
// je ne sais pas ce qui ce passe donc je recommence
// SI ON ARRIVE ICI, C'EST QUE L'ÉTAT EST INCONNU OU INCOHÉRENT
Serial.println("⚠️ État inconnu ! Retour à la sécurité.");
digitalWrite(plaque1, LOW);
digitalWrite(plaque2, LOW);
etatActuel = Verif_RTC; // On réinitialise pour débloquer
break;
}
}
}
Le code ne marche pas
=> Nous en avons déduit qu'il n'était pas possible de changer la variable etatActuel n'était pas modifiabledirectement dans les cases, car nous restons bloqués dans le 1er case.
Les erreurs du code et les corrections
|
#
|
Problème
|
Conséquence
|
|
1
|
Guillemets dans l'enum : enum {"Verif_RTC", "NUIT", ...}
|
Les états deviennent des chaînes de caractères au lieu d'identifiants → ne compile pas
|
|
2
|
Guillemets dans les cases : case "Verif_RTC" :
|
Le switch ne peut pas comparer des chaînes → transitions impossibles
|
|
3
|
Variables déclarées sans { } dans les case
|
Erreur de compilation "crosses initialization"
|
|
4
|
Accolade } manquante dans le else de Test_Bord_2
|
Les cas suivants (Erreur_FATALE, default) deviennent imbriqués et invisibles pour le switch
|
|
5
|
Accolade } en trop à la fin du fichier
|
Structure du programme cassée
|
|
6
|
enum incohérent : contient Test_LDR_REF (inutilisé) mais pas Erreur_FATALE (utilisé)
|
Le compilateur ne reconnaît pas Erreur_FATALE
|
|
7
|
Variable valeurREF redéclarée dans plusieurs cases sans isolation
|
Conflit de noms
|
Code corriger ! MAIS PAS TESTE
#include <Wire.h> // Protocole de communication I2C
#include <I2C_RTC.h> // Bibliothèque RTC
static DS1307 RTC; // Déclaration du modèle de RTC
// --- Variables de Pins ---
const int ldr1 = A1;
const int ldr2 = A0;
const int plaque1 = 2;
const int plaque2 = 3;
const int plaqueref = 4;
const int ldrREF = A2;
// --- Seuils ---
const int seuil = 300; // Seuil jour/nuit pour la LDR de référence
const int seuil1 = 300; // Seuil pour les LDR de bord (à terme dérivé de ldrREF)
int rythme = 30000; // 30 secondes
enum Etat {
Verif_RTC,
NUIT,
Test_Bord_1,
Test_Bord_2,
Erreur_FATALE
};
Etat etatActuel = Verif_RTC;
// --- Gestion de la sécurité ---
int erreursRTC = 0;
const int MAX_ERREURS = 10;
void setup() {
Serial.begin(115200);
while (!Serial); // Attend que la liaison série soit prête
RTC.begin();
Serial.println();
// Boucle tant que la RTC n'est PAS détectée
while (!RTC.isConnected()) {
Serial.println("⚠️ RTC non détectée — vérifiez les connexions !");
delay(rythme);
}
Serial.println("✅ RTC détectée !");
RTC.startClock();
// --- RÉGLAGE DE L'HEURE (UNE SEULE FOIS) ---
// RTC.setDateTime(__DATE__, __TIME__);
// -------------------------------------------
// --- Configuration des entrées ---
pinMode(ldr1, INPUT);
pinMode(ldr2, INPUT);
pinMode(ldrREF, INPUT);
// --- Configuration des sorties ---
pinMode(plaque1, OUTPUT);
pinMode(plaque2, OUTPUT);
pinMode(plaqueref, OUTPUT);
// --- État initial ---
digitalWrite(plaque1, LOW);
digitalWrite(plaque2, LOW);
digitalWrite(plaqueref, HIGH);
}
void loop() {
switch (etatActuel) {
// ============================================================
case Verif_RTC : {
if (RTC.isConnected()) {
Serial.println(RTC.getDateTimeString());
// Serial.print(",Unix Time: ");
// Serial.println(RTC.getEpoch());
// Vérification de la LDR de référence
int valeurREF = analogRead(ldrREF);
if (valeurREF < seuil) {
etatActuel = NUIT;
Serial.print("NUIT | A2= ");
Serial.println(valeurREF);
} else {
etatActuel = Test_Bord_1;
Serial.print("JOUR | A2= ");
Serial.println(valeurREF);
}
} else {
erreursRTC++;
Serial.print("⚠️ RTC absente ! Tentative : ");
Serial.println(erreursRTC);
if (erreursRTC >= MAX_ERREURS) {
etatActuel = Erreur_FATALE;
}
delay(rythme);
}
} break;
// ============================================================
case NUIT : {
int valeurREF = analogRead(ldrREF);
Serial.print("NUIT | A2= ");
Serial.println(valeurREF);
etatActuel = Verif_RTC; // On revérifie la RTC et la LDR REF
delay(rythme);
} break;
// ============================================================
case Test_Bord_1 : {
digitalWrite(plaque1, HIGH);
int valeur1 = analogRead(ldr1);
if (valeur1 < seuil1) {
Serial.print("LDR 1 caché | A1= ");
Serial.println(valeur1);
etatActuel = Verif_RTC;
} else {
Serial.print("LDR 1 ON | A1= ");
Serial.println(valeur1);
digitalWrite(plaque1, LOW); // On éteint avant de passer à l'autre bord
etatActuel = Test_Bord_2;
}
} break;
// ============================================================
case Test_Bord_2 : {
digitalWrite(plaque2, HIGH);
int valeur2 = analogRead(ldr2);
if (valeur2 < seuil1) {
Serial.print("LDR 2 caché | A0= ");
Serial.println(valeur2);
etatActuel = Verif_RTC;
} else {
Serial.print("LDR 2 ON | A0= ");
Serial.println(valeur2);
digitalWrite(plaque2, LOW); // Fin de cycle, on éteint
etatActuel = Verif_RTC;
}
delay(rythme);
} break;
// ============================================================
case Erreur_FATALE : {
// Sécurité : on force l'extinction des plaques
digitalWrite(plaque1, LOW);
digitalWrite(plaque2, LOW);
Serial.println("❌ ERREUR CRITIQUE : RTC perdue. Système stoppé.");
// On vérifie si la RTC revient
if (RTC.isConnected()) {
Serial.println("✅ RTC retrouvée ! Redémarrage...");
erreursRTC = 0;
etatActuel = Verif_RTC;
}
delay(rythme);
} break;
// ============================================================
default : {
// Si on arrive ici, c'est que l'état est inconnu
Serial.println("⚠️ État inconnu ! Retour à la sécurité.");
digitalWrite(plaque1, LOW);
digitalWrite(plaque2, LOW);
etatActuel = Verif_RTC;
} break;
}
}

3. Début de la conception mécanique : La barrette de support
Nous avons lancé la création du support physique qui sera glissé dans le tube en acrylique.
Outil : OpenSCAD (conception 3D par programmation)
Objectif : Créer une "barrette" rigide permettant de placer le montage électronique gravé afin de le faire coulisser dans le tube et le récupérer facilement.
Contraintes de design : La barrette doit épouser la forme courbe du tube (diamètre interne). Il faut prévoir des passages pour le câblage en dessous et créer des barrières opaques entre les LDR pour éviter qu’une lumière entrante ne fausse les détection de lumières des LDR qui sont encore dans le substrats.
1er prototype




Séance 9 (3 Avril) :

1er objectif de la séance : Étude de la sensibilité de la LDR selon le milieu et l'intensité
-
Caractériser la sensibilité du capteur LDR
-
Identifier les valeurs extrêmes
-
Analyser l'impact de l'indice de turbidité de l'eau sur la transmission du flux lumineux.
Code utilisé
Code qui nous permet juste de lire la LDR :
void setup() {
Serial.begin(9600);
pinMode(A0,INPUT);
}
void loop() {
int ldrvalue = analogRead(A0);
Serial.print("LDR = ");
Serial.println(ldrvalue);
delay(10000);
}
Matériel
-
LDR (Photorésistance) + résistance
-
Carte Arduino et breadbord
-
2 béchers
-
Potence
-
les différentes eaux
-
flash lumineux
-
Code simple (lecture analogique) via microcontrôleur.
Protocole

L'expérience consiste à relever l'intensité captée dans 6 milieux ou conditions différents :
-
Référence Obscurité : LDR cachée (étalonnage du point 0 %).
-
Air libre : Sans obstacle.
-
Air libre + Bécher : Pour isoler l'impact du verre seul.
-
Eau transparente : Milieu liquide limpide.
-
Eau trouble niv 1 : Eau avec légère turbidité.
-
Eau trouble niv 2 : Eau avec une turbidité un peu plus forte.
-
Eau trouble niv 3 : Forte concentration de particules.
-> L’opacité a été réalisée avec de la terre
Standardisation des mesures :
Chaque test est effectué avec la lumière ambiante uniquement, puis avec un flash lumineux. La distance entre la source (flash) et la LDR est maintenue identique pour tous les essais.
Pour chaque condition, 10 mesures sont réalisées (intervalle de 10 secondes entre chaque relevé) afin de calculer une moyenne.

2e objectif de la séance : Réaliser un schéma plus complet et précis de la carte électronique vue de dessous et de dessus.



Séance 10 (10 Avril) :
1er objectif : Mettre en forme les résultats des expériences de la séance précédente sous forme d'histogrammes
Résultats des expériences de mesure d'intensité par la LDR


Nous avons ensuite réalisé un diagramme du % de chute d'intensité lumineuse en fonction des différents milieux.

Ldr totalement caché : pourcentage de chute pas égale à 100 mais 53. Donc on capte quand même de la lumière.
2e objectif : Apprendre à utiliser tinkercad pour réaliser des schéma précis
Schéma tinkercad



3eme objectif : Amélioration du code
Nouvelle approche de la FONCTION SWITCH/CASE
Explication du code :
- On vérifie la RTC a chaque boucle
À chaque cycle, on lit toutes les LDR de référence d'un coup selon celle qui capte de la lumière ou non on choisit directement le case dans lequel on va aller
CODE Switch/Case nouvelle approche

#include <Wire.h> // Appel du protocole de communication
// Appel de la bibliothèque RTC
#include <I2C_RTC.h>
static DS1307 RTC; // déclaration du modèle de RTC
// A4 = SDA et A5 = SCL ==> RTC
// --- Variables de Pins ---
// --LDR - BORD 1 --
const int ldr1_B1 = A0;
const int ldr2_B1 = A1;
const int ldr3_B1 = A2;
const int ldr4_B1 = A3;
// --LDR - BORD 2 --
const int ldr1_B2 = A0;
const int ldr2_B2 = A1;
const int ldr3_B2 = A2;
const int ldr4_B2 = A3;
// -- LDR - BORD REF --
const int ldrREF0 = A0;
const int ldrREF1 = A1;
const int ldrREF2 = A2;
// -- BORD / TRANSISTORS --
#define bord1 2
#define bord2 3
#define bordREF 4
//-- SEUIL--
#define seuilREF 200
#define seuil 400
#define rythme 10000
//================================================
// --- ETATs DE CASE---
//================================================
enum Etat {
NUIT,
Test_Bord_1,
Test_Bord_2,
Test_Bord_REF,
Pas_Erosion,
Erreur_FATALE,
};
Etat etatActuel = Test_Bord_REF;
int erreursRTC = 0; // Compteur de déconnexions
const int MAX_ERREURS = 10; // Seuil avant blocage de sécurité
int nbDetectes = 0; // le nbr de LDRs détectées pour évaluer l'évolution de l'érosion de la berge /// ON COMPTE REF1 ET REF2
void setup() {
Serial.begin(115200);
// vérification au démarrage (une seule fois)
while (!Serial); // Empêche le programme de commencer si le matériel est mal connecté dès le départ
RTC.begin();
Serial.println();
// --- Boucle tant que la RTC n'est PAS détectée ---
while (!RTC.isConnected()) {
Serial.println("⚠️ RTC non détectée — vérifiez les connexions !");
delay(rythme);
}
// --------------------------------------------------
Serial.println("✅ RTC détectée !");
RTC.startClock();
// --- RÉGLAGE DE L’HEURE (UNE SEULE FOIS) ---
// RTC.setDateTime(__DATE__, __TIME__);
// -------------------------------------------
// --- CONFIGURATION DES CAPTEURS --
// Pas besoin de mettre les INPUT (mais préférable)
// --BORD 1--
pinMode(ldr1_B1, INPUT);
pinMode(ldr2_B1, INPUT);
pinMode(ldr3_B1, INPUT);
pinMode(ldr4_B1, INPUT);
// --BORD 2--
pinMode(ldr1_B2, INPUT);
pinMode(ldr2_B2, INPUT);
pinMode(ldr3_B2, INPUT);
pinMode(ldr4_B2, INPUT);
// --BORD REF--
pinMode(ldrREF0,INPUT);
pinMode(ldrREF1,INPUT);
pinMode(ldrREF2,INPUT);
// --- CONFIGURATION DES SORTIES (mettre au cas ou même si pas necessaire normalement)
pinMode(bord1, OUTPUT);
pinMode(bord2, OUTPUT);
pinMode(bordREF, OUTPUT);
// --- ÉTAT INITIAL ---
digitalWrite(bord1, LOW);
digitalWrite(bord2, LOW);
digitalWrite(bordREF, HIGH);
}
void loop() {
// ==============================================
// Détermination de L'ETAT en vérifiant les LDR DE REF
// ==============================================
if (!RTC.isConnected()) {
erreursRTC++; // On incrémente le compteur d'erreur
Serial.println("RTC deconnectee !");
delay (rythme);
if (erreursRTC >= MAX_ERREURS) {
etatActuel = Erreur_FATALE; // On coupe tout ! pour pas vider la baterie
}
} else {
Serial.println(RTC.getDateTimeString()); //lecture du temps de manière lisible : String
Serial.println (RTC.getEpoch()); // lecture pour la machine
erreursRTC = 0;
nbDetectes = 0;
//----Vérification de la LDR de REF0 => donne le SEUIL-----
int REF0 = analogRead(ldrREF0);
if (REF0 < seuil){
etatActuel = NUIT;
Serial.print("NUIT");
} else{
Serial.print("JOUR REF0 ");
Serial.println(REF0);
int REF2 = analogRead(ldrREF2);
if (REF2 > seuil){
etatActuel = Test_Bord_2;
Serial.print("JOUR REF2 ");
Serial.println(REF2);
} else {
int REF1 = analogRead(ldrREF1);
if(REF1 > seuil){
etatActuel = Test_Bord_1;
Serial.print("JOUR REF1");
Serial.println(REF1);
} else{
etatActuel = Pas_Erosion ;
Serial.print("pas d'érosion");
}
}
}
delay (rythme);
}
// ==================================================
// Execution de Switch/Case
// ==================================================
switch (etatActuel){
case NUIT:{
Serial.print(" | NUIT - LDRs Détectés: ");
Serial.println(nbDetectes);
} break;
case Test_Bord_1:{
Serial.print("bord 1 allumé");
digitalWrite(bordREF, LOW);
digitalWrite(bord1, HIGH);
int valeurldr1_B1 = analogRead (ldr1_B1);
if (valeurldr1_B1 < seuil){
Serial.print("A0= "); //LDR1 PAS ERODE
Serial.println(valeurldr1_B1);
} else {
Serial.print("A0= erodé "); //LDR1 ERODE +1
Serial.println(valeurldr1_B1);
nbDetectes++ ;
int valeurldr2_B1 = analogRead(ldr2_B1);
/*Serial.print("A1= ");
Serial.println(valeur2);*/
if (valeurldr2_B1< seuil){
Serial.print("ldr 2 caché "); //LDR2 PAS ERODE
} else{ // LDR2 ERODE +1
nbDetectes++ ;
int valeurldr3_B1 = analogRead (ldr3_B1);
if (valeurldr3_B1 < seuil){
//Serial.print("ldr 3 caché "); LDR3 PAS ERODE
} else { // LDR3 ERODE +1
nbDetectes++ ;
int valeurldr4_B1 = analogRead (ldr4_B1);
if (valeurldr4_B1 < seuil){ // LDR4 PAS ERODE
//Serial.print("ldr 4 caché ");
}else{ // LDR4 ERODE +1
nbDetectes++ ;
}
}
} }
Serial.print(" | LDRs Détectés: ");
Serial.println(nbDetectes);
digitalWrite(bord1, LOW);
digitalWrite(bordREF, HIGH);
} break;
case Test_Bord_2:{
Serial.print("bord 2 allumé");
digitalWrite(bordREF, LOW);
digitalWrite(bord2, HIGH);
int valeurldr1_B2 = analogRead (ldr1_B2);
if (valeurldr1_B2 < seuil){
Serial.print("A0= "); // LDR1 PAS ERODE
Serial.println(valeurldr1_B2);
} else {
Serial.print("A0 - B2 = erodé "); // LDR1 ERODE +1
Serial.println(valeurldr1_B2);
nbDetectes++ ;
int valeurldr2_B2 = analogRead(ldr2_B2);
/*Serial.print("A1= ");
Serial.println(valeur2);*/
if (valeurldr2_B2< seuil){
//Serial.print("ldr 2 caché "); LDR2 PAS ERODE
} else{ // LDR2 ERODE +1
nbDetectes++ ;
int valeurldr3_B2 = analogRead (ldr3_B2);
if (valeurldr3_B2 < seuil){
//Serial.print("ldr 3 caché "); LDR3 PAS ERODE
} else { // LDR3 ERODE +1
nbDetectes++ ;
int valeurldr4_B2 = analogRead (ldr4_B2);
if (valeurldr4_B2 < seuil){ // LDR4 PAS ERODE
//Serial.print("ldr 4 caché ");
}else{ // LDR4 ERODE +1
nbDetectes++ ;
}
}
} }
Serial.print(" | LDRs Détectés: ");
Serial.println(nbDetectes);
digitalWrite(bord2, LOW);
digitalWrite(bordREF, HIGH);
} break;
case Pas_Erosion:{
Serial.print(" | PAS d'EROSION - LDRs Détectés: ");
Serial.println(nbDetectes);
} break;
case Erreur_FATALE : {
// Boucle de sécurité = on force extinction des plaques
digitalWrite(bord1, LOW);
digitalWrite(bord2, LOW);
digitalWrite(bordREF, LOW);
// eteindre la caret sd
Serial.println("❌ ERREUR CRITIQUE : RTC perdue. Système stoppé.");
// On vérifie quand même si la RTC revient toutes les 10 secondes
if (RTC.isConnected()) {
Serial.println("✅ RTC retrouvée ! Redémarrage...");
erreursRTC = 0;
}
delay (rythme);
} break;
}
}
Azote = atm protectrice ( peut être à mettre dans le tube)
Règle CODE
⇒ On utilise const int dans notre code → occupe 2 octets en RAM (int = 2 octets sur Uno)
Sur un Uno qui n'a que 2048 octets de RAM, ça peut compter. Donc pour des constantes simples comme des seuils, #define est souvent utilisé sur Arduino.
Sur Arduino → #define pour les constantes numériques simples (seuils, pins) → économise la RAM
Attention syntaxe de CODE : // "ldr1 moins B1" const int ldr1-B1 = A0; plutot ldr1_B1 = A0;
Séance 11 (17 Avril) :

1 er objectif : Amélioration du code : enregistrement de l'heure et des données sur la carte SD
Le CODE
#include <Wire.h> // Appel du protocole de communication
// Appel de la bibliothèque RTC
#include <I2C_RTC.h>
static DS1307 RTC; // déclaration du modèle de RTC
// A4 = SDA et A5 = SCL ==> RTC
// ----- Carte SD ----
#define SD_CS_PIN 10
#define NOM_FICHIER "log.txt"
File fichier;
// --- Variables de Pins ---
// --LDR - BORD 1 --
const int ldr1_B1 = A0;
const int ldr2_B1 = A1;
const int ldr3_B1 = A2;
const int ldr4_B1 = A3;
// --LDR - BORD 2 --
const int ldr1_B2 = A0;
const int ldr2_B2 = A1;
const int ldr3_B2 = A2;
const int ldr4_B2 = A3;
// -- LDR - BORD REF --
const int ldrREF0 = A0;
const int ldrREF1 = A1;
const int ldrREF2 = A2;
// -- BORD / TRANSISTORS --
#define bord1 2
#define bord2 3
#define bordREF 4
//-- SEUIL--
#define seuilREF 200
#define seuil 400
#define rythme 10000
//================================================
// --- ETATs DE CASE---
//================================================
enum Etat {
NUIT,
Test_Bord_1,
Test_Bord_2,
Test_Bord_REF,
Pas_Erosion,
Erreur_FATALE,
};
Etat etatActuel = Test_Bord_REF;
int erreursRTC = 0; // Compteur de déconnexions
const int MAX_ERREURS = 10; // Seuil avant blocage de sécurité
int nbDetectes = 0; // le nbr de LDRs détectées pour évaluer l'évolution de l'érosion de la berge /// ON COMPTE REF1 ET REF2
bool sdOK = false; // pour savoir si la carte sd est utilisable ou pas
void enregistrementdedonne (){
if (!sdOK) return; //si pas de sd on n'écrit rien
fichier = SD.open(NOM_FICHIER, FILE_WRITE);
if (fichier) {
// Format CSV : date;etat;nbDetectes
fichier.print(timestamp);
fichier.print(F(";"));
fichier.print(etatTxt);
fichier.print(F(";"));
fichier.println(nb);
fichier.close();
} else {
Serial.println(F("Erreur : impossible d'ecrire dans le fichier."));
}
}
// --------------------------------------------------------
// c'est la fonction arrêt propre appelé dans erreur fatale
// ----------------------------------------------------------
void arretPropre() {
Serial.println(F("Arret demande - finalisation du fichier..."));
if (sdOK) {
fichier = SD.open(NOM_FICHIER, FILE_WRITE);
if (fichier) {
fichier.print(F("=== Fin du log : "));
if (RTC.isConnected()) fichier.println(RTC.getDateTimeString());
else fichier.println(F("RTC indisponible"));
fichier.close();
}
}
Serial.println(F("Fichier ferme correctement. Systeme arrete."));
}
void setup() {
Serial.begin(115200);
// vérification au démarrage (une seule fois)
while (!Serial); // Empêche le programme de commencer si le matériel est mal connecté dès le départ
RTC.begin();
Serial.println();
// --- Boucle tant que la RTC n'est PAS détectée ---
while (!RTC.isConnected()) {
Serial.println("⚠️ RTC non détectée — vérifiez les connexions !");
delay(rythme);
}
// --------------------------------------------------
Serial.println("✅ RTC détectée !");
RTC.startClock();
// --- RÉGLAGE DE L’HEURE (UNE SEULE FOIS) ---
// RTC.setDateTime(__DATE__, __TIME__);
// -------------------------------------------
Serial.print(F("Initialisation SD... "));
if (!SD.begin(SD_CS_PIN)) {
Serial.println(F("ECHEC ! On continue SANS enregistrement."));
sdOK = false;
} else {
Serial.println(F("OK."));
sdOK = true;
fichier = SD.open(NOM_FICHIER, FILE_WRITE);
if (fichier) {
fichier.println(F("=== Debut du log ==="));
fichier.println(F("date;etat;nbDetectes"));
fichier.close();
}
}
// --- CONFIGURATION DES CAPTEURS --
// Pas besoin de mettre les INPUT (mais préférable)
// --BORD 1--
pinMode(ldr1_B1, INPUT);
pinMode(ldr2_B1, INPUT);
pinMode(ldr3_B1, INPUT);
pinMode(ldr4_B1, INPUT);
// --BORD 2--
pinMode(ldr1_B2, INPUT);
pinMode(ldr2_B2, INPUT);
pinMode(ldr3_B2, INPUT);
pinMode(ldr4_B2, INPUT);
// --BORD REF--
pinMode(ldrREF0,INPUT);
pinMode(ldrREF1,INPUT);
pinMode(ldrREF2,INPUT);
// --- CONFIGURATION DES SORTIES (mettre au cas ou même si pas necessaire normalement)
pinMode(bord1, OUTPUT);
pinMode(bord2, OUTPUT);
pinMode(bordREF, OUTPUT);
// --- ÉTAT INITIAL ---
digitalWrite(bord1, LOW);
digitalWrite(bord2, LOW);
digitalWrite(bordREF, HIGH);
Serial.println(F("Tapez 'S' dans le moniteur serie pour arreter proprement."));
}
void loop() {
if (Serial.available()) {
char c = Serial.read();
if (c == 'S' || c == 's') {
etatActuel = Erreur_FATALE;
}
}
String timestamp = "";
// ==============================================
// Détermination de L'ETAT en vérifiant les LDR DE REF
// ==============================================
if (!RTC.isConnected()){
if (!RTC.isConnected()) {
erreursRTC++; // On incrémente le compteur d'erreur
Serial.println("RTC deconnectee !");
delay (rythme);
if (erreursRTC >= MAX_ERREURS) {
etatActuel = Erreur_FATALE; // On coupe tout ! pour pas vider la baterie
}
} else {
Serial.println(RTC.getDateTimeString()); //lecture du temps de manière lisible : String
Serial.println (RTC.getEpoch()); // lecture pour la machine
erreursRTC = 0;
nbDetectes = 0;
//----Vérification de la LDR de REF0 => donne le SEUIL-----
int REF0 = analogRead(ldrREF0);
if (REF0 < seuil){
etatActuel = NUIT;
Serial.print("NUIT");
} else{
Serial.print("JOUR REF0 ");
Serial.println(REF0);
int REF2 = analogRead(ldrREF2);
if (REF2 > seuil){
etatActuel = Test_Bord_2;
Serial.print("JOUR REF2 ");
Serial.println(REF2);
} else {
int REF1 = analogRead(ldrREF1);
if(REF1 > seuil){
etatActuel = Test_Bord_1;
Serial.print("JOUR REF1");
Serial.println(REF1);
} else{
etatActuel = Pas_Erosion ;
Serial.print("pas d'érosion");
}
}
}
} delay (rythme);
}
// ==================================================
// Execution de Switch/Case
// ==================================================
switch (etatActuel){
case NUIT:{
Serial.print(" | NUIT - LDRs Détectés: ");
Serial.println(nbDetectes);
} break;
case Test_Bord_1:{
Serial.print("bord 1 allumé");
digitalWrite(bordREF, LOW);
digitalWrite(bord1, HIGH);
int valeurldr1_B1 = analogRead (ldr1_B1);
if (valeurldr1_B1 < seuil){
Serial.print("A0= "); //LDR1 PAS ERODE
Serial.println(valeurldr1_B1);
} else {
Serial.print("A0= erodé "); //LDR1 ERODE +1
Serial.println(valeurldr1_B1);
nbDetectes++ ;
int valeurldr2_B1 = analogRead(ldr2_B1);
/*Serial.print("A1= ");
Serial.println(valeur2);*/
if (valeurldr2_B1< seuil){
Serial.print("ldr 2 caché "); //LDR2 PAS ERODE
} else{ // LDR2 ERODE +1
nbDetectes++ ;
int valeurldr3_B1 = analogRead (ldr3_B1);
if (valeurldr3_B1 < seuil){
//Serial.print("ldr 3 caché "); LDR3 PAS ERODE
} else { // LDR3 ERODE +1
nbDetectes++ ;
int valeurldr4_B1 = analogRead (ldr4_B1);
if (valeurldr4_B1 < seuil){ // LDR4 PAS ERODE
//Serial.print("ldr 4 caché ");
}else{ // LDR4 ERODE +1
nbDetectes++ ;
}
}
} }
Serial.print(" | LDRs Détectés: ");
Serial.println(nbDetectes);
digitalWrite(bord1, LOW);
digitalWrite(bordREF, HIGH);
} break;
case Test_Bord_2:{
Serial.print("bord 2 allumé");
digitalWrite(bordREF, LOW);
digitalWrite(bord2, HIGH);
int valeurldr1_B2 = analogRead (ldr1_B2);
if (valeurldr1_B2 < seuil){
Serial.print("A0= "); // LDR1 PAS ERODE
Serial.println(valeurldr1_B2);
} else {
Serial.print("A0 - B2 = erodé "); // LDR1 ERODE +1
Serial.println(valeurldr1_B2);
nbDetectes++ ;
int valeurldr2_B2 = analogRead(ldr2_B2);
/*Serial.print("A1= ");
Serial.println(valeur2);*/
if (valeurldr2_B2< seuil){
//Serial.print("ldr 2 caché "); LDR2 PAS ERODE
} else{ // LDR2 ERODE +1
nbDetectes++ ;
int valeurldr3_B2 = analogRead (ldr3_B2);
if (valeurldr3_B2 < seuil){
//Serial.print("ldr 3 caché "); LDR3 PAS ERODE
} else { // LDR3 ERODE +1
nbDetectes++ ;
int valeurldr4_B2 = analogRead (ldr4_B2);
if (valeurldr4_B2 < seuil){ // LDR4 PAS ERODE
//Serial.print("ldr 4 caché ");
}else{ // LDR4 ERODE +1
nbDetectes++ ;
}
}
} }
Serial.print(" | LDRs Détectés: ");
Serial.println(nbDetectes);
digitalWrite(bord2, LOW);
digitalWrite(bordREF, HIGH);
} break;
case Pas_Erosion:{
Serial.print(" | PAS d'EROSION - LDRs Détectés: ");
Serial.println(nbDetectes);
} break;
case Erreur_FATALE : {
// Boucle de sécurité = on force extinction des plaques
digitalWrite(bord1, LOW);
digitalWrite(bord2, LOW);
digitalWrite(bordREF, LOW);
// eteindre la caret sd
Serial.println("❌ ERREUR CRITIQUE : RTC perdue. Système stoppé.");
// On vérifie quand même si la RTC revient toutes les 10 secondes
if (RTC.isConnected()) {
Serial.println("✅ RTC retrouvée ! Redémarrage...");
erreursRTC = 0;
}
delay (rythme);
} break;
}
}
Le code pas encore testé

2e objectif : Faire la barette sur tinkercad

Lien d'accès https://www.tinkercad.com/things/bg5KvYUesNw-modelisation-du-circuit?sharecode=Q8lX_LgqGzzxe0RfGgDLXN3qSim1PLlqWWHRYsVJsXc
Fin de notre travail sur ce projet
Résultats finale :
Barette tinkercad

- 1 Arduino
- 2 transistors NPN (utilisés comme power switch)
- 3 breadboards (Reference breadboard, Breadboard 1, Breadboard 2)
- 11 LDRs ( 3 de références )
- Des résistances [10Ohm pour les transistors et 10kΩ pour les ldrs]
- Des fils de connexion
On a un nombre de pins analogiques limité sur l'Arduino : ce qui ne suffit pas pour connecter les 11 LDRs individuellement.
Donc : LDRs sont réparties sur 3 breadboards, permettant de regrouper plusieurs LDRs sur un seul pin analogique et contourner la limitation.
Rappel du rôle des pins analogiques : permettent de lire les données de luminosité envoyées par les LDRs.
Schema de la carte éléctronique

Le code
#include <Wire.h> // Appel du protocole de communication
// Appel de la bibliothèque RTC
#include <I2C_RTC.h>
static DS1307 RTC; // déclaration du modèle de RTC
// A4 = SDA et A5 = SCL ==> RTC
// ----- Carte SD ----
#define SD_CS_PIN 10
#define NOM_FICHIER "log.txt"
File fichier;
// --- Variables de Pins ---
// --LDR - BORD 1 --
const int ldr1_B1 = A0;
const int ldr2_B1 = A1;
const int ldr3_B1 = A2;
const int ldr4_B1 = A3;
// --LDR - BORD 2 --
const int ldr1_B2 = A0;
const int ldr2_B2 = A1;
const int ldr3_B2 = A2;
const int ldr4_B2 = A3;
// -- LDR - BORD REF --
const int ldrREF0 = A0;
const int ldrREF1 = A1;
const int ldrREF2 = A2;
// -- BORD / TRANSISTORS --
#define bord1 2
#define bord2 3
#define bordREF 4
//-- SEUIL--
#define seuilREF 200
#define seuil 400
#define rythme 10000
//================================================
// --- ETATs DE CASE---
//================================================
enum Etat {
NUIT,
Test_Bord_1,
Test_Bord_2,
Test_Bord_REF,
Pas_Erosion,
Erreur_FATALE,
};
Etat etatActuel = Test_Bord_REF;
int erreursRTC = 0; // Compteur de déconnexions
const int MAX_ERREURS = 10; // Seuil avant blocage de sécurité
int nbDetectes = 0; // le nbr de LDRs détectées pour évaluer l'évolution de l'érosion de la berge /// ON COMPTE REF1 ET REF2
bool sdOK = false; // pour savoir si la carte sd est utilisable ou pas
void enregistrementdedonne (){
if (!sdOK) return; //si pas de sd on n'écrit rien
fichier = SD.open(NOM_FICHIER, FILE_WRITE);
if (fichier) {
// Format CSV : date;etat;nbDetectes
fichier.print(timestamp);
fichier.print(F(";"));
fichier.print(etatTxt);
fichier.print(F(";"));
fichier.println(nb);
fichier.close();
} else {
Serial.println(F("Erreur : impossible d'ecrire dans le fichier."));
}
}
// --------------------------------------------------------
// c'est la fonction arrêt propre appelé dans erreur fatale
// ----------------------------------------------------------
void arretPropre() {
Serial.println(F("Arret demande - finalisation du fichier..."));
if (sdOK) {
fichier = SD.open(NOM_FICHIER, FILE_WRITE);
if (fichier) {
fichier.print(F("=== Fin du log : "));
if (RTC.isConnected()) fichier.println(RTC.getDateTimeString());
else fichier.println(F("RTC indisponible"));
fichier.close();
}
}
Serial.println(F("Fichier ferme correctement. Systeme arrete."));
}
void setup() {
Serial.begin(115200);
// vérification au démarrage (une seule fois)
while (!Serial); // Empêche le programme de commencer si le matériel est mal connecté dès le départ
RTC.begin();
Serial.println();
// --- Boucle tant que la RTC n'est PAS détectée ---
while (!RTC.isConnected()) {
Serial.println("⚠️ RTC non détectée — vérifiez les connexions !");
delay(rythme);
}
// --------------------------------------------------
Serial.println("✅ RTC détectée !");
RTC.startClock();
// --- RÉGLAGE DE L’HEURE (UNE SEULE FOIS) ---
// RTC.setDateTime(__DATE__, __TIME__);
// -------------------------------------------
Serial.print(F("Initialisation SD... "));
if (!SD.begin(SD_CS_PIN)) {
Serial.println(F("ECHEC ! On continue SANS enregistrement."));
sdOK = false;
} else {
Serial.println(F("OK."));
sdOK = true;
fichier = SD.open(NOM_FICHIER, FILE_WRITE);
if (fichier) {
fichier.println(F("=== Debut du log ==="));
fichier.println(F("date;etat;nbDetectes"));
fichier.close();
}
}
// --- CONFIGURATION DES CAPTEURS --
// Pas besoin de mettre les INPUT (mais préférable)
// --BORD 1--
pinMode(ldr1_B1, INPUT);
pinMode(ldr2_B1, INPUT);
pinMode(ldr3_B1, INPUT);
pinMode(ldr4_B1, INPUT);
// --BORD 2--
pinMode(ldr1_B2, INPUT);
pinMode(ldr2_B2, INPUT);
pinMode(ldr3_B2, INPUT);
pinMode(ldr4_B2, INPUT);
// --BORD REF--
pinMode(ldrREF0,INPUT);
pinMode(ldrREF1,INPUT);
pinMode(ldrREF2,INPUT);
// --- CONFIGURATION DES SORTIES (mettre au cas ou même si pas necessaire normalement)
pinMode(bord1, OUTPUT);
pinMode(bord2, OUTPUT);
pinMode(bordREF, OUTPUT);
// --- ÉTAT INITIAL ---
digitalWrite(bord1, LOW);
digitalWrite(bord2, LOW);
digitalWrite(bordREF, HIGH);
Serial.println(F("Tapez 'S' dans le moniteur serie pour arreter proprement."));
}
void loop() {
if (Serial.available()) {
char c = Serial.read();
if (c == 'S' || c == 's') {
etatActuel = Erreur_FATALE;
}
}
String timestamp = "";
// ==============================================
// Détermination de L'ETAT en vérifiant les LDR DE REF
// ==============================================
if (!RTC.isConnected()){
if (!RTC.isConnected()) {
erreursRTC++; // On incrémente le compteur d'erreur
Serial.println("RTC deconnectee !");
delay (rythme);
if (erreursRTC >= MAX_ERREURS) {
etatActuel = Erreur_FATALE; // On coupe tout ! pour pas vider la baterie
}
} else {
Serial.println(RTC.getDateTimeString()); //lecture du temps de manière lisible : String
Serial.println (RTC.getEpoch()); // lecture pour la machine
erreursRTC = 0;
nbDetectes = 0;
//----Vérification de la LDR de REF0 => donne le SEUIL-----
int REF0 = analogRead(ldrREF0);
if (REF0 < seuil){
etatActuel = NUIT;
Serial.print("NUIT");
} else{
Serial.print("JOUR REF0 ");
Serial.println(REF0);
int REF2 = analogRead(ldrREF2);
if (REF2 > seuil){
etatActuel = Test_Bord_2;
Serial.print("JOUR REF2 ");
Serial.println(REF2);
} else {
int REF1 = analogRead(ldrREF1);
if(REF1 > seuil){
etatActuel = Test_Bord_1;
Serial.print("JOUR REF1");
Serial.println(REF1);
} else{
etatActuel = Pas_Erosion ;
Serial.print("pas d'érosion");
}
}
}
} delay (rythme);
}
// ==================================================
// Execution de Switch/Case
// ==================================================
switch (etatActuel){
case NUIT:{
Serial.print(" | NUIT - LDRs Détectés: ");
Serial.println(nbDetectes);
} break;
case Test_Bord_1:{
Serial.print("bord 1 allumé");
digitalWrite(bordREF, LOW);
digitalWrite(bord1, HIGH);
int valeurldr1_B1 = analogRead (ldr1_B1);
if (valeurldr1_B1 < seuil){
Serial.print("A0= "); //LDR1 PAS ERODE
Serial.println(valeurldr1_B1);
} else {
Serial.print("A0= erodé "); //LDR1 ERODE +1
Serial.println(valeurldr1_B1);
nbDetectes++ ;
int valeurldr2_B1 = analogRead(ldr2_B1);
/*Serial.print("A1= ");
Serial.println(valeur2);*/
if (valeurldr2_B1< seuil){
Serial.print("ldr 2 caché "); //LDR2 PAS ERODE
} else{ // LDR2 ERODE +1
nbDetectes++ ;
int valeurldr3_B1 = analogRead (ldr3_B1);
if (valeurldr3_B1 < seuil){
//Serial.print("ldr 3 caché "); LDR3 PAS ERODE
} else { // LDR3 ERODE +1
nbDetectes++ ;
int valeurldr4_B1 = analogRead (ldr4_B1);
if (valeurldr4_B1 < seuil){ // LDR4 PAS ERODE
//Serial.print("ldr 4 caché ");
}else{ // LDR4 ERODE +1
nbDetectes++ ;
}
}
} }
Serial.print(" | LDRs Détectés: ");
Serial.println(nbDetectes);
digitalWrite(bord1, LOW);
digitalWrite(bordREF, HIGH);
} break;
case Test_Bord_2:{
Serial.print("bord 2 allumé");
digitalWrite(bordREF, LOW);
digitalWrite(bord2, HIGH);
int valeurldr1_B2 = analogRead (ldr1_B2);
if (valeurldr1_B2 < seuil){
Serial.print("A0= "); // LDR1 PAS ERODE
Serial.println(valeurldr1_B2);
} else {
Serial.print("A0 - B2 = erodé "); // LDR1 ERODE +1
Serial.println(valeurldr1_B2);
nbDetectes++ ;
int valeurldr2_B2 = analogRead(ldr2_B2);
/*Serial.print("A1= ");
Serial.println(valeur2);*/
if (valeurldr2_B2< seuil){
//Serial.print("ldr 2 caché "); LDR2 PAS ERODE
} else{ // LDR2 ERODE +1
nbDetectes++ ;
int valeurldr3_B2 = analogRead (ldr3_B2);
if (valeurldr3_B2 < seuil){
//Serial.print("ldr 3 caché "); LDR3 PAS ERODE
} else { // LDR3 ERODE +1
nbDetectes++ ;
int valeurldr4_B2 = analogRead (ldr4_B2);
if (valeurldr4_B2 < seuil){ // LDR4 PAS ERODE
//Serial.print("ldr 4 caché ");
}else{ // LDR4 ERODE +1
nbDetectes++ ;
}
}
} }
Serial.print(" | LDRs Détectés: ");
Serial.println(nbDetectes);
digitalWrite(bord2, LOW);
digitalWrite(bordREF, HIGH);
} break;
case Pas_Erosion:{
Serial.print(" | PAS d'EROSION - LDRs Détectés: ");
Serial.println(nbDetectes);
} break;
case Erreur_FATALE : {
// Boucle de sécurité = on force extinction des plaques
digitalWrite(bord1, LOW);
digitalWrite(bord2, LOW);
digitalWrite(bordREF, LOW);
// eteindre la caret sd
Serial.println("❌ ERREUR CRITIQUE : RTC perdue. Système stoppé.");
// On vérifie quand même si la RTC revient toutes les 10 secondes
if (RTC.isConnected()) {
Serial.println("✅ RTC retrouvée ! Redémarrage...");
erreursRTC = 0;
}
delay (rythme);
} break;
}
}
Le poster

Lien : https://canva.link/oetpy21y3p1zkn7
Nos difficultés :
- Prise en main et découverte de la programmation Arduino : nous avons dû apprendre la syntaxe du langage et les règles des fonctions (comme switch/case) et la logique de lecture des capteurs.
- Découverte des outils de conception et de simulation : Tinkercad et OpenSCAD
- Faux contacts sur les breadboards : On a souvent eu des mauvais contacts qui nous ont fait douter de nos codes. On conseille de faire les tests sur Tinkercad avant de faire le montage physique pour pas se faire avoir.
- Données abérrantes provenant des LDRs : Les photorésistances ont souvent renvoyé des valeurs incohérentes et folles. Elles etaient liées très souvent à un mauvais branchement sur la breadbord : une patte mal insérée ou fil mal connecté.
Ce qu'il reste à poursuivre :
La prochaine étape consiste à graver le montage électronique sur un circuit imprimé afin de remplacer le prototype sur breadboard.
La barrette de support doit être finalisée, améliorée et imprimée en 3D
Ajoutter une LDR 4 de référence à l'intérieur du substrat pour voir l'évolution de la dégradation du matérielle electronique comme les Ldrs. (idée : ajouter de l'azote dans le tube)
Le capteur PEEP étant destiné à être immergé dans une berge en contact avec l'eau, une étude approfondie de l'étanchéité est indispensable :
-
Réaliser des tests d'immersion pour vérifier l'imperméabilité du tube et des jonctions
-
Concevoir et tester des entrées de câbles étanches (joints, résine, presse-étoupes)
-
Vérifier que le stockage des données (carte SD ou autre) reste fonctionnel en conditions humides
Une fois le prototype finalisé, des tests en conditions réelles devront être réalisées :
-
Implantation du capteur dans une berge de rivière
-
Vérification du bon fonctionnement de l'horloge RTC et de l'horodatage des mesures
-
Comparaison des données enregistrées avec des mesures de référence (recul de berge observé visuellement)
-
Évaluation de l'autonomie énergétique du dispositif sur le terrain
BONNE CHANCE :)
No Comments