Programme de contrôle de plusieurs capteurs en même temps

Bonjour à tous,

pour poser les bases, je m'appelle Guillaume, j'ai une formation en conception mécanique à la base mais je suis amener à bidouiller un petit système de contrôle avec 4 capteurs mécaniques à galets (contact NO + NF sur chaque capteur) et carte Arduino.

J'ai de très légères "bases" en programmation et j'ai fait une première version de programme qui fonctionne mais pas à 100%.

En gros il y a 2 capteurs d'un côté d'une machine (C1 et C2) et 2 capteurs de l'autre côté (C3 et C4).
Chaque paire de capteurs vérifie certaines conditions. Les 2 côtés ont le même fonctionnement mais sont indépendants. Par contre au final une certaine combinaison des 2 côtés doit me donner un seul signal de sortie pour soit allumer un voyant rouge, soit un voyant vert.
(Système de sécurité donc si au moins un défaut est présent sur un des 2 côtés, le voyant rouge général doit s'allumer)

Les capteurs sont sur une machine qui vibre et qui fait donc perdre de temps en temps les contacts des capteurs ou à l'inverse donne un contact non souhaité.
(Mon premier montage était en câblage traditionnel sans carte arduino avec uniquement 2 capteurs et du coup mon signal de sortie était souvent faux)

En passant à un système à 4 capteurs et à l'Arduino, j'ai voulu régler le problème en vérifiant les états des capteurs sur 3 secondes afin d'éviter toute mauvaise info due aux vibrations pendant 1 à 2sec.
J'ai utilisé la fonction delay().

Voici le code :

//////////////Définition des ports entrées sorties ////////

  
#define C1 13          //C1 est branché sur le pin digital 13          
#define C1_b 12        //C1_b est branché sur le pin digital 12
#define C2 11          //C2 est branché sur le pin digital 11
#define C2_b 10        //C2_b est branché sur le pin digital 10
#define C3 9           //C3 est branché sur le pin digital 9
#define C3_b 8         //C3_b est branché sur le pin digital 8
#define C4 7           //C4 est branché sur le pin digital 7
#define C4_b 6         //C4_b est branché sur le pin digital 6
#define Led_verte 5    //led_verte est branchée sur le pin digital 5
#define Led_rouge 4    //Led rouge est branchée sur le pin digital 4



void setup() {

  pinMode(C1, INPUT_PULLUP);
  pinMode(C1_b, INPUT);
  pinMode(C2, INPUT_PULLUP);
  pinMode(C2_b, INPUT);
  pinMode(C3, INPUT_PULLUP);
  pinMode(C3_b, INPUT);
  pinMode(C4, INPUT_PULLUP);
  pinMode(C4_b, INPUT);
  pinMode(Led_rouge, OUTPUT);
  pinMode(Led_verte, OUTPUT);
  int variable = 1 ; // On initialise une variable interne permettant le basculement des leds.
  int Tempo=3000; // On configure la temporisation pour 3 secondes.(Modifiable selon besoin )
 
}

void loop() {
  int variable = 1;
  int c = 1 ;
  int Tempo=1000;
// programme permettant la vérification des bons états des capteurs de fin de course ( HIGH = sous tension , Low = 0V )
  if ( ((digitalRead(C1) == LOW) && (digitalRead(C2) == LOW)) || ((digitalRead(C1) == HIGH) && (digitalRead(C2) == HIGH)) || ((digitalRead(C3) == LOW) && (digitalRead(C4) == LOW)) || ((digitalRead(C3) == HIGH) && (digitalRead(C4) == HIGH)) )
  {
    variable = 0;
  }
  else
  {
    variable = 1;
  }

  

  switch (variable) {
    case HIGH:
      digitalWrite(Led_rouge, 1);//allumer la led verte
      digitalWrite(Led_verte, 0);//éteindre la led rouge
   
      break;
    case LOW:
      digitalWrite(Led_rouge, 0);//allumer la led rouge
      digitalWrite(Led_verte, 1);//éteindre la led verte
     
      break;
  }
  delay(Tempo); // Temporisaton 

}

Mon problème est qu'avec la fonction delay(), le programme se stoppe et reprend 3 sec après.
En gros si j'ai des infos des capteurs qui me donnent un signal vert pendant 2,5sec mais rouge à la reprise au bout des 3 sec, ça s'allume en rouge.
Je me suis rendu compte que ce n'était pas la bonne fonction.

Donc pour palier à se problème de vibrations (qu'on ne peut pas supprimer), je voulais vérifier l'état des capteurs avec un ou plusieurs while() et millis() mais je ne m'en sors pas ça devient trop complexe pour moi.
J'ai bien compris qu'on peut utiliser plusieurs variables pour faire une soustraction du temps avec millis() et obtenir les 3 sec mais je ne sais pas comment vérifier mes conditions de capteurs en parallèle sans avoir des infos qui se contredisent.

Merci pour votre aide.

Salut.
Dans setup() tu déclares une Tempo, qui a une portée locale à cette fonction, ce qui t'oblige à la redéclarer dans loop().

Concernant ton problème à propos de millis, si tu ouvrais l'exemple : 02. Digital/BlinkWithoutDelay ?
Si tu veux éviter de bloquer ton programme il va falloir éviter également les boucles while().

@+

Salut,

Merci pour l'info.

Avec l'exemple j'ai toujours le problème de vérifier 4 conditions en même temps sans que ça fasse n'importe quoi. :stuck_out_tongue:

Bonjour Dusson

Avant de voir ce problème de temporisation, une ou deux remarques concernant le programme:

#define C1 13 //C1 est branché sur le pin digital 13

En général, la pin 13, spécialement sur un UNO, est utilisée pour la LED qui est sur le circuit imprimé de l'Arduino, à utiliser avec circonspection.

Tes déclarations de variables

int variable = 1 ; // On initialise une variable interne permettant le basculement des leds.
int Tempo=3000; // On configure la temporisation pour 3 secondes.(Modifiable selon besoin )

sont répétées 2 fois?

Il serait mieux de les mettre une fois mais "tout en haut" si elles doîvent être vues de partout, en effet, une variable déclarée dans une fonction comme setup() {} ou loop() {} ne sont "vues" qu'entre les accolades respectives. En l'occurence, dans notre cas elles peuvent rester locales dans loop()
Surtout, n'hésites pas à donner des noms de variables plus explicites, ça ne "mange pas de pain" et ça rend le programme plus lisible ainsi variable devient contactsCondition c'est mieux imagé et ça évite, souvent, de mettre des remarques.

Pour la temporisation, mieux qu'une longue explication, j'ai préféré adapter ton programme avec, je l'epère, assez de commentaires pour que tu puisses comprendre la "mécanique" à faire ce genre de temporisation.Ja sais, c'est du "tout fait" mais je pense que c'est aussi une excellente façon d'apprendre.
J'ai mis en remarque les lignes qui ne sont pas nécessaires.
la fonction boolean contactsSiCondition() utilisée pour les test est la version réduite en remarque en fin de programme, je n'ai pas la configuration matériel, à toi d'essayer avec ta version.

//////////////Définition des ports entrées sorties ////////


#define C1 13          //C1 est branché sur le pin digital 13
#define C1_b 12        //C1_b est branché sur le pin digital 12
#define C2 11          //C2 est branché sur le pin digital 11
#define C2_b 10        //C2_b est branché sur le pin digital 10
#define C3 9           //C3 est branché sur le pin digital 9
#define C3_b 8         //C3_b est branché sur le pin digital 8
#define C4 7           //C4 est branché sur le pin digital 7
#define C4_b 6         //C4_b est branché sur le pin digital 6
#define Led_verte 5    //led_verte est branchée sur le pin digital 5
#define Led_rouge 4    //Led rouge est branchée sur le pin digital 4

#define  ContactsConditionDelais 3000                 // Delais d'attente de stabilisation que l'on va utiliser avec l'horloge interne millis()
unsigned long contactsConditionTimer = millis();      // Timer qui mesure la durée de contactsCondition

void setup() {

	pinMode(C1, INPUT_PULLUP);
	pinMode(C1_b, INPUT);
	pinMode(C2, INPUT_PULLUP);
	pinMode(C2_b, INPUT);
	pinMode(C3, INPUT_PULLUP);
	pinMode(C3_b, INPUT);
	pinMode(C4, INPUT_PULLUP);
	pinMode(C4_b, INPUT);
	pinMode(Led_rouge, OUTPUT);
	pinMode(Led_verte, OUTPUT);
	//int variable = 1 ; // On initialise une variable interne permettant le basculement des leds.
	//int Tempo=3000; // On configure la temporisation pour 3 secondes.(Modifiable selon besoin )
}

void loop() {
	boolean contactsCondition = false;                     // Variable booléenne si condition des contacts vraie ou fausse   
	boolean contactsConditionAction = false;               // // Variable booléenne si contactsCondition est vraioe depuis 

	//int c = 1 ;
	//int Tempo=1000;

	contactsCondition = contactsSiCondition(); // On va lire les contacts, retourne Vrai ou Faux s'il y a condition ou pas.
	if (contactsCondition == false)       // Si la condition n'est pas remplie on "recharge" le timer
	{
			contactsConditionTimer = millis();
	}
	
	if (millis() - contactsConditionTimer > ContactsConditionDelais)  // Si contactsCondition stable depuis plus de ContactsConditionDelais
	{
		contactsConditionAction = true;                     // Il y aura action
	}
	else
	{
		contactsConditionAction = false;                    // Il n'y aura pas d'action
	}
	
	switch (contactsConditionAction) {
		case true:
			digitalWrite(Led_rouge, 1);//allumer la led verte
			digitalWrite(Led_verte, 0);//éteindre la led rouge
			break;
		case false:
			digitalWrite(Led_rouge, 0);//allumer la led rouge
			digitalWrite(Led_verte, 1);//éteindre la led verte
			break;
	}
	//delay(Tempo); // Temporisaton

}
// programme permettant la vérification des bons états des capteurs de fin de course ( HIGH = sous tension , Low = 0V )
boolean contactsSiCondition()
{
	if ( ((digitalRead(C1) == LOW) && (digitalRead(C2) == LOW)) || ((digitalRead(C1) == HIGH) && (digitalRead(C2) == HIGH)) || ((digitalRead(C3) == LOW) && (digitalRead(C4) == LOW)) || ((digitalRead(C3) == HIGH) && (digitalRead(C4) == HIGH)) )
	{
		return false;
	}
	else
	{
		return true;
	}
}

////------------------------------- Version réduite pour essais avec uniquement le contact C4 (Avec laquelle j'ai fait les essais)
//boolean contactsSiCondition()
//{
	//if (digitalRead(C4) == LOW)
	//{
		//return false;
	//}
	//else
	//{
		//return true;
	//}
//}

A ta disposition pour tout éclaircissement.

Cordialement
jpbbricole

Bonsoir,

merci pour ces infos, je ne savais pas du tout pour le PIN 13.

C'est vrai que mes variables peuvent être déclarées tout en haut une seule fois.

Merci pour ta modification du programme, même si ça devient "beaucoup" plus compliqué pour moi, j'essaie de comprendre. Je comprends la structure après je ne garantie pas de trouver une solution si y a une erreur. ^^

Je vous tiendrais au courant du résultat mardi soir, j'ai seulement accès à la machine pour test mardi après midi.

J'ai quelques questions :

  • En haut tu marques " #define ContactsConditionDelais 3000 ", il n'y a pas besoin de mettre de = devant le 3000 ?

  • Dans le void loop(), il y a "int Tempo=1000" (qui était déjà dans mon programme d'origine je viens de voir).
    Du coup le Tempo=1000 prend la main sur le tempo=3000 du haut, c'est bien ça?
    Ce qui est bizarre c'est que dans mes tests avec l'ancien programme y avait bien 3sec avant le changement d'état des leds.

Bonsoir Dusson

Dusson:
C'est vrai que mes variables peuvent être déclarées tout en haut une seule fois.

C'est pas une règle générale que de mettre les déclarations de variable afin quelles soient vues de partout. Il faut toujours voire si c'est nécessaire.

Dusson:

  • En haut tu marques " #define ContactsConditionDelais 3000 ", il n'y a pas besoin de mettre de = devant le 3000 ?

avec #define on n'attribue pas une valeur à quelque chose comme int Total = 12.
On attribue quelque chose à un nom, pour le compilateur et ça peut prendre tout sorte de choses ainsi:

#define Hauteur 12
#define Texte "Voilà Du Texte"

int x = 12;
int y = 33;
#define Calcul x += y
et faire Serial.println(Calcul);

Dusson:

  • Dans le void loop(), il y a "int Tempo=1000" (qui était déjà dans mon programme d'origine je viens de voir).
    Du coup le Tempo=1000 prend la main sur le tempo=3000 du haut, c'est bien ça?

tempo=3000 est dans void setup() et tempo=1000 est dans void loop() ils ne se voient pas et ailleurs ils ne lesvoient pas.
Recherches Arduino portée des variables et choisi l'explication que tu comprendra le mieux.

Cordialement
jpbbricole

Tous comme toi je suis un débutant.

et les meme personne m'ont aider , c'est vraiment des pointures.

Et moi suivant les conseilles que j'ai reçu et que j'ai mis du temps a utiliser , par ce que je les trouvais trop compliqué. tu devrait lire les tutos sur :

les fonctions suivantes:

blinking without delay
la machine a état
Millis
button state

apparement tous comme moi tu te sert de ton montage au boulot. et en plus pour de la sécurité

croix moi avec déjà ces quatre fonctions ton programme sera sera simple a écrire

Grace a leurs conseilles j'ai en trois mois fais d'énorme progrès .

bien a toi

JP a essayé sans doute de bien séparer la logique en rajoutant des booléens pour que vous compreniez.

Si c'est un peu trop compliqué à lire pour vous, on peut peut-être raccourcir le code proposé par JP car les booléens ne sont pas vraiment nécessaire. (et le switch case sur un booléen pas forcément la meilleure approche, un if / else est plus coutumier et plus facile à lire pour les débutants sans doute)

on dit:

s'il y a un contact
s'il est stable depuis un certains temps alors on fait l'action sinon une autre action
sinon on met à jour l'heure pour calculer le délai d'attente

La boucle deviendrait

void loop()
{
  if (contactsSiCondition()) {
    if (millis() - contactsConditionTimer >= ContactsConditionDelais) { // Si contactsCondition stable depuis plus de ContactsConditionDelais
      // on fait l'action
      digitalWrite(Led_rouge, HIGH);//allumer la led verte
      digitalWrite(Led_verte, LOW);//éteindre la led rouge
    } else {
      digitalWrite(Led_rouge, LOW);//éteindre la led rouge
      digitalWrite(Led_verte, HIGH);//allumer la led verte
    }
  } else contactsConditionTimer = millis();// Si la condition n'est pas remplie on "recharge" le timer
}

J-M-L:
JP a essayé sans doute de bien séparer la logique en rajoutant des booléens pour que vous compreniez.

Exact, c'était pour ne pas démarrer avec un truc trop alambiqué (je sais aussi faire) du fait qu'il débute, après on peut toujours affiner et surtout, c'était une adaptation de son programme en utilisant, le plus possible, sa structure, pas une réécriture, de telle façon qu'il voie les choses positives.

Cordialement
jpbbricole

Si c'est juste pour du guidage tu fais comme tu veux.

Si en plus il y a une gestion de sécurité il faut absolument que l'état "alarme" corresponde à un 0V.
Je sais c'est surprenant et pas logique pour notre petit cerveau.

Mettons nous dans le cas ou quand tout va bien on a 0V et que l'alarme correspond à +5V. Si un câble de liaison avec le capteur se coupe, comme tu aura 0V tu croira que tout va bien alors que tu sera en danger.

Je tiens à préciser qu'Arduino lui même interdit l'utilisation de ses cartes quand la sécurité des personne est concernée.

Je vais essayer de répondre à tout le monde sans faire de quotes, ça sera trop long :stuck_out_tongue:

Oui je suis habitué de l'entraide sur divers forums c'est pour ça que je n'ai pas hésité à venir demander conseils ici. :slight_smile:

J'avais bien regardé l'exemple blinking without delay depuis le début de ma recherche sur une autre manière de traiter le programme mais j'avais du mal à le voir avec plusieurs conditions.

@J-M-L :
Oui on peut toujours optimiser par la suite, j'ai bien compris les booléens et le switch case.

@68tjs : c'est vrai que j'ai utilisé le mot sécurité mais ce n'est pas de la sécurité de la personne, donc c'est plutôt à titre d'information pour la personne le voyant rouge et pour régler la situation par elle même.

C'est vrai que la commande par 0V est logique dans le cas de sécurité. Je me le garde pour le futur.

En tout cas merci à tous pour votre aide.

Je vais essayer de finaliser le programme aujourd'hui et je vous tiens au courant.

Hello,

je reviens vous tenir au courant des avancées. (je suis rentré trop tard hier soir :-[ )

Alors que ce soit la version longue ou courte du programme les 2 fonctionnent bien à l'identique.

Je vais donc rester sur la version courte qui est plus facile à modifier.

Donc le problème rencontré avec ce programme c'est que la tempo de vérification fonctionne dans une situation mais pas dans l'autre.
Je m'explique, lorsque mon voyant est vert et que les conditions vont allumer le voyant rouge, cela se fait immédiatement sans prendre en compte la stabilisation de la condition pendant 3sec.
Par contre du rouge vers le vert là il y a bien les 3 secondes de pris en compte.

Quelqu'un peut m'expliquer pourquoi la tempo n'est active que dans un cas sur 2 ?

//////////////Définition des ports entrées sorties ////////


#define C1 13          //C1 est branché sur le pin digital 13
#define C1_b 12        //C1_b est branché sur le pin digital 12
#define C2 11          //C2 est branché sur le pin digital 11
#define C2_b 10        //C2_b est branché sur le pin digital 10
#define C3 9           //C3 est branché sur le pin digital 9
#define C3_b 8         //C3_b est branché sur le pin digital 8
#define C4 7           //C4 est branché sur le pin digital 7
#define C4_b 6         //C4_b est branché sur le pin digital 6
#define Led_verte 5    //led_verte est branchée sur le pin digital 5
#define Led_rouge 4    //Led rouge est branchée sur le pin digital 4

#define  ContactsConditionDelais 3000                 // Delais d'attente de stabilisation que l'on va utiliser avec l'horloge interne millis()
unsigned long contactsConditionTimer = millis();      // Timer qui mesure la durée de contactsCondition

void setup() {

  pinMode(C1, INPUT_PULLUP);
  pinMode(C1_b, INPUT);
  pinMode(C2, INPUT_PULLUP);
  pinMode(C2_b, INPUT);
  pinMode(C3, INPUT_PULLUP);
  pinMode(C3_b, INPUT);
  pinMode(C4, INPUT_PULLUP);
  pinMode(C4_b, INPUT);
  pinMode(Led_rouge, OUTPUT);
  pinMode(Led_verte, OUTPUT);
}


void loop()
{
  if (contactsSiCondition()) {
    if (millis() - contactsConditionTimer >= ContactsConditionDelais) { // Si contactsCondition stable depuis plus de ContactsConditionDelais
      // on fait l'action
      digitalWrite(Led_rouge, HIGH);//allumer la led rouge
      digitalWrite(Led_verte, LOW);//éteindre la led verte
    } else {
      digitalWrite(Led_rouge, LOW);//éteindre la led rouge
      digitalWrite(Led_verte, HIGH);//allumer la led verte
    }
  } else contactsConditionTimer = millis();// Si la condition n'est pas remplie on "recharge" le timer
}

// Fonctionne mais met une tempo de 3sec du rouge au vert vert mais pas du vert au rouge (ce qui est le plus important dans mon cas avec les vibrations)
// Le relai est bien géré, il tient chaque position.

// programme permettant la vérification des bons états des capteurs de fin de course ( HIGH = sous tension , Low = 0V )

boolean contactsSiCondition()
{
  if ( ((digitalRead(C1) == LOW) && (digitalRead(C2) == LOW)) || ((digitalRead(C1) == HIGH) && (digitalRead(C2) == HIGH)) || ((digitalRead(C3) == LOW) && (digitalRead(C4) == LOW)) || ((digitalRead(C3) == HIGH) && (digitalRead(C4) == HIGH)) )
  {
    return false;
  }
  else
  {
    return true;
  }
}

J'ai donc essayé d'inversé plein de variables, d'inverser les conditions, d'inverser les sorties des voyants mais rien n'y fait je n'ai jamais réussi à avoir la tempo du vert au rouge.
A la limite si je n'ai pas la tempo dans les 2 cas ce n'est pas grave tant que je l'ai du vert au rouge.

Il y a eu un programme qui a presque marché, le suivant :

//////////////Définition des ports entrées sorties ////////


#define C1 13          //C1 est branché sur le pin digital 13
#define C1_b 12        //C1_b est branché sur le pin digital 12
#define C2 11          //C2 est branché sur le pin digital 11
#define C2_b 10        //C2_b est branché sur le pin digital 10
#define C3 9           //C3 est branché sur le pin digital 9
#define C3_b 8         //C3_b est branché sur le pin digital 8
#define C4 7           //C4 est branché sur le pin digital 7
#define C4_b 6         //C4_b est branché sur le pin digital 6
#define Led_verte 5    //led_verte est branchée sur le pin digital 5
#define Led_rouge 4    //Led rouge est branchée sur le pin digital 4

#define  ContactsConditionDelais 1000                 // Delais d'attente de stabilisation que l'on va utiliser avec l'horloge interne millis()
unsigned long contactsConditionTimer = millis();      // Timer qui mesure la durée de contactsCondition

void setup() {

  pinMode(C1, INPUT_PULLUP);
  pinMode(C1_b, INPUT);
  pinMode(C2, INPUT_PULLUP);
  pinMode(C2_b, INPUT);
  pinMode(C3, INPUT_PULLUP);
  pinMode(C3_b, INPUT);
  pinMode(C4, INPUT_PULLUP);
  pinMode(C4_b, INPUT);
  pinMode(Led_rouge, OUTPUT);
  pinMode(Led_verte, OUTPUT);
}


void loop()
{
  if (contactsSiCondition()) {
    if (millis() - contactsConditionTimer >= ContactsConditionDelais) { // Si contactsCondition stable depuis plus de ContactsConditionDelais
      // on fait l'action
      digitalWrite(Led_rouge, LOW);//allumer la led rouge
      digitalWrite(Led_verte, HIGH);//éteindre la led verte
    } else {
      digitalWrite(Led_rouge, HIGH);//éteindre la led rouge
      digitalWrite(Led_verte, LOW);//allumer la led verte
    }
  } else contactsConditionTimer = millis();// Si la condition n'est pas remplie on "recharge" le timer
}

// Tourne dans la boucle 3 fois avant d'enclencher et de maintenir le rouge. Des fois ne tient même pas.
// Le relai s'enclenche une 1/2 seconde mais ne tient pas, il s'enclenche définitivement au bout de la 3ème boucle de 3sec.

// programme permettant la vérification des bons états des capteurs de fin de course ( HIGH = sous tension , Low = 0V )

boolean contactsSiCondition()
{
  if ( ((digitalRead(C1) == HIGH) && (digitalRead(C2) == HIGH)) || ((digitalRead(C1) == LOW) && (digitalRead(C2) == LOW)) || ((digitalRead(C3) == HIGH) && (digitalRead(C4) == HIGH)) || ((digitalRead(C3) == LOW) && (digitalRead(C4) == LOW)) )
  {
    return true;
  }
  else
  {
    return false;
  }
}

Dans ce cas j'arrive à avoir la tempo du vert au rouge mais il y a plusieurs bugs.

C'est comme si la tempo de 3sec enclenchait aussi un comptage de 3 cycles avant d'allumer et de maintenir le voyant rouge.

Merci pour vos lumières et explications de la non prise en compte de la tempo dans un cas ! :slight_smile: