I’ve recently made a post on how to make a pandemic alarming system based on low cost connected thermometers. This post was more about the organization model and business model than the technological solution and implementation. So I also wanted to continue to investigate the connected thermometer solution, mainly for the fun. As I’ve been sponsored by digitspace.com for some free hardware, it has been the opportunity for testing contact-less thermometers module.
The design I’m going to propose in this post will not apply to the low-cost connected thermometers as the technology I’m going to use is far more expensive to the one I proposed in my previous post.
That said, this design can be useful for companies, public site or free access thermometer booth anyone would like to design at low cost.
Prerequisites
Hardware involved
The involved hardware has been chosen for its convenience because I want to make it quickly and I want to reuse most of available components in my stock.
- MKRFOX1200 – Arduino Zero Board with Sigfox Communication Module
- MLX90614 Non-Contact Temperature sensor
- GP2Y0A02YK Infrared proximity sensor (to be replaced by VL53L0 see end of the post)
- 2xLED + 2xR330 Ohm
- 2xR10K for I2C pullup
The proximity sensor consumption is about 10mA so I will pilot its powering from a GPIO. The GPIO for a SAMD21 (Arduino Zero) seams limited to 2-7 mA we need to drive this current from outside. For this we can add:
- 1x 2N2222 transistor
- 1x 330 Ohm
The total price for this sensor is about 75€.
Eventually, we could add a NFC Module or RFID module to access an identity of the user and link the information with a door opening and for traceability (as much as this is legal in your country). These modules are better to be used with a buzzer to confirm card reading.
Libraries involved
The advantage of Arduino platform is to access all the libraries already packaged. That’s really cool for the quick and dirty prototyping approach.
- All the needed libraries for running MKRFOX1200 as documented in my previous post linked.
- The MLX90614 Arduino library you can also install from the Arduino Library manager searching for MLX90614.
- The ZSharpIR Library to control the GP2Y0A02YK distance sensor available from the Arduino library manager.
Thermal sensor and distance
The thermal sensor is measuring the ambient temperature and an object temperature. This object temperature is what we are interested in. The resolution is 0.14°C fitting with human body measurement.
The object temperature depends on the distance with the sensor. Si we need to determine the right distance to make the measurement. For reducing the power consumption we also need to wake up the distance sensor for a short time on regular basis.
Then we will have to manage the correct distance to have the same reference in the measurements and indicate to the user when he have to move to find it and when he have to stabilize. This will be indicated with one Led. The green led is blinking fast when you have to find the right distance, then it will blink slowly when you have to stay stable. The led will finally be On for 5 seconds once the temperature has been captured. The led color can change depends on the temperature level.
We need to investigate the temperature level to switch between over and under normal body temperature and verify what is the impact of the environmental temperature on the measured object temperature. That’s an important TODO for a such system.
Here is basically the (pseudo) code used for this
typedef enum {
WAITFORSOMEONE = 0,
SOMEONEHERE,
GOODDISTANCE,
DISTANCESTABLE,
WAITFORLEAVING
} state_e;
switch(curentState) {
case WAITFORSOMEONE:
// measure distance and compare reference
if ( distance < DIST_OUT ) {
curentState = SOMEONEHERE;
} else {
// if no-one we can go to low-power and sleep
sleepTime = 800;
}
break;
case SOMEONEHERE:
// wait for the right distance by measuring multiple point
// and keeping the min & max
// make the green led flashing fast
if ( dmin > DIST_MIN && dmax < DIST_MAX ) {
curentState = GOODDISTANCE;
} else if ( dmin > DIST_OUT ) {
curentState = WAITFORSOMEONE;
}
break;
case GOODDISTANCE:
// ensure stability of the distance
// make the green led flashing slowly
if ( distance > DIST_MIN && distance < DIST_MAX ) {
curentState = DISTANCESTABLE;
} else {
curentState = SOMEONEHERE;
}
break;
case DISTANCESTABLE:
// measure the temperature
// measure the distance once again
if ( distance > DIST_MIN && distance < DIST_MAX ) {
// reading sounds valid
// light the right led color according to
// the temperature reading and maintain it 5 seconds
curentState = WAITFORLEAVING;
} else {
curentState = SOMEONEHERE;
}
break;
case WAITFORLEAVING:
// wait for distance to be higher than our Noone reference
// during this time the led stays on
if ( distance > DIST_OUT ) {
// Siwtch leds off
curentState = WAITFORSOMEONE;
} else {
// wait a bit for people leaving
}
break;
}
Add the communication Layer
We need to report the measured information in the Sigfox frame. the temperature will be 16 bit signed encoded in centi-degree Celsius.
typedef struct __attribute__ ((packed)) sigfox_message {
int16_t envTemp;
int16_t objTemp;
uint64_t nfcId;
} SigfoxMessage;
I let 64bits to encode the lower bits of a NFC card (I’ll add this later)
Now we can send the Sigfox frame on success:
case DISTANCESTABLE:
digitalWrite(GREENLEDPIN,LOW);
envTemp = mlx.readAmbientTempC();
objTemp = mlx.readObjectTempC();
distance=ZSharpIR.distance();
if ( distance > DIST_MIN && distance < DIST_MAX ) {
// reading sounds valid
curentState = WAITFORLEAVING;
// send the message
msg.envTemp = (int16_t)(envTemp*100);
msg.objTemp = (int16_t)(objTemp*100);
msg.nfcId = 0;
SigFox.beginPacket();
SigFox.write((uint8_t*)&msg,sizeof(msg));
SigFox.endPacket(false);
digitalWrite(GREENLEDPIN,HIGH);
} else {
curentState = SOMEONEHERE;
sleepTime = 1000;
}
break;
In the Sigfox backend we can setup the associated frame decoding
envTemp::int:16:little-endian objTemp::int:16:little-endian nfcId::uint:64:little-endian
And now for each of the temperature we get the following result on the Sigfox backend:
The values here have to be divided by 100 to get the temperature in degree Celsius.
Add a RFID reader
The RFID reader uses SPI communication and it’s better to have a buzzer associated to it for the user feedback on card reading. Here is the dedicated schematic for a better reading.
The RFID code is simply added in the head of the main loop:
// Read the card is present and update the corresponding variable
if ( rfid.PICC_IsNewCardPresent() ) {
if(rfid.PICC_ReadCardSerial()) {
pinMode(BUZZ_PIN, OUTPUT);
tone(BUZZ_PIN,2000);
delay(200);
pinMode(BUZZ_PIN, INPUT); // because noTone seems to be inefficient
for (byte i = 0; i < rfid.uid.size; ++i) {
rfidId <<= 8;
rfidId |= rfid.uid.uidByte[i];
}
}
}
With the badge I have, the value returned is a 32bits value. This value will be added in the Sigfox communication. It is cleared when someone leaving or when the temperature reading has been a success.
Accuracy
The most important thing and most complex part is concerning the accuracy. Currently the solution is not accurate. Basically the measure temperature is not the real object temperature but we have something like:
T-measured = F(T-obj,T-ambient, Distance)
I need to investigate on the relation. The main limiting point is currently distance as the selected sensor does not work under so I’m going to make some test with more precised and short range distance sensors like the VL53L1X.
Improve the accuracy
The distance seems a key factor I can easily lever using a better sensor. First device received has been a VL53L0 sensor working on I2C and able to measure object distances up to 2m.
I selected the VL53L0X library from Popolu in the library manager, version 1.2.
This solution allows to have a distance to the sensor reduced to distance to a precise range from 50 to 65 mm. (This could be reduced). That way the thermal difference between the Ambient and Object is more important. I’ve got 8.3°C of delta. It sounds more promising to get accurate measurement.
The Github project has been updated to support the two sensors. Here is the updated schematics
About the accuracy, here is what I’ve obtained:
Distance | Ambient T° | Object T° |
48mm | 23.15 | 30.59 |
51mm | 23.49 | 29.97 |
50mm | 23.65 | 30.97 |
47mm | 23.71 | 31.07 |
51mm | 23.71 | 30.93 |
50mm | 23.73 | 30.77 |
51mm | 23.81 | 30.19 |
50mm | 23.91 | 30.57 |
47mm | 23.99 | 30.65 |
47mm | 23.97 | 30.81 |
Average | 30.65 | |
Standard Deviation | 0.35 |
The impact of the Ambient T° (basically when you are using it outdoor) is really high. Even the difference between Ambient and Object changes.
Distance | Ambient T° | Object T° |
50mm | 19.52 | 27.42 |
51mm | 18.89 | 27.52 |
48mm | 17.42 | 24.83 |
So the need to calibrate a such equipment with larger experimentation is really needed.
Conclusion
The system has been quickly designed and is not really expensive. That said I see some limitation:
- The proximity sensor need to allow to measure precisely the distance and close to the sensor as the distance is a key factor of temperature level measured by the sensor.
- In relation to this close and reduced distance range you want to measure the temperature, the user-experience algorithm is a key factor. With short distance, LEDs are not really relevant, sound interface is better. Both is the best.
- I do not yet master the sensor calibration to get a reliable body temperature. I assume this may be feasible as this kind of sensor are made for this but regarding environmental temperature impact and distance we need to investigation to make it correctly working.
If you are interested in making this stuff working to continue investigating on this, you can find the code available on my github.
Nice tutorial