IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Cours complet pour apprendre à programmer un Arduino


précédentsommairesuivant

XXI. Perroquet

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.

XXI-A. Éléments pour nécessaire

  • une carte Arduino
  • un piézo
  • une LED
  • une résistance entre 500 - 1 Mega Ohm
  • un peu de ruban adhésif.

XXI-B. Première étape

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.

XXI-B-1. Schéma et montage

Image non disponible

XXI-B-2. Programme

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
////////// 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);
    }
}

XXI-C. Deuxième étape

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.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
////////// 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 digitale 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 impact 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
    }
}

XXI-D. Réglage du SEUIL et du filtre ANTIREBOND

Pour que votre programme fonctionne correctement il vous faut ajuster les constantes SEUIL et ANTIREBOND.

 
Sélectionnez
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.

XXI-E. Les fonctions logiques (et) et (ou)

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.

 
Sélectionnez
1.
2.
3.
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.

 
Sélectionnez
1.
2.
3.
if (marqueurTemps [posTableau] == 0 || posTableau == NOMBREMARQUEURS) {
    ...
}

XXI-F. Troisième étape

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 rejoués.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
////////// 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"); // envoi 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 impact 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);                 // attendre 10 millisecondes
            digitalWrite(LED, LOW);   // éteindre la broche de la LED
            // on mémorise le temps écoulé entre chaque impact
            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"); // envoi 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"); // envoi 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 millisecondes
            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"); // envoi 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.

XXI-G. Les tableaux

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 ArduinoProgrammer Arduino »). Ensuite nous définissons le nombre de variables qu'il comporte avec la constante NOMBREMARQUEURS.

 
Sélectionnez
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 :

 
Sélectionnez
1.
2.
3.
4.
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).

 
Sélectionnez
1.
2.
3.
4.
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.

XXI-H. Fonction DEBUG

Quand vous devez écrire un programme, il est bon de laisser les lignes de code qui vous ont permises de déboguer 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.

 
Sélectionnez
        if(DEBUG == true) Serial.println("mode 1"); // envoi du mode

Si la condition est écrite sur une seule ligne les accolades ne sont pas nécessaires.

XXI-I. Pour aller plus loin

Pour aller plus loin, vous pouvez peut-être améliorer l'actionneur piézo 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 pas détériorer votre carte Arduino. Il est aussi possible d'implémenter une fonction boucle pour fabriquer un séquenceur mécanique…


précédentsommairesuivant

Ce cours est publié sous licence GPLv2, peut être lu et copié librement.