Max30102 + M5StickC

Post date: 2020/06/21

1. なぜ血中酸素濃度測定

在宅ワークのためのホコリセンサーのつもりで Max30105 (particle sensor) を買おうとしていたのだが、何かの間違いで Max30102 (pulse oximeter, heart-rate sensor) を買ってしまった。Amazon でいろいろ見て回るうちに、一番安いのを買ったのかもしれない(が、よく覚えていない)。

せっかくなので、脈拍と血中酸素濃度の測定器を作成することにした。

2. RaspberryPi で測定

RaspberryPi Zero WH につないで、測ってみた。

こちらのサイト(Raspberry Piと心拍センサ(MAX30102)で脈を見てみよう)のソースを動かしてみたところ、5V をつなげばそのまま動いた。

  1. 3V3 -> VIN は NG ($ i2cdetect -y 1 で出ない)
  2. 5V -> VIN, GPIO0->SDA, GPIO2->SCL, GND->GND, GPIO4 -> INT で接続

血中酸素濃度も図れるようなので感心していたら、家族から「それ最近品薄で問題になっているやつ」との指摘あり。

M5StickC につないで、表示ありで動くようにすることにした。

3. M5StickC での苦難

Amazon の販売ページにMeasure Heart Rate and SpO2 with MAX30102という記事へのリンクあったので、それを利用

  1. Arduinoに Sparkfun_MAX3010x library をいれる
  2. 5V, G0->SDA, G26->SCL, GND でつなぐ
    • M5.begin();
    • Wire.begin(0, 26);
  3. 仕様
    • 脈拍と SPO2 値を表示
    • IR データのグラフを表示

問題発生:

  1. particleSensor.begin() が1回で応答しないので、while ループに変更
    • while(!particleSensor.begin()) { delay(1); }
  2. library で計算させた HeartRate がどうもおかしい (時間間隔決め打ち?) ので、ピークをカウントして BPM (Beat Per Minute) を計算
    • なぜかやや大きめ (70 - 80) に出るが、良しとする
  3. SPO2 値がおかしい (ほとんど正常値 (96-99) にならない)
    • SPO2 値は上記 RaspPiZero 版では結構まともに出ていたので、もしかして library がおかしい (なんてことあるのか)?

仕方がないので、SPO2値の計算方法を調べてみるが、とりあえず2波長のAC成分とDC成分から計算すればよいことがわかる。

※本当は、Maker Faire Kyoto Online に参加しようと 5/2 当日朝から頑張っていたのだが、15:30 にぎりぎり間に合わず断念。

4. 解決の兆し

その後、忙しいので放っておいたが、Amazon の販売ページに新しいコメントを発見(同等品と思われるこちらにも記述あり)。やはり library がおかしい (それも、red と IR のデータが逆?点滅の順がおかしい?)。

詳しくはこちら (MAX30102でパルスオキシメーターを作る)。

記事通りに、led=1 (red only) としてみると、

  • IRのみ灯火 (見えない)
  • 指をあてると
    • getRed() はデータが出る
    • getIR() はデータが出ない。

ことがわかる。つまり、

  • led=1 は IR only
  • getRed() は IR灯火時のセンサ読み取り値
  • getIR() は Red 灯火時のセンサ読み取りの値

であることが確認されてしまう。ライブラリのソースを見ると順番に読み取っているだけのようなのだが、面倒なのでアドホックに対応。

  1. プログラム中の getRed()getIR() に変更
  2. プログラム中の getIR()getRed() に変更

これでとりあえず動くようになった。

※ただ、私のはうまく読み取れるのだが。。。。

Red, IR, Green の順に4 byte x 3 づつ読み出し -> 18 bit 抜き出し

修正方法?:

  1. 読み出し順を IR, Red, Green にしてやればOKなのでは??
    1. Max30102には Green はないはず。。。
    2. data sheet によれば Red, IR の順
  2. LEDの発光順を変えれば良い?(できるのか?)
  3. Max 30102 には SpO2 Subsystem があるので、そこからとってくればよいのでは?
    1. SpO2 mode, HR mode がある
...
static const uint8_t SLOT_RED_LED =     0x01;
static const uint8_t SLOT_IR_LED =     0x02;
static const uint8_t SLOT_GREEN_LED =    0x03;
...
void MAX30105::setup(...) {
  ...
  //Multi-LED Mode Configuration, Enable the reading of the three LEDs
  //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
  enableSlot(1, SLOT_RED_LED);
  if (ledMode > 1) enableSlot(2, SLOT_IR_LED);
  if (ledMode > 2) enableSlot(3, SLOT_GREEN_LED);
  ...
}
uint16_t MAX30105::check(void)
{
...
      while (toGet > 0)
      {
        ...
        byte temp[sizeof(uint32_t)]; //Array of 4 bytes that we will convert into long
        uint32_t tempLong;

        //Burst read three bytes - RED
        temp[3] = 0;
        temp[2] = _i2cPort->read();
        temp[1] = _i2cPort->read();
        temp[0] = _i2cPort->read();

        //Convert array to long
        memcpy(&tempLong, temp, sizeof(tempLong));
        tempLong &= 0x3FFFF; //Zero out all but 18 bits

        sense.red[sense.head] = tempLong; //Store this reading into the sense array

        if (activeLEDs > 1)
        {
          ...          
          sense.IR[sense.head] = tempLong;
        }

        if (activeLEDs > 2)
        {
          ...
          sense.green[sense.head] = tempLong;
        }

        toGet -= activeLEDs * 3;
      }

5. そしてこんどこそ

みんなのM5Stack自慢大会」の告知を SwitchScience で発見し、何とかネタにしようと30分考えた。

  • SPO2 > 95 (つまり、健康) だったら
    1. LED 点灯
    2. SOLAR パワーで、100円招き猫が手を振る

ということで、プログラム小修正と、実験開始。しかし、なかなか動くようで、動かないようで。。。。

とりあえず「Heboi」ジャンルで、facebook に投稿 (2020-06-20)。

6. 残った謎

  • なぜ Sparkfun_MAX3010x を使うと getRed() と getIR() が逆になるのか
    • MAX30102 のデータシート
      • p.21, Table 9. Multi-LED Mode Control Registers
        • 001 : LED1 (Red), 010: LED2 (IR)
      • p.25, Figure 3
        • Red -> IR の順に点灯
  • VIN に 5V かけて大丈夫なのか
    • 製品記事には 1.8V ~ 2.5V と書いてある (ボード裏のジャンパーは I2C のプルアップレベル 1.8V/3.3V (3.3Vを選択))
    • RaspberryPi の i2cdetect では、5V 見つかる / 3.3V 見つからず
    • Sparkfun の MAX30105 ボードは 5V (MAX30105 Particle and Pulse Ox Sensor Hookup Guide)
  • INT を使って制御するべきか
  • データシートから
    • 温度補償
    • SPO2モード:Table 5 Events Sequence を再現しないといけないのではないか
  • 頑張ると nRF Toolbox for BLE でデータが読めるらしい