用途
とある制作で非接触検温をシステムに組み込むことになったので、ラズパイ+サーモセンサを使い実装しました。手持ち形式ではなく、据え置き型のイメージです。
※先に言っておくと、そこまで精度は高くなく、誤差も場合によっては1度くらい生じる場合があります。ですが、そもそも非接触型の検温機ってそこまで精度高くない印象ですし、まあこんなものなのかなと思って使っております。(誤差に関しては、自分は複数回検温して、中央値を取って緩和してます)
使用した機材
PCのOS: macOS Catalina v10.15
サーモセンサ: https://www.switch-science.com/catalog/3395/
ラズパイ3B+: https://www.switch-science.com/catalog/3920/
サーモセンサの概要
各素子ごとの温度測定範囲は0℃~80℃です。測定エリアはセンサ正面(上下左右約60度)の四角錘で、このエリアを8x8ピクセルに分割した2次元画像が得られます。
準備
ラズパイの環境構築
ラズパイのセットアップと接続の解説は省略します。SSHやディスプレイ接続等でターミナルが使える状態であることを前提にします。
今だと、ラズパイにOSをインストールするためのツールがあるみたいなので、下記の記事あたりを参考にするといいと思います。
I2C 有効化
sudo raspi-config
CUIの選択画面が出るので、
I2C -> enabled で有効化できます。
配線
ブレッドボートを使うといいです。参考
配線が終わったら、接続できているか確認するコマンドを実行します。
i2cdetect -y 1
68があれば正しく認識されています。
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
Pythonで温度取得
必要モジュールのインストール
sudo pip3 install adafruit-circuitpython-amg88xx
検温プログラム
import time
import busio
import board
import adafruit_amg88xx
i2c_bus = busio.I2C(board.SCL, board.SDA)
sensor = adafruit_amg88xx.AMG88XX(i2c_bus, addr=0x68)
time.sleep(0.5) #スリープを挟まないとsensor.pixelsが取得できない
print(sensor.pixels)
実行すると、二次元配列が返ります。
sudo python3 test.py
[[23.5, 23.5, 24.25, 23.75, 23.25, 24.5, 24.25, 23.25], [23.0, 24.0, 23.5, 24.0, 23.75, 24.25, 24.5, 24.25], [23.75, 23.25, 23.75, 24.0, 23.75, 24.5, 24.5, 24.75], [23.25, 23.25, 23.25, 24.0, 23.5, 24.25, 24.5, 25.75], [23.5, 23.75, 23.75, 24.0, 23.5, 24.25, 24.0, 24.0], [23.75, 23.25, 24.25, 23.5, 23.75, 23.25, 23.75, 24.0], [23.25, 23.75, 23.5, 24.25, 23.75, 23.5, 24.0, 24.0], [23.5, 23.0, 24.0, 23.75, 23.25, 23.25, 24.75, 23.75]]
わかりやすくプロットしてみると...
import time
import busio
import board
import adafruit_amg88xx
import matplotlib.pyplot as plt
i2c_bus = busio.I2C(board.SCL, board.SDA)
sensor = adafruit_amg88xx.AMG88XX(i2c_bus, addr=0x68)
time.sleep(0.5)
fig = plt.imshow(sensor.pixels, cmap="inferno")
plt.colorbar()
plt.savefig("plot.png")
顔です。それっぽく取得できてます。
検温の実装
額周辺を検温する必要があるため、据え置き状態で検温するとなると、利用者に顔の位置を固定してもらう必要があります。さらに、理想は顔を所定の位置に合わせたら検温が始まるとUX的によいです。
これらを実現するために自分はカメラモジュールを別途用意し、所定の位置に顔があることを検知したことをトリガーにし検温を行いました。利用者にはディスプレイに表示されているカメラと枠を頼りに顔を合わせてもらいます。もちろんこの実装を行う場合は、カメラの位置とサーモセンサの相対位置を固定する必要があります。
以下が、サンプルプログラムです。顔検知はOpenCVを利用しました。(実際のコードをサンプル用に改変したもので、動作確認はできていません)
import picamera
import picamera.array
import time
import cv2
import busio
import board
import adafruit_amg88xx
#カスケードファイルは配布されている物を使ってます
CascadeFile = "./haarcascade_frontalface_default.xml"
with picamera.PiCamera() as camera:
#カメラの設定
camera.resolution = (400, 400)
camera.rotation = 180
camera.start_preview()
time.sleep(2)
with picamera.array.PiRGBArray(camera) as stream:
while True:
#カメラの(50,50)から(350,350)の範囲を顔認識の対象かつ顔判定される最小サイズが250x250なので、認識する位置と大きさが絞られます
camera.capture(stream, 'bgr', use_video_port=True)
gray = cv2.cvtColor(stream.array[50:350, 50:350], cv2.COLOR_BGR2GRAY)
cascade = cv2.CascadeClassifier(CascadeFile)
face_list = cascade.detectMultiScale(gray, minSize=(250, 250), minNeighbors=3)
if len(face_list) > 0:
x, y, w, h = face_list[0]:
temps = []
i2c_bus = busio.I2C(board.SCL, board.SDA)
sensor = adafruit_amg88xx.AMG88XX(i2c_bus, addr=0x68)
#5回検温
for i in range(5):
time.sleep(0.3)
_max = 0
for j in sensor.pixels[2:6]:
for k in j[3:5]:
_max = max(_max, k) #範囲内の最大値を扱う
temps.append(_max + 5) #表面温度と体温のギャップ埋め
print(round(sum(sorted(temps)[1:4]) / 3, 1)) #検温結果をソートし中3つの平均を出力
break
stream.seek(0)
stream.truncate()
camera.stop_preview()
この部分は、精度向上の余地があるかもしれません。(気温を元にこの値を決めるなど)
temps.append(_max + 5) #表面温度と体温のギャップ埋め
このコードについて細かく説明するのは大変なので、詳しくはOpenCV
PiCamera
あたりで調べてみてください。
最後に
あくまで学生が制作でざっくりと実装した物なので、確実性が求められる場合はあまり参考にしすぎないようお願いします。
ありがとうございました。