memorandums

日々の作業ログです。

Polar社の心拍センサー受信モジュール(Heart Rate Monitor Interface)で遊んでみた

Arduinoとセンサーをいくつか物色していたときに見つけたのがこの心拍センサー受信モジュール。何かできないかな。。。と購入しました。数週間前に納品されていたのですが触る暇がなく。今日は講義がなかったので少し遊んでみました。

材料は以下の2つ。心拍センサー(T31 CODED™ TRANSMITTER)と受信モジュール(心拍センサー受信モジュール)です。説明書が無かったので使い方がわかるまで1時間ほどかかりました。


Link: T31 CODED™ TRANSMITTER


Link: 心拍センサー受信モジュール

デモに入る前にこれから遊ぼうと考えている人のためにポイントを少し書きます。

■ポイント1

まず心拍センサーの使い方。心拍センサーは直接肌に触れるように胸の下当たり(みぞおちあたりにマークがくるように)つけます。こういうのをよく利用するスポーツ好きな方にとっては当たり前なのでしょうけど私は初めてのことだったので最初に服の上からつけて。。。いつまでたってもセンサー値が表示されず。。。はまりました。電源スイッチはありません。体に巻き付けるだけです。ただ内蔵電池の寿命はあるようですので、もしかするとモノ(中古品とか)によっては電池切れの場合もあるかもしれません。確か2500時間だったと思います。

■ポイント2(Arduinoを使わず直接PCに接続する人はココは読まなくていいです)

次に受信モジュールです。私はArduinoに接続しないと使えないと思い込み、ブレッドボードに接続してサイトに公開されていたサンプルプログラム(hrmi_demos.zip )をDLして動かしてみたもののさっぱりデータ通信がありません。同じくサイトに公開されていたマニュアルをざーっと読んでみると受信モジュールのジャンパ設定が必要とのことです。基盤上のSJ1のハンダを外して絶縁状態にし、OP0を逆にハンダ付けして通電します。受信モジュールをArduinoに接続する人はこのジャンパ設定をしないといつまで経ってもシリアルデータがArduinoに送られません。注意してください。

■ポイント3

受信モジュールとパソコンをUSBケーブルで接続する場合はポイント2に書いたジャンパ変更は一切不要です。購入したそのままの状態で使えます。Processingをインストールしたパソコンを起動し*1、USBケーブルでパソコンと受信モジュールを接続します。この状態で受信モジュールに電源が入りますのでLEDがチカチカするはずです。Statusと書かれた付近のLEDが心拍にあわせてチカチカ明滅するはずです。ここまでくれば心拍センサーと受信モジュールの通信はOKです。次にサイトで公開されているサンプルプログラム(hrmi_demos.zip )をDLします。そのファイルを解凍してhrmi_simpleフォルダ中のhrmi_simple.pdeをダブクリしてProcessing(Arduinoではありませんよ、注意)を起動します。これで準備完了。Processingの開始ボタンを押して心拍数がログ欄に表示されればOKです。エラーが出た場合はシリアルポートの指定がサンプルプログラムとは異なるはずです。プログラム中の以下の行のtty〜の部分を変更しましょう。シリアルポートはターミナルを起動してls /dev/tty.usb*と入力して表示される文字列です。Windowsの場合は。。。面倒なので書きません。自分で探してください。

port = new Serial(this, "/dev/tty.usbserial-A9003PDh", 9600);


では、最後にちょっとしたデモビデオを作りましたので掲載します。


まず平静時。


そして1階から3階まで一気に駆け上がってゼイゼイいいながら撮ったのが以下。


生体信号が取得できるのはやはり面白いですねぇ〜。ただ心拍センサーは肌に直接装着しなければならないので来場者にその場ですぐ遊んでもらうようなインタラクション系のデモには使えません。残念ですが。。。何か用途を考えましょう。

ちなみに、サンプルをちょっと改変しただけの汚いコードですが、何かの参考になるかもしれません。以下に示します。このスケッチを実行するためにはフォント(Serif-48.vlw)を作成しと効果音(tone3.wav)をdataフォルダに入れておかなければなりません。ちなみに効果音はFLOP DESIGNさんのこちらのファイルから取り出したものを使わせて頂きました。

// Include the serial library
import processing.serial.*;

import ddf.minim.*;
Minim minim;
AudioSample in;

// Variable declaration
Serial port;                           // The serial port
byte[] rspCharArray = new byte[32];    // Where we'll put the raw data read from the HRMI device
int[] rspArgArray = new int[3];        // Where we'll put the converted response values
//int validData = 0;
int CR = 13;                           // <CR> constant

void setup() {
  size(300,300);
  minim = new Minim(this);
  in = minim.loadSample("tone3.wav");
  PFont font;
  font = loadFont("Serif-48.vlw"); 
  textFont(font,180); 

  // Open a specific serial device (this will change for each HRMI device)
  port = new Serial(this, "/dev/tty.usbserial-A600dOMu", 9600);
  
  // Setup the serialEvent to be called when we receive complete response
  // packets from the HRMI device
  port.bufferUntil(CR);

  requestData();
  frameRate(10);
}

void stop()
{
  // always stop your Minim object
  minim.stop();
  super.stop();
}

void requestData() {
  // Send a command to get a single heart rate value
  port.write('G');
  port.write('1');
  port.write(CR);
}

float m1, m2, tick=999999;
int c1;

void myfunc() {
  float m1 = millis();
  if (rspArgArray[2] != 0){
    tick = 60000 / rspArgArray[2];
  }   
  if (m1-m2 > tick) {
    background(255);
    fill(0);
    text(rspArgArray[2], 10, 200); 
    m2 = m1;
    in.trigger();
    requestData();
  } else {
    background(0);
    fill(255);
    text(rspArgArray[2], 10, 200); 
  }
}

void draw() {

  myfunc();  

  if (rspArgArray[1] != c1) {
    println(rspArgArray[2]);           // Heart rate
    c1 = rspArgArray[1];
  }
}

// Catch the event from the serial interface.  Make sure there is
// actually data to read before attempting to do any processing.
void serialEvent(Serial port) {
      if (port.readBytesUntil(CR, rspCharArray) != 0) {
        // Read bytes until we get to the end of the packet converting
        // each ASCII digit into a number.  We make use of the space
        // character between sets of digits to delimit numbers.
        //    Argument 0: Status Flags
        //    Argument 1: Second Count
        //    Argument 2: Heartrate
        //
        int ArgIndex = 0;
        int CharIndex = 0;
        for (int i=0; i<3; i++) rspArgArray[i] = 0;
        while (rspCharArray[CharIndex] != CR) {
          if (rspCharArray[CharIndex] != ((byte) ' ')) {
            rspArgArray[ArgIndex] = (rspArgArray[ArgIndex]*10) + (rspCharArray[CharIndex] - ((byte) '0'));
          } else {
            ArgIndex++;
          }
          CharIndex++;
        }
//        validData = 1;
      }
}

*1:Processingのインストールがまだな人はhttp://processing.orgにいってDL&インストールしましょう。