So-net無料ブログ作成
検索選択
前の5件 | -

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
  • メディア: 大型本




久しぶりに人物画の練習 [恥ずかしながらデジ絵やってます]

「君の名は」に触発されて、久しぶりに絵を描きたくなってしまいました。かなり久しぶりなので、きちんと描けるかなと思ったのですが、小一時間で描き上げた割にはよい出来。


練習.jpg


骨格を意識して描くことはなんとなく出来てますが、まだ筋肉の付き方の理解が足りないかなぁ。背景画も描き加えたいところですが、背景画はかなりの労力を使うので、また時間のあったときにでも。しばらくは人物画の練習で我慢。

それを考えると「君の名は」の背景画担当の人たち、すごい大変だっただろうなぁと想像してしまいます。次回作も素晴らしい映像を期待してます。
(^_^)/~





CLIP STUDIO PAINT PRO

CLIP STUDIO PAINT PRO

  • 出版社/メーカー: セルシス
  • メディア: DVD-ROM



デジタルイラストの「塗り」事典 CLIP STUDIO PAINT PROで描く!  多彩な描画のテクニック56 (デジタルイラスト描き方事典)

デジタルイラストの「塗り」事典 CLIP STUDIO PAINT PROで描く! 多彩な描画のテクニック56 (デジタルイラスト描き方事典)

  • 作者: NextCreator編集部
  • 出版社/メーカー: SBクリエイティブ
  • 発売日: 2016/07/16
  • メディア: 単行本







巨大地震と月の満ち欠けが関係? [ちょっと気になるトンデモ学説!]

昔から月と地震は関係あるのではないか?と言われていましたが、統計的に関係がありそうだということが分かってきたようです。


【今年の巨大地震危険日一覧】超巨大地震と潮流の関係が判明! 311もスマトラも当てはまる!?
http://tocana.jp/2016/09/post_10960_entry_2.html


記事によれば、満月と新月のときに発生する満潮が巨大地震を誘発するようです。満潮はつねに地球のどこかで起きていますが、なぜ満月と新月で発生しやすいのか、米国のサイトの解説が分かりやすいです。


New study reveals possible link between moon phase and earthquake potential
http://www.cleveland.com/weather/blog/index.ssf/2016/09/new_study_reveals_possible_lin.html


満月と新月のときはいわゆる大潮(Spring Tide)となり、海水に大きな偏りができて、より地殻を圧迫することが原因のようです。


spring-tide.png


特に地球が太陽にもっとも近づく近日点における満月もしくは新月は、月からの重力の影響に加え、太陽からの重力の影響も強くなるため、より危険性が高まるようです。


moon-orbit.jpeg


プレートテクトニクスに知られるように地球の地殻はいくつかに分かれていますが、大潮になると一部のプレートにだけ通常よりも高い圧力がかかり、隣接する地殻とのズレが大きくなるためプレートの境で巨大地震が発生しやすくなるというメカニズムのようです。


tectonic-plates.jpeg


記事中にも書かれていますが、通常の地震と満潮との関連は特になさそうです。個人的には大潮が巨大地震に影響を与えるなら台風も影響を与えるように思うのですが、だれか研究していないですかね?
σ( ̄ε ̄ )





巨大地震はなぜ連鎖するのか―活断層と日本列島 (NHK出版新書 491)

巨大地震はなぜ連鎖するのか―活断層と日本列島 (NHK出版新書 491)

  • 作者: 佐藤 比呂志
  • 出版社/メーカー: NHK出版
  • 発売日: 2016/07/09
  • メディア: 新書



非常用持ち出し袋36点セット リュックタイプの防災セット

非常用持ち出し袋36点セット リュックタイプの防災セット

  • 出版社/メーカー: HIH
  • メディア: ホーム&キッチン







タグ: 地震 防災

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
  • メディア: 大型本




前の5件 | -