[u][b]YASM[/b][/u] ( Yet Another State Machine library )
Une librairie permettant la mise en place extrêmement simple de machines à états, sur le principe un état = une fonction, et basée sur les pointeurs de fonction.
Cela permet d'avoir un code facile à comprendre et à maintenir.
Avant d'aller plus loin, si vous ne savez pas ce qu'est une machine à état ou automate fini, ni en quoi cela peut vous aider à résoudre efficacement votre problème, je vous conseille de lire le très très bon tuto de J-M-L sur la question.
Vous verrez ensuite en quoi l'utilisation de la librairie simplifie sa mise en œuvre.
Une explication détaillée des fonctions disponibles est disponible en anglais ici : GitHub - bricofoy/yasm: Yet Another State Machine library - a function pointer based state machine library for arduino
Je vais la reprendre ici en français.
Installation
La librairie est disponible directement dans le gestionnaire de librairies de l'IDE arduino. Pour l'installer rien de plus simple donc, il suffit de la sélectionner dans la liste et cliquer sur installer.
Sinon, la dernière version de la librairie est disponible ici : https://github.com/bricofoy/yasm/archive/master.zip
Ce lien permet de télécharger un fichier yasm-master.zip
Quand on décompresse ce fichier soit manuellement soit via le menu "ajouter une bibliothèque zip" de l'IDE, on obtient un dossier "yasm-master", à renommer en "yasm" et à placer dans le dossier "libraries" d'arduino. (Il y est déja si on a décompressé via l'IDE, il faut juste renommer)
Une fois cela fait, la librairie devrait apparaître dans le gestionnaire de librairies de l'IDE arduino.
Utilisation
L'exemple le plus simple étant toujours le même : faire clignoter une led, on va commencer par là.
Cela permet de prendre contact avec la librairie, et avec sa fonction permettant de créer une temporisation.
Pour envisager la question sous l'angle des machines à état, nous voyons immédiatement que nous avons besoin de deux états : un état où la led est allumée, appelons-le ledOn
, et un état où la led est éteinte, ledOff
(comme c'est original...)
Ensuite nous aurons besoin de passer d'un état à l'autre à l'issue d'une temporisation, de manière à faire changer l'état de la led et obtenir son clignotement. Avec une subtilité tant qu'a faire, puisque ce n'est pas plus compliqué à mettre en place : le temps allumé et le temps éteint ne sont pas les mêmes.
Voici comment procéder :
D'abord, il faut inclure la librairie, soit depuis le menu, soit en écrivant directement au début du sketch :
#include <yasm.h>
On va ensuite définir deux constantes pour les délais allumé et éteint :
#define OnDelay 500 //500ms
#define OffDelay 750 //750ms
Puis on va définir sur quelle broche de la carte la led est connectée. Ici, la broche 13 car la plupart des cartes ont déjà une led dessus, ce qui permet de tester le code sans utiliser de composants externes :
#define LedPin 13
Ensuite on rentre dans le vif du sujet avec la déclaration de la machine à états dont on a besoin, que nous allons très originalement nommer "led" :
YASM led;
Puis nous aurons les 2 fonctions habituelles d'un sketch arduino, setup()
et loop()
.
Dans le setup, nous allons initialiser la broche utilisée pour la led en sortie, puis donner à la machine à états son état initial. Ici on veut que la led s'allume, on va donc initialiser la machine sur l'état "ledOn" :
void setup()
{
pinMode(LedPin, OUTPUT); //declaration de la broche de la led comme sortie
led.next(ledOn); //definition de l'etat initial de la machine
}
Ensuite vient la fonction loop, qui ne contient quasiment rien à part la mise à jour de la machine à états :
void loop()
{
led.run(); //mise a jour de la machine a etats
}
Et enfin, il faut définir les état dont nous aurons besoin pour faire clignoter notre led, soit un état allumé : ledOn
, et un état éteint : ledOff
void ledOn()
{
digitalWrite(LedPin, HIGH); //ici c'est l'etat "on" donc nous allumons la led
if(led.elapsed(OnDelay)) //on teste si le delai d'allumage est ecoule
led.next(ledOff); //si le delai est ecoule on passe a l'etat "off"
}
void ledOff()
{
digitalWrite(LedPin, LOW); //ici c'est l'etat "off" donc on eteint la led
if(led.elapsed(OffDelay)) //on teste si le delai d'extinction est ecoule
led.next(ledOn); //si le delai est ecoule on passe a l'etat "on"
}
Chaque état est une fonction indépendante, qui sera exécutée répétitivement par la machine à états tant que l'état qu'elle représente est actif. Ici le modèle des deux fonctions est exactement similaire : on commence par allumer (ou éteindre) la led, puis on vérifie si le délai voulu dans l'état est écoulé avec la fonction elapsed(délai en ms)
.
Si le délai n'est pas écoulé, elapsed(délai)
retourne faux(false
), la condition du if
n'est pas validée donc la fonction se termine directement. Elle est ensuite relancée immédiatement au prochain cycle, nous restons donc dans cet état.
Si le délai est écoulé, elapsed(délai)
retourne vrai(true
), la condition du if
est validée et on demande le changement d'état avec next(etat suivant);
, puis la fonction se termine et c'est alors l'état suivant est exécuté au prochain cycle.
Le code complet de l'exemple BlinkLed (fourni avec la librairie, vous pouvez directement ouvrir l'exemple plutôt que de tout retaper) est donc :
/*
BlinkLed.ino example file for yasm library.
The purpose of this arduino sketch is to blink a led on pin 13.
It creates a state machine with two states : ledOn, ledOff,
and illustrate the use of elapsed(delay_in_ms) timing function to trigger
state change.
*/
#include <yasm.h> //include the yasm library
#define OnDelay 500 //500ms led "On" state delay
#define OffDelay 750 //750ms led "Off" state delay
#define LedPin 13 //pin 13 because most arduino boards provide a led here
YASM led; //declaration of the "led" state machine
void setup()
{
pinMode(LedPin, OUTPUT); //declare the led pin as output
led.next(ledOn); //set the initial state of the led state machine
}
void loop()
{
led.run(); //update the state machine
}
//////////led state machine/////////////
void ledOn()
{
digitalWrite(LedPin, HIGH); //this is the "On" state so we turn on the led
if(led.elapsed(OnDelay)) //check if the delay for the "on" state is elapsed
led.next(ledOff); //if the delay is elapsed we switch to the "off" state
}
void ledOff()
{
digitalWrite(LedPin, LOW); //this is the "Off" state so we turn off the led
if(led.elapsed(OffDelay)) //check if the delay for the "off" state is elapsed
led.next(ledOn); //if the delay is elapsed we switch to the "on" state
}