passage a niveau modelisme

bonjour à tous.

voici mon projet: automatiser un passage à niveau ( 1 seule voie pour commencer), signalisation clignotante et motorisation des barrières.
Je rencontre des problèmes avec la gestion des temporisations, j'aimerai de l'aide pour comprendre ma ou mes erreurs pour être capable seul (si possible) de passé le projet en multi voies

Ma seule formation en codage est le cours dédié sur openclassroom et arduino pour les nuls,
sinon je suis très à l'aise avec les notions d'électricité car je suis dépanneur en porte automatique. Je pourrai facilement le faire avec quelques relais temporisés mais je recherche de nouvelles connaissances/ compétences, d' où mon attirance pour Arduino. Bref.

Le matériel:
2 capteurs magnétiques sous les rails(1 en amont et l' autre en aval du passage à niveau les 2 raccordés en parallèle ),
1 aimant embarqué sous le train.
2 leds pour feux clignotants
2 moteurs pour les 2 barrières (moteur 9 volts sans fins de courses. donc passage par relais et tempo pour le temps de fonctionnement)

l'idée:
le train passe sur le premier capteur, déclenche le clignotement des feux et la fermeture des barrières.
traverse le passage à niveau
passe sur le second capteur ouverture des barrières et arrêt du clignotement.

voici ce que j'ai réussi à faire avec mes maigres connaissance, je suis partis du code pushButtonCounter .

mais voila ça coince! l'inversion de sens (ouvre /ferme) se fait bien et clignotement bien controlé aussi.
seulement tempo moteurs inactives et si la seconde impulsion est donnée après que la tempo moteur soit écoulée le système ne prend plus en compte les impulsions.

const int  buttonPin = 2;    // broche boutton
const int ledPin = 13;       // broche led
const int motSensFerm = 4;   // broche relais ouverture
const int motSensOuv = 7;    // broche relais fermeture
int ledState = LOW;
unsigned long previousMillis = 0;
unsigned long tempoMoteur = 5000; // temps fonctionnement moteur
long interval = 400;              // fréquence clignotement led


int buttonPushCounter = 0;   // compteur d'impulsion
int buttonState = 0;         // état actuel boutton
int lastButtonState = 0;     // état précédent boutton
void setup() {

  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(motSensFerm, OUTPUT);
  pinMode(motSensOuv, OUTPUT);
  Serial.begin(9600);
}


void loop() {
  // lit l'état du boutton
  buttonState = digitalRead(buttonPin);

  // compare les états du boutton
  if (buttonState != lastButtonState) {
    // si état différent incrémente le compteur
    if (buttonState == HIGH) {
      buttonPushCounter++;
      Serial.println("on");
      Serial.print("number of button pushes: ");
      Serial.println(buttonPushCounter);

    } else {

      Serial.println("off");
    }
    // debounce
    delay(100);
  }

  lastButtonState = buttonState;


  unsigned long currentMillis = millis();
  if (buttonPushCounter % 2 != 0) {
    do {
      digitalWrite(motSensOuv, LOW);
    }
    while (currentMillis - previousMillis > tempoMoteur ); {
      previousMillis = currentMillis; 
      digitalWrite(motSensOuv, HIGH);
    }
    digitalWrite(motSensFerm, HIGH);

    if (currentMillis - previousMillis > interval) {
      previousMillis = currentMillis;
      if (ledState == LOW)
        ledState = HIGH;
      else
        ledState = LOW;

      digitalWrite(ledPin, ledState);

    }
  }

  if (buttonPushCounter % 2 == 0)

  {
    unsigned long currentMillis = millis();
    digitalWrite(ledPin, LOW);
    digitalWrite(motSensOuv, HIGH);
    do {
      digitalWrite(motSensFerm, LOW);
    }

    while (currentMillis - previousMillis > tempoMoteur ); {
      previousMillis = currentMillis;
      digitalWrite(motSensFerm, HIGH);
    }
  }

}
[code]


Merci par avance à tous ceux qui prendrons le temps de faire briller ma Led du codage.

j' espère avoir posté au bon endroit et dans les règles du forum.

Bonsoir

ça n’est pas la bonne façon pour le do/while

 do {
      digitalWrite(motSensOuv, LOW);
    }
    while (currentMillis - previousMillis > tempoMoteur ); {
      previousMillis = currentMillis; 
      digitalWrite(motSensOuv, HIGH);
    }

Vous ne mettez pas à jour currentMillis dans la boucle donc le test ne changera jamais + pas besoin d’accolades pour la suite du code (et c’est < pas > qu’il faudrait mettre)

Ce que vous faites est une attente active de tempoMoteur, donc autant utiliser delay()

digitalWrite(motSensOuv, LOW);
delay(tempoMoteur);
digitalWrite(motSensOuv, HIGH);

mais ça bloque l’exécution

Si vous restez avec peu de passages à niveaux, trains — c’est typiquement une définition de programme qui se prête bien à la programmation par machine à états (cf mon tuto éventuellement)

petite précision pour une raison qui m'échappe le seul moyen d'actionner mes relais( marque elegoo)
est de renvoyer un GND sur le pin in1 ou in2.

merci J-M-L je suis sur votre tuto.

Il faudrait savoir quels relais et comment ils sont câblées et alimentés, mais oui certains fonctionnent à LOW suivant ce que vous faites

il s agit d un module 8 relais (aucune ref sur la carte)

10 pins vcc, gnd et in de 1à8

sur 3 autres pins un cavalier me permet de sélectionner vcc/gnd ou jd/vcc.

j ai fais plusieurs essais avec une alim 5 vcc
lorsque je place le cavalier sur vcc/gnd cela crée un court circuit.

lorsque le cavalier est sur jd/vcc
il faut alimenter le module via vcc et gnd
et un retour de gnd sur chaque IN actionne le relais concerné.

Bonsoir

petite précision pour une raison qui m'échappe le seul moyen d'actionner mes relais( marque elegoo)
est de renvoyer un GND sur le pin in1 ou in2.

un petit coup de moteur de recherche et voilà la page du produit

On peut lire "Download" en haut de la pasge web.... on y va et en en bas de page nous voilà avec un fichier à télécharger concernant de produit (notice, schéma, exemples..).

On voit sur le schéma qu'il faut mettre à la masse les entrées IN pour activer les optocoupleurs et les relais correspondants, c'est souvent le cas.

merci Al1fch

honnêtement je n y ai même pas pensé.
j était et suis toujours concentré sur le codage du système.
pour moi le problème s est résolu par LOW au lieu de HIGH.

en effet : quand on se base sur l'exemple blink, par où presque tout le monde a débuté avec arduino, on se met dans l'idée que pour "allumer" il faut faire digitalWrite(pin, HIGH)
pourquoi sur les modules relais c'est l'inverse ?
au lieu de mettre l'entrée de la led de l'optocoupleur sur la cathode, et l'anode reliée au +5v, relier la cathode au gnd et l'entrée sur l'anode était trop compliqué pour les concepteurs ?
les coupeurs de cheveux en quatre vous donneront les explications technologiques adéquates pour expliquer les raisons de ce choix.

La grande majorité de ces modules à relais tout faits ont les entrées actives basses.
Pour que ce soit plus intuitif dans le code, rien n’empêche de faire en début du fichier un :

#define ON LOW
#define OFF HIGH

et ensuite de faire :

digitalWrite(motSensOuv, ON); pour activer le relais, et inversement avec OFF

@Electra - afin d’alimenter le débat je vais jouer le rôle et « Couper les cheveux en 4 »...

  • L'utilisation de signaux bas actifs est antérieure à la logique de circuit intégré et est souvent utilisée dans les voitures où un commutateur peut simplement mettre à la masse un signal pour l’activer - par exemple, le commutateur du plafonnier connectait souvent le signal à la terre (Dans les systèmes où la terre est disponible partout — châssis d'une voiture, par exemple — vous économisez bcp de fil, car vous n'avez besoin que d'un fil pour la charge)

  • Les premières familles de logique bipolaire telles que TTL, DTL ou RTL utilisaient uniquement des transistors bipolaires NPN. Elles pouvaient facilement piloter un signal de sortie à s’approcher à quelques millivolts de la masse (LOW) mais pas facilement à produire un signal élevé (HIGH). C’est pour cela que tant de circuits intégrés ont tendance à utiliser une sortie de signal activé à LOW.

  • Cela permettait également la fonctionnalité de « OU logique câblé » — dans laquelle une porte virtuelle pouvait être créée à partir de signaux à collecteur ouvert.

  • Il y a sur les relais généralement 2 options, NO et NC (normalement ouvert et fermé). il faut toujours faire attention au choix de l'état de repos des relais, le système doit être en sécurité quand aucun relai n'est commandé. Au démarrage ou reboot du microcontrôleurs toutes les E/S sont positionnées en entrée, donc équivalentes à une résistance de plus d'un million d'ohms et vos relais ne se déclenchent donc pas sur pin flottante. C’est pas mal de se dire que au boot (avant que vous n’ayez le temps de mettre vos pins en sortie et à LOW) vous savez ce que va faire votre relai...

Bref tant d’un point de vue historique que pratique, il y a des explications sans tetracapilotomie pour ce choix — la dernière étant sans doute celle qui a conduit elegoo à décider ainsi.

Qu’en pensez vous ?

J-M-L:
(...) le système doit être en sécurité quand aucun relai n'est commandé. Au démarrage ou reboot du microcontrôleurs toutes les E/S sont positionnées en entrée, donc équivalentes à une résistance de plus d'un million d'ohms et vos relais ne se déclenchent donc pas sur pin flottante. C’est pas mal de se dire que au boot (avant que vous n’ayez le temps de mettre vos pins en sortie et à LOW) vous savez ce que va faire votre relai...

Bref tant d’un point de vue historique que pratique, il y a des explications sans tetracapilotomie pour ce choix — la dernière étant sans doute celle qui a conduit elegoo à décider ainsi.

bof, une entrée active haute n'est normalement pas activée non plus par une pin en haute impédance, à moins d'avoir une sensibilité excessive :wink:

C’est vrai aussi :slight_smile:

bien lu et j espere avoir compris le tuto de J-M-L pour le principe du switch/case
combiné a chrono pour les temps de fonctionnement.
je retravaille mon code dès que possible et publierai le résultat.

merci à tous

une fois que tu auras compris le principe avec le tuto de JML tu pourras regarder cette librairie qui va te simplifier la vie en particulier pour les chronos :wink:

Bonjour ou Bonsoir, premier test avec switch / case !! c'est pas jojo! j'ai l impression de conduire avec le levier de vitesse à gauche.

je continue à essayer ! du coup par encore inclus les tempos. Une chose à la fois, je comprend vite mais faut expliquer longtemps!

#include <yasm.h>
#define tempoMoteur 5000

const int  buttonPin = 2;    // broche boutton
const int ledPin = 13;       // broche led
const int motSensFerm = 4;   // broche relais fermeture
const int motSensOuv = 7;    // broche relais ouverture
int ledState = LOW;
unsigned long previousMillis = 0;
long interval = 400;              // fréquence clignotement led


int buttonPushCounter = 0;   // compteur d'impulsion
int buttonState = 0;         // état actuel boutton
int lastButtonState = 0;     // état précédent boutton
enum {ouvert, fermer} etatCourant;

YASM mot;

void setup() {
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);
  pinMode(motSensFerm, OUTPUT);
  pinMode(motSensOuv, OUTPUT);
  Serial.begin(9600);
}

void FERMER () { //nombre d'impulsion impaire == fermer barriere
  switch (buttonPushCounter % 2 != 0) { 
    case fermer:
      digitalWrite(motSensOuv, HIGH);
      break;
    case ouvert:
      digitalWrite(motSensFerm, LOW);
      break;
  }
}
void OUVERT () { //nombre d'impulsion pair == ouvrir barriere
  switch (buttonPushCounter % 2 == 0) {
    case fermer:
      digitalWrite(motSensOuv, LOW);
      break;
    case ouvert:
      digitalWrite(motSensFerm, HIGH);
      break;
  }

}


void loop() {
  // lit l'état du boutton
  buttonState = digitalRead(buttonPin);
  // compare les états du boutton
  if (buttonState != lastButtonState) {
    // si état différent incrémente le compteur
    if (buttonState == HIGH) {
      buttonPushCounter++;
      Serial.println("on");
      Serial.print("number of button pushes: ");
      Serial.println(buttonPushCounter);

    } else {

      Serial.println("off");
    }
    // debounce
    delay(100);
  }

  lastButtonState = buttonState;


  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis > interval) {
    previousMillis = currentMillis;
    if (ledState == LOW)
      ledState = HIGH;
    else
      ledState = LOW;

    digitalWrite(ledPin, ledState);
  }
} 
[code]

[/code]

si tu fais ça avec un switch/case, yasm ne te sert à rien :wink: mais tu as raison, il faut commencer par là

par contre là je n'ai pas l'impression que tes états soient correctement définis

concrètement, comment est faite la détection du passage du train ? je ne comprends pas bien le comptage du nombre d'appui sur le bouton.
Moi j'aurais vu un bouton avant la barrière et un après, pour fermer quand le train passe sur le premier, puis ouvrir quand il passe le second, et inversement dans l'autre sens

la machine à état pourrait servir à gérer le mouvement de la barrière, je verrai bien un truc comme ça :

état 1 = attente ouverte : on surveille si il faut déclancher la fermeture

état 2 = fermeture, on alimente le moteur durant la temporisation

etat 3 = attente fermée : on surveille si il faut déclancher l'ouverture

etat 4 = ouverture, on alimente le moteur durant la temporisation (puis retour à l'état 1)

dans ce cas ton enum doit avoir 4 valeurs, et une seule fonction va réaliser le switch/case avec cette information, et déclencher les différentes actions selon la valeur courante.

j'ai pas pu m'empecher de jeter un oeil à la librairie que tu m'as conseillé du coup j'ai tout mélangé :confused:

c'est ça un bouton avant et un après les deux branché en parallele.
passage sur 1er (nbr impulsion impair) puis passage sur 2nd (nbr impuls pair)

je trouvai ça plus simple pour que cela fonctionne dans les deux sens de passage.
mais pas si simple que ça!

bof, tu l'as inclue, mais pas utilisée, donc peu importe

l’intérêt de la librairie, c'est d’éviter de se prendre la tête avec un switch/case et des temporisations, puisque c'est géré en interne.

je n arrive pas à inclure la tempo sans mettre tout le systeme en pause.

je modifie pour les 4 etats dans énum.

donc je peux enlever le comptage d'impulsion?