Piloter un réseau de train avec une Arduino 2560

Bonsoir,

Voila un bout de temps que j'ai pas eu l'occasion de m'amuser dans le petit monde de l'embarqué libre. Ce soir, je remet le nez dedans.

Passez cette petite introduction de retour, je viens avec une belle interrogation et j'aimerais gravité autour d'un même sujet. Le pilotage d'un réseau de train. J'ai réaliser un séquensage complet et je me charge de travailler avec des sous-routines. Les sorties de la cartes piloterons des petits transistors (2N2222) qui piloterons des relais avec diode de roue libre.

Voyons maintenant la capture d'événements non bloquant. Je possède plusieurs capteur, on va dire entre 6 et 10 en analogique de type LDR (résistance qui varient en fonction de la lumière). Les interruptions sont disponible sur certaines pins. Hélas, je pense utiliser les CAN intégré aux voies A0 à A10.

A ce moment là; en farfouillant sur le net, j'ai vue qu'il était possible de faire ceci:

  • Toutes les 20 à 30µs, passer en interruption
    -- Lire l'état de chaque entrées analogiques
    -- Mettre des flags (pour éviter les rebonds due aux wagons)
    -- Placer dans un tableau chaque état
    -- Revenir au programme principal
  • En fonction des états de chaque capteur, de l'image du terrain, il convient de piloter tel et tel sorties.

Mon principal souci est de savoir si, comme je dois faire des pauses programme sans blocage, on peut faire ces interruptions toute les x µs. Dans le cas ou c'est possible, quelles types de code est à mettre en oeuvre ?

Ensuite, j'ai un second souci. Forcément !! Comme j'ai expliqué, c'est un automatisme. C'est à dire que les trains se pilotent seul. Il se trouve qu'à un moment donné, je gère une séquence qui n'en est plus une. L'ensemble de la séquence peut-être longue.

Pour faire bref, c'est du style.

  • Le train 1 part, 3 minutes plus tard il croise la cellule 1 (capteur optique).
  • Le train 2 part, la section précédente est éteinte.
  • Le train 1 arrive en gare 1, il passe sur la cellule 2 ce qui déclenche le départ du train 3.
  • Le train 3 part, 4 minutes plus tard, il passe sur la cellule 1.
    ...

Comme on voie, la même celule est croisé deux fois dans la séquence et, bien sûr ne doit pas faire la même action. Une des idées aurait été de placé plus astucieusement les cellule. C'est en cours d'étude. Mais je suis convaincue qu'il faille impérativement avoir l'image des train et leurs position en mémoire dans le logiciel. Voila les avis la dessus sont ouvert.

N'hésitez pas à me demande des informations ou à me demander de complété. Je vais essayer d'aller jusqu'au bout. Le tout est que ça soit possible à mettre en ouvre avec des sous-routines (fonctions / classes).

Merci de votre attention et des réponses qui me seront données.

Hello !
Joli projet...

Je me demande si la complexité ne provient pas du fait que tu essayes de faire plusieurs choses en même temps :
1 ) La sécurité du réseau ( Protection pas cantons,... )
2) Le séquencage des trains

Il me semble que tu pourrais te simplifier la vie en y allant par étape.

Par exemple ,si tu implémentes d'abord la sécurité du réseau, tu pourras ensuite batir sur celle-ci pour implémenter le séquençage. Séquençage qui ne se fera qu'en respectant la sécurité sous-jascente.

Essaye de décomposer chaque tâche complexe en sous-tâche plus simple... (Protection d'un canton, puis de deux, puis d'un aiguillage, ... ) C'est aussi plus motivant car tu vois le travail progresser.

Voilà... Ce n'est malheuresuement pas une "solution" mais plutôt une approche.

Bon courage pour la suite !

Michel

Et oui, c'est à peut prêt ça.

Alors voila ou j'en suis. Chaque capteur (LDR) seront raccordé à des LM311N monté en comparateurs. Le but est d'avoir un fron bien nette pour attaquer les entrées digitales.

A partir de là, j'ai établi un ensemble de choses. Ce que nous devons scruter. Ce que nous devons faire comme séquences.

La partie séquencielle:

Au lancement, on doit avoir de Za1 à Za6, 101111, on lance donc la séquence 1.
On attends jusqu'à ce que Za2 soit pleine, 011111. Dans ce cas ça nous amène à la séquence 2.
On attends que Za1 soit pleine, 111110. Dans ce cas ça nous ammène à la séquence 3.
On attends que Za6 soit pleine, 111101. Dans ce cas ça nous ammène à la séquence 4. (Je m'affranchi de 4-a et 4-b).
On attends que Za5 soit pleine, 110111. Dans ce cas ça nous ammène à la séquence 5.
On attends que Za3 soit pleine, 101111. Dans ce ças on se retrouve à la séquence 1.

//Programme principale:
//Si on a 101111
   //-> faire truc séquence 1
//Si on a 011111
   //-> faire truc séquence 2
//Si on a 111110
   //-> faire truc séquence 3
//Si on a 111101
  //-> faire truc séquence 4
//Si on a 110111
   -> faire truc séquence 5

//Interruption
   //Prendre l'état des broches
   //Stoquer dans le tableau
   //Si sécurité
      //Couper le réseau
   //Revenir

Et voila ou j'en suis :slight_smile:

Bon,

J'ai pas totalement abandonné l'idée des interruptions. Je vais le gardé pour une autre fonction très importante de sécurité.

Pour le moment, je teste un bout de programme qui fait la sélection entre 4 capteurs / 10. Histoire de valider le concept.
J'ai écrit cela en pseudo-code. Je but sur la fonction d'attente.

//Si Za1 pleine et Za2 vide.
//Lancer Za1 vers Za2.
//Attendre que Za2 soit pleine.

Il faut comprendre qu'au départ du train de Za1, il peut devenir vide et il peut existé autant de rebonds que de wagon. C'est pourquoi j'attends impérativement Za2 qui est une valeur sûr. Les if fontionnent. Parfit c'est déjà ça. Mais faire un while sur Za2 ça ne va pas du tout. On ne sort jamais de la boucle qui est infini. C'est sur ce dernier point que j'aimerais un peu d'aide.

Merci.

Et bien voila… Nouvel élément de réponse ! Ca fonctionne !

Mais il y a un mais je vais en parlé plus loin :grin:

Au niveau include et variables globales

#include <LiquidCrystal.h>

LiquidCrystal lcd(7, 6, 5, 4, 3, 2);

const int CE1 = 8;	//Cellule 1
const int CE2 = 9;	//Cellule 2
const int CE3 = 10;	//Cellule 3
const int CE4 = 11;	//Cellule 4

Au niveau setup, pour le moment, j’ai assigné mes 4 boutons de base. Elles simules les cellules.

void setup() {
	lcd.begin(16,2);

	pinMode(CE1, INPUT);	//CE1 en mode input
	pinMode(CE2, INPUT);	//CE2 en mode input
	pinMode(CE3, INPUT);	//CE3 en mode input
	pinMode(CE4, INPUT);	//CE4 en mode input
	
}

Et maintenant, mon loop. Attention les yeux !

void loop() {
	
	
	int cellule1 = digitalRead(CE1);
	int cellule2 = digitalRead(CE2);
	int cellule3 = digitalRead(CE3);
	int cellule4 = digitalRead(CE4);
	
	if(cellule1 == HIGH && cellule2 == LOW && cellule3 == HIGH && cellule4 == HIGH) {
		lcd.clear();
		lcd.setCursor(0, 0);
		lcd.print("Za1 -> Za2");
	}
	
	if(cellule1 == LOW && cellule2 == HIGH && cellule3 == HIGH && cellule4 == HIGH) {
		lcd.clear();
		lcd.setCursor(0, 0);
		lcd.print("Za4 -> Za1");
	}
	
	if(cellule1 == HIGH && cellule2 == HIGH && cellule3 == HIGH && cellule4 == LOW) {
		lcd.clear();
		lcd.setCursor(0, 0);
		lcd.print("Za3 -> Za4");
	}
	
	if(cellule1 == HIGH && cellule2 == HIGH && cellule3 == LOW && cellule4 == HIGH) {
		lcd.clear();
		lcd.setCursor(0, 0);
		lcd.print("Za2 -> Za3");
	}
	delay(100);
}

Bon, comme on peut le voir, j’ai été obliger de mettre mes 4 conditions pour que ça marche. La raison en est très simple. Le while (attendre que) ne fonctionne pas. C’est la boucle infinie. J’ai donc étudier les cas. Et j’ai ceci:
1/ Au démarrage 1011 (c’est mes 4 inter, ce1 ce2 ce3 ce4)
2/ Le train part donc 0011
3/ Le train arrive sur la ce2 0111 → séquence 2

Ok mais justement, si on regarde bien, els autres if partait si je ne prennais que 2 cas sur la totalité. Le système croyant qu’il fallait bouclé.

J’ai donc eu une autre idée et qui sera à mon avis beaucoup plus optimisé. Si je fais l’écoute du portB en entier. Pour les test c’est une uno. Bref ! Il faudra que j’ai quelque chose comme 1011000 (pin 9 à 13). Cela m’arrange car !
Si je fais un test sur un masque.
if(port == 1011000) → sequence 1
if(port == 0111000) → sequence 2

On n’a plus besoin de rajouter les “&&” et la ribambelle de code si un jour une extension survient. Vous voyez ou je veux en venir ?

Bon, alors c’est ça que je veux coder maintenant :grin:
Comment configurer le port B de ma Uno de test pour permettre de lire tout le port d’un coup ?
Comment faire pour que le code reste sous forme binaire ?
Comment faire le if() avec le binaire ?

Demain je commencerais une série de recherche en ce sens. Cependant, si quelqu’un d’expérience a déjà tester et à un petit exemple vite paf sur ce port, ça serais pas si mal. XD

Merci beaucoup.

binaire, décimal, hexadécimal c'est juste une manière de représenter des nombres. Cela ne change rien au code que tu écris.
Un peu de lecture : Integer Constants - Arduino Reference

PINA, PINB, PINC, .... permettent de lire l'état d'un port du microcontrôleur en un accès.
PORTA, PORTB, .... permettent d'écrire l'état d'un port du microcontrôleur en un accès.

Ah oui, très intéressant ton lien. Je le garde en mémoire pour m'en servir.

Mais je me demande quel est la démarche pour recevoir le port entier sous forme binaire.

Quoi qu'il existe peut-être un moyen de concaténé pour géré ça.

Geeks:
Mais je me demande quel est la démarche pour recevoir le port entier sous forme binaire.

port = PINB

Après cette instruction port contient l'état du port B (les 8 bits). Ensuite t'en fais ce que tu veux

Ok, je test ça se soir 8)

Bon après je ne sait pas encore comment je vais faire ma tambouille. Mais je trouverais une parade.

Autre chose. Ca n'a rien à voir avec le port en lui-même.

On sait comparer un tableau avec un autre ? Si c'est le cas, c'est une des possibilités à explorer avec la précédente.

Geeks:
On sait comparer un tableau avec un autre ? Si c’est le cas, c’est une des possibilités à explorer avec la précédente.

memcmp fait ça.

Et bien, c'set parfait 8)

Je fini ce que j'ai à faire et je m'y colle :wink:

Merci beaucoup.