Notre monde connecté ; explication des automates à états finis
On dit que l'homme et la femme ont été créés à l'image de Dieu. De la même manière, ils créent aujourd'hui des machines à leur image. Un exemple concret est la programmation (AFM). Les ingénieurs et les développeurs utilisent désormais des ordinateurs pour automatiser des tâches autrefois manuelles. Par exemple, avez-vous du linge sale qui traîne ? Moi aussi ! Avant, il fallait rincer le linge dans une bassine ou un lavabo, ajouter du savon, frotter, rincer à nouveau, etc., pour obtenir un t-shirt propre pour aller travailler ou sortir. Maintenant, les machines à laver font tout le travail à notre place. Nous en sommes arrivés là grâce aux ingénieurs qui ont conçu des milliers de produits et d'appareils exécutant des programmes basés sur la pensée ou l'action humaine. Ce constat s'applique également à l'apprentissage automatique et aux autres concepts à la mode en matière d'intelligence artificielle. Des millions d'appareils et d'applications sont développés pour améliorer l'efficacité et faciliter la vie des hommes et des femmes, et nombre de ces processus d'assistance existent grâce aux AFM.
Les automates à états finis (AEF) sont simplement un calcul mathématique d'une série de causes et d'événements. Dans notre exemple de machine à laver, l'AEF détermine quand démarrer le cycle de rinçage, quand essorer et quand s'arrêter complètement. Pour mieux comprendre un automate à états finis (AEF), il faut d'abord définir la notion d'« état ». Un état est une information unique au sein d'un programme informatique plus vaste. Le calcul de l'AEF passe d'un état à un autre en réponse à des entrées externes. Un AEF est défini par une liste ou un ordre logique de ses états : son état initial et les conditions de chaque transition, jusqu'à un état final. L'AEF est une suite d'instructions programmées par l'ordinateur pour exécuter des opérations en fonction des entrées ; de la même manière que l'être humain pense et agit, nos machines et les ordinateurs qui les contrôlent fonctionnent de la même façon.
Les états constituent l'ADN de l'automate fini, dictant son comportement interne et ses interactions avec l'environnement, comme la réception d'entrées ou la production de sorties, pouvant ou non entraîner un changement d'état du système. L'état à exécuter dépend précisément des différentes conditions définies dans l'automate. Ce concept est fondamental pour les ingénieurs en électronique et en matériel, car de nombreux problèmes pratiques, tels que la programmation des machines à laver (quand ajouter de l'eau ou du savon, quand essorer ou faire une pause), se résolvent plus facilement grâce aux automates finis que par les paradigmes de programmation séquentielle classiques. En d'autres termes, un automate fini représente une solution plus « électrique et électronique » pour résoudre un problème matériel que la programmation séquentielle.
Voici deux exemples de machines à états finis (MEF) qui permettent une prise de décision logique plus rapide et moins énergivore lors du déploiement d'un programme validé. La MEF constitue votre première étape vers l'informatique Edge au niveau d'un seul appareil dans les applications IoT industrielles.
Machine de Mealy : Dans le calcul d'une machine de Mealy, la sortie de chaque état dépend de l'état actuel et de ses valeurs d'entrée. Typiquement, chaque entrée d'un état donné produit une seule sortie, soit une transition, soit un état final. La machine à laver se remplit d'eau ; lorsque le niveau X est atteint, l'eau est coupée.
Machine de Moore : Dans la machine de Moore, les sorties de chaque état dépendent de l’état actuel et sont généralement basées sur des systèmes séquentiels cadencés. La machine à laver essore ; après 4 minutes, arrêtez la machine.
DIAGRAMME D'ÉTAT
Tout automate fini doit être décrit avant d'être programmé à l'aide d'un diagramme d'états, permettant de représenter son fonctionnement. L'exemple ci-dessous illustre le comportement d'un automate fini et ses transitions, généralement représentées par des bulles pour les états et des flèches pour les transitions. Il est également important, pour une exécution correcte d'un automate fini, de définir un état présent unique, permettant d'identifier facilement l'état suivant (futur) grâce à ses identifiants de programmation.
Le diagramme ci-dessus illustre un processus complet de machine à états finis de Mealy. Supposons que l'opération débute à l'état 1, puis passe à l'état 2 une fois les autorisations de programmation obtenues. Après la transition vers l'état 2, la machine à états finis calcule l'état courant jusqu'à ce qu'un déclencheur permette de passer à l'état 3 ou 4. Notez que, dans ce diagramme, les états 3 et 4 sont les états finaux, qui produisent les données calculées pour le résultat final de votre projet.
Ubidots FSM
Commençons maintenant à programmer un automate fini pour envoyer des données à Ubidots et vous offrir une expérience concrète de cette méthode de programmation. Notre automate fini identifiera la demande initiale et y répondra. Nous allons créer une machine de Moore simple : envoyer les données des capteurs de notre microcontrôleur (Espressif ESP8266) à Ubidots
Sur la base de cette exigence initiale, nous avons choisi de mettre en œuvre deux états en utilisant un modèle de calcul FSM de type machine de Moore :
- ATTENDRE : Ne rien faire jusqu'à ce qu'une minute se soit écoulée (rester en état d'inactivité pendant environ 59 secondes).
- READ_SEND : Lire l’entrée analogique du microcontrôleur auquel le capteur est connecté et envoyer le résultat à Ubidots via MQTT à la 60e seconde.
Le diagramme d'état ci-dessous illustre la logique de programmation de notre automate fini :

Ce diagramme montre clairement que la transition de l'état WAIT à l'état READ_SEND dépend exclusivement de la valeur du temps indépendant, supérieure ou inférieure à 60 secondes. À partir de l'état WAIT suivant, le programme s'exécute en continu dans cet état jusqu'à ce que le temps indépendant atteigne ou dépasse 60 secondes. Une fois ce seuil atteint, l'automate à états finis (AEF) passe de l'état WAIT à l'état READ_SEND. Après l'envoi de la valeur, l'AEF repasse en état WAIT pendant environ 59 secondes avant de recalculer la transition.
Codage
Pour simplifier cet exemple, prenons un code FSM concret, divisé en quatre parties détaillant chaque état et condition de transition. Le code complet est disponible ici.
Partie 1 – Définir les contraintes
// Inclure les bibliothèques #include "UbidotsESPMQTT.h" // Définir les constantes #define TOKEN "...." // Votre jeton Ubidots #define WIFINAME "...." // Votre SSID #define WIFIPASS "...." // Votre mot de passe Wi-Fi #define WAIT 0 #define READ_SEND 1 uint8_t fsm_state = WAIT; // État initial int msCount = 0; // Compteur de temps float value; // Espace mémoire pour la valeur à lire Ubidots client(TOKEN);
Cette première partie du code est peu intéressante : nous importons simplement la bibliothèque MQTT pour l’envoi de données aux Ubidots et complétons les définitions nécessaires. Il est important de noter que nous définissons ici les deux états, WAIT et READ_SEND, comme des constantes dans tout le code, et que nous définissons l’état actuel à l’aide de la variable fsm_state. La partie suivante du code réserve de l’espace mémoire pour le minuteur indépendant, la valeur à lire et l’initialisation du client MQTT.
Il est important de ne pas oublier de renseigner correctement votre jeton (TOKEN) ainsi que le nom et le mot de passe de votre réseau Wi-Fi. Si vous ne savez pas où trouver votre jeton, veuillez consulter le Centre d'aide Ubidots pour obtenir des conseils et astuces supplémentaires.
Partie 2 – Rappel
// Fonctions auxiliaires void callback(char* topic, byte* payload, unsigned int length) { Serial.print("Message arrivé ["); Serial.print(topic); Serial.print("] "); for (int i=0;i < length;i++) { Serial.print((char)payload[i]); } Serial.println(); }Dans cette partie du code, nous implémentons une fonction de rappel qui traite les données provenant du serveur en cas de besoin. Pour notre automate fini, cette étape est indispensable à la compilation correcte du code. Comme expliqué dans notre article précédent sur MQTT , la fonction de rappel gère les modifications des variables dans Ubidots ; il est donc nécessaire de compiler le code et de la définir.
Partie 3 – Fonctions principales – Configuration()
// Fonctions principales void setup() { // Initialise la broche numérique LED_BUILTIN en sortie. pinMode(A0, INPUT); client.wifiConnection(WIFINAME, WIFIPASS); client.begin(callback); }Commençons par les fonctions principales. Dans la fonction `setup()`, nous configurons la broche analogique zéro comme entrée (vous devez adapter le numéro de la broche en fonction du branchement physique de votre capteur) afin d'utiliser le convertisseur analogique-numérique (CAN) qui permet au capteur de lire les données environnementales et de les convertir en un nombre flottant. Nous initialisons également le client Wi-Fi et transmettons la fonction de rappel en fonction des paramètres de programmation définis précédemment.
Partie 4 – Fonctions principales – Boucle()
void loop() { switch(fsm_state) { case WAIT: if (msCount >= 60000){ msCount = 0; fsm_state = READ_SEND; } break; case READ_SEND: value = analogRead(A0); if(!client.connected()){ client.reconnect(); } /* Routine pour l'envoi de données */ client.add("stuff", value);ubidotsPublish("source1"); client.loop(); fsm_state = WAIT; break; default: break; } // Incrémente le compteur msCount += 1; delay(1); }
Une méthode courante pour implémenter un automate fini dans les microcontrôleurs consiste à utiliser une de type « switch-case » . Dans notre exemple, les cas correspondent aux états et les interrupteurs à la `fsm_state` . Examinons plus en détail la conception de chaque état :
Une méthode courante pour implémenter un automate fini (FSM) dans un microcontrôleur consiste à utiliser une de type « switch-case » . Dans notre exemple, les états de l'automate et la variable `fsm_state` représentent les instructions de transition. Nous déterminerons ici si les instructions `READ_SEND` ou `WAIT` sont envoyées respectivement à 1 ou 0 pour identifier chaque étape de l'automate et effectuer la transition entre les opérations grâce à un temporisateur indépendant de 60 secondes.
Voyons plus en détail comment chaque État est conçu :
- ATTENTE : D’après le code de cet état, nous pouvons déduire qu’il ne fera rien si le résultat du minuteur indépendant stocké à
msCountest inférieur à 60 000 millisecondes ; une fois cette condition atteinte, la valeur defsm_statechange et nous passons à l’état suivant, l’état READ_SEND. - READ_SEND : Ici, nous lisons la valeur de notre capteur, puis nous l'ajoutons simplement à une variable appelée « stuff » et nous envoyons ses données à un périphérique appelé « source1 ». Lors de l'exécution de ce programme, nous repasserons toujours par l'état WAIT avant d'émettre une seconde sortie.
Enfin, à l'issue de notre structure switch-case, nous incrémentons la valeur de notre minuteur et introduisons un très court délai de 1 milliseconde pour que le temps soit cohérent avec notre compteur.
À ce stade, vous vous demandez peut-être pourquoi programmer tout cela alors que l'on peut utiliser la programmation séquentielle classique ? Imaginez que vous ayez trois tâches supplémentaires à effectuer au sein de votre routine :
- Contrôler un servomoteur à l'aide de la modulation de largeur d'impulsion (PWM)
- Afficher les valeurs sur un écran LCD
- Ouvrir ou fermer une porte
Lors de l'exécution de tâches multiples, l'automate fini (FSM) permet un stockage minimal des données dans la mémoire locale de l'appareil. De plus, ses fonctions d'état peuvent exécuter des tâches immédiates en fonction des valeurs d'entrée, et non d'une seule sortie. L'utilisation d'un FSM permet une prise de décision plus logique, avec un temps et une énergie réduits pour le déploiement d'un programme validé. La valeur ajoutée des FSM réside dans leur capacité à effectuer des calculs au niveau d'un seul appareil – première étape du Edge Computing.
Essai
Nos scripts fonctionnent comme prévu, un nouvel appareil appelé « source1 » est créé avec une variable appelée « stuff » qui reçoit et enregistre la valeur du capteur toutes les 60 secondes dans Ubidots.


Améliorations et idées
Une machine à états finis (FSM) peut être implémentée de nombreuses manières, et l'utilisation de l' instruction switch-case peut s'avérer fastidieuse à maintenir lorsqu'il faut gérer un très grand nombre d'états. Une amélioration possible du code présenté dans la partie 1 consisterait à éviter l'attente d'une milliseconde entre chaque analyse de cas. Ceci peut être réalisé grâce à la fonction millis().
Conclusion
L'homme et la femme ont conçu nos ordinateurs à leur image, et les automates à états finis (AEF) sont les programmes qui permettent aux machines d'exécuter des tâches et d'apporter aux humains une aide précieuse et une sécurité au quotidien. À mesure que la technologie et les connaissances edge les ordinateurs monocartes continueront de se gateway industrielles et les automates programmables industriels (API) de référence tels que Dell, Siemens, etc., tout en offrant des solutions locales permettant d'économiser $ en coûts matériels et d'exploitation.