Ambivalent Wanderer

脳科学(認知科学)、ロボット、現代美術。興味があること、考えたことについて細々と書いています。

MindWaveからPythonを使って脳波の値を取得し、好きなプログラムで利用する方法

どうもどうも、Mikenerianです。


先日ハッカソンというイベントに初めて参加してみましたが、とっても良かったです!

ものづくりにすっかり目覚めました。


内容を詳しく教えることはできませんが、

クリスマスが近いですね!メリークリスマス!!
f:id:Mikenerian:20171218203713j:plain:w200:left












思いの外苦労したので、

MindWaveから脳波の値を出力させ、それを他の入力系(ラズパイとか)に送信する方法をまとめたいと思います。

ちなみにこの記事のコードなどは、自分一人では到底書けないものでした。

チームメンバーの方々には大変感謝しています。




この記事では、

MindWaveとは何ぞや?

ってところから解説するので、既知の方は「MindWaveの値を別プログラムに転送する」から見てください。


MindWaveとは

これはNeuroSky社が開発した、簡易脳波計です!

store.neurosky.com

かなり前から発売していたようで、なんと某大手通販サイトでも販売しています。


従来の脳波計は頭を完全に覆ってジェルなんかをつける必要があったので、ヘッドギアをつけるだけの本脳波計はかなりシンプルといえます。

ただ、研究に使う脳波計ほどちゃんとした値を計測できてるわけではないので、あくまでもお遊び程度の商品です。


脳波データに色々フィルターかけたものを送っているようですが、delta, theta, lowalpha, highalpha, lowbeta, highbeta, lowgamma, midgammaの8種類を計測しているみたいです。


さらに、ATTENTION(集中度)MEDITATION(リラックス度)という独自の値を算出しており、0~100の値で出力してくれるスグレモノです。(アルゴリズムは完全なブラックボックスですが…)



MindWaveから値を取得する

まず、私が使った環境をのせておきます。

PC: MacBook Pro

OS: macOS Sierra 10.12.6

Python: 2.7(macデフォルト)

MindWave: よく分からないが2011年版と2017年版


基本的に、付属の説明書の手順に沿えばMacでもWindowsでもiOSでもAndroidでも接続することはできます。


PCの場合、ThinkGearConnectorというソフトがプラットフォームになっています。

脳波の値はまずここで取得され、他のアプリへと送信されます。


ThinkGear Serial Stream Guide

http://developer.neurosky.com/docs/doku.php?id=thinkgear_communications_protocol





後はMindWave Mobile Tutorialというアプリを立ち上げ、ちゃんと接続されていれば問題はありません!
f:id:Mikenerian:20171218204806p:plain:w120




ただ不良品が多いらしく、この段階でつまずくようでしたらその可能性が考えられます。

ちなみにアプリを立ち上げていない間は、MindWaveをPCに接続中でも「未接続」となることが多々あります。



Macの場合のBluetooth設定画面。
f:id:Mikenerian:20171218205302p:plain




またMindWaveのライト点滅について、古いやつと新しいやつでは意味が違っています。

 

旧バージョンの場合は以下のような意味があるらしいです。

ライト MindWaveの状態 意味
オフ 電源オフ MindWaveは電源オフか、バッテリーが無い
2回青に点滅 ペアリングモード MindWaveはデバイスに接続する準備ができている
赤に点灯 ペアリングしていない MindWaveはデバイスとペアリングする必要がある
青に点滅 準備完了 MindWaveはペアリングしてくれるデバイスを待っている
青に点灯 接続中 MindWaveはペアリングされたデバイスと通信中
赤で2回点滅 バッテリー低 MindWaveのバッテリー交換の必要性(電池の交換)

青に点滅でなかなか点灯に変わってくれない…そんなあなた、安心してください!

アプリを立ち上げたら点いてくれることがよくあります。

 

 

MindWaveの値を別プログラムに転送する

アプリでMindWaveの値を見ることはできた。


だけど、こんなオシャレなビジュアルデータじゃなくて、値が欲しい!


ここからが本当の戦いでした。


色々見ましたが、僕が一番参考になったのは、この記事でした。

necomimiを改造して脳波データを取り出した
http://developer.neurosky.com/docs/doku.php?id=thinkgear_communications_protocol


このやり方を応用して、MindWaveからATTENTION、MEDITATIONの値をテキスト出力してみます!

①下準備

ターミナルで

$pip install thinkgear

と入力してthinkgearライブラリをMacにインストール($は実際には入力しません)

次に、
$ ls /dev/tty.*
と入力して、Bluetooth接続されている機器一覧を取得。

その中から、tty.MindWave~となっている値をコピペします。



②動作確認

以下のプログラムを適当な名前で保存し、実行

test1.py

import thinkgear

PORT = '/dev/tty.MindWaveMobile-SerialPo' /*ここに/dev/tty.~を記述
for packets in thinkgear.ThinkGearProtocol(PORT).get_packets():
    for p in packets:
        if isinstance(p, thinkgear.ThinkGearRawWaveData):
            continue
        print p

これでちゃんと出力されていれば、成功です




③パッケージの内容変更

インストールしたパッケージを変更

おそらく以下のパスになりますが、インストールしたパッケージファイルを開きます
/Library/Frameworks/Python.framework/Versions/2.7/bin/lib/thinkgear/thinkgear.py

そしてこのコードを見ていくと、どうやら_strfmtというコマンドで値を送っているようです。(どうやっているのかはわからない)

なので、ATTENTIONとMEDITATIONの_strfmtを変更します。
また、それ以外の_strfmtを何も送らないようにします。


私はATTENTIONとMEDITATIONの出力を、冒頭の数値が1か2かによって分類するプログラムを作成したので、それぞれ以下のようにしました。
ATTENTION: _strfmt = '1%(value)s'

MEDITATION: _strfmt = '2%(value)s'

その他: _strfmt = ''



④実行!

これで、ATTENTIONだけを出力するコードは以下のようになります

tkg.py

import thinkgear

PORT = '/dev/tty.MindWaveMobile-SerialPo' /*ここに/dev/tty.~を記述

for packets in thinkgear.ThinkGearProtocol(PORT).get_packets():
    for pkt in packets:
        if isinstance(pkt, thinkgear.ThinkGearRawWaveData):
            continue

        t = str(pkt)

        if t != '':
            differencer = t[0:1] /*最初の文字を取り出す
            if int(differencer) == 1:
                attention = t[1:]  /*最初の文字以外をattentionとして代入
                print attention

出力値はstr値のようです。

ATTENTIONとMEDITATION以外も出力するので、それ以外の_strfmtはすっ飛ばすようにしてます。

t[0:1]は、tの1文字目だけを抜き出すコマンドです。



⑤応用編

最終的に使ったコードはラズパイに送ったので、以下のようになります。

tkg_01.py

import thinkgear
import commands
from time import sleep
import paho.mqtt.client as mqtt
import sys


'''以下はラズパイの設定'''
HOST = 
PORT =
KEEP_ALIVE =
TOPIC =
MESSAGE = 

args = sys.argv
PUBLISH_NUMBER = 1
SLEEP_TIME = 1

def publish_many_times(client, topic='topic/default', message='default', number=1, time=1, print_flag=False):

    for i in range(number):
        client.publish(topic, message)
        if print_flag == True:
            print (topic + ' ' + message)
        sleep(time)

    # client.disconnect()

client = mqtt.Client(protocol=mqtt.MQTTv311)
client.connect(HOST, port=PORT, keepalive=KEEP_ALIVE)

PORT = '/dev/tty.MindWaveMobile-DevA' /*ここに/dev/tty.~を記述
count = 1

for packets in thinkgear.ThinkGearProtocol(PORT).get_packets():
    for pkt in packets:
        if isinstance(pkt, thinkgear.ThinkGearRawWaveData):
            continue

        sleep(0.7) /*ラズパイが処理しきれなくなるので一定時間処理をストップ

        t = str(pkt)

        '''setting identifier in the beginning of signal
        attention = 1, meditation = 2'''
        if t != '':
            differencer = t[0:1]
            send = '1'
            meditation = '0'
            if int(differencer) == 1:
                attention = t[1:]

            elif int(differencer) == 2:
                meditation = t[1:]
                if int(meditation) > 50:
                    send = '0'
                else:
                    send = '1'

            MESSAGE = attention + ',' + send
            print MESSAGE + ' ' + meditation
            publish_many_times(client,TOPIC, MESSAGE, PUBLISH_NUMBER, SLEEP_TIME)

このプログラムではattention値とsend値をカンマ区切りで送っています。

send値はmeditationが50以上なら0、それ以下なら1と定義しています。