Dans un article précédent, j’avais découvert le principe de fonctionnement du capteur MLX90614. Le composant que j’avais acheté ayant un champ de vue très large, l’application la plus adaptée n’était pas tant la prise de température que la détection de présence. On s’essaie donc au montage assez simple d’un point de composant, mais plus complexe concerna la partie Arduino. Pour réaliser ce montage, il faudra:
- une plaque de prototypage
- une carte Arduino
- un capteur MLX90614 BAA ou autre xxA à large champ de vue
- un bouton poussoir
- une LED et une résistance de 10 KOhms
Le Montage
On réalise le montage ci-dessous. Attention, l’ensemble est alimenté en 3.3V à cause du composant MLX90614:

On upload dans l’Arduino le code suivant:
// 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;
}
Fonctionnement
Le fonctionnement de ce montage est le suivant:
- Régulièrement, l’Arduino déclenche une mesure sur le MLX et 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
- à 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
La vidéo ci-dessous illustre ce comportement. On commence par brancher, l’Arduino. A ce moment, la détection est erratique, on effectue donc la calibration. Une fois la calibration effectuée, la détection est très fine comme on le voit avec les différents passages de la main. Pour une application de détection de passage d’une personne dans un couloir, une cage d’escalier ou une porte (donc passage à moins d’un mètre), la détection est très performante.

