Programme escrime

Bonjour,
Je suis sur un projet pour une asso d'escrime qui a une installation lumineuse mais pas de matériel pour piloter les lumières. C'est ma première expérience sur de la programmation Arduino.
Je veux contrôler les lumières avec une carte arduino Nano.
J'ai fait une ébauche de programme.
Mon problème qu'il est trop long a réagir entre deux actions.
Je vous mets mon programme:

// C++ code
//
int ledb = 4;
int ledV = 5;
int ledB = 6;
int ledJ = 7;
int ledR = 8;

int masseA = 9;
int toucheA = 10;
int masseB = 11;
int toucheB = 12;
int Sabre = A3;
int Epee = A4;
int Fleuret = A5;

unsigned long tempotouche = 50;
unsigned long tempoled = 3000;

int etattoucheA = LOW;
unsigned long tempsAppuiA = 0;
int etattoucheB = LOW;
unsigned long tempsAppuiB = 0;
int etatEpee = LOW;

void setup() 
{
  pinMode(ledb, OUTPUT);
  pinMode(ledV, OUTPUT);
  pinMode(ledB, OUTPUT);
  pinMode(ledJ, OUTPUT);
  pinMode(ledR, OUTPUT);
  pinMode(masseA, INPUT_PULLUP);  
  pinMode(toucheA, INPUT);
  pinMode(masseB, INPUT_PULLUP);  
  pinMode(toucheB, INPUT);  
  pinMode(Sabre, INPUT);  
  pinMode(Epee, INPUT);
  pinMode(Fleuret, INPUT);
}

void loop() 
// {
//  etatEpee = analogRead(Epee);
//  if (etatEpee == HIGH)
  
{

  etattoucheA = digitalRead(toucheA);
  if (etattoucheA == LOW) {
  tempsAppuiA = millis();
  } 
      etattoucheB = digitalRead(toucheB);
  if (etattoucheB == LOW) {
  tempsAppuiB = millis();
  }  
  
  if (etattoucheA == HIGH && millis() - tempsAppuiA >= tempotouche)
    
  { digitalWrite(ledV, HIGH);
      digitalWrite(ledb, HIGH);
    delay(tempoled);
  } else {
    digitalWrite(ledV, LOW);
       digitalWrite(ledb, LOW);
  }    
    etattoucheB = digitalRead(toucheB);
  if (etattoucheB == LOW) {
  tempsAppuiB = millis();
  }  
   if (etattoucheB == HIGH && millis() - tempsAppuiB >= tempotouche)
     
  { digitalWrite(ledR, HIGH);
      digitalWrite(ledb, HIGH);
    delay(tempoled);
  } else {
    digitalWrite(ledR, LOW);
        digitalWrite(ledb, LOW);
      }
  
  if (etattoucheA == HIGH && etattoucheB == HIGH && (millis() - tempsAppuiA) < tempotouche)
  
  { digitalWrite(ledV, HIGH);
    digitalWrite(ledR, HIGH);

     delay(tempoled);
  } else {
    digitalWrite(ledV, LOW);
    digitalWrite(ledR, LOW); 
      } 
  
    if (digitalRead(masseA) == LOW )
       
  { digitalWrite(ledB, HIGH);
    delay(tempoled);
  } else {
    digitalWrite(ledB, LOW);
      }
     if (digitalRead(masseB) == LOW )
       
  { digitalWrite(ledJ, HIGH);
    delay(tempoled);
  } else {
    digitalWrite(ledJ, LOW);
      }
//}
  if (digitalRead(ledB) == HIGH || digitalRead(ledV) == HIGH || digitalRead(ledJ) == HIGH ||digitalRead(ledR) == HIGH)
  {  digitalWrite(ledb, HIGH);
    delay(tempoled);
  } else {
    digitalWrite(ledb, LOW);
    }
}

Avez vous une solution pour moi?
Est ce que un Arduino est adapter a mon projet?

Bonsoir thierrya76

Cela provient, presque certainement de cette temporisation delay(tempoled); que l'on retrouve souvent.
Comme je n'y connais rien en escrime, (à part Les 3 Mousquetaires :wink:), pourquoi 3 secondes? Que peut il se passer pendant ces 3 secondes, s'il y a une touche, est ce que le duel ne s'arrête pas un moment?

A supposer que l'on diminue, pour essai, tempoled = 3000 à tempoled = 3 est ce que le programme devient assez rapide?
Tout ça pour voir comment mettre une temporisation basée sur millis() à la place de delay() fonction qui est dite bloquante, c'est à dire que, pendant un delay(mmmm), le programme ne fait plus rien.

Voir l'exemple Blink Without Delay

A+
Cordialement
jpbbricole

C'est à dire quels sont tes actions.
A la lecture rapide de ton programme, tu bloques ton programme lorsqu'il y a une touche et que celle-ci a été relâchée ou que les deux ont touché en même temps
Ton code n'étant pas indenté, il est plus difficile à lire.

Du coup, je suppose que le blocage de 3s, n'est pas gênant, car il doit être plus long que la remise en place des participants et leur mise en garde?

pourquoi certaines entrées sont en INPUT et les autres en INPUT_PULLUP?

hello
ton programme ne comporte aucun commentaire, alors pas facile de comprendre ce qu'il doit faire.
deux escrimeurs, chacun équipé :
d'une combinaison raccordée au nano, sur l' entrée "touche" ?
d'une épée raccordée au nano sur l'entrée "masse" ?
pourquoi cette appellation de "masse"?
comment est faite l'épée?(comparable à une tige métallique équipée d'un fil raccordée au nano? ou est ce plus complexe?
pourquoi les entrées sont en INPUT et en INPUT_PULLUP?

on suppose que si une "touche est réalisée pendant 50 milli Secondes, tu allumes une led 3 secondes?
et qu'ensuite, tu éteinds la led et qu'un nouvel assaut peut avoir lieu

pour une personne qui ne connait pas l'escrime, c'est difficile de t'aider.
un schéma, même au papier crayon est nécessaire

Même pour une personne qui a déjà vu l'escrime à la télé et que les escrimeurs ont un fil dans le dos et a leurs armes

Bonjour,
Merci pour vos retour. Je vous met quelque info.
En escrime il y a 3 types d'armes
Le programme est pour l'épée. Sur une épée, il y a 3 fils, 1 fil d'alimentation, 1 retour de touche et une masse.
INPUT_PULLUP permet 2 fonctions en même temps. Alimenter et détecter un cour circuit.
INPUT valide la touche qui dur minimum 50ms.
Mon problème est que si l'épée A ce mets en cour circuit l'épée B ne peut pas faire de touche.
Je ne comprend pas pourquoi, il y a un temps d'attente entre 2 actions.

la touche a donc un pullup ou pulldown externe?

Pour le cas actuel en up.
Pour le programme fleuret cela sera en down.

il y a un condensateur aussi qui évite les rebonds où vous devez filtrer cela en logiciel ?

Bonjour thierrya76

Je pense mais pas sûre, que ton problème vient des temporisations delay(tempoled);, il faut bien te dir que, pendant ce temps, le programme ne peut plus rien faire d'autre.
Pour que tu puisses te rendre compte de ça, tu devrai les désactiver et remplacer l'affichage des LED par des compteurs de touches et tu te rendrai compte (peut être :wink:) que ton programme fonctionne très bien.
Après, avec des millis(), on pourrai réafficher ces LED sans bloquer le programme.

Pour ce qui est de ton programme, j'aurai "attaqué" ça avec une bibliothèque comme OneButton, qui s'occupe des rebonds dont le temps est paramétrable. On crée un événement, comme attachClick qui est déclenché à chaque touche.

Cordialement
jpbbricole

Comme l'indique @jpbbricole, c'est ce que tu demande à ton programme.

if (etattoucheA == HIGH && millis() - tempsAppuiA >= tempotouche) {
  digitalWrite(ledV, HIGH);
  digitalWrite(ledb, HIGH);
  delay(tempoled);
} else {
  digitalWrite(ledV, LOW);
  digitalWrite(ledb, LOW);
}

Je me suis permis de réindenter la portion de code, pour que celui-ci soit plus facile à lire.
Dans cette partie tu demande au programme si A à touché pendant plu de 50ms, allume les LED V et b, puis ne fait plus rien pendant 3s

Puis donc 3s plus tard le programme continue avec le test pour le combattant B

/* code redondant déjà fait un peu plus haut*/
etattoucheB = digitalRead(toucheB);
if (etattoucheB == LOW) {
  tempsAppuiB = millis();
}
/**********/
if (etattoucheB == HIGH && millis() - tempsAppuiB >= tempotouche){
  digitalWrite(ledR, HIGH);
  digitalWrite(ledb, HIGH);
  delay(tempoled);
} else {
  digitalWrite(ledR, LOW);
  digitalWrite(ledb, LOW);
}

hello
tu n'es pas clair, pourquoi 3 fils sur l'épée, et 1 fil sur la combinaison
imaginons 1 fil pour amener le GND en bout de l'épée. l'épée touche la combinaison de l'adversaire qui conduit le GND via le fil vers une entrée.
donc quand lépée de A touche la combinaison de B, l'info arrive au µC

est ce bien ça ?

à quoi servent les 2 autres fils de l'épée ?

L'un des deux doit être pour la combinaison qui va avec l'épée A ?

Comment je peux allumer mes LEDs sans attendre 3s? Est-ce qu'il y a une autre fonction pour laisser une sortie a l'état haut pendant un temps défini ?

image

Bonsoir thierrya76

Oui, avec millis(), regardes l'exemple BlinkWithoutDelay

Si tu le désires, je peux adapter ton programme, comme exemple (demain).

Cordialement
jpbbricole

exactement de la même façon que tu le fait pour attendre 50ms avant de valider la touche d'un combattant.

Tu défini par exemple deux variables etatLEDV et tempsLEDV avec bool etatLEDV = false; unsigned long tempsLEDV = 0;
Dans ta détection de touche au lieu d'uniquement allumer directement ta LED, tu positionne tes variables

etatLEDV = true;
tempsLEDV = millis();
digitalWrite(ledb, HIGH);

Il ne te reste plus qu'a l'éteindre lorsque les conditions de temps son remplis :slight_smile:

if (etatLEDV && millis() - tempsLEDV > tempoled) {
  digitalWrite(ledb, LOW);
  etatLEDV = false;
}

Tu pourra remarqué qu'au vu du nombre de LED, que tu as, il serait intéressant de rationnaliser tout ça, car tu va surement répéter la même structure de code pour chaque LED.
Utiliser un tableau pourrait être intéressant voir l'implémentation d'un objet.

De même pour la structure de ton programme, je ne sais pas quel niveau tu as réellement mais à la vu de ce que tu nous as montré, je pense que tu pourrais passer à l'utilisation d'une machine à état, ce qui te donnerais un code plus simple à lire.

D'ailleurs comme je l'avais déjà indiqué ton code n'est pas indenté correctement, tu peux le faire facilement avec l'IDE d'arduino ou Visual Code.
Une fois fait tu pourra éditer le code que tu as présenté dans le message #1 :slight_smile:

Bonjour thierrya76

Voici ma "vision de la chose".
Tout d'abord, la mise en tableau des pin des LED:

const int ledPin[] = {4, 5, 6, 7, 8};     // Tableau des pin des LED

Leur énumération:

enum {ledb, ledV, ledB, ledJ, ledR};     // Enumération des LE 0, 1, 2...

Attention, ledB, par exemple, qui était un numéro de pin, devient un index (2) dans le tableau ledPin[] qui pointe sur la pin 6.
Avec les pin en tableau, on peut les initialiser "en groupe":

	for (int l = 0; l < ledNombre; l ++)
	{
		pinMode(ledPin[l], OUTPUT);     // Initialisation des pin des LED
		digitalWrite(ledPin[l], LOW);     // Eteindre la LED
	}

Il y a un tableau contenant le chronométrage du temps d'allumage de chaque LED.
unsigned long ledOnMillis[] = {0, 0, 0, 0, 0}; // Tableau des temporisations des LED, si 0 = désactivée
Et, dans loop, on test continuellement s'il y a des LED à éteindre.

	for (int l = 0; l < ledNombre; l ++)

La commande des LED et le démarrage de leur chronomètre se fait dans void ledAllumer(int ledNum)
Je n'ai pas pu faire des essais "en vrai" :woozy_face:

Le programme:

// C++ code
//
enum {ledb, ledV, ledB, ledJ, ledR};     // Enumération des LE 0, 1, 2...
const int ledPin[] = {4, 5, 6, 7, 8};     // Tableau des pin des LED
const int ledNombre = sizeof(ledPin) / sizeof(ledPin[0]);    // Nombre de LED

//int ledb = 4;
//int ledV = 5;
//int ledB = 6;
//int ledJ = 7;
//int ledR = 8;

int masseA = 9;
int toucheA = 10;
int masseB = 11;
int toucheB = 12;
int Sabre = A3;
int Epee = A4;
int Fleuret = A5;

unsigned long ledOnMillis[] = {0, 0, 0, 0, 0};     // Tableau des temporisations des LED, si 0 = désactivée

unsigned long tempotouche = 50;
unsigned long tempoled = 3000;

int etattoucheA = LOW;
unsigned long tempsAppuiA = 0;
int etattoucheB = LOW;
unsigned long tempsAppuiB = 0;
int etatEpee = LOW;

void setup()
{
	Serial.begin(115200);

	for (int l = 0; l < ledNombre; l ++)
	{
		pinMode(ledPin[l], OUTPUT);     // Initialisation des pin des LED
		digitalWrite(ledPin[l], LOW);     // Eteindre la LED
	}
	//pinMode(ledb, OUTPUT);
	//pinMode(ledV, OUTPUT);
	//pinMode(ledB, OUTPUT);
	//pinMode(ledJ, OUTPUT);
	//pinMode(ledR, OUTPUT);
	pinMode(masseA, INPUT_PULLUP);
	pinMode(toucheA, INPUT);
	pinMode(masseB, INPUT_PULLUP);
	pinMode(toucheB, INPUT);
	pinMode(Sabre, INPUT);
	pinMode(Epee, INPUT);
	pinMode(Fleuret, INPUT);
}

void loop()
{
	// Contrôle si des LED à éteindre
	for (int l = 0; l < ledNombre; l ++)
	{
		if (ledOnMillis[l] != 0 && (millis() - ledOnMillis[l] >= tempoled))     // Si échéence de cette LED
		{
			digitalWrite(ledPin[l], LOW);     // Eteindre cette LED
			ledOnMillis[l] = 0;     // Désactiver le chrono de cette LED
			Serial.println("LED off\t" + String(l));
		}
	}

	etattoucheA = digitalRead(toucheA);
	if (etattoucheA == LOW) 
	{
		tempsAppuiA = millis();
	}
	etattoucheB = digitalRead(toucheB);
	
	if (etattoucheB == LOW) 
	{
		tempsAppuiB = millis();
	}
	
	if (etattoucheA == HIGH && millis() - tempsAppuiA >= tempotouche)
	
	{ 
		ledAllumer(ledV);

		ledAllumer(ledb);
		//delay(tempoled);
	} 
		else 
	{
		//digitalWrite(ledV, LOW);
		//digitalWrite(ledb, LOW);
	}
	etattoucheB = digitalRead(toucheB);
	if (etattoucheB == LOW) 
	{
		tempsAppuiB = millis();
	}
	if (etattoucheB == HIGH && millis() - tempsAppuiB >= tempotouche)
	
	{ 
		ledAllumer(ledR);

		ledAllumer(ledb);
		//delay(tempoled);
	} 
	else 
	{
		//digitalWrite(ledR, LOW);
		//digitalWrite(ledb, LOW);
	}
	
	if (etattoucheA == HIGH && etattoucheB == HIGH && (millis() - tempsAppuiA) < tempotouche)
	
	{ 
		ledAllumer(ledV);

		ledAllumer(ledR);

		//delay(tempoled);
	} 
	else 
	{
		//digitalWrite(ledV, LOW);
		//digitalWrite(ledR, LOW);
	}
	
	if (digitalRead(masseA) == LOW )
	
	{ 
		ledAllumer(ledB);
		//delay(tempoled);
	} 
	else 
	{
		//digitalWrite(ledB, LOW);
	}
	if (digitalRead(masseB) == LOW )
	
	{ 
		ledAllumer(ledJ);
		//delay(tempoled);
	} 
	else 
	{
		//digitalWrite(ledJ, LOW);
	}
	//}
	if (digitalRead(ledB) == HIGH || digitalRead(ledV) == HIGH || digitalRead(ledJ) == HIGH ||digitalRead(ledR) == HIGH)
	{  
		ledAllumer(ledb);
		//delay(tempoled);
	} 
	else 
	{
		//digitalWrite(ledb, LOW);
	}
}

void ledAllumer(int ledNum)
{
	if (ledOnMillis[ledNum] != 0)     // Si déjà allumée (chrono en route)
	{
		return;     // On ne fait rien
	}

	Serial.println("LED ON\t" + String(ledNum));
	digitalWrite(ledPin[ledNum], HIGH);
	ledOnMillis[ledNum] = millis();     // Démarrage du chrono
}

Il y a des informations quand au fonctionnement du programme dans la console à 115200.

A+
Cordialement
jpbbricole