Bonjour,
je viens vous présenter un démarrage de projet de détecteur de présence. Il est réalisé à partir d'un capteur de température infrarouge MLX90614. La version que j'avais acheté se révèle à grand angle de vue - 90°. Du coup, l'application prise de température n'étaient pas très adaptée.
Mais l'application détecteur de mouvement marche assez bien. Voici le montage:
Et le code à uploader: (dispo ici: Arduino Cloud)
// Include FIFO array
#include <CircularBuffer.h>
// Include dependencies for MLX communication
#include <Adafruit_MLX90614.h>
// Variables
const unsigned long measurement_period = 50; // delay between two measurements in ms
const unsigned int length_measurements = 20; // nb of consecutive measurements for calirbaiton and measurement
const byte pin_led = 8; // Pin to connect LED (LED blinks for calibration phase et flash when presence detected
const byte interruptPin = 2; // Declare pin 2 as pin for interrupt button
volatile boolean calibration_flag = false; // Flag to pass interruption to Arduino loop()
unsigned long currentMillis = 0; // Store current time at beginning of Arduino loop()
unsigned long measurement_timer = 0; // Check if it is time for measurement
unsigned long detection_timer = 0; // Check if it is time for presence detection
boolean isPresenceDetectedBefore = false;
boolean isPresenceDetectedNow = false;
boolean stateChange = false;
int LED_state = LOW; // State for LED
CircularBuffer<float,length_measurements> measure_data; // Array to store measurements
CircularBuffer<float,length_measurements> calibration_data; // Array to store measurements from calibration
// Instanciate MLX component
Adafruit_MLX90614 myMLX = Adafruit_MLX90614();
// Instanciate here all required: Serial output, led, interrupts and MLX
void setup() {
// Open Serial for output
Serial.begin(9600);
// Set pin for LED
pinMode(pin_led, OUTPUT);
// Set pin for button acting through interruption
// INPUT_PULLUP mode allows using internal resistor and connect directly button to GND and pin
pinMode(interruptPin, INPUT_PULLUP);
// Attach interruption
attachInterrupt(digitalPinToInterrupt(interruptPin), start_calibration_sequence, FALLING);
// MLX equipment declaration
myMLX.begin();
}
// Implementation using timer based event.
// Allow looping rapidly over possible states to handle, and sync tasks to be performed based on timer or interrupts
void loop() {
// Retrieve current time for timer handling
currentMillis = millis();
// Handle calibration sequence: calibration sequence makes use of delay hence cannot be included in interrupt
if (calibration_flag){
calibration_sequence();
}
// Handle measurement sequence: add in FIFO buffer new measure every <measurement_period>
if (currentMillis - measurement_timer >= measurement_period) {
measurement_timer = currentMillis;
// Measure now
Serial.println(myMLX.readObjectTempC());
measure_data.push(myMLX.readObjectTempC());
}
// Handle detection assessment sequence: regularly assess if presence is detected
if (currentMillis - detection_timer >= measurement_period) {
// Assess presence and react
isPresenceDetectedNow = presence_detected();
// Check if detection state changes switches through old and new state
// This is required to enable LED ON or LED OFF only when detection state is changed
stateChange = isPresenceDetectedNow xor isPresenceDetectedBefore;
isPresenceDetectedBefore = isPresenceDetectedNow;
detection_timer = currentMillis;
}
// Handle detection reaction in case presence is now detected
if (isPresenceDetectedNow and stateChange){
LED_state = HIGH;
stateChange = false;
digitalWrite(pin_led, LED_state);
}
// Handle non detection reaction in case presence is now non detected
if (!isPresenceDetectedNow and stateChange){
LED_state = LOW;
stateChange = false;
digitalWrite(pin_led, LED_state);
}
}
// Event linked to button interrupt setiing calibration sequence flag
void start_calibration_sequence() {
calibration_flag = true;
}
// Function to assess if presence is detected using calibration data and measurement data
boolean presence_detected(){
float avg_calibration = 0;
float avg_measurements = 0;
// Compute average of calibration data and measured data
for(unsigned int idx = 0;idx<length_measurements;idx++){
avg_calibration += calibration_data[idx]/length_measurements;
avg_measurements += measure_data[idx]/length_measurements;
}
// Decide depending on difference
return (abs(avg_measurements - avg_calibration))>0.1;
}
// Function to implement calibration sequence
void calibration_sequence(){
Serial.println("Start calibration");
// Blink LED rapidly to inform calibration starts
for(int i=0;i<10;i++){
digitalWrite(pin_led, HIGH);
delay(50);
digitalWrite(pin_led, LOW);
delay(50);
}
// Measures calibration data
for(int i=0;i<10;i++){
calibration_data.push(myMLX.readObjectTempC());
delay(measurement_period);
}
// Set flag back to false
calibration_flag = false;
}
Si vous ouvrez le traceur série, vous verrez en direct les changements détectés par votre capteur.
La LED sert à confirmer qu'une présence est détectée.
J'arrive à détecter facilement une personne dans un couloir ou une cage d'escalier.
Le fonctionnement de ce montage est le suivant:
- Régulièrement, l’Arduino déclenche une mesure sur le MLX est l’enregistre dans un buffer
- Régulièrement, l’Arduino vérifie si les informations enregistrées permettent de conclure à une présence ou non
- A tout moment, le bouton peut interrompre ce comportement et déclencher une phase de calibration: à ce moment, une succession de mesures est effectuée et sert de référence pour la détection de présence
Si vous voulez une démo vidéo de ce montage, j'en ai postée une ici: Initiation électronique #3 - Détecteur de présence infrarouge - YouTube
Maintenant, j'aimerais rendre ce montage embarqué sur une carte indépendante de ma carte arduino, et remplacer la LED par un relais, pour permettre de déclencher une application électrique tierce sur la détection de mouvement (sirène, spot lumineux, ...)
Mais je ne sais pas si ma méthode de détection (moyenne glissante) se prête bien à l'application de détection ?