Programmation Automate fini / Machine à état

content que cela ait pu vous aider! bonne année 2019 et bons bidouillages

Merci à l'auteur !

Bonjour J-M-L

Merci pour le tuto que je suis en train de mettre en pratique

dans le switch case faut-il programmer une chronologie des différents états du système? En me basant sur le 1er exemple, je vois bien une relation chronologique que j'ai tenté de mettre en gras ci-dessous:

case REPOS: // on était au repos et on a un appui, on allume la verte
      digitalWrite(pinLedVerte, HIGH); // LED verte alimentée
      etatCourant = [b]ETAT_V[/b]; // on note le nouvel état de notre système
      break;

    case [b]ETAT_V[/b]: // on était led verte allumée et on a un appui, on allume la jaune
      digitalWrite(pinLedJaune, HIGH); // LED jaune alimentée
      etatCourant = [b]ETAT_VJ[/b];// on note le nouvel état de notre système
      break;

    case [b]ETAT_VJ[/b]: // vert et jaune allumées, on a un appui, on allume la orange
      digitalWrite(pinLedOrange, HIGH); // LED orange alimentée
      etatCourant = [b]ETAT_VJO[/b];// on note le nouvel état de notre système
      break;

ou alors faut'il simplement lister tous les cases possibles ? (ET à condition qu'on les retrouvent dans le enum ) Merci

Bonjour Une approche possible est de lister les états et pour chaque état regarder sur le dessin quelles sont les transitions possibles, de sont celle là que l’on code dans chaque case.

Bonjour J_M_L , suite a vos recommandation j'ai lu votre tuto qui m'a beaucoup appris , j'ai tout de meme une question , avec la librairy Onbutton dont vous vous servez j'ai l'impression qu'elle porte bien son nom , il n'est pas possible d'utiliser un second bouton ? exemple ( j'allume les leds avec le bouton1 et je les éteint en sens inverse avec le 2 ).

si si vous pouvez en instanciez autant que vous voulez. voici un des exemples de la bibliothèque avec 2 boutons.

vous aurez à gérer des événements pour chaque bouton donc des transitions dans la machine à états

il y aussi la librairie de @bricoleau qui est très compacte.

Salut ,

c ' est vraiment enorme votre code dans ce tuto !

avec si peu de lignes de code arriver a gerer tout ca , ca fait des mois que je relis ce tuto , et je le trouve toujours aussi fascinant !

maintenant que je commence a comprendre la technique ca me semble bien plus clair !

Cependant j ' ai une question :P Hors mis le fait que le code se boit comme du petit lait et qu ' il apparait tres simple grace aux bibliotheques utilisées , ceci evidement afin de mettre en evidence le sujet du tuto a savoir la machine a etats , j ' aimerais avoir une idée des avantages que l' on peut tirer de coder de cette maniere sur par exemple un serveur volet roulant interactif ( voir mon projet )

serait il possible de par exemple definir si le volet est dans une position ouverte , fermée ou intermediaire ? il me semble que oui : enum :uint8_t {INTERM, OUVERT, FERME} position; ?

est ce que si j ' implemente la machine a etats dans mon serveur volet roulant , je pourrais par exemple n ' avoir qu un seul bouton afficher a la place de ouvrir et fermer actuellement en fonction de l ' etat de la position ?

par exemple , je sais grace a la machine a etat que je suis en position fermée avec mon volet , donc je n ' affiche sur le serveur que la possibilité de l ' ouvrir et inversement bien sur .

comment vous faites vos jolis diagrammes ?

iznobe: serait il possible de par exemple definir si le volet est dans une position ouverte , fermée ou intermediaire ? il me semble que oui : enum :uint8_t {INTERM, OUVERT, FERME} position; ?

est ce que si j ' implemente la machine a etats dans mon serveur volet roulant , je pourrais par exemple n ' avoir qu un seul bouton afficher a la place de ouvrir et fermer actuellement en fonction de l ' etat de la position ?

par exemple , je sais grace a la machine a etat que je suis en position fermée avec mon volet , donc je n ' affiche sur le serveur que la possibilité de l ' ouvrir et inversement bien sur .

comment vous faites vos jolis diagrammes ?

Salut - merci pour les commentaires — j'ai les chevilles qui enflent! :)

Oui bien sûr vous pouvez avoir une petite machine à état par volet avec vos 3 états. Vous pourriez en avoir 5 sans doute enum :uint8_t {OUVERT, FERME, EN_MONTEE, EN_DESCENTE, ARRET_INTERMEDIAIRE} position;

Les jolis dessins c'est avec keynote - une app (un peu comme powerpoint) qui est fournie gratuitement avec les macs. je fais mon petit schéma, je le copie, et le sauve en format image avec transparence (png) et voilà :)

Merci pour ces infos , pour keynote il n ' y a pas d' equivalent linux ?

j' essaierai avec gimp 2.0 il fait pas mal de choses , un peu trop meme mais bon ...

ben j'utilise un mac parce que justement la productivité c'est plus pratique que sur Linux et j'ai UNIX quand j'en ai besoin... donc je ne sais pas trop. Sans doute que LibreOffice doit savoir faire plein de trucs

Bonsoir

un logiciel de dessin vectoriel parait preférable à GIMP pour ce genre de choses Libre Office Impress peut être vu comme équivalent à Keynote Libre Office Draw permet de faire ce type diagramme d'état , (c'est pour moi l'outil de tous les jours pour produire des documents avec des illustrations, Impress étant réservé aux diapos.) DIA Diagram Editor aussi. yED , multiplatefome, est interessant pour la variété de diagrammes qu'il permet de faire ... il y a du choix.... https://www.tecmint.com/best-flowchart-and-diagramming-software-for-linux/

al1fch: Bonsoir

un logiciel de dessin vectoriel parait preférable à GIMP pour ce genre de choses Libre Office Impress peut être vu comme équivalent à Keynote Libre Office Draw permet de faire ce type diagramme d'état , (c'est pour moi l'outil de tous les jours pour produire des documents avec des illustrations, Impress étant réservé aux diapos.) DIA Diagram Editor aussi. yED , multiplatefome, est interessant pour la variété de diagrammes qu'il permet de faire ... il y a du choix.... https://www.tecmint.com/best-flowchart-and-diagramming-software-for-linux/

C ' est noté !

Merci pour vos conseils , je testerai cela des que j' ai un peu de temps voir si j ' arrive a quelquechose .

Merci beaucoup .

Bonsoir à tous, Petite question, votre exemple marche avec la librairie OneButton. , car on passe d'un état à un autre en appuyant sur un bouton. Cependant lorsque on veut utiliser non un bouton , mais un capteur, qui lors d'une lecture (par exemple distance ) commande le changement pour une valeur , on ne peut utiliser la librairie OneButton. , alors comment peut-on faire ? Merci

C’est juste un événement à traiter Vous testez les conditions qui sont sur les transitions entre états

bonjour, c’est dommage que ce cours très intéressant est été amputé de ses illustrations.

Machine à état.zip (1.2 MB) pour ceux qui comme moi trouvent ce cours super, en voici la sauvegarde.

merci - l’équipe Arduino est en train de réparer les images qui ont été corrompues lors du passage au nouveau logiciel du forum. ça devrait revenir dans l’ordre d’ici quelques temps

1 Like

Re,
par contre les librairies c’est super bien, mais ça gâche pas mal la compréhension. J’ai voulu pour apprendre me passer de la librairie bouton, et là c’est le drame. rien ne fonctionne, j’ai pourtant cru que c’était possible d’appeler une fonction avec un appui. si j’amais je pouvais être aiguillé ? merci.

const byte LeboutonPin4 = 4; // notre bouton est sur la pin 4
const byte LeboutonPin3 = 3; // un autre bouton est sur la pin 3
byte etatBoutonPin4 = 0; // pour enregistrer l'état du bouton 4
byte etatBoutonPin3 = 0; // pour enregistrer l'état du bouton 3

// les pins utilisées pour les LEDs
const byte pinLedRouge = 8;
const byte pinLedOrange = 9;
const byte pinLedJaune = 10;
const byte pinLedVerte = 11;

// On introduit le temps comme évènement supplémentaire
unsigned long chrono; // attention, type unsigned long comme millis()
const unsigned long TimeOut = 15000ul; // 15 secondes (le ul à la fin pour unsigned long)

// la liste des états possible de notre système
// ainsi qu'une variable etatCourant prenant une de ces valeurs
enum {REPOS, ETAT_V, ETAT_VJ, ETAT_VJO, ETAT_VJOR} etatCourant;

// ------------------------------------------------------
// On initialise notre système dans le setup
// ------------------------------------------------------
void setup() {
  pinMode (pinLedRouge,  OUTPUT);
  pinMode (pinLedOrange, OUTPUT);
  pinMode (pinLedJaune,  OUTPUT);
  pinMode (pinLedVerte,  OUTPUT);
  pinMode (LeboutonPin4,  INPUT);
  pinMode (LeboutonPin3,  INPUT);
  //conditions Initiales
  mettreAuRepos();
}

// ------------------------------------------------------
// Cette fonction installe l'état initial
// ------------------------------------------------------
void mettreAuRepos()
{
  digitalWrite(pinLedVerte,  LOW);
  digitalWrite(pinLedJaune,  LOW);
  digitalWrite(pinLedOrange, LOW);
  digitalWrite(pinLedRouge,  LOW);
  etatCourant = REPOS;
}

// ------------------------------------------------------
// La fonction appelée automatiquement quand on clique
// ------------------------------------------------------
void boutonPin4()
{
  switch (etatCourant) {
    case REPOS: // on était au repos et on a un appui, on allume la verte
      digitalWrite(pinLedVerte, HIGH); // LED verte alimentée
      etatCourant = ETAT_V; // on note le nouvel état de notre système
      break;

    case ETAT_V: // on était led verte allumée et on a un appui, on allume la jaune
      digitalWrite(pinLedJaune, HIGH); // LED jaune alimentée
      etatCourant = ETAT_VJ;// on note le nouvel état de notre système
      break;

    case ETAT_VJ: // vert et jaune allumées, on a un appui, on allume la orange
      digitalWrite(pinLedOrange, HIGH); // LED orange alimentée
      etatCourant = ETAT_VJO;// on note le nouvel état de notre système
      break;

    case ETAT_VJO:// vert, orange et jaune allumées, on a un appui, on allume la rouge
      digitalWrite(pinLedRouge, HIGH); // LED rouge alimentée
      etatCourant = ETAT_VJOR;// on note le nouvel état de notre système
      break;

    case ETAT_VJOR: // tout était allumé, on a un appui, on retourne au repos
      mettreAuRepos(); // on retourne à l'état initial
      break;
  }
  chrono = millis(); // on vient d'avoir une action donc on réarme notre chronomètre
}

// ------------------------------------------------------
// La fonction appelée automatiquement quand on clique
// ------------------------------------------------------
void boutonPin3()
{
  switch (etatCourant) {
    case REPOS:    // dans tous les états
    case ETAT_V:   // sauf celui où tout était allumé
    case ETAT_VJ:  // en cas de double click on veut
    case ETAT_VJO: // allumer toutes les LEDs
      digitalWrite(pinLedVerte, HIGH);
      digitalWrite(pinLedJaune, HIGH);
      digitalWrite(pinLedOrange, HIGH);
      digitalWrite(pinLedRouge, HIGH);
      etatCourant = ETAT_VJOR;  // et on déclare notre nouvel état courant
      break;

    case ETAT_VJOR: // on a tout qui est allumé et on reçoit le double click
      mettreAuRepos(); // donc on retourne à l'état de repos
      break;
  }
  chrono = millis(); // on vient d'avoir une action donc on ré-arme notre chronomètre
}

// ------------------------------------------------------
// La fonction de appellée en cas de dépassement du délai
// (on pourrait aussi faire un if (etatCourant != REPOS) mettreAuRepos(); )
// ------------------------------------------------------
void timeOut()
{
  /* // version longue si on veut le switch case
    switch (etatCourant) {
    case ETAT_V:    // pour tous les états
    case ETAT_VO:   // sauf celui au repos
    case ETAT_VOJ:  // on doit tout éteindre
    case ETAT_VOJR: // et revenir à l'état initial
      mettreAuRepos(); // ce que fait cette fonction
      break;
    }
  */
  // version courte, si on n'est pas au repos, alors passer au repos
  if (etatCourant != REPOS) mettreAuRepos();

  // à noter que le timeOut continuera de se déclencher toutes les 15 secondes
  // mais ne fera rien puisqu'on sera au repos
  // ça peut être utile pour continuer à faire autre chose
  // sinon il faut tester avant de l’appeler qu’on n’est pas au repos
}

  void loop() {
    // On vérifie l'état des boutons, ce qui déclenche l'appel d'une des fonctions nécessaire
    etatBoutonPin4 = digitalRead(LeboutonPin4);
    if (etatBoutonPin4 == HIGH) {
      boutonPin4();
    }

    etatBoutonPin3 = digitalRead(LeboutonPin3);
    if (etatBoutonPin3 == HIGH) {
      boutonPin3();
    }

  // On vérifie le timer et on déclenche l'évènement si nécéssaire
  // rajouter dans la condition “&& (etatCourant != REPOS)” si vous ne souhaitez pas
  // appeler la fonction au repos
  if (millis() - chrono >= TimeOut) {
    timeOut();
    chrono = millis(); // on ré-arme notre chronomètre
  }

  // ici on peut faire autre chose du moment que ça ne prend pas trop longtemps

}

quand vous regardez digitalRead(LeboutonPin4) vous surveillez l’état de la pin. L’appui sur le bouton c’est une transition d’état (on passe de HIGH à LOW). Donc détecter l’appui ce n’est pas juste voir si c’est LOW, c’est voir si c’est LOW ET que c’était HIGH avant (et c’est sans parler des rebonds, il faut que ce soit une transition stable depuis un moment).

→ si vous voulez vous passer de la bibliothèque il faut écrire une petite machine à état qui surveille l’état des boutons (et c’est ce que font déjà très bien la librairie de @bricoleau oula librairie OneButton de Matthias Hertel donc pas sûr de vouloir réinventer la roue pour cela).

merci beaucoup. Donc on ne peut pas appeler une fonction sur l’appui d’un bouton ? on ne peut que déclencher des actions ? genre appui bouton = allumer led ok, mais appui bouton lance la fonction c’est pas possible ? j’ai bien compris ? même si je trouve ça vraiment curieux. :sweat_smile: