So-net無料ブログ作成

mbed HRM1017 で Heart Rate Profile をサポートしてみる(6) [mbed]

mbed HRM1017 で心拍を視覚的に表現するために、Pixel Led (WS2812b) を接続してみました。


DSC04351.JPG


心拍センサー は5ピンに、LED は6ピンに接続をしています。


mbedHRM1017.png


プログラムは下記のサイトを参照してください。mbed にアカウントがあれば、インポートして使えると思います。


BLE_HeartRate.pnghttps://developer.mbed.org/users/YoshinoTaro/code/BLE_HeartRate/


実際の動きがこちら。思ったよりもつまらくてガッカリです。





うーん、なんか面白い視覚効果が出せないかなぁ。
ε=(ー。-)





mbed HRM1017

mbed HRM1017

  • 出版社/メーカー: スイッチサイエンス
  • メディア: Personal Computers



心拍センサ

心拍センサ

  • 出版社/メーカー: スイッチサイエンス
  • メディア: エレクトロニクス



waves WS2812B neopixel PCB 8連

waves WS2812B neopixel PCB 8連

  • 出版社/メーカー: waves
  • メディア:




mbed HRM1017 でカラーLED(WS2812B)を光らせてみた [mbed]

先日、カラーLEDアレイ WS2812B を買いました。しばらく放っておいたのですが、mbed HRM1017 で光らせてみることにしました。


DSC04332.JPG


mbed nRF51822 用の WS2812B 用のライブラリはこちらにあります。ライブラリとしてのインポートになるので、新しいプロジェクトを作って、”Import into Compiler” でワークスペースに取り込んでください。

https://developer.mbed.org/teams/Seeed/code/color_pixels/
color_pixels.png


WS2812B のシグナル用のピンはp6 ピンに接続しました。


mbedHRM1017_WS2812B.png


簡単なテストプログラムで動きを確認してみました。


#include "mbed.h"
#include "color_pixels.h"

// ColorPixels(signal_pin, number_of_LED)
ColorPixels pixels(6, 8);

int main() {
    while (true) {
        pixels.rainbow(rand()/256, rand()/256, rand()/256);
        wait(1);
    }
}



プログラムをコンパイルしダウンロードして書き込むと、あっけなく動きました!すげぇ。


DSC04330.JPG


動画はこちら!





mbed で出来ることも少しずつ増えてきました。さて、これで何を作ろうかなぁ!
(^_^)/~






waves WS2812B neopixel PCB 8連

waves WS2812B neopixel PCB 8連

  • 出版社/メーカー: waves
  • メディア:



mbed HRM1017

mbed HRM1017

  • 出版社/メーカー: スイッチサイエンス
  • メディア: Personal Computers



mbed電子工作レシピ

mbed電子工作レシピ

  • 作者: 勝 純一
  • 出版社/メーカー: 翔泳社
  • 発売日: 2016/01/23
  • メディア: 大型本




mbed HRM1017 で Heart Rate Profile をサポートしてみる(5) [mbed]

mbed HRM1017 をいよいよ Heart Rate Monitor にして、スマホとBLEで接続できるようにしてみたいと思います。心拍センサーの出力は前回の実験から10kΩを挟んで計測しています。


DSC04325.JPG


Heart Rate 計測のアルゴリズムは PulseSensor.com の内容をmbedに移植しました。


PULSE SENSOR AMPED
http://pulsesensor.com/pages/pulse-sensor-amped-arduino-v1dot1


ときどき値が飛ぶのでまだバグがあるようですが、参考までにソースコードを公開しておきます。


#include "mbed.h"
#include <limits.h>

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

#define NEED_DEBUG 
#ifdef NEED_DEBUG
#define DEBUG(...) { printf(__VA_ARGS__); }
#else
#define DEBUG(...) /* nothing */
#endif 

#define N 10
#define DEFAULT_THRESHOLD 500
#define DEFAULT_AMP 100

volatile int BPM = 60;
volatile int IBI = 600;

volatile bool Pulse = false;
volatile bool QS = false;

volatile int Rate[N];
volatile int CurrentBeatTime = 0;
volatile int LastBeatTime = 0;

volatile uint16_t Signal;
volatile uint16_t P = DEFAULT_THRESHOLD;
volatile uint16_t T = DEFAULT_THRESHOLD;
volatile uint16_t Threshold = DEFAULT_THRESHOLD;

volatile int Amplifier = DEFAULT_AMP;

Timer timer;
AnalogIn ain(p6);

void initPulseSensor(void) {
    for (int i = 0; i < N; ++i) {
        Rate[i] = 0;
    }
    timer.start();
    LastBeatTime = timer.read_ms();
}

int getBPM(void) {
    return BPM;
}

bool isQS(void) {
    bool qs = QS;
    QS = false;
    return qs;
}


void reset() {
    Threshold = DEFAULT_THRESHOLD;
    Amplifier = DEFAULT_AMP;
    P = T = DEFAULT_THRESHOLD;
}

void calcHeartRate(void) {
    
    Signal = ain.read_u16();
    CurrentBeatTime = timer.read_ms();
    // printf("%d\t%d\r\n", CurrentBeatTime, Signal);
    
    int interval = 0;
    if (CurrentBeatTime < LastBeatTime) {
        interval = INT_MAX - CurrentBeatTime + LastBeatTime;
    } else {
        interval = CurrentBeatTime - LastBeatTime;
    }
    
    if ((Signal < Threshold) && (interval > IBI * 3/5)) {
        if (Signal < T) { 
            T = Signal; // hold bottom
        }
    } else if ((Signal > Threshold) && (Signal > P)) {
        P = Signal; // hold peak 
    }
    
    if (interval > 250 && interval < 2500) { // msec
    
        if ((Signal > Threshold) && !Pulse && (interval > IBI * 3/5)) {
            Pulse = true;
            IBI = interval;
            
            if (Rate[0] < 0) {  // first time
                Rate[0] = 0;
                LastBeatTime = timer.read_ms();
                return;
            } else if (Rate[0] == 0) { // second time
                for (int i = 0; i < N; ++i) {
                    Rate[i] = IBI;
                }
            }
            
            int running_total = 0;
            for (int i = 0; i < N-1; ++i) {
                Rate[i] = Rate[i+1];
                running_total += Rate[i];
            }
            
            Rate[N-1] = IBI;
            running_total += IBI;
            running_total /= N;
            BPM = 60000 / running_total;
            QS = true;
            LastBeatTime = timer.read_ms();
            DEBUG("P:%d T:%d AMP:%d THR:%d BPM:%d\r\n"
                    ,P ,T ,Amplifier ,Threshold ,BPM);
        }
    }
    
    if (Pulse) {
        Pulse = false;
        if (P >= T) {
            Amplifier = P - T;
            Threshold = Amplifier/2 + T;  // update Threshold
            P = T = Threshold;
            DEBUG("Update Threshold:%d\r\n", Threshold);
        } else {
            DEBUG("Error: T(%d) over P(%d)\r\n", T, P);
            reset();
        }
    }
    
    // check if no Signal is over 2.5 sec
    if (interval >= 2500) {
        DEBUG("No Signal over 2.5sec\r\n");
        reset();
        LastBeatTime = timer.read_ms();
        for (int i = 0; i < N; ++i) {
            Rate[i] = -1;
        }
    }
}

#ifdef __cplusplus
}
#endif



メインのプログラムは下記のように変更を加えました。BLEのライブラリはこちらのサンプルで使われているライブラリをアップデートせずに使っています。

#include "mbed.h"
#include "BLE.h"
#include <math.h>

#include "PulseSensor.h"

#define NEED_DEBUG
#ifdef NEED_DEBUG
#define DEBUG(...) { printf(__VA_ARGS__); }
#else
#define DEBUG(...) /* nothing */
#endif 

const static char  DEVICE_NAME[] = "mbed HRM1017";
static volatile bool  triggerSensorPolling = false;

BLEDevice  ble;

/* Heart Rate Service */ 
static uint8_t hrmCounter = 100;
static uint8_t bpm[2] = {0x00, hrmCounter};
GattCharacteristic  hrmChar(
     GattCharacteristic::UUID_HEART_RATE_MEASUREMENT_CHAR
    ,bpm, sizeof(bpm) ,sizeof(bpm)
    ,GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
static uint8_t location = 0x05; /* Ear Lobe */
GattCharacteristic hrmLocation(
     GattCharacteristic::UUID_BODY_SENSOR_LOCATION_CHAR
    ,(uint8_t *)&location ,sizeof(location) ,sizeof(location)
    ,GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);
GattCharacteristic *hrmChars[] = {&hrmChar, &hrmLocation,};
GattService hrmService(GattService::UUID_HEART_RATE_SERVICE
    ,hrmChars ,sizeof(hrmChars)/sizeof(GattCharacteristic *));

/* Battery Level Service */
static uint8_t batt = 100;
GattCharacteristic battLevel(
     GattCharacteristic::UUID_BATTERY_LEVEL_CHAR
    ,(uint8_t *)&batt ,sizeof(batt) ,sizeof(batt)
    ,GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);             
GattCharacteristic *battChars[] = {&battLevel,};
GattService battService(
     GattService::UUID_BATTERY_SERVICE
    ,battChars ,sizeof(battChars)/sizeof(GattCharacteristic *));

/* Device Information service */
static uint8_t deviceName[] = {'H', 'R', 'M', '1', '0', '1', '7'};
GattCharacteristic deviceManufacturer(
     GattCharacteristic::UUID_MANUFACTURER_NAME_STRING_CHAR
    ,(uint8_t *)deviceName ,sizeof(deviceName) ,sizeof(deviceName)
    ,GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);
GattCharacteristic *devInfoChars[] = {&deviceManufacturer,};
GattService deviceInformationService(
     GattService::UUID_DEVICE_INFORMATION_SERVICE
    ,devInfoChars ,sizeof(devInfoChars)/sizeof(GattCharacteristic *));

static uint16_t uuid16_list[] = {
     GattService::UUID_HEART_RATE_SERVICE
    ,GattService::UUID_BATTERY_SERVICE
    ,GattService::UUID_DEVICE_INFORMATION_SERVICE
};

void updateServiceValues(void);
static Gap::ConnectionParams_t connectionParams;

void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
{
    DEBUG("Disconnected handle %u, reason %u\r\n", params->handle, params->reason);
    DEBUG("Restarting the advertising process\r\n");
    ble.gap().startAdvertising();
}

void onConnectionCallback(const Gap::ConnectionCallbackParams_t *params) 
{
    DEBUG("connected. Got handle %u\r\n", params->handle);

    connectionParams.slaveLatency = 1;
    if (ble.gap().updateConnectionParams(params->handle, &connectionParams)  
        != BLE_ERROR_NONE) {
        DEBUG("failed to update connection paramter\r\n");
    }
}

void periodicCallback(void)
{
    triggerSensorPolling = true;
}

int main(void)
{   
    Ticker ticker;
    ticker.attach(periodicCallback, 1);
        
    DEBUG("Initialising the nRF51822\r\n");
    ble.init();
    DEBUG("Init done\r\n");
    ble.gap().onDisconnection(disconnectionCallback);
    ble.gap().onConnection(onConnectionCallback);
    ble.gap().getPreferredConnectionParams(&connectionParams);

    /* setup advertising */
    ble.gap().accumulateAdvertisingPayload(
          GapAdvertisingData::BREDR_NOT_SUPPORTED 
        | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
    ble.gap().accumulateAdvertisingPayload(
         GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS
        ,(uint8_t*)uuid16_list, sizeof(uuid16_list));
    ble.gap().accumulateAdvertisingPayload(
         GapAdvertisingData::GENERIC_HEART_RATE_SENSOR);
    ble.gap().accumulateAdvertisingPayload(
         GapAdvertisingData::COMPLETE_LOCAL_NAME
        ,(uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
    ble.gap().setAdvertisingType(
         GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
    ble.gap().setAdvertisingInterval(160);  /* 100ms; in multiples of 0.625ms. */
    ble.gap().startAdvertising();
    DEBUG("Start Advertising\r\n");

    ble.gattServer().addService(hrmService);
    ble.gattServer().addService(battService);
    ble.gattServer().addService(deviceInformationService);
    DEBUG("Add Service\r\n");
    
    initPulseSensor();

    Ticker hrm_ticker;
    hrm_ticker.attach(calcHeartRate, 0.02);

    while (true) {
        if (triggerSensorPolling) {
            triggerSensorPolling = false;
            updateServiceValues();
        } else {
            ble.waitForEvent();
        }
    }
}

void updateServiceValues(void)
{
    /* Decrement the battery level. */
    batt <= 50 ? batt = 100 : batt--;
    ble.gattServer().write(
        battLevel.getValueAttribute().getHandle() ,(uint8_t*)&batt, sizeof(batt));

    /* Randomize the heart rate. */
    if (isQS()) {
        hrmCounter = getBPM();
        DEBUG("BPM: %d\r\n", hrmCounter);
    }
    bpm[1] = hrmCounter;
    ble.gattServer().write(hrmChar.getValueAttribute().getHandle() ,bpm, sizeof(bpm));
}



Nordic のスマホ向けテストアプリ nRFToolBox で動きを確かめてみました。心拍数が時々あがっているところは軽くスクワットをしているところです。


nRFToolBox_HRM.png


ちょっと値がおかしいところもありますが、ほぼ想定通りに動いているようです。実験しながらアルゴリズムを調整していきたいと思います。
(^_^)/~





心拍センサ

心拍センサ

  • 出版社/メーカー: スイッチサイエンス
  • メディア: エレクトロニクス



mbed HRM1017

mbed HRM1017

  • 出版社/メーカー: スイッチサイエンス
  • メディア: Personal Computers



mbed電子工作レシピ

mbed電子工作レシピ

  • 作者: 勝 純一
  • 出版社/メーカー: 翔泳社
  • 発売日: 2016/01/23
  • メディア: 大型本




mbed HRM1017 で Heart Rate Profile をサポートしてみる(4) [mbed]

前回まで心拍データにランダム値を使っていましたが、それではつまらないので、mbed HRM1017 に HeartRateSensor を接続してみました。


DSC04326.JPG


センサーの値がAnalogIn端子から読み取れるか試してみます。ピン配は下記のようにしてみました。


mbedHRM1017withPulseSensor.png


HeartRateSensor の値を読みだすプログラムを作ってみました。非常にシンプルなので分かりやすい!

#include "mbed.h"

AnalogIn ain(p6);
Timer timer;

void getHeartRateValue(void)
{
    uint16_t signal = ain.read_u16();
    int cur_time = timer.read_ms();
    printf("%d\t%d\r\n", cur_time, signal);
}

int main()
{
    timer.start();
    
    Ticker hrm_ticker;
    hrm_ticker.attach(getHeartRateValue, 0.02); // 20msec

    while(true);
}



読み取った値をグラフにしてみました。


mbedHRM1017_Pulse0ohm.png


心拍はとれているようですが、値がサチってしまっています。抵抗を間に入れたほうがよさそうです。10kΩを間に入れてみました。


DSC04325.JPG


10kΩを挟んでみたデータをグラフにしてみました。ピークが少し小さいですが、なかなか良い値がとれているようです。


mbedHRM1017_Pulse10kohm.png


センサーからデータが取れるようになったので、心拍計算用のアルゴリズムを導入してBLE心拍センサーに仕上げてみたいと思います!
(^_^)/~






心拍センサ

心拍センサ

  • 出版社/メーカー: スイッチサイエンス
  • メディア: エレクトロニクス



mbed HRM1017

mbed HRM1017

  • 出版社/メーカー: スイッチサイエンス
  • メディア: Personal Computers



mbed電子工作レシピ

mbed電子工作レシピ

  • 作者: 勝 純一
  • 出版社/メーカー: 翔泳社
  • 発売日: 2016/01/23
  • メディア: 大型本




mbed HRM1017 の Nordic BLE ライブラリにはまる [mbed]

mbed を使っていると、BLEライブラリをアップデートしたら?という案内が出てきます。下の緑にリサイクルマークのような奴がそうです。しかし、この誘いにやすやすと乗るのはよしましょう。


nRF51822.png


迂闊にアップデートをすると、自分の書いたソースコードを一行も変更していないのに Nordic のBLEライブラリの中でエラーが出てしまいます。さすがにライブラリの中でエラーが出ると手出しができません。


nRF51822_compile_error.png


mbed の BLEライブラリは更新頻度が高くてついていくのが大変だという話はよく聞きますが、ここまでとは。おかげで小一時間無駄にしてしまいました。mbed がいまいち盛り上がりに欠けるのはこういうところもあるのかなぁ。
ε=(-A -#)





mbed HRM1017

mbed HRM1017

  • 出版社/メーカー: スイッチサイエンス
  • メディア: Personal Computers



mbed NXP LPC1768

mbed NXP LPC1768

  • 出版社/メーカー: スイッチサイエンス
  • メディア: おもちゃ&ホビー



mbed電子工作レシピ

mbed電子工作レシピ

  • 作者: 勝 純一
  • 出版社/メーカー: 翔泳社
  • 発売日: 2016/01/23
  • メディア: 大型本




mbed HRM1017 で Heart Rate Profile をサポートしてみる(3) [mbed]

いよいよ、今回から mbed HRM1017 で Heart Rate Profile をサポートしてみたいと思います。前回の検討で、Heart Rate Profile は、Heart Rate Service と Device Information Service をサポートする必要があることが分かりました。


Services in Heart Rate Sensor.png


Heart Rate Service では、Heart Rate Measurement Characteristic とBody Sensor Location Characteristic の2つをサポートします。 mbed での宣言部は下記のようになります。

// Heart Rate Measurement Characteristic Setting
static uint8_t hrmCounter = 100;   // default value
static uint8_t bpm[2] = {0x00, hrmCounter};
GattCharacteristic  hrmChar(GattCharacteristic::UUID_HEART_RATE_MEASUREMENT_CHAR
                           ,bpm, sizeof(bpm) ,sizeof(bpm)
                           ,GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);

// Body Sensor Location Characteristic Setting
static uint8_t location = 0x05; /* Ear Lobe */
GattCharacteristic hrmLocation(GattCharacteristic::UUID_BODY_SENSOR_LOCATION_CHAR
                           ,(uint8_t *)&location ,sizeof(location) ,sizeof(location)
                           ,GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);

// Heart Rate Service Service
GattCharacteristic *hrmChars[] = {&hrmChar, &hrmLocation,};
GattService hrmService(GattService::UUID_HEART_RATE_SERVICE
                       ,hrmChars ,sizeof(hrmChars)/sizeof(GattCharacteristic *));



Device Information Service では、Device Information Service Characteristic をサポートします。

// Device Information Service Characteristic Setting
static uint8_t deviceName[] = {'H', 'R', 'M', '1', '0', '1', '7'};
GattCharacteristic deviceManufacturer(GattCharacteristic::UUID_MANUFACTURER_NAME_STRING_CHAR
                             ,(uint8_t *)deviceName ,sizeof(deviceName) ,sizeof(deviceName)
                             ,GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ);

// Device Information Service
GattCharacteristic *devInfoChars[] = {&deviceManufacturer,};
GattService deviceInformationService(GattService::UUID_DEVICE_INFORMATION_SERVICE
                             ,devInfoChars ,sizeof(devInfoChars)/sizeof(GattCharacteristic *));



NORDIC の nRFToolbox では、Battery Level も表示するようになっていますので参考までに設定を載せておきます。(mbed HRM1017 のサンプルプログラムでも記載されています)

// Battery Level Characteristic Setting
static uint8_t batt = 100;
GattCharacteristic battLevel(GattCharacteristic::UUID_BATTERY_LEVEL_CHAR
                            ,(uint8_t *)&batt ,sizeof(batt) ,sizeof(batt)
                            ,GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);

// Battery Level Service             
GattCharacteristic *battChars[] = {&battLevel,};
GattService battService(GattService::UUID_BATTERY_SERVICE
                       ,battChars ,sizeof(battChars)/sizeof(GattCharacteristic *));



だいたいパターンはわかったと思います。次にサポートするサービスを Advertising パケットに組み込みます。Advertising とは Collector と接続するための仕組みで、Advertising パケットの中に自分がどのようなサービスを提供しているか記述する必要があります。

// service list
static uint16_t uuid16_list[] = {
    GattService::UUID_HEART_RATE_SERVICE
   ,GattService::UUID_BATTERY_SERVICE
   ,GattService::UUID_DEVICE_INFORMATION_SERVICE
};


BLEDevice ble;

// only BLE support, not support the classic bluetooth
ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED  |   GapAdvertisingData::LE_GENERAL_DISCOVERABLE);

// registering the supported services
ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS , (uint8_t*)uuid16_list, sizeof(uuid16_list));

// the appearance is a heart rate sensor
ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR);

// registering the device name
ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME , (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));

// setting as a connectable device to a collector
ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);

// advertising interval is 100msec
ble.gap().setAdvertisingInterval(160); 
ble.gap().startAdvertising();


Advertising パケットの詳細については、こちらを参照ください。非常に参考になります。


BluetoothSMARTデバイスをmbed で開発する(4)
http://bril-tech.blogspot.jp/2014/06/bluetoothsmartmbed-4.html


今回作成した全コードは下記リポジトリにありますので参照ください。今回は心拍センサーは接続せずにランダム値を心拍データとして扱っています。


BLE_HeartRate
https://developer.mbed.org/users/YoshinoTaro/code/BLE_HeartRate/


それでは、nRFToolbox の Heart Rate Monitor でどう見えるか見てみましょう。


Heart Rate Monitor.png


おお、それらしく見えてますね!Device Information も Body Location も認識しているようです。

スマホと接続できると値を記録できるので、心拍計としての応用範囲がぐっと広がりますね。次はいよいよ心拍センサーを接続してみたいと思います!
(^_^)/~






mbed HRM1017

mbed HRM1017

  • 出版社/メーカー: スイッチサイエンス
  • メディア: Personal Computers



mbed LPC824

mbed LPC824

  • 出版社/メーカー: スイッチサイエンス
  • メディア: エレクトロニクス



mbed電子工作レシピ

mbed電子工作レシピ

  • 作者: 勝 純一
  • 出版社/メーカー: 翔泳社
  • 発売日: 2016/01/23
  • メディア: 大型本




mbed HRM1017 で Heart Rate Profile をサポートしてみる(2) [mbed]

前回から少し間が空きましたが mbed HRM1017 で Heart Rate Profile をサポートする検討の続きです。 Heart Rate Profile の仕様書は下記サイトでダウンロードできます。

仕様書へのリンクは少し分かりにくいところにありますので注意してください。


heartrateprofile.png
https://developer.bluetooth.org/TechnologyOverview/Pages/HRP.aspx


Heart Rate Sensor は二つのサービスをサポートすることが必須となります。Heart Rate Service と、Device Information Service です。心拍情報を提供と製品情報の提供ですね。


Services in Heart Rate Sensor.png


こちらは、仕様書から抜き出した Heart Rate Service と Device Information Service がサポートすべきCharacteristics の抜粋です。


characteristics-in-heartratesensor.png


まずは Heart Rate Service がサポートすべき Characteristics から、

  • Heart Rate Measurement Characteristic は、心拍数データを表します。Heart Rate Sensor から Collector へ通知するデータです。

  • Body Sensor Location Characteristic は、身体のどの位置につけるセンサーかを示すデータです。Other(0x00)、Chest(0x01)、Wrist(0x02)、Finger(0x03)、Hand(0x04)、Ear Lobe(0x05)、Foot(0x06)等が定義されています。

  • Heart Rate Control Point Characteristic は、何なのか一番悩みました。Energy Expended がよく分からなかったのですが、文字通り”エネルギー消費量”、活動量計ってことですね。活動量を提示する機能があるデバイスなら、Collector からゼロリセット出来るようにしておけということらしいです。


  • Device Information Service の Characteristics については詳細が記述されていませんが、ここには製品情報(メーカー名や製品名)を格納します。

    だいたい様子は分かりました。今回は活動量計をつけるつもりはないので、Heart Rate Control Point はサポートしなくてもよいかな。
    σ( ̄_ ̄)






    mbed HRM1017

    mbed HRM1017

    • 出版社/メーカー: スイッチサイエンス
    • メディア: Personal Computers



    Garmin Heart Rate Monitor 正規品

    Garmin Heart Rate Monitor 正規品

    • 出版社/メーカー: GARMIN(ガーミン)
    • メディア: Wireless Phone Accessory



    Bluetooth Low Energyをはじめよう (Make:PROJECTS)

    Bluetooth Low Energyをはじめよう (Make:PROJECTS)

    • 作者: Kevin Townsend
    • 出版社/メーカー: オライリージャパン
    • 発売日: 2015/02/25
    • メディア: 単行本(ソフトカバー)


    mbed HRM1017 で Heart Rate Profile をサポートしてみる(1) [mbed]

    mbed HRM1017 のサンプルプログラムはHealth Thermometer Profile (HTM) をサポートしています。

    c_nRFToolbox.png


    今回はサンプルプログラムを改造して Health Thermometer Profile の代わりに Heart Rate Profile をサポートしてみたいと思います。

    その前に、BLEの基本プロトコルであるGATTプロファイルの構造について調べてみました。GATTプロファイルは大きく3つの情報から構成されています。


    ・デバイスが提供するサービス (Service)
    ・デバイスの持つ属性値 (Characteristic)
    ・デバイスの持つ属性 (Characteristic) への付加情報 (Descriptor) 

    出典: http://yegang.hatenablog.com/entry/2014/08/09/195246


    GATTは、サービスとプロファイルが混在しており分かりにくいですが、どうも機器固有機能はプロファイルとサービスが定義され、機器によらない一般的な情報はサービスのみとなっているようです。
    https://www.bluetooth.com/specifications/adopted-specifications

    参考までに、GATTでサポートしているプロファイルの一覧を列挙しておきます。

    Alert NotificationThis profile enables a client device to receive different types of alerts and event information, as well as information on the count of new alerts and unread items, which exist in the server device.
    Blood PressureThis profile enables a device to connect and interact with a Blood Pressure Sensor device for use in consumer and professional health care applications.
    Cycling PowerThis profile enables a Collector device to connect and interact with a Cycling Power Sensor for use in sports and fitness applications.
    Cycling Speed and CadenceThis profile enables a Collector device to connect and interact with a Cycling Speed and Cadence Sensor for use in sports and fitness applications.
    Find MeThe Find Me profile defines the behavior when a button is pressed on one device to cause an alerting signal on a peer device.
    GlucoseThis profile enables a device to connect and interact with a glucose sensor for use in consumer and professional healthcare applications.
    Health ThermometerThis profile enables a Collector device to connect and interact with a Thermometer sensor for use in healthcare applications.
    Heart RateThis profile enables a Collector device to connect and interact with a Heart Rate Sensor for use in fitness applications.
    HID OVER GATTThis profile defines how a device with Bluetooth low energy wireless communications can support HID services over the Bluetooth low energy protocol stack using the Generic Attribute Profile.
    Location and NavigationThis profile enables a Collector device to connect and interact with a Location and Navigation Sensor for use in outdoor activity applications.
    Phone Alert StatusThis profile enables a PUID device to alert its user about the alert status of a phone connected to the PUID device.
    ProximityThe Proximity profile enables proximity monitoring between two devices.
    Running Speed and CadenceThis profile enables a Collector device to connect and interact with a Runners Speed and Cadence Sensor for use in sports and fitness applications.
    Scan ParametersThis profile defines how a Scan Client device with Bluetooth low energy wireless communications can write its scanning behavior to a Scan Server, and how a Scan Server can request updates of a Scan Client scanning behavior.
    TimeThe Time profile enables the device to get the date, time, time zone, and DST information and control the functions related the time.

    出典:https://developer.bluetooth.org/gatt/profiles/Pages/ProfilesHome.aspx


    BLEではホスト機能を持つ機器を "Central" と呼びデバイス機能を持つ機器を "Peripheral" と呼びます。(参考: http://yegang.hatenablog.com/entry/2014/07/19/224754 ) これらのプロファイル は Peripheral が持つ機能に相当します。

    サンプルプログラムではどのように mbed HRM1017 へ Health Thermometer Profile を設定しているか抜粋し整理してみました。


    // Health Thermometer の Characteristics の定義 
    uint8_t  thermTempPayload[5] = { 0, 0, 0, 0, 0 };
    GattCharacteristic  tempChar (GattCharacteristic::UUID_TEMPERATURE_MEASUREMENT_CHAR, thermTempPayload, 5, 5, GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_INDICATE);
    GattCharacteristic *htmChars[] = {&tempChar, };
    ...
    // Health Thermometer の Service の定義
    GattService htmService(GattService::UUID_HEALTH_THERMOMETER_SERVICE, htmChars, sizeof(htmChars) / sizeof(GattCharacteristic *));
    ...
    // サポートするサービス一覧
    uint16_t uuid16_list[] = {GattService::UUID_HEALTH_THERMOMETER_SERVICE, GattService::UUID_BATTERY_SERVICE};
    ...
    // Advertising (サービスディスカバリー)のための設定    
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t*)uuid16_list, sizeof(uuid16_list));
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_THERMOMETER);
    ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
    ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
    ble.gap().setAdvertisingInterval(160); /* 100ms; in multiples of 0.625ms. */
    ble.gap().startAdvertising();
    ...
    // サービスの登録
    ble.gattServer().addService(htmService);
    ...
    //デバイス情報の Central (例えばスマホ)へ通知 
    ble.gattServer().write(tempChar.getValueAttribute().getHandle(), thermTempPayload, sizeof(thermTempPayload));
    


    Advertising は Central (スマホ)が Peripheral を見つけるためのプロトコルです。詳細について知りたい方はこちらのサイトが参考になると思います。

    まぁ中身は詳しく分からなくとも、この流儀に従えば Heart Rate Profile の追加ができそうですね。
    (^_^)/~





    mbed HRM1017

    mbed HRM1017

    • 出版社/メーカー: スイッチサイエンス
    • メディア: Personal Computers



    mbed LPC824

    mbed LPC824

    • 出版社/メーカー: スイッチサイエンス
    • メディア: エレクトロニクス



    mbed電子工作レシピ

    mbed電子工作レシピ

    • 作者: 勝 純一
    • 出版社/メーカー: 翔泳社
    • 発売日: 2016/01/23
    • メディア: 大型本



    mbed HRM1017 で "Hello World" してみた [mbed]

    mbed HRM1017 でLチカするのは、GPIO が 0.5mA しかドライブできないのでちょっとやっかいです。ということで、手軽にデバッグするためにシリアル出力を試してみました。


    ab_DSC04297.JPG


    シリアル出力をするには、ドライバをインストールする必要があります。Switch Science さん提供の mbed HRM1017 のページから辿れます。

    9_mbed-serial-driver.png
    mbed-HRM1017をはじめよう


    ドライバをインストールする時は、mbed HRM1017 をUSBで接続しておく必要があります。接続していないと、「The driver could not be installed」と出て失敗してしまいます。

    ドライバのインストールが成功すると、mbed用のCOMポートが見えます。baud rate はデフォルトで 9600 bps ですので注意してください。

    tera-term-mbed.png


    それでは、プログラムを書いて試してみましょう。メニューの新規を選択して、「mbed_blinky」をテンプレートに選択します。

    mbed_HelloWorld.png


    LEDはついてないのでコメントアウトをして、おなじみの "Hello World" を書き加えます。

    mbed_HelloWorld_2.png


    ターミナルを立ち上げて、ダウンロードしたイメージの mbed HRM1017 への書き込みをします。書き込みが完了すると”Hello World”が表示されるはずです。

    mbed_HelloWorld_3.png

    無事に”Hello World”が表示されました!これでデバッグが捗りそうです。
    (^_^)/~






    mbed HRM1017

    mbed HRM1017

    • 出版社/メーカー: スイッチサイエンス
    • メディア: Personal Computers



    mbed LPC824

    mbed LPC824

    • 出版社/メーカー: スイッチサイエンス
    • メディア: エレクトロニクス



    mbed電子工作レシピ

    mbed電子工作レシピ

    • 作者: 勝 純一
    • 出版社/メーカー: 翔泳社
    • 発売日: 2016/01/23
    • メディア: 大型本




    mbed で HRM1017 を動かしてみた! [mbed]

    前回、mbed でのプログラムのコンパイルまで終わりましたので、いよいよダウンロードしたイメージを書き込み、HRM1017を動かしてみたいと思います。

    00_DSC04296.JPG


    mbed にイメージを書き込むのは、すごく簡単です。 HRM1017 をUSBで接続すると、mbed というドライブが追加されます。そこにダウンロードしてきたイメージをコピーするだけです。

    a_mbed-install.png


    書き込み中はLEDが点滅します。LEDの点滅が終わったら書き込み完了です。

    ab_DSC04297.JPG


    書き込んだプログラムが動作しているか確認するために、Android アプリをインストールする必要があります。Nordic が提供している nRF TOOLBOX というアプリをインストールします。※使用しているスマートフォンがBLE (Bluetooth 4.0以上)に対応しているか確認してください。

    b_nRFToolbox.png


    インストールが終わったら nRF TOOLBOX を起動します。メニューが出てきますので、そこで「HTM」を選択します。

    c_nRFToolbox.png


    「CONNECT」を選択します。

    d_nRFToolbox.png


    接続機器リストが表示されますので、その中から「HRM1017_HTM」を選択します。

    e_nRFToolbox.png


    ボタンが”CONNECT”から”DISCONNECT”に変わりますので、接続されたことが分かります。肝心の温度はセンサーを接続していないので”0.00”から変化しませんが、バッテリーの数値が変わりますので、そこからも動作しているのが分かります。

    f_nRFToolbox.png


    mbed での開発のスタイルはだいたい分かりました。次はこのプログラムを Heart Rate Monitor に対応させてみようかな。
    (^_^)/~





    mbed HRM1017

    mbed HRM1017

    • 出版社/メーカー: スイッチサイエンス
    • メディア: Personal Computers



    mbed NXP LPC1768

    mbed NXP LPC1768

    • 出版社/メーカー: スイッチサイエンス
    • メディア: おもちゃ&ホビー



    mbed電子工作レシピ

    mbed電子工作レシピ

    • 作者: 勝 純一
    • 出版社/メーカー: 翔泳社
    • 発売日: 2016/01/23
    • メディア: 大型本