Piloter une locomotive avec un ESP8266

Avec le train de jardin, j’ai voulu évacuer tout de suite le problème de captation de courant par les rails. Après plusieurs années dehors, le travail de nettoyage deviendra fastidieux et le plaisir s’en ira. J’ai donc cherché une méthode et je suis parti sur un pilotage via ESP8266 et batterie externe.

Tout d’abord, une grand merci à Jacques du site http://www.train35.fr/ qui a été d’une très grande inspiration dans mes recherches et mises en oeuvre.

Principe de fonctionnement

Classiquement, une locomotive analogique capte le courant sur les rails pour alimenter un moteur qui entraine les roues de la locomotive. Plus le voltage est élevé, plus la locomotive avance vite.

Dès que le réseau devient grand, il faut gérer :

  • la séparation en canton (zones) afin de permettre de faire circuler plusieurs trains en même temps sur le réseau (sinon ils tournent tous avec la même tension)
  • la reprise d’alimentation à effectuer à plusieurs endroits du réseau
  • une très grosse alimentation (>3 ou 4 A) dès que l’on veut plusieurs locomotives en même temps
  • etc…

Pour contourner ce problème, j’ai pris le parti de considérer que chaque loco devrait être autonome avec son alimentation. Ainsi, il ne restera qu’à gérer le positionnement des trains sur le réseau pour avoir un système à peu près complet.

La locomotive doit donc ne plus capter le courant via ses roues sur les rails (voir l’article sur la transformation de la loco) mais par une batterie externe.

Asservissement du moteur

Il ne s’agit pas de piloter le moteur directement avec l’ESP8266 car ca ne serait pas possible. Au lieu de de ça, on va utiliser un pont en H qui va transformer un signal PWM fourni par l’ESP8266 en une tension équivalente à la locomotive. J’ai choisi d’utiliser un L298N.

Ce module permet de faire 2 moteurs DC soit en tension fixe, soit en PWM. Avant de détailler le principe du moteur, voici le schéma final retenu pour la locomotive.

Le bornier du bas sert pour l’alimentation générale. J’ai choisi une batterie Lipo 3C 11,1V (marque Tattu). Le 3ème bornier bleu est une sortie 5V permettant d’alimenter l’ESP8266 directement.

Ensuite, on retrouve 6 pins : ENA, IN1, IN2, IN3, IN4, ENB.

On a un premier bloc ENA, IN1, IN2. Le principe sera identique pour les 3 autres pins. Si on laisse le cavalier ENA, on ne pilote que IN1 et IN2. On aura alors en sortie une tension fixe sur OUT1/OUT2 de +VCC ou -VCC (dépend de votre source d’entrée.

ENA/ENBIN1/IN3IN2/IN4OUT1-2/OUT3-4
Cavalier en placeHIGHLOWRotation sens 1 +VCC
Cavalier en placeLOWHIGHRotation sens 2 -VCC
Cavalier en placeLOWLOWMoteur arrêté
Cavalier en placeHIGHHIGHMoteur bloqué
Cavalier enlevéHIGHLOWRotation sens 1 PWM
Cavalier enlevéLOWHIGHRotation sens 2 PWM
Cavalier enlevéLOWLOWMoteur arrêté
Cavalier enlevéHIGHHIGHMoteur bloqué

Sur un ESP8266, le PWM se gère de 0 à 1023 (100%). Pour avoir 50% de puissance, on appliquera donc un PWM de 512.

J’ai choisi le nodemcu comme ESP8266. Les pins PWM sur un Nodemcu sont celles-ci :

Source : https://www.electronicwings.com/nodemcu/nodemcu-pwm-with-arduino-ide

Pour définir la valeur PWM, on utilise la fonction analogWrite(). Voici un exemple.

#define pinENA D1
pinMode(pinENA, OUTPUT);
analogWrite(pinENA,650);

Communication MQTT

Comme décrit sur l’article MQTT, ce protocole sert à échanger des messages via un broker. J’ai choisi de partir sur cette technologie pour faciliter l’information. On imagine quand chaque élément du réseau sera en nodemcu (loco, aiguillage, détecteur ILS pour la rétrosignalisation), il sera facile via un serveur de récupérer l’ensemble des informations.

Pour le moment, j’utilise le broker MQTT de mon serveur domotique avec le wifi de la maison. A terme, un raspberry pi sera le centre du réseau. Il servira de coeur de système, sera broker MQTT, serveur web, hotspot wifi du réseau et enfin une application PHP pilotera intégralement le réseau.

Principe de fonctionnement de la locomotive

Le code est somme toute très classique. Connexion au wifi, connexion au broker MQTT et abonnement au topic. On déclare un topic dédié pour la locomotive.

char* topic = "train/loco/loco01";

Comme dit plus haut, le moteur 1 du module L298H servira pour le moteur de la locomotive, le moteur 2 servira pour les lumières de la loco (comme la valeur est fixe, le cavalier restera en place sur ENB).

On déclare donc les variables en conséquence :

// définition des pins de l'Arduino qui contrôlent le 1er moteur
#define pinIN1 4 //D2
#define pinIN2 0 //D3
#define pinENA D1 //D1, doit être une pin PWM

// définition des pins de l'Arduino qui contrôlent les lampes
#define pinIN3 14 //D5
#define pinIN4 12 //D6

Puis on les initialise dans le setup :

//déclaration des pin comme sorties
  pinMode(pinIN1, OUTPUT);
  pinMode(pinIN2, OUTPUT);
  pinMode(pinENA, OUTPUT);
  
  pinMode(pinIN3, OUTPUT);
  pinMode(pinIN4, OUTPUT);
  
  //Marche avant par défaut
  digitalWrite(pinIN1, HIGH);
  digitalWrite(pinIN2, LOW);
  //Vitesse 0
  analogWrite(pinENA,  0);
  //Feux éteints
  digitalWrite(pinIN3, LOW);
  digitalWrite(pinIN4, LOW);

Aparté sur la fréquence PWM : par défaut, le PWM du nodemcu tourne à 1 kHz. Avec cette fréquence, vous entendrez le moteur siffler à basse vitesse, ce qui est normal. Ça n’abime pas le moteur mais est un peu casse pied. Pour régler le problème, il faut changer la fréquence PWM. Mais attention, le L298H ne supporte pas plus de 25 kHz (d’autres modèles peuvent aller plus haut), sachant qu’au delà de 18/20 kHz, nos oreilles n’entendent plus ces bruits.

Du coup, faites des tests et n’allez pas trop haut pour ne pas faire souffrir le L298H. Mes tests se sont arrêtés sur 12 kHz. On définit donc la fréquence comme suit, toujours dans le setup.

  //Modifier la fréquence PWM -> pour ne pas que la loco "siffle",
  //il faut des fréq > 10 kHz. 
  //Il faut faire plusieurs essais.
  //Attention : ne pas monter >20 kHz car le L298H n'aime pas trop
  analogWriteFreq(12000);

Pour contrôler la loco, on va le faire en fonction du message MQTT envoyé. J’ai décidé de n’utiliser qu’un seul caractère à l’envoi. De 0 à 8, ce seront les crans de vitesse, F et B définiront le sens de marche (front/back), O et N définiront les feux (O = ON / N = OFF).

Dans la fonction callback de MQTT, on ajoute donc le code souhaité pour piloter la loco. Le code ci dessous est commenté pour être compréhensible.

//Gestion de la Vitesse. 
//La valeur varie de 0 à 1023. 
//Cette loco démarre autour de 650/1023 (environ 5V). 
  //Ensuite, les palliers sont progressifs
  if ((char)payload[0] == '0') analogWrite(pinENA,  0);
  if ((char)payload[0] == '1') analogWrite(pinENA,  650);
  if ((char)payload[0] == '2') analogWrite(pinENA,  720);
  if ((char)payload[0] == '3') analogWrite(pinENA,  770);
  if ((char)payload[0] == '4') analogWrite(pinENA,  820);
  if ((char)payload[0] == '5') analogWrite(pinENA,  870);
  if ((char)payload[0] == '6') analogWrite(pinENA,  920);
  if ((char)payload[0] == '7') analogWrite(pinENA,  970);
  if ((char)payload[0] == '8') analogWrite(pinENA,  1023);
  

  //Gestion du Sens de marche
  //Marche avant
   if ((char)payload[0] == 'F') {
    analogWrite(pinENA,  0);
    digitalWrite(pinIN1, HIGH);
    digitalWrite(pinIN2, LOW);
   }
   //MArche arriere
   if ((char)payload[0] == 'B') {
    analogWrite(pinENA,  0);
    digitalWrite(pinIN1, LOW);
    digitalWrite(pinIN2, HIGH);
   }

   //Gestion des Feux
   //Eteint
   if ((char)payload[0] == 'O') {
    digitalWrite(pinIN3, HIGH);
    digitalWrite(pinIN4, LOW);
   }
   //Allumés
   if ((char)payload[0] == 'N') {
    digitalWrite(pinIN3, LOW);
    digitalWrite(pinIN4, LOW);
   }

Il n’y a rien d’autre à rajouter ! Avec ces quelques lignes, on récupère le message et la locomotive s’exécute instantanément. C’est très facile à faire, le code global Arduino fait 173 lignes avec les commentaires !

Le code complet de la loco est à retrouver sur github : https://github.com/doddyfab/Nodemcu_LGB_Locomotive/blob/master/Nodemcu_LGB_Loco01.ino

Interface PHP

Sur mon serveur PHP, j’ai developpé une interface basé sur AdminLTE3 (voir l’article sur le site web de la météo), auquel j’ai rajouté la classe php phpMQTT.php pour la gestion MQTT. Voici la fonction de publication d’un message MQTT;

function publishMQTT($topic,$message){
  /*********************
  -----MQTT------
  *********************/
  $mqtt_server = "xxxxx";     
  $mqtt_port = 1883;                     
  $mqtt_username = "xxxxx";                 
  $mqtt_password = "xxxxx";                  
  $mqtt_client_id = "Ribotrain"; 

  $mqtt = new phpMQTT($mqtt_server, $mqtt_port, $mqtt_client_id);
  if ($mqtt->connect(true, NULL, $mqtt_username, $mqtt_password)) {
    $mqtt->publish($topic, $message, 0);
    $mqtt->close();
  } else {
      echo "Time out!\n";
  }
}

Dans la page, on déclare des boutons plats dans un formulaire, qui envoie donc une requête POST à la même page PHP. Ce POST est traité pour récupérer le choix fait et exécuter le code correspondant. Voici l’interface :

Et voici le code POST de post-traitement pour par exemple passer la loco en vitesse 5 :

if(isset($_POST['btn_loco01_5'])){
  publishMQTT("train/loco/loco01",5);
  $tab['loco'][1]['vitesse'] = 5;
}

Voici un aperçu en réel du système :

Et voici quelques photos de l’installation :

La loco est accrochée à son wagon qui dispose de tout le matériel pour tracter !

Conclusion

Le système est assez facile à réaliser, et on ne dépend plus ni de l’analogique traditionnel ni du DCC couteux. Un effort certain de programmation est nécessaire mais il ouvre selon moi de nouvelles perspectives sur nos réseaux extérieurs. Les prochaines étapes seront l’ajout de sonorisation dans le wagon suiveur puis une réflexion sur l’automatisation de trajets avec une rétrosignalisation par ILS.

2 Comments

Laisser un commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.