LOCODUINO

Aide
Forum de discussion
Dépôt GIT Locoduino
Flux RSS

mardi 19 mars 2024

Visiteurs connectés : 40

Bibliothèque Commanders

Ou comment donner des ordres !

.
Par : Thierry

DIFFICULTÉ :

Petit préalable. Pour les nouveaux sur Locoduino, un peu d’archéologie informatique. A mes débuts ici j’ai créé une bibliothèque ’Universal Accessory Decoder’ qui outre un nom pompeux (universelle ?) et trompeur (Decoder : seulement DCC ?) avait l’inconvénient d’être tentaculaire. Je l’ai faite un peu évoluer, puis je suis passé à d’autres projets. Evidemment, pour ces nouveaux programmes comme souvent j’ai eu besoin de gérer des boutons et des bus, et regretté de devoir à nouveau coder ce qui était déjà fait dans UAD... C’est ce qui m’a poussé à trancher dans le vif, en clair à couper UAD en deux morceaux. Cet article décrit la première partie, les Commanders.

<

Tous les projets Arduino ont en commun de devoir transmettre des ordres entre des commanditaires et des exécuteurs...
Les commanditaires peuvent être des capteurs ou des timers qui vont signaler qu’une action doit être entreprise, ou des intermédiaires entre un humain et sa machine, voire même entre deux machines. Les exécuteurs sont les leds et les moteurs qui sont au contact du monde réel... Entre les deux, c’est l’Arduino qui doit transformer l’appui sur un bouton ou la réception d’un message en activation d’un relais ou en broche mise au niveau haut...
Le rôle de la bibliothèque ici décrite est de simplifier au maximum l’utilisation de tous les types d’organes de commande, qu’ils soient physiques (boutons, interrupteurs, encodeurs, potentiomètres etc...), ou dématérialisés (DCC, bus série, CAN ou I2C ...), à l’usage de n’importe quel besoin. A noter que la bibliothèque est prévue pour accepter simultanément des messages de toutes les sources, donc de tous les Commanders !

Pour qu’une bibliothèque soit possible, et que des éléments aussi différents que des boutons poussoirs, une liaison série ou deux fils de DCC deviennent compatibles, il faut virtualiser. C’est à dire extraire la substantifique moelle du fonctionnement de ces commanditaires.
Un ordre à donner à des actionneurs peut se résumer à cinq cas de base (IMHO (In My Humble Opinion (à mon humble avis))) :

  • Inversion de l’état, une bascule (type poussoir, interrupteur, ordre DCC...).
  • L’évolution d’une valeur absolue, type potentiomètre.
  • Une évolution relative, type encodeur.
  • L’évolution vers une valeur absolue mémorisée par un identifiant
  • Un mouvement typé. Par exemple pour un moteur : ’gauche’, ’droite’, ’centre’, ’haut’, ’bas’, ’droit’, ’dévié’ ou ’stop’... Pour un feu ’on’ ou ’off’, ou ’plus’ ou ’moins’ pour un choix sur un écran LCD...

D’autres cas pourraient être traités, comme l’appui long sur un poussoir, ou l’équivalent d’un double clic (triple, quadruple...).

Commanders travaille avec des événements comprenant un identifiant, un entier long positif, un type comme TOGGLE, MOVE, MOVEPOSITION, MOVEPOSITIONID ou CONFIG, et une donnée contextuelle, un entier signé. Cette donnée est utilisée dans tous les types d’événement à part TOGGLE et MOVEPOSITIONID. A charge pour le programme Arduino d’exploiter les événements reçus !
L’identifiant servira à reconnaître l’action à effectuer.

Il y a cinq Commanders possibles dans la version actuelle de la bibliothèque : les boutons au sens large, le DCC, l’interface série, le bus CAN et le bus I2C.
D’autre types de Commander pourraient être ajoutés, comme le Wifi, le SPI, du Bluetooth, une liaison radio ou une connexion Loconet...

DCC, ou comment deux fils donnent des ordres...

Définition

setup()
{
  Commanders::begin(LED_BUILTIN);

  DccCommander.begin(0x00, 0x00, digitalPinToInterrupt(3));
}

Le fonction Commanders::begin() ne dépend pas du type de commander, elle est donc appelée comme une fonction statique de la classe Commanders. Son rôle est de faire flasher la DEL demandée à chaque événement envoyé, quelle que soit sa source. Si le DCC est activé, la DEL pourra aussi clignoter pour signaler la bonne présence d’un signal DCC sur les deux fils d’entrée. L’argument de la fonction LED_BUILTIN, fourni par l’IDE Arduino, remplace le numéro de broche en fonction de la carte Arduino utilisée. En effet selon le modèle d’Arduino ce n’est pas toujours la broche 13 qui est relié à cette DEL !
L’initialisation du bus DCC par DccCommander.begin() réclame trois arguments, les deux premiers donnent l’identifiant du fabricant du récepteur DCC, ainsi qu’un code produit. Comme c’est un produit maison, j’ai choisi de les laisser à 0... Le troisième argument détermine l’interruption qui sera utilisée par le Commander. Est utilisée ici une fonction récente digitalPinToInterrupt() de l’IDE Arduino qui permet de donner un numéro de broche (3) et d’en déduire le numéro d’interruption selon le modèle d’Arduino.

Exploitation

Le croquis Arduino doit pouvoir recevoir les ordres et les interpréter :

void loop()
{
  if (Commanders::loop() == DCCINT(124, 1))
  {
     // activer ce qui doit l'être !
  })
}

Commanders::loop() s’occupe de gérer l’ensemble des Commanders déclarés, et renvoie soit rien, représenté par une valeur UNDEFINED_ID, soit un identifiant. Dans le cas du Commander DCC, on a encodé l’adresse DCC et l’octet d’activation/désactivation à l’intérieur de l’identifiant retourné par Commanders::loop(). Une macro DCCINT() permet de recalculer cet entier et de le comparer sous une forme plus humainement lisible... Ici on vérifie si l’adresse DCC est 124, et si le code d’activation est bien 1. On aurait aussi pu comparer avec 100124, qui est la version entière encodée, ou comparer séparément les deux termes :

  unsigned long ret = Commanders::loop();
  if (DCCID(ret) == 124 && DCCACTIVATION(ret) == 1)
  {
    // activer ce qui doit l'être !
  }

A noter qu’outre l’identifiant, le type d’événement est disponible via la fonction Commanders::GetLastEventType(), et sa donnée associée avec Commanders::GetLastEventData() .

"Nous avons tous notre fardeau de manettes, de boutons et de voyants !" [1]

Si l’on veut des boutons en tout genre, ce sont directement les classes dérivées de ButtonsCommanderButton qu’il faut implémenter. On peut mettre de simples boutons poussoirs, des poussoirs câblés en ’analogique’, c’est à dire raccordés en série à des résistances de valeurs différentes et reliés à une seule broche analogique, des interrupteurs, des potentiomètres, des encodeurs...
Prenons un exemple avec cinq boutons poussoirs simples reliés à cinq appareils de voie :

Déclaration

ButtonsCommanderPush Left;
ButtonsCommanderPush Dc;
ButtonsCommanderPush Right;
ButtonsCommanderPush EPS;
ButtonsCommanderPush TJD;

Les cinq boutons sont déclarés.

Définition

void setup()
{
  Commanders::begin(LED_BUILTIN);

  Left.begin(24, 100);
  Dc.begin(26, 101);
  Right.begin(28, 102);
  EPS.begin(30, 103);
  TJD.begin(32, 104);
}

Chaque bouton est associé à une broche de l’Arduino (24, 26, etc...) et doté d’un identifiant unique (100, 101 ...). Pas de DCC dans cet exemple.

Exploitation

void loop()
{
  unsigned long ret = Commanders::loop();

  switch(ret)
  {
    case 100:
      // activer ce qui doit l'être !
      break;
    case 101:
      // activer ce qui doit l'être !
      break;
    case 102:
      // activer ce qui doit l'être !
      break;
    case 103:
      // activer ce qui doit l'être !
      break;
    case 104:
      // activer ce qui doit l'être !
      break;
  }
}

Comme pour le DccCommander, on va récupérer l’identifiant sélectionné avec Commanders::loop()et faire ce qui doit être fait. On voit aussi que c’est bien Commanders::loop() qui est appelé, le même que pour l’exemple précédent en DCC et que donc on n’est pas lié à un type de Commander particulier.

Quelques mots sur les différents boutons

Poussoirs

Assortiment de boutons poussoir.
Assortiment de boutons poussoir.

Un poussoir est un organe très simple raccordé à une seule broche. Pourtant il est nécessaire d’y appliquer un traitement anti-rebond bien sûr déjà prévu dans la bibliothèque (voir pourquoi et comment ici). Comme il a été dit plus haut, un poussoir envoie un événement TOGGLE à chaque appui. Il est aussi possible de boucler sur une liste d’identifiants, avec éventuellement des événements associés :

ButtonsCommanderPush Push;

void setup()
{
  Push.begin(105, 17); // id 105, broche 17

  Push.AddEvent(106); // autre id : 106
  Push.AddEvent(107);
  Push.AddEvent(108);
}

Quatre identifiants (105, 106, 107, 108) vont défiler à chaque appui sur le poussoir, et lorsque le dernier est envoyé, on recommence au début ! On peut ainsi basculer un moteur d’un côté ou d’un autre, ou balayer toutes les positions utiles d’un servo :

ButtonsCommanderPush PushMotor;
ButtonsCommanderPush PushServo;

void setup()
{
  Commanders::begin(LED_BUILTIN);

  PushMotor.begin(200, 10, COMMANDERS_EVENT_MOVE, COMMANDERS_MOVE_LEFT);  // Id = 200, broche 10
  PushMotor.AddEvent(201, COMMANDERS_EVENT_MOVE, COMMANDERS_MOVE_RIGHT); // Id = 201

  PushServo.begin(300, 11, COMMANDERS_EVENT_MOVEPOSITION, 30);  // Id = 300 broche 11
  PushServo.AddEvent(301, COMMANDERS_EVENT_MOVEPOSITION, 45);
  PushServo.AddEvent(302, COMMANDERS_EVENT_MOVEPOSITION, 90);
  PushServo.AddEvent(303, COMMANDERS_EVENT_MOVEPOSITION, 135);
}

Deux positions pour PushMotor et quatre pour PushServo.

Poussoirs en série

C’est une variante intéressante de connexion de plusieurs poussoirs en série sur une seule broche analogique, et séparés par des résistances de valeurs différentes et décroissantes (Voir le blog de Jean-Luc à ce sujet). S’il n’y a pas de contrainte d’appui simultané de plusieurs poussoirs, c’est une option pratique pour augmenter artificiellement le nombre de broches d’entrée !

ButtonsCommanderAnalogPushes Pushes;

int values[] = { 0, 145, 329, 505, 741 };
unsigned long ids[] = { 1000, 1001, 1002, 1003, 1004 };

void setup()
{
  Commanders::begin(LED_BUILTIN);

  Pushes.begin(A0, 5, ids, values, 20);
}

La matrice ’values’ représente les valeurs théoriques de tension qui seront mesurées sur la broche analogique pour chaque bouton pressé, entre 0 et 1023.
La matrice ids est la liste des identifiants, un pour chaque bouton poussoir.
Enfin le begin() utilise la broche A0, les ids et les valeurs, et une tolérance de 20 autour de la valeur théorique de tension. Le troisième bouton sera par exemple reconnu pour une valeur analogique comprise entre 309 et 349 (329 +/- 20)...

Interrupteur

Assortiment d'interrupteurs à levier.
Assortiment d’interrupteurs à levier.

Un interrupteur est un contact permanent doté de deux positions stables ou plus. Chaque position est raccordée à une broche et optionnellement un événement :

  ButtonsCommanderSwitch Switch;

void setup()
{
  Commanders::begin(LED_BUILTIN);

  Switch.begin();
  Switch.AddEvent(150, 15); // id 150, broche 15
  Switch.AddEvent(160, 16);
  Switch.AddEvent(170, 17);
  Switch.AddEvent(180, 18);
}

La fonction AddEvent ajoute un identifiant pour chaque broche et un type d’événement. Si le type n’est pas spécifié, c’est un TOGGLE qui sera envoyé.

Encodeur

Encodeur sans son bouton
Encodeur sans son bouton

Un encodeur est un type particulier de bouton rotatif sans point milieu ni limites mini/maxi. C’est le genre de bouton qui tourne à l’infini dans un sens ou l’autre, comme le contrôle de vitesse d’une Mobile Station 2 de Marklin/Minitrix, ou d’une Ecos ESU... Sa particularité est de gérer une direction de mouvement plutôt qu’une valeur absolue. Très souvent, ce type de bouton est mécaniquement associé avec un bouton poussoir sur l’axe de rotation. Ce poussoir est géré indépendamment.

ButtonsCommanderEncoder EncoderAbsolute;
ButtonsCommanderEncoder EncoderRelative;

void setup()
{
  Commanders::begin(LED_BUILTIN);

  EncoderAbsolute.begin(20, 8, 9, 0, -100, 100);
  EncoderRelative.begin(30, 11, 12);
}

Dans commanders, un encodeur peut fonctionner selon deux modes.
Il y a un mode absolu comme celui présenté ici avec EncoderAbsolute. Le begin() définit l’identifiant de l’encoder 20, les deux broches de pilotage 8 et 9, puis une position de départ (0), un minimum (-100) et un maximum (100). Le mouvement du bouton va augmenter ou diminuer la valeur courante, et la limitera si elle sort des limites fixées. Les événements générés seront de type MOVEPOSITION et la donnée associée donnera la position courante.
Il y a aussi un mode relatif vu avec EncoderRelative, qui n’a rien à spécifier à part son identifiant (30) et les deux broches 11 et 12. Les événements générés seront de type MOVE et la donnée associée sera égale à MORE (plus) ou LESS (moins). A noter que les valeurs de MORE (+1) et LESS (-1) permettent de s’en servir directement dans une expression mathématique sans faire de tests...

Potentiomètre

Potentiomètres de montage
Potentiomètres de montage

Le potentiomètre renvoie une valeur absolue proportionnelle à la position du bouton physique.

  ButtonsCommanderPotentiometer Potar;

void setup()
{
  Commanders::begin(LED_BUILTIN);

  Potar.begin(25, A1, -100, 100);
}

Potar est déclaré avec l’identifiant 25, sur la broche A1, forcément analogique, pour une valeur oscillant entre -100 et +100. C’est la bibliothèque qui va se charger de traduire la valeur lue sur la broche analogique A1 dans l’intervalle -100/+100 . Les événements seront donc du type MOVEPOSITION et la donnée associée sera comprise entre -100 et +100 .

Liaison série

L’implémentation de cette classe n’occupe de la mémoire que si elle est utilisée, et elle permet d’utiliser toute liaison série qui répond à la même interface que le Serial bien connu : les fonctions begin, read et write. Les alternatives logicielles comme les bibliothèques SoftwareSerial, NewSoftSerial et AltSoftSerial fonctionnent par exemple...
Pour arriver à ce résultat, j’ai créé une macro qui construit totalement la classe SerialCommander en lui donnant le canal à exploiter, Serial par exemple...

Définition

SERIAL_COMMANDER(Serial);

Ici est créée la classe SerialCommander pour diriger la liaison série de base d’un Arduino : Serial.

Déclaration

void setup()
{
  Commanders::begin(LED_BUILTIN);

  Serial.begin(115200);
  SerialCommander.begin();
}

Rien de spécial ici, on remarque simplement la vitesse de communication que je mets la plupart du temps assez rapide, 115200 bauds...

Exploitation

Le code de l’exploitation pourrait au choix reprendre celui du DccCommander vu plus haut, ou celui du ButtonsCommander. Comme les autres, SerialCommander renvoie l’identifiant que la liaison série à reçu. Pour tester, il suffit d’entrer la bonne syntaxe sur la ligne d’envoi de la console série de l’IDE Arduino.
La syntaxe est

###### :#-c-###

Le premier nombre symbolisé par ###### est une valeur entière positive comprise entre 0 et 4294967295, ce qui fait beaucoup ! C’est l’identifiant. Si la seconde partie optionnelle de l’identifiant est précisée ’ :#’, alors c’est un identifiant DCC dont l’adresse est le ######, et l’activation (0 ou 1) le # tout seul. Il est possible de limiter l’entrée à cette première partie uniquement, et dans ce cas l’effet sera le même que si un bouton avec ce même identifiant avait été pressé !
Le ’c’ est l’initiale de l’événement. C’est au choix en minuscule ou en majuscule. Le texte peut être plus long, mais seul le premier caractère compte :

  • ’t’ signifie Toggle, c’est à dire bascule en bon français. C’est un événement simple, comme ceux que fournissent les boutons poussoirs ou les interrupteurs.
  • ’m’ signifie Move, ou mouvement dans la langue de Molière. Le troisième terme donne le type de mouvement voulu...
  • ’p’ signifie Position. C’est un mouvement absolu, le troisième terme de la syntaxe est dans ce cas une valeur entière signée. Un potentiomètre ou un encodeur peuvent envoyer ce type d’événement.
  • ’c’ signifie Config, pour configurer le décodeur. Le troisième terme est à la fois l’adresse de la variable de configuration et sa nouvelle valeur. Cette fonctionnalité n’est pas encore implémentée.

Le caractère de séparation entre les trois termes peut être n’importe lequel parmi ’,’ (virgule) , ’ ;’ (point_virgule), ’/’ (division ou slash) ou ’ ’ (espace). On peut donc taper :

124 événement TOGGLE sur l’identifiant 124
124,T idem
300:1 identifiant de type DCC avec l’adresse 300 activée (1).
125 P 300 événement ABSOLU de l’identifiant 125, à la valeur 300
126 ;M ;-1 événement de mouvement de l’identifiant 126, de la valeur -1 (LESS).

Les différents types de mouvement permis sont donnés par les valeurs de l’enum :

enum COMMANDERS_MOVE_TYPE
{
	COMMANDERS_MOVE_MORE = +1,
	COMMANDERS_MOVE_LESS = -1,
	COMMANDERS_MOVE_STOP = 0,
	COMMANDERS_MOVE_LEFT = -2,
	COMMANDERS_MOVE_RIGHT = -3,
	COMMANDERS_MOVE_CENTER = -4,
	COMMANDERS_MOVE_TOP = -5,
	COMMANDERS_MOVE_BOTTOM = -6,
	COMMANDERS_MOVE_STRAIGHT = -7,
	COMMANDERS_MOVE_DIVERGE = -8,
	COMMANDERS_MOVE_ON = -9,
	COMMANDERS_MOVE_OFF = -10
};

Le bus I2C

Présent sur presque tous les Arduino (mais pas sur le Leonardo par exemple...), c’est un moyen simple et économique de faire discuter deux Arduino. Voir ici pour le détail du fonctionnement de ce bus.

Déclaration

void setup()
{
  Commanders::begin(LED_BUILTIN);

  I2CCommander.begin(128);  // 128 est l'adresse du récepteur I2C.
}

Sur un bus I2C, il y a un maître, et un ou plusieurs esclaves. Commanders se place uniquement en tant qu’esclave. Le I2CCommander a donc besoin d’un entier comme adresse de son ’esclavagitude’ ! Seuls les messages adressés à cet esclave seront traités.

Exploitation

void loop()
{
  if (Commanders::loop() == 2002)  // Si l'émetteur a envoyé un événement sur l'identifiant Commanders 2002
  {
     // activer ce qui doit l'être !
  }
}

Un exemple de maître à exécuter sur un autre Arduino est présent dans les exemples de la bibliothèque. Cet exemple n’utilise pas Commanders. Pour être compris, l’expéditeur du message pour I2CCommander doit transférer sept octets :

  • quatre pour l’identifiant, un ’unsigned long’ soit un entier long sur quatre octets non signé.
  • un pour le type d’événement, avec la même syntaxe que pour le port série.
  • enfin un entier classique non signé sur deux octets pour la donnée complémentaire.

Le bus CAN

Ce bus très utilisé dans l’industrie et l’automobile est accessible à nos petits Arduino (voir ici).
Sauf exception comme l’Arduino DUE, aucun Arduino commun ne comporte de bus CAN intégré. Il s’agit toujours de circuits extérieurs comme le MCP2515. Seul ce circuit a été traité dans Commanders, pour le moment en tout cas...

MCP_2515
MCP_2515

Du point de vue de Commanders et de vous, son utilisateur, le bus CAN et le bus I2C ne présentent que peu de différences.

Déclaration

void setup()
{
  Commanders::begin(LED_BUILTIN);

  CANCommander.begin(10, CAN_500KBPS, digitalPinToInterrupt(3), 128);
}

La bibliothèque mcp_can utilisée par Commanders se sert d’un lien SPI pour communiquer entre l’Arduino et le 2515. Le lien SPI a besoin d’une broche de communication. C’est la 10 ici. La vitesse est fixée à 500 KiloBytesPerSeconds, et la réception passe par une interruption sur la broche 3.
L’émetteur du message va ajouter un identifiant à ses messages, permettant ainsi à tout récepteur CAN sur le bus de n’attraper que les messages qui le concerne. Je sais que l’émetteur a fixé son identifiant à 128, alors je le répète ici en dernier argument du begin(). Les messages qui n’auront pas cet identifiant ne seront même pas regardés par le 2515 ! Alors attention à bien le coder...
Tout comme I2CCommander, sept octets avec exactement la même signification et organisation doivent être transmis par l’émetteur.

Exploitation

void loop()
{
  if (Commanders::loop() == 2002)  // Si l'émetteur a envoyé un événement sur l'identifiant Commanders 2002
  {
     // activer ce qui doit l'être !
  }
}

Sauf erreur ou omission, tout à déjà été dit ! A part que tout comme pour I2C, un exemple d’émetteur est livré avec le bibliothèque, et lui non plus n’utilise pas Commanders.

Gestion d’événements

Pour l’exploitation, il y a une alternative intéressante au remplissage de la fonction loop() dans le croquis : la gestion événementielle. La fonction de base Commanders::begin() peut recevoir en argument l’adresse d’une fonction qui recevra les événements envoyés par les Commanders :

void ReceiveEvent(unsigned long inId, COMMANDERS_EVENT_TYPE inEventType, int inEventData)
{
    Commanders::printEvent(inId, inEventType, inEventData);
}

void setup()
{
  Commanders::begin(ReceiveEvent, LED_BUILTIN);

  ...
}

La fonction ReceiveEvent va recevoir directement les événements lancés par les Commanders : l’identifiant, le type d’événement et l’entier signé associé si besoin. L’adresse de la fonction est bien passée en argument au Commanders::begin(). La fonction printEvent() sert au débuggage en affichant les événements reçus sur la console. A noter que les deux canaux sont alimentés. Lorsqu’un événement survient, il est envoyé à la fonction ReceiveEvent si elle est déclarée, mais l’identifiant est aussi envoyé en valeur de retour de Commanders::loop() !
Comme déjà dit plus haut, si l’on ne passe pas par cette fonction événementielle, il est possible de récupérer le type du dernier événement avec Commanders::GetLastEventType(), et sa donnée associée avec Commanders::GetLastEventData(). Le même code que ci-dessus mais dans la loop() donnerait :

void loop()
{
  unsigned long eventID = Commanders::loop();

  if (eventID != UNDEFINED_ID)        // UNDEFINED_ID = no event  !
  {	
    Commanders::printEvent(eventID, Commanders::GetLastEventType(), Commanders::GetLastEventData());
  }
}

La bibliothèque

Optimisations

On le sait, l’Arduino est une plateforme puissante et passionnante, mais qui manque cruellement de mémoire. Une bibliothèque comme celle ci, qui tente d’unifier des comportements disparates en offrant de multiples fonctionnalités est confrontée tôt ou tard à des problèmes de compatibilité et de mémoire.
Dans le fichier Commanders.h qui se trouve dans le répertoire de la bibliothèque elle même, vous verrez :

//#define NO_BUTTONSCOMMANDER
//#define NO_BUTTONSCOMMANDERENCODER
//#define NO_BUTTONSCOMMANDERPUSH
//#define NO_BUTTONSCOMMANDERANALOGPUSHES
//#define NO_BUTTONSCOMMANDERSWITCH
//#define NO_BUTTONSCOMMANDERPOTENTIOMETER
#define NO_CANCOMMANDER
//#define NO_DCCCOMMANDER
//#define NO_I2CCOMMANDER
//#define NO_SERIALCOMMANDER

Cette longue litanie de #define NO_ est là pour vous permettre d’exclure définitivement des parties de la bibliothèque qui ne vous sont pas utiles à l’instant T. Enlevez le ’//’ devant le #define NO_BUTTONSCOMMANDER, et tout le code correspondant aux boutons sera purement et simplement éliminé de la compilation ! Le compilateur tente bien de faire ce travail tout seul, mais il peut échouer dans certains cas particuliers. Vous gagnerez ainsi un peu de mémoire programme, et peut être aussi un peu de mémoire dynamique, mais pas forcément. C’est plus flagrant avec les bus (I2C, CAN, DCC, SERIAL) qui en général déclarent des zones mémoires de tampon qui vont être inutiles si le bus en question n’est pas utilisé.
L’autre usage concerne l’emploi de bibliothèques extérieures qui ne sont pas toujours présentes. Par exemple, NO_CANCOMMANDER est activé par défaut parce que le CANCommander a besoin de la présence d’une bibliothèque ’mcp_can’ pour fonctionner. Comme le CAN est d’un usage rare et que cette bibliothèque n’est pas toujours présente, j’ai choisi de désactiver le CANCommander par défaut. Pour le réactiver, il suffit de remettre le ’//’ devant le #define NO_CANCOMMANDER. Bien entendu, il faudra aussi que vous ayez la bibliothèque mcp_can installée. Pour vous éviter de fastidieuses recherches, elle est présente dans le répertoire ’extra’ !

La mise au point

C’est toujours difficile sur un Arduino de trouver la ligne qui fait que rien ne se passe comme prévu... J’ai inclus deux mécanismes pour aider a faire marcher le programme.

Toujours dans le fichier Commanders.h , vous verrez :

//#define COMMANDERS_DEBUG_MODE

Retirez les deux ’//’ qui représentent le début d’un commentaire. En faisant cela, vous verrez apparaître sur la console série tout un tas de messages d’initialisation, et éventuellement d’erreur. Avant de passer à la suite corrigez ces erreurs, inutile d’aller plus loin si Commanders lui même vous signale des problèmes ! Pendant l’exécution, vous verrez aussi passer des messages vous informant du fonctionnement de la bibliothèque : activation d’un commander, envoi d’un événement, etc...
Je vous ai mis à disposition une fonction PrintEvent qui formatte et affiche un événement sur la console, comme c’est le cas dans l’exemple cité plus haut... Utile pour savoir si Commanders a bien reçu l’ordre voulu, quel que soit le canal. Attention : certains des exemples fournis ne compileront correctement qu’avec le mode debug activé parce qu’ils utilisent PrintEvent !

Ces affichages augmentent considérablement la taille du programme et affecte aussi un peu sa vitesse. Avant de mettre l’Arduino en production, il vaut mieux penser à remettre le ’//’ à sa place pour revenir à un programme léger et réactif ! D’ailleurs il peut arriver que j’oublie de remettre le ’//’ avant de construire le .zip de la bibliothèque. Normalement en fonctionnement, Commanders n’envoie rien sur la console. Donc si vous voyez apparaître le Copyright et d’autres choses, remettez le ’//’ en place !

Où ça se passe...

Le bibliothèque est disponible ici : Forge Locoduino

Notez que dans le répertoire ’extras/Doc’ se trouve une documentation html visible sur n’importe quel système avec n’importe quel navigateur un peu moderne. Cette documentation reprend en Anglais l’ensemble des informations données ici et détaille plus précisément les rôles des classes, des fonctions et de leurs arguments. Sous Windows pour la lancer, il suffit de double cliquer sur le fichier StartDoc.bat présent dans le répertoire de la bibliothèque, sinon il faut manuellement double-cliquer sur le fichier ’extras/Doc/index.html’ .

Commanders utilise une autre bibliothèque, appelée Dio2, qui gère des accès plus rapide aux broches qu’avec les fonctions natives de l’Arduino. C’est transparent pour l’utilisateur de Commanders, mais nécessaire pour réduire les temps de traitement. Cette bibliothèque annexe est disponible dans le répertoire ’extras’ présent avec les sources de la bibliothèque Commanders. Elle est également disponible sur la Forge Locoduino

Conclusion

La virtualisation des comportements des Commanders permet de pouvoir allumer la même DEL avec un bouton poussoir, un interrupteur, un ordre DCC, un message CAN, un message I2C ou une demande sur la ligne de la console série ! La légèreté du code, allié à la quasi certitude que tout est fait pour que le matériel réponde au doigt et à l’œil (rebonds des poussoirs, buffer circulaire en CAN, gestion d’un encodeur...) permet de coder sereinement des exemples hyper simples comme des projets plus importants.

[1William Shatner / Y a t-il enfin un pilote dans l’avion 2

48 Messages

Réagissez à « Bibliothèque Commanders »

Qui êtes-vous ?
Votre message

Pour créer des paragraphes, laissez simplement des lignes vides.

Lien hypertexte

(Si votre message se réfère à un article publié sur le Web, ou à une page fournissant plus d’informations, vous pouvez indiquer ci-après le titre de la page et son adresse.)

Rubrique « Bibliothèques »

Bibliothèque Accessories (1)

Bibliothèque Accessories (2)

Un décodeur d’accessoires universel (1)

Un décodeur d’accessoires universel (2)

Un décodeur d’accessoires universel (3)

Bibliothèque LcdUi (1)

Bibliothèque LcdUi (2)

La bibliothèque Servo

Bibliothèque SoftWare Serial

Bibliothèque Serial

Bibliothèque EEPROM

Bibliothèque Wire : I2C

Bibliothèque LCD

La bibliothèque ScheduleTable

Bibliothèque MemoryUsage

Bibliothèque EEPROMextent

La bibliothèque SlowMotionServo

Bibliothèque Commanders

Bibliothèque DCCpp

Bibliothèque DcDccNanoController

La bibliothèque ACAN (1)

La bibliothèque ACAN (2)

Bibliothèque LightEffect

Les derniers articles

Bibliothèque LightEffect


Christian

La bibliothèque ACAN (2)


Jean-Luc

La bibliothèque ACAN (1)


Jean-Luc

La bibliothèque SlowMotionServo


Jean-Luc

Bibliothèque DCCpp


Thierry

Bibliothèque DcDccNanoController


Thierry

Bibliothèque LcdUi (2)


Thierry

Bibliothèque LcdUi (1)


Thierry

Bibliothèque Accessories (2)


Thierry

Bibliothèque Accessories (1)


Thierry

Les articles les plus lus

Bibliothèque Wire : I2C

La bibliothèque Servo

Bibliothèque SoftWare Serial

Bibliothèque DCCpp

Bibliothèque DcDccNanoController

Un décodeur d’accessoires universel (1)

La bibliothèque ACAN (1)

Bibliothèque Commanders

Bibliothèque EEPROM

Bibliothèque Serial