Discussion houleuse (?) sur Les machines à état :)

Voilà un topic qui semble déchainer les foules :slight_smile:

5_cylindres:
tu dis (message #107)
OK, je te suis :
la TV est allumée,
le bouton on/off est appuyé --> j'éteins la TV
MAIS
le doigt est toujours sur le BP, donc je rallume la TV, puisque le BP est appuyé ... et pourtant, mon vieux machin d'il y a 12 ans (full hd quand même, mais même le CRT que j'avais il y a 35 ans) ne se rallume pas dans la foulée, donc "y'a un truc".

moralité :
il faut bien, même dans une machine à états finis bien carrée, déterminer si le BP a été entre-deux relâché ou pas !

mais tu vas me dire que ta machine possède un état "intermédiaire" qui vérifie l'état relâché du BP ... donc on en revient bien toujours au même : l'état précédent.

Comme expliqué plusieurs fois dans la discussion tout dépend de ce que vous appelez le système (ce que la machine à états finis pilote) et de la granularité des événements.

Par exemple la télécommande ne renvoie pas l'évènement bouton appuyé. C'est le cas de nombreuses télécommandes du marché elles renvoient un code différent qui dit 'même bouton toujours appuyé'). C'est le cas de la bibliothèque Keypad par exemple qui ne renvoie pas par défaut deux fois de suite le même évènements si vous n'avez pas relâché. De même la bibliothèque OneButton n'appelle pas le call back deux fois de suite.

==> Donc mon système ne recevrait pas d'évènement.

Comment ça marche ? il y a souvent une autre machine à états qui pilote un autre système, ici la télécommande, le keypad, la bibliothèque OneButton etc...

5_cylindres:
réponse à la modif de ton post précédent pendant que j'écrivais :
non, réponse pas claire, je ne sais toujours pas comment tu fais, toi, pour définir un changement d'état sans mémoriser l'état précédent ... à moins que tu n'aies un "état intermédiaire" comme je l'écris plus haut ... ce qui revient à mémoriser l'état précédent dans ma façon de faire.

Si vous englobez la gestion de la télécommande dans votre système alors vous pilotez deux machines à états en parallèle. Celle de la télécommande a "sa vie propre".

De plus Dans le cas d'un bouton imparfait (avec rebonds) la connaissance de ce que vous appelez "l'état précédent" (lecture HIGH ou LOW ?) n'est pas suffisant il vous faut savoir si vous êtes en période de rebonds d'appui ou de relâchement par exemple, donc bien gérer un état indépendant de l'événement HIGH ou LOW sur le bouton et une autre notion d'évènements, le temps. L'état précédent ne se résume pas à la valeur de la tension lue lors de la boucle précédente.

Pour moi ça ressemblerait plus à cela donc

OK, là, tes explications sont déjà plus claires, tout est enfin posé à plat d'une façon facile à comprendre.

pour que greglamouche capte tout bien comme ici, c'est ça qu'il fallait écrire dans son topic plutôt que t'acharner sur ma façon de faire ... qui soit dit en passant n'est pas moins efficace que celle que tu emploies, elles peuvent même être complémentaires.

quand je pense qu'au départ je ne me suis mêlé à ce topic que pour étayer les idées d'un autre, qui m'a lui-même taclé par la suite !

je retourne jouer aux légos avec mon petit-fils.

J'appuie juste un peu.

On pourrait appliquer la gestion par machine à états au cas d'un bouton ou d'un capteur fin de course.
Imaginons que ce contact n'ait pas de rebonds (anti-rebonds à condensateur par exemple).
Imaginons que la lecture soit effectuée dans une routine d'interruption. Il y aura donc une interruption RAISING et une interruption FALLING pour chaque appui / relâché. Chaque interruption est un événement.

La machine d'état est dans l'état OFF.
On appuie : un événement APPUYÉ est généré.
La machine exécute une action (ou pas).
La machine d'état passe dans l'état ON.
On relâche : un événement RELÂCHÉ est généré.
La machine exécute une action (ou pas).
La machine d'état passe dans l'état OFF.
etc.

Il n'y a donc qu'un seul état à gérer.

Bien évidemment les actions exécutées par cette machine à états peuvent envoyer un événement BOUTON_APPUYÉ ou BOUTON_RELÂCHÉ (ou les deux) à une autre machine à états située à plus haut niveau.

J-M-L:
Si vous englobez la gestion de la télécommande dans votre système alors vous pilotez deux machines à états en parallèle. Celle de la télécommande a "sa vie propre".

Nous avons la chance d'avoir à disposition un compilateur C++. Autant s'en servir.

Un machin qui a sa vie propre, j'en fait un objet (instance d'une classe).
Cet objet me rend les services que j'ai décidé. En l'occurence m'informer d'un événement significatif pour mon projet. Selon le projet, il sera significatif de savoir si tel bouton reste appuyé, ou si seul l'appui compte.
Si l'appareil génère des difficultés, telles que des rebonds de bouton, c'est son problème : tout est encapsulé dans la classe.
Si ce périphérique fonctionne selon une machine à état, celle si sera encapsulée aussi.

Si le niveau supérieur, le système, est aussi une machine à état, les états du sytème ne se mélangent pas avec les états du bouton. D'ailleurs le système ignore même que la télécommande a des états (d'âme?). Tout ce qu'il sait c'est que la télécommande lui envoie des événements significatifs, rien d'autre.

A tel point que le code de la télécommande et celui du système peuvent être écrits par des personnes différentes.

[Edit] et le jour où je dois changer de modèle de télécommande, je ne touche pas à une seule ligne du code du système. Et ça ... j'achète ! :slight_smile:

Cela devient donc une machine à états étages ... :slight_smile:

biggil:
A tel point que le code de la télécommande et celui du système peuvent être écrits par des personnes différentes.

c'est ce que j'appelle la granularité des événements

Dans le code que j'ai proposé j'utilise la bibliothèque de Bricoleau et un état qui sert de mémoire. Je n'ai donc ni à tester ni connaître l'état précédent pour prendre des décisions de transition d'état.

================================

Je ne vous ai pas 'taclé' - j'ai juste dit que ce n'était pas tel que vous l'exprimiez. Pas ma faute si vous l'avez pris comme cela...

Quand vous dites

c'est la comparaison entre l'état actuel et l'état précédent qui met en avant l'événement

ce n'est pas vraiment applicable

Le système que j'avais proposé:

et la machine à état pour ce système:

On voit par exemple qu'il y a 2 évènements qui permettent de passer de l'état VIDANGE à l'état MISE A NIVEAU. Donc connaitre "l'état précédent" et "l'état courant" ne suffit pas pour dire quel évènement s'est produit.

ça marche pour moi dans l'autre sens: je suis dans un état VIDANGE, je surveille une liste connue d'évènements pertinents (ici expiration d'un timeout ou bac à vidange plein) et dans ce cas je passe en l'état MISE A NIVEAU après avoir éteint une pompe et allumé l'autre (mention oubliée d'ailleurs dans le graphe)

J-M-L:
==> Je ne vous ai pas 'taclé' - j'ai juste dit que ce n'était pas tel que vous l'exprimiez. Pas ma faute si vous l'avez pris comme cela...

? ? ? ? ? ? ? ? ? ?
J'ai dit quelque part que j'avais été taclé ? ? ?
Vraiment pas compris, là ...

On voit par exemple qu'il y a 2 évènements qui permettent de passer de l'état VIDANGE à l'état MISE A NIVEAU. Donc connaitre "l'état précédent" et "l'état courant" ne suffit pas pour dire quel évènement s'est produit.

Depuis des jours on ne parle plus de la même chose.
Les états dont tu parles sont ceux du système complet.
Ceux dont je parle sont ceux du bouton (ou du flotteur, ou de la télécommande...)

Mémoriser l'état du système ne servira effectivement pas à savoir si un événement s'est produit.
Mais pour le bouton, j'ai besoin de l'état précedent pour déclencher (ou pas) l'évenement.

J’ai dit quelque part que j’avais été taclé ? ? ?
Vraiment pas compris, là …

dsl - c’était 2 réponses séparées dans le même post

biggil:
Depuis des jours on ne parle plus de la même chose.
Les états dont tu parles sont ceux du système complet.
Ceux dont je parle sont ceux du bouton (ou du flotteur, ou de la télécommande…)

oui effectivement je parlais du système complet. il me semblait avoir été clair sur ce point mais sans doute pas assez.

biggil:
Mémoriser l’état du système ne servira effectivement pas à savoir si un événement s’est produit.
Mais pour le bouton, j’ai besoin de l’état précedent pour déclencher (ou pas) l’évenement.

On peut discuter sur la notion de précedent - c’est relatif.
Pour moi il n’y a qu’un état courant et un état futur si on déclenche une transition, l’état précédent serait pour moi l’état avant l’état courant, donc celui avant la dernière transition. Mais je comprends et suppose que vous voulez dire “état lors de la loop précédente”

Après je ne suis pas sûr de bien comprendre ce que recouvre la notion d’état pour vous. Si c’est juste HIGH ou LOW alors ce que j’essaye de dire c’est que ça ne suffit pas à caractériser le système ‘bouton’ pour envoyer des évènements au bon niveau d’abstraction.

Mon bouton est il au repos, en train de rebondir sur appui, appuyé, en train de rebondir sur relâchement ? avait-il déjà marqué une transition d’appui il n’y a pas longtemps (pour calcul de double click) ?
==> En fonction de la connaissance de l’état courant du bouton et de l’état du système et d’une mesure du temps, je suis capable où non de déclencher l’évènement (simple click, double click, appui long, …). C’est donc le couple (temps + “état” (mais pas juste HIGH ou LOW)) qui permet de prendre une décision, c’est ce qu’un état modélise.

Je suis épuisé.
Je passe mon tour.

bon je vais essayer de simplifier:

Si le système est un bouton, on peut en lisant sa valeur HIGH ou LOW dire s'il est appuyé ou pas.

Si on connait la valeur précédente et qu'elle diffère de la valeur actuelle on peut dire qu'il y a eu une transition HIGH - LOW ou LOW - HIGH.

Je suis d'accord et je pense que c'est ce que vous voulez dire.

Ce que je dis c'est que la connaissance de cette transition n'est pas suffisante pour caractériser l'état du bouton (donc du système). On peut avoir une transition LOW HIGH ou HIGH LOW à cause des rebonds lors de l'appui ou du relâchement.

Donc si l'état précédent se limite à la mémorisation de HIGH ou LOW, on ne peut pas décider de quel événement est en cours à la lecture d'une transition. il faut mémoriser autre chose.

c'est plus clair ?

Une différence entre "état" et "événement" en quelque sorte ?

Oui - c'est pour cela que je propose dans mon tuto d'utiliser une bibliothèque pour la gestion des boutons. C'est la bibliothèque qui implémente une petite machine à état pour la gestion du bouton et donne une granularité des évènements au bon niveau pour l'autre machine à état.

C'est exactement ce que je dis dans mon post #4
Comme tu dis : "il me semblait avoir été clair sur ce point mais sans doute pas assez."

Ok - je conçois que vous puissiez le penser.

Ça change ensuite rien au fait que la détection de transition - sans information complémentaire mémorisée - ne suffit pas à gérer un bouton qui a des rebonds.

C’était mon point de désaccord. Il faut pour cela une notion d’état plus complète d’où l’intérêt de sérialiser les problèmes et de confier la gestion du bouton à une bibliothèque qui émet des événements de plus haut niveau.

J-M-L:
Ça change ensuite rien au fait que la détection de transition - sans information complémentaire mémorisée - ne suffit pas à gérer un bouton qui a des rebonds.

[humour]
Oui mais avec un petit condensateur pas besoin de bibliothèque pour les rebonds du bouton :slight_smile:
[humour/]

OK -> je sors :slight_smile:

68tjs:
[humour]
Oui mais avec un petit condensateur pas besoin de bibliothèque pour les rebonds du bouton :slight_smile:
[humour/]

OK -> je sors :slight_smile:

et oui :slight_smile:

Bah.... pas de boutons, pas de rebonds.....

Je sors également :smiley:

J-M-L:
Ça change ensuite rien au fait que la détection de transition - sans information complémentaire mémorisée - ne suffit pas à gérer un bouton qui a des rebonds.

C’était mon point de désaccord.

Il n'y a jamais eu de désaccord.
Nous étions dans une discussion houleuse(?) sur la nécessité de garder un état "précédent" et sur comment l'appeler...
Je dit qu'il faut garder une mémoire (la fourmi).
Mais il faut n'est pas il suffit.

Le pourtant si simple bouton poussoir est un bien mauvais exemple canonique, avec ses foutus rebonds.
Il est bien évident qu'une seule info on/off ne suffit pas à le gérer, qu'il faut lui écrire sa petite machine à états à lui...
Qu'il faut planquer tous les boyaux dans une classe (pas besoin de faire un bibliothèque, la classe peut aller dans le .ino)

J-M-L:
Oui - c'est pour cela que je propose dans mon tuto d'utiliser une bibliothèque pour la gestion des boutons. C'est la bibliothèque qui implémente une petite machine à état pour la gestion du bouton et donne une granularité des évènements au bon niveau pour l'autre machine à état.

C'est pour ça aussi que dans ma librairie, il y a une classe dédiée à la gestion d'un bouton, qui contient elle-même une machine à états qui renvoie différent événements : click, appui long, double click, relaché.
En séparant ainsi ça permet (comme en utilisant une lib externe) dans la machine à états principale d'un programme de se concentrer sur l'essentiel, sans y mélanger des mémoires d'état de boutons ou autre... sinon ça devient illisible