Des documents de références techniques, comme quelques principes de base de la locomotive à vapeur ou la numérotation des engins moteur ou des wagons, l'histoire de l'échelle N, les époques en modélisme et pleins d'autres documentions indispensables aux modélistes ferroviaires et à toutes autres personnes qui s'intéressent au domaine ferroviaire ...
Le système Arduino est un outil pour fabriquer de petits ordinateurs qui peuvent capter et contrôler une multitude de dispositifs. C'est une plateforme open-source (Les schémas électroniques des cartes Arduino et les codes sources pour la partie développement des programmes, sont distribués librement et téléchargeables gratuitement) qui est basée sur une simple carte à microcontrôleur, et un logiciel, véritable environnement de développement intégré, pour écrire, compiler et transférer le programme vers la carte à microcontrôleur.
Arduino peut être utilisé pour développer des modules pouvant recevoir des entrées d'une grande variété d'interrupteurs ou de capteurs, et pouvant contrôler la lumière ou le son, mesurer une distance ou une température et piloter des moteurs, des LEDs, des relais ou toutes autres sorties matérielles. Les projets Arduino peuvent être autonomes, ou bien ils peuvent communiquer avec des logiciels tournant sur votre ordinateur. Les cartes électroniques peuvent être fabriquées par l'utilisateur ou bien être achetées pré-assemblées. Le logiciel de programmation est facile à utiliser et peut-être utilisé sans avoir une connaissance approfondie en programmation. Arduino convient parfaitement pour notre hobby, le modélisme ferroviaire.
La famille de ce circuit électronique programmable s'est agrandie au fur et à mesure des années. Il en existe de différentes tailles et chacune dispose de fonctionnalités différentes, voici celles que j'utilise:
Pour visualiser la vitesse des différentes rames et locomotives (une vapeur qui va plus vite qu'une diesel est tout de même assez rare dans la réalité), un petit montage avec un module Arduino s'imposait.
Le montage est alimenté en 5V.
Pour ce faire j'ai utilisé un module Uno, un écran LCD 2x16, deux KY-033 et un potentiomètre pour régler la luminosité de l'écran.
Le module de capteur de suivi de ligne KY-033 détecte si une surface est réfléchissante ou absorbante de lumière devant le capteur. Lors du passage d'un train, le convoi réfléchit la lumière. Cette capacité rend ce module idéal pour une utilisation comme barrière infrarouge. La sensibilité du capteur peut être ajustée à l'aide du potentiomètre, du module capteur, afin de garantir des performances optimales en fonction de l'emplacement sur le réseau.
La programmation du module est modulable en fonction de l'échelle utilisée (N ou HO) et de la distance entre les deux barrières infrarouges.
A chaque passage d'un convoi devant la barrière "DEBUT" puis la "FIN", l'Arduino enregistre le temps écoulé entre les 2 capteurs et affiche la mesure de vitesse pendant 5 secondes sur le LCD.
La vitesse est donnée par un simple calcul; par exemple, un train met 770ms pour parcourir les 10cm entre les deux barrières infrarouges:
Choix du Coëf
`Coëf=E`
Formule de calcul
`V=\frac{\d times s times Coëf}{Delta t}=\frac{\100 times 3600 times 160}{770}`
`V=\frac{\d times s times Coëf}{Delta t}`
`V=\frac{\100 times 3600 times 160}{770}`
`V=74805` `m`/`h`
Légende
L'afficheur via l'Arduino affiche directement la vitesse en km/h à l'échelle N, soit 74,81km/h:
Capteur infrarouge
Ecran LCD 16x02
Par exemple e (e en exposant):
Instructions :
/*
**************************************************************************************
** **
** Mesure et calcule de la vitesse des trains dans leur sens de marche sur 1 voie. **
** **
** Mentionner la distance entre les 2 capteur infrarouge (variable "Distance"), **
** puis sélectionner l'échelle "N" ou "HO" (variable "Echelle") et si besoin **
** changer le temps maximum avant la detection de Fin (variable "Delais"). **
** **
** - créé le 19 décembre 2024 - **
** - modifié le 21 juin 2025 - **
** **
**************************************************************************************
*/
// Import de la librairie pour l'afficheur LCD
#include ‹LiquidCrystal.h›
// Initialise la librairie avec les pins à connecter
LiquidCrystal lcd(12, 11, 10, 9, 8, 7);
// Initialisation des variables
int Voie; // Voie de mesure
int VoieDebut = 2; // Barrière optique Début
int VoieFin = 0; // Barrière optique Fin
int lectdeb; // Valeur lue sur les barrières optiques
int lectfin; // Valeur lue sur les barrières optiques
int Tdebut; // Temps sur la barrière début
int debut; // Détection début
int Tfin; // Temps sur la barrière fin
int fin; // Détection fin
int Temps; // Temps de passage ( = Tfin - Tdebut )
float Vitesse; // Vitesse calculée
double Coef; // Coefficient d'échelle
unsigned long timer; // Base du compteur
byte Compteur = 0; // Compteur après détection capteur début
// - Variable à personnaliser - //
const int Echelle = "N"; // Défini l'échelle employée (N ou HO)
long Distance = 100; // Distance entre les barrières infrarouge en mm
byte Delais = 30; // Délais avant raz détection
// Initialisation du caractères personnalisés (e en exposant)
byte expo[8] = {
B01110,
B10001,
B11110,
B10000,
B01110,
B00000,
B00000,
B00000,
};
// Initialisation du caractères personnalisés (é)
byte eaigu[8] = {
B00010,
B00100,
B01110,
B10001,
B11110,
B10000,
B01110,
B00000,
};
// Initialisation Arduino
void setup() {
// Défini les colonnes et lignes, affiche la première ligne et la fin de la seconde
lcd.createChar(0, expo); // Mémorise le caractère spécial
lcd.begin(16, 2); // Déclaraton du type d'afficheur 16 cracteres sur 2 lignes
lcd.clear();
lcd.setCursor (0, 0); // Positionne le curseur ligne 1 colonne 2
lcd.print("Vitesse"); // Ecrit "Vitesse"
lcd.setCursor(8, 0); // Positionne le curseur ligne 1 colonne 10
if ( Echelle == "N" ) { // Echelle "N"
Coef = 576,00;
lcd.print ("au 160"); // Ecrit "au 160" à la suite de "vitesse"
lcd.setCursor(14, 0); //Positionne le curseur ligne 1 colonne 16
lcd.write(byte(0)); // Ecrit le caractère spécial
}
if ( Echelle == "HO" ) { // Echelle "HO"
Coef = 313,20;
lcd.print ("au 87"); // Ecrit "au 87" à la suite de "vitesse"
lcd.setCursor(14, 0); //Positionne le curseur ligne 1 colonne 15
lcd.write(byte(0)); // Ecrit le caractère spécial
}
lcd.setCursor(0, 1); // Positionne le curseur ligne 2 colonne 1
lcd.print(" < En attente > "); // Efface la deuxième ligne
}
// Programmation Arduino
void loop() {
debut = 0;
fin = 0;
Compteur = 0;
// Détection sur capteur de Début
while (debut == 0 ) {
// Détection d'un train en sens inverse
lectfin = analogRead (VoieFin); // Lis la tension de la broche fin
if ( lectfin < 200 ) { // Si déctection retour au début de la boucle
lcd.setCursor(0, 1); // Positionne le curseur ligne 2 colonne 1
lcd.print("Train contresens"); // Efface la deuxième ligne
while (true) {
if (millis() - timer > 995) {// si 995 ms se sont écoulées - ajouter une seconde à la variable Compteur
timer = millis();
Compteur++;
}
if (Compteur >= Delais) { // attente xx secondes selon délais paramètré
goto Abandon;
}
lectdeb = analogRead (VoieDebut); // Lis la tension de la broche début
if ( lectdeb < 200 ) {
delay (500);
goto Abandon;
}
}
}
// Détection début d'un train
lectdeb = analogRead (VoieDebut); // Lis la tension de la broche début
if ( lectdeb < 200 ) { // Si la tension est inférieur à 1 Volt
Tdebut = millis ();
debut = 1;
lcd.createChar(1, eaigu); // Mémorise le caractère spécial
lcd.setCursor(0, 1); // Positionne le curseur ligne 2 colonne 1
lcd.print("D"); // Efface la deuxième ligne
lcd.setCursor(1, 1); // Positionne le curseur ligne 2 colonne 2
lcd.write(byte(1)); // Ecrit le caractère spécial
lcd.setCursor(2, 1); // Positionne le curseur ligne 2 colonne 3
lcd.print("tection train");
Compteur = 0;
}
}
// Détection sur capteur de Fin
while (fin == 0 ) {
if (millis() - timer > 995) {// si 995 ms se sont écoulées - ajouter une seconde à la variable Compteur
timer = millis();
Compteur++;
}
if (Compteur >= Delais) { // attente xx secondes selon délais paramètré
goto Abandon;
}
lectfin = analogRead (VoieFin); // Lis la tension de la broche fin
if ( lectfin < 200 ) { // Si la tension est inférieur à 1 Volt
Tfin = millis ();
fin = 1;
}
}
Temps = Tfin - Tdebut; // Calcule le temps entre Fin et Début
Vitesse = Coef * Distance / Temps;
lcd.setCursor(0, 1); // Positionne le curseur ligne 2 colonne 1
lcd.print(" "); // Efface la 2ème ligne (16 espaces)
lcd.setCursor(1, 1); // Repositionne le curseur ligne 2 colonne 2
lcd.print(Vitesse); // Ecrit la vitesse calculée
lcd.setCursor(8, 1); // Repositionne le curseur ligne 2 colonne 9
lcd.print("Km/h"); // Ecrit
delay (5000); // Affichage pendant 5 secondes
Abandon:
lcd.setCursor(0, 1); // Positionne le curseur ligne 2 colonne 1
lcd.print(" < En attente > "); // Efface la deuxième ligne
}
Pour simuler la lumière émise par un poste de soudure à l'arc, il suffit de commander une LED bleu haute luminosité en la faisant s'allumer selon des flashes très courts, très rapprochés et se succédant de façon aléatoire.
Le montage, très simple, fait appel à un module Arduino Nano et une LED, son comportement est réglable en fonction du besoin. La figure ci-dessous montre un train d'impulsions émis par le programme, pour allumer la LED. Ce train d'impulsion est appelé cycle de soudure. Le cycle est constitué d'un certain nombre d'événements, chaque événement étant constitué d'un flash d'une certaine durée, suivi d'une période intermédiaire d'une certaine durée également, au cours de laquelle aucune lumière n'est émise. Entre deux cycles existe une période de repos, pendant laquelle le soudeur contrôle son travail ou bien positionne sa pièce autrement...
Le montage est alimenté en 5V.
Instructions :
// Ce programme commande une LED bleue haute luminosité pour simuler un poste de soudure à l'arc.
// Il fait appel à la fonction random qui génère des nombres aléatoires.
// Duree_flash est la durée d'un flash.
// Duree_int est la durée entre deux flashes.
// Duree_flash et Duree_int forment un événement.
// Nbre_even est le nombre d'événements au cours d'un cycle de soudure
// P_repos est la durée entre deux cycles de soudure.
// Toutes ces données sont aléatoires mais bornées entre une valeur minimum et une valeur maximum.
// En jouant sur l'intervalle, on peut simuler au mieux l'effet de soudure à l'arc.
// Broche est la broche sur laquelle la LED est connectée.
// Initialisation des variables
const byte Broche = 13 ;
const long Duree_flash_mini = 10 ;
const long Duree_flash_maxi = 101 ;
const long Duree_int_mini = 10 ;
const long Duree_int_maxi = 31 ;
const long Nbre_even_mini = 10 ;
const long Nbre_even_maxi = 21 ;
const long P_repos_mini = 1500 ;
const long P_repos_maxi = 7001 ;
// Fonction d'initialisation, nécessaire pour mise au point
void setup ()
{
randomSeed (analogRead (0)) ;
pinMode (Broche, OUTPUT) ;
}
// Corps du programme
void loop ()
{
long Nbre_even = random (Nbre_even_mini, Nbre_even_maxi) ;
for (long i = 1 ; i <= Nbre_even ; i++)
{
long Duree_flash = random (Duree_flash_mini, Duree_flash_maxi) ;
long Duree_int = random (Duree_int_mini, Duree_int_maxi) ;
digitalWrite (Broche, HIGH) ;
delay (Duree_flash) ;
digitalWrite (Broche, LOW) ;
delay (Duree_int) ;
}
long P_repos = random (P_repos_mini, P_repos_maxi) ;
delay (P_repos) ;
}
Source: locoduino.org
L'effet voulu est celui d'une flamme vacillante, avec par moment de petits courants d'air qui la font presque s'éteindre. Cet effet réside essentiellement dans la légère variation de couleur obtenue avec le random() sur la LED rouge (donc un mélange jaune/orange/rouge). L'utilisation de la fonction random() dans la fonction delay() permet d'avoir un clignotement (et donc variation de couleur) totalement aléatoire.
Une simple LED RVB anode commune et 3 résistances de 220Ω sous 5v sont nécessaire pour ce montage ...
Le montage est alimenté en 5V.
Instructions :
// ******************************
// * Simulateur de bougies *
// ******************************
// Utilisation d'une led RVB à anode commune
// Déclarations des sorties PWM
int led_bleue = 11;
int led_rouge = 9;
int led_verte = 10;
int vert;
int rouge;
void setup() {
// En mode sortie
pinMode(led_bleue, OUTPUT);
pinMode(led_verte, OUTPUT);
pinMode(led_rouge, OUTPUT);
}
void loop() {
vert = random(160,255);
rouge = random(20,160);
analogWrite(led_bleue, 255);
analogWrite(led_verte, vert);
analogWrite(led_rouge, rouge);
delay(random(30,100));
}
Les feux tricolores sont comme leur nom l'indique une animation lumineuse qui trouvera sa place sur tout réseau suffisamment récent dans le temps.
Le schéma correspond à une situation à deux feux tricolores, par exemple d'un croisement d'une route à sens unique.
Pour un croisement de deux routes, avec les 2 feux de la même route synchronisée, il suffit de rajouter une DEL de la même couleur en série sur chaque DEL de chaque feu. Dans cette hypothèse, il sera nécessaire de diminuer la valeur des résistances pour conserver une brillance adaptée. Le programme reste le même.
Le montage est alimenté en 5V.
Instructions :
/*
* Programme pour arduino nano
* idée originale C. Bézanger Octobre 2013
* https://www.locoduino.org/spip.php?article3
* Licence GNU GPLv3
*
* Ce programme fait fonctionner des feux tricolores.
* Six LED (vertes, oranges et rouge) sont reliées aux sorties 4 à 9
* Les sorties 4 à 6 forment le feu F1
* Les sorties 7 à 9 forment le feu F2
*/
// Initialisation des variables
const byte FeuVert1 = 4 ;
const byte FeuOrange1 = 5 ;
const byte FeuRouge1 = 6 ;
const byte FeuVert2 = 7 ;
const byte FeuOrange2 = 8 ;
const byte FeuRouge2 = 9 ;
//Délai des différents temps mis en const pour changer facilement
// si le délai imparti ne vous satisfait pas. Il s'agit de millisecondes
const long TempsAttenteFeuRouge = 2000;
const long TempsAttenteFeuVert = 30000;
const long TempsAttenteFeuOrange= 5000;
// Initialisation des lignes 4 à 9 en sortie
void setup () {
pinMode (FeuVert1, OUTPUT) ;
pinMode (FeuOrange1, OUTPUT) ;
pinMode (FeuRouge1, OUTPUT) ;
pinMode (FeuVert2, OUTPUT) ;
pinMode (FeuOrange2, OUTPUT) ;
pinMode (FeuRouge2, OUTPUT) ;
}
// Fonction loop
void loop () {
// Extinction de toutes les LED au départ
digitalWrite (FeuVert1, LOW) ;
digitalWrite (FeuOrange1, LOW) ;
digitalWrite (FeuRouge1, LOW) ;
digitalWrite (FeuVert2, LOW) ;
digitalWrite (FeuOrange2, LOW) ;
digitalWrite (FeuRouge2, LOW) ;
// Allumage du feuVert1 et FeuRouge2
digitalWrite (FeuVert1, HIGH) ; // Allumage du feu vert F1
digitalWrite (FeuRouge2, HIGH) ; // Allumage du feu rouge F2
// Début de cycle
// Concerne le feu F1
delay (TempsAttenteFeuVert) ; // Feu vert F1 pendant 30 secondes
digitalWrite (FeuVert1, LOW) ; // Extinction du feu vert F1
digitalWrite (FeuOrange1, HIGH) ; // Allumage du feu orange F1
delay (TempsAttenteFeuOrange) ; // Temporisation du feu orange F1
digitalWrite (FeuOrange1, LOW) ; // Extinction du feu orange F1
digitalWrite (FeuRouge1, HIGH) ; // Allumage du feu Rouge F1
delay (TempsAttenteFeuRouge) ; // Temporisation du feu Rouge F1
// Concerne l'autre feu F2
digitalWrite (FeuRouge2, LOW) ; // Extinction du feu Rouge F2
digitalWrite (FeuVert2, HIGH) ; // Allumage du feu vert F2
delay (TempsAttenteFeuVert) ; // Feu vert F2 pendant 30 secondes
digitalWrite (FeuVert2, LOW) ; // Extinction du feu vert F2
digitalWrite (FeuOrange2, HIGH) ; // Allumage du feu orange F2
delay (TempsAttenteFeuOrange) ; // Temporisation feu orange F2
digitalWrite (FeuOrange2, LOW) ; // Extinction du feu orange F2
digitalWrite (FeuRouge2, HIGH) ; // Allumage du feu Rouge F2
delay (TempsAttenteFeuRouge) ; // Temporisation du feu Rouge F2
digitalWrite (FeuVert1, HIGH) ; // On est revenu au point de départ
// Feu vert sur F1 et feu rouge sur F2 : le cycle peut recommencer
}
Source: locoduino.org
Ce montage est une commande d'éclairage pour bâtiments, jusqu'à 52 LEDs, via un générateur aléatoire basé sur un Arduino Mega. Chaque broche de l'Arduino Mega peut fournir jusqu'à 40mA maximum ce qui est largement supérieur à la consomation moyenne d'une LED qui est de 20mA.
Un état Haut sur l'entrée analogique A8 déclenche l'allume de toutes les LEDs; au retour de l'état BAS, le cycle d'allumage aléatoire reprend.
Les bâtiments équipés de LEDs s'allument ou s'éteignent de manière purement aléatoire.
J'utilise des LEDs 12v sur pas de vis pour remplacer les ampoules Faller© 180670.
Les sorties de l'arduino délivrant du 5V, ce n'est pas suffisant pour alimenter mes LEDs 12V du décors. J'utilise donc plusieurs modules d'optocoupleurs pour piloter ces LEDs.
Le montage utilise 2 sorties DCC sur un DR4018 de Digikeijs©. Une pour lancer le démarrage de l'animation (mise sous tension de l'Arduino), l'autre pour allumer toutes les LEDs.
Saisisser le nombre de LEDs dans le champ "Nombre de LEDs" et obtener sa conversion instantanée en code binaire pour le transcrire au DIP en basculant les petits leviers.
Convertisseur multi-bases.
Exemple : Dans le montage cité ci-dessus, 20 LEDs sont utilisées: le code binaire correspondant est 10100. Sur le DIP, en partant de la gauche, laisser les leviers 1, 2, 4 et 6 sur Off, basculer le 3 et le 5 sur On.
Les leviers 7 et 8 ne sont pas utilisés.
Instructions :
La position des DIP n'est pas mémorisé par Wokwi©, sans action sur ces DIP la simulation de fonctionne pas.
/*
******************************************************************************
* Commande d'éclairage jusqu'à 52 LED via un générateur aléatoire basé *
* sur un Arduino Mega. *
* Le nombre de LED connectées est règlé via des interrupteurs DIP. *
* Le programme démarre automatiquement lorsque l'ADRUINO est alimenté. *
* Un état Haut sur l'entrée digitale A8 allume toutes les LED, *
* au retour à l'état BAS, le cycle d'allumage aléatoire reprend. *
* *
* - Crée le 10 juin 2025 - *
* - Modifié le 06 juillet 2025 - *
* *
******************************************************************************
*/
// Configuration des variables
int i,NumeroLed,BoutonPoussoir,Etat,NbreLed,NbreSortie;
int BinaireA,BinaireB,BinaireC,BinaireD,BinaireE,BinaireF;
int AllumeTout = 8; // Port d'entrée pour allumer toutes les LED
int DIP1 = 0; // Port d'entrée binaire 000001
int DIP2 = 1; // Port d'entrée binaire 000010
int DIP3 = 2; // Port d'entrée binaire 000100
int DIP4 = 3; // Port d'entrée binaire 001000
int DIP5 = 4; // Port d'entrée binaire 010000
int DIP6 = 5; // Port d'entrée binaire 100000
unsigned long TempsPause = 5000; // Pause de pause entre chaque cycle
unsigned long TempsRef = 0;
// Initialisation de l'Arduino
void setup() {
// Converti l'entrée A0 du binaire 000001 en décimale 1
BinaireA = analogRead (DIP1); if (BinaireA == 0) {BinaireA = 1;}else{BinaireA = 0;}
// Converti l'entrée A1 du binaire 000010 en décimale 2
BinaireB = analogRead (DIP2); if (BinaireB == 0) {BinaireB = 2;}else{BinaireB = 0;}
// Converti l'entrée A2 du binaire 000100 en décimale 4
BinaireC = analogRead (DIP3); if (BinaireC == 0) {BinaireC = 4;}else{BinaireC = 0;}
// Converti l'entrée A3 du binaire 001000 en décimale 8
BinaireD = analogRead (DIP4); if (BinaireD == 0) {BinaireD = 8;}else{BinaireD = 0;}
// Converti l'entrée A4 du binaire 010000 en décimale 16
BinaireE = analogRead (DIP5); if (BinaireE == 0) {BinaireE = 16;}else{BinaireE = 0;}
// Converti l'entrée A5 du binaire 100000 en décimale 32
BinaireF = analogRead (DIP6); if (BinaireF == 0) {BinaireF = 32;}else{BinaireF = 0;}
// Additionne le résultat décimale
NbreLed = BinaireA + BinaireB + BinaireC + BinaireD + BinaireE + BinaireF + 1;
// Limite le résultat à 52 (Nombre de sortie maximum)
if (NbreLed >= 52) {
NbreLed = 52;
}
// Déclare en masse les ports 2 à NbreLed
for (int i = 2; i <= NbreLed; i++) {
pinMode(i, OUTPUT);
}
}
// Boucle de programmation
void loop() {
NbreSortie = NbreLed + 1;
DebutProg:
// Allumage de certaines LED à l'initialisation
for (int i = 2; i <= NbreSortie; i++) {
Etat = random(2);
if (Etat == 0) {
Etat = LOW;
} else {
Etat = HIGH;
}
digitalWrite (i, Etat);
}
// Allumage ou extenction aléatoire
while (true) { // Boucle infini
NumeroLed = random(2,NbreSortie); // Etats aléatoires entre 2 et NbreLed
Etat = random(2); // Etats aléatoires entre 0 et 1
if (Etat == 0) {
digitalWrite (NumeroLed, LOW); // Eteint la LED (NumeroLed)
} else {
digitalWrite (NumeroLed, HIGH);// Allume la LED (NumeroLed)
}
//on arme la tempo en millis pour pouvoir surveiller l'entrée A8
TempsRef = millis();
Pause:
// xxx (TempsPause) ms de pause après l'extinction ou l'activation de la ième sortie
if ((millis() - TempsRef ) <= TempsPause) { // Compare temps référence/durée pause
BoutonPoussoir = analogRead (AllumeTout);
if (BoutonPoussoir > 200) { // Sortie de la boucle si broche A8 état HAUT
goto AllumeToutesLED;
}
goto Pause; //
}
}
// Allumage de toutes les LED (si A8 = HAUT)
AllumeToutesLED:
// Allume toutes les LED
for (int i = 2; i <= NbreLed; i++) {
digitalWrite (i, HIGH);
}
while (true) {
// Boucle infini (Attente état BAS sur broche A8)
BoutonPoussoir = analogRead (AllumeTout);
if ( BoutonPoussoir < 200 ) { // Sortie de la boucle si broche A8 état BAS
goto DebutProg; // Retour au début du programme
}
}
}