Remplissage automatique

Bonjour à tous,
Voici mon nouveau projet (pour un réseau de train de jardin. (posté également sur locoduino..).
Je souhaiterais faire une entreprise de chargement de produits chimiques (en vrai de l'eau pour arroser les plantes du réseau)

En gros : le feu est au vert, le train arrive sous le chargeur, une pédale de voie est activée, au bout de deux secondes (pédale enfoncée), le feux passe au rouge, le chargeur rempli le wagon de produit pendant un temps donné, puis une fois la tempo écoulé, le feu repasse au vert, le train repart.

j'ai essayé des programmes toutes l'aprem en vain (je suis en vacances!) j'ai testé machine à états, delay, millis...
mais rien ne fonctionne!!

Le remplissage est assuré par un relais qui actionne une pompe à eau.

Je n'arrive pas à faire en sorte que l'action ne se fasse, que lorsque la pédale reste 2 secondes, (comme ça si le train ne fait que passer le remplissage ne ce fait pas!) je reviens toujours à mon programme de base :

//déclaration des variables
int pinBouton;
int pinLed1, pinLed2;

void setup() {
// definition mode relais
  pinMode(13, OUTPUT);

    //initialisation des variables
  pinBouton = 2;
  pinLed1 = 4;
  pinLed2 = 6;
  
  //définition des modes
  pinMode(pinBouton, INPUT); //mode lecture pour le bouton
  pinMode(pinLed1, OUTPUT); //mode écriture pour led1
  pinMode(pinLed2, OUTPUT); //mode écriture pour led2
  
}
void loop() {
   //lecture de l'état du bouton et stockage dans etatBouton
  boolean etatBouton = digitalRead(pinBouton);
  //test des conditions
  if (etatBouton==HIGH && ????)//test si bouton appuyé
  {
remplissage ();

  }
  if (etatBouton==LOW)//test si bouton levé
  {
    digitalWrite(pinLed1,HIGH); //Led1 allumée
    digitalWrite(pinLed2,LOW); //led2 éteinte
    digitalWrite(13, HIGH); //Relais sur OFF
  }
  delay(100); //petite attente
  
  
  
       
}

void remplissage ()
{
  digitalWrite(pinLed1,LOW); //led1 éteinte
    digitalWrite(pinLed2,HIGH); //led2 allumée
    delay (2000); //atternte de 2 secondes pour etre sur que le train ne bouge plus
    digitalWrite(13, LOW);//relais sur ON
    delay (10000);
    digitalWrite(pinLed1,HIGH); //Led1 allumée
    digitalWrite(pinLed2,LOW); //led2 éteinte

}

  //digitalWrite(13, HIGH);

Pour le temps d'attente, j'ai trouvé ça qui fonctionne et que je pourrais intégrer à mon code mais je pense pouvoir faire plus simple..

int temps_defini = 2000;   
int ledPin     = 4;       
int boutonPin  = 2;      

unsigned long debut_appui;
boolean variable = false;
int etat_bouton;
int dernier_etat_bouton = LOW;
int etat_led = LOW;

void setup() {
pinMode(ledPin, OUTPUT);      
pinMode(boutonPin, INPUT);    
}



void loop(){
  
   etat_bouton = digitalRead(boutonPin);            
  
   
   
   if (etat_bouton == HIGH && dernier_etat_bouton == LOW){      
   debut_appui = millis();                                      
   variable = true;                                           
   }
   
   
   if ( variable == true && etat_bouton == HIGH &&  dernier_etat_bouton == HIGH){    
                                                                                  
     if ((millis() - debut_appui) >= temps_defini){                                             
     etat_led = HIGH;                                                          
     
     if(etat_bouton == LOW && etat_led == HIGH && dernier_etat_bouton == HIGH){
     etat_led = LOW;
     variable = true;}}
                          
}
dernier_etat_bouton = etat_bouton;  
digitalWrite(ledPin, etat_led);
}

Le summum serait d'arrêter le remplissage si le train part avant la fin, mais c'est pas ma priorité...

Des pistes, un conseil? d'avance merci à vous et bonne soirée.

Peyo

J'ai du mal à comprendre.
La pédale dont tu parles correspond au bouton dans ton code ? Reste t-il enfoncé pendant le remplissage ou bien est il juste enfoncé puis relâché avant que le remplissage commence ?
Quelle led est verte, quelle est rouge (4 ou 6)?

Je tense que ton problème se prête bien à une machine à états. Il faut juste que tu le définisses bien précisément, par exemple avec un graphe d'états.

Ensuite, tu fais le code soit avec une bibliothèque ad-hoc soit en codant selon ton graphe.

Merci pour ta réponse,

Oui le train arrive et s'arrête sur la pédale (il est radiocommandé), tout fonctionne si et seulement si le train reste sur la pédale.
la pédale correspond effectivement à un bouton poussoir.

led verte : pin 4 (poste de remplissage libre)
led rouge : pin 6 (poste de remplissage occupé)

Tu as raison, ça me parait simple mais je vais quand même me faire un grafcet.

Merci en tous les cas.

Bonjour Peyodu5656

Tu as raison, ça me parait simple mais je vais quand même me faire un grafcet.

Cela me semble utile.

Dans le deuxième exemple, il me semble qu'il ne se passe pas grand chose si le bouton redescend.

Cordialement,
bidouilleelec

Voici mon grafcet :

il manque une étape dans ton grafcet : attendre que le train reparte après la fin du remplissage. sinon là si le train ne repart pas avant 2s, te relance un remplissage... débordement assuré

Ok, c'est plus clair. Tu dois surveiller le bouton, dès qu'il est enfoncé, tu lances un chrono et tu fais les actions sur les leds et la pompe en fonction de l'état du bouton et du temps écoulé sur le chrono.

As tu besoin d'aide ?

Ce type de problème correspond exactement à une machine à états !

Je te conseille de lire l’excellent tuto de JML sur la question

Et sinon, voila un code qui devrait fonctionner, et être facile à comprendre et à modifier
Pour que ça compile il faut installer la librairie YASM (disponible directement dans le gestionnaire de librairies, juste la sélectionner dans la liste et cliquer sur “installer” )

//broches de l'arduino utilisées
#define pinPedale   2
#define pinLedRouge 4
#define pinLedVerte 6
#define pinRelais   13

//délais (en ms)
#define tempoActive       2000
#define tempoRemplissage  10000

//inclusion de la librairies de machines à états YASM
#include <yasm.h>

//déclaration de la machines à états "pompe"
YASM pompe;

void setup()
{
  // paramétrage des broches d'entrées
  pinMode(pinPedale, INPUT);

  // paramétrage des broches de sorties
  pinMode(pinRelais, OUTPUT);
  pinMode(pinLedRouge, OUTPUT);
  pinMode(pinLedVerte, OUTPUT);

  //lancement de la machine à états : definition de l'état initial
  pompe.next(pompeAttente);
}

void loop()
{
  //execution de la machine à états
  pompe.run();
}

/////////////états de la machine "pompe" /////////////////////

void pompeAttente()
{
  //on attends le train (meuhhh ! )
  
  digitalWrite(pinLedRouge, LOW);
  digitalWrite(pinLedVerte, HIGH);
  digitalWrite(pinRelais, LOW);

  //si le train est sur la pédale, on passe à l'étape suivante
  if (digitalRead(pinPedale) == HIGH)
    pompe.next(pompeTempoActivation);
}

void pompeTempoActivation()
{
  //ici le train est sur la pédale
  
  digitalWrite(pinLedRouge, HIGH);
  digitalWrite(pinLedVerte, LOW);
  digitalWrite(pinRelais, LOW);

  //si le train quitte la pédale, on retourne en attente
  if (digitalRead(pinPedale) == LOW)
    pompe.next(pompeAttente);

  //et si le temps d'activation est écoulé, on passe à l'état suivant (remplissage)
  if (pompe.elapsed(tempoActive))
    pompe.next(pompeRemplissage);
}

void pompeRemplissage()
{
  //ici on remplit la citerne
  
  digitalWrite(pinLedRouge, HIGH);
  digitalWrite(pinLedVerte, LOW);
  digitalWrite(pinRelais, HIGH);

  //si le train quitte la pédale, on retourne en attente
  if (digitalRead(pinPedale) == LOW)
    pompe.next(pompeAttente);

  //et si le temps de remplissage est écoulé, on passe à l'état suivant (attente départ train)
  if (pompe.elapsed(tempoRemplissage))
    pompe.next(pompeAttenteDepart);
}

void pompeAttenteDepart()
{
  //la citerne est pleine, on attends le départ du train
  
  digitalWrite(pinLedRouge, HIGH);
  digitalWrite(pinLedVerte, LOW);
  digitalWrite(pinRelais, LOW);

  //si le train quitte la pédale, on retourne en attente
  if (digitalRead(pinPedale) == LOW)
    pompe.next(pompeAttente);
}

Salut les gars et merci pour vos réponses,
Je suis en train de me casser la tête avec ça : mais ça ne fonctionne pas, je sais pourquoi mais je ne sais pas comment y remédier..

//déclaration des variables
int pinBouton;
int pinLed1, pinLed2;
int tempopedale;
 //tableau états de la pédale de voie
 
enum {pedaleON, pedaleOFF} etatpedale;

unsigned long dateDernierChangement = 0;
 

///////////////////////////////////////////////////////////////////
void setup() {
  
//initialisation des variables
  pinBouton = 2;
  pinLed1 = 4;
  pinLed2 = 6;
  
  tempopedale = LOW;
  
  // definition mode relais
  pinMode(13, OUTPUT);
  //définition des modes bouton et leds
  pinMode(pinBouton, INPUT); //mode lecture pour le bouton
  pinMode(pinLed1, OUTPUT); //mode écriture pour led1
  pinMode(pinLed2, OUTPUT); //mode écriture pour led2
  
  //initialisation de l'état de la pédale de voie
  etatpedale = pedaleOFF;
  
  //initialisation des leds et du relai de puissance
   digitalWrite(pinLed1,HIGH); //Led1 allumée
   digitalWrite(pinLed2,LOW); //led2 éteinte
   digitalWrite(13, HIGH); //Relais sur OFF
  
}

/////////////////////////////////////////////////////////////////////
void loop() {

   //lecture de l'état du bouton et stockage dans etatBouton
  boolean etatBouton = digitalRead(pinBouton);
  
  //test des positions de la pédale de voie
  if (etatBouton==HIGH)//test si pédale appuyé
  {etatpedale = pedaleON;
  }
 if (etatBouton==LOW)//test si pédale levé
  {etatpedale = pedaleOFF;}
  
      if (etatBouton == HIGH && etatpedale==pedaleON){
        // definition de la fonction millis
              unsigned long dateCourante = millis();
              unsigned long intervalle = dateCourante - dateDernierChangement;
      
          if (etatpedale == pedaleON && intervalle >2000){
              tempopedale = HIGH;
               dateDernierChangement = dateCourante;
                }}
           
                      
  
  if (etatpedale == pedaleON && tempopedale == HIGH)
  {remplissage ();}
  
if (etatpedale == pedaleON)
    { digitalWrite(pinLed1,LOW); //Led1 allumée
   digitalWrite(pinLed2,HIGH); //led2 éteinte
   }
if (etatpedale == pedaleOFF)
   {   digitalWrite(pinLed1,HIGH); //Led1 allumée
   digitalWrite(pinLed2,LOW); //led2 éteinte
   }
}
/////////////////////////////////////////////////////////////////
void remplissage (){
   { digitalWrite(13, LOW);}//relais sur ON
   delay (5000);
   digitalWrite(13, HIGH);
}

Bref je mets de coté ce code et vais me pencher sur le code de Bricofoy !!!! un grand merci pour la piste :slight_smile:
peyo

Bricofoy : t'es un GÉNIE !!!!!!!

Ton code est simple à comprendre, après quelques modifs il fonctionne exactement comme je le souhaite !!!!
merci infiniment !!!!!

Je modifie encore quelques trucs puis je le publie pour d'autres.

Merci encore !!

Voilà, j’ai modifié le programme pour répondre parfaitement à mes attentes :
Mon relais est actif en LOW et non en HIGH… va savoir!
J’ai ajouté une led orange pour signaler au train qu’il peut partir, le remplissage est fini.

pour le reste, je n’ai rien touché. Merci une nouvelle fois à Bricofoy pour son sacré coup de pouce !!

//broches de l'arduino utilisées
#define pinPedale   2
#define pinLedRouge 4
#define pinLedOrange 5
#define pinLedVerte 6
#define pinRelais   13

//délais (en ms)
#define tempoActive       2000
#define tempoRemplissage  10000

//inclusion de la librairies de machines à états YASM
#include <yasm.h>

//déclaration de la machines à états "pompe"
YASM pompe;

void setup()
{
  // paramétrage des broches d'entrées
  pinMode(pinPedale, INPUT);

  // paramétrage des broches de sorties
  pinMode(pinRelais, OUTPUT);
  pinMode(pinLedRouge, OUTPUT);
  pinMode(pinLedOrange, OUTPUT);
  pinMode(pinLedVerte, OUTPUT);

  //lancement de la machine à états : definition de l'état initial
  pompe.next(pompeAttente);
}

void loop()
{
  //execution de la machine à états
  pompe.run();
}

/////////////états de la machine "pompe" /////////////////////

void pompeAttente()
{
  //on attends le train (meuhhh ! )
  
  digitalWrite(pinLedRouge, LOW);
  digitalWrite(pinLedVerte, HIGH);
  digitalWrite(pinLedOrange, LOW);
  digitalWrite(pinRelais, HIGH);

  //si le train est sur la pédale, on passe à l'étape suivante
  if (digitalRead(pinPedale) == HIGH)
    pompe.next(pompeTempoActivation);
}

void pompeTempoActivation()
{
  //ici le train est sur la pédale
  
  digitalWrite(pinLedRouge, HIGH);
  digitalWrite(pinLedVerte, LOW);
  digitalWrite(pinLedOrange, LOW);
  digitalWrite(pinRelais, HIGH);

  //si le train quitte la pédale, on retourne en attente
  if (digitalRead(pinPedale) == LOW)
    pompe.next(pompeAttente);

  //et si le temps d'activation est écoulé, on passe à l'état suivant (remplissage)
  if (pompe.elapsed(tempoActive))
    pompe.next(pompeRemplissage);
}

void pompeRemplissage()
{
  //ici on remplit la citerne
  
  digitalWrite(pinLedRouge, HIGH);
  digitalWrite(pinLedVerte, LOW);
  digitalWrite(pinRelais, LOW);

  //si le train quitte la pédale, on retourne en attente
  if (digitalRead(pinPedale) == LOW)
    pompe.next(pompeAttente);

  //et si le temps de remplissage est écoulé, on passe à l'état suivant (attente départ train)
  if (pompe.elapsed(tempoRemplissage))
    pompe.next(pompeAttenteDepart);
}

void pompeAttenteDepart()
{
  //la citerne est pleine, on attends le départ du train
  
  digitalWrite(pinLedRouge, LOW);
  digitalWrite(pinLedOrange, HIGH);
  digitalWrite(pinLedVerte, LOW);
  digitalWrite(pinRelais, HIGH);

  //si le train quitte la pédale, on retourne en attente
  if (digitalRead(pinPedale) == LOW)
    pompe.next(pompeAttente);
}

Tchouoououououououo !!!

Alors voici la solution pour réaliser un chargeur automatique de produit lors de l'appui long sur un bouton

Dans mon cas, une pédale de voie pour un train, afin de remplir automatiquement les wagons.

pour le fonctionnement, CF grafcet fonctionnel.

le câblage :

Le grafcet :

Le code :

//broches de l'arduino utilisées
#define pinPedale   2
#define pinLedRouge 4
#define pinLedOrange 5
#define pinLedVerte 6
#define pinRelais   13

//délais (en ms)
#define tempoActive       2000
#define tempoRemplissage  10000

//inclusion de la librairies de machines à états YASM
#include <yasm.h>

//déclaration de la machines à états "pompe"
YASM pompe;

void setup()
{
  // paramétrage des broches d'entrées
  pinMode(pinPedale, INPUT);

  // paramétrage des broches de sorties
  pinMode(pinRelais, OUTPUT);
  pinMode(pinLedRouge, OUTPUT);
  pinMode(pinLedOrange, OUTPUT);
  pinMode(pinLedVerte, OUTPUT);

  //lancement de la machine à états : definition de l'état initial
  pompe.next(pompeAttente);
}

void loop()
{
  //execution de la machine à états
  pompe.run();
}

/////////////états de la machine "pompe" /////////////////////

void pompeAttente()
{
  //on attends le train (meuhhh ! )
  
  digitalWrite(pinLedRouge, LOW);
  digitalWrite(pinLedVerte, HIGH);
  digitalWrite(pinLedOrange, LOW);
  digitalWrite(pinRelais, HIGH);

  //si le train est sur la pédale, on passe à l'étape suivante
  if (digitalRead(pinPedale) == HIGH)
    pompe.next(pompeTempoActivation);
}

void pompeTempoActivation()
{
  //ici le train est sur la pédale
  
  digitalWrite(pinLedRouge, HIGH);
  digitalWrite(pinLedVerte, LOW);
  digitalWrite(pinLedOrange, LOW);
  digitalWrite(pinRelais, HIGH);

  //si le train quitte la pédale, on retourne en attente
  if (digitalRead(pinPedale) == LOW)
    pompe.next(pompeAttente);

  //et si le temps d'activation est écoulé, on passe à l'état suivant (remplissage)
  if (pompe.elapsed(tempoActive))
    pompe.next(pompeRemplissage);
}

void pompeRemplissage()
{
  //ici on remplit la citerne
  
  digitalWrite(pinLedRouge, HIGH);
  digitalWrite(pinLedVerte, LOW);
  digitalWrite(pinRelais, LOW);

  //si le train quitte la pédale, on retourne en attente
  if (digitalRead(pinPedale) == LOW)
    pompe.next(pompeAttente);

  //et si le temps de remplissage est écoulé, on passe à l'état suivant (attente départ train)
  if (pompe.elapsed(tempoRemplissage))
    pompe.next(pompeAttenteDepart);
}

void pompeAttenteDepart()
{
  //la citerne est pleine, on attends le départ du train
  
  digitalWrite(pinLedRouge, LOW);
  digitalWrite(pinLedOrange, HIGH);
  digitalWrite(pinLedVerte, LOW);
  digitalWrite(pinRelais, HIGH);

  //si le train quitte la pédale, on retourne en attente
  if (digitalRead(pinPedale) == LOW)
    pompe.next(pompeAttente);
}

Voilà :slight_smile:

peyodu5656:
Bricofoy : t'es un GÉNIE !!!!!!!

au moins tout ça... disons plutôt que je programme assez régulièrement des automates, et comme faire des machines à états "à la main" à chaque fois, c'est relou,je me suis fait une lib qui va bien. C'est plus limité qu'une machine à états à base d'enums, mais dans bien des cas, ça suffit. Et le code est plus facile à lire/modifier, ce qui ne gâche rien.

Je te conseille de lire la doc complète de la librairie(en anglais) ou encore sa traduction partielle pour voir en détail comment l'utiliser, pour automatiser des trucs dans du modélisme, ça risquera de te resservir :wink: Pour des feux ou des passages à niveaux, par exemple. Note qu'il est parfaitement possible de créer une (ou plusieurs) autre machine à états et de la faire executer en parallèle à celle qui gère la pompe,le même arduino peut ainsi gérer tout ton réseau.

En tout cas, champagne ! c'est la première fois il me semble que ma librairie est utilisée par un autre que moi :slight_smile:

Ceci dit,c'est quand même bien de savoir faire une machine à états "à la main"pour bien saisir comment ça fonctionne. Dans ton essai, l'enum ne sert à rien : un simple booléen suffit pour stocker l'état d'un bouton, et en plus tu le fais aussi ! Et puis pourquoi le stocker alors que tu peux juste... le lire :stuck_out_tongue: C'est l'état de la machine (de l'enum)qui doit te donner la mémoire du bouton, une variable séparée n'est pas utile.
L'énum aurait donc du contenir les étapes du grafet, et ensuite, bah le code devrait peu ou prou ressembler au mien, avec un switch case contenant les conditions et les actions à faire dans chaque état (au lieu des fonctions séparées dans mon cas) et sauf aussi qu'il faut faire les temporisations avec millis à la main également dans chaque état ou c'est nécessaire.