Probleme avec les "delay" et aide a la redaction de mon code

Bonjour à tous ,

Tout débutant en programmation et en Arduino, j’aurai besoin de vos conseils qui me seraient bien précieux.
Étant en train d’essayer de faire un programme où une charrette passe devant 2 piquets, et où le passage devant chaque piquet doit déclencher la marche de moteur différent ( branchés sur 12 volts, d’où les relais ), mais le premier moteur doit continuer a marcher quand les autres se mettent en route , ce serait pour utiliser dans mon jardin .

J’ai esquissé ce programme dans lequel j’ai enlever les " delay" car ils bloquent … et j’ai chercher une solution.
J’ai trouvé le tuto de la machine à état, qui semble correspondre à ce que je cherche à faire:

Programmation Automate fini / Machine à état
Apr 16, 2017, 11:28 am Last Edit: Jun 05, 2018, 10:19 am by J-M-L
Dans ce tuto très instructif, on peut lire :
“Toute l’intelligence de la machine est donc dans la fonction callBack simpleclick()”

Justement c’est là ou je bloque.

En cas d’utilisation , au lieu d’un bouton ,de capteurs ultrason , quelle fonction utiliser à la place de " callBack simpleclick()" ? et quelle librairie installer à la place de :
→ télécharger et installer cette librairie OneButton.

je vous met le programme que j’ai commencer à faire , et qui devrait être corrigé avec vos conseils, car il doit être bien imparfait … . :roll_eyes:

Merci beaucoup pour ce que vous m’apporterez pour m’aider à programmer .

Cavok

//------------------------------------------------------------------------------ Définitions des  BROCHES UTILISEES
//A)--------------------  les relais

int  relais1 = 8; // relais moteur ar
int relais2 = 9; //  relais moteur f
int relais3 = 10;  //  relais moteur e
int relais4 = 11;  //  relais moteur ac

//B)-------------------  broches pour ultrasons
int trig1 = 4;
int echo1 = 5;

int trig2 = 12;
int echo2 = 7;

//------------------------------------------------------------------------------------------- temps de marche des relais
int b = 4000; //  temps de marche relais2 moteur f
int c = 1000; //  temps de marche relais3 moteur e
int d = 4000; //  temps de marche relais4 moteur ac





//----------------------------------------------------------------------------------------  definition des distances lues

long lecture_echo;
long cm1;
long cm2;

//----------------------------------------------------------------------  inclusion de librairies

// Reference the I2C Library
#include <Wire.h>













void setup() {
  // put your setup code here, to run once:
  //-----------------------------------------------------------------initialise les 2 capteurs ultrason
  pinMode(trig1, OUTPUT);
  digitalWrite(trig1, LOW);
  pinMode(echo1, INPUT);
  Serial.begin(9600);

  pinMode(trig2, OUTPUT);
  digitalWrite(trig2, LOW);
  pinMode(echo2, INPUT);
  Serial.begin(9600);

  //-------------------------------------------------------------------------- relais en output

  pinMode(relais1, OUTPUT);
  pinMode(relais2, OUTPUT);
  pinMode(relais3, OUTPUT);
  pinMode(relais4, OUTPUT);

 

}

//________________________________________________________________________________________________________________________________________fin du setup








void loop() {
  // put your main code here, to run repeatedly:


  //---------------------------------------------------------------lit l'echo cm1

  digitalWrite(trig1, HIGH);
  delayMicroseconds(10);
  digitalWrite(trig1, LOW);
  lecture_echo = pulseIn(echo1, HIGH);
  cm1 = lecture_echo / 58;
  Serial.print("Distance : ");
  Serial.println(cm1);
  delay(20);

  //-----------------------------------------------------------------lit l'echo cm2

  digitalWrite(trig2, HIGH);
  delayMicroseconds(10);
  digitalWrite(trig2, LOW);
  lecture_echo = pulseIn(echo2, HIGH);
  cm2 = lecture_echo / 58;
  Serial.print("Distance : ");
  Serial.println(cm2);
  delay(20);

  //----------------------------------------------------------- pas de piquet

  if ( cm1 > 100 )

    digitalWrite(8, HIGH);
  digitalWrite(9, HIGH);
  digitalWrite(10, HIGH);
  digitalWrite(11, HIGH);

  //-----------------------------------------------l rencontre le 1er piquet
  if ( cm1 < 100 )
  {
    digitalWrite(11, LOW);
    digitalWrite(8, HIGH);
    digitalWrite(9, HIGH);
    digitalWrite(10, HIGH);
  }
  //--------------------------------------------------------------------------   MAIS " LOW ne dure pas = DONC delay pour obtenir qu'il dure un certain temps ,  MAIS empeche  action suivante durant le delay 
  
  //  -----------------------------------------------------------------------  cm2 ( 2eme piquet qui arrive  => cm2 devient < à 100 )
  else if ( cm2 < 100 )
  {
    digitalWrite(11, HIGH);
    digitalWrite(8, HIGH);
    digitalWrite(9, LOW);
    digitalWrite(10, LOW);
  }

  //-------------------------------------------------------------  MAIS " LOW ne dure pas = DONC delay pour obtenir qu'il dure un certain temps ,  MAIS empêche  action suivante durant le delay 
  
  //-------------------------------------------------------------  on passe à la 3eme action 

  else
  {
    digitalWrite(8, LOW);
    digitalWrite(9, HIGH);
    digitalWrite(10, HIGH);
    digitalWrite(11, HIGH);
    delay (3000  ) ; //  ---------------------toujours le meme problème 
  }

}

dans mon tuto (j'ai corrigé le problème d'affichage des images au fait, ça devrait être plus lisible maintenant), ce qui déclenche le call back c'est le fait que dans la loop() j'appelle   button.tick();

il vous faut donc remplacer dans la loop() ce bout de code par une fonction qui va lire les détecteurs de distance et quand la charrette est passée (un peu donc comme le bouton: on détecte un appui, on attend le relâchement on déclenche, pour vous c'est vous détectez l'arrivée de la charrette, elle passe devant, puis elle n'est plus là ça y-est c'est le moment de déclencher - ou alors vous pouvez décider de déclencher dès que vous commencez à la voir mais dans ce cas faut vous assurer que votre code attende qu'elle soit entièrement passée avant de dire 'tiens il y'en a une nouvelle qui passe")

je ne sais pas si un détecteur ultra-son est la solution idéal - à vous de voir en fonction de votre context. utiliser la librairire NewPing pour que la boucle tourne vite en n'attendant pas trop longtemps quand il n'y a rien devant le capteur (mettre une distance max jusqu'à laquelle "regarder")

Bonjour,
Merci beaucoup d'avoir pris le temps de me répondre.

Je comprend qu'il va falloir remplacer " button.tick();" par une fonction qui va lire les détecteurs de distance, mais comment l'appeler, et surtout que mettre dans cette fonction (en terme de mots ).

J'ai opté pour des capteurs ultrasons (2 ou 3) , qui seront sur la charrette , 1 à l'avant, et 1 a l’arrière (+ 1 au milieu peut être ), et c'est quand chaque capteur passera devant le piquet que ça déclenchera le relai correspondant. les moteurs étant sur la charrette , il seront donc déclenché (via le relai correspondant ).
Je vais regarder ce que vous me conseillé, et je reviendrais vers vous en cas de difficultés ( ce qui est vraisemblable,vu mon niveau...)
En tout cas merci pour votre disponibilité .

oubliez la charrette pour le moment, commencez à utiliser la librairie NewPing pour comprendre comment elle fonctionne. il y a des exemples.

à quel distance du piquet le détecteur se trouvera sur la charrette ?

Bonjour,
D’abord un grand merci pour m’épauler et me guider ainsi.
La distance où passera les capteurs (sur la charrette ) et le piquet sera de 1 à 3 m, la charrette passant devant le piquet , il y aura un piquet tous les 2/3 mètres .

J’ai regarder attentivement NewPing, et j’y ai mis ce que je pensais être utile , ainsi que les questions que je me suis posé.

 #include <NewPing.h>
     
    #define SONAR_NUM     2 // on défini le nombre de capteurs (ici 2 capteurs)
    #define MAX_DISTANCE 300 // on définit la distance  Max en cm. (ici 300cm)
    #define PING_INTERVAL 33 // c'est le temps entre chaque mesure ? 
     
    unsigned long pingTimer[SONAR_NUM]; // When each pings.
    unsigned int cm[SONAR_NUM]; // Store ping distances.
    uint8_t currentSensor = 0; // Which sensor is active.
     
    NewPing sonar[SONAR_NUM] = { // Sensor object array.
      NewPing(4, 5, MAX_DISTANCE),  //  mets t'on "MAX_DISTANCE", ou 300 ?
      NewPing(12, 7, MAX_DISTANCE)  //  idem ?
      
    };

//-----------------------------------------------------------------------




void setup() {
  // put your setup code here, to run once:
 Serial.begin (115200);  // on utilise 115200 pour les mesures
      Serial.begin(115200);
      pingTimer[0] = millis() + 75; // First ping start in ms.     envoi du premier echo 
      for (uint8_t i = 1; i < SONAR_NUM; i++)
        pingTimer[i] = pingTimer[i - 1] + PING_INTERVAL;  //  c'est l'intervalle entre les  signaux des 2 

//capteurs , ou l'intervalle entre 2 echos d'un seul capteur pour mesurer ?






}


//-------------------------------------------------------------------------


void loop() {
  // put your main code here, to run repeatedly:

  for (uint8_t i = 0; i < SONAR_NUM; i++) {
        if (millis() >= pingTimer[i]) {
          pingTimer[i] += PING_INTERVAL * SONAR_NUM;
          if (i == 0 && currentSensor == SONAR_NUM - 1)
            oneSensorCycle(); // L'action qu'on veut faire , on la met entre ces parenthèses ,ou là :
// The rest of your code would go here./

          sonar[currentSensor].timer_stop();
          currentSensor = i;
          cm[currentSensor] = 0;
          sonar[currentSensor].ping_timer(echoCheck);
        }
      }
      // The rest of your code would go here.  S'agit-il du code de déclenchement des moteurs ?
    }
         void echoCheck() { // si il y a 1 écho, le capteur lit la distance et la met dans son tableau de résultats
      if (sonar[currentSensor].check_timer())
        cm[currentSensor] = sonar[currentSensor].ping_result / US_ROUNDTRIP_CM;
    }
     
    void oneSensorCycle() { // Do something with the results.  //  C'est là qu'on dit d'actionner le moteur correspondant, MAIS comment faire correspondre le moteur voulu avec le numero de capteur ?  

      for (uint8_t i = 0; i < SONAR_NUM; i++) {
        Serial.print(i);
        Serial.print("=");
        Serial.print(cm[i]);
        Serial.print("cm ");
      }
      Serial.println();
    }



Voilà, je vous souhaite une bonne après midi

Vous avez 2 fois Serial.begin(115200);, une seule fois suffit :slight_smile:

oui on conserve MAX_DISTANCE puisque c’est pour cela qu’on l’a défini au début du programme :slight_smile:

Dans cet exemple chaque capteur est lu à tour de rôle, et quand ils ont tous été lus, la fonction oneSensorCycle() est appelée. Dans ce code de démo, cette fonction ne fait qu’afficher la lecture réalisée par chaque capteur.

MAIS comment faire correspondre le moteur voulu avec le numero de capteur ?

la variable i dans la boucle for vous dit si vous êtes en train de regarder le capteur 0 ou le capteur 1

petits commentaires:

  • 3m de distance c’est assez loin… pas sûr que votre capteur va voir le poteau s’il n’est pas très large.

  • prenez l’habitude d’appuyer sur ctrl-T dans l’éditeur de code, ça met le code en forme et c’est plus simple à lire. éviter plein de lignes vide, espacez les blocs fonctionnels pour que ce soit agréable à l’oeil.

Comme ça c’est déjà mieux

#include <NewPing.h>

#define SONAR_NUM     2 // on défini le nombre de capteurs (ici 2 capteurs)
#define MAX_DISTANCE 300 // on définit la distance  Max en cm. (ici 300cm)
#define PING_INTERVAL 33 // en ms

unsigned long pingTimer[SONAR_NUM]; // When each pings.
unsigned int cm[SONAR_NUM]; // Store ping distances.
uint8_t currentSensor = 0; // Which sensor is active.

NewPing sonar[SONAR_NUM] = { // Sensor object array.
  NewPing(4, 5, MAX_DISTANCE),
  NewPing(12, 7, MAX_DISTANCE)
};

//-----------------------------------------------------------------------
// LA FONCTION APPELEE QUAND ON A LU TOUS LES SONARS
//-----------------------------------------------------------------------

void oneSensorCycle()
{
  for (uint8_t i = 0; i < SONAR_NUM; i++) {
    Serial.print(i);
    Serial.print("=");
    Serial.print(cm[i]);
    Serial.print("cm ");
  }
  Serial.println();
}

//-----------------------------------------------------------------------

void echoCheck() // si il y a 1 écho, le capteur lit la distance et la met dans son tableau de résultats
{
  if (sonar[currentSensor].check_timer())
    cm[currentSensor] = sonar[currentSensor].ping_result / US_ROUNDTRIP_CM;
}

//-----------------------------------------------------------------------

void setup()
{
  Serial.begin (115200);  // on utilise 115200 pour l'affichage sur la console série
  pingTimer[0] = millis() + 75;
  for (uint8_t i = 1; i < SONAR_NUM; i++)
    pingTimer[i] = pingTimer[i - 1] + PING_INTERVAL;
}

void loop()
{
  for (uint8_t i = 0; i < SONAR_NUM; i++) {
    if (millis() >= pingTimer[i]) {
      pingTimer[i] += PING_INTERVAL * SONAR_NUM;
      if (i == 0 && currentSensor == SONAR_NUM - 1)oneSensorCycle();
      sonar[currentSensor].timer_stop();
      currentSensor = i;
      cm[currentSensor] = 0;
      sonar[currentSensor].ping_timer(echoCheck);
    }
  }
}

Bonsoir,
D’abord Merci,
J’ai bien lu vos observations, cependant, j’ai vu que vous m’expliquiez que :
“Dans cet exemple chaque capteur est lu à tour de rôle, et quand ils ont tous été lus, la fonction oneSensorCycle() est appelée. Dans ce code de démo, cette fonction ne fait qu’afficher la lecture réalisée par chaque capteur.”
Hors dans mon cas, il faudrait que à chaque case-Etat, il y ait une action .
Je vais limiter à 2 mètres la distance entre le passage de la charrette et le piquet selon votre remarque.
( la finalité ,c’est que la charrette ( tirée par mon âne), que je conduis, puisse passer devant des piquets, et 1)arroser, 2) mettre un peu de fumier, 3) gratter avec un instrument un peu la terre du jardin; actuellement, je dois appuyer sur des boutons de petits moteur et électro-vanne pour cela ).
Donc c’est différent, et j’ai beau y travailler , je ne vois pas comment faire pour accorder tout cela ,
je patauge un peu , beaucoup. :confused:

J’espère beaucoup de votre aide
Bonne Soirée

PS Voici ce que je voudrais obtenir, que j’ai essayer de mettre en code, et votre suggestion(où il y a le setup et le loop, je ne vois pas comment articuler tout cela …

// Reference the I2C Library
#include <Wire.h>
#include <NewPing.h>

/* Utilisation du capteur Ultrason HC-SR04 */
int  relais1;  // relais ar moteur1
int relais2;  //  relais f  moteur2
int relais3;  //  relais e  moteur3
int relais4; //  relais ac  moteur4
int relais5; //  relais f-  moteur2  avec inversion des polarités par rapport a relais2 => tourne dans l'autre sens
int relais6; //  relais e-  moteur3 avec inversion des polarités par rapport a relais3 => tourne dans l'autre sens
int relais7; //  relais ac-  moteur4 avec inversion des polarités par rapport a relais3 => tourne dans l'autre sens

// la liste des états possible de notre système
// ainsi qu'une variable etatCourant prenant une de ces valeurs
enum {REPOS, ETAT_p0, ETAT_p1, ETAT_p2,  ETAT_p3 ,  ETAT_p4 , ETAT_p5 } etatCourant;
//ETAT_ p0 : avant  piquet;
//ETAT_ p1 : capteur 1 devant  piquet;
// ETAT_ p2 : capteur1 a passé le 1er piquet et capteur 2 toujours pas au niveau piquet
//ETAT_ p3 :  capteur 2 devant piquet
//ETAT_ p4 :  APRES 30 secondes
//ETAT_ p5 :  les 2 capteurs ont passé le piquet
// puis retour au stade avant (prochain ) piquet

// ETAT_p0 : aucun moteur ne fonctionne
// ETAT_p1 : mise en route du moteur 4
// ETAT_p2 : le moteur 4 doit rester en marche
// ETAT_p3 : le moteur 4 s'arrete , mise en route des moteurs 2 , 3 et 1 pendant 30 secondes puis s'arretent puis les moteurs 2 et 3 tournent dans l'autre sens pendant 5 secondes
// ETAT_p4 :  le moteur 4 tourne dans l'autre sens pendant 5 seconde puis s'arrete
// retour à l'ETAT_p0 : aucun moteur ne fonctionne

void mettreAuRepos()
{
  digitalWrite(relais1,  LOW);
  digitalWrite(relais2,  LOW);
  digitalWrite(relais3, LOW);
  digitalWrite(relais4,  LOW);
  etatCourant = REPOS;
}

// ------------------------------------------------------
// La fonction de call back, appellée automatiquement quand on clique
// ------------------------------------------------------
void simpleclick() // c'est là que je ne vois pas par quels mots remplacer " simpleclick "  pour les sonars, ce n'est pas un click, mais une distance 'lue' , j'ai essayer de mettre " void distance lue () ", mais ça ne marche pas
{
  switch (etatCourant) {
      digitalWrite(relais1,  LOW);
      digitalWrite(relais2,  LOW);
      digitalWrite(relais3, LOW);
      digitalWrite(relais4,  LOW);
      etatCourant = ETAT_p0; // on note le nouvel état de notre système
      break;


    case ETAT_p0:  //  avant  piquet
      // on était au repos (p0 )et on passe a p1 : le 1er capteur est en face du piquet ,( echo 1er capteur inferieur à 2 metres, et pas d'echo pour le 2ème capteur )
      digitalWrite(relais4, LOW); // moteurs eteints
      digitalWrite(relais1,  LOW);
      digitalWrite(relais2,  LOW);
      digitalWrite(relais3, LOW);
      etatCourant = ETAT_p1; // on note le nouvel état de notre système
      break;

    case ETAT_p1: //capteur 1 devant  piquet
      //  le moteur 4 est alimenté (  pas d'echo pour le capteur 2 )
      digitalWrite(relais4, HIGH); // moteur 4 alimenté
      digitalWrite(relais1,  LOW);
      digitalWrite(relais2,  LOW);
      digitalWrite(relais3, LOW);
      etatCourant = ETAT_p2;// on note le nouvel état de notre système
      break;

     case ETAT_p2: //capteur1 a passé le 1er piquet et capteur 2 toujours pas au niveau du piquet
      //  on arrete le moteur 4
      digitalWrite(relais4,  LOW); // le moteur 4 s'arrete
      digitalWrite(relais2,  LOW);
      digitalWrite(relais3,  LOW);
      digitalWrite(relais1,  LOW);
      etatCourant = ETAT_p3;// on note le nouvel état de notre système
      break;

    case ETAT_p3:   // capteur 2 devant piquet
      digitalWrite(relais4,  LOW); // le moteur 4 arreté
      digitalWrite(relais2, HIGH); //  moteur 2 alimenté
      digitalWrite(relais3,  HIGH); //   moteur 3 alimenté
      digitalWrite(relais1,  HIGH); // mise en route du moteur  1   pendant 30 secondes
     //.... comment utiliser la fonction unsigned long millis() ici pour le moteur 1------?
      etatCourant = ETAT_p4;// on note le nouvel état de notre système
      break;

    case ETAT_p4:     //après les 30 secondes
     //    mise en route des moteurs 2 , 3 , 4  tournant dans l'autre sens pendant 5 secondes
      digitalWrite(relais7,  HIGH); // le moteur 4 tourne dans autre sens  pendant 5 secondes
      digitalWrite(relais5,  HIGH); //  moteur 2 tourne dans autre sens    pendant 5 secondes
      digitalWrite(relais6,  HIGH); //   moteur 3 tourne dans autre sens    pendant 5 secondes
      digitalWrite(relais1,  LOW); //  moteur  1 arreté

      etatCourant = ETAT_p5;// on note le nouvel état de notre système
      break;


    case ETAT_p5: //les 2 capteurs ont passé le piquet
      //le moteur 4 est arreté , mise en route des moteurs 2 , 3 , 4  tournant dans l'autre sens pendant 5 secondes comment coder ceci avec mollis ?
      digitalWrite(relais4,  LOW);
      digitalWrite(relais7,  LOW); // le moteur 4 arreté
      digitalWrite(relais5,  LOW); //  moteur 2 arreté
      digitalWrite(relais6,  LOW); //   moteur 3 arreté
      digitalWrite(relais1,  LOW); //  moteur  1 arreté
      etatCourant = ETAT_p0;// on note le nouvel état de notre système
      break;

      mettreAuRepos(); // on retourne à l'état initial
      break;

  }
}

et votre conseil de code :

#define SONAR_NUM     2 // on défini le nombre de capteurs (ici 2 capteurs)
#define MAX_DISTANCE 300 // on définit la distance  Max en cm. (ici 300cm)
#define PING_INTERVAL 33 // en ms

unsigned long pingTimer[SONAR_NUM]; // When each pings.
unsigned int cm[SONAR_NUM]; // Store ping distances.
uint8_t currentSensor = 0; // Which sensor is active.

NewPing sonar[SONAR_NUM] = { // Sensor object array.
  NewPing(4, 5, MAX_DISTANCE),
  NewPing(12, 7, MAX_DISTANCE)
};

//-----------------------------------------------------------------------
// LA FONCTION APPELEE QUAND ON A LU TOUS LES SONARS
//-----------------------------------------------------------------------

void oneSensorCycle()
{
  for (uint8_t i = 0; i < SONAR_NUM; i++) {
    Serial.print(i);
    Serial.print("=");
    Serial.print(cm[i]);
    Serial.print("cm ");
  }
  Serial.println();
}

//-----------------------------------------------------------------------

void echoCheck() // si il y a 1 écho, le capteur lit la distance et la met dans son tableau de résultats
{
  if (sonar[currentSensor].check_timer())
    cm[currentSensor] = sonar[currentSensor].ping_result / US_ROUNDTRIP_CM;
}

//-----------------------------------------------------------------------

void setup()
{
  Serial.begin (115200);  // on utilise 115200 pour l'affichage sur la console série
  pingTimer[0] = millis() + 75;
  for (uint8_t i = 1; i < SONAR_NUM; i++)
    pingTimer[i] = pingTimer[i - 1] + PING_INTERVAL;
}

void loop()
{
  for (uint8_t i = 0; i < SONAR_NUM; i++) {
    if (millis() >= pingTimer[i]) {
      pingTimer[i] += PING_INTERVAL * SONAR_NUM;
      if (i == 0 && currentSensor == SONAR_NUM - 1)oneSensorCycle();
      sonar[currentSensor].timer_stop();
      currentSensor = i;
      cm[currentSensor] = 0;
      sonar[currentSensor].ping_timer(echoCheck);
    }
  }
}