| | Piloter un relais bistable avec Arduino | |
|
+5class66 cambouis19 jlb tking-1007 VAUBAN38 9 participants | |
Auteur | Message |
---|
SavignyExpress Membre
Age : 61 Localisation : yyy Nombre de messages : 2032 Date d'inscription : 10/10/2010
| Sujet: Re: Piloter un relais bistable avec Arduino Dim 19 Jan 2014, 13:15 | |
| Bonjour à tous, Je confirme qu'une durée de 100 ms au moins est nécessaire pour actionner un électro-aimant d'aiguille à l'aide d'un relais piloté par micro-contrôleur. Le système qui gère ma gare utilise 100 ms. Pour la gare du réseau de Jappy, c'est pour l'instant fixé à 200 ms, mais nous verrons lors des tests sur le réseau si on peut revenir à 100 ms. @JLB: Une question / remarque de programmation. Le fait de déclarer const devant tes tableaux évite qu'ils soient accidentellement modifiés, mais les tableaux restent en RAM. La RAM étant comptée sur la plupart des micro-contrôleurs, il vaut mieux placer les tableaux de constantes en mémoire programme, plus grande, à l'aide de la directive PROGMEM, puis utiliser la librairie de même nom pour y accéder. C'est faisable aussi bien en C standard qu'avec l'Arduino: http://arduino.cc/en/Reference/PROGMEMJ'ai utilisé ce principe pour la gare de Jappy dont le programme comprend plusieurs tables définissant les relais à activer en fonction de l'état. La description détaillée sera prochainement sur mon blog. Bon dimanche et belles réalisations. |
| | | VAUBAN38 Membre
Age : 72 Localisation : GRENOBLE Nombre de messages : 501 Date d'inscription : 04/02/2012
| Sujet: Re: Piloter un relais bistable avec Arduino Lun 20 Jan 2014, 10:47 | |
| Bonjour, Bon j'ai essayé d'avancer avec les éléments communiqués hier matin, mais si je capte bien le but recherché et les sécurités mises en place, j'avoue que dès qu'il s'agit de "jongler" avec les automates et les notions de garde, transition, etc... et d'incorporer tout çà dans le code existant, çà s'embrouille plus que sérieusement dans ma tête, et là JE CALE ! Par ailleurs sur un aspect purement matériel, comment connecter le poussoir ? Faut-il s'inspirer du schéma de ton article "Commande du servo-moteur par bouton poussoir" pour le câblage ? CA Y'EST ...... C'EST LA PANNE SECHE !! |
| | | jlb Membre
Age : 60 Localisation : Ici Nombre de messages : 1543 Date d'inscription : 31/12/2011
| Sujet: Re: Piloter un relais bistable avec Arduino Lun 20 Jan 2014, 15:56 | |
| Bonjour, Commençons par le poussoir. Dans « Commande du servo-moteur par bouton poussoir » il s'agit d'un clavier analogique. Là on a juste un seul bouton. Donc on va le brancher sur un entrée numérique. Supposons que le poussoir soit connecté comme ceci sur la broche pinPoussoir La résistance de tirage est incluse dans l'Arduino. Pour l'activer il suffit de faire dans setup() : - Citation :
pinMode(pinPoussoir, INPUT); digitalWrite(pinPoussoir, HIGH);
Tout d'abord, il faut régler le problème du rebond. Quand on appuie sur le bouton on n'a pas un beau signal comme ceci : Mais quelque chose comme ça : Si on ne prend pas de précaution, le logiciel voit plusieurs pressions alors qu'il n'y en a qu'une. Pour gommer le rebond, on va utiliser un automate À l'état de repos, l'automate est dans l'état RELACHE Si le poussoir est enfoncé, on passe dans l'état ENFONCE_REBOND, état intermédiaire permettant d'absorber le rebond. Si 10ms plus tard (je rappelle que le tick est à 10ms) le poussoir est toujours enfoncé, on passe dans l'état ENFONCE. Voilà l'anti-rebond, on a laissé passer 10ms, le rebond est derrière nous. Sinon, on retourne dans l'état RELACHE. Les déclarations : - Citation :
const byte pinPoussoir = 10;
// les états de l'automate du poussoir enum { RELACHE, ENFONCE_REBOND, ENFONCE }; // La variable pour mémoriser l'état de l'automate byte etatPoussoir = RELACHE; // La variable pour mémoriser l'état du poussoir byte poussoir = RELACHE;
La gestion de cet automate : - Citation :
switch (etatPoussoir) { case RELACHE: if (digitalRead(pinPoussoir) == LOW) { etatPoussoir = ENFONCE_REBOND; } break; case ENFONCE_REBOND: if (digitalRead(pinPoussoir) == LOW) { etatPoussoir = ENFONCE; poussoir = ENFONCE; } else { etatPoussoir = RELACHE; } break; case ENFONCE: if (digitalRead(pinPoussoir) == HIGH) { etatPoussoir = RELACHE; poussoir = RELACHE; } break; }
Dans l'automate de détection de train, on va consulter la variable poussoir pour savoir si le bouton est enfoncé avec les conditions que j'avais expliquées auparavant. C'est à dire qu'il faut être dans l'état ATTENTE, que la gare avec qui on partage l'aiguille soit aussi dans l'état ATTENTE ( etatTrain[conjointDeGare[gare]] == ATTENTE ) et qu'il y ait un train dans la gare (c'est à dire que l'aiguille est positionné pour l'autre gare, ce qui correspond à ce que l'aiguille soit comme dans le tableau commandeDeGareAAiguille : ( etatAiguille[gare / 2] == commandeDeGareAAiguille[gare] ) et on va dans l'état ARRET Comme action, on positionne l'aiguille comme indiqué dans le tableau commandeDeGareAAiguilleArret et on remet la variable poussoir à RELACHE pour être sûr de ne faire tout ceci qu'une fois à chaque pression sur le poussoir : - Citation :
// tableau indexé par le numéro de gare qui donne la position de l'aiguille associée // pour la procédure d'arret const byte commandeDeGareAAiguilleArret[4] = {DROITE, DEVIEE, DROITE, DEVIEE};
Note que l'état ARRET est un état final de l'automate. Une fois là, plus rien ne se passe, il faut faire un reset. Pour bien faire, il faudrait un second poussoir pour remettre le système en mode normal si par exemple tu veux juste récupérer un train sans vraiment tout arrêter. Le programme complet (toujours non testé, donc aucune garantie de fonctionnement ) : - Citation :
// les états que l'automate de détection de train peut prendre enum { ATTENTE, WAGON, ATTELAGE, ARRET };
const int pinsCapteur[4] = {2, 3, 4, 5}; byte etatTrain[4] = {ATTENTE, ATTENTE, ATTENTE, ATTENTE}; byte compteur[4];
const unsigned long dureeAttelage = 50;
// les états que l'automate d'aiguille peut prendre enum { DEVIEE, DROITE, PULSE_DEVIEE, PULSE_DROITE };
byte etatAiguille[2] = {DROITE, DROITE}; byte compteurAiguille[2]; byte commandeAiguille[2] = {DROITE, DROITE};
// tableau permettant à une gare de connaitre la gare avec laquelle // elle partage l'aiguille const byte conjointDeGare[4] = { 1, 0, 3, 2 };
// tableau indexé par le numéro de gare qui donne la position de l'aiguille associée const byte commandeDeGareAAiguille[4] = {DEVIEE, DROITE, DEVIEE, DROITE};
// tableau indexé par le numéro de gare qui donne la position de l'aiguille associée // pour la procédure d'arret const byte commandeDeGareAAiguilleArret[4] = {DROITE, DEVIEE, DROITE, DEVIEE};
const byte pinDroite[2] = {6, 8}; const byte pinDeviee[2] = {7, 9};
const unsigned long dureeImpulsion = 10; // valeur arbitraire, à ajuster
const byte pinPoussoir = 10;
// les états de l'automate du poussoir enum { RELACHE, ENFONCE_REBOND, ENFONCE }; // La variable pour mémoriser l'état de l'automate byte etatPoussoir = RELACHE; // La variable pour mémoriser l'état du poussoir byte poussoir = RELACHE;
void setup() { pinMode(pinPoussoir, INPUT); digitalWrite(pinPoussoir, HIGH); int gare; for (gare = 0; gare < 4; gare++) { pinMode(pinsCapteur[gare], INPUT); } int aiguille; for (aiguille = 0; aiguille < 2; aiguille++) { // les deux pins de commande sont mises à LOW digitalWrite(pinDeviee[aiguille], LOW); digitalWrite(pinDroite[aiguille], LOW); // les deux pins de commande sont mises en sortie pinMode(pinDeviee[aiguille], OUTPUT); pinMode(pinDroite[aiguille], OUTPUT); // et on met une impulsion sur la commande droite // pour mettre l'aiguille en position initiale connue digitalWrite(pinDroite[aiguille], HIGH); delay(dureeImpulsion); digitalWrite(pinDroite[aiguille], LOW); } }
void loop() { int gare; for (gare = 0; gare < 4; gare++) { byte capteur = digitalRead(pinsCapteur[gare]); switch (etatTrain[gare]) { case ATTENTE: if (capteur == LOW) { etatTrain[gare] = WAGON; } else if (poussoir == ENFONCE && etatAiguille[gare / 2] == commandeDeGareAAiguille[gare] && etatTrain[conjointDeGare[gare]] == ATTENTE) { etatTrain[gare] = ARRET; commandeAiguille[gare / 2] = commandeDeGareAAiguilleArret[gare]; poussoir = RELACHE; } break; case WAGON: if (capteur == HIGH) { etatTrain[gare] = ATTELAGE; compteur[gare] = 0; } break; case ATTELAGE: if (capteur == LOW) { etatTrain[gare] = WAGON; } else { if (compteur[gare] < dureeAttelage) { compteur[gare]++; } else { etatTrain[gare] = ATTENTE; // commande l'aiguille associée pour sélectionner la gare associée commandeAiguille[gare / 2] = commandeDeGareAAiguille[gare]; } } break; } } int aiguille; for (aiguille = 0; aiguille < 2; aiguille++) { switch (etatAiguille[aiguille]) { case DEVIEE: if (commandeAiguille[aiguille] == DROITE) { // commande pour mettre l'aiguille DROITE compteurAiguille[aiguille] = 0; // commande pour mettre l'aiguille DROITE digitalWrite(pinDroite[aiguille], HIGH); // on va dans l'état PULSE_DROITE etatAiguille[aiguille] = PULSE_DROITE; } break; case DROITE: if (commandeAiguille[aiguille] == DEVIEE) { // commande pour mettre l'aiguille DEVIEE compteurAiguille[aiguille] = 0; // commande pour mettre l'aiguille DROITE digitalWrite(pinDeviee[aiguille], HIGH); // on va dans l'état PULSE_DEVIEE etatAiguille[aiguille] = PULSE_DEVIEE; } break; case PULSE_DEVIEE: if (compteurAiguille[aiguille] < dureeImpulsion) { // on reste dans PULSE_DEVIEE pendant dureeImpulsion ticks compteurAiguille[aiguille]++; } else { // transition vers l'état DEVIEE, on coupe le pulse digitalWrite(pinDeviee[aiguille], LOW); etatAiguille[aiguille] = DEVIEE; } break; case PULSE_DROITE: if (compteurAiguille[aiguille] < dureeImpulsion) { // on reste dans PULSE_DROITE pendant dureeImpulsion ticks compteurAiguille[aiguille]++; } else { // transition vers l'état DROITE, on coupe le pulse digitalWrite(pinDroite[aiguille], LOW); etatAiguille[aiguille] = DROITE; } break; } }
switch (etatPoussoir) { case RELACHE: if (digitalRead(pinPoussoir) == LOW) { etatPoussoir = ENFONCE_REBOND; } break; case ENFONCE_REBOND: if (digitalRead(pinPoussoir) == LOW) { etatPoussoir = ENFONCE; poussoir = ENFONCE; } else { etatPoussoir = RELACHE; } break; case ENFONCE: if (digitalRead(pinPoussoir) == HIGH) { etatPoussoir = RELACHE; poussoir = RELACHE; } break; } // attente de 10ms entre 2 analyses du système delay(10); }
|
| | | VAUBAN38 Membre
Age : 72 Localisation : GRENOBLE Nombre de messages : 501 Date d'inscription : 04/02/2012
| Sujet: Re: Piloter un relais bistable avec Arduino Lun 20 Jan 2014, 19:53 | |
| Bien, je n'ai pas cherché à comprendre tout çà immédiatement, car çà risque de prendre du temps Je me plongerai dedans demain ! En revanche j'ai mis immédiatement en test et çà fonctionne. Il faut par contre donner deux impulsions successives pour libérer les deux trains "prisonniers". La première libérant indifféremment les deux quais de la gare voie extérieure, et la deuxième impulsion libérant ceux de la voie intérieure. Comme tu l'indiquais, l'utilisation du forçage neutralise le fonctionnement de l'automate. Les IR continuent à détecter mais il n'y a plus d'action sur aiguillage et relais. Seul un reset rétablit le fonctionnement. En revanche avec une seule impulsion, la voie externe est libérée et son automate neutralisé. La voie interne continuant à fonctionner normalement. Est-ce que cela correspond à ce que tu avais prévu ? L |
| | | jlb Membre
Age : 60 Localisation : Ici Nombre de messages : 1543 Date d'inscription : 31/12/2011
| Sujet: Re: Piloter un relais bistable avec Arduino Lun 20 Jan 2014, 20:05 | |
| À moitié Le premier automate qui remet la variable poussoir a RELACHE gagne et inhibe l'autre. D'où la nécessité des deux pressions. Pour libérer les deux trains, il faut changer un peu la logique de fonctionnement. poussoir devient un nombre de train à libérer. La pression sur la bouton met poussoir à 2. Chaque automate le décrémente. La garde sur la transition devient : poussoir > 0 Donc à l'init : - Citation :
// La variable pour mémoriser l'état du poussoir byte poussoir = 0;
Le traitement de l'état ATTENTE de l'automate de détection : - Citation :
case ATTENTE: if (capteur == LOW) { etatTrain[gare] = WAGON; } else if (poussoir > 0 && etatAiguille[gare / 2] == commandeDeGareAAiguille[gare] && etatTrain[conjointDeGare[gare]] == ATTENTE) { etatTrain[gare] = ARRET; commandeAiguille[gare / 2] = commandeDeGareAAiguilleArret[gare]; poussoir--; } break;
L'automate du poussoir : - Citation :
switch (etatPoussoir) { case RELACHE: if (digitalRead(pinPoussoir) == LOW) { etatPoussoir = ENFONCE_REBOND; } break; case ENFONCE_REBOND: if (digitalRead(pinPoussoir) == LOW) { etatPoussoir = ENFONCE; poussoir = 2; } else { etatPoussoir = RELACHE; } break; case ENFONCE: if (digitalRead(pinPoussoir) == HIGH) { etatPoussoir = RELACHE; } break; }
De cette manière poussoir devient un nombre de jetons mis à 2. Chaque automate consomme un jeton et libère son train |
| | | VAUBAN38 Membre
Age : 72 Localisation : GRENOBLE Nombre de messages : 501 Date d'inscription : 04/02/2012
| Sujet: Re: Piloter un relais bistable avec Arduino Lun 20 Jan 2014, 21:57 | |
| Modifications implantées et çà marche NICKEL ! Une seule impulsion libère les deux trains. Ci-dessous le code complet actualisé, pour ceux qui voudraient le copier/coller : - Code:
-
// les états que l'automate de détection de train peut prendre enum { ATTENTE, WAGON, ATTELAGE, ARRET };
const int pinsCapteur[4] = {2, 3, 4, 5}; byte etatTrain[4] = {ATTENTE, ATTENTE, ATTENTE, ATTENTE}; byte compteur[4];
const unsigned long dureeAttelage = 50;
// les états que l'automate d'aiguille peut prendre enum { DEVIEE, DROITE, PULSE_DEVIEE, PULSE_DROITE };
byte etatAiguille[2] = {DROITE, DROITE}; byte compteurAiguille[2]; byte commandeAiguille[2] = {DROITE, DROITE};
// tableau permettant à une gare de connaitre la gare avec laquelle // elle partage l'aiguille const byte conjointDeGare[4] = { 1, 0, 3, 2 };
// tableau indexé par le numéro de gare qui donne la position de l'aiguille associée const byte commandeDeGareAAiguille[4] = {DEVIEE, DROITE, DEVIEE, DROITE};
// tableau indexé par le numéro de gare qui donne la position de l'aiguille associée // pour la procédure d'arret const byte commandeDeGareAAiguilleArret[4] = {DROITE, DEVIEE, DROITE, DEVIEE};
const byte pinDroite[2] = {6, 8}; const byte pinDeviee[2] = {7, 9};
const unsigned long dureeImpulsion = 10; // valeur arbitraire, à ajuster
const byte pinPoussoir = 10;
// les états de l'automate du poussoir enum { RELACHE, ENFONCE_REBOND, ENFONCE }; // La variable pour mémoriser l'état de l'automate byte etatPoussoir = RELACHE; // La variable pour mémoriser l'état du poussoir byte poussoir = 0;
void setup() { pinMode(pinPoussoir, INPUT); digitalWrite(pinPoussoir, HIGH); int gare; for (gare = 0; gare < 4; gare++) { pinMode(pinsCapteur[gare], INPUT); } int aiguille; for (aiguille = 0; aiguille < 2; aiguille++) { // les deux pins de commande sont mises à LOW digitalWrite(pinDeviee[aiguille], LOW); digitalWrite(pinDroite[aiguille], LOW); // les deux pins de commande sont mises en sortie pinMode(pinDeviee[aiguille], OUTPUT); pinMode(pinDroite[aiguille], OUTPUT); // et on met une impulsion sur la commande droite // pour mettre l'aiguille en position initiale connue digitalWrite(pinDroite[aiguille], HIGH); delay(dureeImpulsion); digitalWrite(pinDroite[aiguille], LOW); } }
void loop() { int gare; for (gare = 0; gare < 4; gare++) { byte capteur = digitalRead(pinsCapteur[gare]); switch (etatTrain[gare]) { case ATTENTE: if (capteur == LOW) { etatTrain[gare] = WAGON; } else if (poussoir > 0 && etatAiguille[gare / 2] == commandeDeGareAAiguille[gare] && etatTrain[conjointDeGare[gare]] == ATTENTE) { etatTrain[gare] = ARRET; commandeAiguille[gare / 2] = commandeDeGareAAiguilleArret[gare]; poussoir--; } break; case WAGON: if (capteur == HIGH) { etatTrain[gare] = ATTELAGE; compteur[gare] = 0; } break; case ATTELAGE: if (capteur == LOW) { etatTrain[gare] = WAGON; } else { if (compteur[gare] < dureeAttelage) { compteur[gare]++; } else { etatTrain[gare] = ATTENTE; // commande l'aiguille associée pour sélectionner la gare associée commandeAiguille[gare / 2] = commandeDeGareAAiguille[gare]; } } break; } } int aiguille; for (aiguille = 0; aiguille < 2; aiguille++) { switch (etatAiguille[aiguille]) { case DEVIEE: if (commandeAiguille[aiguille] == DROITE) { // commande pour mettre l'aiguille DROITE compteurAiguille[aiguille] = 0; // commande pour mettre l'aiguille DROITE digitalWrite(pinDroite[aiguille], HIGH); // on va dans l'état PULSE_DROITE etatAiguille[aiguille] = PULSE_DROITE; } break; case DROITE: if (commandeAiguille[aiguille] == DEVIEE) { // commande pour mettre l'aiguille DEVIEE compteurAiguille[aiguille] = 0; // commande pour mettre l'aiguille DROITE digitalWrite(pinDeviee[aiguille], HIGH); // on va dans l'état PULSE_DEVIEE etatAiguille[aiguille] = PULSE_DEVIEE; } break; case PULSE_DEVIEE: if (compteurAiguille[aiguille] < dureeImpulsion) { // on reste dans PULSE_DEVIEE pendant dureeImpulsion ticks compteurAiguille[aiguille]++; } else { // transition vers l'état DEVIEE, on coupe le pulse digitalWrite(pinDeviee[aiguille], LOW); etatAiguille[aiguille] = DEVIEE; } break; case PULSE_DROITE: if (compteurAiguille[aiguille] < dureeImpulsion) { // on reste dans PULSE_DROITE pendant dureeImpulsion ticks compteurAiguille[aiguille]++; } else { // transition vers l'état DROITE, on coupe le pulse digitalWrite(pinDroite[aiguille], LOW); etatAiguille[aiguille] = DROITE; } break; } }
switch (etatPoussoir) { case RELACHE: if (digitalRead(pinPoussoir) == LOW) { etatPoussoir = ENFONCE_REBOND; } break; case ENFONCE_REBOND: if (digitalRead(pinPoussoir) == LOW) { etatPoussoir = ENFONCE; poussoir = 2; } else { etatPoussoir = RELACHE; } break; case ENFONCE: if (digitalRead(pinPoussoir) == HIGH) { etatPoussoir = RELACHE; } break; } // attente de 10ms entre 2 analyses du système delay(10); }
Encore un grand MERCI à Jlb sans qui rien n'aurait été possible !!! Merci également à tous ceux qui m'ont prodigué avis, conseils et suggestions. C'est toute la richesse de ce super forum ! En espérant que d'autres pourront tirer de ce sujet l'envie de se lancer sur ce petit mais bel outil qu'est l'Arduino.
Pour ma part, je suis conquis !! Prochaine étape : gestion de ma raquette en automatique. Je vais essayer de me débrouiller tout seul ..... (c'est pas gagné, mais c'est comme çà qu'on apprend le mieux!) A minima une fois mes "élucubrations" finies je les soumettrai pour vérif (et sans doute optimisation,...... voir refonte totale !) Au pire je crierai à l'aide si je bloque . Donc à bientôt pour les suites de mes aventures sur Arduino |
| | | SavignyExpress Membre
Age : 61 Localisation : yyy Nombre de messages : 2032 Date d'inscription : 10/10/2010
| Sujet: Re: Piloter un relais bistable avec Arduino Lun 20 Jan 2014, 22:23 | |
| Bravo à Vauban38 pour avoir fait le pas de l'Arduino, tu progresses à pas de géant ! Bravo à Jlb pour ses explications toujours au top. Ils vont finir par t'engager chez LocoRevue pour continuer les articles sur l'Arduino. |
| | | VAUBAN38 Membre
Age : 72 Localisation : GRENOBLE Nombre de messages : 501 Date d'inscription : 04/02/2012
| Sujet: Re: Piloter un relais bistable avec Arduino Lun 20 Jan 2014, 22:50 | |
| - SavignyExpress a écrit:
- Bravo à Vauban38 pour avoir fait le pas de l'Arduino, tu progresses à pas de géant !
Merci de tes encouragements, mais si déjà j'arrive à progresser comme un des sept nains..... (on va éviter Grincheux et Simplet, Prof est déjà pris par Jlb .... il me reste que Joyeux et c'est déjà pas mal !!!) Et puis je resterai modeste, et pour plagier la phrase (pas la phase!) lunaire d'Armstrong "Ce fut un grand bond pour l'homme, mais un petit pas pour l'humanité !!!!" |
| | | Contenu sponsorisé
| Sujet: Re: Piloter un relais bistable avec Arduino | |
| |
| | | | Piloter un relais bistable avec Arduino | |
|
Sujets similaires | |
|
| Permission de ce forum: | Vous ne pouvez pas répondre aux sujets dans ce forum
| |
| |
| |