https://kinneko.booth.pm/items/1963720
----------------------------------------------------------------------------------------
サンプルコードでは生データしか取っていないので、SpO2の値が見えていない。基本的には動脈が脈動するので測定値はギザギザするので、それを平均化して計算式に当てはめてSpO2値を推測する感じ。
how to compute heart rate and SPO2 from MAX30100 | element14 | Maxim
https://www.element14.com/community/thread/54733/l/how-to-compute-heart-rate-and-spo2-from-max30100?displayFullThread=true
http://www.ti.com/lit/an/slaa655/slaa655.pdf
計算式はこんな感じ。
R = (AC RMS of Red / DC of Red)/ (AC RMS of IR / DC of IR)
% SpO2= 110 – 25 × R
参考資料はこんなとこ。
How pulse oximeters work explained simply.
https://www.howequipmentworks.com/pulse_oximeter/
Implementing pulse oximeter using MAX30100 - MORF - Coding And Engineering
https://morf.lv/implementing-pulse-oximeter-using-max30100
https://github.com/xcoder123/MAX30100
今回使ったライブラリにも、SpO2値を求める関数がある。サンプルコードもあった。
Arduino-MAX30100/MAX30100_Minimal.ino at master · oxullo/Arduino-MAX30100
https://github.com/oxullo/Arduino-MAX30100/blob/master/examples/MAX30100_Minimal/MAX30100_Minimal.ino
サンプルコードをそのまま使って、センサに指をあてて、シリアルに値が出るのを確認する。

結果、心拍高い感じに出ている。普段から割と高めなんだけど、自宅の血圧計で心拍測っても、ここまで高くはない。アテになんないか...
SpO2値は、目安になるものがないけど、普通は98とか99が出るらしい。あかんわ。深呼吸したり、ハイパーペンチレーションしたり、戸外で測ったりしても変わらない。
生データを見ながら息を止めて我慢していると値が下がってくるので、一応有効な結果が出てくるということはわかる。しかし、これが50%以下になるとかあるんだろうか。
シリアルに出るだけではM5Stick Cを買った意味がないので、表示部分を追加。M5.Lcdを使った表示は、簡単にテキスト表示だけにした。
void setup()の中でM5.Lcdを初期化するのに、センサの後でやったら"Initializing pulse oximeter..FAILED"と表示されてセンサの初期化に失敗してしまった。めんどくさいな。センサの初期化前にM5.Lcdを初期化したらうまくいった。
デフォルトでは、LCDの輝度が高すぎで眩しい。値を10にしても眩しい。8にしたら、少し暗いかなとも思えるが眩しさはないのでこれで行く。

最終的なコードは、こんな感じに。追記したのはボールドの表示部分だけ。
/*
Arduino-MAX30100 oximetry / heart rate integrated sensor library
Copyright (C) 2016 OXullo Intersecans x@brainrapers.org
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses/.
*/
#include <M5StickC.h>
#include <Wire.h>
#include "MAX30100_PulseOximeter.h"
#define REPORTING_PERIOD_MS 1000
// PulseOximeter is the higher level interface to the sensor
// it offers:
// * beat detection reporting
// * heart rate calculation
// * SpO2 (oxidation level) calculation
PulseOximeter pox;
uint32_t tsLastReport = 0;
// Callback (registered below) fired when a pulse is detected
void onBeatDetected()
{
Serial.println("Beat!");
}
void setup()
{
M5.begin();
M5.Axp.ScreenBreath(8);
M5.Lcd.setRotation(3);
M5.Lcd.fillScreen(BLACK);
M5.Lcd.setTextSize(2);
M5.Lcd.print("MAX30100");
M5.Lcd.setCursor(0, 40);
Serial.begin(115200);
Serial.print("Initializing pulse oximeter..");
// Initialize the PulseOximeter instance
// Failures are generally due to an improper I2C wiring, missing power supply
// or wrong target chip
if (!pox.begin()) {
Serial.println("FAILED");
for(;;);
} else {
Serial.println("SUCCESS");
}
// The default current for the IR LED is 50mA and it could be changed
// by uncommenting the following line. Check MAX30100_Registers.h for all the
// available options.
// pox.setIRLedCurrent(MAX30100_LED_CURR_7_6MA);
// Register a callback for the beat detection
pox.setOnBeatDetectedCallback(onBeatDetected);
}
void loop()
{
// Make sure to call update as fast as possible
pox.update();
// Asynchronously dump heart rate and oxidation levels to the serial
// For both, a value of 0 means "invalid"
if (millis() - tsLastReport > REPORTING_PERIOD_MS) {
Serial.print("Heart rate:");
Serial.print(pox.getHeartRate());
Serial.print("bpm / SpO2:");
Serial.print(pox.getSpO2());
Serial.println("%");
M5.Lcd.fillScreen(BLACK);
M5.Lcd.setCursor(3, 10, 1);
M5.Lcd.println("SpO2 checker");
M5.Lcd.print(" SpO2: ");
M5.Lcd.print(pox.getSpO2());
M5.Lcd.println(" %");
M5.Lcd.println(" Heart rate:");
M5.Lcd.print(" ");
M5.Lcd.print(pox.getHeartRate());
M5.Lcd.println(" bpm");
tsLastReport = millis();
}
}
M5Stick Cには、時計バンドがついているので、それに付けてみた。GROVEもどきのケーブルが長すぎる。

手首の上側にセンサをはさんでみたけれど、安定した値が取れない。

皮膚の薄い反対側ならどうかとも思ってやってみたけど、それほど改善もしない。

手のひらがわりと安定するのだけど、これを装着するのは手袋のようなインターフェイスがいりそう。

これを自作キット化して頒布しようと思ったりすると、パルスオキシメーターは医療機器なので、結構めんどくさいことになる。まぁ、個人だとムリぽだね。
パルスオキシメーターに関する法規・規格 - パルスオキシメーター深堀り知恵袋 | コニカミノルタ
https://www.konicaminolta.jp/healthcare/knowledge/details/standard.html
まだスイッチサイエンスの荷物は届いていないし、Aliexpressで頼んだパルスオキシメーター3個も届いていないのだけど、もう飽きたw
いつも使っているSmartConfigでの無線LANの自動設定を組み込むとか、センサの固定方法を考えるのとか、センシングの結果を無線LAN経由でクラウドに上げたり、ローカルでデータストアしてグラフで見せるとか、やることはあるのだけど、センシングが安定しないのがまず駄目だな。固定方法を何か考えないと。
通信は、Bluetoothで送ってスマホアプリにデータ蓄積するほうが現実的だろうか?
センサがもう一個届いたら、センサに個体差がどのくらいあるのかも少しは見えるのかも。
中国からパルスオキシメーターが届いたら、それで結果の誤差を見られるかもしれない。
オリジナル投稿:
M5Stick CとHeart Rate UNITでSpO2を測ってみる -2-|kinneko|pixivFANBOX
https://kinneko.fanbox.cc/posts/994033



