La détection des locomotives et des convois sur nos réseaux est essentielle dès que nous souhaitons introduire un peu d’automatisation, en particulier pour ce qui concerne la sécurité. Les méthodes de détection classiques fonctionnent généralement bien pour signaler la présence (ou non) d’une locomotive, mais peu sont capables de nous renseigner sur l’adresse DCC de la locomotive.
Par exemple, avec un LMD18200, on envoie un état HIGH sur la broche Brake.
Le signal qui est alors retourné par la locomotive durant ce cutout est très faible, quelques mA. Il nécessite donc une électronique appropriée pour l’amplifier. C’est le rôle du décodeur que nous vous proposons.
Et pour pouvoir en tirer parti, il faut « traiter » ce signal car il est codé de façon assez complexe. C’est l’objet du programme proposé qui délivre, in fine, l’adresse de la locomotive.
Nous allons donc parler tour à tour de la carte de décodage et de l’application que nous avons développée permettant d’obtenir le numéro de locomotive. Et comme il n’existe pas à notre connaissance de centrales DCC en DIY permettant de générer de cutout, nous vous proposerons une centrale DCC++ sur une base ESP32 que nous avons développé pour obtenir cette possibilité.
En fait, on devrait plutôt dire les cartes car vous aurez besoin d’autant de cartes que le nombre de cantons pour lesquels vous souhaitez faire de la détection pour connaître l’adresse de la locomotive.
Schéma d’implantation de principe
Le détecteur se monte en série entre l’alimentation en provenance de la centrale et les rails du canton. Les deux câbles d’entrée doivent donc être reliés à DCC In et la sortie vers les rails est raccordée sur DCC Out. Il faut bien sûr respecter la polarité sur toutes les cartes. Notez également que les deux rails doivent être isolés entre chaque canton.
Sur le bornier triple, il faut relier la masse commune avec le microcontrôleur et l’alimentation VCC. Cette alimentation doit avoir la même tension que celle du microcontrôleur, soit 5V pour un Arduino ou 3,3 V pour un ESP32. Ceci pour assurer que la tension du signal série délivrée soit compatible avec la tension de fonctionnement du microcontrôleur.
Le signal produit par le détecteur est un classique signal série 8N1 soit 8 bits de données, pas de parité de bit et 1 bit de stop. La vitesse de transmission est de 250 Kbps.
Ce signal peut donc être envoyé sur la broche RX de n’importe quel Arduino ou ESP. En pratique, il sera préférable d’utiliser des cartes possédant plusieurs entrées RX comme un Mega ou un ESP32. Avec un débit de 250 Kbs, il est peu probable que des bibliothèques comme SoftwareSerial supportent de lire plusieurs ports série sur des cartes de faible puissance comme le Uno ou le Nano.
Pour peu que vous ayez choisi le bon débit (250 Kbps), la fonction Serial.read() vous permettra d’afficher très simplement les caractères reçus sur le moniteur série de l’IDE Arduino par exemple.
Voici le schéma de la carte :
la liste des composants :
et les fichiers Gerber :
Les programmes pour décoder :
Lire les bits transmis par le décodeur n’est pas très compliqué. Néanmoins, à ce stade, on est loin encore de pouvoir obtenir l’adresse de notre locomotive. Le décodage des messages consiste en une succession d’opérations assez complexes. Sans entrer dans des détails, on peut tout de même signaler que le signal est dit 4/8 encoding. Cela veut dire que, pour s’assurer d’une transmission correcte, chaque trame envoyée doit avoir 4 bits à 1 et 4 bits à zéro.
Nous vous proposons ci-après trois programmes différents selon ce que vous souhaitez faire. Ces programmes sont adaptés à ESP32 mais doivent pouvoir être portés sur Arduino sans difficulté majeure.
Le programme railcom_detector_ESP32
Ce programme a un intérêt plutôt théorique puisqu’il se contente d’afficher l’adresse de la locomotive dans le moniteur série. Mais il servira de base pour tester puis adapter vos propres développements.
Voici ce qu’il faut principalement savoir sur ce code :
#ifndef ARDUINO_ARCH_ESP32
#error "Select an ESP32 board"
#endif
Empêche le fonctionnement sur une autre carte qu’un ESP32
#include <RingBuf.h> // https://github.com/Locoduino/RingBuffer
#define NB_ADDRESS_TO_COMPARE 100 // Nombre de valeurs à comparer pour obtenir l'adresse de la loco
RingBuf<uint16_t, NB_ADDRESS_TO_COMPARE> buffer;
Le programme compare l’adresse décodée avec, ici, les 100 dernières adresses lues. Ce qui limite les éventuelles lectures défectueuses. Pour celà, il utilise la bibliothèque Locoduino RingBuf disponible sur le github :
const byte railComRX = 14; // GPIO14 connecté à RailCom Detector RX
const byte railComTX = 17; // GPIO17 non utilisée mais doit être déclarée
Vous pouvez choisir la broche RX pour la réception des données série. Ici, la broche 14 est sélectionnée. La sortie TX n’est pas utile ici mais doit cependant être renseignée.
TaskHandle_t ReceiveData;
TaskHandle_t ParseData;
Le programme repose sur la gestion de tâches en parallèle disponible avec freeRTOS. Il va lancer ces deux tâches dans le setup. Ce n’est pas l’objet de cet article de traiter de la gestion de tâches mais ce point pourra être abordé dans le fil sur le forum pour ceux que cela intéresserait.
void setup()
{
Serial.begin(115200);
...
Serial1.begin(250000, SERIAL_8N1, railComRX, railComTX); // Port série pour la réception des données (250k bauds)
Dans le setup, on va ouvrir une connexion Serial "classique" pour l’affichage dans la fenêtre moniteur de l’IDE à 115 200 bps.
On va également établir une seconde connexion sur le port Serial1 à 250 000 bps, 8 bits de données, aucun ( N ) bit de parité et un 1 bit d’arrêt sur les broches railComRX, railComTX déclarées au début du programme.
uint16_t x = 0;
for (uint8_t i = 0; i < NB_ADDRESS_TO_COMPARE; i++) // On place des zéros dans le buffer de comparaison
buffer.push(x);
xQueue = xQueueCreate(QUEUE_SIZE, sizeof(uint8_t)); // Création de la file pour les échanges de data entre les 2 tâches
xTaskCreatePinnedToCore(receiveData, "ReceiveData", 2048, NULL, 10, NULL, 0); // Création de la tâches pour la réception
xTaskCreatePinnedToCore(parseData, "ParseData", 2048, NULL, 10, NULL, 1); // Création de la tâches pour le traitement
while (true)
;
}
void loop(){}
On crée une "queue" pour les échanges de données entre les 2 tâches. Puis on lance les deux tâches "receiveData" et "parseData".
La fonction xTaskCreatePinnedToCore nous permet de lancer l’un des traitements sur le cœur 0 et le second traitement sur le cœur 1 ce qui optimise le potentiel de l’ESP32.
Pour minimiser les erreurs de transmission, la norme NMRA prévoit que les données envoyées par les décodeurs sont codées selon un principe dit 4/8 encoding. Cela veut dire que chaque octet transmis doit toujours avoir 4 bits à 0 et 4 bits à 1. Dans le cas contraire, il doit être ignoré.
Selon ce principe, seules 70 combinaisons de bits sont possibles. Le tableau ci-dessous, publié par le NMRA, donne la valeur qui doit être retenue pour chaque combinaison de bits.
NMRA Table 2 : 4/8 Encoding
Par exemple 0x0B (ou 11 en décimal) pour l’octet envoyé de valeur binaire 10010110.
Pour le programme, ces différents bits sont stockés dans un tableau decodeArray[]
Dans la fonction parseDatas();, on va chercher dans ce tableau la valeur de l’octet reçu.
C’est la fonction lambda placée dans la variable check_4_8_code qui permet de trouver dans le tableau la valeur de l’octet reçu. Si inByte est trouvée dans le tableau, la fonction retourne true et la variable inByte prend la valeur de decodeArray[inByte], la valeur décodée de l’octet !
auto check_4_8_code = [&]() -> bool
{
if(decodeArray[inByte] < 255) // Si la valeur de inByte est une valeur "valide"
{
inByte = decodeArray[inByte];
return true;
}
return false;
};
Le programme railcom_display
Ce programme permet d’afficher l’adresse de la locomotive sur un afficheur 4 X 7 segments. Il reprend l’essentiel du programme précédent.
Ca peut être intéressant pour afficher rapidement l’adresse de la locomotive en la posant simplement sur les rails.
Le programme railcom_detector_inClass
Ce dernier programme vous intéresse si vous souhaitez récupérer facilement et simplement l’adresse de la locomotive pour pouvoir l’utiliser par exemple dans un programme plus global ou l’envoyer sur un bus de communication, CAN, S88 ou Loconet, ou encore en TCP.
Cette classe Railcom va se comporter comme une bibliothèque qui retourne l’adresse DCC en invoquant simplement une méthode.
Il vous suffira dans votre programme principal, d’inclure le fichier d’entête « Railcom.h », de spécifier les broches de réception du signal série, ici la broche 33. Notez que la broche 17 est déclarée mais ne sera pas utilisée car il n’y a aucune communication série du microcontrôleur vers le détecteur.
Enfin, vous créez une instance de la classe Railcom qui peut avoir pour nom railcom et vous passerez en paramètres RAILCOM_RX et RAILCOM_TX.
Il est possible de créer jusqu’à trois instances ce qui veut dire que trois lecteurs Railcom différents peuvent-être reliés à un même ESP32.
Voici un exemple :
Railcom railcom_0(GPIO_NUM_3, GPIO_NUM_1); // Instance de la classe Railcom
Railcom railcom_1(GPIO_NUM_16, GPIO_NUM_17); // Instance de la classe Railcom
Railcom railcom_2(GPIO_NUM_13, GPIO_NUM_14); // Instance de la classe Railcom
Vous penserez alors à régler le débit de Serial à 250 000 bauds : Serial.begin (250000);
Dans votre programme principal vous pourrez à tout moment connaître l’adresse de la loco en appelant la méthode : Railcom::address();
Par exemple, uint16_t addressLoco = railcom.address(); où la variable de type uint16_t (ou unsigned int) va recevoir l’adresse de la loco.
Il s’agit d’une variable sur 2 octets (16 bits) capable de recevoir une adresse longue.
Lorsqu’il n’y a pas de locomotive détectée, l’adresse retournée est 0 (zéro).
Pour plusieurs instances, l’affichage nécessitera de modifier le code comme ceci :
Serial.printf("Adresse loco 0 = %d\n", railcom_0.address());
Serial.printf("Adresse loco 1 = %d\n", railcom_1.address());
Serial.printf("Adresse loco 2 = %d\n", railcom_2.address());
Voici un exemple qui montre que dans le fichier principal (.ino) le code est très simple d’utilisation :
Téléchargement du code complet pour Railcom_detector_inClass
Une centrale DCC qui répond au protocole de messagerie de DCC++ et génère le cutout.
A notre connaissance, il n’existe aucune centrale DCC en DIY capable de générer le cutout. Cela à souvent été évoqué pour DCC-Ex mais ne semble pas implanté à ce jour. Aussi, nous vous proposons une centrale sur une base d’ESP32 qui peut être reliée à un logiciel de pilotage par le port USB ou en WiFi comme la plupart des centrales. Elle utilise le protocole de messagerie de DCC++, cela veut dire qu’elle est totalement compatible avec des logiciels comme JMRI par exemple.
Vous n’avez pas besoin de matériel spécifique pour réaliser cette centrale hormis un ESP32, un LMD18200, un capteur pour la mesure du courant et des câbles de liaison.
La carte que nous vous présentons ici est une carte universelle conçue pour recevoir des projets ESP32 « génériques ». La communication CAN y est implantée en utilisant un MCP2562 mais cela est optionnel.
La configuration de l’application est assez simple regroupée dans le fichier Config.h
Ligne 16, pour utiliser la centrale avec le port série, on placera 0 comme valeur pour COMM_INTERFACE
// Define communication interface : 0 = Serial Port, 1 = Wifi
#define COMM_INTERFACE 0 // Select mode
Pour l’utilisation en WiFi, on choisira 1
// Define communication interface : 0 = Serial Port, 1 = Wifi
#define COMM_INTERFACE 1 // Select mode
Il faudra alors régler les paramètres de connexion WiFi selon les spécificités de votre installation domestique. Le SSID et le mot de passe d’accès au réseau WiFi et peut-être l’adresse IP qui peut éventuellement être du type 192.168.0.200 comme l’adresse de la « Gateway » qui peut-être 192.168.1.1 mais aussi 192.168.0.1 ou encore 192.168.1.254 !!!
Par contre, vous n’aurez pas besoin de modifier le port réglé sur 2560.
Cette centrale est aussi conçue pour recevoir des commandes par le bus CAN, si vous souhaitez activer ce bus, il vous faut « décommenter » la ligne 36 :
Pour la carte moteur, il est nécessaire que celle-ci dispose de la fonction BRAKE qui, quand elle est activée, met les deux rails en court-circuit, condition pour générer le Railcom. La carte LMD18200 que l’on ne présente plus sur Locoduino réalise cela parfaitement avec une entrée spécifique.
Du point de vue des câblages, la PWM sera reliée à la broche 12 de l’ESP32, la DIR à la broche 13 et le BRAKE à la broche 14.
Pour la mesure du courant et l’arrêt en cas de court-circuit, l’entrée se fera sur la broche 35.
Dans notre montage, nous utilisons un MAX471, il nous en restait en stock…
Comme vous pouvez le constater sur cette vidéo, cette centrale est simple à réaliser. Il suffit d’un LMD18200 câblé comme indiqué ci-dessus et d’un composant pour la mesure de courant comme le MAX471 qui est celui que j’utilise dans ce montage. La broche de signal du module étant reliée à la broche 35 de l’ESP32.
La carte LaBox qui est en cours de développement par quelques membres de Locoduino convient parfaitement et intègre sur le même PCB tous les composants, LMD18200, lecture de courant, ESP32, régulateur de tension...
Le programme DCC qui génére le cutout nécessaire pour Railcom® est téléchargeable sur le GitHub de Locoduino
Pour les autres modèles et autres marques, ESU comme LENZ proposent dans ce cas une carte électronique de très petit format que l’on place (en général) sous la locomotive, que l’on achète en général par 5 unités pour environ 60 à 80€ (soit 12 à 15€ l’unité).
Chez LENZ, le nom est LRC100 et la référence LE15105
Chez ESU, la référence est 54680
Ce ne sont pas des produits courants (souvent en rupture de stock) mais en cherchant un peu sur le net on arrive à en trouver.
La carte Lenz dispose d’un fil rouge et d’un fil noir, la carte ESU dispose en plus de deux fils marrons qui sont à dessouder.
Pour éviter les risques de court-circuit, il est conseillé de recouvrir la carte d’une gaine thermo rétractable.
La carte se programme en parallèle du décodeur de la locomotive à laquelle elle sera associée. Ainsi, quand vous envoyer une commande de modification/confirmation d’adresse au décodeur, la carte est automatiquement mise à jour.
Avec votre centrale ou avec un logiciel comme JMRI dans notre exemple, entrez l’adresse souhaitée pour la locomotive qui sera la même copiée dans la carte.
Nous avons ici choisi l’adresse longue 4251.
Avant de faire le montage dans la locomotive, vous pouvez tester « à vide » que tout fonctionne bien.
La carte est ensuite installée dans la locomotive ou sous le châssis, ou encore dans un wagon suiveur (tender).
Vous devez simplement relier les fils d’alimentation au courant des rails en soudant par exemple chacun des fils aux patins frotteurs de prise de courant.
Une fois tout terminé, une dernière vérification ne sera pas inutile.
Elle est sans doute incomplète et c’est la raison pour laquelle nous avons ouvert un fil sur le forum pour permettre les échanges, corrections, propositions et ajouts. N’hésitez surtout pas à intervenir. https://forum.locoduino.org/index.php?topic=1606
Bonjour, j’ai téléchargé le gerber et envoyé la fabrication à JLCPCB.
Ils me renvoient une demande de confirmation :
There is no keep out layer in your file, could we use the highlight outer frame of silkscreen layer as board outline ? (If there are cutouts in gerber file, please help to point out)