Forums LR PRESSE

Où il est question de trains, petits et grands

  • Advertisement

Arduino et incompatibilité de manoeuvre (enclenchement)

Toutes les discussions sur l'Arduino !

Modérateur: MOD

Re: Arduino et incompatibilité de manoeuvre (enclenchement)

Publié: Mar 25 Fév 2014, 20:43 
Mais est-ce vraiment nécessaire pour nos réseau ? :siffle:
Cordialement,

Christian.
Avatar de l’utilisateur
likiki
Causant
 
Messages: 252
Inscrit le: Dim 29 Avr 2012, 15:21
Localisation: Corbeil Essonne
Âge: 50
Echelle pratiquée: N
Prénom: Christian

Re: Arduino et incompatibilité de manoeuvre (enclenchement)

Publié: Mar 25 Fév 2014, 21:15 
tout dépend de ce que tu recherches.
Pour moi il est impensable d'utiliser un truc façon windaube pour simuler un PRCI
et dans le cas d'un poste à levier et de la table d'enclenchement, celà permet par exemple de ne pas être en court circuit suite à un franchissement inapproprié d'une alimentation sur la voie, ou d'éviter une fausse manoeuvre et de simplifier considérablement le cablage.

Le bouquin que je présente décrit précisément toute la signalisation "moderne" SNCF, avec la detection, la commande, le controle, les enclenchements, l'espacement, les ICPS, les PN, les postes, l'informatique lié, il s'agit d'un résumé quasi officiel.
J'étais aux WC :mdr:
Avatar de l’utilisateur
fa57
Zorro est à rivets
 
Messages: 15999
Inscrit le: Sam 20 Août 2005, 15:52
Localisation: ACAL

Re: Arduino et incompatibilité de manoeuvre (enclenchement)

Publié: Mer 26 Fév 2014, 11:05 
likiki a écrit:Mais est-ce vraiment nécessaire pour nos réseau ? :siffle:


Non, ce n'est pas nécessaire. A chacun de choisir jusqu'où il souhaite se rapprocher de la réalité et sous quel angle
Fabrice Fayolle
Avatar de l’utilisateur
ffayolle
Causant
 
Messages: 247
Inscrit le: Mar 09 Mai 2006, 19:55
Localisation: Amiens, Somme, Picardie
Âge: 50

Re: Arduino et incompatibilité de manoeuvre (enclenchement)

Publié: Jeu 27 Fév 2014, 09:40 
Intéressant...
Mais je me demande s'il ne serait pas possible de modulariser :
-> une table de décision fonction du réseau et de l'analyse des enclenchements;
-> un programme générique de gestion de la table de décision;
-> les entrées/sorties en fonction des besoins...
Bref, le code est écrit une fois pour toute et la table de décision taillée sur mesure.
Avatar de l’utilisateur
Ramboman
Disert
 
Messages: 423
Inscrit le: Lun 23 Oct 2006, 18:13
Localisation: Waterloo, Belgique
Âge: 72
Echelle pratiquée: LGB

Re: Arduino et incompatibilité de manoeuvre (enclenchement)

Publié: Dim 09 Mars 2014, 11:37 
ramboman a écrit:Intéressant...
Mais je me demande s'il ne serait pas possible de modulariser :
-> une table de décision fonction du réseau et de l'analyse des enclenchements;
-> un programme générique de gestion de la table de décision;
-> les entrées/sorties en fonction des besoins...
Bref, le code est écrit une fois pour toute et la table de décision taillée sur mesure.


Bonjour,

C'est déjà un peu le cas.

La table de décision est dans une matrice. Il suffit de changer les différentes valeurs pour gérer un autre plan de voies.

Quant aux entrées sorties, tout au moins pour les sorties, elles peuvent avoir un type différent, type qui permettra de faire une action spécifique. Il suffit alors de créer le bout de programme spécifique au type.
Fabrice Fayolle
Avatar de l’utilisateur
ffayolle
Causant
 
Messages: 247
Inscrit le: Mar 09 Mai 2006, 19:55
Localisation: Amiens, Somme, Picardie
Âge: 50

Re: Arduino et incompatibilité de manoeuvre (enclenchement)

Publié: Dim 24 Avr 2016, 16:28 
Bonjour,

De retour avec mon poste d'aiguillage avec gestion des enclenchements.

J'ai quelque peu modifié le code depuis le 1er post!!! Le principe de base reste le même.

Un exemple avec cette gare typique d'une ligne secondaire britannique :

Image

Le code :

// SignalBox
// Signal box with "Nb_lever" levers with interlocking system
// Lever sound -> Wtv020
// Digitrax LocoNet message -> LocoNet

//Fabrice Fayolle, April 2016
//Beta Version for Arduino Uno

//Signal box with "NB_lever"
const int Nb_lever = 7;

// Arduino Uno
// Pin -> Use for -> Connect to
// 0
// 1
// 2
// 3
// 4 -> Default -> Red LED (with a 220 ohms resistor)
// 5
// 6 -> LocoNet Transmit pin -> Locoshield PCB Tx pin
// 7
// 8 -> LocoNet Receive pin -> Locoshield PCB Rx pin
// 9 to 15 -> Lever Input -> SPDT ON-ON
// 16 to 19 -> Wtv020 -> Wtv020 PCB

// INPUT
// Lever : SPDT ON-ON
// 1 -> 5V -> Normal position
// Common point -> Lever Input
// 2 -> GND -> Reverse position
// OUTPUT
// Digitrax LocoNet message

// Type lever table
// 0 -> Not use
// 1 -> Point
// 2 -> FPL
// 3 -> Signal
const int Table_lever_type[Nb_lever] = {3, 3, 1, 2, 1, 3, 0};

// Locking lever table to initialize each lock lever
// 0 -> No lock
// 1 -> 1 lock
// x -> x lock
const int Table_lever_lock[Nb_lever] = {1, 1, 0, 0, 0, 1, 1};

// Interlocking system table (locking rules)
// 0 -> Nothing
// 1 -> Lock
// -1 -> Release
// 1xx -> LW (Lock When Normal)
// -1xx -> RW (Release When Normal)
// 2xx -> LW (Lock When Reverse)
// -2xx -> RW (Release When Reverse)
const int Table_interlocking[Nb_lever * Nb_lever] = {
// Lever 1 (signal)
// 1 locks 2, 4 and 5
0, 1, 0, 1, 1, 0, 0,
// Lever 2 (signal)
// 2 locks 1, 4 and 5
1, 0, 0, 1, 1, 0, 0,
// Lever 3 (point)
// 3 locks 4
0, 0, 0, 1, 0, 0, 0,
// Lever 4 (FPL)
// 4 releases 1 and 2. 4 locks 3
-1, -1, 1, 0, 0, 0, 0,
// Lever 5 (point)
// 5 locks 1 and 2. 5 locks 3 BW. 5 releases 6
1, 1, 1, 0, 0, -1, 0,
// Lever 6 (signal)
// 6 locks 3 BW and 5
0, 0, 1, 0, 1, 0, 0,
// Lever 7 (-)
// not used
0, 0, 0, 0, 0, 0, 0,
};

// Visual management for interlocking system
// Default lever position
const int DefaultPin = 4;

//LocoNet
#include <LocoNet.h>
// LocoNet Transmit pin
#define LNtxPin 6
// pointer to a received LocoNet packet
lnMsg *LnPacket;
//DDC Address of stationary decoder
const int Table_lever_dcc[Nb_lever] = {1, 2, 3, 4, 5, 6, 7};
void sendOPC_SW_REQ(int SLever_dcc, boolean SLever_state, boolean On)
{
lnMsg SendPacket ;
int sw2 = 0x00;
if (SLever_state)
{
sw2 |= B00100000;
}
if (On)
{
sw2 |= B00010000;
}
sw2 |= (SLever_dcc >> 7) & 0x0F;
SendPacket.data[ 0 ] = OPC_SW_REQ ;
SendPacket.data[ 1 ] = SLever_dcc & 0x7F ;
SendPacket.data[ 2 ] = sw2 ;
LocoNet.send( &SendPacket );
//Serial.println("OPC_SW_REQ LocoNet message sent");
}
void LocoNet_Message(int SLever_dcc, int SLever_type, boolean SLever_state)
{
switch (SLever_type)
{
case 0 :
// 0 -> Not use
break;
case 1 :
// 1 -> Point
sendOPC_SW_REQ(SLever_dcc, SLever_state, true);
sendOPC_SW_REQ(SLever_dcc, SLever_state, false);
break;
case 2:
// 2 -> FPL
break;
case 3:
// 3 -> Signal
break;
default:
break;
}
}

//Wtv020
#include <Wtv020sd16p.h>
const int clockPin = 16; // CLOCK 7
const int resetPin = 17; // RESET 1
const int diPin = 18; // DATAIN 10
const int busyPin = 19; // BUSY 15
Wtv020sd16p wtv020sd16p(resetPin, clockPin, diPin, busyPin);
// 0000.AD4 -> 0 -> Lever change
// 0001.AD4 -> 1 -> Signal box is ready to use
//Wait the end of the sound before to do
void Wtv020_wait()
{
delay(250);
while (digitalRead(busyPin) == HIGH)
{
}
}

//Object "Lever"
class Lever
{
private:
int Lever_input;
int Lever_type;
int Lever_state;
int Lever_lock;
int Lever_dcc;
public:
void Setup(int SLever_input);
boolean State_of_lever();
boolean Change_asking();
boolean Change_is_possible();
void Change();
void Change_lever_lock(int SChange);
}
;

void Lever::Setup(int SLever_input)
{
// Input : from pin 9 to pin 15
Lever_input = SLever_input + 9;
pinMode (Lever_input, INPUT);
digitalWrite(Lever_input, HIGH);
boolean Normal = true;
boolean Reverse = false;
if (digitalRead(Lever_input) == Reverse)
{
delay(100);
if (digitalRead(Lever_input) == Reverse)
{
digitalWrite(DefaultPin, HIGH);
while (digitalRead(Lever_input) == Reverse)
{
}
digitalWrite(DefaultPin, LOW);
}
}
Lever_type = Table_lever_type[SLever_input];
// State of the lever
// true -> Normal(by default)
// false -> Reverse
Lever_state = true;
Lever_lock = Table_lever_lock[SLever_input];
Lever_dcc = Table_lever_dcc[SLever_input];
LocoNet_Message(Lever_dcc, Lever_type, true);
}

boolean Lever::Change_asking()
{
boolean result = false;
if (digitalRead(Lever_input) != Lever_state)
{
delay(100);
if (digitalRead(Lever_input) != Lever_state)
{
result = true;
}
}
return result;
}

boolean Lever::Change_is_possible()
{
boolean result = false;
result = (Lever_lock == 0);
if (result == false)
{
while (digitalRead(Lever_input) != Lever_state)
{
digitalWrite(DefaultPin, HIGH);
}
digitalWrite(DefaultPin, LOW);
}
return result;
}

void Lever::Change()
{
Lever_state = !Lever_state;
// Wtv020
wtv020sd16p.asyncPlayVoice(0);
//DCC
LocoNet_Message(Lever_dcc, Lever_type, Lever_state);
//Wtv020
Wtv020_wait();
}

boolean Lever::State_of_lever()
{
boolean result = true;
result = Lever_state;
return result;
}

void Lever::Change_lever_lock(int SChange)
{
Lever_lock += SChange;
}

Lever L[Nb_lever];

void setup()
{
// Initialize Serial Port USB at 57600 baud
Serial.begin(57600);
Serial.println("Monitor");
// Wtv020
wtv020sd16p.reset();
delay(250);
// Visual management
pinMode(DefaultPin, OUTPUT);
digitalWrite(DefaultPin, LOW);
// Levers setup
for (int i = 0; i < Nb_lever; i++)
{
L[i].Setup(i);
}
// Wtv020
wtv020sd16p.asyncPlayVoice(1);
//Wtv020_wait();
Serial.println("Ready to use");
}

void loop()
{
for (int i = 0; i < Nb_lever; i++)
{
if (L[i].Change_asking())
{
if (L[i].Change_is_possible())
{
// Interlocking rules
Locking_rules(i);
// Change the state of the lever
L[i].Change();
Serial.print("Lever ");
Serial.print(i + 1);
Serial.print(" changed to ");
if (L[i].State_of_lever())
{
Serial.print("Normal");
}
else
{
Serial.print("Reverse");
}
Serial.println();
}
}
}
}

void Locking_rules(int Slever)
// Apply interlocking system rules when you move a lever
{
int Shift = Slever * Nb_lever;
if (L[Slever].State_of_lever())
// Lever on "Normal" position
{
for (int i = 0; i < Nb_lever; i++)
{
switch (Table_interlocking[Shift + i])
{
case 0 :
break;
case -1 :
// Releases
L[i].Change_lever_lock(Table_interlocking[Shift + i]);
Serial.print(Slever + 1);
Serial.print(" releases ");
Serial.println(i + 1);
break;
case 1 :
// Locks
L[i].Change_lever_lock(Table_interlocking[Shift + i]);
Serial.print(Slever + 1);
Serial.print(" locks ");
Serial.println(i + 1);
break;
default :
// Locks/Releases when xx Normal/Reverse
L[i].Change_lever_lock(Conditionnal_locking(Table_interlocking[Shift + i]));
;
}
}
}
else
// Lever on "Reverse" position
{
for (int i = 0; i < Nb_lever; i++)
{
switch (Table_interlocking[Shift + i])
{
case 0 :
break;
case -1 :
// Locks
L[i].Change_lever_lock(-Table_interlocking[Shift + i]);
Serial.print(Slever + 1);
Serial.print(" locks ");
Serial.println(i + 1);
break;
case 1 :
// Releases
L[i].Change_lever_lock(-Table_interlocking[Shift + i]);
Serial.print(Slever + 1);
Serial.print(" releases ");
Serial.println(i + 1);
break;
default :
// Releases/Locks when xx Normal/Reverse
L[i].Change_lever_lock(-Conditionnal_locking(Table_interlocking[Shift + i]));
;
}
}
}
}

int Conditionnal_locking (int Locking)
// Verify lever position if interlocking system rule is Locks/Releases When Lever xx is Normal/Reverse
{
int Hundred = Locking / 100;
int result = 0;
switch (Hundred)
{
case 1 :
// Locks when Lever (Locking-(HundredX100)) is Normal
if (L[Locking - 101].State_of_lever())
{
result = 1;
}
break;
case -1 :
// Releases when Lever (Locking-(HundredX100)) is Normal
if (L[-Locking - 101].State_of_lever())
{
result = -1;
}
break;
case 2 :
// Locks when Lever (Locking-(HundredX100)) is Reverse
if (!L[Locking - 201].State_of_lever())
{
result = 1;
}
break;
case -2 :
// Releases when Lever (Locking-(HundredX100)) is Reverse
if (!L[-Locking - 201].State_of_lever())
{
result = -1;
}
break;
}
return result;
}


J'ai ajouté un certain nombre de messages (Moniteur Série 57600 bauds) afin de mieux comprendre ce qui se passe.

Le poste d'aiguillage construit pour le test :

Image

La manœuvre du levier, lorsqu'elle est possible, génère un message Digitrax LocoNet. Mais rien n'empêche comme avant de définir un type de levier (Lever_type) qui modifierait l'état LOW ou HIGH d'une sortie. Ce qui permettrait de commander un relais,...

Je n'attends plus que le circuit imprimé pour effectuer mes tests avec mon système Digitrax.

J'utilise un module WTV020 pour générer le son d'un levier de poste d'aiguillage en mouvement.

Ce code permet de gérer un poste d'aiguillage à 7 leviers. Mais il s'adapte à n'importe quelle situation ou presque!!!
Il suffit de modifier le contenu de 3 tables :
    Table_lever_type
    Table_lever_lock
    Table_interlocking
Test and enjoy!!!

Fabrice

PS : Le code manque encore un peu de commentaires!!!
Fabrice Fayolle
Avatar de l’utilisateur
ffayolle
Causant
 
Messages: 247
Inscrit le: Mar 09 Mai 2006, 19:55
Localisation: Amiens, Somme, Picardie
Âge: 50

Re: Arduino et incompatibilité de manoeuvre (enclenchement)

Publié: Lun 02 Mai 2016, 18:20 
Bonsoir,
Je viens de finaliser mes tests avec le Locoshield pour Arduino (cf. viewtopic.php?f=63&t=76609&p=1906711#p1897162)
C'est parfait. Je peux maintenant commander mes aiguilles via Digitrax LocoNet depuis mon poste d'aiguillage qui inclut le système d'enclenchements.

Le code complet du programme (hors bibliothèques complémentaires):

Code: Tout sélectionner
// SignalBox
// Signal box (terminus station with single track) with "Nb_lever" levers
// Signal box integrated interlocking system and tokenless block system (single track / terminus station)
// Sound system -> Wtv020
// Digitrax LocoNet -> LocoNet
// Tokenless Block System -> Tokenless

// Fabrice Fayolle, May 2016
// Version 1.0 for Arduino Uno

// Signal box with "NB_lever"
const int Nb_lever = 7;

// Arduino Uno
// Pin        -> Use for                      -> Connect to
// 0
// 1
// 2          -> Tokenless Up (IN)            -> Tokenless PCB
// 3          -> Tokenless Signal Up (OUT)    -> Tokenless PCB
// 4         
// 5          -> Tokenless Signal Down (OUT)  -> Tokenless PCB
// 6          -> Default                      -> Red LED (with a 220 ohms resistor)
// 7          -> LocoNet Transmit pin         -> Locoshield PCB Tx pin
// 8          -> LocoNet Receive pin          -> Locoshield PCB Rx pin
// 9 to 15    -> Lever Input                  -> SPDT ON-ON
// 16 to 19   -> Wtv020                       -> Wtv020 PCB

// INPUT
// Lever : SPDT ON-ON
// 1 -> 5V -> Normal position
// Common point -> Lever Input
// 2 -> GND -> Reverse position
// OUTPUT
// Digitrax LocoNet message

// Type lever table
// 0 -> Not use
// 1 -> Point
// 2 -> FPL
// 3 -> Signal
// 4 -> Block signal
const int Table_lever_type[Nb_lever] = {4, 4, 1, 2, 1, 3, 0};

// Locking lever table to initialize each lock lever
// 0 -> No lock
// 1 -> 1 lock
// x -> x lock
const int Table_lever_lock[Nb_lever] = {1, 2, 0, 0, 0, 1, 1};

// Interlocking system table (locking rules)
// It's not necessary to simplify locking rules like with mechanical locking bars
// 0 -> Nothing
// 1 -> Lock
// -1 -> Release
// 1xx -> LWxxN (Lock When xx Normal)
// -1xx -> RWxxN (Release When xx Normal)
// 2xx -> LWxxR (Lock When xx Reverse)
// -2xx -> RWxxR (Release When xx Reverse)
const int Table_interlocking[Nb_lever * Nb_lever] = {
  // Lever 1 (signal)
  // 1 locks 2, 3, 4, 5 and 6
  0, 1, 1, 1, 1, 1, 0,
  // Lever 2 (signal)
  // 2 locks 1, 3, 4, 5 and 6
  1, 0, 1, 1, 1, 1, 0,
  // Lever 3 (point)
  // 3 locks 1,2 and 4
  1, 1, 0, 1, 0, 0, 0,
  // Lever 4 (FPL)
  // 4 releases 1 and 2. 4 locks 3
  -1, -1, 1, 0, 0, 0, 0,
  // Lever 5 (point)
  // 5 locks 1 and 2. 5 releases 6
  1, 1, 0, 0, 0, -1, 0,
  // Lever 6 (signal)
  // 6 locks 1, 2, 3(BW) and 5
  1, 1, 1, 0, 1, 0, 0,
  // Lever 7 (-)
  // not used
  0, 0, 0, 0, 0, 0, 0
};

// Visual management for interlocking system
// Default lever position
const int DefaultPin = 6;

// Tokenless block system
// Rail directions : Up Line -> To London / Down Line -> To the station
boolean Block_ON = false;
// Define which Arduino UNO Pin you use for communicate with the Tokenless PCB
const int upBlock_request_PIN = 2;
const int upBlock_signalopen_PIN = 3;
const int downBlock_signalopen_PIN = 5;
// Define which lever type you use for Block signal
const int Block_signal = 4;
// Define which lever you use to control signal
const int upSignal_lever = 1;
const int downSignal_lever = 0;
boolean upBlock_request = false;
boolean upBlock_blocked = false;

// LocoNet
#include <LocoNet.h>
// LocoNet Transmit pin
#define LN_TX_PIN     7
// Pointer to a received LocoNet packet
lnMsg  *LnPacket;
// DDC Address of stationary decoder
const int Table_lever_dcc[Nb_lever] = {1, 2, 3, 4, 11, 6, 7};
void sendOPC_SW_REQ(int SLever_dcc, boolean SLever_state, boolean On)
{
  lnMsg SendPacket ;
  int sw2 = 0x00;
  if (SLever_state)
  {
    sw2 |= B00100000;
  }
  if (On)
  {
    sw2 |= B00010000;
  }
  sw2 |= (SLever_dcc >> 7) & 0x0F;
  SendPacket.data[ 0 ] = OPC_SW_REQ ;
  SendPacket.data[ 1 ] = SLever_dcc & 0x7F ;
  SendPacket.data[ 2 ] = sw2 ;
  LocoNet.send( &SendPacket );
  Serial.print ("DCC address ");
  Serial.print(SLever_dcc+1);
  Serial.println(" : OPC_SW_REQ LocoNet message sent");
}
void LocoNet_Message(int SLever_dcc, int SLever_type, boolean SLever_state)
{
  switch (SLever_type)
  {
    case 0 :
      // 0 -> Not use
      break;
    case 1 :
      // 1 -> Point
      sendOPC_SW_REQ(SLever_dcc - 1, SLever_state, true);
      sendOPC_SW_REQ(SLever_dcc - 1, SLever_state, false);
      break;
    case 2:
      // 2 -> FPL
      break;
    case 3:
      // 3 -> Signal
      break;
    case 4:
      // 4 -> Block signal
      break;
    default:
      break;
  }
}

// Wtv020
#include <Wtv020sd16p.h>
const int clockPin = 16;  // CLOCK   7
const int resetPin = 17;  // RESET   1
const int diPin = 18;     // DATAIN  10
const int busyPin = 19;   // BUSY    15
Wtv020sd16p wtv020sd16p(resetPin, clockPin, diPin, busyPin);
// 0000.AD4 -> 0 -> Lever change
// 0001.AD4 -> 1 -> Block system code bell
// 0002.AD4 -> 2 -> People talking
// 0003.AD4 -> 3 -> Steam engine
// 0004.AD4 -> 4 -> People talking (2)
// Wait the end of the sound before to do something else
void Wtv020_wait()
{
  delay(250);
  while (digitalRead(busyPin) == HIGH)
  {
  }
}
void Play_random_sound()
{
  unsigned long time = millis();
  if (time % random(1, 1000) == random(0, 10))
  {
    Serial.println("Sound system");
    wtv020sd16p.asyncPlayVoice(random(2, 5));
    Wtv020_wait();
  }
}

// Object "Lever"
class Lever
{
  private:
    int Lever_input;
    int Lever_type;
    int Lever_state;
    int Lever_lock;
    int Lever_dcc;
  public:
    void Setup(int SLever_input);
    boolean State_of_lever();
    int Type_of_lever();
    boolean Change_asking();
    boolean Change_is_possible();
    void Change();
    void Change_lever_lock(int SChange);
}
;

void Lever::Setup(int SLever_input)
{
  // Input : from pin 9 to pin 15
  Lever_input = SLever_input + 9;
  pinMode (Lever_input, INPUT);
  digitalWrite(Lever_input, HIGH);
  boolean Normal = true;
  boolean Reverse = false;
  if (digitalRead(Lever_input) == Reverse)
  {
    delay(100);
    if (digitalRead(Lever_input) == Reverse)
    {
      digitalWrite(DefaultPin, HIGH);
      while (digitalRead(Lever_input) == Reverse)
      {
      }
      digitalWrite(DefaultPin, LOW);
    }
  }
  Lever_type = Table_lever_type[SLever_input];
  // State of the lever
  // true -> Normal(by default)
  // false -> Reverse
  Lever_state = true;
  Lever_lock = Table_lever_lock[SLever_input];
  Lever_dcc = Table_lever_dcc[SLever_input];
  LocoNet_Message(Lever_dcc, Lever_type, true);
}

boolean Lever::Change_asking()
{
  boolean result = false;
  if (digitalRead(Lever_input) != Lever_state)
  {
    delay(100);
    if (digitalRead(Lever_input) != Lever_state)
    {
      result = true;
    }
  }
  return result;
}

boolean Lever::Change_is_possible()
{
  boolean result = false;
  result = (Lever_lock == 0);
  if (result == false)
  {
    while (digitalRead(Lever_input) != Lever_state)
    {
      digitalWrite(DefaultPin, HIGH);
    }
    digitalWrite(DefaultPin, LOW);
  }
  return result;
}

void Lever::Change()
{
  Lever_state = !Lever_state;
  // Wtv020
  wtv020sd16p.asyncPlayVoice(0);
  // LocoNet
  LocoNet_Message(Lever_dcc, Lever_type, Lever_state);
  // Wtv020
  Wtv020_wait();
}

boolean Lever::State_of_lever()
{
  boolean result = true;
  result = Lever_state;
  return result;
}

int Lever::Type_of_lever()
{
  int result = 0;
  result = Lever_type;
  return result;
}

void Lever::Change_lever_lock(int SChange)
{
  Lever_lock += SChange;
}

Lever L[Nb_lever];

void setup()
{
  // Initialize Serial Port USB at 57600 baud
  Serial.begin(57600);
  Serial.println("Monitor");
  // LocoNet
  LocoNet.init(LN_TX_PIN);
  // Wtv020
  wtv020sd16p.reset();
  delay(500);
  // If you want to adjust the speaker volume, modify on Wtv020sd16p library (Wtv020sd16p.cpp)
  // this constant VOLUME_MAX = 0xFFF7 (from 0xFFF0 to 0xFFF7)  and use the unmute() function
  wtv020sd16p.unmute();
  delay(500);
  // Visual management
  pinMode(DefaultPin, OUTPUT);
  digitalWrite(DefaultPin, LOW);
  // Levers setup
  for (int i = 0; i < Nb_lever; i++)
  {
    L[i].Setup(i);
  }
  Serial.println("Ready to use");
  // Tokenless
  pinMode(upBlock_request_PIN, INPUT);
  pinMode(upBlock_signalopen_PIN, OUTPUT);
  digitalWrite(upBlock_request_PIN, HIGH);
  digitalWrite(upBlock_signalopen_PIN, HIGH);
  pinMode(downBlock_signalopen_PIN, OUTPUT);
  digitalWrite(downBlock_signalopen_PIN, HIGH);
  Serial.println("Tokenless Block System : Normal");
}

void loop()
{
  for (int i = 0; i < Nb_lever; i++)
  {
    if (L[i].Change_asking())
    {
      if (L[i].Change_is_possible())
      {
        // Interlocking rules
        Locking_rules(i);
        // Change the state of the lever
        L[i].Change();
        Serial.print("Lever ");
        Serial.print(i + 1);
        Serial.print(" changed to ");
        if (L[i].State_of_lever())
        {
          Serial.print("Normal");
        }
        else
        {
          Serial.print("Reverse");
        }
        Serial.println();
        // Tokenless
        if ( i == upSignal_lever)
        {
          if (L[i].State_of_lever())
          {
            if (Block_ON)
            {
              L[i].Change_lever_lock(1);
              Serial.print("Block System locks ");
              Serial.println(i + 1);
              upBlock_blocked = true;
              digitalWrite(upBlock_signalopen_PIN, HIGH);
            }
          }
          else
          {
            if (Block_ON)
            {
              digitalWrite(upBlock_signalopen_PIN, LOW);
              Serial.println("Tokenless Block System : UP -> Blocked");
            }
          }
        }
        if ( i == downSignal_lever)
        {
          if (L[i].State_of_lever())
          {
            digitalWrite(downBlock_signalopen_PIN, HIGH);
            Serial.println("Signal DOWN Line -> Closed");
          }
          else
          {
            digitalWrite(downBlock_signalopen_PIN, LOW);
            Serial.println("Signal DOWN Line -> Open");
          }
        }
      }
    }
  }
  // Tokenless
  upBlock_accept();
  upBlock_normal();
  // Wtv020
  Play_random_sound();
}

void Locking_rules(int Slever)
// Apply interlocking system rules when you move a lever
{
  int Shift = Slever * Nb_lever;
  if (L[Slever].State_of_lever())
    // Lever on "Normal" position
  {
    for (int i = 0; i < Nb_lever; i++)
    {
      switch (Table_interlocking[Shift + i])
      {
        case 0 :
          break;
        case -1 :
          // Releases
          L[i].Change_lever_lock(Table_interlocking[Shift + i]);
          Serial.print(Slever + 1);
          Serial.print(" releases ");
          Serial.println(i + 1);
          break;
        case 1 :
          // Locks
          L[i].Change_lever_lock(Table_interlocking[Shift + i]);
          Serial.print(Slever + 1);
          Serial.print(" locks ");
          Serial.println(i + 1);
          break;
        default :
          // Locks/Releases when xx Normal/Reverse
          L[i].Change_lever_lock(Conditionnal_locking(Table_interlocking[Shift + i]));
          ;
      }
    }
  }
  else
    // Lever on "Reverse" position
  {
    for (int i = 0; i < Nb_lever; i++)
    {
      switch (Table_interlocking[Shift + i])
      {
        case 0 :
          break;
        case -1 :
          // Locks
          L[i].Change_lever_lock(-Table_interlocking[Shift + i]);
          Serial.print(Slever + 1);
          Serial.print(" locks ");
          Serial.println(i + 1);
          break;
        case 1 :
          // Releases
          L[i].Change_lever_lock(-Table_interlocking[Shift + i]);
          Serial.print(Slever + 1);
          Serial.print(" releases ");
          Serial.println(i + 1);
          break;
        default :
          // Releases/Locks when xx Normal/Reverse
          L[i].Change_lever_lock(-Conditionnal_locking(Table_interlocking[Shift + i]));
          ;
      }
    }
  }
}

int Conditionnal_locking (int Locking)
// Verify lever position if interlocking system rule is Locks/Releases When Lever xx is Normal/Reverse
{
  int Hundred = Locking / 100;
  int result = 0;
  switch (Hundred)
  {
    case 1 :
      // Locks when Lever (Locking-(HundredX100)) is Normal
      if (L[Locking - 101].State_of_lever())
      {
        result = 1;
      }
      break;
    case -1 :
      // Releases when Lever (Locking-(HundredX100)) is Normal
      if (L[-Locking - 101].State_of_lever())
      {
        result = -1;
      }
      break;
    case 2 :
      // Locks when Lever (Locking-(HundredX100)) is Reverse
      if (!L[Locking - 201].State_of_lever())
      {
        result = 1;
      }
      break;
    case -2 :
      // Releases when Lever (Locking-(HundredX100)) is Reverse
      if (!L[-Locking - 201].State_of_lever())
      {
        result = -1;
      }
      break;
  }
  return result;
}

void upBlock_accept()
// Tokenless Block System on "Accepted" for Up Line
{
  upBlock_request = digitalRead(upBlock_request_PIN);
  delay(100);
  if ( !upBlock_request && (!Block_ON && L[downSignal_lever].State_of_lever()))
  {
    // Wtv020
    wtv020sd16p.asyncPlayVoice(1);
    Wtv020_wait();
    Serial.println("Tokenless Block System : UP Line -> Accepted");
    L[upSignal_lever].Change_lever_lock(-1);
    Serial.print("Block System releases ");
    Serial.println(upSignal_lever + 1);
    L[downSignal_lever].Change_lever_lock(1);
    Serial.print("Block System locks ");
    Serial.println(downSignal_lever + 1);
    Block_ON = true;
  }
}

void upBlock_normal()
// Tokenless Block System on "Normal"
{
  upBlock_request = digitalRead(upBlock_request_PIN);
  delay(100);
  if (L[upSignal_lever].State_of_lever())
  {
    if ( upBlock_request && Block_ON )
    {
      if (!upBlock_blocked)
      {
        L[upSignal_lever].Change_lever_lock(1);
        Serial.print("Block System locks ");
        Serial.println(upSignal_lever + 1);
      }
      upBlock_blocked = false;
      Block_ON = false;
      L[downSignal_lever].Change_lever_lock(-1);
      Serial.print("Block System releases ");
      Serial.println(downSignal_lever + 1);
      Serial.println("Tokenless Block System : Normal");
    }
  }
}


La suite : faire un Locoshield pour Arduino Mega afin d'étendre les possibilités

Des commentaires ? Des questions ?

Modélistement, Fabrice
Fabrice Fayolle
Avatar de l’utilisateur
ffayolle
Causant
 
Messages: 247
Inscrit le: Mar 09 Mai 2006, 19:55
Localisation: Amiens, Somme, Picardie
Âge: 50

Re: Arduino et incompatibilité de manoeuvre (enclenchement)

Publié: Mar 03 Mai 2016, 12:02 
Ca à l'air très bon. peut être une vidéo pour démonstration apporterait un éclaircissement aux lecteurs.
Le train de la vie file.
Avatar de l’utilisateur
HDE5962
Éloquent
 
Messages: 347
Inscrit le: Mar 20 Août 2013, 10:03
Localisation: Malakoff par obligation et Schti par naissance
Âge: 55
Echelle pratiquée: HO et de cordes

Re: Arduino et incompatibilité de manoeuvre (enclenchement)

Publié: Mar 03 Mai 2016, 13:36 
Merci beaucoup pour ce post
@+
12035
Avatar de l’utilisateur
12035
Communicatif
 
Messages: 921
Inscrit le: Lun 08 Déc 2008, 14:20

Re: Arduino et incompatibilité de manoeuvre (enclenchement)

Publié: Sam 08 Oct 2016, 12:14 
Bonjour,

De retour pour suite et fin de ce fil sauf question bien évidemment.

Le shield pour Arduino Mega :

Image

Testé et approuvé :

Image

Et qui permet de gérer ce tableau :

Image
Fabrice Fayolle
Avatar de l’utilisateur
ffayolle
Causant
 
Messages: 247
Inscrit le: Mar 09 Mai 2006, 19:55
Localisation: Amiens, Somme, Picardie
Âge: 50

Re: Arduino et incompatibilité de manoeuvre (enclenchement)

Publié: Mar 01 Nov 2016, 09:00 
Bonjour à tous,

Pour mon programme d'une gare sur étagère, je crée actuellement une librairie ARDUINO de gestion des enclenchements. Vous pouvez suivre les détails sur ce post :http://forum.e-train.fr/viewtopic.php?f=63&t=80885#p1961806.
Dernière édition par macsddau le Mar 01 Nov 2016, 10:57, édité 1 fois au total.
MS2 CC2 S-DEC-4-DC Rocrail
macsddau
Papotier
 
Messages: 114
Inscrit le: Jeu 17 Oct 2013, 22:46
Echelle pratiquée: N

Re: Arduino et incompatibilité de manoeuvre (enclenchement)

Publié: Mar 01 Nov 2016, 10:29 
Salut
Merci pour le partage.
@+
12035
Avatar de l’utilisateur
12035
Communicatif
 
Messages: 921
Inscrit le: Lun 08 Déc 2008, 14:20

Précédent

Retour vers Arduino

Qui est en ligne ?

Utilisateur(s) parcourant actuellement ce forum : Yahoo [Bot] et 3 invité(s)