Bonjour, aujourd’hui je vous propose un projet un peu fou que j’ai conçu en extra durant mon stage. On va utiliser très finement un simple ruban de led pour donner un circuit de train lumineux. Sur notre réseau ferroviaire on pourra faire rouler plusieurs trains séparément, mettre des aiguillages et des fins de voies. Le tout contrôler depuis un smartphone. Je vous donne un aperçu du résultat dans la vidéo ci-dessous.
Introduction
Il existe dans le commerce des rubans de leds de plusieurs mètres de long possédant 300 voire 500 leds. Ces rubans sont conçus pour piloter facilement de manière informatique chaque led ainsi que sa couleur. On peut donc décider de mettre la led 1 en rouge, la led 2 en vert, éteindre la led 3, mettre la led 4 en violet, etc. La boutique Adafruit vend ces rubans sous le nom neopixel, mais on peut également les trouver sur ebay ou autre.
Ce que je souhaite développer est un train lumineux. Sur le ruban de leds un groupe de led s’allume et peut se déplacer donnant l’impression d’un train. J’arrive très rapidement à un montage permettant de contrôler un train sur une boucle. Ce que je désire est de pouvoir contrôler plusieurs trains indépendamment sur un circuit comprenant plusieurs boucles, aiguillages et fins de voies.
La difficulté
Pour montrer où se situe la difficulté nous allons voir un exemple de réseau simple. Il s’agit d’une boucle avec un aiguillage et une fin de voie. Visuellement on voit deux voies : la boucle et la voie de garage. Le premier problème vient du fait que je peux contrôler uniquement un ruban. Électriquement, il faut déjà couper la boucle pour avoir un début et un fin. Toujours électriquement, nous devons souder par des fils cachés la fin de la boucle avec le début de la voie de garage. La figure ci-dessus illustre le passage du circuit de principe au circuit électrique de contrôle.
Admettons que le train tourne dans le sens des indices croissants avec une longueur de 3 leds, il est sur les leds [0 1 2] à t, il sera sur [1 2 3] à t+1, c’est le cas simple.
Maintenant, il est sur les indices décroissants. Lorsque la tête du train arrive sur la led 19, il est [19 20 21] à t, il sera soit sur [18 19 20] à t+1 soit sur [22 19 20] à t+1. Tout de suite ça se complique, et la question est :
Existe t-il une représentation mathématique efficace qui permet un calcul immédiat des nouveaux indices du train pour un circuit donné ?
Après une prépa et une école d’ingénieur, on finit par voir des matrices partout, y comprit sur un ruban de leds…
Les maths pour la vie
D’un train à un vecteur
L’idée principale est de représenter un train comme une suite de leds allumées ou éteintes. De ce fait une notation vectorielle devient évidente : 0 led éteinte, 1 led allumée. Si on reprend le circuit d’exemple avec notre train sur l’aiguillage qui se dirige vers la voie de garage [22 19 20], cela nous donne :
La première analogie avec les notations vectoriels vues en école se retrouve dans l’état du train synthétisé par un vecteur état, comme le X en éléments finis ou le vecteur U en structure symbolisant l’état du système. Il suffit de synthétiser le réseau par une matrice R pour que le calcul de la position du train (i.e. des états des leds) se fasse par
L’autre analogie se trouve dans la construction de la matrice R. Le calcul direct est compliqué. Par contre le calcul d’éléments simples comme une ligne, un aiguillage ou une fin de voie est possible. Il suffit ensuite de reconstruire la matrice globale à l’aide des sous matrices locales. Le calcul de la matrice du circuit d’exemple est après.
D’un réseau à une matrice
L’idée principale du calcul réside dans la gestion led par led. Si un train est sur une led d’indice x alors au prochain coup elle sera sur la led d’indice y, ce qui se traduit par une fonction f(x) = y. Matriciellement, cela signifie que si un 1 est présent à l’indice x du vecteur, la matrice doit le déplacer sur l’indice y du vecteur. Nous devons simplement mettre la case à 1 de la colonne x à la ligne y, soit .
Il ne reste plus qu’à concevoir les fonctions pour les trois éléments de base : ligne, aiguillage, fin de voie.
-
Lignes : Si le train est sur les indices croissants, f(x) = x + 1. Pour les indices décroissant, on a f(x) = x - 1.
-
Aiguillages : Si le train arrive sur une séparation en a qui l’envoie soit en b, soit en c, alors
Si le train arrive de l’autre sens, nous avons f(x) = a, si x = b ou c.
On peut aussi utiliser les aiguillages pour boucler une ligne. Dans notre exemple, on boucle entre les indices 0 et 21.
-
Fins de voie : Notre représentation oblige à la dynamique d’un train, on ne peut pas le stopper. On va donc le boucler sur lui même pour simuler un fin de voie de manière dynamique. Par exemple, si notre train de 3 leds arrive à la fin de voie en 26, alors le début de train sera déplacer en queue, ici en 24. On peut en déduire la fonction générale f(x) = x + 1 - longueur du train.
Les fonction de chaque élément simple permettent de construire les matrices locales de chaque élément simple. La matrice globale représentant le réseau est la somme de toutes les sous matrices locales.
On remarque également que les matrices locales ont plusieurs états en fonction de la direction du train, du choix d’aiguillage ou de la longueur du train. Il faut donc reconstruire la matrice globale à chacun de ces changements.
A titre d’exemple, voici la matrice globale du circuit pour un train roulant dans le sens horaire avec l’aiguillage vers la voie de garage et une longueur de 3 leds.
Programmes
Les codes sources sont disponibles sur mon github
Le programme principal est écrit en python. Il fonctionne sur Raspberry pi où une bibliothèque Adafruit existe déjà pour contrôler le ruban. Il fonctionne comme une API, un serveur TCP/IP écoute les ordres, puis le ruban est mis à jour.
* L’ordre (message sous forme de String) est reçu par le serveur TCP/IP.
* En fonction de la demande, on appelle une méthode du TrainManager.
* Celui-ci met à jour les informations du train, et demande une nouvelle matrice à Network
* Network assemble une nouvelle matrice depuis les éléments de bases
Et voici le déroulement pour le déplacement :
1. Clock envoie un signal toute les 5ms à TrainManager
2. TrainManager calcule pour chaque train son nouveau vecteur à l’aide de la matrice réseau.
3. Les différents vecteurs sont concaténés en un seul avec les indices RGB.
4. Strip met à jour les leds sur le ruban.
L’application android n’est pas très intéressante, elle ajoute juste une interface graphique pour utiliser l’API.
Faire son propre circuit
Le programme, ainsi que la représentation matricielle vont pour n’importes quels circuits, il y a juste quelques restrictions
* les boucles pour changer de sens sont interdites
* lorsque votre train est sur une fin de voie, il ne doit pas dépasser ! Cela veut dire que si votre fin de voie la plus petite est de 9 leds, alors la taille maximale autorisée sera de 9 leds.
Bien maintenant voyons la construction :
1. découper votre ruban en petits segments. Les segments ont un sens, vérifier toujours que le output d’un segment arrive sur le intput d’un autre. (Mise à part pour le dernier)
2. Ensuite lier électrique les segments entre eux, il faut refaire un seul ruban électriquement. Pour les petites distances j’utilisais des pattes de résistance, pour les grandes distances j’utilisais du fil que je cachais derrière la plaque.
3. Repérer les indices des éléments : lignes, aiguillage, fin de voie sur un schéma. Pour rappel, une ligne ne doit pas comporter d’aiguillage au milieu. Dans ce cas il s’agit de deux lignes avec un aiguillages au bout.
4. Remplisser le fichier `config.sbl`. Lorsque vous déclarer une ligne, le sens _start_ vers _end_ doit être le sens horaire. Pour vous aidez, je vous mets le fichier de l’exemple : ```{
"line" : [
{"start" : 18, "end" : 0},
{"start" : 21, "end" : 19},
{"start" : 22, "end" : 26}
],
"junction" : [
{"serial" : 1, "a" : 19, "b" : 18, "c" : 22},
{"serial" : 2, "a" : 0, "b" : 21, "c" : 21}
],
"end_line" : [
{"position" : 26}
] }```
5. Enfin, il vous faudra modifier l’application android en fonction du nombre d’aiguillages sur votre circuit. Un simple copier-coller des blocs de code existants est suffisant.