心拍センサーの値をmbed「Simple IoT Board」で読み、 Ambientに送って心拍数をモニターしてみました。

心拍センサー「Pulse Sensor Amped」

使用したのは 「Pulse Sensor Amped」という心拍センサーキット で、スイッチサイエンスで購入しました。 60cmぐらいのリード線のついた心拍センサーと保護フィルムなどの付属品が同梱されてきます。 この心拍センサーはLEDと受光部を持った光学式です。 光学式心拍センサーはLEDから皮膚に光を照射し、血流によって変化する反射光を測定することで、 心拍を測るものだそうです。

心拍センサーは直径16mmの丸い基盤にLEDと受光部、いくつかの部品が載っています。

部品がむき出しなので、 センサーのWebサイトの動画を参考に、センサーを保護しました。 LEDと受光部が見えている面に付属の保護フィルムを貼り、 反対側の部品が載っている面はホットグルーを盛って保護します。 写真はホットグルーの上に付属の丸いマジックテープを付けたところです。

心拍センサーの値を読む

心拍センサーをmbed「Simple IoT Board」につなぎ、値を読んでみます。

心拍センサーからは3本のピン、3〜5Vの電源とグランドと信号線が出ています。 これをSimple IoT BoardのGroveコネクターのアナログポートにつなぎます。 心拍センサーの信号線はmbed LPC1114FN28のdp13につながります。

これで心拍センサーの値は次のようにfloatかunsigned shortで読めるようになります。

    AnalogIn pulsePin(dp13);
    f_val = pulsePin.read();
    us_val = pulsePin.read_u16();

心拍センサーの動作確認のために、信号線を5m秒間隔で600回読み、 プリントアウトしてグラフ化してみました。 センサーの値はメモリを節約するためにunsigned shortで扱うことにしました。 プログラムはこんな感じです。

    #include "mbed.h"
    #include "SoftSerialSendOnry.h"

    #define SAMPLING 5      //  Sampling period in milliseconds
    #define NSAMPLES 600    //  Number of Samples

    SoftSerialSendOnry pc(dp10);

    AnalogIn pulsePin(dp13);
    Ticker t2;
    volatile int done = false;
    unsigned short signal[NSAMPLES];
    int sampleIndex = 0;

    void sampling() {
        signal[sampleIndex++] = pulsePin.read_u16();
        if (sampleIndex >= NSAMPLES) {
            done = true;
        }
    }

    int main() {
        pc.baud(9600);
        wait(2.0);

        t2.attach_us(&sampling, SAMPLING * 1000.0f);
        while (!done) {
            ;
        }
        t2.detach();

        for (int i = 0; i < NSAMPLES; i++) {
            pc.printf("%d, ", signal[i]);
        }
    }

プログラムを動かすと、次のような心拍データーが得られました。

なんとなくそれらしいグラフです。 センサーのWebサイトにあるグラフ と比べても、似たような波形が得られています。 心拍数については、3秒間に4拍ぐらいしており、1分間だと80拍ぐらいです。 初めての心拍数計測で、少しドキドキしていたのかもしれません。

心拍数を計算する

心拍数を計算するプログラムはセンサーのWebサイトに公開されています。 公開されているのはArduinoプログラム(スケッチ)ですが、これをmbedに移植しました。 アルゴリズムはセンサーのWebサイトに詳しい説明がありますが、ざっくり言うと、次のような流れです。

  • 2m秒ごとにタイマー割り込みを発生させ、センサーの値をサンプリングする
  • 波形の立ち上がり部分の底(T)と頂点(P)を見つけ、その半分の点を心拍の基準点とする
  • 基準点と次の基準点の間の時間(心拍間隔)を求め、1拍ごとに1分間の心拍数(BPM)を求める
  • 10拍分の移動平均で最終的なBPM値を計算する

Ambientに送信して心拍数をモニターする

心拍データーはタイマー割り込みでサンプリングされ、心拍数が更新され続けます。 プログラムのメインループでは、5秒ごとにその時の心拍数をAmbientに送り、 グラフ化するようにしました。

プログラムはmbedサイトで公開しました。

心拍モニターで心拍を測っているところです。心拍に合わせてLEDを点滅させています。 心拍モニターからは5秒ごとに心拍数をAmbientに送っており、 Ambientはデーターを受信すると、リアルタイムにグラフを更新しています。

心拍波形をグラフ化する

冒頭の心拍データーのグラフは、心拍センサーを5m秒間隔で600回読み、一旦メモリー上に記録し、 センサーの読み込みが終わったら記録したデーターをプリントアウトし、 それを手作業でExcelに貼り込んでグラフ化しました。

次はこれを、複数データー一括送信bulk_send()を使って自動化してみます。

心拍数のモニターはmbed「Simple IoT Board」を使いましたが、 「Simple IoT Board」に搭載されているLPC1114FN28というマイコンは RAMエリアが4kBと小さく、数百件のデーターをメモリー上で扱うのは向いていません。 そこで今回は手元にあったESP8266というArduinoが動くマイコンを使いました。 ESP8266はユーザーが使えるRAMエリアが40〜45kBぐらいあるので、 数百件のデーターも楽に扱えそうです。

プログラムはGithubに公開しました。

本来は、センサー値を読んだ時刻をmillis()で取得し、 時刻とデーターのペアを配列にして記録して送信する必要がありますが、 今回はサボって時刻は5ミリ秒の倍数として計算しました。 タイマー割り込みでセンサー値を読んでいるので、実際とそれほどずれていないと思います。

複数データー一括送信機能bulk_send()の詳細は 「複数データーの一括送信機能 bulk_send()を実現しました」 をご覧ください。

得られた心拍波形はこんな感じです。