You can experience body measurements to detect ill people everywhere - at entrance of offices, doctor offices, airports. But how to do this measurement?
One of reliable solution, how to measure all visitors is to use industry-level thermographic camera, but this kind of device costs around ~$30k - small companies are not able to pay so large investment and you can see it only on places like airports.
Few hackers got an idea to create this kind of device themselves with Arduino and standard temperature sensors (like DS18B20), but to measure human body temperature accurately is little magic and most of these sensors are not designed for this mission - to calculate body temperate is different than surface temperature (you need to take into calculation room temperature).
There is widely common solution you have probably already met - there is a dedicated person with contactless thermometer gun and the person makes a measurement of every incomer before entrance the building.
This kind of device works pretty well (±0.2°C - these devices are calibrated for body temperature measurement), it's affordable, but you have a single point of contact with every incomer and you could spread of disease by that person.
Project Goals
Main goal of our device is aiming to improve the scenario with thermometer gun, in these areas mainly:
- to remove a contact with any person
- to speed up the workflow
- make a solution scaleable (you would not need multiple persons, only more instances of device)
- save measured data for real-time info and future analysis
- make a solution cheap as possible
To make a device contactless, we had to integrate it with proximity sensor - when the device detects somebody next to thermometer, it should "press the trigger button" for person automatically to avoid any contact with person or with surface of the button. When the measurement is finished, the device should send measured data to cloud for processing.
Our StoryWe had one Raspberry Pi 4 board available - it has enough GPIO ports, RPi4 is also capable to provide power supply for thermometer itself and for proximity sensor + it has enough performance we need => so we decided to use Raspberry Pi. You could build this kind of device on another platform, only keep on mind you will need GPIO ports and capability to run scikit.
Hardware ChangesHow To Get Data From Thermometer - Reverse Engineering
The thermometer workflow is simple - when user press trigger button, it turns on the thermometer and make a one measurement.
As first step, we had to figure out how to get data from thermometer. As first step, we opened the original device enclosure and saw on circuit board few jumpers, probably used for debugging purposes by manufacturer.
One of these jumpers, JP15 looked like serial port. We attached a logic analyzer and tried various settings (baud rate+bits) to capture data from the serial port.
And we were lucky - after few attempts, we found there is readable ASCII output (after every measurement) from this jumper with baud speed 115 200 settings.
'27'[033mW' '(0)' 'MAIN:' 'JUHONG' '2.8.1' 'Apr' '' '9' '2020' '17:13:07'27'[0m\n
'27'[033mW' '(121)' 'NSA:' 'model' 'MTP10BXF55COMMAXC001'27'[0m\n
2363' '2363' '2363' '2363' '2363' '2363' '2363' '2363' '2363' '\n
3371' '3392' '3406' '3450' '3465' '3481' '3493' '3495' '3500' '\n
In Python script we read the data by this code via UART0 RXD port on Raspberry Pi:
ser = serial.Serial("/dev/ttyS0", 115200)
while True:
received_data = ser.read()
time.sleep(0.03)
data_left = ser.inWaiting()
received_data += ser.read(data_left)
For more details, please see listen_uart_rx method in connectedthermometer.py file
Connect Proximity Sensor
For connection of proximity sensor we used HC-SR04 sensor, based on this great tutorial on tutorials-raspberrypi.com
You need sensor and 330Ω+470Ω resistors only for the feature.
For more details, please see distance method in connectedthermometer.py
Control the Button & Replace Power Source
As next step we need to extend "trigger button" (called K1 on the board) to be controlled by our software (via GPIO). We had to solder photocoupler PC817B next to button and connect it to Raspberry Pi GPIO port. Button click is simulated by turning on GPIO port for 0.1sec.
print ("Simulating button...")
GPIO.output(GPIO_BUTTON, GPIO.HIGH)
time.sleep(0.1)
GPIO.output(GPIO_BUTTON, GPIO.LOW)
Originally the thermometer have been powered by two AA batteries. We were switched the battery power source to 3V3 pin+GND from Raspberry Pi. Thanks to that, we will don't have to care about battery replacement.
See the schema below for wiring.
Model New Enclosure & StandI designed in OpenSCAD new enclosure with holes for display, sensors and with supports to be mounted on standard lighting studio stand and printed on 3D printer.
I also added some holders, to secure all the components inside (sensors, display) from falling down.
You can download all printable parts on links below the article.
Understand DataLast step was to understand messages sent by device via serial line. If you remember ASCII output from device:
'27'[033mW' '(0)' 'MAIN:' 'JUHONG' '2.8.1' 'Apr' '' '9' '2020' '17:13:07'27'[0m\n
'27'[033mW' '(121)' 'NSA:' 'model' 'MTP10BXF55COMMAXC001'27'[0m\n
2363' '2363' '2363' '2363' '2363' '2363' '2363' '2363' '2363' '\n
3371' '3392' '3406' '3450' '3465' '3481' '3493' '3495' '3500' '\n
First two lines in message are static intro (JUHONG is manufacturer) and rest of data are HW info about circuit version and info about firmware.
Lines #3, #4 are important. We assume, that CPU makes 9x measurements during one click: paired values <room temperature, body temperature>:
At example above:
Measurement #1: 23.63°C;33.71°C
Measurement #2: 23.63°C;33.92°C
Measurement #3: 23.63°C;34.06°C...
ARM CPU on board takes all these values and performs some magic (because room temperature has effect on body temperature - e.g. body temperature 34° at 23° means 35°, but same body temperature 34° at room temperature 29° means 40.2°), before it returns value 36.7°C on LCD display.
The question is, how to get the real value, display on LCD from device?
We considered multiple ideas - one of the idea was to download and reverse-engineer firmware from ARM CPU, but that looked really complicated. Other idea was to replace hardware connection on integrated circuit between ARM CPU and LCD CPU to GPIO, but that had high risk to damage whole circuit.
We decided to use machine learning and saved result from hundreds of measurements with expected LCD temperatures together.
With all these values, we launched a scikit-learn library to train our model based on all these measurements. Scikit-learn generated a model for our purpose and we were able to call it in our python script - we send all measured data to the model, and output is temperature displayed on LCD.
Train the Model
You need to create another python script for creating a model. Output model will be create by the script as output to file model.joblib
#!/usr/bin/env python3
import pandas as pd
from matplotlib import pyplot
from mpl_toolkits.mplot3d import Axes3D
from sklearn.model_selection import cross_val_score
from sklearn.tree import DecisionTreeRegressor
from sklearn.ensemble import RandomForestRegressor
import xgboost as xgb
from sklearn.model_selection import train_test_split
df = pd.read_excel('measurements.xlsx')
df.drop("Time", axis=1, inplace=True)
df.drop(df[df['Display'] == 'H1'].index, inplace=True)
df.drop(df[df['Display'] == 'Lo'].index, inplace=True)
df.drop(df[df['Display'] == 'Err1'].index, inplace=True)
df.drop(df[df['Display'] == 'Err2'].index, inplace=True)
df['Display'] = df['Display'].astype(float)
X, X_test, Y, Y_test = train_test_split(df.drop('Display',axis=1), df['Display'], test_size=0.05)
regressor = RandomForestRegressor(n_estimators=500)
regressor.fit(X,Y)
import joblib
joblib.dump(regressor, 'model.joblib')
In our main script, we will load the trained model and call it this way:
predicter = joblib.load('./model.joblib')
body_temp = predicter.predict(np.array(combined_temperatures).reshape(1,-1))
Send Data to CloudWhen the "real" (LCD) body temperature is calculated via machine learning, we send the data into Azure IoT Hub.
iot_hub_payload_template = '{{"bodyTemp": {result_body_temp}}}'
iot_hub_payload = iot_hub_payload_template.format(result_body_temp = result_body_temp)
iot_hub_message = Message(iot_hub_payload)
if result_body_temp > 38.0:
iot_hub_message.custom_properties["temperatureAlert"] = "true"
else:
iot_hub_message.custom_properties["temperatureAlert"] = "false"
myIotHubClient.send_message(iot_hub_message)
If the temperature is higher than 38.0°C, the message is marked with custom property and we can easily trigger some warning, there is probably some visitor with fever.
Example of message sent to IoTHub:
[IoTHubMonitor] [11:45:10 AM] Message received from [thermometer1]:
{
"body": {
"bodyTemp": 36.7
},
"applicationProperties": {
"temperatureAlert": "false"
}
}
ConclusionYou can build this kind of accurate thermometer by yourself under $150 (the largest investment is thermometer, Raspberry and proximity sensor).
You can find source codes of the project on GitHub repository. For trained model, please perform a training for your instance of thermometer to ensure you don't have different firmware or different some HW settings from manufacturing process.
We share these files under non-commercial license.
It would be great if you donated this device to those in need for free.
If you need to cover your production costs, we are ok with you selling the device for production cost. However, we do not want to see these devices on eBay for 1000€.
Comments