Skip to main content

Projet PEEP-River

Informations :

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 : 

Comment concevoir et prototyper un dispositif électronique autonome capable de mesurer et de transmettre en temps réel le recul d'une berge (érosion) ou l'accumulation de sédiments, afin d'étudier la dynamique d'un cours d'eau au cours du temps ?

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 :

image.png

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

image.png

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 

image.png

image.pngMontage 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.

IMG_2162.jpg

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 

IMG_2161.jpg

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 que faible luminosité est due à une mauvaise météo

Séance 1 (30 Janv) : 

image.pngimage.pngCompré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.

image.png

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) :

image.pngimage.png

  • 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 Ω ).

image.png

image.png

  • 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.

Cimage.pngode : 

 

 image.png

image.png

image.png

Montage :

WhatsApp Image 2026-02-18 at 15.15.47.jpeg

image.png

WhatsApp Image 2026-02-18 at 17.00.20.jpeg

Montage expérience 2 séance 3 fablab.JPG

 

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

image.png

"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

image.png

 

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. 

BQ5image.png

image.png

Code :image.png

 

 Montage :

image.png

photo montage transitor 1.JPG

Montage transisto avec doigt.JPGMontage transistor sans doigt.JPG

 

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

image.png

Code :

image.png

image.png

Montage :

WhatsApp Image 2026-02-27 at 15.17.09.jpegWhatsApp Image 2026-02-27 at 15.17.10.jpeg

 

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

image.png

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

image.png

IMG_2300.jpg

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

image.png

  

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.

  • 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

image.png

 

download.jpg

Code utilisé

image.png

Explication du code : 

image.png

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;

 }

}

image.png

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

image.png

image (1).pngimage.png

image (2).png

Séance 9 (3 Avril) :

image.png

image.png1er 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é

image.pngCode 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

image.png

L'expérience consiste à relever l'intensité captée dans 6 milieux ou conditions différents :

  1. Référence Obscurité : LDR cachée (étalonnage du point 0 %).

  2. Air libre : Sans obstacle.

  3. Air libre + Bécher : Pour isoler l'impact du verre seul.

  4. Eau transparente : Milieu liquide limpide.

  5. Eau trouble niv 1 : Eau avec légère turbidité.

  6. Eau trouble niv 2 : Eau avec une turbidité un peu plus forte.

  7. 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.

IMG_2653.jpg  IMG_2655.jpg   IMG_2656.jpg  IMG_2662.jpg

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.

image.pngimage.png

WhatsApp Image 2026-05-28 at 16.29.57.jpeg

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

image.png

image.png

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

image.png

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

image.png

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

image.png





#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)

  • #define seuil = 435 : Ça ne crée aucune variable en mémoire ça occupe 0 octet en RAM

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) :

image.png

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é 

image.png

2e objectif : Faire la barette sur tinkercad 

image.png

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

image.png

  • 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

    WhatsApp Image 2026-05-28 at 16.29.57.jpeg

    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

    image.png

    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 :)