見出し画像

心拍センサーを用いた心拍異常の検出と救助を促すアプリの開発

++++
千葉県立柏の葉高等学校情報理数科は、情報分野のスペシャリスト育成を目指し、大学進学を目指す情報の専門学科です。クラウドファンディングにチャレンジ中!
++++

こんにちは。
今日は、「課題研究」という授業で開発したアプリの備忘録として、後輩へのメッセージとしてこのブログに残したいと思います。

はじめに

課題研究は、班で問題を見つけ、ICT技術を用いてそれを解決していくという授業です。わたしたちの班は、「心肺機能停止傷病者の一般市民による救助数が少ない」という問題を解決するために、ウェアラブル端末で心拍数を取得してスマートフォンのアプリに送信し、心拍異常を検出した際には、スマートフォンから心肺蘇生法の方法をガイダンスする音声を再生するアプリの開発を行いました。

心拍数を取得、アプリに表示
正常域から外れた場合、音声を再生し、画面上に表示

開発環境・使用機材

Replit
アプリの開発に使用した、オンライン統合開発環境


Replitの開発画面

Web Blutooth CG
githubに掲載されているライブラリ。アプリのウェアラブル端末とスマートフォンの接続と、心拍数の送信をこのライブラリを使用し開発しました。

https://github.com/WebBluetoothCG/demos/tree/gh-pages/heart-rate-sensor

narakeet
合成音声の作成に使用しました。

CooSpo HW706
使用したウェアラブル端末

CooSpo HW706

コード概要

参考にさせていただいたアプリはこちら。

今回はindex.html、styles.css、app.js、heartRateSensor.jsを使用します。
開発環境にファイルごとコピーすれば使用できます。前述したように、今回はReplitでコードをいじってみます。

index.html

<!doctype html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Heart App</title>
    <meta name="description" content="Monitor a heart rate sensor with a Web Bluetooth app.">
    <link rel="icon" sizes="192x192" href="../favicon.png">
    <link href="style.css" rel="stylesheet" type="text/css" />
  </head>
  <body>
    <div id="container">
      <h1 id="title">Heart App</h1>
      <div id="booo"></div>
      <div id="aooo"></div>
      <div id="statusText">GET &#x2764;</div>
      <canvas id="waves"></canvas>
    </div>
    <script src="heartRateSensor.js"></script>
    <script src="app.js"></script>
  </body>
</html>

heartRateSensor.js

(function() {
  'use strict';

  class HeartRateSensor {
    constructor() {
      this.device = null;
      this.server = null;
      this._characteristics = new Map();
    }
    connect() {
      return navigator.bluetooth.requestDevice({filters:[{services:[ 'heart_rate' ]}]})
      .then(device => {
        this.device = device;
        return device.gatt.connect();
      })
      .then(server => {
        this.server = server;
        return server.getPrimaryService('heart_rate');
      })
      .then(service => {
        return this._cacheCharacteristic(service, 'heart_rate_measurement');
      })
    }


アプリ起動時


「Bluetooth接続を開始する」を押した際に遷移する画面

「Bluetooth接続を開始する」を押した際に遷移する画面真ん中の「GET」ボタンを押すとBluetooth接続が開始される。
「GET」ボタンのHTML部分

<div id="statusText">GET &#x2764;</div>

ウェアラブル端末での心拍数の取得
(heartRateSensor.js27~66行目)

startNotificationsHeartRateMeasurement() {
      return this._startNotifications('heart_rate_measurement');
    }
    stopNotificationsHeartRateMeasurement() {
      return this._stopNotifications('heart_rate_measurement');
    }
    parseHeartRate(value) {
      // In Chrome 50+, a DataView is returned instead of an ArrayBuffer.
      value = value.buffer ? value : new DataView(value);
      let flags = value.getUint8(0);
      let rate16Bits = flags & 0x1;
      let result = {};
      let index = 1;
      if (rate16Bits) {
        result.heartRate = value.getUint16(index, /*littleEndian=*/true);
        index += 2;
      } else {
        result.heartRate = value.getUint8(index);
        index += 1;
      }
      let contactDetected = flags & 0x2;
      let contactSensorPresent = flags & 0x4;
      if (contactSensorPresent) {
        result.contactDetected = !!contactDetected;
      }
      let energyPresent = flags & 0x8;
      if (energyPresent) {
        result.energyExpended = value.getUint16(index, /*littleEndian=*/true);
        index += 2;
      }
      let rrIntervalPresent = flags & 0x10;
      if (rrIntervalPresent) {
        let rrIntervals = [];
        for (; index + 1 < value.byteLength; index += 2) {
          rrIntervals.push(value.getUint16(index, /*littleEndian=*/true));
        }
        result.rrIntervals = rrIntervals;
      }
      return result;
    }

ウェアラブル端末との接続が完了すると取得された心拍数が表示されます。

心拍数の処理
app.js73~90行目

/*値を取って文字として表示*/
heartRateMeasurement.addEventListener('characteristicvaluechanged', event => {
  var heartRateMeasurement = heartRateSensor.parseHeartRate(event.target.value);
  statusText.innerHTML = heartRateMeasurement.heartRate + ' &#x2764;';
/*異常値にいた時の処理*/
  if (heartRateMeasurement.heartRate < min || heartRateMeasurement.heartRate > Max) {
    music.play();//警告音を鳴らす
    statusText.textContent = "心拍異常を検出";
    booo.innerHTML = '<a type= button id= stop onClick="stop();">止める</a>';
   /*通常時に戻った時と通常時*/
 if (typeof navigator.vibrate == 'function') { navigator.vibrate(200); };
  } else {
    music.pause();
    booo.innerHTML = '';
  }
  heartRates.push(heartRateMeasurement.heartRate);
 /*グラフを描画する*/
  drawWaves();
 });

var heartRateMeasurement = heartRateSensor.parseHeartRate(event.target.value);
上記のコードで宣言している変数に心拍数が格納されます。

これで、心拍異常を検出することができました。

まとめ

当初考案したシステムは完成しましたが、救助を要請などに適した音を研究がまだまだ足りませんでした。また、たくさんの人に使ってもらうためには過去の記録を見れるようにしたり、不整脈の検知や使用可能なデバイスの拡大などの工夫をしていく必要があると感じました。

++++
情報理数科では、3Dプリンタを新調すべくクラウドファンディングに挑戦中です!

https://cms1.chiba-c.ed.jp/kashiwanoha/htdocs/寄附/

みんなにも読んでほしいですか?

オススメした記事はフォロワーのタイムラインに表示されます!