Auteur Sujet: Modélisation logicielle d'un réseau - le système de Pierre59  (Lu 70024 fois)

Pierre59

  • Sr. Member
  • ****
  • Messages: 316
    • Voir le profil
Bonjour

Je voudrais monter ici une approche objet de la modélisation logicielle d'un réseau.

Mon réseau est constitué d'un ovale à double voie sur lequel il y a une coulisse et une gare moyenne. Cette gare comporte plusieurs voies à quai, une partie marchandises et un dépot, de la gare part aussi une voie unique finissant à une petite gare terminus.

Le réseau comporte une trentaine d'aiguilles, une trentaine de zones et une dizaine de cantons.

Le réseau est géré par un très gros programme sur PC. Une dizaine de cartes électroniques sur deux bus I2C font l'interface entre le PC et le réseau.

Le programme sur PC comporte plusieurs parties :

- une partie de gestion des cartes électroniques (rétrosignalisation, souris, commandes des alimentations, des aiguilles, des signaux …)

- une partie de gestion de TCOs sur l'écran du PC (il pourrait avoir un TCO réel)

- une grosse partie de gestion du fonctionnement du réseau, cette partie reçoit toutes les infos du réseau (rétrosignalisation …) et toutes les commandes des utilisateurs (souris, itinéraires, …), elle sait ainsi toujours ce qui se passe sur le réseau. Cette partie est réalisée en programmation objet et ne comporte pas de tables, la description du réseau se fait par les liens entre les objets et les méthodes (fonctions) de ces objets.

Je vais essayer de décrire les principales classes et leur fonctionnement en détaillant un peu plus la classe Zone. Mes classes sont en Java mais je vais essayer de les présenter à la C++ (longtemps que je n'ai pas fait de C++ objet).

La classe essentielle est la classe Zone :

class Zone {
   String nom;
   boolean etat; // libre ou occupé
   Train train; // le train dans la zone
   Signal signalPair,signalImpair; // les signaux éventuels de la zone

   Zone(…) {…} // constructeur

   virtual Zone suivantePaire(); // la zone suivante paire (éventuellement vide)
   virtual Zone suvanteImpaire(); // la zone suivante impaire (éventuellement vide)

   virtual void actions(); // les actions spécifiques à faire en cas d'occupation
   virtual void desactions(); // les actions spécifiques à faire en cas de libération

   boolean occupee() { return etat; } // méthode utilitaire
   boolean libre() { return !etat; } // méthode utilitaire

   void occuper() { // appelée par la rétrosignalisation
      // fait tout ce qu'il y a à faire en cas d'occupation (actions communes à toutes les zones)
      actions(); // fait les actions spécifiques à une zone
   }
   void liberer() { // appelée par la rétrosignalisation
      // fait tout ce qu'il y a à faire en cas de libération (actions communes à toutes les zones)
      desactions(); // fait les actions spécifiques à une zone
   }
}

chaque zone réelle fait l'objet d'une classe héritant de la classe Zone, voici un exemple :

class Z9 : Zone { // héritage de Zone
   
   Z9(…) {…} // constructeur

   void actions() { aubiner(c3,c5); } // fermeture de signaux (occupation)
   void desactions() { detruire(XA,XB,XC); } // destruction d'itinéraires (liberation)

   Zone suivantePaire() { return z11; } // la zone paire suivante (toujours la meme)
   Zone suivantePaire() { if (a3.directe()) return z9; else return z7; } // la zone impaire suivante (dépends de la position de l'aiguille a3)
}

Ces classes zones décrivent la géométrie du réseau et les interactions entre les différentes parties. Elles précisent les liens entre les zones (de façon dynamique en fonction de la position réelle des aiguilles), l'emplacement des signaux, … Tout le réseau est ainsi décrit.

Les autres classes principales s'articulent autour des zones :

- la classe signal gère les signaux (lumineux et mécaniques), elle calcule les feux en fonction des occupations de zones, des signaux adjacents et de la position des aiguilles, elle fait le cantonnement pour les parties du réseau qui en sont équipées) et commandes les signaux.

- la classe Aiguille garde la position d'une l'aiguille et fait l'interface avec l'électronique pour les commandes

- la classe Train mémorise les informations sur un train ( sens, vitesse, nom de l'engin moteur, adresse DCC, …)

- la classe Itineraire réalise les itinéraires (une centaine), elle fait les enclanchements entre itinéraires, la mémorisation/création/destruction des itinéraires. Elle est organisée comme la classe Zone, la classe Itineraire contient tout ce qui est commun à tous les itinéraires, des classes (héritant de la classe Itineraire) contenant  les parties spécifiques.


Cette programmation objet bien que assez technique est très puissante, elle peut gérer des petits ou grands réseaux,, elle évite les tables (avec leur problèmes de construction/mise à jour, …), elle facilite grandement des modification ponctuelles du réseau (seules quelques classes sont à modifier ou à créer) et facilite la mise au point au début. Elle nécessite un processeur assez puissant. Du point de vue allocation mémoire les objets sont tous crées à l'initialisation du programme, l'accroissement des variables est linéaire avec l'accroissement du réseau.

Cette programmation n'évite pas (comme avec d'autres types de  programmations) les problèmes de synchronisation dans le cas de fonctionnement multi-tâches et/ou de programmation évenementielle (sur interruptions).

Voila, n'hésitez pas à poser des questions, et franchissez le pas de la programmation objet (voir les cours sur les objets et l'héritage dans une autre partie du site)

Pierre



Pierre59

  • Sr. Member
  • ****
  • Messages: 316
    • Voir le profil
Re : Modélisation logicielle d'un réseau - le système de Pierre59
« Réponse #1 le: juin 16, 2015, 05:23:56 pm »
Bonjour

J'en remet une couche (d'objets), voici un squelette d'itinéraire.

Il faut d'abord quelque classes accessoires  :

class Zone {
  boolean etat; // etat de la Zone (libre ou occupee)
public:
  boolean libre() { return !etat; }
};

class Aiguille {
public:
  boolean directer() { /* commande de l'aiguille */ return true; }
  boolean devier()   { /* commande de l'aiguille */ return true; }
};

class Signal {
public:
  boolean ouvrir() { /* commande du signal */ return true; }
  boolean fermer() { /* commande du signal */ return true; }
} ;

Puis quelques variables :

TB iTB; TD iTD; BT iBT; DT iDT; // itineraires
Zone za,zb,zc; // zones
Aiguille a1,a2,a3; // aiguilles
Signal s1,s2,s3; // signaux

La classe de base "Itineraire" contient tout ce qui est commun à tous les itinéraires :

class Itineraire { // classe de base des itineraires
  byte etat; // l'etat de l'itineraire (libre, en attente, forme, ... )

public:
  boolean libre() { return etat==0; }
  boolean formation()    { if (formable()) return former(); else return false; }
  boolean destruction() { if (deformable()) return deformer(); else return false; }
   
protected:
  virtual boolean formable();
  virtual boolean former();
  virtual boolean deformable();
  virtual boolean deformer();
 
// methodes utilitaires
protected:
  boolean libre(Zone &a) { return a.libre(); }
  boolean libres(Zone &a,Zone &b) { return a.libre() && b.libre(); }
  boolean libres(Zone &a,Zone &b,Zone &c) { return a.libre() && b.libre()&& c.libre(); }
  boolean libres(Zone &a,Zone &b,Zone &c,Zone &d) { return a.libre() && b.libre() && c.libre() && d.libre(); }
  // ...
  boolean libre(Itineraire &a) { return a.libre();
  boolean libres(Itineraire &a,Itineraire &b) { return a.libre() && b.libre(); }
  boolean libres(Itineraire &a,Itineraire &b,Itineraire &c) { return a.libre() && b.libre()&& c.libre(); }
  boolean libres(Itineraire &a,Itineraire &b,Itineraire &c,Itineraire &d) { return a.libre() && b.libre() && c.libre() && d.libre(); }
   // ...
  };

Les méthodes formation() et deformation() permettent de former et de détruire l'itinéraire (elles peuvent êtres enrichies si nécessaire). Elles peuvent êtres appellées par les boutons de commande et/ou par d'autres objets (Zone par exemple) pour des destructions automatiques.

Les méthodes formable(), former(), deformable() et deformer() sont propres à un itinéraire particulier, elles seront définies dans des classes dérivées, une par itinéraire (c'est pour cela qu'elles sont marquées virtuelles).

Les méthodes libre(s)(…) sont des méthodes utilitaires pour faciliter l'écriture des méthodes précédentes. Pour ne pas faire de copies inutiles les objets sont appelés par référence. (on peut aussi utiliser des méthodes avec un nombre d'arguments variables).

Voici pour finir un exemple d'itinéraire particulier (une des classes correspondant à chaque itinéraire) :

class TC:public Itineraire { // un itineraire particulier de T vers C
  virtual boolean formable() { return
    libres(iTB,iTD,iBT,iDT) && // enclanchements entre itineraires
    libres(za,zb,zc); // enclanchements sur les zones
  }
  virtual boolean former() { return a1.devier() && a2.directer() && s1.ouvrir(); }
  virtual boolean deformable() { return libres(za,zb,zc); }
  virtual boolean deformer() { return s1.fermer(); }
};


La méthode formable() gère les enclanchements.
La méthode former() établit l'itinéraire en positionnant les aiguilles et en ouvrant le signal.
La méthode deformable() s'assure que l'itinéraire peut être détruit.
La méthode deformer() ferme le signal.

Bien sur d'autres tests et d'autres actions peuvent êtres ajoutées dans ces méthodes.

Vous voyez ce n'est pas si compliqué que cela, il faut bien entendu écrire toutes les classes itinéraire particulier, mais c'est assez répétitif.
Il est facile de modifier des itinéraires d'ajouter des itinéraires …
Il est facile de faire la mise au point avec des affichages sur le moniteur série.
Bon courage !

Pierre

Dominique

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 2870
  • 100% Arduino et N
    • Voir le profil
Re : Modélisation logicielle d'un réseau - le système de Pierre59
« Réponse #2 le: juin 16, 2015, 07:45:28 pm »
Merci beaucoup Pierre,

L'intérêt de la programmation Objet s'avère particulièrement utile dans ce domaine (je ne veux pas dire qu'il ne l'est pas dans d'autres).

Tes contributions m'ont convaincu : je vais essayer de concevoir la modélisation de mon réseau de cette façon, ce qui nous permettra d'en discuter avec du concrêt.

Amicalement
Dominique
Cordialement,
Dominique

Pierre59

  • Sr. Member
  • ****
  • Messages: 316
    • Voir le profil
Re : Modélisation logicielle d'un réseau - le système de Pierre59
« Réponse #3 le: juillet 06, 2015, 05:03:03 pm »
Bonjour

Une dernière couche avant les vacances (toujours d'objet) pour les signaux. Les signaux sont très "polymorphes", c'est à dire qu'ils ont pas mal d'aspects et de comportements différents (lumineux, mécaniques, sémaphores, carrés, avertissements, …). Même façon d'écrire que pour les classes précédentes, une classe de base qui contient tout ce qui est commun, des classes dérivées pour les particularités. Sauf qu'ici on va regrouper des particularités, conduisant à de l'héritage d'héritage (pas de panique c'est tout naturel).

La première classe est la classe Signal :

typedef unsigned int typeFeux;

enum Feu {E=0,Vl=1,A=2,S=4,C=8,R=16,RR=32,M=64,Cv=128,D=256};

   
class Signal {
protected:
  typeFeux feu=E; // 16 cas possibles (16 bits)
public:
  virtual boolean ouvrir() { /* commande du signal */ return true; }
  virtual boolean fermer() { /* commande du signal */ return true; }
  boolean aubiner() {  return fermer();  }

  boolean ferme() { return feu&(S|C|Cv); }
  boolean v30() { return feu&RR; } // vitesse 30
  boolean r30() { return feu&A|R; } // ralentissement a 30
  };

  virtual typeFeux feux() { return E; }
  virtual void maj() {}
 
  virtual Signal* suivant() { return NULL; }
  virtual Signal* precedent() { return NULL; }
  virtual boolean occupe() { return false; } // occupation du canton

// methodes utilitaires
  Signal* selon(Aiguille &a,Signal &s1,Signal &s2) { return a.directe()?&s1:&s2; }

  boolean occupee(Zone &z) { return z.occupee(); }
  boolean occupees(Zone &z1,Zone &z2) { return z1.occupee() || z2.occupee(); }
  boolean occupees(Zone &z1,Zone &z2,Zone &z3) { return z1.occupee() || z2.occupee() || z3.occupee(); }
};


La classe Signal comporte une variable mémorisant l'état des feux, les valeurs des feux sont des puissances de 2 pour pouvoir faire des opérations ensemblistes (unions, intersections) facilement. Les fonctions ouvrir() et fermer() seront définies dans les classes dérivées. La fonction aubiner() ferme le signal (on pourrait éventuellement la redéfinir en cas de besoin). Les fonctions ferme(), v30() ou r30() sont des fonctions utilitaires ainsi que les fonctions occupee(s)() et la fonction selon(). Les fonctions fonctions feux() et maj() seront définies dans les classes dérivées, la fonction feux() "calcule" les feux à l'ouverture du signal, la fonction maj() est appelée par le signal suivant lors d'un changement de feux. La fonction utilitaire selon() retourne le signal suivant en fonction de la position de l'aiguille (facilité d'écriture). Les fonctions utilitaires occupee(s)() testent l'occupation du canton (utiles pour les cantons multi-zones notamment dans les gares).

Quelques classes correspondant à des signaux particuliers :

La classe Carré violet est la plus simple, pas d'interactions avec d'autre signaux. On peut aubiner le signal lors de l'occupation de la zone qui suit le signal. Cette classe peut être utilisée directement (sans faire de nouvelles classes). Pour ce type de carré on sait définir les méthodes ouvrir(), fermer() (feux() et maj() ne servent pas) :

class CarreViolet:public Signal {
  boolean ouvrir() { feu=M;  /* commande signal */ return true; }
  boolean fermer() { feu=Cv;  /* commande signal */ return true; }
};

Exemple de carré violet :

CarreViolet cv5;


La classe Carré (sans sémaphore) est plus intéressante car elle dépend d'autres signaux. On peut aubiner le signal lors de l'occupation de la zone qui suit le signal. Pour ce type de signal on sait définir les méthodes ouvrir(), fermer(), feux() et maj(), par contre les fonctions suivant() et precedent() dépendent d'un carré particulier (topologie du réseau), il faudra donc hériter de Carre pour un carré particulier. La classe Carre :

class Carre:public Signal {
  boolean ouvrir() { feu=feux(); precedent()->maj(); /* commande signal */ return true; }
  boolean fermer() { feu=C; precedent()->maj(); /* commande signal */ return true; }

  typeFeux feux() { // feux a l'ouverture
    if (suivant()->ferme()) return A; else return Vl;
  }

  void maj() { typeFeux f; // appele par le signal suivant
    if (ferme()) return; // pas de propagation si pas de changement
    f=feux(); if (f!=feu) { feu=f; precedent()->maj(); }
  }
};


Exemple de carré  particulier :

class C2:public Carre {
  virtual Signal* suivant() { return selon(a2,s1,s3); } // selon a2
  virtual Signal* precedent() { return &s1; }
};


le signal suivant dépends d'une aiguille.

La classe Sémaphore interagit avec d'autres signaux et avec des zones. Le sémaphore est fermé (aubiné) par l'occupation de la première zone du canton, lors de la libération de la dernière zone du canton ouvrir() est appelée pour mettre à jour les feux. La fonction occupe() teste l'occupation du canton (pour les cantons multi-zones). Pour ce type de signal on sait définir les méthodes ouvrir(), fermer(), feux() et maj(), par contre les fonctions suivant() et precedent() dépendent d'un sémaphore particulier, il faudra donc hériter de Semaphore pour un sémaphore particulier. La classe Semaphore :

class Semaphore:public Signal {
  boolean ouvrir() { feu=feux(); precedent()->maj(); /* commande signal */ return true; }
  boolean fermer() { feu=S; precedent()->maj(); /* commande signal */ return true; }

  typeFeux feux() { // feux a l'ouverture
    if (occupe()) return S; else // canton occupe ( precaution )
    if (suivant()->ferme()) return A; else return Vl;
  }

  void maj() { typeFeux f; // appele par le signal suivant
    if (ferme()) return; // pas de propagation si pas de changement
    f=feux(); if (f!=feu) { feu=f; precedent()->maj(); }
  }
};


Exemple de sémaphore particulier :

class S2:public Semaphore {
  virtual Signal* suivant() { return &s2; }
  virtual Signal* precedent() { return &s1; }
  virtual boolean occupe() { return occupees(za,zb,zc); } // occupation du canton (3 zones)
};

Voila avec cette façon de programmer on peut prendre en compte toutes les configurations de signal possible, j'ai sur mon réseau des carrés avec manoeuvre ou rappel de ralentissement et  en plus sémamaphore (pour les itinéraires permanents).

Je n'ai pas de classe Canton, mais cela serait possible.

Comme pour des zones et les itinéraires il manque les constructeurs (les destructeurs ne sont pas utiles ici), ce que je voudrai montrer ici c'est essentiellement l'aspect conceptuel de l'approche objet. Les classes ne sont pas exemptes d'erreurs, ni de mauvaises écritures (notamment Zone qui n'utilise pas les pointeurs où il faudrait). Bien qu'ayant enseigné, il y longtemps, le C++, j'ai beaucoup oublié (mais cela revient) car maintenant je fais du Java (je transcode ici du Java en C++), de plus je ne peux pas faire de tests, je peux juste compiler pour vérifier.

On pourrait imaginer de construire une bibliothèque de classes, mais cette bibliothèque ne pourrait pas être utilisée directement comme d'autres bibliothèques, il faudrait écrire des classes héritant des classes de la bibliothèque pour beaucoup de composants du réseau (zones, aiguilles, signaux, …), car ce sont ces classes qui définissent la topologie du réseau.

Bonnes vacances.

Pierre


Dominique

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 2870
  • 100% Arduino et N
    • Voir le profil
Re : Modélisation logicielle d'un réseau - le système de Pierre59
« Réponse #4 le: juillet 10, 2015, 12:22:01 am »
Voilà une serie de contributions fort intéressantes et concrètes  :)

Je retiens d'abord le fait que la description du réseaux ne se fait pas dans une table, mais dans chaque objet directement : chaque zone (ou canton, mais une zone peut inclure une aiguille, pas un canton normalement) décrit les connexions aux zones adjacentes.

Cela demande certainement un petit travail de préparation : est-il possible de montrer un exemple simple ?
-> ce serait le coté statique !

Ensuite chaque objet peut être personnalisé (à partir de l'héritage) ce qui laisse entrevoir la grande souplesse du modèle et la facilité d'évolution (on ne peut pas penser à tout dès le début !).

Ensuite ce modèle vit au rythme des événements (les traitements des signaux remontés par les capteurs aux passage des trains appellent-ils les méthodes des objets directement ? ).
-> c'est le coté dynamique !

Merci pour ces "devoirs de vacances" : il va me falloir un peu de temps pour imaginer mon réseau de cette façon.

Et bravo encore à Denis et Pierre de rendre cette rubrique si concrète..

Dominique
Cordialement,
Dominique

Pierre59

  • Sr. Member
  • ****
  • Messages: 316
    • Voir le profil
Re : Modélisation logicielle d'un réseau - le système de Pierre59
« Réponse #5 le: juillet 11, 2015, 11:57:50 am »
Bonjour

Quelques réponses :

Citer
chaque zone (ou canton, mais une zone peut inclure une aiguille, pas un canton normalement)

Toujours la polémique avec les cantons. Pour moi une zone est une portion de voie (avec ou sans aiguille(s)) munie d'une détection de présence des trains. Un canton est une portion de voie entre deux sémaphores.

Cela n'exclue pas qu'il puisse y avoir plusieurs zones dans un canton, dont des zones avec aiguilles.
Sur nos réseaux un canton a généralement au moins deux zones une zone de pleine voie et une zone d'arret.

Citer
est-il possible de montrer un exemple simple ?

J'ai regardé pour extraire une toute petite partie de mon réseau, mais c'est pas évident.

Citer
les traitements des signaux remontés par les capteurs aux passage des trains appellent-ils les méthodes des objets directement ?

Les évènements issus du réseau appellent les méthodes sur les objets, par exemple l'occupation et la libération des zones appellent les méthodes occuper() et liberer() de Zone. Il faut seulement veiller que pendant le traitement d'un évènement d'autres ne soient pas pris en compte, pour que la mise à jour de l'état du réseau puisse faire complètement. Plus généralement quand on a appelé une méthode sur un objet il faut que tout ce qui en découle se fasse sans interruption  (pour préserver un état cohérent du réseau).

Pierre

Dominique

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 2870
  • 100% Arduino et N
    • Voir le profil
Re : Modélisation logicielle d'un réseau - le système de Pierre59
« Réponse #6 le: novembre 18, 2015, 06:55:55 pm »
Bonjour à tous,

Je voudrais témoigner ici que la modélisation "objet" de Pierre fonctionne bien !

J’ai donc modélisé mon réseau avec les objets Aiguille et Zone seulement pour commencer.

Cela se passe en 4 étapes :

Etape 1 : les classes prototypes (copier-coller du code de Pierre).

J’en ai profité pour ajouter l’action d’envoi des commandes d’aiguille sur le bus CAN, mais cela ne sert pas pour le moment.

///////////// PROTOTYPE CLASSE AIGUILLE ////////////////////

class Aiguille {
private:
  byte index;             // 0.. MaxAIG-1
  boolean etat=true;      // directe (true) ou deviee false)
  Zone* zone;             // la Zone ou est l'aiguille

public:
 
  Aiguille(byte a_index, Zone* z) { // constructeur
    index = a_index;
    zone=z; 
  }
 
  boolean directer() {     // commande de l'aiguille en position directe
    this->etat=true;
    output.id = 0x40;
    output.length = 1;
    output.data.bytes[0] = this->index + 0xC0;
    Can0.sendFrame(output);
    return true;
  }
 
  boolean devier()   {     // commande de l'aiguille en position déviée
    this->etat=false;
    output.id = 0x40;
    output.length = 1;
    output.data.bytes[0] = this->index + 0x80;
    Can0.sendFrame(output);
    return true;
  }
 
  boolean directe() {     // demande d'état
    return this->etat;
    } // méthode utilitaire};
};

////////////////// PROTOTYPE CLASSE ZONE ////////////////////

class Zone {
public:
  byte index;           // 0.. MaxZone-1
  boolean etat;         // libre ou occupé
  Signal* signalPair;
  Signal* signalImpair; // les signaux éventuels de la zone

  Zone(byte a_index, Signal* sp, Signal* si) { // constructeur
    index = a_index;
    signalPair=sp;
    signalImpair=si; }
   
   virtual Zone* suivantePaire() { return NULL; } // la zone suivante paire (éventuellement vide)
   virtual Zone* suivanteImpaire() { return NULL; } // la zone suivante impaire (éventuellement vide)

   virtual void actions() {} // les actions spécifiques à faire en cas d'occupation
   virtual void desactions() {} // les actions spécifiques à faire en cas de libération

   boolean occupee() { return etat; } // méthode utilitaire
   boolean libre() { return !etat; } // méthode utilitaire

   void occuper() { // appelée par la rétrosignalisation
      // fait tout ce qu'il y a à faire en cas d'occupation (actions communes à toutes les zones)
      actions(); // fait les actions spécifiques à une zone
   }
   void liberer() { // appelée par la rétrosignalisation
      // fait tout ce qu'il y a à faire en cas de libération (actions communes à toutes les zones)
      desactions(); // fait les actions spécifiques à une zone
   }

   Zone* selonAiguille(Aiguille* a,Zone* z1,Zone* z2) { return a->directe()?z1:z2; } // méthode utilitaire
};

Etape 2 : je crée toutes mes zones par héritage du prototype (voici seulement les 4 premières, elle sont toutes identiques)

////////////// HERITAGES CLASSES ZONES REELLES ////////////////////
// les zones reelles (héritages de Zone)

// 0 gare base loisirs (pair/droite= 1 impair/gauche=0=butoir)
class Z0 : public Zone { // 0 gare base loisirs (pair/droite= 1 impair/gauche=0=butoir)
public:
  Z0(byte ai, Signal* sp, Signal* si):Zone(ai,sp,si) {}
  virtual Zone* suivantePaire();
  virtual Zone* suivanteImpaire();
};
// 1 VV centre (pair/droite=2, impair/gauche=0)
class Z1 : public Zone { // 1 VV centre (pair/droite=2, impair/gauche=0)
public:
  Z1(byte ai, Signal* sp, Signal* si):Zone(ai,sp,si) {}
  virtual Zone* suivantePaire();
  virtual Zone* suivanteImpaire();
};
// 2 liaison VV-Hor (pair/droite=3siPdroite, impair/gauche=1+aiguillePdevié=4)
class Z2 : public Zone {
public:
  Z2(byte ai, Signal* sp, Signal* si):Zone(ai,sp,si) {}
  virtual Zone* suivantePaire();
  virtual Zone* suivanteImpaire();
};
// 3 gare centre (droite/pair=3=butoir, gauche/impair=2)
class Z3 : public Zone {
public:
  Z3(byte ai, Signal* sp, Signal* si):Zone(ai,sp,si) {}
  virtual Zone* suivantePaire();
  virtual Zone* suivanteImpaire();
};
etc…

Etape 3 : déclaration des objets réels (zones et aiguilles).

Pour accéder individuellement aux objets, à partir des index contenus dans les messages CAN (dans un événement « occupation de zone » par exemple), j’ai déclaré un tableau de zones. De même pour le tableau d’aiguilles.
De cette façon, on ne manipule que des pointeurs sur les zones et les aiguilles.

/////////////////// DECLARATIONS ZONES ////////////////////
// zones
Zone* z0=new Z0(0,NULL,s2);
Zone* z1=new Z1(1,NULL,s2);
Zone* z2=new Z2(2,NULL,NULL);
Zone* z3=new Z3(3,s2,NULL);
Zone* z4=new Z4(4,s2,c2);
Zone* z5=new Z5(5,s2,c2);
Zone* z6=new Z6(6,s2,c2);
Zone* z7=new Z7(7,s2,c2);
Zone* z8=new Z8(8,s2,c2);
Zone* z9=new Z9(9,s2,c2);
etc…

const int MaxZone = 40;

Zone* listez[MaxZone]=  {
    z0, z1, z2, z3, z4, z5, z6, z7, z8, z9, z10, z11, z12, z13, z14, z15,
    z16, z17, z18, z19, z20, z21, z22, z23, z24, z25, z26, z27, z28, z29, z30,
    z31, z32, z33, z34, z35, z36, z37, z38, z39
  };

/////////////////// DECLARATIONS AIGUILLES //////////////////// 
// aiguilles
Aiguille* a0=new Aiguille(0,z26);  //A
Aiguille* a1=new Aiguille(1,z26);  //B
Aiguille* a2=new Aiguille(2,z15);  //C
Aiguille* a3=new Aiguille(3,z26);  //D
Aiguille* a4=new Aiguille(4,z15);  //E
Aiguille* a5=new Aiguille(5,z14);  //F
Aiguille* a6=new Aiguille(6,z14);  //G
Aiguille* a7=new Aiguille(7,z12);  //H
Aiguille* a8=new Aiguille(8,z12);  //I
Aiguille* a9=new Aiguille(9,z29);  //J
Aiguille* a10=new Aiguille(10,z38); //K
Aiguille* a11=new Aiguille(11,z29); //L
Aiguille* a12=new Aiguille(12,z39); //M
Aiguille* a13=new Aiguille(13,z6); //N
Aiguille* a14=new Aiguille(14,z35); //O
Aiguille* a15=new Aiguille(15,z2); //P
Aiguille* a16=new Aiguille(16,z4); //Q
Aiguille* a17=new Aiguille(17,z17); //R
Aiguille* a18=new Aiguille(18,z24); //S
Aiguille* a19=new Aiguille(19,z37); //T TJD demi a5 vers deviation
Aiguille* a20=new Aiguille(20,z37); //U TJD demi a6 vers deviation

const int MaxAig = 21;
 
Aiguille* listea[MaxAig]= {
  a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11,
  a12, a13, a14, a15, a16, a17, a18, a19, a20
};

Etape 4 : la modélisation de mon réseau commence maintenant par l’écriture des méthodes particulières « suivantePaire » et « suivanteImpaire »

Pour ce faire, j’ai découpé mon réseau en zones. Certaines zones contiennent une aiguille ou plusieurs. J’ai défini le sens Pair (horaire) et Impaire (trigo) pour savoir quelle est la zone suivante paire ou impaire en fonction de la position d’aiguille s’il y en a une à traverser.



J’applique alors la méthode utilitaire du prototype :

selonAiguille(Aiguille* a,Zone* z1,Zone* z2) { return a->directe()?z1:z2; }
et cela donne :

///////////////////// METHODES PARTICULIERES DES ZONES ///////////////////////
// les methodes des zones

// Z0 gare base loisirs (pair/droite= z1 impair/gauche=butoir)
Zone* Z0::suivantePaire() { return z1; }
Zone* Z0::suivanteImpaire() { return NULL; }

// 1 VV centre (pair/droite=2, impair/gauche=0)
Zone* Z1::suivantePaire() { return z2; }
Zone* Z1::suivanteImpaire() { return z0; }

// 2 liaison VV-Hor (pair/droite=3, impair/gauche=1+aiguillePdevié=4)
Zone* Z2::suivantePaire() { return selonAiguille(a15,z3,NULL); }
Zone* Z2::suivanteImpaire() { return selonAiguille(a15,z1,selonAiguille(a16,NULL,z4)); }

// 3 gare centre (droite/pair=3=butoir, gauche/impair=2)
Zone* Z3::suivantePaire() { return NULL; }
Zone* Z3::suivanteImpaire() { return z2; }

// 4 GC Hor Ext (pair=6+aiguilleQdevié=2, impair=17)
Zone* Z4::suivantePaire() { return selonAiguille(a16,selonAiguille(a13,NULL,z7),selonAiguille(a15,NULL,z3)); }
Zone* Z4::suivanteImpaire() { return selonAiguille(a17,NULL,z16); }

// 5 GC Hor Int (pair=6, impair=17)
Zone* Z5::suivantePaire() { return selonAiguille(a13,z7,NULL); }
Zone* Z5::suivanteImpaire() { return selonAiguille(a17,z16,NULL); }

// 6 sortie GC Hor (pair=7, impair=5+aiguilleNdevié=4) - Normalement pas utilisé
Zone* Z6::suivantePaire() { return z7; }
Zone* Z6::suivanteImpaire() { return selonAiguille(a13,z5,selonAiguille(a16,z4,NULL)); }

etc..

Tests et Simulations

J’ai réalisé un petit montage sur le Due, avec un écran graphique 2,4 pouces et 3 boutons poussoirs (+, - et OK).
+ et - permettent de se déplacer dans les lignes et OK execute une fonction (menu sélectionné ou action)
Le programme affiche une liste de menus:



- menus Aiguilles :  je peux positionner chaque aiguille



- menu train : je peux définir le sens de déplacement
- menu Itinéraire : j’ai défini 7 points de départ. En appuyant sur OK, le programme demande la zone suivante successives aux objets en fonction des positions d’aiguilles (ici elles sont toutes droites, d’ou la série de « 1 » en bas de l’écran)

Ce petit bout de code fait tout (exemple pour le départ de la zone 5) :

zonedepart = 5;
        Show("5 ");
        zindex = 5;
        for (int i=0; i<10; i++)  {
          zt = senstrain? listez[zindex]->suivantePaire() : listez[zindex]->suivanteImpaire();
          if (zt == NULL) break;
          zindex = zt->index;
          tft.print(zindex);
          tft.print(" ");
        }



J’ai varié les positions d’aiguilles, le sens du train et à chaque fois, en vérifiant sur mon plan de réseau, les itinéraires sont tous bons !!!

CQFD
Un bon tuto suivra peut-être, prochainement.

Bien cordialement

Dominique
« Modifié: mai 07, 2016, 06:30:23 pm par Dominique »
Cordialement,
Dominique

Dominique

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 2870
  • 100% Arduino et N
    • Voir le profil
Re : Modélisation logicielle d'un réseau - le système de Pierre59
« Réponse #7 le: novembre 18, 2015, 07:05:39 pm »
Juste une petite précision supplémentaire :
J'ai volontairement réduit les tailles des images qui doivent, au total, ne pas dépasser 192Ko.

Donc si vous voulez en savoir plus, je répondrai volontiers aux questions.

Dominique
Cordialement,
Dominique

Dominique

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 2870
  • 100% Arduino et N
    • Voir le profil
Re : Modélisation logicielle d'un réseau - le système de Pierre59
« Réponse #8 le: mars 11, 2016, 12:48:07 pm »
Pour illustrer l'article de Pierre : "Un gestionnaire en C++ pour votre réseau" http://www.locoduino.org/spip.php?article154,
voici un exemple qui est la modélisation de mon propre réseau:

Je donne en pièces jointes la topographie réelle du réseau et le programme que j'explique ci-après:

Voici une version simplifiée (utilisée pour mon TCO) montrant les numéros d'aiguilles et de zones (à imprimer) :



Elle sera nécessaire pour se servir du programme.

Je suis parti du dossier Noyau de Base Gestionnaire C++ à la fin de l'article de Pierre et j'ai ajouté mes classes réelles d'aiguilles et de zones.

Les enchainements entre zones et aiguilles sont tout simplement décrits dans les méthodes suivantePaire() et suivanteImpaire() particulières de chaque zone.

Téléversez le programme dans un Arduino Mega ou Due (je n'ai pas encore essayé le Nano ou Uno) et ouvrez la fenêtre Moniteur à 115200 b/s.

Le programme initialise toutes les 19 aiguilles à "directe"

PRS1_DB1 v0.1 du 11 mars 2016
Toutes les aiguilles sont droites
aiguilles 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18
          1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1 
>

On peut faire, avec les commandes du moniteur :

A (ret) : afficher l'état de toutes les aiguilles (comme ci-dessus)

A n (ret) : inverser l'état de l'aiguille n
> A 0
aiguilles 0  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18
          0  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1  1 

I n (ret) : afficher l'itinéraire possible à partir de la zone n, dans le sens horaire, selon les positions des aiguilles
> I 13
Itineraires sens horaire a partir de 13->15->16->17->5->6->7->8->9->10->11->12->13->boucle

I n < (ret) : idem en sens inverse (anti-horaire)
> I 13 <
Itineraires sens trigo a partir de 13->12->11->10->9->8->7->6->5->17->16->15->13->boucle

La fin d'itinéraire est soit "sans fin" et il s'affiche "boucle", soit en "cul de sac" et il s'affiche "fin" :

> I 40
Itineraires sens horaire a partir de 40->0->1->2->3->41->fin

Vous remarquerez que les aiguilles sont dans des zones, ce qui permet de savoir si une aiguille est occupée ou libre (indispensable pour savoir si elles sont manoeuvrables). Parfois il peut y avoir plusieurs aiguilles dans une même zone. C'est réaliste.

Avec cette méthode il n'est pas besoin de savoir comment est connectée une aiguille, par son talon ou ses branches. Il suffit seulement de savoir quelle zone peut être atteinte en fonction de la position de l'aiguille. C'est NULL s'il n'y en a pas !
« Modifié: mars 11, 2016, 12:57:18 pm par Dominique »
Cordialement,
Dominique

Dominique

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 2870
  • 100% Arduino et N
    • Voir le profil
Re : Modélisation logicielle d'un réseau - le système de Pierre59
« Réponse #9 le: mars 11, 2016, 10:52:27 pm »
Retour sur la modélisation de Pierre : un exemple simple sera bien apprécié, je pense.  8)

Nous avons choisi le petit Locodrome initialisé par Guillaume ici : http://forum.locoduino.org/index.php?topic=91.msg650#msg650



Et le programme pour modéliser les 5 zones et les 2 aiguilles se trouve ici en fichier joint.

Le programme tourne sur tous les types d'Arduino, même un Nano !

La commande "A n" permet d'inverser une aiguille n
La commande "I n" ou "I n <" permet d'afficher la suite de zones qui peuvent être parcourues (itinéraire possible) à partir d'une zone n de départ, dans le sens horaire ou anti-horaire (avec "<")

La modélisation du réseau se résume à la définition des méthodes des zones suivantes :

// 0 gare quai droit (zone paire = z2 si a0 droite, impaire = z5 si a1 droite)
Zone* Z0::suivantePaire() { return selonAiguille(a0,z2,NULL); }
Zone* Z0::suivanteImpaire() { return selonAiguille(a1,z5,NULL); }
/* si on accepte de passer les aiguilles en entrant par un talon, quelle que soit leur position
 * alors on peut définir ces methodes comme :
 * Zone* Z0::suivantePaire() { return z2; }
 * Zone* Z0::suivanteImpaire() { return z5; }
 */

// 1 gare quai gauche (zone paire = z2 si a0 deviée, impaire = z5 si a0 déviée)
Zone* Z1::suivantePaire() { return selonAiguille(a0,NULL,z2); }
Zone* Z1::suivanteImpaire() { return selonAiguille(a1,NULL,z5); }
/* si on accepte de passer les aiguilles en entrant par un talon, quelle que soit leur position
 * alors on peut définir ces methodes comme :
 * Zone* Z1::suivantePaire() { return z2; }
 * Zone* Z1::suivanteImpaire() { return z5; }
 */

// 2 aiguille a0 (zone paire = z3, impaire = z0 si a0 droite ou z1 si a0 deviée)
Zone* Z2::suivantePaire() { return z3; }
Zone* Z2::suivanteImpaire() { return selonAiguille(a0,z0,z1); }

// 3 boucle est (zone paire = z4, impaire = z2)
Zone* Z3::suivantePaire() { return z4; }
Zone* Z3::suivanteImpaire() { return z2; }

// 4 boucle ouest (zone paire = z5, impaire = z3)
Zone* Z4::suivantePaire() { return z5; }
Zone* Z4::suivanteImpaire() { return z3; }

// 5 aiguille a1 (zone paire = z0 si a1 droite ou z1 si a1 déviée, impaire = z4)
Zone* Z5::suivantePaire() { return selonAiguille(a1,z0,z1); }
Zone* Z5::suivanteImpaire() { return z4; }

Nous introduirons progressivement les autres méthodes (notamment la méthode provenance() qui permettra le suivi des trains), ainsi que les interfaces avec les organes réels du réseau.

Cordialement,
Dominique

Pierre59

  • Sr. Member
  • ****
  • Messages: 316
    • Voir le profil
Re : Modélisation logicielle d'un réseau - le système de Pierre59
« Réponse #10 le: octobre 04, 2016, 10:18:48 am »
Bonjour

Le troisième article de la série  "Un gestionnaire en C++ pour votre réseau" ( http://www.locoduino.org/spip.php?article172 ) est paru sur le site de LOCODUINO. Après les aiguilles, les zones et les signaux, les itinéraires sont abordés, ainsi qu'un exemple complet avec un réseau minimaliste, le Locodrome. Ce gestionnaire de réseau complet est destiné à fonctionner sur un Arduino Uno (ou plus), il pourra être testé complètement par le biais d’un TCO virtuel avec circulation effective de trains (tout aussi virtuels). Ce TCO virtuel est un programme écrit en Processing qui communique avec le gestionnaire par une liaison USB/série.

On trouvera dans le fichier joint (c'est le même que celui de l'article) :
- le programme de gestion du Locodrome en C++
- le programme du TCO en Processing
- une notice d'utilisation
- un dessin du TCO et un dessin du Locodrome

Le programme de gestion de réseau, utilisé pour le Locodrome, doit être considéré comme la version de référence (pour l'instant) rendant obsolète toutes les versions antérieures.

Avec ces deux programmes on peut jouer au trains (virtuels) presque comme sur un réseau réel.

Voir aussi sur le forum : "LOCODUINO->Parlons Arduino->Vos projets->TCO en Processing" ( http://forum.locoduino.org/index.php?topic=119.15 ), pour plus d'informations sur le TCO.

Bon amusement.

Pierre59
« Modifié: octobre 04, 2016, 10:24:02 am par Pierre59 »

Dominique

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 2870
  • 100% Arduino et N
    • Voir le profil
Re : Modélisation logicielle d'un réseau - le système de Pierre59
« Réponse #11 le: octobre 04, 2016, 10:25:10 am »
Bonjour à tous,

Le 3ème volet du gestionnaire en C++ de Pierre est maintenant en ligne sur le site editorial de Locoduino, ici :
http://www.locoduino.org/spip.php?article172

Nous vous invitons à en discuter ici.

Personnellement j'y trouve les réponses à toutes mes interrogations sur le fonctionnement complet d'un réseau ferroviaire, en particulier quelles sont toutes les interactions entre les éléments du réseau : les zones, les cantons, les aiguilles, les signaux, les itinéraires et, bien-sur, les trains et le TCO.

L'exemple du Locodrome avec le TCO séparé comprenant un simulateur de déplacement de 2 trains, montre bien la "dématérialisation" du gestionnaire par rapport au réseau et ses composants matériels. Mon architecture autour du réseau local CAN se prête bien à la réalisation complète de mon projet, les contributions précédentes de ce fil le montrent bien.

Amicalement
Dominique
Cordialement,
Dominique

DDEFF

  • Hero Member
  • *****
  • Messages: 730
    • Voir le profil
Re : Modélisation logicielle d'un réseau - le système de Pierre59
« Réponse #12 le: octobre 06, 2016, 12:53:28 pm »
De vrais bijoux de programmation objet.

Ces programmes valent vraiment le coup d'être étudiés et décortiqués.

Le programme TCO en processing a évidemment servi de base à mon propre développement (bientôt l'article ...  ;) ).
Je l'ai adapté à ma sauce, développé certains points, mais, fondamentalement, c'est le même programme.
Est même déjà développé ce que je voulais faire : mettre un point pour suivre le train !!
Merci Pierre.
"Ce n'est pas le puits qui est trop profond, c'est ta corde qui est trop courte" (proverbe chinois)

Dominique

  • Global Moderator
  • Hero Member
  • *****
  • Messages: 2870
  • 100% Arduino et N
    • Voir le profil
Re : Modélisation logicielle d'un réseau - le système de Pierre59
« Réponse #13 le: décembre 06, 2016, 06:17:22 pm »
Bonjour à tous,

Les 3 articles de Pierre contiennent tout ce qu'il faut pour construire un gestionnaire complet, sophistiqué, évolutif, donc parfait selon mes intuitions, ce dont je suis sûr également, et ce n'est pas qu'une affaire de goût.

La question que l'on peut se poser est : est-il bien adapté à mon projet, à mon réseau, à son architecture technique, à mes scénarii de circulation, etc... ?

J'ai commencé, plus haut dans ce fil, à expliquer comment j'ai modélisé mon réseau, c'est à dire trouvé une description informatique de la topographie des voies, principalement grâce aux méthodes particulières suivantePaire() et suivanteImpaire() des objets Zone.

Et, de plus, cette modélisation est dynamique puisqu'elle s'adapte aux sens des aiguilles à tout instant !

Cela fait plus d'un an que mon embryon de gestionnaire, basé sur les objets zones et aiguilles de Pierre fonctionne sans la moindre erreur !

Je vais maintenant compléter ce gestionnaire jusqu'au bout, en partageant, avec vous, les étapes de ma progression, et en montrant les relations entre le gestionnaire et le matériel du réseau.

En général dans un projet, on commence toujours par une phase "papier" qui s'appelle "spécifications fonctionnelles puis organiques (dans le temps, quand je travaillais encore pour de vrai...). Cette étape avait pour but de prétendre qu'on allait tout prévoir dans le détail avant de commencer à réaliser.

Mais là on est dans un loisir ! A bas la rigidité !

Personnellement, je veux construire au fur et à mesure de mes disponibilités en temps et en argent, sans me sentir bloqué, sans avoir l'impression de faire des compromis, toujours en visant l'idéal et la perfection. C'est ambitieux ?

En fait non, grâce à Locoduino dirai-je !

Car mon réseau est construit autour de plusieurs modules qui prennent chacun en charge un partie du boulot : traction, aiguilles, occupations, TCO, etc..

C'est selon ce schéma d'architecture que j'ai publié avec l'article L’Arduino au coeur des systèmes de pilotage analogiques ou numériques : http://www.locoduino.org/spip.php?article153 :

J'ai donc réalisé plusieurs modules (même pas la moitié de ce que j'ai prévu, en fait), raccordés sur un bus CAN à 500kb/s, qui s'échangent des messages, sans hiérarchie.

Ce qui permet de répartir les responsabilités entre les organes capteurs (occupations, clés d'aiguilles sur le TCO, par exemple), les organes actionneurs (commandes d'aiguilles, par exemple) et le gestionnaire qui assure l'intelligence du réseau selon l'exemple ci-dessous :


On en déduit tout de suite que le gestionnaire peut se réduire à un simple Arduino Due (le plus costaud de la famille, tant qu'à faire), disposant seulement d'une interface CAN pour recevoir des messages et en envoyer d'autres.

C'est vraiment le chef d'orchestre en haut de son estrade qui dirige les musiciens !

Et dans ce Due, le programme est exactement ce que Pierre a décrit dans ses articles Un gestionnaire en C++ pour votre réseau :
http://www.locoduino.org/spip.php?article154
http://www.locoduino.org/spip.php?article167
http://www.locoduino.org/spip.php?article172

Et c'est d'autant plus naturel que le programme de l'Arduino tourne indéfiniment dans sa loop et ne va faire que lire les messages entrant, analyser ces messages et, en fonction de leur contenu, appeler des méthodes des objets Zone, Aiguilles, Signaux, Trains, etc..

La loop contiendra donc un grand switch pour traiter tous les cas, et on sait bien que l'on peut facilement rajouter d'autres cas par la suite : quelle souplesse cet Arduino !

Et certaines de ces méthodes vont envoyer un ou plusieurs message vers des organes de commande, via le bus CAN, tandis que d'autres ne feront que mettre à jour des variables dans les objets.

La définition de mon projet prend donc une toute autre forme, après avoir défini les modules nécessaires : définir les messages à échanger entre les modules (principalement avec le gestionnaire).

Ensuite, même si tous les messages ne sont pas encore définis, je peux commencer à coder.

C'est un peu cette aventure que je souhaite partager avec vous, dans la suite à venir. Je vais décrire succinctement mes modules et les messages qui les concernent. Puis l'intégration de tout cela dans le gestionnaire de Pierre.

Je pense que cela pourra vous aider à franchir le pas !

A suivre ...
Dominique
Cordialement,
Dominique

Pierre59

  • Sr. Member
  • ****
  • Messages: 316
    • Voir le profil
Re : Modélisation logicielle d'un réseau - le système de Pierre59
« Réponse #14 le: décembre 07, 2016, 01:33:51 pm »

Bonjour

Il y a quelque chose qui me chiffonne beaucoup, dans le LocodromeBAL, associé à l'article 3 http://www.locoduino.org/spip.php?article172, les méthodes suivantePaire() et suivanteImpaire() ne servent pas, on peut les enlever cela ne change rien, en fait elles ne sont la que pour anticiper un peu la suite (l'article 4 à paraitre).

Ce qui veut dire que la topologie du réseau n'est en fait pas décrite explicitement, malgré cela le gestionnaire fonctionne tout à fait normalement, c'est donc le train lors de ses déplacements qui décrit d'une certaine façon la topologie du réseau ???

Bien sûr ces méthodes auront une utilité par la suite.

Pierre59