Après avoir disserté de la récupération des variables de simulation d’Open Rails vers le pupitre, il est temps de leur trouver une première utilisation ! Sur presque tous les pupitres de locomotives, vous trouverez des jauges circulaires à aiguilles, et c’est de ce sujet que nous allons traiter aujourd’hui. Ci-dessous, je vous propose une petite vidéo, réalisée il y a un certain nombre d’années, de mon premier prototype d’indicateur de vitesse de ce type. On y reconnait le protocole d’envoi des données du programme Python vers la carte Arduino, et l’aiguille de la jauge est commandée par un servomoteur électrique.
Le montage
Avant tout, regardons de quoi nous avons besoin. En plus de la traditionnelle carte Arduino (peu importe le modèle), il faudra utiliser un mini servomoteur électrique.
En voici un exemple : https://www.gotronic.fr/art-servomoteur-analogique-miniature-fs90-25826.htm, mais vous pouvez prendre d’importe quel modèle puisqu’ils fonctionnent tous sur le même principe. A noter cependant qu’il est parfois intéressant d’avoir un servomoteur le plus petit possible (par exemple pour le loger dans un manomètre). Sachez aussi que les modèles à quelques euros comme celui ci-dessus se trouvent sur ebay par lots de 10 ou plus, avec parfois un ou plusieurs servos défectueux ou bruyant à l’intérieur. Je vous conseille donc de toujours les tester avant de les monter sur votre système (je me suis déjà rendu compte d’un servomoteur HS alors que je venais de le coller à l’intérieur d’un manomètre après plusieurs heures de travail !).

Reliez votre servomoteur à votre carte Arduino de la façon suivante :
Fil brun -> GND
Fil rouge -> 5V
Fil jaune -> Pin de commande au choix (NB : les pins 0 et 1 sont inutilisables en même temps que le port série)
(les couleurs peuvent légèrement varier selon le modèle, n’hésitez pas à consulter la documentation)
Remarque : Si vous utilisez un nombre important de servomoteurs, n’utilisez pas l’alimentation 5V de la carte Arduino mais une alimentation externe (type alimentation de PC par exemple). En effet, la puissance disponible sur l’Arduino est limitée. Par ailleurs, même avec une carte Due, le fil rouge doit être relié au 5V.
Piloter un servomoteur
Le pilotage d’un servomoteur avec Arduino fait appel à la bibliothèque « Servo » qu’il faudra importer, et dont la documentation est disponible sur le site Arduino. Il faut ensuite créer un objet servomoteur pour chacun de vos servos. Déclarez ensuite votre servomoteur dans le bloc « setup ». Enfin, pour commander votre servomoteur, utiliser la fonction « write() », avec une valeur en argument comprise entre 0 et 180 qui correspond à l’angle du servomoteur.
Dans l’exemple ci-dessous, on va faire tourner le servo entre ses deux positions extrêmes toutes les secondes.
#include <Servo.h>
Servo myservo1; // instanciation d'un premier objet servo
Servo myservo2; // exemple d'instanciation d'un deuxième objet servomoteur
void setup() {
myservo1.attach(3);
}
void loop() {
myservo1.write(0);
delay(1000);
myservo1.write(180);
delay(1000);
}
Notez qu’avec cette fonction « write() », on dispose de 180 pas pour piloter le servomoteur. Il existe une fonction « writeMicroseconds() » qui permet de commander le servomoteur avec 1000 pas avec un argument variant de 1000 (équivalent à 0°) et 2000 (équivalent à 180°).
Le bloc loop ci-dessus peut donc se réécrire de manière équivalente de la façon suivante :
void loop() {
myservo1.writeMicroseconds(1000);
delay(1000);
myservo1.writeMicroseconds(2000);
delay(1000);
}
Les servomoteurs bas de gamme ne sont pas toujours très précis, aussi je vous encourage à faire des tests avec différentes valeurs pour bien noter les valeurs extrêmes.
On utilisera par la suite cette fonction writeMicroseconds();
Afficher la valeur d’une variable de simulation
Nous allons désormais supposer que vous avez suivi toute la marche à suivre pour récupérer sur votre carte Arduino la valeur des variables de simulation. Vous disposez donc d’une variable « vitesse » sous forme d’un nombre entier qui contient la vitesse du train en km/h (ou toute autre variable, par exemple la pression CG, etc.).
Imaginons que comme dans l’exemple nous souhaitons afficher cette vitesse sur une jauge à l’aide de notre servomoteur, avec les correspondances suivantes : 0° pour 0 km/h, et 180° pour 160km/h. Pour cela, la fonction « map() » nous sera très utile. Celle-ci permet de redistribuer linéairement une variable, en changeant les bornes. Par exemple, dans notre cas, nous écrirons dans le bloc loop :
valeurServoVitesse = map(vitesse, 0, 160, 1000, 2000);
myServo1.writeMicroseconds(valeurServoVitesse);
Dans l’ordre, les arguments de « map() » sont les suivants :
– variable de départ
– valeur minimale de départ
– valeur maximale de départ
– valeur minimale d’arrivée
– valeur maximale d’arrivée
Nous avons là un premier programme d’affichage d’une variable à l’aide d’un servomoteur. Celui-ci fonctionne très bien pour l’affichage de la vitesse puisque celle-ci ne varie pas très vite. Avec un rafraichissement de la variable « vitesse » environ toutes les demi-secondes, on a un mouvement de l’aiguille tout à fait similaire à ce que l’on observe en réalité sur un Tachro. Pour des jauges de types manomètres, en revanche, on peut rechercher un mouvement beaucoup plus fluide de l’aiguille (il s’agit normalement d’une évolution continue d’une pression d’air). C’est ce point que nous allons aborder à présent.
Obtenir un mouvement continu des servomoteurs
L’idée pour obtenir un mouvement fluide et continu des servomoteurs est de passer progressivement par toutes les valeurs intermédiaires lorsque l’on commande un saut de position. Au lieu de directement dire au servomoteur « va à la nouvelle valeur que le jeu m’envoie », on va comparer sa position à cette valeur, et l’incrémenter tant qu’on ne l’a pas atteinte. En supposant que la variable pressionCG a été précédemment obtenue, cela donne un programme de la forme suivante :
int consigneServoCG = 1000;
int valeurServoCG = 1000;
void loop(){
consigneServoCG = map(pressionCG, 0, 50, 1000, 1600);
if (consigneServoCG > valeurServoCG ){
valeurServoCG += 1;
myServo1.write(valeurServoCG);
delay(2); //Diminuer le délais ici pour augmenter la vitesse de variation du manomètre
}
if (consigneServoCG < valeurServoCG ){
valeurServoCG -= 1;
myServo1.write(valeurServoCG);
delay(2); // Diminuer le délais ici pour augmenter la vitesse de variation du manomètre
}
}
Rappelons que l’utilisation de « delay » n’est pas conseillé dans un programme en raison de son caractère bloquant. Nous allons donc réécrire le programme ci-dessus en l’adaptant avec l’utilisation de millis().
int consigneServoCG = 1000;
int valeurServoCG = 1000;
unsigned long timerCG = 0;
unsigned long delayCG = 2; // Diminuer le délais ici pour augmenter la vitesse de variation du manomètre
void loop(){
consigneServoCG = map(pressionCG, 0, 50, 1000, 1600);
if (consigneServoCG > valeurServoCG and millis() >= timerCG + delayCG){
timerCG = millis();
valeurServoCG += 1;
myServo1.write(valeurServoCG);
}
if (consigneServoCG < valeurServoCG and millis() >= timerCG + delayCG){
timerCG = millis();
valeurServoCG -= 1;
myServo1.write(valeurServoCG);
}
}
Comme toujours, n’hésitez pas à adapter le programme, en particulier les délais, pour arriver au résultat parfait !