日別アーカイブ: 2024/12/16

PsychoPy+Processing#01

PsychoPyと外部プログラムの連携
ここでは,下記のようなシンプルな実験プロジェクトに外部プログラムで測定した測定結果をUDPで送り込み保存してみる。プロジェクトは,Fixation(+)の後にTarget(□)が出るので,スペースキーを押すと,反応時間が記録されるというもの。

BuilderのPythonマーク(青と黄のヘビ)をクリックすると,Coderが起動する。ここでコードを改造すると,UnityやProcessingからのデータを受け取ることができる。ただし,Builderでコードを生成すると,改造部分はすべて消し飛ぶので注意が必要だ。

まず冒頭で,ライブラリを呼んで,グローバル変数とUDPでデータを受け取るサブルーチンを用意する。

############# NAGANO #################
import socket
import threading

# UDPソケット設定
UDP_IP = "127.0.0.1"  # 受信するIPアドレス
UDP_PORT = 5005       # ポート番号

# グローバル変数に最新のUDPデータを格納
latest_udp_data = "No Data"

def udp_listener():
    """非同期でUDPデータを受信する関数"""
    global latest_udp_data
    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    sock.bind((UDP_IP, UDP_PORT))
    while True:
        data, addr = sock.recvfrom(1024)  # 1024バイトまで受信
        latest_udp_data = data.decode("utf-8")  # デコードして文字列に
############# NAGANO #################

次にプログラム開始部分でスレッドをスタートする。

    win = setupWindow(expInfo=expInfo)
    setupDevices(expInfo=expInfo, thisExp=thisExp, win=win)
    
    ############# NAGANO #################
    # UDPリスナーをスレッドで起動
    udp_thread = threading.Thread(target=udp_listener, daemon=True)
    udp_thread.start()    
    ############# NAGANO #################

でさらに,UDPでうけとったデータを保存する。データの受取は,別スレッドが非同期で行ってくれる。

                    key_resp_target.duration = _key_resp_target_allKeys[-1].duration
                    
                    ############# NAGANO #################
                    # UDPデータをログに記録
                    thisExp.addData('UDP_Data', latest_udp_data)
                    thisExp.addData('KeyPress_Time', globalClock.getTime())  # キー押下時刻も記録
                    ############# NAGANO #################
        
                    # a response ends the routine
                    continueRoutine = False

実行すると,以下のような感じでUDP経由で送られたデータが保存される。ちなみに,データ送信側は,ローカルホストの5005ポートにProcessingでCerry,Diamond,Sevenのどれかひとつの文字列を送るもの。もう一度いうが,Builderで更新するとこれらの改造部分は消し飛ぶので注意