encore des histoires de feu rouge avec arduino

Modérateurs : Kerguelen, steph

steph
Messages : 56
Inscription : 25 oct. 2014, 19:15
Contact :

encore des histoires de feu rouge avec arduino

Message par steph » 28 sept. 2017, 00:02

BAT,

Pour le TP Nr 2 du MOOC arduino, Il est indiqué qu'en dehors du fonctionnement normal, si on appuie sur le bouton pendant que le feu voiture est vert, alors on active le feu pieton.

J'ai écrit ça:

Code : Tout sélectionner

const int buttonPin = 2;    // pin bouton
int buttonState = 0;        // état du bouton

const int rv =  12;    // pin LED rouge voiture    
const int ov =  11;    // pin LED orange voiture
const int vv =  10;    // pin LED vert voiture   
const int rp =  9;    // pin LED rouge pieton      
const int vp =  8;    // pin LED vert pieton

void setup() {
 
  // on définit les pins des diodes comme sorties
  pinMode(rv, OUTPUT);
  pinMode(ov, OUTPUT);
  pinMode(vv, OUTPUT);
  pinMode(rp, OUTPUT);
  pinMode(vp, OUTPUT);
 
  // on définit la pin du bouton comme entrée
  pinMode(buttonPin, INPUT);    
}

void loop(){
  // initialisation feu pieton
  digitalWrite(vp, LOW);    // vert pieton éteint
  digitalWrite(rp, HIGH);    // rouge pieton allumé
 
  // mode mormal
    digitalWrite(vv, LOW);
  digitalWrite(ov, HIGH);
  delay(1000);
  digitalWrite(ov, LOW);
  digitalWrite(rv, HIGH);
  delay(3000);
  digitalWrite(rv, LOW);
  digitalWrite(vv, HIGH);
 
  // passage mode pieton si appuie sur bouton pendant le feu vert.
  buttonState = digitalRead(buttonPin);
  if (buttonState == HIGH) {
   
    digitalWrite(vv, LOW);
    digitalWrite(ov, HIGH);
      delay(1000);
      digitalWrite(ov, LOW);
      digitalWrite(rv, HIGH);
    digitalWrite(vp, HIGH);
      delay(5000);
  }
  else { // sinon, on attend 3 secondes
    delay(3000);
  }
  // retour mode normal en redemarrant la boucle.
}
Mon problème, c'est que l'on ne colle pas exactement à la consigne... Il est demandé de passer au feu pieton si le bouton est actionné alors que le feu voiture est vert. Dans ce cas, on lit l'état du bouton juste après avoir allumée le feu voiture vert. Si il est actionné, on lance le feu pieton, sinon, on attend 3 secondes.
Si on appuie sur le bouton alors que le feu vert voiture est déjà allumé, alors on repars pour un tour de cycle normal avant de déclencher le cycle piéton. En plus si on lâche le bouton avant que le feu voiture repasse au vert, on repart à nouveau pour un tour.

Comment on pourrait gérer que quelque soit le moment où l'on appuie pendant les 3 secondes de feu vert, alors on lance la séquence piéton ?
--
Stephane.

steph
Messages : 56
Inscription : 25 oct. 2014, 19:15
Contact :

Re: encore des histoires de feu rouge avec arduino

Message par steph » 28 sept. 2017, 00:02

En y repensant, j'ai pensé faire une boucle for qui teste l'état du bouton toutes les millisecondes.

Code : Tout sélectionner

/* DECLARATIONs CONSTANTES ET VARIABLES */


const int buttonPin = 2;    // pin bouton
int buttonState = 0;        // état du bouton

const int rv =  12;    // pin LED rouge voiture    
const int ov =  11;    // pin LED orange voiture
const int vv =  10;    // pin LED vert voiture   
const int rp =  9;    // pin LED rouge pieton      
const int vp =  8;    // pin LED vert pieton

int i; // compteur de boucle


/* INITIALISATION */


void setup() {
 
  // on définit les pins des diodes comme sorties
  pinMode(rv, OUTPUT);
  pinMode(ov, OUTPUT);
  pinMode(vv, OUTPUT);
  pinMode(rp, OUTPUT);
  pinMode(vp, OUTPUT);
 
  // on définit la pin du bouton comme entrée
  pinMode(buttonPin, INPUT);    
}

/* BOUCLE PRINCIPALE */


void loop(){
 
  // initialisation feu pieton
  digitalWrite(vp, LOW);    // vert pieton éteint
  digitalWrite(rp, HIGH);    // rouge pieton allumé
  digitalWrite(vv, LOW);    // vert voiture éteint
   
  // mode mormal
  digitalWrite(ov, HIGH);    // orange voiture allumée pendant 1s.
  delay(1000);
  digitalWrite(ov, LOW);    // orange voiture éteint pendant 3s
  digitalWrite(rv, HIGH);    // rouge voiture allumé pendant 3s
  delay(3000);
  digitalWrite(rv, LOW);    // rouge voiture éteint
  digitalWrite(vv, HIGH);    // vert voiture allumé
 
 
  // passage mode pieton si on appuie sur bouton pendant le feu vert.
    for (i=0 ; i<2999 ; i++) { //on teste toutes les millisecondes si on appuie sur le bouton pendant 3000 millisecondes (3s)
 
    buttonState = digitalRead(buttonPin);    // on lit l'état du bouton
      if (buttonState == HIGH) {    // si le bouton est actionné, on active le mode pieton
       
          // mode pieton
        digitalWrite(vv, LOW);    // vert voiture éteint
        digitalWrite(ov, HIGH);    // orange voiture allumé
          delay(1000);            // on attend 1s
          digitalWrite(ov, LOW);    // orange voiture éteint
          digitalWrite(rv, HIGH);    // rouge voiture allumé
          digitalWrite(rp, LOW);    // rouge pieton éteint
        digitalWrite(vp, HIGH);    // vert pieton éteint
          delay(4999);            // attente de 4.999s
      }
    delay(1);                    //délai de 1 milliseconde avant de tester l'état du bouton à nouveau.
  }
  // retour mode normal en redemarrant la boucle principale
}
Bon, ça marche mais bon, on teste l'état du bouton 3000 fois par tour de la boucle principale.
C'est un peu bourrin...

Il doit y avoir moyen de faire plus élégant, non?
Des idées?
--
Stephane.

Guillaume
Messages : 11
Inscription : 31 oct. 2014, 00:56
Localisation : Saint-Louis

Re: encore des histoires de feu rouge avec arduino

Message par Guillaume » 28 sept. 2017, 00:42

Ce que tu proposes est déjà sur la bonne voie.

Bon là le souci c'est que tu peux lancer autant de cycles piéton que tu veux pendant le feu vert, ce qui n'est pas le comportement attendu je pense :)

Une solution plus propre serait par exemple de remplacer ton for() par :

Code : Tout sélectionner

uint32_t tpsPassageVert = millis(); // La fonction millis() renvoie le nombre de millisecondes (en unsigned int) écoulées depuis le démarrage de l'Arduino
while (millis() - tpsPassageVert < 3000) // Tant que 3 secondes ne sont pas écoulées, on exécute le contenu de la boucle
{
	// Le code qu'il y a dans ton for
	// Pas de delay() ici, la gestion du temps se fait avec millis()
}
En fait on enregistre l'"heure" au moment où le feu passe au vert et on exécute le contenu de la boucle tant que les 3 secondes ne sont pas écoulées.
Ainsi, si on rentre dans le cycle piéton, on sort de fait du mode feu vert puisque les 3 secondes seront écoulées.

Une façon beaucoup plus propre d'écrire ce programme serait de réaliser un automate à états (ou machine à états).
En gros cela pourrait s'écrire de la façon suivante :

Code : Tout sélectionner

// Constante définissant les différents états de l'automate
enum etats = { CYCLE_ROUGE, CYCLE_ORANGE, CYCLE_VERT, CYCLE_PIETON }

// Constantes définissant les temps de cycles en millisecondes
const uint32_t TEMPS_CYCLE_ROUGE = 3000;
const uint32_t TEMPS_CYCLE_ORANGE = 1000;
const uint32_t TEMPS_CYCLE_VERT = 3000;
const uint32_t TEMPS_CYCLE_PIETON = 5000;

// Variables régissant le fonctionnement de l'automate
bool demande_pieton;	// Enregistre l'appui du signal piéton pendant le cycle vert
uint8_t etat;			// Etat courant de l'automate
uint32_t tempsDebutCycle;	// Horaire en millisecondes auquel a commencé le cycle courant de l'automate

void init()
{
	// Initialisation matériel
	// [...]
	
	// Intialisation machine à états
	etat = CYCLE_ROUGE;
	demande_pieton = false;
	digitalWrite([...]); // Mettre les feux dans la configuration feu voiture rouge
	tempsDebutCycle = millis();
}

void loop()
{
	switch(etat)
	{
		case CYCLE_ROUGE:
		// Si temps de cycle écoulé, on passe au feu vert
		if (millis() - tempsDebutCycle > TEMPS_CYCLE_ROUGE)
		{
			etat = CYCLE_VERT;
			digitalWrite(FEU_ROUGE_VOITURE, LOW);
			digitalWrite(FEU_VERT_VOITURE, HIGH);
			tempsDebutCycle = millis();
		}
		break;
		
		case CYCLE_VERT:
		// Enregistrer l'appui piéton
		if (digitalRead(APPUI_PIETON) == HIGH)
		{
			demande_pieton = true;
		}
		// Si temps de cycle écoulé ou demande piéton, on passe à l'orange
		if (millis() - tempsDebutCycle > TEMPS_CYCLE_VERT || demande_pieton)
		{
			etat = CYCLE_ORANGE;
			digitalWrite(FEU_VERT_VOITURE, LOW);
			digitalWrite(FEU_ORANGE_VOITURE, HIGH);
			tempsDebutCycle = millis();
		}
		
		case CYCLE_ORANGE:
		// Si le temps de cycle est écoulé, on passe le feu au rouge
		if (millis() - tempsDebutCycle > TEMPS_CYCLE_ORANGE)
		{
			digitalWrite(FEU_ORANGE_VOITURE, LOW);
			digitalWrite(FEU_ROUGE_VOITURE, HIGH);
			// En cas d'appui piéton lors du cycle vert, on va au cycle piéton
			if (demande_pieton)
			{
				etat = CYCLE_PIETON;
				digitalWrite(FEU_VERT_PIETON, HIGH);
				demande_pieton = false;
			}
			// Sinon au feu rouge voiture
			else
				etat = CYCLE_ROUGE;
			tempsDebutCycle = millis();
		}
		break;
		
		case CYCLE_PIETON:
		// Si le temps de cycle est écoulé, on fait un cycle feu rouge voiture
		if (millis() - tempsDebutCycle > TEMPS_CYCLE_PIETON)
		{
			etat = CYCLE_ROUGE;
			digitalWrite(FEU_ROUGE_PIETON, HIGH);
			digitalWrite(FEU_VERT_PIETON, LOW);
			tempsDebutCycle = millis();
		}
		break;
	}
}
C'est beaucoup plus long à écrire mais on peut assez facilement rajouter des cas supplémentaires (plusieurs feux, plusieurs passages piétons, etc.)

Bon après sans avoir l'énoncé complet, je ne sais pas si ce programme remplit le cahier des charges...

MarcoF
Messages : 1
Inscription : 03 oct. 2017, 16:28

Re: encore des histoires de feu rouge avec arduino

Message par MarcoF » 03 oct. 2017, 16:44

Salut,

Je suis le même MOOC, et si on tiens compte du jeux d'instructions mis a disposition, les possibilités sont minces.
Il n'y a que la possibilité de tester si le bouton piéton est appuyer à la fin du feu vert pour répondre à l’exercice.

Bon MOOC

vsahler
Messages : 21
Inscription : 09 mai 2015, 17:42
Localisation : Wittelsheim(11rue du 3février 68310 Wittelsheim, France)

Re: encore des histoires de feu rouge avec arduino

Message par vsahler » 14 janv. 2018, 20:00

MarcoF a écrit :
03 oct. 2017, 16:44
Je suis le même MOOC, et si on tiens compte du jeux d'instructions mis a disposition, les possibilités sont minces.
Il n'y a que la possibilité de tester si le bouton piéton est appuyer à la fin du feu vert pour répondre à l’exercice.
Je ne suis pas un expert en arduino, mais je pense que si l'on veut faire un code fonctionnel, l'évaluation par pair (comme le cas présent si je me souviens bien), de gens qui ont peut-être des capacités moindre est compliquée et pourra ne pas vous être validé alors que le code est bien fonctionnel et même bien mieux que ce que le mooc vous permet. :?
De type interrupt ou comme Guillaume le dit, avec while et millis()
Cordialement,

Vincent SAHLER

Répondre