Projet sur Arduino => allumer une LED en tapant 2 fois dans les mains [Résolu]

Signaler
-
Messages postés
5383
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
10 juillet 2020
-
Bonjour,
j'ai un projet qui consiste à allumer une LED en tapant 2 fois dans le mains sur ARDUINO.

En gros :
Après avoir taper 1 fois dans les mains, si pendant un petit temps donné on ne tape pas une deuxième fois dans les mains alors la LED ne s'allume pas. Pareillement pour l'éteindre.
Il faut donc taper 2 fois assez rapidement pour pouvoir l'allumer.

Mon problème c'est que je n'arrive pas à faire le programme.
J'ai déjà le montage.

Pour l'instant j'ai trouvé ça pour l'allumer en tapant une fois dans les mains :

void setup() {
  Serial.begin(9600);             // using serial port to check analog value
  pinMode(2, OUTPUT);             // LED on digital pin 2
}

void loop() {
  int analog_val;                 // analog value read from A2
  static bool led_state = false;  // current state of LED
  
  analog_val = analogRead(A2);

  if (analog_val > 10) {          // trigger threshold
    // toggle LED
    if (led_state) {
      led_state = false;          // LED was on, now off
      digitalWrite(2, LOW);
      Serial.println(analog_val); // print analog value for debug purposes
    }
    else {
      led_state = true;
      digitalWrite(2, HIGH);      // LED was off, now on
      Serial.println(analog_val);
    }
    delay(50);  // wait for clap noise to subside
  }
}




J’espère avoir des retours.

Merci d'avance.



Configuration: Windows / Firefox 76.0

8 réponses

Messages postés
4868
Date d'inscription
lundi 31 janvier 2011
Statut
Contributeur
Dernière intervention
11 juillet 2020
1 163
Bonjour,

Qui dit projet dit recherche, essais, corrections, améliorations. C'est de mon point de vue la démarche qui permet la satisfaction d'avoir trouvé la solution.

Pour l'instant, je subodore que vous avez trouvé un code sur le net et n'avez même pas cherché à le modifier d'un iota.

Comme vous le dîtes, ce code permet de changer une fois l'état de la diode.

Si l'on veut que l'action se fasse après deux claps, il faut sans doute introduire une boucle de comptage avant la détection du clap, par exemple un while en ligne 11.

Une fois cela fait, il faudra sans doute ajuster le délai de 50 millisecondes pour régler l'écart entre les deux claps.

Je vous laisse faire le reste puisqu'ils 'agit manifestement d'un exercice.

Faîtes part de vos progressions ou blocages en repostant un code modifié et commenté par vous pour situer les blocages et joignez y les éventuels messages d'erreur.

Cordialement
Messages postés
10
Date d'inscription
mercredi 27 mai 2020
Statut
Membre
Dernière intervention
5 juin 2020

Bonjour,
Merci de m'avoir répondu.
Sans vouloir vous vexer, certes j'ai pris ce programme sur internet, mais cela fait déjà une semaine que je travaille déçu affin de trouver le bon programme, hélas en vain.
J'avais déjà eu l'idée de cette boucle de comptage mais cela a conclue par un échec.
Je vais donc retravailler ceci encore et encore comme vous l'avez dit.

Merci encore, cordialement.
Messages postés
4868
Date d'inscription
lundi 31 janvier 2011
Statut
Contributeur
Dernière intervention
11 juillet 2020
1 163 >
Messages postés
10
Date d'inscription
mercredi 27 mai 2020
Statut
Membre
Dernière intervention
5 juin 2020

C'est une bonne initiative. Je n'ai pas voulu dire que vous n'avez rien fait, mais juste qu'il faut montrer ce que vous avez fait.

Par ailleurs, quand ça coince, n'essayez pas de réussir à faire tout le code en une fois. Décomposez, en l'occurrence, fîtes un programme plus court portant sur la boucle while, pour effectuer les deux "tours", sans inclure la partie capteur de son par exemple.

Vous l'intégrerez en suite au programme complet. En tous cas, c'est ainsi que je fais et cela m'a plutôt réussi.

L'échec dont vous parlez est soit une faute de syntaxe, soit un défaut en sortie de boucle qui fait que le reste du programme n'a pas intégré le résultat. En tous cas, c'est ainsi que je fais et cela m'a plutôt réussi.a boucle .

Ceci dit, je ne suis pas un cador en programmation, mais il y en a sur CCM et il vous viendront sans aucun doute en aide, dès qu'ils verront vos premières modifs.

A vous lire.

Bonne soirée
Messages postés
5383
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
10 juillet 2020
885
Salut frozice,

Sur Arduino, tu peux quantifier le temps qui passe avec la fonction millis()

https://www.arduino.cc/reference/en/language/functions/time/millis/


Dal
Messages postés
10
Date d'inscription
mercredi 27 mai 2020
Statut
Membre
Dernière intervention
5 juin 2020

Bonjour Dal,
je n'arrive pas vraiment à utiliser cette fonction ici
Messages postés
5383
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
10 juillet 2020
885 >
Messages postés
10
Date d'inscription
mercredi 27 mai 2020
Statut
Membre
Dernière intervention
5 juin 2020

Bonjour frozice,

As-tu lu la documentation Arduino sur cette fonction ?

As-tu réfléchi à l’algorithme que tu pourrais mettre en place pour gérer l'état de ton système ? Il y a 3 états :
  • AUCUN_CLAP : état initial, ou état après PREMIER_CLAP non suivi de DEUXIEME_CLAP dans le délai prévu, ou état après PREMIER_CLAP suivi de DEUXIEME_CLAP dans le délai prévu et après exécution de l'action d'allumage ou d'extinction (remise à zéro de l'état)
  • PREMIER_CLAP : état lorsque PREMIER_CLAP se produit et que l'on est dans le délai de survenance de DEUXIEME_CLAP
  • DEUXIEME_CLAP : état lorsque PREMIER_CLAP se produit, suivi de DEUXIEME_CLAP dans le délai prévu, et où tu dois réaliser une action d'allumage ou d'extinction


La fonction
milli()
permet seulement de quantifier le temps écoulé. Elle n'est pas difficile à utiliser si tu sais déclarer une variable du bon type et y mettre le résultat de l'appel à cette fonction et faire des soustractions :-)

Qu'as-tu essayé ?

Dal
Messages postés
4868
Date d'inscription
lundi 31 janvier 2011
Statut
Contributeur
Dernière intervention
11 juillet 2020
1 163
Bonsoir à tous deux,


@ [Dal],

Je n'ai pas une grande expertise en "langage" Arduino (je fais de la robotique en utilisant un "fork" de Scratch nommé Mblock.

Mais je peux affirmer en m'appuyant sur des lectures appropriées (notamment Srackoverflow.com) que la fonction loop() ne peut être employée qu'une fois.

Elle correspond à la fonction main() en C et englobe toutes les autres fonctions après les déclarations de variables et le paramétrage du GPIO. A la différence que le programme boucle indéfiniment à la fin du bloc loop(), ce qui permet notamment de checker en permanence les variables correspondant aux entrées-sorties de la carte.

A moins que j'aie mal interprété l'expression Tu mets toute ta logique dans une seule itération de la fonction loop() et tu voudras bien dans ce cas m'en excuser.

@ frozice,

Bravo si vous le permettez d'avoir persévéré et introduit vos modifs. Vous voyez que vous progressez en surmontant vos erreurs ou votre maîtrise du langage. Comme je le disais, c'est ainsi que je procède (je lis tout de même les tutoriels sur les différents langages).

J'ai mis pour la part des mois à comprendre comment fonctionnait millis() dans certains programmes. La principale différence entre delay() et millis() est que la première fonction interrompt la fonction en cours pour exécuter une ou plusieurs autres fonctions, puis retour à la fonction de départ.

Millis() permet d'exécuter parallèlement plusieurs fonctions:

Par exemple, je lance un mouvement du robot, puis je mesure une température sur un capteur pendant 3 secondes, je pourrais lancer un autre mouvement du robot pendant ces 3 secondes, ce que je ne peux pas faire avec delay(), qui, s'il dure 10 secondes, bloque toutes les autre fonctions qu'on pourrait souhaiter lancer pendant ces 3 ou 10 secondes.

Je ne suis pas persuadé par ailleurs que millis() soit indispensable pour ce double clap, mais s'il en complique l'exécution, tant que vous n'en aurez pas la maîtrise, je vous propose d'utiliser delay() dans un premier temps, à moins que la précision entre les deux claps soit essentielle.

Par ailleurs, vous utilisez trop de while, un seul devrait suffire (voire deux) comme indiqué dans mon premier post, while() placé dans le loop() et qui engloberait l'ensemble détection de clap/action consécutive.

La fonction compteur() est parfaitement superflue comme l'indique Dal, puisque vous disposez de delay() ou millis()

Je vous incite de rester sous la houlette bienveillante de Dal, qui est bien plus qualifié que moi en programmation (je le sais parce que je le suis depuis des années et ai beaucoup appris et continue de profiter indirectement de ses conseils).

Mais si vous le permettez et le jugez utile, je ferais des commentaires de ce type en toute humilité et dans un esprit d'change.

Je n'ai pas le temps en ce moment de vous proposer une version de ce code, mais le ferai par la suite si cela s'avère utile.

Cordialement
Messages postés
10
Date d'inscription
mercredi 27 mai 2020
Statut
Membre
Dernière intervention
5 juin 2020

Si au moins quelqu'un saurait comment faire un programme où on doit juste allumer quelque chose en sortie mais pour ça il faut 2 enclenchements sur un bouton par exemple et non pas 1.

Je dois avoué que je suis désespéré ...
Messages postés
10
Date d'inscription
mercredi 27 mai 2020
Statut
Membre
Dernière intervention
5 juin 2020

Bonjour,

Ça y est j'ai réussi à faire allumer la LED avec 2 clappements grâce à des boucles while.
Ce qui se passe avec le programme ci-après, c'est que quand je clap 1 fois cela ne fait rien et si après un délaie infini je clap une 2ème fois la LED s'allume.
Donc tant que je clap 2 fois dans les mains, qu'importe le temps d'attente, la
LED va s'allumer.

Le problème maintenant c'est que je n'arrive pas à mettre un temps limite entre les 2 clappements.

Pour le délaie limite, j'ai créé un compteur de temps hors du programme principale. Je n'ai pas réussi à placer la fonction millis() car elle compte au lancement du programme et non au 1er clappement rendent nécessaire l'utilisation de soustraction à plusieurs endroits du programme ce que je trouve plus compliqué.

Merci des futurs réponses.


void setup()
{
pinMode(2, OUTPUT); // LED sur la branche pin 2
}

void compteur ()
{
int compteur ;
for (compteur < 2000 ; compteur > 2000 ; compteur = compteur + 5)
{
delay (5);
}
}

void loop()
{
int analog_val; // valeur analogique lue sur A2
static bool led_state = false; // état actuel de la LED
int compteur = 2000;
analog_val = analogRead(A2);

while (analog_val <= 10) // 1er clap
{
analog_val = analogRead(A2);
}

compteur = 0;
delay (100); // delaie entre 1er clap et 2eme clap
analog_val = analogRead(A2);

while (compteur < 1000 )
{
while (analog_val <= 10) // 2eme clap
{
analog_val = analogRead(A2);
}

if (led_state) // si la LED est allumée
{
led_state = false; // LED était allumée, maintenant éteinte
digitalWrite(2, LOW);
}

else // si la LED est éteinte
{
led_state = true;
digitalWrite(2, HIGH); // LED était éteinte, maintenant allumée
}

delay(50); // attendre que le bruit des claquements disparaisse

}
}
Messages postés
5383
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
10 juillet 2020
885
Tu mets toute ta logique dans une seule itération de la fonction
loop()
. Je suis loin d'être une autorité en Arduino, et je n'en ai pas sous la main pour tenter de déboguer ton code (si j'avais le temps et la motivation pour le faire) mais à mon sens ce n'est pas comme cela que la fonction
loop()
d'Arduino est sensée être utilisée :

https://www.arduino.cc/reference/en/language/structure/sketch/loop/

Tu dois imaginer la fonction
milli()
comme un chronomètre qui se déclenche dès que la carte Arduino commence à exécuter ton programme et qui te permet de mesurer des temps intermédiaires quand tu le souhaites.

Ta boucle
loop()
est là pour être à l'écoute des événements que les capteurs peuvent capter. Lorsque tu captes un clap, et que tu es à l'état AUCUN_CLAP, tu gardes la valeur retournée par la fonction
milli()
, comme un chronomètre prendrait un temps intermédiaire, et tu passes de l'état AUCUN_CLAP à PREMIER_CLAP.

Lorsque tu tu captes un clap, et que tu es à l'état PREMIER_CLAP, tu consultes la valeur retournée par la fonction
milli()
, et si un temps suffisant s'est écoulé par rapport au temps du clap précédent, tu as ton DEUXIEME_CLAP.

A mon sens, utiliser
delay()
, ou un autre mode de temporisation bricolé comme ta fonction
compteur()
(que tu as codée et qui est de toutes façon boguée, mais que tu n'utilises pas, avec par ailleurs une variable
compteur
dans ta fonction
loop()
fixée à 0 et qui ne bouge pas...) ne t'aidera pas, car cela suspend l'exécution du programme, alors qu'il doit, au contraire, être à l'écoute.

Renseigne toi sur la programmation des machines à états en C.

Dal
Messages postés
10
Date d'inscription
mercredi 27 mai 2020
Statut
Membre
Dernière intervention
5 juin 2020

Bonjour,
J'ai réussi a faire 2 clap pour que la led s'allume sur un temps donné. Mais le problème c'est qu'après l'avoir allumé la led ne veut plus s'éteindre.
Ci-après le programme que j'ai fais.
Je ne sais pas su tout pourquoi ça ne marche pas !
Si vous avez des réponses a ma question ...

void setup()
{
pinMode(2, OUTPUT); // LED sur la branche pin 2
}

void(* reset) (void) = 0; //declare reset function @ address 0


void loop()
{
long PREMIER_CLAP;
long DEUXIEME_CLAP;
long temps;
int analog_val; // valeur analogique lue sur A2
static bool led_state = false; // état actuel de la LED

analog_val = analogRead(A2);

while (analog_val <= 10) // 1er clap
{
analog_val = analogRead(A2);
}

PREMIER_CLAP = millis() + 200; // délaie minimum
DEUXIEME_CLAP = PREMIER_CLAP + 2000; // delaie entre 1er clap et 2eme clap
temps = millis();

while (temps < PREMIER_CLAP) // attente du délaie minimum
{
temps = millis();
}

analog_val = analogRead(A2);

while (temps < DEUXIEME_CLAP && analog_val < 10) // attente du 2eme clap ou du reset
{
analog_val = analogRead(A2);
temps = millis();
}

if (temps >= DEUXIEME_CLAP)
{
delay(50);
reset();
}

else
{
if (led_state) // si la LED est allumée
{ //
led_state = false; // LED était allumée, maintenant éteinte
digitalWrite(2, LOW); //
} //
//
else // si la LED est éteinte
{ //
led_state = true; //
digitalWrite(2, HIGH); // LED était éteinte, maintenant allumée
} //
}

delay(200); // attendre que le bruit des claquements disparaisse
reset();
}<code>
Messages postés
10
Date d'inscription
mercredi 27 mai 2020
Statut
Membre
Dernière intervention
5 juin 2020

Bonjour,
Aujourd'hui est un grand jour car j'ai enfin réussi a faire un programme qui permet d'allumer une LED en tapant 2 fois dans les mains.
Je vous envoie si après le programme.

Je tiens a remercier georges97 et Dal, sans qui je n'aurais sans doute pas réussi avant aujourd'hui.

void setup() 
{
pinMode(2, OUTPUT); // LED sur la branche pin 2
}

void(* reset) (void) = 0; //declare reset function @ address 0


void loop()
{
long PREMIER_CLAP;
long DEUXIEME_CLAP;
long temps;
int delai = 2000;
int analog_val; // valeur analogique lue sur A2
static bool led_state = false; // état actuel de la LED

analog_val = analogRead(A2);

while (analog_val <= 10) // 1er clap
{
analog_val = analogRead(A2);
}

PREMIER_CLAP = millis() + 200; // délaie minimum
DEUXIEME_CLAP = PREMIER_CLAP + delai; // delaie entre 1er clap et 2eme clap
temps = millis();

while (temps < PREMIER_CLAP) // attente du délaie minimum
{
temps = millis();
}

analog_val = analogRead(A2);

while (temps < DEUXIEME_CLAP && analog_val < 10) // attente du 2eme clap ou du reset
{
analog_val = analogRead(A2);
temps = millis();
}

if (temps >= DEUXIEME_CLAP)
{
reset();
}

else
{
if (led_state) // si la LED est allumée
{ //
led_state = false; // LED était allumée, maintenant éteinte
digitalWrite(2, LOW); //
} //
//
else // si la LED est éteinte
{ //
led_state = true; //
digitalWrite(2, HIGH); // LED était éteinte, maintenant allumée
} //

delay(200); // attendre que le bruit des claquements disparaisse
}
}
Messages postés
5383
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
10 juillet 2020
885
Bravo !

Lorsque tu postes du code sur le forum, sélectionne bien le langage "c" avec la boite déroulante à droite du symbole code (consignes détaillées là : https://codes-sources.commentcamarche.net/faq/11288-les-balises-de-code ). Ainsi, il sera plus fidèlement affiché sur le forum, avec indentation et coloration syntaxique.

Je n'ai pas pu tester ton code, et j'aurai fait différemment en ne bloquant pas l'exécution de la boucle
loop()
, mais si tu es arrivé à tes fins, c'est ce qui compte :-)

Autrement, une machine à états finis peut être codée assez facilement en C, avec des énumérations pour nommer ces états et un switch/case organisant ce que fait la machine dans chaque état, et gérant le passage d'un état à un autre. C'est avec ces outils que j'aurai personnellement travaillé. Le gros du travail est d'identifier les états et les conditions qui déclenchent le passage de l'un à l'autre. Ensuite la machine tourne toute seule, et le fait qu'elle soit dans une boucle ne pose pas de problèmes, et si ta machine ne bloque pas l'exécution de la boucle, ton Arduino pourrait faire plus d'une tâche.
Messages postés
5383
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
10 juillet 2020
885
Salut frozice,

J'ai eu un peu de temps pour illustrer sous forme de code quelques lignes d'une machine à états qui implémenterait le comportement souhaité de façon non bloquante.

Pour simplifier le code, j'ai déporté dans une fonction
do_switch_lamp()
à implémenter le changement d'état de la lampe et son extinction / allumage alternés.

Enjoy !

enum etat_clap  { AUCUN_CLAP, PREMIER_CLAP, DEUXIEME_CLAP };
enum etat_lampe { LAMPE_ETEINTE, LAMPE_ALLUMEE };

void do_switch_lamp(enum etat_lampe * lampe);

void loop()
{
    static enum etat_clap  clap = AUCUN_CLAP;
    static enum etat_lampe lampe = LAMPE_ETEINTE;
    static unsigned long temps_clap_precedent = 0;

    unsigned long temps_actuel = millis();
    int analog_val = analogRead(A2);

    /* si on a un clap */
    if (analog_val > 10) {
        switch (clap) {
            case AUCUN_CLAP:
                /* Premier CLAP */
                temps_clap_precedent = temps_actuel;
                clap = PREMIER_CLAP;
                break;
            case PREMIER_CLAP:
                if (temps_actuel < temps_clap_precedent + 2000) {
                    /* Deuxième CLAP */
                    clap = DEUXIEME_CLAP;
                } else {
                    /* Deuxième clap trop tardif, ce clap compte comme Premier CLAP */
                    clap = PREMIER_CLAP;
                    temps_clap_precedent = temps_actuel;
                }
                break;
             default:
                /* TODO: Erreur, état imprévu */
             break;
        }
        if (clap == DEUXIEME_CLAP) {
            do_switch_lamp(&lampe);
            clap = AUCUN_CLAP;
        }
        /* attendre que le bruit du clap disparaisse */
        delay(200);
    }
}
Messages postés
5383
Date d'inscription
mercredi 15 septembre 2004
Statut
Contributeur
Dernière intervention
10 juillet 2020
885
Ces quelques lignes proposent une implémentation du comportement décrit dans mon message précédent ici :

https://forums.commentcamarche.net/forum/affich-36679801-projet-sur-arduino-allumer-une-led-en-tapant-2-fois-dans-les-mains#9