心拍センサー(Grove - Ear-clip Heart Rate Sensor)を使ってArduinoからTouchDesignerにシリアル通信する


Qiitaの初投稿がアドベントカレンダー

Qiitaで書く動機になったのは、僕の所属する大学の教授から、とある授業の中で、"アドベントカレンダー"という企画がQiitaにあることを知ったからです。アドベントとはもともとクリスマスにキリストの生誕を祝うとかなんとかで行われていることらしいですが、それにちなんで、このQiitaでも、年末は毎日誰かが記事を書いているようです。
アドベントカレンダーもいくつかあって、本当はTouchDesignerの方に参加したかったのですが(個人的に書く予定です笑)、もうすでに埋まっていたので、定員がまだ空いていたArduinoの方に参加してみました。2020年の12/21です。

noteALISではいろいろ書いたことはあるんですが、Qiitaに記事を書くのは今回が初めてで、書き進める上で、いくつか参考にしました。まず、「マークダウン記法」という記法をQiitaは採用していて、これをざっくり説明すると、**Bold**が、Boldのように記載される書き方で、Qiitaで記事を書く上で重要な要素でした。
また、どのような書き方がいいのかをまとめてある「Qiita公式のガイドライン」を参考にしました。
同じく(といってもTouchDesignerの方だが笑)、アドベントカレンダーに記事を書かれていた「TouchDesignerでOpenCVを使った簡単な顔認識について」は、記事の構成で参考にしました。

ここからが本題になります〜

デモ

↓TouchDesignerに表示されるビジュアル↓

↓Arduino接続のデモの様子↓ (サイズのせいか、こっちはgifアニメーションにできひんかった...)

サンプルファイル

GitHubにアップロードした"HeatBeat.zip"というzipファイルです。
中身は、ArduinoIDEのプログラムファイルと、TouchDesignerのプログラムファイルです。
↓ここからダウンロードできます↓
https://github.com/kusibikiyutaka/HeatBeat

動作環境

MacOS:Big Sur ver.11.1
ArduinoIDE:1.8.13
Arduino:Arduino UNO R3 BOARD
TouchDesigner:099 2020 27390

概要

ArduinoIDE

  • 心拍センサーの値を取得する
  • 取得した値をシリアル通信で送る

TouchDesigner

  • SerialDATでシリアル通信を受け取る
  • logicCHOPで論理演算をする
  • 映像や音を出力する

具体的な内容

*注意
ArduinoIDEのシリアルモニターをつけていると、シリアル通信のときにエラーが出ます
また、シリアル通信を送信する側を先に起動させて、受信する側はその後に起動させてください。今回だと、Arduinoが先で、TouchDesignerが後です。自分の動作環境では、この順序を逆にしたとき、エラーが出ていたので。もし勘違いだったらすみません。。。

■Arduino

①接続ピン

ArduinoUNOと心拍センサーの接続するピンは、
「3.3V(赤)、GND(黒)、D2(黄)」
でいけました。

Connect this module to the digital port D2 on Grove-Base shield. And connect
このモジュールをGrove-BaseシールドのデジタルポートD2に接続します。

と公式サイトにあったので!
・心拍センサー公式サイト(Grove - Ear-clip Heart Rate Sensor)
https://wiki.seeedstudio.com/Grove-Ear-clip_Heart_Rate_Sensor/

connect Grove-LED to Digital port 4.
Grove-LEDをデジタルポート4に接続します。

(LEDライトも、D4ピンにつなげば光るみたいなので、動作確認に使えそうです。)

②プログラム

プログラムも、公式サイトのコピペでいけました。


    // Function: This program can be used to measure heart rate, the lowest pulse in the program be set to 30.
    //         Use an external interrupt to measure it.
    // Hardware: Grove - Ear-clip Heart Rate Sensor, Grove - Base Shield, Grove - LED
    // Arduino IDE: Arduino-1.0
    // Author: FrankieChu       
    // Date: Jan 22, 2013
    // Version: v1.0
    // by www.seeedstudio.com
    #define LED 4//indicator, Grove - LED is connected with D4 of Arduino
    boolean led_state = LOW;//state of LED, each time an external interrupt 
                                    //will change the state of LED
    unsigned char counter;
    unsigned long temp[21];
    unsigned long sub;
    bool data_effect=true;
    unsigned int heart_rate;//the measurement result of heart rate

    const int max_heartpluse_duty = 2000;//you can change it follow your system's request.
                            //2000 meams 2 seconds. System return error 
                            //if the duty overtrip 2 second.
    void setup()
    {
        pinMode(LED, OUTPUT);
        Serial.begin(9600);
        Serial.println("Please ready your chest belt.");
        delay(5000);
        arrayInit();
        Serial.println("Heart rate test begin.");
        attachInterrupt(0, interrupt, RISING);//set interrupt 0,digital port 2
    }
    void loop()
    {
        digitalWrite(LED, led_state);//Update the state of the indicator
    }
    /*Function: calculate the heart rate*/
    void sum()
    {
     if(data_effect)
        {
          heart_rate=1200000/(temp[20]-temp[0]);//60*20*1000/20_total_time 
          Serial.print("Heart_rate_is:\t");
          Serial.println(heart_rate);
        }
       data_effect=1;//sign bit
    }
    /*Function: Interrupt service routine.Get the sigal from the external interrupt*/
    void interrupt()
    {
        temp[counter]=millis();
        Serial.println(counter,DEC);
        Serial.println(temp[counter]);
        switch(counter)
        {
            case 0:
                sub=temp[counter]-temp[20];
                Serial.println(sub);
                break;
            default:
                sub=temp[counter]-temp[counter-1];
                Serial.println(sub);
                break;
        }
        if(sub>max_heartpluse_duty)//set 2 seconds as max heart pluse duty
        {
            data_effect=0;//sign bit
            counter=0;
            Serial.println("Heart rate measure error,test will restart!" );
            arrayInit();
        }
        if (counter==20&&data_effect)
        {
            counter=0;
            sum();
        }
        else if(counter!=20&&data_effect)
        counter++;
        else 
        {
            counter=0;
            data_effect=1;
        }

    }
    /*Function: Initialization for the array(temp)*/
    void arrayInit()
    {
        for(unsigned char i=0;i < 20;i ++)
        {
            temp[i]=0;
        }
        temp[20]=millis();
    }

③回路図

「fritzing」で回路図も書いてみたかったんですが、

The source code of Fritzing is available on our Github repository. Everyone is welcome to participate in the development.
We are asking you to pay 8€ (less than US$9) for downloading the application.
Fritzingのソースコードは、Githubリポジトリで入手できます。 どなたでもご参加いただけます。
アプリケーションのダウンロードには8ユーロ(9米ドル未満)の支払いをお願いしています。

2020年12月現在は無料ではなく、8ユーロの支払いからになっていて、今回は断念しました。。。
↓fritzing 公式サイト↓
https://fritzing.org/download/

■TouchDesigner

ノードを組む

といっても、基本的にYouTubeにあったチュートリアルをいじっていく感じです。
・YouTubeにあったチュートリアル(Aurora Audio Spectrum – TouchDesigner Tutorial 2)
https://www.youtube.com/watch?v=NJE48IVzNVc&t=6s

(以下の①〜⑤は、チュートリアル動画を見てから読むことを推奨します。)

①LookUpTOP・RampTOP


LookUpTOPと繋がっているRampTOPの色を調整します。これによってビジュアルの色が画像のようになると思います。
私はHeatBeatという作品を制作したので、熱と心臓をイメージした赤色を主体にしていますが、他にもいろいろ試してみてください。

②TransformTOP・FeedbackTOP


いじくるところは、TransformTOPのScaleの部分です。おおむねチュートリアルの通りできていれば、手前に進んでくるような動きに変化があると思います。これは主にFeedbackTOPLevelTOPのOpacityCompositionTOPのAddのセットによるものです。このセットは他のチュートリアルでもよく見かけたので、覚えておくといいかもです。

③Audio File In CHOP


今回使用した音源は、もとからTouchDesignerに入っている音源です。Audio File In CHOPのFileからAudio/SonarBlackie666.wavを選んでいます。ソナー音がいい感じです。
(ちなみに、Audio Device Out CHOPを繋がないと音がならないので注意です)

④SerialDAT


ここでArduinoから送られてきたシリアル通信を受け取っています。ポートは、SerialDATのPortから選んでください。BaudRateはArduinoIDEのプログラムに合わせていればOKです。9600で大丈夫でした。MaximumLinesは1にしましょう。
(前述しましたが、このとき、ArduinoIDEでシリアルモニタを開いていると、うまくシリアル通信ができないので、確認ができれば閉じておきましょう。)

⑤LogicCHOP


このオペレーターが、今回の鍵になると思います。ざっくりいうと、送られてきた値によって、0か1を返すオペレーターです。
↓LogicCHOPの日本語ドキュメント↓
http://ted-kanakubo.com/touchdesigner-jp/?p=26
ConvertInputをOn When Value Changedにすることで、心拍センサーからのデータを取得してシリアル通信で送られてきた値は常に変化していくので、値が変化した時に1、つまりOnにすることができます。
このLogicCHOPによって、心拍センサーのデータがシリアル通信で送られ、映像の変化や音を出力するトリガーになっています。

あとがき

初投稿がアドベントカレンダーということで、緊張しました笑 至らないところもあったと思いますが、精一杯書いたので許してください。笑 記事にするときって、自分の中であいまいだったことが結構浮き彫りになってきますね。プレゼンの時でもそうですが、書いていくうちにハッとさせられるというか。「なんでここはこの設定なんだっけ?」「これってどういう機能だっけ?」みたいな。でもこうやって外に出してみるとわかることあったり、書きながら勉強にもなったり。
心拍センサーは、大学の機材を扱うときに知り合った大学院の人にもらったもので、もらうきっかけは、TwitterでTouchDesignerで作ったHeatBeatを投稿したときに、「それって心拍センサー使ってできる?」と聞かれ、実際にいただいたものです。そんな心やさしき方のTwitterアカウントも載せておきますね。笑
Arduinoを普段利用されている方も、別のソフトウェアと連携させることで表現の幅が広がることもあると思うので、これをきっかけにTouchDesignerとかしてくれたら嬉しいです。はしゃぎすぎて天井に突き刺さりますうそです。
こういうインタラクティブなものを制作するときは、「input」「output」「その間をつなぐアルゴリズムやプログラム」といった三つに分けると良きです。これも大学で、インタラクティブアート関連のスペシャリスト教授に教えてもらいました。こちらも載せておきます。笑
ここまで読んでくださり、ありがとうございます。
今日も一日、お疲れ様です。

心拍センサーくれた心やさしき人
https://twitter.com/amanozyakulab

インタラクティブアート関連のスペシャリスト
https://makotohirahara.com/


TODAY IS A GOOD DAY FOR YOU