作ろうと思ったきっかけは、通いの病院でこれを見たからです。前々から非接触の体温計に興味があったのですが、これを見てとても欲しくなりました。早速、家に戻ってGoogleで探してびっくり。30,000円です。とても手が出ません。そこで自作を思い立ちました。
構想
非接触の温度センサを探しました。
これも面白そうです。
◇ 心拍センサーモジュールMAX30102 血液酸素センサー
これらのモジュールが入手可能で、Arduinoで使えるようです。自作されている事例もありましたので、自分でもできそうな気がしてきました。
- 形はキューブ状にする(市販品のイメージ)
- 手をかざして体温測定(手の表面温度);距離センサで手の位置を判定
- 指を赤外線に置いて、血中酸素濃度を測定
- 体温と血中酸素濃度をモニタ表示
- 音で測定状態を示す
- 通常は休止状態にしておき、タッチセンサでウェイクアップさせる
- 電源(電池)内蔵するか/USB電源にするか
- 測定値を記録(Blynk、Ambient)
部品と仕様
構想から、必要な部品が決まってきます。マイコンはwifi搭載を考えるとESP8266かESP32に絞られます。また、使っていないときはLEDや赤外線を消しておきたいので、スイープ/ウェイクアップが必要です。
- 非接触温度センサ:GY-906;赤外線温度センサ MLX90614を搭載
- 血中酸素濃度センサ:MAX30102
- 測距センサー:VL53L0X
- 7セグディスプレイ:TM1637;体温表示用
- 液晶モニター:SPI SSD1306;血中酸素濃度表示用
- マイコン:ESP32 DEVkit V1
- ブザー:Daiso イヤホン
- ケース:Daiso 9cm角透明ボックス
1. 非接触温度センサ:GY-906
2. 血中酸素濃度センサ:MAX30102
3. 測距センサー:VL53L0X
4. 7セグLEDディスプレイ:TM1637
5. 液晶モニター:SPI SSD1306
"Adafruit_SSD1306.h"は使用するOLEDの解像度によって、不要な"#define"分をコメントアウトしなければなりません。"128 x 64"を選びファイル名を"Adafruit_SSD1306_128_64.h"に変更しておきました。
構成
部品をユニバーサル基板に組み、透明ケースの中に入れました。電池の内臓は固定がむつかしいので、USB電源方式にしました。非接触温度センサ:GY-906と測距センサー:VL53L0Xはケースのプラスチックを介すと具合が良くないので検出部には穴を開けました。
左側が体温測定部で右側が血中酸素濃度の測定部です。手前に貼ったアルミテープを触るとウェイクアップします。
ピンアサイン
ESP32には色々とつなぐのでGPIOの割り振りをしておきます。3つのセンサはI2Cで接続します。7セグLEDは特殊な固有のつなぎ方です。0.96インチOLEDはSPI版なので、それでつなぎます。
さらに、ウエイクアップ用、確認のLチカ用、作動確認の音出し用にそれぞれpinを設定しました。speaker直結の抵抗は音量調整用です。
体温計について
平静にした状態で20~25℃程度の部屋にある程度いてから測定するなら、それなりに接触式温度計に近い値が出ます。しかし、軽い運動して体に熱を持っていると感じるときとか、冬場に外から帰ってきて玄関で測定する場合では測定精度が低く、現状では安心して値を信ずるまでは行っていません。よく店頭や街中で見かけるものより良くないと思います。
なおかつ、手のひらの測定では測定時の環境の影響が大きいと思われます。しばらく使用してみて感じた測定値に影響するであろう因子は、気温、湿度、測定位置、運動の程度です。
測定精度を上げるには、手のひら温度と体温のデータをいろいろな環境で集めて、換算するロジックを開発する必要があります。
血中酸素濃度と心拍数について
どの程度の再現性を求めるのかによりますが、繰り返し測って同じ数値(もちろん、小数点以下はなしで)が欲しいならば、測定精度が低い、再現性が低い、時間をかけても安定しないといった課題があります。
医療用のものがどれくらいの精度や再現性があるのかは知りませんが、繰り返し測って同じ数値を求めるならば実用は無理です。
健康管理
毎日データーを取って健康管理に役立てようと思っていましたが、測定値の精度が悪いので、BlynkやAmbientでデータを集積することまでは行いませんでした。
今後、興味が湧いてきたら推定ロジックを煮詰めるかもしれませんが、現状は置物になっています。
スクリプト概要
体温計
このブログに載っている”mlx90614_test.ino”をベースにしました。距離センサをHC-SR04からVL53L0Xへ変更しています。また、ESP32はtone関数が使えないので、代わりにledcWriteTone()を使っています。
体温の推定方法について説明します。
室温、手のひらの表面温度とセンサとの間隔の3種類のデータについて、出力間隔(例えば1秒)ごとに100個データの2乗平均(rms)を取って、それを平均します。その平均値を用いて、手のひらとセンサの間隔が40㎜の値となるように線形近似で補正します。さらに、測定時の室温での値を23.8度の値になるように線形近似で補正します。23.8度とは、手のひらの体表温度と接触式の体温計での体温の相関を見たときの室温です。この時の関係(23.8度の室温で手のひらが体温より2.8度低かった)から、体温を推定します。
これを繰り返し、ひとつ前の値との差が0.2度以下になる状態が連続して3回続くと、その値を体温として表示します。
血中酸素濃度と心拍数
ここで紹介されているスクリプト"ESP32_MAX30102_simple-SpO2_plotter.ino"を元にしました。
その他
体温計モードと血中酸素濃度モードの切り換え
切り換えというよりも、if文でMAX30102に指が乗せられている(particleSensor.getFIFORed() < 30000 )ときは血中酸素濃度測定を行い、指が乗せられていないときは体温測定を行う処理にしています。
ディスプレイ
2種類のディスプレイを使っています。7セグLEDディスプレイTM1637(I2C接続)と液晶モニターSSD1306(SPI接続)です。体温測定のモードと血中酸素濃度測定のモードの両モードで表示する内容を下表のように振り分けました。
ウェイクアップ
血中酸素濃度センサMAX30102( particleSensor.getFIFORed() < FINGER_ON )に指を乗せていない状態と、測距センサーVL53L0Xの測定範囲外(measure.RangeStatus != 4)が10秒以上続くと、ESP32をdeepsleepにします。復帰はESP32の内蔵タッチセンサーT6(GPIO14)を使いました。ESP32のボード上にある赤色LEDも消したかったのですがやり方がわかりませんでした。
内蔵タッチセンサーはここが詳しいです。
スクリプト
体温推定
手のひらで測った表面温度は体温よりも低くなります。これは参考にしたブログでも触れられていますし、測定してみればすぐに実感できます。さらに、センサと手のひらの距離にも依存しているようです。そこで、少しデータを取ってみました。
日や時間によってバラツキがありますが、測定時の体温はOMRONの体温計を脇に挟む測定法で36.1~36.7度でした。
センサまでの間隔
左のグラフが室温25℃で右のグラフが室温18℃です。40mm離れた測定値と100mm離れた測定値では約4度の差があります。この4度の差は室温が25℃でも18℃でも、ほぼ同じでした。(近似曲線の傾きはほぼ同じ)
間隔が離れると室温に近づくと言えます。関係は線形なので容易に任意位置の温度を計算することができます。
データでは間隔の最小値が30㎜ですが、これ以下は測距センサーVL53L0Xがそれ以下では距離を測定できなかったからです。
測定時の室温
体表温度に及ぼす室温の影響は下の図のようになります。各データは手のひらまでの距離が40mmの時の値を選び出して、その時のセンサ検出の室温と体表温度をグラフ化したものです。室温が低いほど体表温度が低くなるようです。この傾向はNECの論文と同傾向です。
問題は室温が同じでも体表温度が2度ほどは変わることです。下記のグラフは日ごとにのマーク色を変えて表しました。同じ日の同じ温度で2度くらい、日が変わると6度程度ばらつきます。
さらに、第2の問題点は室温20℃を基準にしたとして、体温との差は私の手のひらのケースで4度、図5の顔のケースで2度、図6の(部位不明)ケースで8度と一様にならない点です。体表測定の部位(顔、手)やその他の測定環境により違いが出ることです。
部位のよる違いの点では、この事例のブログでは、おでこと手のひらで平均値で1.2度の差がありました。
NECの論文では次のような記載もあります。室温が20度前後をキープできるならば体表温度と体温の相関付けが可能でしょうが、室温が10度を下回るようであればそれは厳しいと思います。
図5では、環境温度が25℃のとき、体温は36.4℃、体表温度は34.8℃となります。図5及び図6は、測定条件が異なるため表面温度に若干の違いはありますが、環境温度が上昇するにともない、体表温度と体内温度の差が小さくなってゆく点では、ほぼ相関が取れます。
これらのグラフから、空港などの環境温度が一定の場所では、アラーム設定値を検出したい体温より1.6℃程度低い値にすれば良いことが分かります。例えば、体温が38℃以上ある人物を検出する場合は36.4℃をアラーム設定値とすれば良いことになります。
しかし、図5では、環境温度が15℃より低くなると体表温度と体温の差が大きくなり、同時に個人差の幅も大きくなるという結果が出ています。このため、冬に屋外から建屋に入ってくる人物を測定する場合には更に十分な検討が必要です。
パルスオキシメーターの原理(参考)
酸素飽和度
酸素と結びついたヘモグロビンは赤い色をしていますが、これは赤い色だけをあまり吸収せずに通してしまうからです。つまり、赤い色の吸光度が低いのです。一方、酸素を離したヘモグロビンは黒っぽい色になります。これは光をよく吸収するからです。赤色(R)を血液に当てると、ヘモグロビンと酸素がより多く結びついていると、それだけ多くの光が指を通り抜け、センサーが受け取る光の量が多くなります。赤外光(IR)はヘモグロビンと酸素が結びついていてもいなくてもどちらも、あまり変わらず血液を通り抜けます。HbO2が増えHbが減れば、センサーが受け取る赤色光(R)は多くなり、赤外光(IR)はあまり変わりません。その逆では赤色光は少なくなり、赤外光はやはりあまり変わりません。
つまり、センサーが受け取るR/IRの比率が分かれば、HbO2とHbの比率、即ち酸素飽和度が分かる事になります。
引用元:パルスオキシメーター知恵袋 基礎編
生体に照射された光は、血液以外の組織層、動脈層、静脈層を通るなか、各層で吸収を受けセンサーに届きます。心臓から拍出された動脈血は、脈波と呼ばれるように波のような形で血管内を移動します。極く短い時間の中で、厚みが変化するのは脈動をしている動脈血だけです。皮膚や肉などの組織や静脈は、極く短時間では厚みは一定です。厚みが変わると透過する光の量も変わり、センサーの受け取る信号も変化します。つまり、信号の変化成分は厚みの変わった組織だけの成分、すなわち動脈血だけの情報となります。脈動(変化成分)を見ることで、動脈血だけの成分を見ることができ、R、IRの変化成分の比率から動脈血だけの酸素飽和度が求められます。パルスオキシメーターは脈拍数も表示しますが、それは、このように変動を見ることで、脈拍も同時に求められるからです。引用元:パルスオキシメーター知恵袋 基礎編