11
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

TLB Enjoy DevelopersAdvent Calendar 2022

Day 11

【M5StickCPlus】パルスオキシメーターを自作する

Last updated at Posted at 2022-12-11

はじめに

こんにちは

Advent Calendar 2022

先日は東京の生ビールの価格がいかに高いかを調査する記事を投稿しておりました。

ありがたいことにTLB Enjoy Developers Advent Calendar 2022も全日程が埋まり、盛り上がってまいりました。

では11日目、行きましょう!

この記事は TLB Enjoy Developers Advent Calendar 2022 の11日目の記事です。

目次

ある日のこと

いつものごとく職場の同僚とアキバを散策していたところ

同僚「最近マイコン欲が激上がりしている。」

ワイ「は?」

同僚「最近!マイコン欲が!!激上がりしていルゥ!!!!
同僚「マルツに行くぞ!!!!!!!!

〜マルツにて〜

ワイ「マイコンとかほんまラズパイって名前くらいしか知らんなぁ・・・。」
同僚「有名どころはラズパイだが、M5Stackというのが注目を浴びていてぇ。特にM5Stackはモジュールやセンサーが数多く作られていて色いr...」
ワイ「お!時計バンド付きのやつとかあるやんけ!おもろそうやんけ!!買お!!!(脳死)

で、入手したのがこちら
20221204_194740.jpg

M5StickC Plus(腕時計アクセサリー付き)【M5STACK-K016-H】
M5Stack用心拍センサユニット【M5STACK-HEARTRATE-UNIT】
M5Stack用GROVE互換ケーブル(20cm、5個入り)【M5STACK-CABLE-20】
※付属のケーブル短そうなんで、いるかなと思って買ったこの互換ケーブルは
まさかの付属のケーブルと同じ長さでした(草)

概要

本記事ではM5StickCPlusを用いて持ち運べるパルスオキシメーターを自作するところまでを目標とします。

環境

  • VSCode v1.73.1
    • PlatformIO IDE v2.5.5

方法としてはArduino IDEがメジャーらしいですが、
同僚がVSCodeのPlatformIOをオススメしてくれたのでそちらで開発を進めます。
個人的にはmicro Pythonでの開発をしてみたかったのですが、
いろいろ調べたところ結構ハードル高かったので、C++で頑張るます・・・

実装

M5StickCPlusはすでに6軸ジャイロ、RTC、マイク、IRなどを用いた5つの画面が用意されており、
それぞれディスプレイ下の「M5」と彫られたAボタンを押して切り替えができるようです。

また、これらのソースコードは「FactoryTest」としてオープンソースとしてあるみたいなので、
こちらを参考に実装を進めていこうと思います。

なるほど

わからん。

ライブラリインストール

PIO Homeのサイドメニュー"Libraries"からM5StickCplusをインストールしておきます。

スクリーンショット 2022-12-11 13.31.34.png

[env:m5stick-c]
platform = espressif32
board = m5stick-c
framework = arduino
lib_deps = 
	m5stack/M5StickCPlus@^0.0.8 // これが追加される

Lチカ

どうも電子工作でははじめの一歩としてLチカから行うようです。

自分自身こういった電子工作は全くの初めてなので全てが新鮮ですね。

#include <M5StickCPlus.h>

#define LED_PIN 10 // G10

void setup() {
    M5.begin();
    pinMode(LED_PIN, OUTPUT);
}

void loop() {
    digitalWrite(LED_PIN, LOW); // LED点灯
    delay(1000); // 1秒ごとに切り替え
    digitalWrite(LED_PIN, HIGH); // LED消灯
    delay(1000);
}

LチカGIF.gif

感動

自分でコードを書いて、それをビルド→アップロードして機器に実際に反映されるところを見ると既に達成感でいっぱいです。

ここまでみてくださった方々、
本当にありがとうございました!

Hello World

というのは冗談です。ごめんなさい。
流石にもう少しつづけます。

ハードはLチカからでしたが、ソフトはやっぱりHello World
画面表示も試してみます。

#include <M5StickCPlus.h>

void setup() {
    M5.begin();
    M5.Lcd.print("Hello World");
}

void loop() {
}

20221210_175211 (1).jpg

ちっさぁ...

ちなみに最初にHello Worldを間違えてシングルクォーテーションで囲ってしまって表示がバグったのをしばらくハマってたのは内緒です。

20221211_041110 (1).jpg

パルスオキシメータ

ライブラリインストール

追加でPlatformIOにて下記ライブラリのインストールをしておきます

[env:m5stick-c]
platform = espressif32
board = m5stick-c
framework = arduino
lib_deps = 
	m5stack/M5StickCPlus@^0.0.8
	oxullo/MAX30100lib@^1.2.1
	sparkfun/SparkFun MAX3010x Pulse and Proximity Sensor Library@^1.1.2

それではいよいよメインディッシュです。
看護師時代はイヤというほどみてきたパルスオキシメータ
「酸素の値測りますねぇ〜」
「98%...ヨシ!
「94%...ちょっと深呼吸してみましょか〜」 94%..93%..94%..95% 「ヨシ!!!!!!
「92%...えーーAさんの既往は...特に目立つものなしか、ヨシ!!!!!!!!!

そんな自分がまさかパルスオキシメータを作るとは過去の自分は思いもしませんでしょうね。

まずは素直に公式のスクリプトをコピペしてきます。

/*
*******************************************************************************
* Copyright (c) 2022 by M5Stack
*                  Equipped with M5Core sample source code
*                          配套  M5Core 示例源代码
* Visit for more information: https://docs.m5stack.com/en/core/gray
* 获取更多资料请访问: https://docs.m5stack.com/zh_CN/core/gray
*
* Describe: Heart Rate.  心率
* Date: 2021/8/16
*******************************************************************************
  Please connect to Port A, HEART Unit obtains the original value of the heart
rate detection and displays it on the screen. The user can also use the Arduino
IDE Serial Plotter to view the line graph output. 请连接端口A,HEART
Unit获取心率检测的原始值并显示在屏幕上。用户还可以使用Arduino IDE Serial
Plotter查看线图输出。
*/

#include <M5StickCPlus.h>
#include <FS.h>
#include <SPI.h>
#include <Wire.h>

#include "MAX30100.h"

#define SAMPLING_RATE   MAX30100_SAMPRATE_100HZ
#define IR_LED_CURRENT  MAX30100_LED_CURR_24MA
#define RED_LED_CURRENT MAX30100_LED_CURR_27_1MA
#define PULSE_WIDTH     MAX30100_SPC_PW_1600US_16BITS
#define HIGHRES_MODE    true

MAX30100
sensor;  // Instantiate a MAX30100 sensor class.  实例化一个MAX30100传感器类

void setup() {
    M5.begin();        // Init M5Stack.  初始化M5Stack
    M5.Axp.begin();  // Init power  初始化电源模块
    Serial.print("Initializing MAX30100..");

    while (!sensor.begin()) {  // Initialize the sensor.  初始化传感器
        M5.Lcd.setTextFont(4);
        M5.Lcd.setCursor(50, 100, 4);
        M5.Lcd.println("Sensor not found");
        delay(1000);
    }
    M5.Lcd.fillScreen(BLACK);
    // Set up the wanted parameters.  设置所需的参数
    sensor.setMode(MAX30100_MODE_SPO2_HR);
    sensor.setLedsCurrent(IR_LED_CURRENT, RED_LED_CURRENT);
    sensor.setLedsPulseWidth(PULSE_WIDTH);
    sensor.setSamplingRate(SAMPLING_RATE);
    sensor.setHighresModeEnabled(HIGHRES_MODE);
}

void loop() {
    uint16_t ir, red;
    sensor.update();  //更新传感器读取到的数据
    while (sensor.getRawValues(&ir, &red)) {  //如果获取到数据
        M5.Lcd.setTextFont(4);
        M5.Lcd.setCursor(100, 100, 4);
        M5.Lcd.printf("IR:%d               ", ir);
        M5.Lcd.setCursor(100, 130, 4);
        M5.Lcd.printf("RED:%d              ", red);
    }
}

include文をM5StickCPlus用に変更しています

#include <M5StickCPlus.h>
#include <FS.h>
#include <SPI.h>
#include <Wire.h>

Wire.hより下は、platform.iniを下記のように追記してもよさそうですね。

[env:m5stick-c]
platform = espressif32
board = m5stick-c
framework = arduino
lib_deps = 
	m5stack/M5StickCPlus@^0.0.8
	oxullo/MAX30100lib@^1.2.1
	sparkfun/SparkFun MAX3010x Pulse and Proximity Sensor Library@^1.1.2
	Wire
	FS
	SPI

M5StackはPowerがあるようですが、StickCではAxpのようなのでsetupも変えておきます

M5.Axp.begin();  // Init power  初始化电源模块

IRGIF.gif

おもてたんとちゃう。

なんかIRとREDという値がひたすらに動き回ってます。

SpO2は赤色光(RED)と赤外光(IR)の2種類の光の透過率で酸化Hbの割合を算出しているみたいですね。
コニカミノルタの知恵袋が非常に参考になりました。

看護師時代では脳死で指に挟めばわかるのであんまし原理とか気にしたことなかったので、
今改めて原理がわかると非常に面白いもんですね。

さて、いろいろ計算するのも面倒なので、今回はMAX30100libのMAX30100_PulseOximeter.hのPluseOximeterクラスを使用します

float PulseOximeter::getHeartRate()
{
    return beatDetector.getRate();
}

uint8_t PulseOximeter::getSpO2()
{
    return spO2calculator.getSpO2();
}

ライブラリで既に関数が用意されてるので非常に便利ですね。
下記に全ソースを格納しておきます。

main.cpp
main.cpp
#include <M5StickCPlus.h>
#include "MAX30100_PulseOximeter.h"

#define LED_PIN 10 // G10
#define REPORTING_PERIOD_MS 1000
#define MAX_SPO2 100

PulseOximeter pox;
uint32_t tsLastReport = 0;

void pulseOximeter()
{
		pox.update();

		// 心拍数と酸化度を非同期でシリアルにダンプ
		// どちらも0は "無効 "
		if (millis() - tsLastReport > REPORTING_PERIOD_MS) {
				M5.Lcd.fillScreen(BLACK);
				M5.Lcd.setCursor(3, 5, 1);
				M5.Lcd.print("SpO2 \n");
				M5.Lcd.print((pox.getSpO2() > MAX_SPO2)? MAX_SPO2 : pox.getSpO2() );
				M5.Lcd.println(" %\n");
				M5.Lcd.print("PR \n");
				M5.Lcd.print(pox.getHeartRate());
				M5.Lcd.println(" bpm");
				
				tsLastReport = millis();
		}
}

// パルス検出時Lチカ
void onBeatDetected()
{
    digitalWrite(LED_PIN, LOW);
    delay(1);
    digitalWrite(LED_PIN, HIGH);
}

void setup()
{
    M5.begin();
    pinMode(LED_PIN, OUTPUT);
    digitalWrite(LED_PIN, HIGH);
    M5.Axp.ScreenBreath(10);
    M5.Lcd.setRotation(3);
    M5.Lcd.fillScreen(BLACK);
    M5.Lcd.setTextSize(3);
    M5.Lcd.print("MAX30100");
    M5.Lcd.setCursor(0, 40);
    
    Serial.begin(115200);
    Serial.print("Initializing pulse oximeter");

    // パルスオキシメータインスタンスの初期化
    if (!pox.begin()) {
        Serial.println("FAILED");
        for(;;);
    } else {
        Serial.println("SUCCESS");
    }

    // IR LEDのデフォルトの電流は50mAですが、以下の行をコメントアウト解除することで変更可能
	// 利用可能なすべてのオプションについては、MAX30100_Registers.hを確認
    // pox.setIRLedCurrent(MAX30100_LED_CURR_7_6MA);

    // パルス検出用コールバック
    pox.setOnBeatDetectedCallback(onBeatDetected);
		M5.Lcd.fillScreen(BLACK);
}

void loop()
{
		pulseOximeter();

		M5.update();
    delay(50);
}

とりあえず前述の関数でSpO2とPR(脈拍数)は取得できました。
しかしSpO2が100%を超えることがあり、医療現場でそれはあり得ないので、下記のように条件式を追記しておきました。

M5.Lcd.print((pox.getSpO2() > MAX_SPO2)? MAX_SPO2 : pox.getSpO2() );

完成

完成品は私のTwitterにて動画を上げております。

付属の時計バンドは過去に経験したことのない固さ
Groveケーブルは間違えて購入したので、長さが足りず絶対にジャンケンでパーを出せない仕様

そういやセンサーどうやって指につけようと考えた結果、
便利そうな穴が2つ空いてたので家にあった結束バンドで対処

あらゆる面で便利すぎる現代への反骨精神が垣間見られて、
逆張りでオシャレなシロモノが出来上がりました。

おわりに

ここまでお読みいただきありがとうございました!!
マイコン、初めてのチャレンジですが、機器が動くのを見るとやはり少なからず達成感はありますし、面白いですね。
課題は結構ありますが、今回の記事ではここまでとしたいと思います。

今回紹介したハードも買った時は安い!と思ってたんですが、
販売当初は数百〜数千円安かったらしいです・・・。
半導体不足解消でまた値段が落ち着いたら色々なモジュール買って遊びたいですね。

とりあえず、

ナースリーでパルスオキシメータ買いましょうか

明日は@ko27 さんの記事です!お楽しみに!!

参考文献

11
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?