LOCODUINO
Parlons Arduino => Débuter => Discussion démarrée par: jojo 77 le mars 17, 2019, 05:36:52 pm
-
Bonjour,
Première réalisation de programme avec Arduino, je bute sur un petit problème.
Il s'agit d'un passage à niveau sans feux clignotant (juste les barrières) détecté par un ILS pour l'ouverture, la fermeture s'effectuant au bout d'une temporisation.
Seulement, lorsque le train arrive sur le capteur, il se passe un certain temps avant que les barrières se ferment, de ce fait elles sont complètement fermées quand le train commence à quitter le pn. Que dois-je changer sur le programme ?
Sinon elles se referment bien au bout de la tempo
Voici le programme
/*
Gestion d'un passage à niveau avec 2 capteurs ILS.
Bibliothèques utilisées :
- SlowMotionServo pour les barrières
- LightDimmer pour le clignotement du feu du PN
*/
#include <Servo.h>
#include <SlowMotionServo.h>
/*
* Décommentez la ligne ci-dessous pour avoir l'affichage
* de l'état courant de l'automate sur les broches 8 à 12
*/
// #define AVEC_AFFICHAGE_ETAT
/*-------------------------------------------------------------------*/
/* Les états possible pour le PN */
enum { PN_OUVERT, PN_SE_FERME, PN_FERME, PN_TEMPO, PN_S_OUVRE };
/*-------------------------------------------------------------------*/
/* Les pin des capteurs et les informations renvoyées */
const byte capteurPin1 = 2;
const byte capteurPin2 = 6;
const byte trainPresent = LOW;
const byte trainAbsent = HIGH;
/*-------------------------------------------------------------------*/
/* Les pins des servos */
const byte barriere1Pin1 = 4;
const byte barriere2Pin1 = 5;
const byte barriere1Pin2 = 4;
const byte barriere2Pin2 = 5;
/* Les positions cibles des barrières */
const float positionOuverteBarriere1 = 0.0;
const float positionFermeeBarriere1 = 1.0;
const float positionOuverteBarriere2 = 0.0;
const float positionFermeeBarriere2 = 1.0;
/* Les servos */
SMSSmooth barriere1;
SMSSmooth barriere2;
/*-------------------------------------------------------------------*/
/* La temporisation entre la fin du train et l'ouverture des barrières
en ms
*/
const unsigned long temporisationOuverture = 3000;
#ifdef AVEC_AFFICHAGE_ETAT
const byte ledEtat = 8;
void initAffEtat()
{
for (byte i = ledEtat ; i < ledEtat + 5; i++) {
pinMode(i, OUTPUT);
digitalWrite(i, LOW);
}
}
void afficheEtat(const byte etat)
{
for (byte i = ledEtat ; i < ledEtat + etat; i++) {
digitalWrite(i, LOW);
}
for (byte i = ledEtat + etat + 1 ; i < ledEtat + 5; i++) {
digitalWrite(i, LOW);
}
digitalWrite(ledEtat + etat, HIGH);
}
#define INITAFFETAT() initAffEtat()
#define AFFICHEETAT(e) afficheEtat(e)
#else
#define INITAFFETAT()
#define AFFICHEETAT(e)
#endif
/*-------------------------------------------------------------------*/
/* Intialisations */
void setup()
{
/* capteur de présence */
pinMode(capteurPin1, INPUT_PULLUP);
pinMode(capteurPin2, INPUT_PULLUP);
/* les barrières */
barriere1.setPin(barriere1Pin1);
barriere1.setPin(barriere1Pin2);
barriere1.setSpeed(1.0);
barriere1.setInitialPosition(0.5);
barriere1.goTo(positionOuverteBarriere1);
barriere2.setPin(barriere2Pin1);
barriere2.setPin(barriere2Pin2);
barriere2.setSpeed(1.0);
barriere2.setInitialPosition(0.5);
barriere2.goTo(positionOuverteBarriere2);
INITAFFETAT();
}
/*-------------------------------------------------------------------*/
/* Contrôle du PN */
void loop()
{
static byte etatPN = PN_OUVERT;
static unsigned long dateOuverture;
/* Fait fonctionner les servos */
SlowMotionServo::update();
AFFICHEETAT(etatPN);
switch (etatPN)
{
case PN_OUVERT:
/* lecture du capteur pour détecter un train */
if (digitalRead(capteurPin1) == trainPresent || digitalRead(capteurPin2) == trainPresent) {
/* train présent */
/* On ferme les barrière */
barriere1.goTo(positionFermeeBarriere1);
barriere2.goTo(positionFermeeBarriere2);
/* Le PN est en train de se fermer */
etatPN = PN_SE_FERME;
}
break;
case PN_SE_FERME:
/* Si les deux servos sont arrêtés, le PN a terminé de se fermer */
if (barriere1.isStopped() && barriere2.isStopped()) {
etatPN = PN_FERME;
}
break;
case PN_FERME:
/* lecture du capteur pour détecter le départ du train */
if (digitalRead(capteurPin1) == trainAbsent && digitalRead(capteurPin2) == trainAbsent) {
dateOuverture = millis() + temporisationOuverture;
etatPN = PN_TEMPO;
}
break;
case PN_TEMPO:
/* Un train est présent, on retourne à l'état PN_FERME */
if (digitalRead(capteurPin1) == trainPresent || digitalRead(capteurPin2) == trainPresent){
etatPN = PN_FERME;
}
else {
/* Si la date est arrivée, on ouvre */
if (millis() >= dateOuverture) {
/* On ouvre les barrière */
barriere1.goTo(positionOuverteBarriere1);
barriere2.goTo(positionOuverteBarriere2);
etatPN = PN_S_OUVRE;
}
}
break;
case PN_S_OUVRE:
/* Un train est présent, on retourne à l'état PN_SE_FERME et on ferme la barrière */
if (digitalRead(capteurPin1) == trainPresent || digitalRead(capteurPin2) == trainPresent) {
barriere1.goTo(positionFermeeBarriere1);
barriere2.goTo(positionFermeeBarriere2);
etatPN = PN_SE_FERME;
}
else {
/* Si les deux servos sont arrêtés, le PN a terminé de s'ouvrir */
if (barriere1.isStopped() && barriere2.isStopped()) {
etatPN = PN_OUVERT;
}
}
break;
default:
/* normalement impossible */
break;
}
}
Merci pour vos réponses
-
Je ne vois à priori pas de problème.
Il faut prendre les choses dans l'ordre et ajouter des Serial.print() pour comprendre, tester que les capteurs renvoient bien ce qu'il faut, que l'on passe bien par les endroit attendus.
-
Bonjour,
Merci pour cette réponse.
Seulement je suis novice. De plus je ne comprends pas l'anglais.
J'ai effectué une recherche sur le site d'Arduino pour comprendre Sérial.print() et j'ai tenté une traduction mais je n'ai pas compris où placer cette commande dans le programme.
Cordialement.
-
Dans un premier temps, avez vous vérifié que vos ILS fonctionnent comme il faut ?
-
Oui, je l'ai vérifié, ils fonctionnent correctement.
Merci pour votre aide.
-
le premier truc à verifier est le changement d'état de PN_OUVERT à PN_SE_FERME s'effectue (ajout d'un print) :
case PN_OUVERT:
/* lecture du capteur pour détecter un train */
if (digitalRead(capteurPin1) == trainPresent || digitalRead(capteurPin2) == trainPresent) {
/* train présent */
Serial.println("detection !"); /* Mettre un Serial.begin(9600); */
/* On ferme les barrière */
barriere1.goTo(positionFermeeBarriere1);
barriere2.goTo(positionFermeeBarriere2);
/* Le PN est en train de se fermer */
etatPN = PN_SE_FERME;
}
break;
-
Merci encore !
Je dois m'absenter mais j'essaierai ce soir et je vous tiens au courant.
Cordialement
-
Bonjour,
Peut-être devrais-tu tracer le graphe de la machine d'états ce qui permettrait de mieux suivre ?
J'ai une question au sujet des 2 états suivants:
case PN_OUVERT:
/* lecture du capteur pour détecter un train */
if (digitalRead(capteurPin1) == trainPresent || digitalRead(capteurPin2) == trainPresent) {
/* train présent */
/* On ferme les barrière */
barriere1.goTo(positionFermeeBarriere1);
barriere2.goTo(positionFermeeBarriere2);
/* Le PN est en train de se fermer */
etatPN = PN_SE_FERME;
}
break;
case PN_SE_FERME:
/* Si les deux servos sont arrêtés, le PN a terminé de se fermer */
if (barriere1.isStopped() && barriere2.isStopped()) {
etatPN = PN_FERME;
}
break;
Dans l'état PN_SE_FERME, on teste si les servos sont arrêtés et on en déduit que la fermeture est terminée. Cela suppose que suite aux 2 appels goTo de l'état PN_OUVERT, le mouvement des barrières a effectivement commencé. J'imagine que l'appel à SlowMotionServo::update();, avant le switch sur les états assure cela. Sinon, on passe directement à l'état PN_FERME où on teste à nouveau les ILS. Ce test surviendrait beaucoup trop tôt par rapport au précédent et on aurait un problème de rebond.
Comme déjà évoqué par Jean-Luc, il peut être bien d'afficher sur la ligne série, par exemple l'entrée dans l'état PN_SE_FERME, à généraliser pour tous les changements d'état:
#define DEBUG
...
void setup (void)
{
...
#ifdef DEBUG
Serial.begin (9600);
#endif
...
}
void loop (void)
{
...
case PN_OUVERT:
...
etatPN = PN_SE_FERME;
#ifdef DEBUG
Serial.print (millis (), DEC);
Serial.println (" -- PN_SE_FERME");
#endif
...
break;
...
}
Dans l'IDE Arduino, la combinaison de touches Ctrl-Shift-M ouvre le terminal de la ligne série. Avec le format de trace proposé, tu peux voir à quel moment la transition est effectuée.
Bonne suite.
-
Bonjour Marc-Henri
Peut-être devrais-tu tracer le graphe de la machine d'états ce qui permettrait de mieux suivre ?
Ce sketch est celui de mon article : http://www.locoduino.org/spip.php?article25
-
...
Ce sketch est celui de mon article : http://www.locoduino.org/spip.php?article25
Merci Jean-Luc pour cette précision.
Je n'avais pas pensé au copier-coller, en soit tout à fait légitime, mais passé allègrement sous silence par Jojo 77. La moindre des choses aurait été de mentionner qu'il avait repris ce sketch de Locoduino.
Du coup ma question sur les 2 états dans mon message précédent tombe partiellement. Le fonctionnement de SlowMotionServo::update(); ne doit donc pas poser de problème. En revanche, je me demande si on ne devrait pas tout de même tenir compte d'éventuels rebonds sur les ILS.
Bon début de semaine.
-
Bonsoir,
J'ai en effet omis d'indiquer que j'avais repris le sketch de Jean-Luc qui m'a bien conseillé et je vous prie de m'en excuser.
Avant d'ouvrir cette nouvelle discussion, j'avais répondu au bas de la rubrique "Comment concevoir rationnellement votre système" pour expliquer mon problème.
Je ne l'ai peut-être pas fait au bon endroit.
En tout cas, merci à vous deux de votre patience car je ne suis pas très doué.
Je vais donc essayer vos conseils ce soir. Je vous tiendrais au courant des résultats demain.
Bonne soirée !
Cordialement
-
Bonjour,
Je n'ai pas eu le réflexe d'aller consulter le site éditorial et n'ai donc pas vu ta 1ère question. :)
Tiens-nous au courant des résultats de tes investigations.
Bonne suite et meilleures salutations.
-
Bonjour,
Nouveaux essais après modifications du sketch. Ajout d'un Serial.println.
La locomotive passe sur le capteur, la barrière se ferme une fois que le train à dépassé le pn.
Je vois donc deux réponses : soit agir sur la rapidité de fermeture de la barrière, soit, ce qui est pour moi le plus probable, j'aurais placé mes capteurs trop près du pn.
Qu'en pensez-vous ?
Cordialement
-
... soit, ce qui est pour moi le plus probable, j'aurais placé mes capteurs trop près du pn...
Sur mon réseau en N, la détection de part et d'autre du PN se situe à ~80 cm. À l'échelle H0, cela correspondrait à ~147 cm. Cette longueur permet:- de faire clignoter les signaux avant de commencer à fermer les barrières;
- de commencer à fermer les barrières avant que le train n'arrive au PN;
- la durée de fermeture / ouverture des barrières est de 2.7 secondes. C'est calculé comme suit:
- Position min servo: 1000 (impulsion de 1 ms, valeur pour le timer 16 bits)
- Position max servo: 1900 (impulsion de 1.9 ms, valeur pour le timer 16 bits)
- Différence: 900
- Incrément / décrément servo: 20
- Intervalle de temps entre chaque mise à jour servo: 60 ms
- Durée fermeture / ouverture: 900 / 20 * 60 ms = 2.7 sec
Même avec cette distance et cette durée, on s'approche de la réalité, mais c'est encore trop court.
Cf le sujet sur mon PN sur le forum du N:- http://le-forum-du-n.forumotions.net/t12790-pn-actionne-par-servo-moteurs-electronique (http://le-forum-du-n.forumotions.net/t12790-pn-actionne-par-servo-moteurs-electronique), contient notamment le programme pour Attiny 2313.
- http://le-forum-du-n.forumotions.net/t10919-commande-de-pn-1er-essai (http://le-forum-du-n.forumotions.net/t10919-commande-de-pn-1er-essai), contient les schémas électroniques (devrait aussi être dans le 1er sujet).
- http://le-forum-du-n.forumotions.net/t12789-pn-actionne-par-servo-moteurs-montage-et-mecanique (http://le-forum-du-n.forumotions.net/t12789-pn-actionne-par-servo-moteurs-montage-et-mecanique)
Bonne réalisation et meilleures salutations.
-
En effet, selon votre message, mes capteurs sont placés beaucoup trop près du pn.
Je vais donc les déplacer.
Je pense faire cela ce week-end à moins que je trouve le temps avant.
De toutes façons je vous tiens au courant.
Cordialement
-
Bonsoir,
J'ai déplacé mes capteurs et il y a du mieux. Les barrières sont totalement baissées juste avant l'arrivée du train, mais il faut pour cela qu'il n'aille pas trop vite.
Je ne peux pas allonger la distance des capteurs car la voie plus loin est sous un tunnel. N'est-il pas possible que les barrières se baissent plus vite même si cela enlève un peu de réalisme ?
Cordialement.
-
Bonjour,
Ben si, c'est le rôle de setSpeed. Il faut mettre une valeur plus élevée
-
Bonjour,
En mettant une valeur plus élevée à setSpeed, le résultat est acceptable. Je mets donc ce post en résolu.
Merci à tous pour votre aide.
Cordialement;
-
Au début j’avais compris que le programme avait un bug et que entre l’instant de détection de la présence du train et l’instant de démarrage du mouvement des barrières, il s’écoulait du temps.
J’ai fini par comprendre que ce délai dont tu parlais était en fait l’intervalle de temps entre la détection et le moment où les barrières sont fermées et le fait qu’elles soient fermées au moment du passage du train. Délai qui dépend de la vitesse du train, de la distance entre le passage à niveau et le capteur et de la vitesse du movement des barrières, donc majoritairement de l’installation et non du programme.
Content que tu aies réussi à faire une installation acceptable.
-
« Garçon ! Un café s’il vous plaît. ». Non, ça ne marche pas comme ça.
Bonjour,
puisqu'il n'est possible de faire immédiatement une automatisation complète de passage à niveau, je m'oriente vers l'acquisition d'un équipement comme sur la photo jointe pour résoudre le problème soulevé par Jean-Luc. Mais je n'ai pas trouvé d'article pour sa mise œuvre : est-ce prévu dans un proche avenir ?
Il est clair que cela ne peut qu'aider les cogitations dans le domaine ferroviaire !
Cordialement