Modèles de conception d’applications : Machines à états

Aperçu

La machine à états est l’une des architectures fondamentales fréquemment utilisées par les développeurs de LabVIEW pour créer rapidement des applications. L’architecture de machine à états peut être utilisée pour implémenter des algorithmes de prise de décision complexes représentés par des diagrammes d’états ou des organigrammes. Une machine à états peut être implémentée à l’aide des fonctions natives LabVIEW ; aucun toolkit ou module supplémentaire n’est requis pour l’architecture.

 

Cet article explore la définition d’une machine à états, des exemples de cas d’usage, des exemples conceptuels d’une machine à états et des exemples de code d’une machine à états.

 

Consultez une présentation destinée aux développeurs pour voir une présentation du modèle Machine à états simple.

Contenu

Qu'est-ce qu'une machine à états ?

Une machine à états est une architecture de programmation qui permet un flux dynamique vers des états en fonction des valeurs des états précédents ou des entrées utilisateur.

Ce modèle est bien adapté aux applications qui peuvent être décrites comme une combinaison des éléments suivants :

  • États
  • Logique décisionnelle qui détermine quand passer à un état particulier.


Un état peut être défini comme l’état au sein du programme tout en exécutant la tâche globale du programme ; des exemples d’état peuvent être l’initialisation, l’attente, l’exécution d’un calcul, la vérification de l’état, etc.

Les instructions logiques aident à déterminer quand passer à un nouvel état et à quel état passer. Les événements peuvent être utilisés pour déclencher le passage d’un état à l’autre ; ils peuvent être des événements programmatiques ou définis par l’utilisateur, comme d’appuyer sur un bouton.

Chaque état d’une machine à états fait quelque chose d’unique et appelle d’autres états. La communication d’état dépend d’une condition ou d’une séquence. Pour traduire le diagramme d’états en une architecture de programmation LabVIEW, vous avez besoin de l’infrastructure suivante :

  1. Boucle While – exécute en continu les différents états
  2. Structure Condition : chaque condition contient du code à exécuter pour chaque état
  3. Registre à décalage : contient des informations de transition d’état
  4. Code de transition : détermine l’état suivant de la séquence (voir la section Exemples de codede transitionci-dessous)

Pourquoi utiliser une machine à états ?

Les machines à états sont utilisées dans des applications où des états distincts existent. Chaque état peut conduire à un ou plusieurs états et peut également terminer le flux de processus. Une machine à états repose sur l’entrée utilisateur ou le calcul en état pour déterminer l’état à passer. Les applications requièrent un état « initialiser », suivi d'un état par défaut, dans lequel de multiples actions peuvent être effectuées. Les actions effectuées peuvent dépendre des entrées et des états précédents et actuels. Un état « d’arrêt » peut ensuite être utilisé pour effectuer des actions de nettoyage.

En plus de sa puissante capacité à implémenter des algorithmes de prise de décision, les machines à états sont également des formes fonctionnelles de planification d’applications. Au fur et à mesure que les applications se développent, le besoin d’une conception adéquate s’est également amélioré. Les diagrammes d’état et les organigrammes sont utiles et parfois essentiels pour le processus de conception. Les machines à états sont non seulement avantageuses pour la planification des applications, mais aussi faciles à créer.

Cas d'usage

Par exemple, les applications suivantes peuvent bénéficier du modèle Machine à états :

  • Boîtes de dialogue à page unique ou à onglets. Chaque onglet de la boîte de dialogue correspond à un état. Un utilisateur initie des transitions d'état en cliquant sur un onglet particulier. Les actions que l'utilisateur peut effectuer pour chaque état sont incluses dans l'état.
  • Un distributeur automatique de billets (DAB). Les états de cette application peuvent inclure l'attente d'entrée utilisateur, la vérification du montant demandé par rapport au solde du compte, la distribution des billets, l'impression d'un reçu, etc.
  • Une application qui relève une mesure, l'enregistre dans un fichier sur disque puis attend une autre action utilisateur. Les états de cette application peuvent inclure l'attente d'entrée utilisateur, le relevé de la mesure, l'enregistrement des données, l'affichage des données, etc.
  • Les machines à états sont le plus souvent utilisées lors de la programmation d’interfaces utilisateur. Lors de la création d’une interface utilisateur, différentes actions de l'utilisateur envoient l'interface utilisateur dans différents segments de traitement. Chacun de ces segments agira comme des états dans la machine à états. Ces segments peuvent conduire à un autre segment pour poursuivre le traitement ou attendre une autre action de l'utilisateur. Dans cet exemple, la machine à états surveille constamment l’action suivante prise par l’utilisateur.
  • Le test de processus est une autre application courante des machines à états. Dans cet exemple, chaque segment du processus est représenté par un état. Un état différent peut être appelé en fonction du résultat du test de chaque état. Cela peut se produire en continu, effectuant ainsi une analyse détaillée du processus testé.


Il existe un autre modèle de conception qui peut être utilisé pour implémenter une interface utilisateur, le Gestionnaire de messages dans une file d’attente. Un gestionnaire de messages dans une file d’attente est une version plus sophistiquée de la machine à états et offre une flexibilité supplémentaire, mais il ajoute également une complexité supplémentaire. 

Création d'une machine à états

La création d’une machine à états efficace nécessite que le concepteur (1) crée une liste d’états possibles. Avec cette liste, le concepteur peut (2) planifier comment chaque état est lié à un autre. Ensuite, le diagramme d’états peut (3) être traduit en architecture de programmation graphique LabVIEW.

Exemple : Tirer un canon

Dans cet exemple, nous voulons générer une application qui tire un canon de façon continue sans le laisser chauffer dangereusement.

(1) Énumérer les états possibles
Pour commencer, nous créons une liste de tous les états possibles pour notre tâche. Pour accomplir la tâche de tirer le canon de façon continue, vous devrez :

  • Initialiser le programme
  • Allumer le canon
  • Tirer les canons
  • Vérifier la température (l’état) du périphérique
  • Refroidir le périphérique passif (si la température est toujours dans la gamme, mais en augmentation)
  • Refroidir activement le périphérique (si la température est hors de la gamme)
  • Arrêter le périphérique
     

(2) Mapper les relations entre les états dans un diagramme d’états
Ensuite, nous examinerons comment ces états sont liés les uns aux autres et nous créerons un diagramme d’états. Lors de la création du diagramme d’états, envisagez ce qui entraînerait le programme à passer d’un état à l’autre : est-ce une transition automatique ? Y a-t-il un déclenchement externe de l’utilisateur ? La transition est-elle basée sur le résultat d’un calcul ?

Par exemple, examinons les relations entre l’état d’initialisation et les autres états.

  1. L’initialisation est la première étape du programme. Il n’y aura aucune entrée pour cet état.
  2. Une fois initialisée, si aucune erreur n’est présente, nous passerons à l’alimentation du canon.
  3. S’il existe des erreurs, fermez le programme
  4. Si l’utilisateur appuie sur un bouton stop pendant l’initialisation, nous voulons passer à l’état d’arrêt.

Notezque tout en réfléchissant à la façon dont les états sont liés entre eux, nous avons commencé à définir la logique permettant de passer entre ces états. La logique de programmation que nous utiliserons dans le code dépend (1) du nombre d’états de transition possibles et (2) du nombre d’entrées prises en compte dans la logique. Les options de transition de code sont discutées ci-dessous dans la section Exemples de code de transition.

Continuez à explorer comment les états se lient entre eux jusqu’à ce que vous disposiez d’un diagramme d’états complet. Le diagramme d’états comprendra tous les états et leurs relations (Figure 1). Notez que dans ce diagramme, les états (nœuds ovales) décrivent les actions effectuées lorsque le processus de contrôle est dans cet état, tandis que les transitions (flèches) décrivent simplement quand et comment le processus peut passer d’un état à l’autre.

Figure 1 : Diagramme d’états du tir d’un canon

La relation entre chaque état vous aidera à programmer la logique nécessaire pour passer d’un état à l’autre.

(3) Construire une machine à états dans LabVIEW
Après avoir défini les états et leur relation dans un diagramme d’états, vous pouvez traduire cela en architecture de codage dans LabVIEW (Figure 2). Le flux entre les états du diagramme d’états (Figure1) est implémenté par la boucle. Les états individuels sont remplacés par des conditions dans la structure Condition. Chaque état du diagramme représenté ci-dessus correspond à un sous-diagramme de la structure Condition. Chaque état :

  1. Effectue une certaine action
  2. Indique à la machine à états quel est l'état suivant en passant une instruction à un registre à décalage de la boucle While (par ex. code de transition)


Un registre à décalage sur la boucle While suit l’état actuel, qui est alimenté dans l’entrée de la structure Condition.

Figure 2 : Machine à états

Exemple de programme de machine à états

Reportez-vous au projet échantillon Mesure à mono-déclenchement, disponible à partir de la boîte de dialogue Créer un projet, pour voir un exemple d'adaptation de ce modèle à une application de mesure.

  • Après l’initialisation, la machine à états passe à l'état Attendre un événement. Cet état contient une structure Événement qui attend les changements sur la face-avant. Lorsque l'utilisateur clique sur un bouton, LabVIEW reconnaît l'événement et passe au sous-diagramme approprié de la structure Événement. Ce sous-diagramme initie une transition vers l'état approprié.
  • Chaque état a accès à un cluster de données. Les types de données de ce cluster sont définis dans Data.ctl.
  • Les états valides sont répertoriés dans la définition de type State.ctl. L'utilisation d'une définition de type pour les transitions d'états limite les transitions que vous pouvez utiliser et par conséquent minimise le risque pour la machine à états d'arriver dans un état non reconnu.
  • Seul l'état Stop peut arrêter l'application. Cette conception évite les arrêts partiels et accidentels en assurant que :
     

1.     Le code d'arrêt ne s'exécute que lorsque l'utilisateur veut arrêter l'application.
2.     Le code d'arrêt s'exécute toujours jusqu'à la fin.

  • Un seul état s'exécute à tout moment, et la boucle While unique garantit que toutes les tâches s'exécutent à la même vitesse. Si vous avez besoin de tâches à plusieurs vitesses ou parallèles, envisagez d'utiliser plutôt les modèles Gestionnaire de messages dans une file d'attente ou Framework d'acteur, accessibles à partir de la boîte de dialogue Créer un projet.
  • L'état Attendre un événement est le seul qui reconnaisse les entrées utilisateur. La machine à états doit être dans cet état pour que les entrées utilisateur soient acceptées.

Création de votre propre application de machine à états

Consultez le tutorielModifier la machine à états simple LabVIEWpour commencer.  

Détermination de vos besoins

Avant de personnaliser ce modèle, posez-vous les questions suivantes :

  • De quels états se compose l’application ? La réponse à cette question détermine les états que vous ajoutez.
  • Quel devrait être l’état suivant pour chaque état ? La réponse détermine la valeur de l'énum État suivant envoyée par chaque état au registre à décalage de la boucle While.

    Un seul état peut conditionnellement passer à plusieurs états. Un exemple est l'état Attendre un événement du modèle, qui passe à un état en fonction de l'entrée utilisateur.
  • À quel type de données chaque état aura-t-il besoin d’accéder ? La réponse à cette question détermine les types de données que vous ajoutez à Data.ctl.
  • Quelles sont certaines erreurs pouvant se produire et comment l’application doit-elle répondre à ces erreurs ? Les réponses à ces questions déterminent le volume de gestion des erreurs dont vous avez besoin.
     

Exemples de code de transition

Il existe différentes méthodes pour déterminer l’état vers lequel effectuer une transition, comme discuté ci-dessous.
Notez que bien que les exemples d’images montrent l’état « Init », ces possibilités de transition peuvent s’appliquer à n’importe quel état.

Biunivoque : Si vous passez toujours de l’état A à l’état B, il n’y a pas besoin de programmer de logique, il suffit de générer en sortie le nom de la condition suivante (Condition B) vers le registre à décalage.

Figure 3a : Un seul état de transition possible

Un à deux : Si vous pouvez passer de l’état A à l’état B ou à l’état C, vous pouvez utiliser une fonction Sélectionner pour évaluer l’état d’un indicateur. Vous devriez évaluer quelque chose qui détermine l’état vers lequel vous souhaitez passer. Par exemple, sur la figure 3b, nous voyons que l’entrée utilisateur du bouton Stop détermine si nous avançons depuis l’état au démarrage ou si nous continuons vers l’état Arrêt.

Figure 3b : Deux états de transition possibles

Un à plusieurs utilisant des tableaux : Si vous avez plusieurs états vers lesquels vous pouvez passer, vous pouvez utiliser une zone booléenne associée à une constante énum pour programmer la transition. Par exemple, sur la figure 3c, un code est conduit où le résultat du code détermine la transition, dont la sortie est un tableau de booléens. Le tableau booléen correspond à une constante énum qui contient une liste d’états possibles vers lesquels on peut passer. En utilisant la fonction Indexer un tableau, l’indice du premier booléen « Vrai » dans le tableau de booléens est en sortie. Ensuite, à l’aide de la fonction Sous-ensemble d’un tableau, vous pouvez extraire la valeur appropriée de la constante énum à laquelle elle est corrélée.

Figure 3c

Astuce : Rappelez-vous que les tableaux sont indexés par 0 et les énums par 1. Pour corréler le tableau de booléens avec la constante énum, utilisez la fonction Incrément pour corriger cet offset :

Un à plusieurs utilisant une boucle While : Une autre option si vous avez plusieurs états de transition possibles est d’utiliser une boucle While dans une condition. Le code à l’intérieur de la boucle While continuera jusqu’à ce qu’un état booléen soit défini sur Vrai, déclenchant le bouton Stop. Cela permettra au code de s’exécuter efficacement jusqu’à ce qu’un événement de déclenchement se produise.

La Figure 3d illustre un état « Init » utilisant une boucle interne et une structure Condition pour passer à l’état suivant. La structure Condition interne contient un diagramme pour chaque transition qui quitte l’état actuel. Chaque condition de la structure Condition interne a deux sorties : une valeur booléenne, qui spécifie si la transition doit être prise ou non, et une constante énumération, qui spécifie l’état vers lequel la transition va. En utilisant l’indice de boucle comme entrée dans la structure Condition, ce code passe effectivement à travers chaque condition de transition un par un, jusqu’à ce qu’il trouve un diagramme avec une sortie booléenne « Vrai ». Une fois que la sortie booléenne « Vrai » est trouvée, la condition génère le nouvel état vers lequel la transition se dirige. Bien que cette méthode puisse sembler légèrement plus compliquée que les méthodes précédentes, elle offre la possibilité d’ajouter des noms aux transitions en « convertissant » la sortie de l’indice de la boucle en un type énuméré. Cet avantage vous permet d’ajouter une « documentation automatique » à votre code de transition.

Figure 3d

Autres considérations relatives à la programmation

 

Redondance de code
Problème : La partie la plus difficile lors de la création d’une machine à états est de différencier les états possibles dans le diagramme d’états. Par exemple, dans le diagramme d’états de la machine à coke (Figure 4), nous aurions pu avoir des états de 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50 cent au lieu d’avoir un état « en attente de réponse » qui passe d’un état à l’autre en fonction du type de pièce tombé. Cela créerait 11 états différents avec exactement le même diagramme de condition. Le code redondant peut créer un gros problème dans une application plus grande.

Solution
 : Si différents états ont le même diagramme de condition, essayez de les combiner en un seul état. Par exemple, l’état « Attendre une réponse » est créé pour éviter la redondance de code.

Utilisation de l’énum
Problème : Les énums sont largement utilisées comme sélecteurs de condition dans les machines à états. Si l’utilisateur essaie d’ajouter ou de supprimer un état à partir de cet énum, les fils de liaison restants connectés aux copies de cet énum seront brisés. C’est l’un des obstacles les plus courants lors de l’implémentation des machines à états avec des énums.

Solution : Voici deux solutions possibles à ce problème :
1. Si toutes les énumérations sont copiées de l’énum modifié, les pauses disparaîtront.
2. Créez une nouvelle commande avec l’énum et sélectionnez « déf. de type » dans le sous-menu. En sélectionnant une déf. de type, toutes les copies d’énum seront automatiquement mises à jour si l’utilisateur ajoute ou supprime un état.

Étapes suivantes

Si vous souhaitez en savoir plus sur les machines à états et d’autres architectures avancées dans LabVIEW, envisagez de suivre le cours de formation pour clients LabVIEW Fondamental 2.