Détection de mouvement avec l'ESP32 et un capteur de mouvement PIR
Ce tutoriel montre comment détecter un mouvement
avec l'ESP32 à l'aide d'un capteur de mouvement PIR. Dans cet exemple,
lorsqu'un mouvement est détecté (une interruption est déclenchée), l'ESP32
démarre un timer et allume une LED pendant un nombre prédéfini de
secondes. Lorsque le compte à rebours est terminé, la LED s'éteint
automatiquement.
Avec ce tutoriel, nous
explorerons également deux concepts importants : les interruptions et les timers.
Pièces requises
Pour suivre ce tutoriel, vous
avez besoin des pièces suivantes
• Mini détecteur de mouvement PIR
• LED
• Résistance 330 Ohms
• Fils de liaison
• Platine (breadboard)
Vous pouvez utiliser les liens précédents pour
trouver toutes les pièces de vos projets au meilleur prix !
Introduction aux
interruptions
Pour déclencher un événement avec un détecteur de mouvement PIR, vous utilisez des interruptions. Les interruptions sont utiles pour faire en sorte que les choses se produisent automatiquement dans les programmes du microcontrôleur et peuvent aider à résoudre les problèmes de synchronisation.
Avec les interruptions, vous n'avez pas besoin de vérifier constamment la valeur actuelle d'une broche. Avec les interruptions, lorsqu'un changement est détecté, un événement est déclenché (une fonction est appelée).
Pour définir une interruption dans l'IDE Arduino, vous utilisez la fonction attachInterrupt(), qui accepte comme arguments : la broche GPIO, le nom de la fonction à exécuter et le mode :
attachInterrupt(digitalPinToInterrupt(GPIO), function, mode);
Interruption GPIO
Le premier argument est un numéro GPIO.
Normalement, vous devez utiliser digitalPinToInterrupt(GPIO) pour définir le
GPIO réel comme broche d'interruption.
Par
exemple, si vous souhaitez utiliser GPIO 27 comme interruption, utilisez :
digitalPinToInterrupt(27)
Avec une carte ESP32, toutes les broches mises
en évidence par un rectangle rouge dans la figure suivante peuvent être
configurées comme broches d'interruption. Dans cet exemple, nous utiliserons le
GPIO 27 comme une interruption connectée au capteur de mouvement PIR.
Fonction à déclencher
Le deuxième argument de la fonction
attachInterrupt() est le nom de la fonction qui sera appelée à chaque
déclenchement de l'interruption.
Mode
Le troisième argument est le mode. Il existe 5
modes différents :
• LOW : pour déclencher l'interruption chaque
fois que la broche est LOW ;
• HIGH : pour déclencher l'interruption chaque
fois que la broche est HIGH ;
• CHANGE : pour déclencher l'interruption chaque
fois que la broche change de valeur – par exemple de HIGH à LOW ou LOW à HIGH ;
• FALLING : lorsque la broche passe de HIGH à
LOW ;
• RISING : pour se déclencher lorsque la broche
passe de LOW à HIGH.
Pour cet
exemple, nous utiliserons le mode RISING, car lorsque le capteur de mouvement
PIR détecte un mouvement, le GPIO auquel il est connecté passe de LOW à HIGH.
Introduction des Timers
Dans cet exemple, nous allons également
introduire des timers. Nous
voulons que la LED reste allumée pendant un nombre prédéterminé de secondes
après la détection d'un mouvement. Au lieu d'utiliser une fonction delay() qui
bloque votre code et ne vous permet pas de faire autre chose pendant un nombre
déterminé de secondes, nous devrions utiliser un timer.
La fonction delay()
Vous devez
être familiarisé avec la fonction delay() car elle est largement utilisée.
Cette fonction est assez simple à utiliser. Il accepte un seul nombre int comme
argument. Ce nombre représente le temps en millisecondes que le programme doit
attendre avant de passer à la ligne de code suivante.
delay(temps
en millisecondes)
Lorsque
vous faites delay(1000), votre programme
s'arrête sur cette ligne pendant 1 seconde.
delay() est
une fonction bloquante. Les fonctions de blocage empêchent un programme de
faire quoi que ce soit d'autre jusqu'à ce que cette tâche particulière soit
terminée. Si vous avez besoin que plusieurs tâches se produisent en même temps,
vous ne pouvez pas utiliser delay().
Pour la
plupart des projets, vous devez éviter d'utiliser des retards et utiliser des timers à la place.
La fonction millis()
En
utilisant une fonction appelée millis(), vous pouvez
renvoyer le nombre de millisecondes qui se sont écoulées depuis le premier démarrage
du programme.
millis()
Pourquoi
cette fonction est-elle utile ? Parce qu'en utilisant des calculs, vous pouvez
facilement vérifier combien de temps s'est écoulé sans bloquer votre code.
Clignotement d'une LED avec
millis()
L'extrait de code suivant montre comment vous pouvez utiliser la fonction millis() pour créer un projet de LED clignotante. Il allume une LED pendant 1000 millisecondes, puis l'éteint.
// les constantes ne changeront pas. Utilisé ici pour définir un numéro de broche :
const int ledPin = 26; // le numéro de la broche LED
// Les variables changeront :
int ledState = LOW; // ledState utilisé pour régler la LED
// Généralement, vous devez utiliser "unsigned long" pour les variables qui contiennent du temps
// La valeur deviendra rapidement trop grande pour qu'un int puisse la stocker
unsigned long previousMillis = 0; // enregistrera la dernière fois que la LED a été mise à jour
// Les variables changeront :
const long interval = 1000; // intervalle
de cligno
tement
(milliseconds)
void setup() {
// définissez la broche numérique
(digital) comme sortie :
pinMode(ledPin, OUTPUT);
}
void loop() {
// c'est ici que vous placeriez le code qui doit être exécuté tout le temps.
// vérifie s'il est temps de faire clignoter la LED ; c'est-à-dire si l
a
// différence entre l'heure actuelle et la dernière fois
du clignotement
// la LED est plus grande que l'intervalle auquel vous voulez
// fait clignoter la LED.
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
// si le voyant est éteint, allumez-le et vice-versa :
if (ledState == LOW) {
ledState = HIGH;
} else {
ledState = LOW;
}
// définissez la LED avec le ledState de la variable :
digitalWrite(ledPin, ledState);
}
}
Comment fonctionne le code
Examinons de plus près cette code de clignotement qui fonctionne sans fonction delay() (il utilise à la place la fonction millis()).
Ce code soustrait l'heure enregistrée précédente (previousMillis) de l'heure actuelle (currentMillis). Si le reste est supérieur à l'intervalle (dans ce cas, 1000 millisecondes), le programme met à jour la variable previousMillis à l'heure actuelle et allume ou éteint la LED.
if (currentMillis - previousMillis >= interval) {
// enregistrer la dernière fois que vous avez clignoté la LED
previousMillis = currentMillis;
(...)
Étant donné que cet extrait de code n'est pas bloquant, tout code situé en dehors de cette
première instruction if devrait fonctionner normalement.
Vous devriez maintenant être en mesure de
comprendre que vous pouvez ajouter d'autres tâches à votre fonction loop() et
que votre code fera toujours clignoter la LED toutes les secondes.
Vous pouvez télécharger ce code sur votre ESP32
et assembler le diagramme schématique suivant pour le tester et modifier le
nombre de millisecondes pour voir comment cela fonctionne.
ESP32 avec capteur de
mouvement PIR
Après avoir
compris ces concepts : les interruptions et les timers, poursuivons le projet.
Schéma
Le circuit que nous allons construire est facile
à assembler, nous allons utiliser une LED avec une résistance. La LED est
connectée au GPIO 26. Nous utiliserons le capteur de mouvement PIR Mini AM312
qui fonctionne à 3,3 V. Il sera connecté au GPIO 27. Suivez simplement le
schéma suivant.
Important: le capteur de
mouvement PIR Mini AM312 utilisé dans ce projet fonctionne à 3,3 V.
Cependant, si vous utilisez un autre capteur de mouvement PIR comme le
HC-SR501, il fonctionne à 5V. Vous pouvez soit le modifier pour qu'il
fonctionne à 3,3 V, soit simplement l'alimenter à l'aide de la broche Vin.
La figure suivante montre le brochage du
capteur de mouvement AM312 PIR.
Téléchargement du code
Après avoir câblé le circuit comme indiqué dans le schéma, copiez le code fourni dans votre IDE Arduino.
Vous pouvez télécharger le code tel quel ou vous pouvez modifier le nombre de secondes pendant lesquelles la LED est allumée après la détection d'un mouvement. Changez simplement la variable timeSeconds avec le nombre de secondes que vous voulez.
#define timeSeconds 10
// Définir les GPIO pour le capteur de mouvement LED et PIR
const int led = 26;
const int motionSensor = 27;
// Timer: Variables auxiliaires
unsigned long now = millis();
unsigned long lastTrigger = 0;
boolean startTimer = false;
// Vérifie si un mouvement a été détecté, règle la LED sur HIGH et démarre une minuterie
void IRAM_ATTR detectsMovement() {
Serial.println("MO
UVEMENT DETECTE!!!");
digitalWrite(led, HIGH);
startTimer = true;
lastTrigger = millis();
}
void setup() {
// Port série à des fins de débogage
Serial.begin(115200);
// Mode capteur de mouvement PIR INPUT_PULLUP
pinMode(motionSensor, INPUT_PULLUP);
// Définissez la broche motionSensor comme interruption, affectez la fonction d'interruption et définissez le mode RISING
attachInterrupt(digitalPinToInterrupt(motionSensor), detectsMovement, RISING);
// Réglez la LED sur
LOW
pinMode(led, OUTPUT);
digitalWrite(led, LOW);
}
void loop() {
// Current time
now = millis();
// Étein
dre
la LED après le nombre de secondes défini dans la variable timeSeconds
if(startTimer && (now - lastTrigger > (timeSeconds*1000))) {
Serial.println("Motion stopped...");
digitalWrite(led, LOW);
startTimer = false;
}
}
Comment fonctionne le code
Jetons un coup d'œil au code. Commencez par attribuer deux broches GPIO aux variables led et motionSensor.
// Définir les GPIO pour le capteur de mouvement LED et PIR
const int led = 26;
const int motionSensor = 27;
Ensuite, créez des variables qui vous permettront de définir une minuterie pour éteindre la LED après la détection d'un mouvement.
// Timer: Auxiliar variables
long now = millis();
long lastTrigger = 0;
boolean startTimer = false;
La variable
"now" contient
l'heure actuelle. La variable lastTrigger contient l'heure à laquelle le
capteur PIR détecte un mouvement. Le startTimer est une variable booléenne qui
démarre la minuterie lorsqu'un mouvement est détecté.
setup()
Dans le setup(), commencez par initialiser le port série à 115200 bauds.
Serial.begin(115200);
Définissez le capteur de mouvement PIR comme INPUT PULLUP.
pinMode(motionSensor, INPUT_PULLUP);
Pour définir la broche du capteur PIR comme une interruption, utilisez la fonction attachInterrupt() comme décrit précédemment.
attachInterrupt(digitalPinToInterrupt(motionSensor), detectsMovement, RISING);
La broche qui détectera le mouvement est le GPIO
27 et appellera la fonction detectsMovement() en mode RISING.
La LED est un OUTPUT dont l'état commence sur LOW.
pinMode(led, OUTPUT);
digitalWrite(led, LOW);
loop()
La fonction loop() s'exécute constamment encore et encore. Dans chaque boucle, la variable now est mise à jour avec l'heure actuelle.
now = millis();
Rien d'autre n'est fait dans la boucle().
Mais, lorsqu'un mouvement est détecté, la fonction detectsMovement() est appelée car nous avons précédemment défini une interruption dans setup().
La fonction detectsMovement() imprime un message dans le moniteur série, allume la LED, définit la variable booléenne startTimer sur true et met à jour la variable lastTrigger avec l'heure actuelle.
void IRAM_ATTR detectsMovement() {
Serial.println("MO
UVEMENT DETECTE!!!");
digitalWrite(led, HIGH);
startTimer = true;
lastTrigger = millis();
}
Remarque : IRAM_ATTR est utilisé pour exécuter le
code d'interruption dans la RAM, sinon le code est stocké dans la mémoire flash
et il est plus lent.
Après cette étape, le code retourne à la boucle loop().
Cette fois, la variable startTimer est vraie. Ainsi, lorsque le temps défini en secondes s'est écoulé (depuis la détection du mouvement), l'instruction if suivante sera vraie.
if(startTimer && (now - lastTrigger > (timeSeconds*1000))) {
Serial.println("
Mouvement arrêté...");
digitalWrite(led, LOW);
startTimer = false;
}
Le message
"Mouvement arrêté…" sera imprimé dans le moniteur série, la LED
s'éteindra et la variable startTimer sera définie sur faux.
Démonstration
Téléchargez le code sur votre carte ESP32.
Assurez-vous d'avoir sélectionné la bonne carte et le bon port COM.
Ouvrez le moniteur série à un débit en bauds de
115 200.
Déplacez votre main devant le capteur PIR. La
LED doit s'allumer et un message est imprimé dans le moniteur série indiquant
"MOUVEMENT
DETECTE!!!". Après 10 secondes, la LED
doit s'éteindre.
Résumé
les
interruptions sont utilisées pour détecter un changement d'état GPIO sans qu'il
soit nécessaire de lire en permanence la valeur GPIO actuelle. Avec les
interruptions, lorsqu'un changement est détecté, une fonction est déclenchée.
Vous avez également appris à définir une minuterie simple qui vous permet de
vérifier si un nombre prédéfini de secondes s'est écoulé sans avoir à bloquer
votre code.