M5Stackでパルスオキシメーター

M5Stack

 話題のパルスオキシメーターを医療現場に迷惑がかからないように試したいという話。

 4月24日にこういう記事があった。
 コロナ「突然重症化した人」の驚くべき共通点
 これで知ったのがパルスオキシメーター。その数日後に、M5StackのHEART UNITに酸素濃度を測る機能があると知る。酸素濃度とパルスオキシメーターが測定するという酸素飽和濃度。同じなのか? 違うものなのか? 調べてみると同じものらしい。HEART UNITに搭載されるセンサーMAX30100のスペックを調べたら、「pulse oximeter」とあった。

 さらに調べる。パルスオキシメーターは市販品があり、数千円で買える。しかし、一般の人が買うのはやめろという声が医療現場からあがっているとも。そりゃそうだ。しかし、M5StackのHEART UNITが医療現場で使われることはないだろう。ということで購入。コードはセンサーユニットのドキュメントからリンクされてたサンプルコードにあった。GitHubにあがっていた。 MAX30100_RawData/

 MAX30100のライブラリは、Arduino IDEのライブラリの管理から検索すれば出てくる(スケッチ – ライブラリをインクルード – ライブラリの管理)。MAX30100lib by OXullo Intersecans というやつ。サンプルもインストールされる。コードはHEART UNITのサンプルよりもわかりやすい。これベースに表示まわりを追加した。あと、バッテリー表示も加えた。M5Stackでバッテリー残量表示。 みなさん、ありがとうございます。


 コードをあげておく。

/*
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/>.

MAX30100lib
oxullo/Arduino-MAX30100
Arduino library for MAX30100, integrated oximeter and heart rate sensor - oxullo/Arduino-MAX30100
*/ #include <M5Stack.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!"); } //battery #define RGB(r,g,b) (int16_t)(b + (g << 5) + (r << 11)) //色0~31 緑0~63 unsigned long currentMillis; unsigned long lastupdateMillis = 0; int lastbattery = -1; void displayBatteryLevel() { if (currentMillis - lastupdateMillis > 10000) { //元は1000 int battlevel = 0; byte retval; Wire.beginTransmission(0x75); Wire.write(0x78); if (Wire.endTransmission(false) == 0 && Wire.requestFrom(0x75, 1)) { retval = Wire.read() & 0xF0; if (retval == 0xE0) battlevel = 25; else if (retval == 0xC0) battlevel = 50; else if (retval == 0x80) battlevel = 75; else if (retval == 0x00) battlevel = 100; } if (lastbattery != battlevel){ M5.Lcd.fillRect(250, 5, 56, 21, RGB(31, 63, 31)); M5.Lcd.fillRect(306, 9, 4, 13, RGB(31, 63, 31)); M5.Lcd.fillRect(252, 7, 52, 17, RGB(0, 0, 0)); if (battlevel <= 25) M5.Lcd.fillRect(253, 8, battlevel/2, 15, RGB(31, 20, 10)); else M5.Lcd.fillRect(253, 8, battlevel/2, 15, RGB(20, 40, 31)); lastbattery = battlevel; } lastupdateMillis = currentMillis; } } void setup() { M5.begin(); //M5.Axp.ScreenBreath(8); //M5.Lcd.setRotation(3); M5.Lcd.fillScreen(BLACK); M5.Lcd.setTextColor(WHITE, BLACK); M5.Lcd.setTextSize(2); M5.Lcd.print("MAX30100 / SpO2"); 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.setTextSize(2); M5.Lcd.setCursor(3, 60, 1); M5.Lcd.print("SpO2: "); M5.Lcd.setCursor(3, 140, 1); M5.Lcd.println("Heart rate:"); M5.Lcd.setTextSize(4); M5.Lcd.setCursor(80, 85, 1); M5.Lcd.printf("%3d %% ", pox.getSpO2()); M5.Lcd.setCursor(80, 165, 1); M5.Lcd.printf("%6.2f bpm", pox.getHeartRate()); //battery currentMillis = millis(); displayBatteryLevel(); tsLastReport = millis(); } }

 センサー部を直接触らないようにするのが重要らしい。とりあえずセロテープを貼っている。あと、測定が完了する20~30秒ほどかかる。心拍数を計測するのにそれくらいかかるからだろうか。酸素濃度(SpO2)は97%程度が正常な範囲らしい。ときおり100%を超えることもある。うまく測れないこともあるので、角度とかを調整する必要がありそう。あと、市販の製品は上下で挟む感じだけど、こちらは一方向のみ。そのへんも正確さの違いとして出てる気がする。

M5Stack, pulse oximeter (パルスオキシメーター)

M5Stack用心拍センサユニット (スイッチサイエンス)

AliExpress.com Product – M5Stack Newest Mini Heart Rate Unit MAX30100 Module Sensor for Arduino/Low Power Heart Rate Oxygen Pulse Breakout I2C Interface

コメント