Cette série d’articles est née d’une part d’une discussion sur le forum de Loco Revue mais également d’une préoccupation de beaucoup de modélistes. La demande initiale concernait la réalisation d’une gestion automatique de gare cachée à 4 voies. Le but de cette série est de se détacher du modèle de conception traditionnel de ce genre d’automatisme, modèle de conception qui prend sa source dans le matériel électromécanique : interrupteurs, relais, matrices de diodes, et de montrer comment la puissance d’un langage permet de mettre en œuvre des solutions plus élégantes, concises et compréhensibles que les solutions traditionnelles.
Gestion d’une gare cachée
Gestion d’une gare cachée (1)
Que veut-on faire ?
.
Par :
DIFFICULTÉ :★★★
La gestion d’une gare cachée est un classique en automatisme de réseaux ferroviaires miniatures. Le but d’une gare cachée est de constituer un réservoir de trains que l’on va automatiquement gérer de manière à varier les circulations et donner l’impression que le réseau n’est pas un réseau bouclé. La gare cachée en elle même est un simple faisceau de voies avec un grill d’entrée et un grill de sortie, tous deux constitués d’aiguillages. La figure ci-dessous montre une gare cachée à 4 voies.
Les grills d’entrée et de sortie sont composés de 3 aiguillages chacun. Lorsqu’un train arrive en vue du grill d’entrée, la combinaison des positions des aiguillages détermine sur laquelle des 4 voies le train est orienté. De même la combinaison des positions des aiguillages du grill de sortie détermine quel train est extrait de la gare. Le pilotage des 6 aiguillages demande 6 actionneurs dans le meilleur des cas [1].
Pour arrêter les trains en gare, il est nécessaire de commander l’alimentation des locomotives. En analogique, on se contentera de couper l’alimentation des voies au moyen de 4 relais. En numérique cela nécessitera l’envoi d’information à la centrale via un bus comme XpressNET. Faire démarrer un train consiste à rétablir l’alimentation sur la voie choisie. L’arrivée d’un nouveau train entraîne la libération d’un des trains stockés dans la gare. Si au moment où un nouveau train se présente toutes les voies sont occupées, il est arrêté à l’entrée de la gare en attendant que le train libéré par son arrivée ait quitté la gare. Il est aussi nécessaire de gérer quelques aspects de sécurité et on prévoira donc un arrêt d’urgence coupant l’alimentation dans toutes les voies.
La position des trains est connue grâce à des ILS. Un premier ILS, ILSEntree
, informe le système de l’arrivée d’un train. Il doit être placé de manière à laisser de temps aux aiguillages d’accomplir leur mouvement. Quatre ILS, un par voie de la gare, ILSVoie0
, ILSVoie1
, ILSVoie2
et ILSVoie3
, informent le système de l’arrivée du train sur la voie correspondante. Ils doivent être placés de telle sorte que la queue du train ait quitté le grill d’entrée lorsqu’ils sont déclenchés. Enfin, un dernier ILS, ILSSortie
, situé de telle sorte qu’il soit déclenché lorsque la queue d’un train quittant la gare ait évacué le grill de sortie, informe le système de la libération d’une voie de la gare.
La conception orientée automatismes
Cette conception consiste à énumérer toutes les combinaisons possibles de détection de la présence des trains et d’en déduire les fonctions logiques qui établissent les commandes des relais en fonction des détections. Comme les ILS ne donnent que des informations fugaces, pendant la fraction de seconde ou l’aimant en tête de train provoque le collage de l’ILS, il est également nécessaire d’ajouter des états internes permettant de mémoriser que tel ou tel ILS a, par le passé, été déclenché.
Cette conception est celle que l’on mettrait en œuvre pour de la logique câblée et le programme résultant ne sera qu’une suite de fonction logiques.
L’inconvénient de cette conception est ce que l’on appelle le « niveau d’abstraction ». Il est ici extrêmement faible. Le concepteur doit lui même traduire le cahier des charges que j’ai décrit ci-dessus en langage naturel en fonctions logiques et, comme tout être humain normalement constitué, il va faire des erreurs. Il sera difficile de tracer la source de ces erreurs car, à cause de la différence importante de niveau d’abstraction, la mise en relation de ces fonctions logiques avec le cahier des charges est difficile.
De plus, cette conception nous fait perdre toute notion liée à la gare. Le programme n’a aucune représentation des liaisons entre les aiguillages et les voies. Or, comme on va le voir, cette représentation est extrêmement utile pour gérer la gare de manière beaucoup plus simple.
Une conception plus abstraite
Or l’Arduino, et c’est un énorme avantage comparé à de la logique câblée, permet justement d’écrire notre gestion de gare cachée de manière plus abstraite et plus proche de notre cahier des charges. C’est ça l’informatique : empiler les abstractions de manière à atteindre une plus grande capacité de résolution des problèmes.
Qu’est ce qu’une gare et par extension un réseau de train du point de vue informatique ? C’est un graphe, c’est à dire des nœuds reliés entre eux par des arcs. De ce point de vue, notre gare peut se représenter comme ceci :
Chaque nœud est un élément de voie. On a donc la voie d’entrée en gare, les 3 aiguillages d’entrée, les 4 voies de la gare, les 3 aiguillages de sorties et la voie de sortie de la gare. Chaque arc, une ligne entre deux nœuds est une connexion entre les deux éléments de voie. Notez que ce graphe est dit « orienté », cette orientation est symbolisée par les flèches. Un nœud ne connait que les nœuds vers lesquels il pointe. Ainsi AS0
connaît AS1
et voie3
mais pas sortie
.
En représentant ce graphe par des données dans le programme, on pourra écrire des algorithmes permettant d’établir un chemin entre deux nœuds du graphe et donc d’établir la position des aiguilles. Ceci de manière bien plus simple qu’en calculant à la main toutes les combinaisons possibles.
C’est aussi l’occasion de mettre en œuvre la programmation orientée objet car le problème s’y prête bien.
Chaque nœud du graphe est un élément de voie et partage donc des caractéristiques communes avec d’autres noeuds.
Mais dans notre graphe nous avons trois types d’éléments de voie particuliers : les voies d’entrée et de sortie, les voies de gare et les aiguillages.
La programmation orientée objet va nous permettre de manipuler chaque élément de voie en tenant compte de ses spécificités. Par exemple, quand il s’agit de connecter les éléments de voie entre eux, il est nécessaire de s’intéresser à leurs spécificités.
Par contre quand on souhaite les parcourir, on désire juste savoir qu’il s’agit d’éléments de voie. La programmation objet va nous permettre de les manipuler grâce à des methodes communes.
Nous allons également programmer « récursivement » pour chercher un chemin entre deux élément en suivant les arcs intermédiaires.
On pourra ainsi « demander » à l’élément de voie de départ de trouver le chemin, c’est la façon récursive de faire. Si il se trouve être la destination, il répond que l’on est arrivé, sinon il demande à l’élément de voie suivant qui à son tour fait la même chose, etc. Un aiguillage demandera aux deux éléments de voie suivants. Le mauvais coté sera éliminé tout de suite. C’est un peu la version informatique de « passe à ton voisin ». La compréhension demande une petite gymnastique intellectuelle mais quand on écrit le programme, c’est beaucoup plus simple qu’une version itérative du type "while(...)".
La suite de cet article traitera des structures de données, permettant de représenter notre gare.
En attendant, je vous engage à lire ou relire les articles de Thierry :
[1] Dans le pire des cas, celui où des moteurs à solénoïde à deux bobines sont employés, 2 actionneurs par aiguillage seront nécessaires