So-net無料ブログ作成

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




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




ウィキペディアに寄付しちゃいました! [徒然日記]

息子は世に言う ウィキペディアン。彼いわく ウィキペディア を開かない日はないようです。スマホにも専用アプリをインストールし、何か疑問に思ったらすぐに検索するそうです。しかし、最近こんなメッセージが、でかでかと出るようになってきました。


wikipedia.png


かなり経営が圧迫されている様子。サーバーの維持にものすごい費用がかかるのは仕事柄よく知っています。それを寄付だけでやっていくのは大変でしょう。息子も ”ウィキペディア大丈夫なのかなー?”と心配しています。

私も自他ともに認めるオープンソース信者。ここは一つ貢献しちゃろうか!ということで、思い切って寄付をしちゃいました!アメリカ人と違って寄付に慣れていないのでドキドキします。


wikipedia_thankyou.png


寄付すると、すぐに電子メールで感謝のお手紙が届きました。


ウィキメディア財団に¥ 3000の寄附をお寄せ頂き、ありがとうございました。ウィキメディア財団は非営利組織で、ウィキペディアをはじめ、その他の自由な知識を無料で提供するプロジェクトをサポートしています。私たちの使命は、世界中で最もアクセスできる包括的で自由な知識の源を構築することです。
知識は基本的な人権であると私たちは考えています。人類がデジタルの未来に突入していることから、私たちには、オンラインで知識にアクセスするための、オープンで、アクセス可能で、公開されたスペースが必要です。ウィキメディアこそがそのスペースなのです。ウィキメディアは、地球上の何百もの言語で、人々により、人々に対して自由な知識をお届けしているのです。
年間を通じ、南極大陸を含めあらゆる大陸の人々がウィキペディアの編集に参加し、閲覧しています。およそ5億人の人々が、文化遺産の保護から、癌検知の改善、また宿題のリサーチまで、あらゆることを求めて、毎月ウィキペディアで調べています。皆、学ぶことが目的なのです。ウィキペディアを読み、発見するのです。
誰もが「ウィキペディアン」になれます。ウィキペディアで探しているものが見つからなければ、それは自分で作成できます。様々な記事、言葉、画像、データは、知識を世界中で共有しようとする様々なボランティア達のコミュニティによって作成されているのです。
私たちはいつも、どうすれば自分たちのインパクトを高められるかを考え、明日のウィキペディアと姉妹プロジェクトが、今日よりもより正確で、情報豊かで、アクセス可能になるよう努力しています。皆様からのご寄附がそれを助けてくれるのです。
私たちがさらにもう一年成長し皆に良い影響力となるようご協力くださりありがとうございます。
ウィキメディア財団



微々たる金額ではありますが、ウィキペディアの理想に協力できたと思うとちょっと嬉しい気分になります。息子も嬉しそうにしてました。ウィキペディア の中の人達、これからも頑張ってくださいねー!
(^_^)/~






ウィキペディア・レボリューション―世界最大の百科事典はいかにして生まれたか (ハヤカワ新書juice)

ウィキペディア・レボリューション―世界最大の百科事典はいかにして生まれたか (ハヤカワ新書juice)

  • 作者: アンドリュー リー
  • 出版社/メーカー: 早川書房
  • 発売日: 2009/08
  • メディア: 単行本



Wikipediaをつくったジミー・ウェールズ (時代をきりひらくIT企業と創設者たち)

Wikipediaをつくったジミー・ウェールズ (時代をきりひらくIT企業と創設者たち)

  • 作者: スーザン・メイヤー
  • 出版社/メーカー: 岩崎書店
  • 発売日: 2013/02/25
  • メディア: 単行本



A Social History of Knowledge II: From the Encyclopaedia to Wikipedia

A Social History of Knowledge II: From the Encyclopaedia to Wikipedia

  • 作者: Peter Burke
  • 出版社/メーカー: Polity
  • 発売日: 2012/01/17
  • メディア: ペーパーバック




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




「君の名は」を見てきましたー [徒然日記]

今日は家族で「君の名は」を見てきましたー。息子が見たがっていたのですが、男ばかりで見に行くような映画でないので躊躇していた様子。(早く彼女作れよ・・)カミさんも見たがっていたのと、私も会社の同僚からイチオシされていたので、家族で出かけることにしました。


yourname.jpg



評判どおり素晴らしい映画です。映像はもう芸術作品と言ってもよいと思います。あざやかな配色、動き、アニメでここまで表現できるのかと感動すら覚えます。

それに加えて練りに練られたストーリー、魅力的なキャラクタ。伏線がいくつも張られており、単なるラブストーリーに終わっていません。これはアニメ映画の中でも名作と呼ぶにふさわしい作品だと思います。


yourname_story_scene.jpg


しかし、天文オタクの私にとって気になる点が・・・。物語のキーとなる彗星です。すでにネットでは彗星の軌道がおかしい!と騒がれていますが、一番最初に出てきた映像では正しい軌道で描かれていたのですよね。


yourname-commet1.png


で、ガセかなと思ったのですが、そのあとから出てくる軌道の画像が下記。謎の力によって彗星の軌道が捻じ曲げられています。あれ?突然ダークマターが発生したのかな?


yourname-commet2.png


まぁ、これは明らかな勘違いとしても、それ以上に私が一番気になるのが、ポスターにも描かれている彗星の姿。彗星が地球の潮汐力で分裂をしてしまうのですが、この図は明らかにおかしい。


yourname-commet-scene-wrong.png


こうなるのが正しい姿のはずです。


yourname-commet-scene-right.jpg


太陽風は局所的には一定方向なので、分裂しても尾の向きは変わらないはず。木星の潮汐力でバラバラになったシューメーカーレビー彗星の姿を見てみましょう。


fragments.jpg


みんな尾はきれいに揃ってますよねぇ。

それでも、流れ星となって地球に落ちてきているので向きが違ってもOKという人もいると思います。だがしかーし、この下のシーン。他の流れ星と輝跡が明らかに違う。。。


yourname-commet-shooting-star.png


参考までに、はやぶさが大気圏突入したときの写真です。尾は皆同じ向き向いてますよねー。


Hayabusa-Nasa1-medium.jpg


ね、おかしいでしょ?

ということを映画を見終わったあとで話をしていたら、カミさんと娘に無粋なこと言うなー!と叱られました。息子よ、話が分かるのはお前だけだ・・・。
(TдT)トホホ・・






小説 君の名は。 (角川文庫)

小説 君の名は。 (角川文庫)

  • 作者: 新海 誠
  • 出版社/メーカー: KADOKAWA/メディアファクトリー
  • 発売日: 2016/06/18
  • メディア: 文庫



君の名は。 Another Side:Earthbound (角川スニーカー文庫)

君の名は。 Another Side:Earthbound (角川スニーカー文庫)

  • 作者: 加納 新太
  • 出版社/メーカー: KADOKAWA/角川書店
  • 発売日: 2016/07/30
  • メディア: 文庫



君の名は。(通常盤)

君の名は。(通常盤)

  • アーティスト:
  • 出版社/メーカー: Universal Music =music=
  • 発売日: 2016/08/24
  • メディア: CD




俺氏、Stack Overflow デビューする!そこで明かされた浮動小数点の危険性とは? [ソフトウェア関連のもろもろ]

先日、 ftoa (少数を文字列に変換する関数) を自作していたときに、不可解な現象に出くわしました。問題となったのは下記のようなプログラムです。

#include <stdio.h>

void main()
{
    double f = 0.12;
    int d;
    f *= 10;    // f = 1.2
    d = (int)f; // d = 1
    f -= d;     // f = 0.2
    f *= 10;    // f = 2.0
    d = (int)f; // d should be 2
    f -= d;     // f should be 0.0
    printf("%lf\n", f);
}



この結果は当然ゼロとなるべきところですが。結果は、1.000000 となってしまいます。極論すると、

2.0 - 2 = 1.0

と同じということです。しかも、問題が発生するのは、0.12 という数字だけ。0.11 でも 0.13 でも 0.23 でも 0.34 でも問題は出ません。

あまりにも不可解なので、こんな問題に答えられるのは、世界中のプログラマが集まる掲示板 Stack Overflow くらいだろうということで、思い切って質問することにしました。ドキドキ。


stackoverflow.png
http://stackoverflow.com/


日本の掲示板では答えに巡り合うまでに時間がかかることが多いですが、さすが世界の天才プログラマが跋扈する Stack Overflow、なんと数分後には回答が来ました。すげぇ・・・。アドバイスに従い、下記のプログラムを動かすと答えはすぐに見つかりました。


#include <stdio.h>

void main()
{
    double f = 0.12;
    int d;
    printf("f          :f: %.16f\n", f);

    f *= 10;
    printf("f *= 10    :f: %.16f\n", f);

    d = (int)f;
    printf("d = (int)f :d: %d\n", d);

    f -= d;
    printf("f -= d     :f: %.16f\n", f);

    f *= 10;
    printf("f *= 10    :f: %.16f\n", f);

    d = (int)f;
    printf("d = (int)f :d: %d\n", d);

    f -= d;
    printf("f -= d     :f: %.16f\n", f);
}



演算の結果はこちらです。


      1 f         :f: 0.1200000000000000
      2 f *= 10   :f: 1.2000000000000000
      3 d = (int)f:d: 1
      4 f -= d    :f: 0.2000000000000000
      5 f *= 10   :f: 1.9999999999999996
      6 d = (int)f:d: 1
      7 f -= d    :f: 0.9999999999999996



4行目から5行目でいきなり数値が豹変しています。ここで問題が発生していました。問題発生のメカニズムも教えてもらいました。

1.0 は、C言語の採用している binary64 では正しくは以下の数値となります。17桁以降は丸め誤差です。

1.0000000000000000444089...

上記の値を4行目の 1.2 -1.0 に適用すると下記のようになります。

1.2000000000000000 - 1.0000000000000000444089 = 0.1999999999999999555911

この段階では、小数点以下17桁以下の数は丸め込まれるので、0.2 と表示されます。

しかし、5行目で10をかけると、状況が一変し、この誤差がひょっこり顔をのぞかせます。末尾の一桁が、繰り上げられますので、f の値は、1.9999999999999996 となってしまいます。

あとはプログラムの通り、この微妙な誤差が致命的な違いとなって表れ、期待された値とまったく異なる結果となります。しかもこの条件にあてはまるのは、17桁以降の数値と丸め誤差が重なったときなので非常に稀です。

このようなプログラムが人命にかかわる車や飛行機、ロケットなどに混入していたらと思うとぞっとします。プログラマの皆さん、浮動小数点の扱いは十分に注意してくださいね。

せっかくなので、Stack Overflow で解決策ないの?と質問をしたら下記の対策を勧められました。


#include <stdio.h>
#include <float.h>

void main()
{
    double f = 0.12;
    int d;

    printf("f          :f: %.16f\n", f);

    f *= 10;
    printf("f *= 10    :f: %.16f\n", f);

    d = (int)f;
    printf("d = (int)f :d: %d\n", d);

    f -= d;
    printf("f -= d     :f: %.16f\n", f);

    f *= 10;
    printf("f *= 10    :f: %.16f\n", f);

    f *= (1 + DBL_EPSILON);
    printf("DBL_EPSILON:f: %.16f\n", f);

    d = (int)f;
    printf("d = (int)f :d: %d\n", d);

    f -= d;
    printf("f -= d     :f: %.16f\n", f);
}



EPSILON は、理系の人ならお馴染みのイプシロン・デルタのイプシロンです。float の場合は接頭子は FLTになりますので注意してください。詳細については下記のサイトが参考になります。


Is floating point math broken?
http://stackoverflow.com/questions/588004/is-floating-point-math-broken


普段、見てばかりいる Stack Overflow ですが、今回は自分で参加してみて、あらためて世界の叡智の凄さを体感しました。日本のプログラマの皆さんもどんどん世界に出ていきましょう!
(^_^)/





苦しんで覚えるC言語

苦しんで覚えるC言語

  • 作者: MMGames
  • 出版社/メーカー: 秀和システム
  • 発売日: 2011/06/24
  • メディア: 単行本






絵で見てわかるシステムパフォーマンスの仕組み

絵で見てわかるシステムパフォーマンスの仕組み

  • 作者: 小田 圭二
  • 出版社/メーカー: 翔泳社
  • 発売日: 2014/06/21
  • メディア: 単行本(ソフトカバー)