Commander OpenRails à partir d’un potentiomètre

Après avoir étudié les commandes de type bouton poussoir, intéressons nous désormais à un autre type de contrôle que l’on peut trouver sur un pupitre de conduite : le potentiomètre. Contrairement aux boutons poussoirs, qui s’assimilent relativement facilement à des appuis sur une touche de clavier, les potentiomètres renvoient une valeur analogique, qui une fois traitée s’assimile à une information de type pourcentage. Or, OpenRails ne gère pas ce type d’information en entrée, comme le permettent certains jeux vidéos commandés par des joysticks. Il va donc falloir ruser pour que notre potentiomètre agissent sur le jeu.

Le principe électronique du potentiomètre

Symbole normalisé du potentiomètre

Avant tout, attardons nous un instant sur le potentiomètre. De nombreux sites dédiés à l’électronique expliquent son principe de fonctionnement, je ne vais donc pas m’y attarder. Sachez simplement que le potentiomètre est équivalent à un diviseur de tension réglable. Il comporte 3 broches, deux permettent de fixer la plage de réglage de la tension, et la 3ème sera à un potentiel compris entre les deux potentiels extrêmes, et dépendra de la position mécanique du potentiomètre (qui peut être rotatif ou linéaire).

Le montage ci-dessous présente un potentiomètre relié à une carte Arduino. On utilisera une broche d’entrée analogique, qui permettra de lire une tension comprise entre 0V et 5V (attention sur les cartes Due il ne faut pas utiliser le 5V mais le 3,3V) :

Une fois le montage réalisé, on lit la valeur du potentiomètre et on l’enregistre dans une variable (nommée ici « pot1 »), et on l’affiche sur le terminal Arduino de la façon suivante :

int pot

void setup(){
Serial.begin(9600);
}

void loop(){
pot1 = analogRead(A1);
Serial.print(pot1);
delay(100);
}

Si vous observez bien la valeur du potentiomètre dans le terminal, c’est que le prérequis électronique à la partie programmation que nous allons aborder est maintenant terminé.

NB : la fonction analogRead renvoie une valeur de potentiomètre entre 0 et 255. Pour la convertir en pourcentage, la fonction map est très utile :

pot1pourcent = map(pot1, 0, 255, 0, 100);

Le principe de la commande d’OpenRails

Nous l’avons dit, OpenRails ne gère pas les Joysticks, et on ne peut donc pas lui donner directement en entrée une valeur comprise entre 0 et 100% qu’il répercuterait sur une variable interne (par exemple le pourcentage de traction). OpenRails ne comprend que des envois de touches de clavier. Autrement dit on ne peut pas lui dire « mets la traction à 7% » comme le ferait un joystick, mais seulement « augmente la traction de 1% » (par l’appui de la touche de clavier « D »). Par contre, on se rend compte que, si au départ la traction est à 0%, on peut obtenir le résultat souhaité en lui disant 7 fois « augmente la traction de 1% ». C’est d’ailleurs ce que l’on fait manuellement lorsque l’on commande avec un bouton poussoir, ou équivalent, une locomotive à crans.

C’est cette méthode que nous allons désormais exploiter. Côté OpenRails, la locomotive utilisée doit être configurée comme si elle était à crans. Cela se passe dans le fichier .eng (TRAINS/TRAINSET/votre_dossier_loco/votre_loco.eng). Il faut définir les 100 pas de 1% comme s’il s’agissait de crans de tractions que l’on ne peut passer que un par un (avec un relâchement de la touche nécessaire entre deux) :

    EngineControllers (
        Throttle ( 0 1 0.01 0
            NumNotches ( 101
                Notch ( 0.00  0 Dummy )
                Notch ( 0.01  0 Dummy )
                Notch ( 0.02  0 Dummy )
                Notch ( 0.03  0 Dummy )
                Notch ( 0.04  0 Dummy )

               /*** définir les "Notch" un par un avec un pas de 0,1***

                Notch ( 0.96  0 Dummy )
                Notch ( 0.97  0 Dummy )
                Notch ( 0.98  0 Dummy )
                Notch ( 0.99  0 Dummy )
                Notch ( 1.00  0 Dummy )
            )
        )

Il est possible de se limiter à 50 « crans » avec des pas de 2%, pour permettre des réactions plus rapides. C’est pour ma part cette solution que j’ai retenue sur le simulateur de BB26000.

Maintenant que notre locomotive se comporte comme une machine à crans, passons au code Arduino permettant de transformer la position du potentiomètre en une série d’appuis de clavier.

L’idée va dans un premier temps être la suivante : on crée une variable qui représente la valeur de en % de la variable dans OpenRails, et on la compare en permanence à la valeur renvoyée par notre potentiomètre. Si la valeur dans le jeu est plus faible que celle du potentiomètre, on émule une touche de clavier « D » pour l’augmenter, sinon on émule une touche « Q » pour la réduire. Si les valeurs sont égales on ne fait rien. A chaque fois que l’on envoie une touche de clavier à OpenRails, on incrémente la variable « % dans OpenRails » afin de garder une image de la valeur réelle dans le jeu. Ce n’est ni plus ni mois que le principe d’un asservissement.

En l’absence de retour d’information du jeu, pour commencer, on initialise la variable « % dans OpenRails » à 0%. En supposant que les émulations de touches de clavier sont toutes bien reçues par OpenRails, l’incrémentation et la décrémentation progressive de cette variable simultanée à l’émulation d’une touche permettent de garder à tout moment une image de la valeur dans le jeu.

Pour simplifier la compréhension, on considère que la variable commandée est le pourcentage de traction et on définir les variables suivantes :

int cran_virtuel; // valeur lue du potentiomètre
int niveauTraction_calcule; // valeur calculée par incrémentation du pourcentage de traction dans OpenRails

On obtient ainsi le code suivant :

void setup(){

   Keyboard.begin();
   niveauTraction_calcule = 0;
}

void loop(){
 
   cran_virtuel = map(pot1, 0, 255, 0, 100); // remplacer 100 par 50 si on se limite à 50 crans dans OR

   if(cran_virtuel > niveauTraction_calcule){
		Keyboard.press('d'); // progression d'un cran dans OpenRails
		niveauTraction_calcule = niveauTraction_calcule + 1; // incrémentation de la variable image du cran dans le jeu
		delay(50);
        Keyboard.release('d');
   }

   if(cran_virtuel < niveauTraction_calcule){
		Keyboard.press('q'); // régression d'un cran
		niveauTraction_calcule = niveauTraction_calcule - 1; // décrémentation de la variable image du cran dans le jeu
		delay(50);
		Keyboard.release('q');
   }
}

Ce code nous permet d’avoir en première approche une commande d’Open Rails par un potentiomètre.

Selon la qualité du potentiomètre, un premier problème de stabilité peut se présenter : la valeur analogique lue peut osciller entre deux valeurs proches, ce qui va avoir pour effet de faire osciller la variable « cran_virtuel » entre deux pourcentages. En appliquant le code ci-dessus, l’effet immédiat et que la carte Arduino va sans cesse envoyer alternativement des touches ‘d’ et ‘q’ au jeu. Pour palier à ce problème, il est possible de conditionner la mise à jour de la variable « cran_virtuel » à un seuil de différence avec la valeur précédent. Cela se traduit de la façon suivante, avec ici un seuil à 5% qu’il sera possible d’ajuster :

if(abs(cran_virtuel - map(pot1, 0, 255, 0, 100)) > 5){
   cran_virtuel = map(pot1, 0, 255, 0, 100);
}

Avec cette solution, il ne faut pas oublier de forcer le « cran_virtuel » à 0 si le potentiomètre est ramené à 0, car le seuil de 5% empêcherait par exemple de ramener la traction de 3% à 0%. Cela se fait en ajoutant en modifiant le code ci-dessus comme suit :

if(abs(cran_virtuel - map(pot1, 0, 255, 0, 100)) > 5){
   cran_virtuel = map(pot1, 0, 255, 0, 100);
}
if(pot1 == 0){
   cran_virtuel = 0;
}

Un deuxième problème qui se posera certainement à vous, est la fidélité de la variable « niveauTraction_calcule » au pourcentage de traction réel dans OpenRails. En effet, cette variable est calculée de proche en proche par incrémentation et décrémentation successive. Si une des émulation clavier n’était pas correctement reçue par OpenRails (ce qui arrive régulièrement), un décalage se produirait. Il est donc possible d’améliorer le code ci-dessus en mettant régulièrement à jour cette variable avec la valeur réelle de traction dans OpenRails, obtenue avec la méthode décrite dans l’article Envoyer les variables de simulation à une carte Arduino appliqué à la variable « Throttle ».

Enfin, je rappelle que cet article décrit un fonctionnement de principe. Pour l’intégrer dans un code complet de simulateur, il est recommandé de se passer de la fonction « delay », et de fonctionner par comparaison de l’horloge (fonction « millis() ») à des repères temporels. Cette méthode fera l’objet d’un article ultérieur.

Ultérieurement, le code complet de la gestion du manipulateur de traction/freinage de la BB26000 sera publié, dans le cadre de ce projet OpenSource. En attentant, à vous de jouer pour adapter la méthode décrite ci-dessus à votre projet !

Laisser un commentaire