質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
M5Stack

M5Stackは、小型のマイコンモジュールです。拡張モジュールが豊富に用意されており、センサと組み合わせることで測定機能を自由に追加することができます。

Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

Q&A

解決済

2回答

1755閲覧

M5Stack パルスオキシメータを用いた心拍数の表示

gakutp

総合スコア1

M5Stack

M5Stackは、小型のマイコンモジュールです。拡張モジュールが豊富に用意されており、センサと組み合わせることで測定機能を自由に追加することができます。

Arduino

Arduinoは、AVRマイコン、単純なI/O(入出力)ポートを備えた基板、C言語を元としたArduinoのプログラム言語と、それを実装した統合開発環境から構成されたシステムです。

0グッド

0クリップ

投稿2021/01/06 12:09

前提・実現したいこと

M5Stackを使って心拍数を表示させる

発生している問題・エラーメッセージ

プログラミング自体にはエラーは出ていないが、動作結果が想定していたものが表示されない シリアルプロッタで 本来、hr(心拍数)を表示するはずがSerialprintで指定したもの以外で埋め尽くされ表示されない 添付した画像は書き込んだあとシリアルプロッタで波形を表示させたもの

イメージ説明

該当のソースコード

#include <M5Stack.h> #include <Wire.h> #include "MAX30105.h" #include "CircularBuffer.h" MAX30105 Sensor;//MAX30105を定義 CircularBuffer<int, 100> buffer_ir, buffer_red; //リングバッファを定義容量は100 CircularBuffer<int, 3> avgHR; CircularBuffer<int, 5> avgSPO2; //それぞれ定義 const int32_t TH_AMOUNT = 300; //パルスの起点となる変化量これを超えるとパルスの起点となる int32_t a = 0; //カウント用変数 int32_t c=0; float sum_ir = 0.0; float sum_red = 0.0; float sum_hr = 0.0; float sum_spo2 = 0.0; const int32_t MIN_INIT = 9999999; //最小値の初期値 const int32_t MAX_INIT = 0; //最大値の初期値 double ir_v_dc; double red_v_dc; double hr; double spo2; long l_time = millis(); int32_t before_ir_v = 0; int32_t b_diff = 0; long pulse_interval = -1; //表示する心拍数とSpO2の範囲(用途により適宜変更) const uint32_t DISP_MIN_HR = 30; const uint32_t DISP_MAX_HR = 180; const uint32_t DISP_MIN_SPO2 = 70; const uint32_t DISP_MAX_SPO2 = 100; //1パルス中の生データの最大・最小値の保持 int32_t min_ir_v = MIN_INIT; int32_t min_red_v = MIN_INIT; int32_t max_ir_v = MAX_INIT; int32_t max_red_v = MAX_INIT; bool isChecked = true; bool isChecked2 = true; void setup() { M5.begin(); M5.Power.begin(); Serial.begin(115200); M5.Lcd.clear(BLACK); while (!Sensor.begin(Wire, I2C_SPEED_FAST)) { //MAX30105を初期化 Serial.print("."); } Serial.println("OK!"); //サンプリングレート等を設定 byte ledBrightness = 0x1f; byte sampleAverage = 8; byte ledMode = 2; int sampleRate = 400; int pulseWith = 411; int adcRange = 4096; Sensor.setup(ledBrightness, sampleAverage, ledMode, sampleRate, pulseWith, adcRange); //初期値として読んでおく before_ir_v = Sensor.getIR(); //初期値として for (a = 0; a < 100; a++) { buffer_ir.unshift(Sensor.getIR()); sum_ir += buffer_ir.first(); } /*for (a = 0; a < 100; a++) { buffer_red.unshift(Sensor.getRed()); sum_red += buffer_red.first(); }*/ //パルス最終取得時間の初期化 l_time = millis(); } void loop() { uint32_t ir_v = Sensor.getIR(); uint32_t red_v = Sensor.getRed(); //移動平均を算出するためのプログラム buffer_ir.unshift(ir_v);//リングバッファにir_vの値を入れる ir_v_dc = sum_ir / 100.0; //平均を算出 sum_ir -= buffer_ir.last(); //総和から一番古いデータを引く sum_ir += buffer_ir.first(); //1パルスの時間を計算 pulse_interval = millis() - l_time; l_time = millis(); //パルス検出にはir_vを利用。前回との差分を求める int32_t diff = before_ir_v - ir_v; //TH_AMOUNT以上の差がある場合、パルス起点とする if (b_diff < TH_AMOUNT && diff > TH_AMOUNT) { //1パルスの時間を計算 pulse_interval = millis() - l_time; l_time = millis(); //心拍数の計算、結果をリングバッファに入れる avgHR.unshift((60000 * 1000 / pulse_interval) / 1000.0); //平均を算出 hr = sum_hr / 3.0; //カウント用 c++; if (c > 2) { sum_hr -= avgHR.last(); //総和から一番古いデータを引く } sum_hr += avgHR.first(); Serial.print(ir_v); Serial.print(","); Serial.print(ir_v_dc); Serial.print(","); Serial.println(hr); } //パルス検出用値の保持 before_ir_v = ir_v; b_diff = diff; }

試したこと

サークルバッファを使う事が良くないのか参考にしたサイトが使っていた移動平均のライブラリを使おうとしたが、ボードには対応していないようで使えなかった。

補足情報(FW/ツールのバージョンなど)

参考にしたサイト
https://androiphone.uvs.jp/?p=3027

開発環境:arduino IDE
ボード:M5Stack-Core-ESP32
Upload Speed:921600
Flash Frequency:80MHz

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

デバイスを持っているわけじゃないのでデータのとり方の妥当性はよくわからないけれど、

・シリアルプロッタの凡例の部分は、ブートローダーやその他のメッセージが出ているようです。M5Stackは走らせたまま、シリアルプロッタを一旦閉じて開き直したら出ないのではないかと思います。

・「サークルバッファを使う事が良くない」とかいうことはないと思いますし、移動平均のライブラリに「ボードに対応」もヘッタクレもないと思います。
それぞれ何をやっているのかを理解して使えば問題ないはずです。逆に、意味もわからずに使えるものでもないでしょう。

・これで本当に平均が求まるのでしょうか? データ数を少なくして、平均を求めるだけのテストプログラムを書いてみて正しく動くか試してみてはいかがでしょう。

C++

1 buffer_ir.unshift(ir_v);//リングバッファにir_vの値を入れる 2 3 ir_v_dc = sum_ir / 100.0; //平均を算出 4 5 sum_ir -= buffer_ir.last(); //総和から一番古いデータを引く 6 sum_ir += buffer_ir.first();

まずはシリアルプロッタでなくシリアルモニタで「生の出力」を観察すべきかと思います。


//心拍数の計算、結果をリングバッファに入れる avgHR.unshift((60000 * 1000 / pulse_interval) / 1000.0);

ここで0除算でリセットになっている様子。

投稿2021/01/07 12:36

編集2021/01/22 07:26
thkana

総合スコア7639

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

gakutp

2021/01/27 14:41

こんな自分のプログラムをみて回答していただいてありがとうございます。 色々見返してしょうもないミスでグラフが表示されないのに気付きました。(心拍数表示は今もできませんが)
guest

0

何を聞きたいのかいまいちはっきりしないので当てずっぽですが、
提示のグラフのような波形が出るなら、その波形のピークを数えればいいんじゃないかと思いますが

投稿2021/01/06 23:19

y_waiwai

総合スコア87774

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問