Dans ce projet nous allons réaliser un système qui permet d'enregistrer et répéter des séries d’impacts effectués sur un objet. Pour cela nous allons utiliser un capteur piézoélectrique qui permet de mesurer une vibration qui se propage dans un matériau. Pour information, ce capteur peut aussi servir de petite enceinte pour produire des sons. Pour afficher l'information enregistrée par le programme nous utiliserons une LED.
|
Pour commencer, votre piézo doit être nu, et la pastille métallique doit être fixée sur un support tel qu’une table avec un bout de ruban adhésif qui le maintient en pression contre votre support. Nous devons ensuite choisir notre résistance pour régler la nervosité de la réponse de notre capteur. Il faut savoir que plus la résistance utilisée est grande, plus le capteur produira une réponse lente, à l'inverse, plus la résistance est faible plus le capteur nous donnera une réponse rapide. Pour bien comprendre ces notions nous allons réaliser le montage de notre piézo et afficher les valeurs captées sur notre ordinateur. Cette étape nous permettra de bien choisir notre résistance ainsi que de bien comprendre l'utilisation de ce capteur.
////////// Déclaration des variables const int CAPTEUR = A0; // le piézo est connecté à la broche Analogue 0 int lectureCapteur = 0; // variable pour stocker la valeur du capteur ////////// Initialisation void setup() { Serial.begin(9600); // configurer le port série } ////////// Boucle principale void loop() { // lecture de la valeur du piézo lectureCapteur = analogRead(CAPTEUR); // envoi de la valeur à l'ordinateur if (lectureCapteur > 0) // fera s'afficher toute valeur supérieure à zéro { Serial.println(lectureCapteur, DEC); } }
Nous devons maintenant introduire au code deux nouvelles fonctions. La première nous permettra de déterminer à partir de quelle valeur analogique captée nous considérons que le capteur détecte un impact. Cette fonction est un seuil qui nous permettra de mesurer le temps écoulé entre chaque impact. La deuxième fonction (ANTIREBOND) que nous devons introduire est une fonction de filtrage qui nous permettra d'éviter que le programme enregistre plusieurs impacts lorsqu'un seul impact est donné. Pour mesurer le temps, nous utiliserons la fonction millis() qui nous permet de connaître à tout moment le temps écoulé depuis le démarrage du programme.
////////// Déclaration des variables const int CAPTEUR = A0; // le Piezo est connecté à la pin Analogue 0 int lectureCapteur = 0; // variable pour stocker la valeur du capteur const int LED = 13; // LED connectée à la broche digital 13 const int SEUIL = 1; // choix du seuil de détection const int ANTIREBOND = 600; // choix du filtre anti-rebond long temps = 0; // variable pour mémoriser le temps ////////// Initialisation void setup() { pinMode(LED, OUTPUT); // définir la pin associée à LED comme sortie Serial.begin(9600); // configurer le port série } ////////// Boucle principale void loop() { // lecture de la valeur du Piezo lectureCapteur = analogRead(CAPTEUR); // si la valeur captée est supérieure au seuil choisi et // que le temps écoulé depuis le dernier impacte est // supérieur au temps de l'ANTI-REBOND, // alors on rentre dans la condition if (lectureCapteur >= SEUIL && millis() - temps >= ANTIREBOND) { // envoi de l'information à l'ordinateur Serial.println("impact"); temps = millis(); // mise à jour du temps courant } else { // on ne fait rien } }
Pour que votre programme fonctionne correctement il vous faut ajuster les constantes SEUIL et ANTIREBOND.
const int SEUIL = 1; // choix du seuil de détection const int ANTIREBOND = 600; // choix du filtre anti-rebond
La constante SEUIL vous permet de supprimer les parasites éventuellement présents dans le signal capté. Plus la valeur de cette constante est élevée, plus il faudra taper fort pour déclencher l'enregistrement de l'impact.
La constante ANTIREBOND définit un temps durant lequel la lecture de l'entrée Analogique n'est pas active. Ce temps permet de filtrer le signal d'entrée car le capteur peut produire plusieurs signaux pour un seul impact. L'idée est donc d'enregistrer le premier signal et de fermer la lecture pendant un court instant pour ne pas enregistrer les signaux résiduels.
Dans le programme ci-dessus nous avons utilisé un opérateur logique &&. Cet opérateur nous a permis d'introduire plusieurs conditions à la fonction if(), puisque nous voulions que TOUTES les conditions soient vraies pour que les instructions s'exécutent. Seul (vrai && vrai) retourne une valeur vraie, alors que (vrai && faux) et (faux && vrai) retournent tous deux faux.
Ci-dessous l’opérateur logique && (et) nous permet de rentrer dans la fonction if() seulement si les deux conditions sont vraies.
if (lectureCapteur >= SEUIL && millis () - temps >= ANTIREBOND) { ... }
Ci-dessous l’opérateur logique || (ou) nous permet de rentrer dans la fonction if() si l'une ou l'autre des conditions est vraie.
if (marqueurTemps [posTableau] == 0 || posTableau == NOMBREMARQUEURS) { ... }
Dans cette étape nous allons implémenter un mécanisme qui va nous permettre de formaliser notre scénario d'utilisation qui comporte deux modes différents : le MODE ÉCOUTE et le MODE JEUX. Cette troisième étape introduit aussi plusieurs astuces pour que le programme puisse fonctionner dans son ensemble notamment un concept permettant de définir les conditions de passage d'un mode à un autre ainsi que l'ajout d'une LED facilitant la visualisation les impacts enregistrés puis re-joués.
////////// Déclaration des variables // ces variables sont constantes const int LED = 13; // LED connectée à la pin digitale 13 const int CAPTEUR = A0; // Piezo connecté à la pin Analogue 0 const int SEUIL = 1; // seuil de détection du capteur const int ANTIREBOND = 200; // filtre anti-rebond const int FIN = 2000; // temps pour définir la fin du mode écoute const int NOMBREMARQUEURS = 50; // nombre maximum de marqueurs temps // ces variables changent int lectureCapteur = 0; // valeur du capteur int ledEtat = LOW; // état de la LED int mode = 1; // mode écoute (1) ou jeux (2) int posTableau = 0; // Position dans le tableau long temps = 0; // variable pour mémoriser le temps long marqueurTemps[NOMBREMARQUEURS]; // tableau pour mémoriser les temps qui séparent chaque impacte int i = 0; // variable pour parcourir la liste boolean DEBUG = false; // activer ou non le DEBUG boolean BOUCLE = false; // TODO void setup() { pinMode(LED, OUTPUT); // déclarer la pin en sortie Serial.begin(9600); // configurer le port série } ////////// Boucle principale void loop() { switch(mode) { case 1: // mode enregistrement if(DEBUG == true) Serial.println("mode 1"); // envoie du mode // lecture de la valeur du capteur Piezo lectureCapteur = analogRead(CAPTEUR); // si la valeur captée est supérieure au seuil choisi et // que le temps écoulé depuis le dernier impacte est supérieur au temps de l'ANTIREBOND // alors on rentre dans la condition if (lectureCapteur >= SEUIL && millis() - temps >= ANTIREBOND) { marqueurTemps[posTableau] = millis() - temps; // digitalWrite(LED, HIGH); // activer la broche de la LED delay(5); // atendre 10 milisegonde digitalWrite(LED, LOW); // éteindre la broche de la LED // on memorise le temps écoulé entre chaque impacte posTableau++; // on incrémente la position temps = millis(); // initialisation } // si le temps écoulé depuis le dernier impact est supérieur // au temps dit de FIN et que plus de deux impacts sont enregistrés // alors on rentre dans la condition if (millis() - temps >= FIN && posTableau >= 2) { posTableau = 0; // initialiser la position mode = 2; // choisir le mode 2 if (DEBUG == true) Serial.println("mode 2"); // envoie du mode temps = millis(); // initialisation du temps } break; // sortir du mode 1 case 2: // mode de jeux // lecture de la valeur du capteur Piezo lectureCapteur = analogRead(CAPTEUR); // si la valeur du capteur est supérieure au seuil // alors on entre dans la condition puisque l'usager rejoue if (lectureCapteur >= SEUIL) { // on efface toutes les valeurs du tableau for (i=0; i<NOMBREMARQUEURS; i++) { marqueurTemps[i] = 0; } posTableau = 0; // initialiser la position mode = 1; // choisir le mode 1 if (DEBUG == true) Serial.println("mode 2 stop"); // envoie du mode temps = millis(); // initialisation du temps break; // sortir du mode 2 } // si la valeur de temps stockée dans le tableau n'est pas nulle // et que cette valeur de temps est dépassée par le conteur millis() // alors on entre dans la condition if ( marqueurTemps[posTableau] != 0 && millis() - temps >= marqueurTemps[posTableau] ) { digitalWrite(LED, HIGH); // activer la broche de la LED delay(5); // attendre 5 milisegonde digitalWrite(LED, LOW); // éteindre la broche de la LED posTableau++; // on incrémente la position temps = millis(); // initialisation du temps } // si la valeur de temps stockée dans le tableau est nulle // ou que nous arrivons à la fin du tableau // alors on entre dans la condition if ( marqueurTemps[posTableau] == 0 || posTableau == NOMBREMARQUEURS ) { for (i=0; i<NOMBREMARQUEURS; i++) { // on efface toutes les valeurs du tableau marqueurTemps[i] = 0; } posTableau = 0; // initialiser la position mode = 1; // changer de mode if(DEBUG == true) Serial.println("mode 2 end"); // envoie du mode temps = millis(); // initialisation du temps } break; // sortir du mode 2 } }
Ce programme peut sembler complexe et comporte une multitude de fonctions. Pour démystifier ces mécanismes, voici quelques explications supplémentaires.
Nous allons tout d'abord revenir sur les tableaux. Nous avons utilisé un tableau nommé marqueurTemps pour stocker les valeurs de temps qui séparent chacun des impacts. Notre tableau est un conteneur qui permet de stocker une liste de variables. Pour utiliser un tableau, nous devons tout d’abord le déclarer au même niveau que les variables (voir chapitre « Programmer Arduino »). Ensuite nous définissons le nombre de variables qu'il comporte avec la constante NOMBREMARQUEURS.
const int NOMBREMARQUEURS = 50; // nombre maximum de marqueurs temps long marqueurTemps [NOMBREMARQUEURS]; // tableau pour mémoriser les temps
Pour écrire une valeur dans une case du tableau nous devons utiliser deux variables, soit une pour choisir la position dans le tableau où nous souhaitons enregistrer celle-ci (posTableau) et une pour la valeur à inscrire (val). Nous allons ici écrire la valeur 127 dans la deuxième case du tableau :
int posTableau = 2; // initialisation de posTableau à 2 long val = 127; // initialisation de val à 127 marqueurTemps [Position] = valeur;
Pour accéder à la valeur que nous avons stockée dans la deuxième case du tableau, nous devons encore utiliser deux variables, soit une variable de position (posTableau) et une variable pour contenir la valeur que nous souhaitons lire (val).
int posTableau = 2; // initialisation de posTableau à 2 int val = 0; // initialisation de val à 0 val = marqueurTemps [posTableau];
La valeur contenue dans val est maintenant égale à 12.
Quand vous devez écrire un programme, il est bon de laisser les lignes de code qui vous ont permises de débuger votre programme. Cependant comme ces lignes de code utilisent des ressources processeur pour transmettre les informations sur le port série, il faut pouvoir les désactivées quand le programme doit fonctionner normalement. Pour cela vous pouvez utiliser des variables booléennes qui vous permettront d'activer ou pas le mode DEBUG du programme.
if(DEBUG == true) Serial.println("mode 1"); // envoie du mode
Si la condition est écrite sur une seule ligne les accolades ne sont pas nécessaires.
Pour aller plus loin, vous pouvez peut-être améliorer l’actionneur piezo en le remplaçant par un électro-aimant qui vous permettra de produire un son acoustique (un percuteur mécanique). Cependant il faut faire attention à la consommation de l'électro-aimant qui demande plus de 20 mA. La démarche consiste alors à utiliser un transistor pour ne par détériorer votre carte Arduino. Il est aussi possible d’implémenter une fonction boucle pour fabriquer un séquenceur mécanique...
Il y a une erreur de communication avec le serveur Booktype. Nous ne savons pas actuellement où est le problème.
Vous devriez rafraîchir la page.