|
@@ -2,7 +2,7 @@
|
|
|
# -*- coding: utf-8 -*-
|
|
|
"""
|
|
|
This experiment was created using PsychoPy3 Experiment Builder (v2023.2.3),
|
|
|
- on Thu Dec 14 13:37:19 2023
|
|
|
+ on 十二月 14, 2023, at 15:41
|
|
|
If you publish work using this script the most relevant publication is:
|
|
|
|
|
|
Peirce J, Gray JR, Simpson S, MacAskill M, Höchenberger R, Sogo H, Kastman E, Lindeløv JK. (2019)
|
|
@@ -34,6 +34,7 @@ import psychopy.iohub as io
|
|
|
from psychopy.hardware import keyboard
|
|
|
|
|
|
# Run 'Before Experiment' code from config
|
|
|
+import argparse
|
|
|
import time
|
|
|
from device.fubo_pneumatic_finger import FuboPneumaticFingerClient
|
|
|
from device.trigger_box import TriggerNeuracle
|
|
@@ -176,7 +177,7 @@ def setupData(expInfo, dataDir=None):
|
|
|
thisExp = data.ExperimentHandler(
|
|
|
name=expName, version='',
|
|
|
extraInfo=expInfo, runtimeInfo=None,
|
|
|
- originPath='/Users/dingkunliu/Projects/MI-BCI-Proj/kraken/backend/grasp_data_collection.py',
|
|
|
+ originPath='C:\\Users\\asena\\Desktop\\kraken\\backend\\grasp_data_collection.py',
|
|
|
savePickle=True, saveWideText=True,
|
|
|
dataFileName=dataDir + os.sep + filename, sortColumns='time'
|
|
|
)
|
|
@@ -414,6 +415,9 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
|
|
|
attention = sound.Sound('static/audios/ding.wav', secs=1.0, stereo=True, hamming=True,
|
|
|
name='attention')
|
|
|
attention.setVolume(1.0)
|
|
|
+ extend_wav = sound.Sound('static/audios/extend.wav', secs=2, stereo=True, hamming=True,
|
|
|
+ name='extend_wav')
|
|
|
+ extend_wav.setVolume(1.0)
|
|
|
|
|
|
# --- Initialize components for Routine "flex" ---
|
|
|
flex_img = visual.ImageStim(
|
|
@@ -424,6 +428,9 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
|
|
|
color=[1,1,1], colorSpace='rgb', opacity=None,
|
|
|
flipHoriz=False, flipVert=False,
|
|
|
texRes=128.0, interpolate=True, depth=0.0)
|
|
|
+ flex_wav = sound.Sound('static/audios/flex.wav', secs=2, stereo=True, hamming=True,
|
|
|
+ name='flex_wav')
|
|
|
+ flex_wav.setVolume(1.0)
|
|
|
|
|
|
# --- Initialize components for Routine "hold" ---
|
|
|
hold_img = visual.ImageStim(
|
|
@@ -434,6 +441,9 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
|
|
|
color=[1,1,1], colorSpace='rgb', opacity=None,
|
|
|
flipHoriz=False, flipVert=False,
|
|
|
texRes=128.0, interpolate=True, depth=0.0)
|
|
|
+ hold_wav = sound.Sound('static/audios/hold.wav', secs=2, stereo=True, hamming=True,
|
|
|
+ name='hold_wav')
|
|
|
+ hold_wav.setVolume(1.0)
|
|
|
|
|
|
# --- Initialize components for Routine "rest" ---
|
|
|
rest_img = visual.ImageStim(
|
|
@@ -444,6 +454,12 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
|
|
|
color=[1,1,1], colorSpace='rgb', opacity=None,
|
|
|
flipHoriz=False, flipVert=False,
|
|
|
texRes=128.0, interpolate=True, depth=0.0)
|
|
|
+ rest_wav1 = sound.Sound('static/audios/ding.wav', secs=1.0, stereo=True, hamming=True,
|
|
|
+ name='rest_wav1')
|
|
|
+ rest_wav1.setVolume(1.0)
|
|
|
+ rest_wav2 = sound.Sound('static/audios/rest.wav', secs=2, stereo=True, hamming=True,
|
|
|
+ name='rest_wav2')
|
|
|
+ rest_wav2.setVolume(1.0)
|
|
|
|
|
|
# --- Initialize components for Routine "end" ---
|
|
|
end_text = visual.TextStim(win=win, name='end_text',
|
|
@@ -716,8 +732,11 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
|
|
|
# Run 'Begin Routine' code from code
|
|
|
i = 0
|
|
|
|
|
|
+ extend_wav.setSound('static/audios/extend.wav', secs=2, hamming=True)
|
|
|
+ extend_wav.setVolume(1.0, log=False)
|
|
|
+ extend_wav.seek(0)
|
|
|
# keep track of which components have finished
|
|
|
- extendComponents = [extend_img, attention]
|
|
|
+ extendComponents = [extend_img, attention, extend_wav]
|
|
|
for thisComponent in extendComponents:
|
|
|
thisComponent.tStart = None
|
|
|
thisComponent.tStop = None
|
|
@@ -813,6 +832,36 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
|
|
|
i += 1
|
|
|
# 每轮开始前空白等待1s + 反应时1s + 新版extend时间4.5s + 1s裕量 = 7.5s
|
|
|
|
|
|
+ # if extend_wav is starting this frame...
|
|
|
+ if extend_wav.status == NOT_STARTED and tThisFlip >= 1.8-frameTolerance:
|
|
|
+ # keep track of start time/frame for later
|
|
|
+ extend_wav.frameNStart = frameN # exact frame index
|
|
|
+ extend_wav.tStart = t # local t and not account for scr refresh
|
|
|
+ extend_wav.tStartRefresh = tThisFlipGlobal # on global time
|
|
|
+ # add timestamp to datafile
|
|
|
+ thisExp.addData('extend_wav.started', tThisFlipGlobal)
|
|
|
+ # update status
|
|
|
+ extend_wav.status = STARTED
|
|
|
+ extend_wav.play(when=win) # sync with win flip
|
|
|
+
|
|
|
+ # if extend_wav is stopping this frame...
|
|
|
+ if extend_wav.status == STARTED:
|
|
|
+ # is it time to stop? (based on global clock, using actual start)
|
|
|
+ if tThisFlipGlobal > extend_wav.tStartRefresh + 2-frameTolerance:
|
|
|
+ # keep track of stop time/frame for later
|
|
|
+ extend_wav.tStop = t # not accounting for scr refresh
|
|
|
+ extend_wav.frameNStop = frameN # exact frame index
|
|
|
+ # add timestamp to datafile
|
|
|
+ thisExp.timestampOnFlip(win, 'extend_wav.stopped')
|
|
|
+ # update status
|
|
|
+ extend_wav.status = FINISHED
|
|
|
+ extend_wav.stop()
|
|
|
+ # update extend_wav status according to whether it's playing
|
|
|
+ if extend_wav.isPlaying:
|
|
|
+ extend_wav.status = STARTED
|
|
|
+ elif extend_wav.isFinished:
|
|
|
+ extend_wav.status = FINISHED
|
|
|
+
|
|
|
# check for quit (typically the Esc key)
|
|
|
if defaultKeyboard.getKeys(keyList=["escape"]):
|
|
|
thisExp.status = FINISHED
|
|
@@ -840,6 +889,7 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
|
|
|
thisComponent.setAutoDraw(False)
|
|
|
thisExp.addData('extend.stopped', globalClock.getTime())
|
|
|
attention.pause() # ensure sound has stopped at end of Routine
|
|
|
+ extend_wav.pause() # ensure sound has stopped at end of Routine
|
|
|
# using non-slip timing so subtract the expected duration of this Routine (unless ended on request)
|
|
|
if routineForceEnded:
|
|
|
routineTimer.reset()
|
|
@@ -853,8 +903,11 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
|
|
|
# Run 'Begin Routine' code from code_2
|
|
|
i = 0
|
|
|
|
|
|
+ flex_wav.setSound('static/audios/flex.wav', secs=2, hamming=True)
|
|
|
+ flex_wav.setVolume(1.0, log=False)
|
|
|
+ flex_wav.seek(0)
|
|
|
# keep track of which components have finished
|
|
|
- flexComponents = [flex_img]
|
|
|
+ flexComponents = [flex_img, flex_wav]
|
|
|
for thisComponent in flexComponents:
|
|
|
thisComponent.tStart = None
|
|
|
thisComponent.tStop = None
|
|
@@ -920,6 +973,36 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
|
|
|
|
|
|
# 反应时1s+新版气动手flex时间4.5s + 1s裕量 = 6.5s
|
|
|
|
|
|
+ # if flex_wav is starting this frame...
|
|
|
+ if flex_wav.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance:
|
|
|
+ # keep track of start time/frame for later
|
|
|
+ flex_wav.frameNStart = frameN # exact frame index
|
|
|
+ flex_wav.tStart = t # local t and not account for scr refresh
|
|
|
+ flex_wav.tStartRefresh = tThisFlipGlobal # on global time
|
|
|
+ # add timestamp to datafile
|
|
|
+ thisExp.addData('flex_wav.started', tThisFlipGlobal)
|
|
|
+ # update status
|
|
|
+ flex_wav.status = STARTED
|
|
|
+ flex_wav.play(when=win) # sync with win flip
|
|
|
+
|
|
|
+ # if flex_wav is stopping this frame...
|
|
|
+ if flex_wav.status == STARTED:
|
|
|
+ # is it time to stop? (based on global clock, using actual start)
|
|
|
+ if tThisFlipGlobal > flex_wav.tStartRefresh + 2-frameTolerance:
|
|
|
+ # keep track of stop time/frame for later
|
|
|
+ flex_wav.tStop = t # not accounting for scr refresh
|
|
|
+ flex_wav.frameNStop = frameN # exact frame index
|
|
|
+ # add timestamp to datafile
|
|
|
+ thisExp.timestampOnFlip(win, 'flex_wav.stopped')
|
|
|
+ # update status
|
|
|
+ flex_wav.status = FINISHED
|
|
|
+ flex_wav.stop()
|
|
|
+ # update flex_wav status according to whether it's playing
|
|
|
+ if flex_wav.isPlaying:
|
|
|
+ flex_wav.status = STARTED
|
|
|
+ elif flex_wav.isFinished:
|
|
|
+ flex_wav.status = FINISHED
|
|
|
+
|
|
|
# check for quit (typically the Esc key)
|
|
|
if defaultKeyboard.getKeys(keyList=["escape"]):
|
|
|
thisExp.status = FINISHED
|
|
@@ -946,6 +1029,7 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
|
|
|
if hasattr(thisComponent, "setAutoDraw"):
|
|
|
thisComponent.setAutoDraw(False)
|
|
|
thisExp.addData('flex.stopped', globalClock.getTime())
|
|
|
+ flex_wav.pause() # ensure sound has stopped at end of Routine
|
|
|
# using non-slip timing so subtract the expected duration of this Routine (unless ended on request)
|
|
|
if routineForceEnded:
|
|
|
routineTimer.reset()
|
|
@@ -958,8 +1042,11 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
|
|
|
thisExp.addData('hold.started', globalClock.getTime())
|
|
|
# Run 'Begin Routine' code from code_3
|
|
|
win.callOnFlip(trigger.send_trigger, settings.FINGERMODEL_IDS['hold'])
|
|
|
+ hold_wav.setSound('static/audios/hold.wav', secs=2, hamming=True)
|
|
|
+ hold_wav.setVolume(1.0, log=False)
|
|
|
+ hold_wav.seek(0)
|
|
|
# keep track of which components have finished
|
|
|
- holdComponents = [hold_img]
|
|
|
+ holdComponents = [hold_img, hold_wav]
|
|
|
for thisComponent in holdComponents:
|
|
|
thisComponent.tStart = None
|
|
|
thisComponent.tStop = None
|
|
@@ -1015,6 +1102,36 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
|
|
|
hold_img.status = FINISHED
|
|
|
hold_img.setAutoDraw(False)
|
|
|
|
|
|
+ # if hold_wav is starting this frame...
|
|
|
+ if hold_wav.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance:
|
|
|
+ # keep track of start time/frame for later
|
|
|
+ hold_wav.frameNStart = frameN # exact frame index
|
|
|
+ hold_wav.tStart = t # local t and not account for scr refresh
|
|
|
+ hold_wav.tStartRefresh = tThisFlipGlobal # on global time
|
|
|
+ # add timestamp to datafile
|
|
|
+ thisExp.addData('hold_wav.started', tThisFlipGlobal)
|
|
|
+ # update status
|
|
|
+ hold_wav.status = STARTED
|
|
|
+ hold_wav.play(when=win) # sync with win flip
|
|
|
+
|
|
|
+ # if hold_wav is stopping this frame...
|
|
|
+ if hold_wav.status == STARTED:
|
|
|
+ # is it time to stop? (based on global clock, using actual start)
|
|
|
+ if tThisFlipGlobal > hold_wav.tStartRefresh + 2-frameTolerance:
|
|
|
+ # keep track of stop time/frame for later
|
|
|
+ hold_wav.tStop = t # not accounting for scr refresh
|
|
|
+ hold_wav.frameNStop = frameN # exact frame index
|
|
|
+ # add timestamp to datafile
|
|
|
+ thisExp.timestampOnFlip(win, 'hold_wav.stopped')
|
|
|
+ # update status
|
|
|
+ hold_wav.status = FINISHED
|
|
|
+ hold_wav.stop()
|
|
|
+ # update hold_wav status according to whether it's playing
|
|
|
+ if hold_wav.isPlaying:
|
|
|
+ hold_wav.status = STARTED
|
|
|
+ elif hold_wav.isFinished:
|
|
|
+ hold_wav.status = FINISHED
|
|
|
+
|
|
|
# check for quit (typically the Esc key)
|
|
|
if defaultKeyboard.getKeys(keyList=["escape"]):
|
|
|
thisExp.status = FINISHED
|
|
@@ -1041,6 +1158,7 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
|
|
|
if hasattr(thisComponent, "setAutoDraw"):
|
|
|
thisComponent.setAutoDraw(False)
|
|
|
thisExp.addData('hold.stopped', globalClock.getTime())
|
|
|
+ hold_wav.pause() # ensure sound has stopped at end of Routine
|
|
|
# using non-slip timing so subtract the expected duration of this Routine (unless ended on request)
|
|
|
if routineForceEnded:
|
|
|
routineTimer.reset()
|
|
@@ -1053,8 +1171,14 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
|
|
|
thisExp.addData('rest.started', globalClock.getTime())
|
|
|
# Run 'Begin Routine' code from code_4
|
|
|
i = 0
|
|
|
+ rest_wav1.setSound('static/audios/ding.wav', secs=1.0, hamming=True)
|
|
|
+ rest_wav1.setVolume(1.0, log=False)
|
|
|
+ rest_wav1.seek(0)
|
|
|
+ rest_wav2.setSound('static/audios/rest.wav', secs=2, hamming=True)
|
|
|
+ rest_wav2.setVolume(1.0, log=False)
|
|
|
+ rest_wav2.seek(0)
|
|
|
# keep track of which components have finished
|
|
|
- restComponents = [rest_img]
|
|
|
+ restComponents = [rest_img, rest_wav1, rest_wav2]
|
|
|
for thisComponent in restComponents:
|
|
|
thisComponent.tStart = None
|
|
|
thisComponent.tStop = None
|
|
@@ -1117,6 +1241,66 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
|
|
|
|
|
|
i += 1
|
|
|
|
|
|
+ # if rest_wav1 is starting this frame...
|
|
|
+ if rest_wav1.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance:
|
|
|
+ # keep track of start time/frame for later
|
|
|
+ rest_wav1.frameNStart = frameN # exact frame index
|
|
|
+ rest_wav1.tStart = t # local t and not account for scr refresh
|
|
|
+ rest_wav1.tStartRefresh = tThisFlipGlobal # on global time
|
|
|
+ # add timestamp to datafile
|
|
|
+ thisExp.addData('rest_wav1.started', tThisFlipGlobal)
|
|
|
+ # update status
|
|
|
+ rest_wav1.status = STARTED
|
|
|
+ rest_wav1.play(when=win) # sync with win flip
|
|
|
+
|
|
|
+ # if rest_wav1 is stopping this frame...
|
|
|
+ if rest_wav1.status == STARTED:
|
|
|
+ # is it time to stop? (based on global clock, using actual start)
|
|
|
+ if tThisFlipGlobal > rest_wav1.tStartRefresh + 1.0-frameTolerance:
|
|
|
+ # keep track of stop time/frame for later
|
|
|
+ rest_wav1.tStop = t # not accounting for scr refresh
|
|
|
+ rest_wav1.frameNStop = frameN # exact frame index
|
|
|
+ # add timestamp to datafile
|
|
|
+ thisExp.timestampOnFlip(win, 'rest_wav1.stopped')
|
|
|
+ # update status
|
|
|
+ rest_wav1.status = FINISHED
|
|
|
+ rest_wav1.stop()
|
|
|
+ # update rest_wav1 status according to whether it's playing
|
|
|
+ if rest_wav1.isPlaying:
|
|
|
+ rest_wav1.status = STARTED
|
|
|
+ elif rest_wav1.isFinished:
|
|
|
+ rest_wav1.status = FINISHED
|
|
|
+
|
|
|
+ # if rest_wav2 is starting this frame...
|
|
|
+ if rest_wav2.status == NOT_STARTED and tThisFlip >= 0.8-frameTolerance:
|
|
|
+ # keep track of start time/frame for later
|
|
|
+ rest_wav2.frameNStart = frameN # exact frame index
|
|
|
+ rest_wav2.tStart = t # local t and not account for scr refresh
|
|
|
+ rest_wav2.tStartRefresh = tThisFlipGlobal # on global time
|
|
|
+ # add timestamp to datafile
|
|
|
+ thisExp.addData('rest_wav2.started', tThisFlipGlobal)
|
|
|
+ # update status
|
|
|
+ rest_wav2.status = STARTED
|
|
|
+ rest_wav2.play(when=win) # sync with win flip
|
|
|
+
|
|
|
+ # if rest_wav2 is stopping this frame...
|
|
|
+ if rest_wav2.status == STARTED:
|
|
|
+ # is it time to stop? (based on global clock, using actual start)
|
|
|
+ if tThisFlipGlobal > rest_wav2.tStartRefresh + 2-frameTolerance:
|
|
|
+ # keep track of stop time/frame for later
|
|
|
+ rest_wav2.tStop = t # not accounting for scr refresh
|
|
|
+ rest_wav2.frameNStop = frameN # exact frame index
|
|
|
+ # add timestamp to datafile
|
|
|
+ thisExp.timestampOnFlip(win, 'rest_wav2.stopped')
|
|
|
+ # update status
|
|
|
+ rest_wav2.status = FINISHED
|
|
|
+ rest_wav2.stop()
|
|
|
+ # update rest_wav2 status according to whether it's playing
|
|
|
+ if rest_wav2.isPlaying:
|
|
|
+ rest_wav2.status = STARTED
|
|
|
+ elif rest_wav2.isFinished:
|
|
|
+ rest_wav2.status = FINISHED
|
|
|
+
|
|
|
# check for quit (typically the Esc key)
|
|
|
if defaultKeyboard.getKeys(keyList=["escape"]):
|
|
|
thisExp.status = FINISHED
|
|
@@ -1143,6 +1327,8 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
|
|
|
if hasattr(thisComponent, "setAutoDraw"):
|
|
|
thisComponent.setAutoDraw(False)
|
|
|
thisExp.addData('rest.stopped', globalClock.getTime())
|
|
|
+ rest_wav1.pause() # ensure sound has stopped at end of Routine
|
|
|
+ rest_wav2.pause() # ensure sound has stopped at end of Routine
|
|
|
# using non-slip timing so subtract the expected duration of this Routine (unless ended on request)
|
|
|
if routineForceEnded:
|
|
|
routineTimer.reset()
|