Demande d'aide pour un projet de détection de chute de graine

Bonsoir,

Tout d'abord je tiens a préciser que je débute dans l'arduino, le principe ouvre énormément de possibilité mais mon manque de connaissance me bloque rapidement.

Mon projet actuel lié au milieu agricole est la fabrication d un boitier qui me permettra de contrôler la chute des graines d'un semoir a mais pour un amis agriculteur.
Je m'explique, aujourd'hui le problème c'est que lorsqu' il sème du mais si il ne contrôle pas régulièrement les tubes d'ou sorte les graines il y a un risque qu'ils se bouchent de par l’accumulation de terre ou bien tout simplement qu'il n'y ai plus de graines dans le semoir.
Ce semoir est un 6 rangs donc 6 tubes.

Après quelques essais j'ai réussi a équiper les tubes de capteurs photoélectriques qui me permette d'allumer une LED rouge a chaque passage d'une ou plusieurs graines.
Cela donne une indication visuelle en cabine mais c'est pour moi trop juste encore car il ne peut bien sur pas toujours avoir les yeux rivés sur le boitier.

C'est pour cela que je souhaite y intégrer la technologie arduino en renvoyant toujours une indication visuelle en cabine mais aussi et surtout en contrôlant le temps de passage des graines, si le capteur renvoi un niveau haut plus de 3 secondes c'est que le tube est bouché et si un niveau bas plus de 3 secondes c'est qu'il n'y a plus de graines dans la réserve.
Pour signaler le problème en cabine, la led correspondant au tube en question clignotera lentement et un buzzer retentira.
Pour valider le fait que le problème est réglé (débouchage du tube ou plein fait du semoir) un bouton reset sera mis en place sur le boitier.

J'aillais oublier, le mécanisme de semis est animé par deux roues en contact au sol qui permettent de faire tomber les graines si le semoir est en mouvement donc pour éviter que l'alarme tube vide ne retentisse sans arrêt je souhaite lancer le programme de contrôle que si le semoir est en mouvement.
Je compte pour cela placer un capteur inductif devant un pignon d entrainement ou bien tout simplement devant la roue équipée de pions qui seront détectés par le capteur.

Pour le moment en piquant des bouts de programme à droite, à gauche je suis parvenu a réaliser une base de programme qui me fait clignoter les leds si détection ou non de plus de 3 secondes.

int temps_defini = 3000;   //définition du temps de maintien désiré en ms
   int ledPin1 = 6;
   int capteur1 = 2;
   long debut_appui1;
   long debut_appui2;
   boolean variable1 = false;
   int etat_capteur1;
   int dernier_etat_capteur1 = LOW;
   int etat_led1 = LOW;
   int roue = 5;
   //int reset = 7;

   void setup()   {
    
      pinMode(ledPin1, OUTPUT); 
      pinMode(roue, INPUT);
      //pinMode(reset, INPUT);
      pinMode(capteur1, INPUT);
      digitalWrite(ledPin1, HIGH);                           //test visuel des led avant de commencer
      delay(2000);
      digitalWrite(ledPin1, LOW);
   }

   
   void loop()   {

   

   if (digitalRead(roue) == HIGH){                                  //lecture de l'etat de la roue (pour l'instant un contact sec)

     etat_capteur1 = digitalRead(capteur1);                        //lecture de l'état du capteur
      
      if (etat_capteur1 == HIGH){                                  //image de l'état du capteur
      digitalWrite(ledPin1, HIGH);      
      }
      if (etat_capteur1 == HIGH && dernier_etat_capteur1 == LOW){ 
       
         debut_appui1 = millis();                                   //initialisation du compteur 1
         variable1 = true;                                         //enregistrement du changement d'état du capteur 1
      }
      else {
      
         if (etat_capteur1 == LOW && dernier_etat_capteur1 == HIGH){

         debut_appui2 = millis();
         variable1 = true;
      }
      }
   
          if ( variable1 == true && etat_capteur1 == HIGH && dernier_etat_capteur1 == HIGH){    //le capteur 1 était et est toujours enclenché
                                                                                 
          if ((millis() - debut_appui1)  >= temps_defini){             //est-ce que le temps choisi est écoulé ?   
                                        
           digitalWrite(ledPin1, HIGH);
           delay(2000);                 
           digitalWrite(ledPin1, LOW);  
           delay(2000); 
          
           } 
         } 

               
     }

      if ( variable1 == true && etat_capteur1 == LOW && dernier_etat_capteur1 == LOW){    //le capteur 1 était et est toujours désenclenché
                                                                                 
         if ((millis() - debut_appui2)  >= temps_defini){             //est-ce que le temps choisi est écoulé ? 
           
                                      
           digitalWrite(ledPin1, HIGH);  
           delay(1000);                 
           digitalWrite(ledPin1, LOW); 
           delay(1000); 
        
            
           }
         } 

    
   

      
     dernier_etat_capteur1 = etat_capteur1;
     digitalWrite(ledPin1, LOW);
    
                                                                    //actualisation de l'état du bouton
      
     
     }

Mes questions sont les suivantes:

  • Déjà est ce que mon programme est correct ?

  • Comment intégrer le reset pour arrêter le buzzer et le clignotement de la led

  • Comment intégrer tout simplement la fonction buzzer car lorsque j'essais, dés le démarrage de mon programme le buzzer se met a sonner et ne s’arrête pas.

  • Comment contrôler les 6 capteurs en simultané car dans l'exemple il n'y en a qu'un.

Merci par avance pour vos réponses car je bloque depuis quelques semaines la dessus et cela me prend la tête.

Bonjour adagri,

Plutôt que de me lancer directement dans des réponses, j'aimerai avant tout comprendre le fonctionnement de ton système.

Tu dis utiliser des capteurs photoélectriques pour détecter le passage des grains. J'imagine que ces passages doivent sûrement être furtifs, car dans le cas contraire le capteur serai la plupart du temps occulté.

Or l'utilisation de la fonction delay() n'est pas compatible avec ce genre de traitement qui nécessite de scruter en permanence (ou plutôt très souvent) l'état des capteurs.

Cette instruction dite 'bloquante' empêchera le traitement en parallèle de tes tubes, et ne permettra pas forcément de détecter le passage furtif du grain.

Il faudra t'orienter vers l'utilisation de la fonction millis() pour gérer:

  • la commande des leds
  • la commande du buzzer
  • les temps de détection des défauts (présence ou absence continue de grains)
  • l'anti-rebond du ou des boutons poussoirs
  • éventuellement la fréquence de balayage des capteurs

Tu trouveras de nombreux exemples de l'utilisation de millis() dans le forum.

Puisque tu vas réaliser la même opération sur tes 6 tubes, je te conseille d'organiser tes variables en utilisant des tableaux dont l'index représentera le tube concerné.

Concernant le fonctionnement du buzzer, il est indispensable de bien définir son comportement à travers un organigramme car il y a de nombreux paramètres à prendre en comptes (bouton poussoir, 6 capteurs, roue en mouvement, délais de déclenchement).

Il est préférable de bien être clair sur ce dernier point car on peut rapidement se retrouver avec une usine à gaz si on traite chaque cas séparément (recherche dans le forum de 'machine à état' et en particulier celui-ci ).

Bonsoir Zlika et merci pour ta réponse,

Alors pour les capteurs oui le passage est furtif, aujourd'hui le système fonctionne avec des leds branchées en direct sur les capteurs et elles ne clignotent que très légèrement.

Pour simuler leur fonctionnement sur ma breadboard j'appuis très rapidement sur un BP, je me doute bien que cela n'est pas aussi rapide mais ça fonctionne.

Pour ce qui est des fonctions delay() dans mon programme elles ne sont utilisées que pour générer une alerte donc a ce moment la le programme est bloqué donc je pensais que cela ne poserait pas de problème..

Pour la fonction millis() je ne pensais pas qu'il lui était possible de gérer autant de chose, je vais m’ y intéresser du coup.

Pour l'histoire du tableau je commençais à m en rapprocher mais déjà rien qu'avec une simple gestion de temps je m'arrache les cheveux donc la j'ai un peu bloqué.

Pour le buzzer il doit fonctionner en parallèle du clignotement des leds juste au moment ou le système est en alarme.

hello
j'ai commencé a regarder, mais je suis pris par un autre projet
donc a controler, et à finir...

byte roue  = 2;
byte raz = 3;
byte buzer = 4;//si buzer actif
byte capteur[7] = {0, 5, 6, 7, 8, 9, 10};
byte ledPin[7]  = {0, 11, 12, 13, 14, 15, 16};

unsigned long temps_defini[7] = {3000, 3000, 3000, 3000, 3000, 3000, 3000};   //définition du temps de maintien désiré en ms
unsigned long chrono[7] = {0, 0, 0, 0, 0, 0, 0};
//unsigned long chrono[7] = {0, 0, 0, 0, 0, 0, 0};
boolean chgt_etat[7] = {false, false, false, false, false, false, false};
byte etat_tube[7] = {0, 0, 0, 0, 0, 0, 0};
byte dernier_etat_tube[7] = {0, 0, 0, 0, 0, 0, 0};
byte etat_led[7] = {0, 0, 0, 0, 0, 0, 0};
byte memo_roue = 0;

void setup()
{ //initiaisation des entrées et des sorties
  pinMode(roue,  INPUT_PULLUP);
  pinMode(raz,   INPUT_PULLUP);
  pinMode(buzer, OUTPUT);
  for (byte f = 1; f < 7; f++)
  {
    pinMode(ledPin[f], OUTPUT); digitalWrite(ledPin[f], LOW);
    pinMode(capteur[f], INPUT_PULLUP);
  }                                      //controle des sorties
  for (byte t = 1; t < 3; t++)           //controle des leds, 3 fois
  {
    for (byte f = 1; f < 7; f++)          //allume toutes les leds
    {
      digitalWrite(ledPin[f], HIGH);
      delay(400);
    }
    for (byte f = 1; f < 7; f++)           //éteins toutes les leds
    {
      digitalWrite(ledPin[f], LOW);
      delay(400);
    }
  }
  for (byte f = 1; f < 3; f++)              //controle du buzer, 2 fois
  {
    digitalWrite(buzer, HIGH);            //deux "bip"
    delay(400);
    digitalWrite(buzer, LOW);
    delay(400);
  }
  memo_roue = digitalRead(roue);
  for (byte f = 1; f < 7; f++)
  {
    dernier_etat_tube[f] = digitalRead(capteur[f]); //init dernier état tubes
  }
}

void loop() {
  if (digitalRead(roue)  != memo_roue)          //si la roue à bougé
  {
    memo_roue = digitalRead(roue);
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //à chaque changement d'état d'un tube, on initialise son chrono et on allume/éteins sa led témoin
    for (byte f = 1; f < 7; f++)
    {
      etat_tube[f] = digitalRead(capteur[f]);   //si la roue tourne, alors lecture de l'état des tubes

      if (etat_tube[f] == HIGH && dernier_etat_tube[f] == LOW)//si une graine viens d'arriver devant le capteur
      {
        digitalWrite(ledPin[f], HIGH);          //la led témoin du tube en cours est allumée
        chrono[f] = millis();                    //le chrono de presence est lancé
        dernier_etat_tube[f] = etat_tube[f];
      }
      else
      {
        if (etat_tube[f] == LOW && dernier_etat_tube[f] == HIGH)//si une graine viens de quitter le capteur
        {
          digitalWrite(ledPin[f], LOW);          //la led témoin du tube en cours est éteinte
          chrono[f] = millis();                  //le chrono d'absence est lancé
          dernier_etat_tube[f] = etat_tube[f];
        }
      }
      ///////////////////////////////////////////////////////////////////////////////////////////////////////////////

      if ( etat_tube[f] == HIGH && dernier_etat_tube[f] == HIGH)//si la graine est toujours devant le capteur
      {
        if ((millis() - chrono[f])  >= temps_defini[f])         //depuis trop longtemps
        {
          digitalWrite(buzer, HIGH);                            //alors alarme tube bouché
          digitalWrite(ledPin[f], HIGH);
          delay(2000);                                          //frequence du son et lumiere = 1/2 Hertz
          digitalWrite(buzer, LOW);
          digitalWrite(ledPin[f], LOW);
          delay(2000);
        }
      }
      if ( etat_tube[f] == LOW && dernier_etat_tube[f] == LOW)    //si aucune graine n'est revenue devant le capteur
      {
        if ((millis() - chrono[f])  >= temps_defini[f])            //depuis trop longtemps
        {
          digitalWrite(buzer, HIGH);                               //alors alarme cuve vide
          digitalWrite(ledPin[f], HIGH);                      
          delay(1000);                                             //frequence du son et lumiere = 1 Hertz
          digitalWrite(buzer, LOW);
          digitalWrite(ledPin[f], LOW);
          delay(1000);
        }
      }
      dernier_etat_tube[f] = etat_tube[f];
      digitalWrite(ledPin[f], LOW);
      //actualisation de l'état du bouton
    }
  }
  else
  {
    reset_des_chronos();
  }
}
void reset_des_chronos()
{
  for (byte f = 1; f < 7; f++)
  {
    chrono[f] = millis();
  }
}

Arg.... Encore du delay().

Ça va pas simplifier la détection du bouton poussoir qui inhibe le buzzer mais c'est sympa d'avoir bien avancé le projet... :wink:

Merci dfgh pour ton code, j'étudie ça ce soir.

Je reviens sur mon projet bien tardivement mais pris par le boulot je n'ai pas eu le temps de m' y remettre et les semis arrivent a grand pas.

J'ai quelques questions sur ton programme dfgh,

Quand tu me met if (digitalRead(roue) != memo_roue) //si la roue à bougé

Il faut que "roue" passe a l état 1 pour que cela soit validé ?

Quand je simule un capteur avec un Bouton poussoir, rien ne se passe et je ne comprend pas d'ou cela peut venir, je me doute que cela doit être du au fait que la roue ne bouge pas mais je ne vois pas comment le simuler.

D'un point de vue pratique, je doute que tu sois capable d'installer sur une roue de semoir un capteur assez robuste pour supporter le passage répété dans les champs. Tu remplaceras avantageusement ce procédé par un accéléromètre qui t'indiquera si le dispositif est en mouvement. Une petite temporisation évitera que le dispositif ne s'arrête trop souvent quand même.

Je me suis amusé à réécrire ton code en utilisant la fonction attachInterrupt. Elle ne fonctionne malheureusement qu'avec 2 pin d'une Arduino Uno mais avec suffisamment de pins sur d'autres cartes. Je suis parti sur les pins d'une Mega.

J'ai inclus une fonction mouve() qui reste à définir en fonction de l'accéléromètre utilisé.

J'ai pris une durée assez courte pour le tube vide afin d'éviter les interruptions trop longues, si on peut la baisser, ce serait encore mieux mais en pratique, il faut voir si ça ne déclenche pas trop d'alarmes inutiles. On peut par contre tranquillement augmenter la durée pour le tube plein vu que ça n'est pas bloquant. J'imagine qu'en pratique, des tubes bouchés se débouchent tout seuls avec les cahots et qu'il n'y a pas lieu de faire sonner l'alarme tant que ça dure pas trop longtemps.

Voici le code mais j'ai un problème de compilation avec la commande attachInterrupt (tout le reste fonctionne) :

byte buzer = 4;//si buzer actif
byte capteur[6] = {2, 3, 18, 19, 20, 21}; // Seulement sur une Mega - se renseigner sur les pins qui fonctionnent avec attachInterrupt suivant le type de carte
byte ledPin[6]  = {11, 12, 13, 14, 15, 16};

int duree_plein = 2000; //définition dde la duree maxi pour tube plein (blocage)
int duree_vide = 500; //définition dde la duree maxi pour tube vide (réalimentatin nécessaire)

volatile unsigned long chrono1[6] = {0, 0, 0, 0, 0, 0};
volatile unsigned long chrono2[6] = {0, 0, 0, 0, 0, 0};

void setup()
{ //initiaisation des entrées et des sorties

  pinMode(buzer, OUTPUT);

  for (byte f = 0; f < 6; f++)
  {
    pinMode(ledPin[f], OUTPUT); digitalWrite(ledPin[f], LOW); //initialisation des sorties
    pinMode(capteur[f], INPUT_PULLUP); //initialisation capteurs
    attachInterrupt(digitalPinToInterrupt(capteur[f]), pouls(f), RISING); // déclenchera la fonction pouls chaque fois que le capteur d'un tube passera à l'état haut
  }
 
  for (byte t = 0; t < 3; t++)           //controle des leds, 3 fois
  {
    for (byte f = 0; f < 6; f++)          //allume toutes les leds
    {
      digitalWrite(ledPin[f], HIGH);
      delay(400);
    }
    for (byte f = 0; f < 6; f++)           //éteins toutes les leds
    {
      digitalWrite(ledPin[f], LOW);
      delay(400);
    }
  }
  for (byte f = 1; f < 3; f++)              //controle du buzer, 2 fois
  {
    digitalWrite(buzer, HIGH);            //deux "bip"
    delay(400);
    digitalWrite(buzer, LOW);
    delay(400);
  }

}

void pouls(byte cpt) {

  digitalWrite(ledPin[cpt], HIGH); // mise à jour état LED

  chrono1[cpt] = micros()/1000; // mémorise la date du dernier passage à l'état haut
  chrono2[cpt] = pulseIn(capteur[cpt], HIGH, duree_vide)/1000; // mémorise la durée du passage à l'état haut avec un maximum correspondant au temps défini;

}


bool mouve() {
  // écrire une fonction qui retourne True si le semoir est en mouvement ou arrêté depuis moins de X secondes (temporisation de X secondes) et False sinon
  // cette fonction dépend du module accelerometre choisi
  return true ;
}

void scan() {

  for (byte f = 1; f < 6; f++)
  {
    if (digitalRead(capteur[f]) == LOW) {
      digitalWrite(ledPin[f], LOW);
    }

  }
}

void alarm(byte cpt) {
  digitalWrite(buzer, HIGH);            // "bip"
  for (int i = 0; i < 50; i++) {     // clignotement de la led du capteur fautif pendant 5 secondes
    digitalWrite(ledPin[cpt], HIGH);
    delay(100);
    digitalWrite(ledPin[cpt], LOW);
    delay(100);
  }
  digitalWrite(buzer, LOW); // arrêt alarme
}

void loop() {

  scan(); // mise à jour des LED

  if (mouve())          //si le semoir est en mouvement
  {
    for (byte f = 1; f < 6; f++)
    {
      int delai = millis() - chrono1[f] ;
      if ((digitalRead(capteur[f]) == LOW && delai >= duree_plein) || chrono2[f] >= duree_vide ) // si le tube est vide depuis plus lontemps que le temps défini ou plein pendant plus longtemps que le temps défini
      {
        alarm(f);     // déclenchement de l'alarme avec clignotement de la LED correspondant au tube vide ou bouché
      }
    }
  }
}

EDIT : après quelques tests, je m'aperçois qu'on ne peut pas utiliser d'argument dans la définition d'une routine d'interruption. Je n'en ai pas trouvé la raison. Quelqu'un saurait me l'expliquer?

hello
en partant du principe que tu mettes une came qui est actionnée à chaque tour de roue
je suis passé par interruption
cette interruption arme un flag
ce flag arme une tempo. le flag est repassé à zéro
si la roue actionne à nouveau la came, dans le delai prévu, tout va bien, la tempo est réarmée.
sinon on considère que la roue ne tourne plus.

pour simuler la came de la roue, un BP entre D2 et GND

tu lances le prog avec le moniteur ouvert à 1000000 bauds
au debut, ecran blanc.
tu actionnes ton BP et tu peux voir le prg travailler.
il faut réactionner le BP avant 10 secondes pour que le prg voit la roue tourner
un autre BP sur une des entrées "tube" pour simuler le passage d'une graine
j'avais mis tes 4 delay() à 100 pour les tests

il faudra virer les lignes de serial.print() lorsque tu te seras accaparé le programme

byte roue  = 2;
byte raz = 3;
byte buzer = 4;//si buzer actif
byte capteur[7] = {0, 5, 6, 7, 8, 9, 10};
byte ledPin[7]  = {0, 11, 12, 13, 14, 18, 19};
boolean flag_rotation=false;
unsigned long chrono_roue     = 0;
unsigned long tempo_roue      = 10000;// un peu plus long qu'un tour de roue
unsigned long temps_defini[7] = {3000, 3000, 3000, 3000, 3000, 3000, 3000};   //définition du temps de maintien désiré en ms
unsigned long chrono[7] = {0, 0, 0, 0, 0, 0, 0};


boolean chgt_etat[7] = {false, false, false, false, false, false, false};
byte etat_tube[7] = {0, 0, 0, 0, 0, 0, 0};
byte dernier_etat_tube[7] = {0, 0, 0, 0, 0, 0, 0};
byte etat_led[7] = {0, 0, 0, 0, 0, 0, 0};
byte memo_roue = 0;
volatile boolean flag_chrono_roue_arme=false; // une variable utilisée dans une interruption doit être déclarée "volatile"
void isr_roue() //comptage de l'ILS
{
  flag_chrono_roue_arme=true;
}
void setup()
{ //initiaisation des entrées et des sorties
  Serial.begin(1000000);
  pinMode(roue,  INPUT_PULLUP);
  pinMode(raz,   INPUT_PULLUP);
  pinMode(buzer, OUTPUT);
  for (byte f = 1; f < 7; f++)
  {
    pinMode(ledPin[f], OUTPUT); digitalWrite(ledPin[f], HIGH);
    pinMode(capteur[f], INPUT_PULLUP);
  }                                      //controle des sorties
  //while(1);
  for (byte t = 1; t < 3; t++)           //controle des leds, 3 fois
  {
    for (byte f = 1; f < 7; f++)          //allume toutes les leds
    {
      digitalWrite(ledPin[f], HIGH);
      delay(100);
    }
    for (byte f = 1; f < 7; f++)           //éteins toutes les leds
    {
      digitalWrite(ledPin[f], LOW);
      delay(100);
    }
  }
  for (byte f = 1; f < 3; f++)              //controle du buzer, 2 fois
  {
    digitalWrite(buzer, HIGH);            //deux "bip"
    delay(100);
    digitalWrite(buzer, LOW);
    delay(100);
  }
  memo_roue = digitalRead(roue);
  for (byte f = 1; f < 7; f++)
  {
    dernier_etat_tube[f] = digitalRead(capteur[f]); //init dernier état tubes
  }
  attachInterrupt(INT0, isr_roue, FALLING);
}

void loop() 
{
  if (flag_chrono_roue_arme==true)          //la roue actionne sa came pour la premiere fois
  {   
    flag_rotation = true;Serial.println("la roue bouge, le chrono est arme");
    reset_des_chronos();Serial.println("les chronos sont a zero");
    chrono_roue=millis();  
  while (flag_rotation==true)       //tant que la tempo de rotation roue est en cours
  {if (flag_chrono_roue_arme==true)
  {chrono_roue=millis(); }
    
    flag_chrono_roue_arme=false;     
    if ((millis()-chrono_roue)>tempo_roue)        //si la roue ne tourne plus, le chrono se termine
    {
      flag_rotation=false;
    Serial.println((millis()-chrono_roue));
Serial.println("fin de tempo rotation roue on termine la scrutation en cours");    
    }               //le flag passe faux et on va sortir du while
 ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
    //à chaque changement d'état d'un tube, on initialise son chrono et on allume/éteins sa led témoin
    for (byte f = 1; f < 7; f++)
    {
      etat_tube[f] = digitalRead(capteur[f]);   //si la roue tourne, alors lecture de l'état des tubes

      if (etat_tube[f] == HIGH && dernier_etat_tube[f] == LOW)//si une graine viens d'arriver devant le capteur
      {
Serial.print("etat_tube ");Serial.print(f);Serial.print(" ");Serial.print(etat_tube[f]);
        digitalWrite(ledPin[f], HIGH);          //la led témoin du tube en cours est allumée
Serial.print("led ");Serial.print(f);Serial.print(" ");Serial.println(digitalRead(ledPin[f])); 
        chrono[f] = millis();                    //le chrono de presence est lancé
        dernier_etat_tube[f] = etat_tube[f];
      }
      else
      {
        if (etat_tube[f] == LOW && dernier_etat_tube[f] == HIGH)//si une graine viens de quitter le capteur
        {
          digitalWrite(ledPin[f], LOW);          //la led témoin du tube en cours est éteinte
Serial.print("led ");Serial.print(f);Serial.print(" ");Serial.println(digitalRead(ledPin[f]));           
          chrono[f] = millis();                  //le chrono d'absence est lancé
          dernier_etat_tube[f] = etat_tube[f];
        }
      }
      ///////////////////////////////////////////////////////////////////////////////////////////////////////////////

      if ( etat_tube[f] == HIGH && dernier_etat_tube[f] == HIGH)//si la graine est toujours devant le capteur
      {
        if ((millis() - chrono[f])  >= temps_defini[f])         //depuis trop longtemps
        {
 Serial.print("buzer ");Serial.print(f);Serial.print(" ");Serial.println(digitalRead(buzer)); 
 Serial.print("graine bloquee dans tube ");Serial.println(f);       
          digitalWrite(buzer, HIGH);                            //alors alarme tube bouché
          digitalWrite(ledPin[f], HIGH);
 Serial.print("led ");Serial.print(f);Serial.print(" ");Serial.println(digitalRead(ledPin[f]));  
          delay(2000);                                          //frequence du son et lumiere = 1/2 Hertz
          digitalWrite(buzer, LOW);
          digitalWrite(ledPin[f], LOW);
          delay(2000);
        }
      }
      if ( etat_tube[f] == LOW && dernier_etat_tube[f] == LOW)    //si aucune graine n'est revenue devant le capteur
      {
        if ((millis() - chrono[f])  >= temps_defini[f])            //depuis trop longtemps
        {
 Serial.print("buzer ");Serial.print(f);Serial.print(" ");Serial.println(digitalRead(buzer)); 
 Serial.println("++++++++++++++++++++++ cuve vide +++++++++++++++++++");     
          digitalWrite(buzer, HIGH);                               //alors alarme cuve vide
          digitalWrite(ledPin[f], HIGH);                     
          delay(1000);                                             //frequence du son et lumiere = 1 Hertz
          digitalWrite(buzer, LOW);
          digitalWrite(ledPin[f], LOW);
          delay(1000);
        }
      }
      dernier_etat_tube[f] = etat_tube[f];
      digitalWrite(ledPin[f], LOW);
      //actualisation de l'état du bouton
    }
  }
}
}
void reset_des_chronos()
{
  for (byte f = 1; f < 7; f++)
  {
//Serial.println("reset des chronos ");
    chrono[f] = millis();
//Serial.print("chrono ");Serial.print(f);Serial.print(" ");Serial.println(chrono[f]);
  }
}