grasp_data_collection.py 64 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. """
  4. This experiment was created using PsychoPy3 Experiment Builder (v2023.2.3),
  5. on 十二月 18, 2023, at 10:55
  6. If you publish work using this script the most relevant publication is:
  7. Peirce J, Gray JR, Simpson S, MacAskill M, Höchenberger R, Sogo H, Kastman E, Lindeløv JK. (2019)
  8. PsychoPy2: Experiments in behavior made easy Behav Res 51: 195.
  9. https://doi.org/10.3758/s13428-018-01193-y
  10. """
  11. # --- Import packages ---
  12. from psychopy import locale_setup
  13. from psychopy import prefs
  14. from psychopy import plugins
  15. plugins.activatePlugins()
  16. prefs.hardware['audioLib'] = 'ptb'
  17. prefs.hardware['audioLatencyMode'] = '3'
  18. from psychopy import sound, gui, visual, core, data, event, logging, clock, colors, layout
  19. from psychopy.tools import environmenttools
  20. from psychopy.constants import (NOT_STARTED, STARTED, PLAYING, PAUSED,
  21. STOPPED, FINISHED, PRESSED, RELEASED, FOREVER, priority)
  22. import numpy as np # whole numpy lib is available, prepend 'np.'
  23. from numpy import (sin, cos, tan, log, log10, pi, average,
  24. sqrt, std, deg2rad, rad2deg, linspace, asarray)
  25. from numpy.random import random, randint, normal, shuffle, choice as randchoice
  26. import os # handy system and path functions
  27. import sys # to get file system encoding
  28. import psychopy.iohub as io
  29. from psychopy.hardware import keyboard
  30. # Run 'Before Experiment' code from config
  31. import argparse
  32. import time
  33. from device.fubo_pneumatic_finger import FuboPneumaticFingerClient
  34. from device.trigger_box import TriggerNeuracle
  35. from settings.config import settings
  36. # get train params
  37. def parse_args():
  38. parser = argparse.ArgumentParser(
  39. description='Grasp training'
  40. )
  41. parser.add_argument(
  42. '--n-trials',
  43. dest='n_trials',
  44. help='Trial number',
  45. type=int,
  46. )
  47. parser.add_argument(
  48. '--com',
  49. dest='com',
  50. help='Peripheral serial port',
  51. type=str
  52. )
  53. parser.add_argument(
  54. '--finger-model',
  55. '-fm',
  56. dest='finger_model',
  57. help='Gesture to train',
  58. type=str
  59. )
  60. return parser.parse_args()
  61. args = parse_args()
  62. hand_device = FuboPneumaticFingerClient({'port': args.com})
  63. # connect to trigger box
  64. trigger = TriggerNeuracle()
  65. # Run 'Before Experiment' code from code
  66. # --- Setup global variables (available in all functions) ---
  67. # Ensure that relative paths start from the same directory as this script
  68. _thisDir = os.path.dirname(os.path.abspath(__file__))
  69. # Store info about the experiment session
  70. psychopyVersion = '2023.2.3'
  71. expName = 'grasp_data_collection' # from the Builder filename that created this script
  72. expInfo = {
  73. 'participant': f"{randint(0, 999999):06.0f}",
  74. 'session': '001',
  75. 'date': data.getDateStr(), # add a simple timestamp
  76. 'expName': expName,
  77. 'psychopyVersion': psychopyVersion,
  78. }
  79. def showExpInfoDlg(expInfo):
  80. """
  81. Show participant info dialog.
  82. Parameters
  83. ==========
  84. expInfo : dict
  85. Information about this experiment, created by the `setupExpInfo` function.
  86. Returns
  87. ==========
  88. dict
  89. Information about this experiment.
  90. """
  91. # temporarily remove keys which the dialog doesn't need to show
  92. poppedKeys = {
  93. 'date': expInfo.pop('date', data.getDateStr()),
  94. 'expName': expInfo.pop('expName', expName),
  95. 'psychopyVersion': expInfo.pop('psychopyVersion', psychopyVersion),
  96. }
  97. # show participant info dialog
  98. dlg = gui.DlgFromDict(dictionary=expInfo, sortKeys=False, title=expName)
  99. if dlg.OK == False:
  100. core.quit() # user pressed cancel
  101. # restore hidden keys
  102. expInfo.update(poppedKeys)
  103. # return expInfo
  104. return expInfo
  105. def setupData(expInfo, dataDir=None):
  106. """
  107. Make an ExperimentHandler to handle trials and saving.
  108. Parameters
  109. ==========
  110. expInfo : dict
  111. Information about this experiment, created by the `setupExpInfo` function.
  112. dataDir : Path, str or None
  113. Folder to save the data to, leave as None to create a folder in the current directory.
  114. Returns
  115. ==========
  116. psychopy.data.ExperimentHandler
  117. Handler object for this experiment, contains the data to save and information about
  118. where to save it to.
  119. """
  120. # data file name stem = absolute path + name; later add .psyexp, .csv, .log, etc
  121. if dataDir is None:
  122. dataDir = _thisDir
  123. filename = u'data/%s_%s_%s' % (expInfo['participant'], expName, expInfo['date'])
  124. # make sure filename is relative to dataDir
  125. if os.path.isabs(filename):
  126. dataDir = os.path.commonprefix([dataDir, filename])
  127. filename = os.path.relpath(filename, dataDir)
  128. # an ExperimentHandler isn't essential but helps with data saving
  129. thisExp = data.ExperimentHandler(
  130. name=expName, version='',
  131. extraInfo=expInfo, runtimeInfo=None,
  132. originPath='D:\\Graduate\\kraken\\backend\\grasp_data_collection.py',
  133. savePickle=True, saveWideText=True,
  134. dataFileName=dataDir + os.sep + filename, sortColumns='time'
  135. )
  136. thisExp.setPriority('thisRow.t', priority.CRITICAL)
  137. thisExp.setPriority('expName', priority.LOW)
  138. # return experiment handler
  139. return thisExp
  140. def setupLogging(filename):
  141. """
  142. Setup a log file and tell it what level to log at.
  143. Parameters
  144. ==========
  145. filename : str or pathlib.Path
  146. Filename to save log file and data files as, doesn't need an extension.
  147. Returns
  148. ==========
  149. psychopy.logging.LogFile
  150. Text stream to receive inputs from the logging system.
  151. """
  152. # this outputs to the screen, not a file
  153. logging.console.setLevel(logging.EXP)
  154. # save a log file for detail verbose info
  155. logFile = logging.LogFile(filename+'.log', level=logging.EXP)
  156. return logFile
  157. def setupWindow(expInfo=None, win=None):
  158. """
  159. Setup the Window
  160. Parameters
  161. ==========
  162. expInfo : dict
  163. Information about this experiment, created by the `setupExpInfo` function.
  164. win : psychopy.visual.Window
  165. Window to setup - leave as None to create a new window.
  166. Returns
  167. ==========
  168. psychopy.visual.Window
  169. Window in which to run this experiment.
  170. """
  171. if win is None:
  172. # if not given a window to setup, make one
  173. win = visual.Window(
  174. size=[1707, 1067], fullscr=True, screen=0,
  175. winType='pyglet', allowStencil=False,
  176. monitor='testMonitor', color=[1,1,1], colorSpace='rgb',
  177. backgroundImage='', backgroundFit='none',
  178. blendMode='avg', useFBO=True,
  179. units='height'
  180. )
  181. if expInfo is not None:
  182. # store frame rate of monitor if we can measure it
  183. expInfo['frameRate'] = win.getActualFrameRate()
  184. else:
  185. # if we have a window, just set the attributes which are safe to set
  186. win.color = [1,1,1]
  187. win.colorSpace = 'rgb'
  188. win.backgroundImage = ''
  189. win.backgroundFit = 'none'
  190. win.units = 'height'
  191. win.mouseVisible = False
  192. win.hideMessage()
  193. return win
  194. def setupInputs(expInfo, thisExp, win):
  195. """
  196. Setup whatever inputs are available (mouse, keyboard, eyetracker, etc.)
  197. Parameters
  198. ==========
  199. expInfo : dict
  200. Information about this experiment, created by the `setupExpInfo` function.
  201. thisExp : psychopy.data.ExperimentHandler
  202. Handler object for this experiment, contains the data to save and information about
  203. where to save it to.
  204. win : psychopy.visual.Window
  205. Window in which to run this experiment.
  206. Returns
  207. ==========
  208. dict
  209. Dictionary of input devices by name.
  210. """
  211. # --- Setup input devices ---
  212. inputs = {}
  213. ioConfig = {}
  214. # Setup iohub keyboard
  215. ioConfig['Keyboard'] = dict(use_keymap='psychopy')
  216. ioSession = '1'
  217. if 'session' in expInfo:
  218. ioSession = str(expInfo['session'])
  219. ioServer = io.launchHubServer(window=win, **ioConfig)
  220. eyetracker = None
  221. # create a default keyboard (e.g. to check for escape)
  222. defaultKeyboard = keyboard.Keyboard(backend='iohub')
  223. # return inputs dict
  224. return {
  225. 'ioServer': ioServer,
  226. 'defaultKeyboard': defaultKeyboard,
  227. 'eyetracker': eyetracker,
  228. }
  229. def pauseExperiment(thisExp, inputs=None, win=None, timers=[], playbackComponents=[]):
  230. """
  231. Pause this experiment, preventing the flow from advancing to the next routine until resumed.
  232. Parameters
  233. ==========
  234. thisExp : psychopy.data.ExperimentHandler
  235. Handler object for this experiment, contains the data to save and information about
  236. where to save it to.
  237. inputs : dict
  238. Dictionary of input devices by name.
  239. win : psychopy.visual.Window
  240. Window for this experiment.
  241. timers : list, tuple
  242. List of timers to reset once pausing is finished.
  243. playbackComponents : list, tuple
  244. List of any components with a `pause` method which need to be paused.
  245. """
  246. # if we are not paused, do nothing
  247. if thisExp.status != PAUSED:
  248. return
  249. # pause any playback components
  250. for comp in playbackComponents:
  251. comp.pause()
  252. # prevent components from auto-drawing
  253. win.stashAutoDraw()
  254. # run a while loop while we wait to unpause
  255. while thisExp.status == PAUSED:
  256. # make sure we have a keyboard
  257. if inputs is None:
  258. inputs = {
  259. 'defaultKeyboard': keyboard.Keyboard(backend='ioHub')
  260. }
  261. # check for quit (typically the Esc key)
  262. if inputs['defaultKeyboard'].getKeys(keyList=['escape']):
  263. endExperiment(thisExp, win=win, inputs=inputs)
  264. # flip the screen
  265. win.flip()
  266. # if stop was requested while paused, quit
  267. if thisExp.status == FINISHED:
  268. endExperiment(thisExp, inputs=inputs, win=win)
  269. # resume any playback components
  270. for comp in playbackComponents:
  271. comp.play()
  272. # restore auto-drawn components
  273. win.retrieveAutoDraw()
  274. # reset any timers
  275. for timer in timers:
  276. timer.reset()
  277. def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
  278. """
  279. Run the experiment flow.
  280. Parameters
  281. ==========
  282. expInfo : dict
  283. Information about this experiment, created by the `setupExpInfo` function.
  284. thisExp : psychopy.data.ExperimentHandler
  285. Handler object for this experiment, contains the data to save and information about
  286. where to save it to.
  287. psychopy.visual.Window
  288. Window in which to run this experiment.
  289. inputs : dict
  290. Dictionary of input devices by name.
  291. globalClock : psychopy.core.clock.Clock or None
  292. Clock to get global time from - supply None to make a new one.
  293. thisSession : psychopy.session.Session or None
  294. Handle of the Session object this experiment is being run from, if any.
  295. """
  296. # mark experiment as started
  297. thisExp.status = STARTED
  298. # make sure variables created by exec are available globally
  299. exec = environmenttools.setExecEnvironment(globals())
  300. # get device handles from dict of input devices
  301. ioServer = inputs['ioServer']
  302. defaultKeyboard = inputs['defaultKeyboard']
  303. eyetracker = inputs['eyetracker']
  304. # make sure we're running in the directory for this experiment
  305. os.chdir(_thisDir)
  306. # get filename from ExperimentHandler for convenience
  307. filename = thisExp.dataFileName
  308. frameTolerance = 0.001 # how close to onset before 'same' frame
  309. endExpNow = False # flag for 'escape' or other condition => quit the exp
  310. # get frame duration from frame rate in expInfo
  311. if 'frameRate' in expInfo and expInfo['frameRate'] is not None:
  312. frameDur = 1.0 / round(expInfo['frameRate'])
  313. else:
  314. frameDur = 1.0 / 60.0 # could not measure, so guess
  315. # Start Code - component code to be run after the window creation
  316. # --- Initialize components for Routine "prepare" ---
  317. text = visual.TextStim(win=win, name='text',
  318. text='抓握训练即将开始\n如果准备好了,请按空格键',
  319. font='Open Sans',
  320. pos=(0, 0), height=0.05, wrapWidth=None, ori=0.0,
  321. color='black', colorSpace='rgb', opacity=1.0,
  322. languageStyle='LTR',
  323. depth=0.0);
  324. key_resp = keyboard.Keyboard()
  325. # --- Initialize components for Routine "ready" ---
  326. ready_text = visual.TextStim(win=win, name='ready_text',
  327. text='请准备',
  328. font='Open Sans',
  329. pos=(0, 0), height=0.05, wrapWidth=None, ori=0.0,
  330. color='black', colorSpace='rgb', opacity=None,
  331. languageStyle='LTR',
  332. depth=0.0);
  333. # --- Initialize components for Routine "extend" ---
  334. extend_img = visual.ImageStim(
  335. win=win,
  336. name='extend_img',
  337. image='static/images/extend.png', mask=None, anchor='center',
  338. ori=0.0, pos=(0, 0), size=(0.5, 0.5),
  339. color=[1,1,1], colorSpace='rgb', opacity=None,
  340. flipHoriz=False, flipVert=False,
  341. texRes=128.0, interpolate=True, depth=0.0)
  342. attention = sound.Sound('static/audios/ding.wav', secs=1.0, stereo=True, hamming=True,
  343. name='attention')
  344. attention.setVolume(1.0)
  345. extend_wav = sound.Sound('static/audios/extend.wav', secs=2, stereo=True, hamming=True,
  346. name='extend_wav')
  347. extend_wav.setVolume(1.0)
  348. # --- Initialize components for Routine "flex" ---
  349. flex_img = visual.ImageStim(
  350. win=win,
  351. name='flex_img',
  352. image='static/images/flex.png', mask=None, anchor='center',
  353. ori=0.0, pos=(0, 0), size=(0.5, 0.5),
  354. color=[1,1,1], colorSpace='rgb', opacity=None,
  355. flipHoriz=False, flipVert=False,
  356. texRes=128.0, interpolate=True, depth=0.0)
  357. flex_wav = sound.Sound('static/audios/flex.wav', secs=2, stereo=True, hamming=True,
  358. name='flex_wav')
  359. flex_wav.setVolume(1.0)
  360. # --- Initialize components for Routine "hold" ---
  361. hold_img = visual.ImageStim(
  362. win=win,
  363. name='hold_img',
  364. image='static/images/hold.png', mask=None, anchor='center',
  365. ori=0.0, pos=(0, 0), size=(0.5, 0.5),
  366. color=[1,1,1], colorSpace='rgb', opacity=None,
  367. flipHoriz=False, flipVert=False,
  368. texRes=128.0, interpolate=True, depth=0.0)
  369. hold_wav = sound.Sound('static/audios/hold.wav', secs=2, stereo=True, hamming=True,
  370. name='hold_wav')
  371. hold_wav.setVolume(1.0)
  372. # --- Initialize components for Routine "rest" ---
  373. rest_img = visual.ImageStim(
  374. win=win,
  375. name='rest_img',
  376. image='static/images/rest.png', mask=None, anchor='center',
  377. ori=0.0, pos=(0, 0), size=(0.5, 0.5),
  378. color=[1,1,1], colorSpace='rgb', opacity=None,
  379. flipHoriz=False, flipVert=False,
  380. texRes=128.0, interpolate=True, depth=0.0)
  381. rest_wav1 = sound.Sound('static/audios/ding.wav', secs=1.0, stereo=True, hamming=True,
  382. name='rest_wav1')
  383. rest_wav1.setVolume(1.0)
  384. rest_wav2 = sound.Sound('static/audios/rest.wav', secs=2, stereo=True, hamming=True,
  385. name='rest_wav2')
  386. rest_wav2.setVolume(1.0)
  387. # --- Initialize components for Routine "end" ---
  388. end_text = visual.TextStim(win=win, name='end_text',
  389. text='恭喜您!\n完成训练!',
  390. font='Open Sans',
  391. pos=(0, 0), height=0.05, wrapWidth=None, ori=0.0,
  392. color='black', colorSpace='rgb', opacity=1.0,
  393. languageStyle='LTR',
  394. depth=0.0);
  395. # create some handy timers
  396. if globalClock is None:
  397. globalClock = core.Clock() # to track the time since experiment started
  398. if ioServer is not None:
  399. ioServer.syncClock(globalClock)
  400. logging.setDefaultClock(globalClock)
  401. routineTimer = core.Clock() # to track time remaining of each (possibly non-slip) routine
  402. win.flip() # flip window to reset last flip timer
  403. # store the exact time the global clock started
  404. expInfo['expStart'] = data.getDateStr(format='%Y-%m-%d %Hh%M.%S.%f %z', fractionalSecondDigits=6)
  405. # --- Prepare to start Routine "prepare" ---
  406. continueRoutine = True
  407. # update component parameters for each repeat
  408. thisExp.addData('prepare.started', globalClock.getTime())
  409. key_resp.keys = []
  410. key_resp.rt = []
  411. _key_resp_allKeys = []
  412. # Run 'Begin Routine' code from config
  413. # keep track of which components have finished
  414. prepareComponents = [text, key_resp]
  415. for thisComponent in prepareComponents:
  416. thisComponent.tStart = None
  417. thisComponent.tStop = None
  418. thisComponent.tStartRefresh = None
  419. thisComponent.tStopRefresh = None
  420. if hasattr(thisComponent, 'status'):
  421. thisComponent.status = NOT_STARTED
  422. # reset timers
  423. t = 0
  424. _timeToFirstFrame = win.getFutureFlipTime(clock="now")
  425. frameN = -1
  426. # --- Run Routine "prepare" ---
  427. routineForceEnded = not continueRoutine
  428. while continueRoutine:
  429. # get current time
  430. t = routineTimer.getTime()
  431. tThisFlip = win.getFutureFlipTime(clock=routineTimer)
  432. tThisFlipGlobal = win.getFutureFlipTime(clock=None)
  433. frameN = frameN + 1 # number of completed frames (so 0 is the first frame)
  434. # update/draw components on each frame
  435. # *text* updates
  436. # if text is starting this frame...
  437. if text.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance:
  438. # keep track of start time/frame for later
  439. text.frameNStart = frameN # exact frame index
  440. text.tStart = t # local t and not account for scr refresh
  441. text.tStartRefresh = tThisFlipGlobal # on global time
  442. win.timeOnFlip(text, 'tStartRefresh') # time at next scr refresh
  443. # add timestamp to datafile
  444. thisExp.timestampOnFlip(win, 'text.started')
  445. # update status
  446. text.status = STARTED
  447. text.setAutoDraw(True)
  448. # if text is active this frame...
  449. if text.status == STARTED:
  450. # update params
  451. pass
  452. # *key_resp* updates
  453. waitOnFlip = False
  454. # if key_resp is starting this frame...
  455. if key_resp.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance:
  456. # keep track of start time/frame for later
  457. key_resp.frameNStart = frameN # exact frame index
  458. key_resp.tStart = t # local t and not account for scr refresh
  459. key_resp.tStartRefresh = tThisFlipGlobal # on global time
  460. win.timeOnFlip(key_resp, 'tStartRefresh') # time at next scr refresh
  461. # add timestamp to datafile
  462. thisExp.timestampOnFlip(win, 'key_resp.started')
  463. # update status
  464. key_resp.status = STARTED
  465. # keyboard checking is just starting
  466. waitOnFlip = True
  467. win.callOnFlip(key_resp.clock.reset) # t=0 on next screen flip
  468. win.callOnFlip(key_resp.clearEvents, eventType='keyboard') # clear events on next screen flip
  469. if key_resp.status == STARTED and not waitOnFlip:
  470. theseKeys = key_resp.getKeys(keyList=['space'], ignoreKeys=["escape"], waitRelease=False)
  471. _key_resp_allKeys.extend(theseKeys)
  472. if len(_key_resp_allKeys):
  473. key_resp.keys = _key_resp_allKeys[-1].name # just the last key pressed
  474. key_resp.rt = _key_resp_allKeys[-1].rt
  475. key_resp.duration = _key_resp_allKeys[-1].duration
  476. # a response ends the routine
  477. continueRoutine = False
  478. # check for quit (typically the Esc key)
  479. if defaultKeyboard.getKeys(keyList=["escape"]):
  480. thisExp.status = FINISHED
  481. if thisExp.status == FINISHED or endExpNow:
  482. endExperiment(thisExp, inputs=inputs, win=win)
  483. return
  484. # check if all components have finished
  485. if not continueRoutine: # a component has requested a forced-end of Routine
  486. routineForceEnded = True
  487. break
  488. continueRoutine = False # will revert to True if at least one component still running
  489. for thisComponent in prepareComponents:
  490. if hasattr(thisComponent, "status") and thisComponent.status != FINISHED:
  491. continueRoutine = True
  492. break # at least one component has not yet finished
  493. # refresh the screen
  494. if continueRoutine: # don't flip if this routine is over or we'll get a blank screen
  495. win.flip()
  496. # --- Ending Routine "prepare" ---
  497. for thisComponent in prepareComponents:
  498. if hasattr(thisComponent, "setAutoDraw"):
  499. thisComponent.setAutoDraw(False)
  500. thisExp.addData('prepare.stopped', globalClock.getTime())
  501. # check responses
  502. if key_resp.keys in ['', [], None]: # No response was made
  503. key_resp.keys = None
  504. thisExp.addData('key_resp.keys',key_resp.keys)
  505. if key_resp.keys != None: # we had a response
  506. thisExp.addData('key_resp.rt', key_resp.rt)
  507. thisExp.addData('key_resp.duration', key_resp.duration)
  508. thisExp.nextEntry()
  509. # the Routine "prepare" was not non-slip safe, so reset the non-slip timer
  510. routineTimer.reset()
  511. # set up handler to look after randomisation of conditions etc
  512. trials = data.TrialHandler(nReps=args.n_trials, method='random',
  513. extraInfo=expInfo, originPath=-1,
  514. trialList=[None],
  515. seed=None, name='trials')
  516. thisExp.addLoop(trials) # add the loop to the experiment
  517. thisTrial = trials.trialList[0] # so we can initialise stimuli with some values
  518. # abbreviate parameter names if possible (e.g. rgb = thisTrial.rgb)
  519. if thisTrial != None:
  520. for paramName in thisTrial:
  521. globals()[paramName] = thisTrial[paramName]
  522. for thisTrial in trials:
  523. currentLoop = trials
  524. thisExp.timestampOnFlip(win, 'thisRow.t')
  525. # pause experiment here if requested
  526. if thisExp.status == PAUSED:
  527. pauseExperiment(
  528. thisExp=thisExp,
  529. inputs=inputs,
  530. win=win,
  531. timers=[routineTimer],
  532. playbackComponents=[]
  533. )
  534. # abbreviate parameter names if possible (e.g. rgb = thisTrial.rgb)
  535. if thisTrial != None:
  536. for paramName in thisTrial:
  537. globals()[paramName] = thisTrial[paramName]
  538. # --- Prepare to start Routine "ready" ---
  539. continueRoutine = True
  540. # update component parameters for each repeat
  541. thisExp.addData('ready.started', globalClock.getTime())
  542. # keep track of which components have finished
  543. readyComponents = [ready_text]
  544. for thisComponent in readyComponents:
  545. thisComponent.tStart = None
  546. thisComponent.tStop = None
  547. thisComponent.tStartRefresh = None
  548. thisComponent.tStopRefresh = None
  549. if hasattr(thisComponent, 'status'):
  550. thisComponent.status = NOT_STARTED
  551. # reset timers
  552. t = 0
  553. _timeToFirstFrame = win.getFutureFlipTime(clock="now")
  554. frameN = -1
  555. # --- Run Routine "ready" ---
  556. routineForceEnded = not continueRoutine
  557. while continueRoutine and routineTimer.getTime() < 1.5:
  558. # get current time
  559. t = routineTimer.getTime()
  560. tThisFlip = win.getFutureFlipTime(clock=routineTimer)
  561. tThisFlipGlobal = win.getFutureFlipTime(clock=None)
  562. frameN = frameN + 1 # number of completed frames (so 0 is the first frame)
  563. # update/draw components on each frame
  564. # *ready_text* updates
  565. # if ready_text is starting this frame...
  566. if ready_text.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance:
  567. # keep track of start time/frame for later
  568. ready_text.frameNStart = frameN # exact frame index
  569. ready_text.tStart = t # local t and not account for scr refresh
  570. ready_text.tStartRefresh = tThisFlipGlobal # on global time
  571. win.timeOnFlip(ready_text, 'tStartRefresh') # time at next scr refresh
  572. # add timestamp to datafile
  573. thisExp.timestampOnFlip(win, 'ready_text.started')
  574. # update status
  575. ready_text.status = STARTED
  576. ready_text.setAutoDraw(True)
  577. # if ready_text is active this frame...
  578. if ready_text.status == STARTED:
  579. # update params
  580. pass
  581. # if ready_text is stopping this frame...
  582. if ready_text.status == STARTED:
  583. # is it time to stop? (based on global clock, using actual start)
  584. if tThisFlipGlobal > ready_text.tStartRefresh + 1.5-frameTolerance:
  585. # keep track of stop time/frame for later
  586. ready_text.tStop = t # not accounting for scr refresh
  587. ready_text.frameNStop = frameN # exact frame index
  588. # add timestamp to datafile
  589. thisExp.timestampOnFlip(win, 'ready_text.stopped')
  590. # update status
  591. ready_text.status = FINISHED
  592. ready_text.setAutoDraw(False)
  593. # check for quit (typically the Esc key)
  594. if defaultKeyboard.getKeys(keyList=["escape"]):
  595. thisExp.status = FINISHED
  596. if thisExp.status == FINISHED or endExpNow:
  597. endExperiment(thisExp, inputs=inputs, win=win)
  598. return
  599. # check if all components have finished
  600. if not continueRoutine: # a component has requested a forced-end of Routine
  601. routineForceEnded = True
  602. break
  603. continueRoutine = False # will revert to True if at least one component still running
  604. for thisComponent in readyComponents:
  605. if hasattr(thisComponent, "status") and thisComponent.status != FINISHED:
  606. continueRoutine = True
  607. break # at least one component has not yet finished
  608. # refresh the screen
  609. if continueRoutine: # don't flip if this routine is over or we'll get a blank screen
  610. win.flip()
  611. # --- Ending Routine "ready" ---
  612. for thisComponent in readyComponents:
  613. if hasattr(thisComponent, "setAutoDraw"):
  614. thisComponent.setAutoDraw(False)
  615. thisExp.addData('ready.stopped', globalClock.getTime())
  616. # using non-slip timing so subtract the expected duration of this Routine (unless ended on request)
  617. if routineForceEnded:
  618. routineTimer.reset()
  619. else:
  620. routineTimer.addTime(-1.500000)
  621. # --- Prepare to start Routine "extend" ---
  622. continueRoutine = True
  623. # update component parameters for each repeat
  624. thisExp.addData('extend.started', globalClock.getTime())
  625. attention.setSound('static/audios/ding.wav', secs=1.0, hamming=True)
  626. attention.setVolume(1.0, log=False)
  627. attention.seek(0)
  628. # Run 'Begin Routine' code from code
  629. i = 0
  630. extend_wav.setSound('static/audios/extend.wav', secs=2, hamming=True)
  631. extend_wav.setVolume(1.0, log=False)
  632. extend_wav.seek(0)
  633. # keep track of which components have finished
  634. extendComponents = [extend_img, attention, extend_wav]
  635. for thisComponent in extendComponents:
  636. thisComponent.tStart = None
  637. thisComponent.tStop = None
  638. thisComponent.tStartRefresh = None
  639. thisComponent.tStopRefresh = None
  640. if hasattr(thisComponent, 'status'):
  641. thisComponent.status = NOT_STARTED
  642. # reset timers
  643. t = 0
  644. _timeToFirstFrame = win.getFutureFlipTime(clock="now")
  645. frameN = -1
  646. # --- Run Routine "extend" ---
  647. routineForceEnded = not continueRoutine
  648. while continueRoutine and routineTimer.getTime() < 7.0:
  649. # get current time
  650. t = routineTimer.getTime()
  651. tThisFlip = win.getFutureFlipTime(clock=routineTimer)
  652. tThisFlipGlobal = win.getFutureFlipTime(clock=None)
  653. frameN = frameN + 1 # number of completed frames (so 0 is the first frame)
  654. # update/draw components on each frame
  655. # *extend_img* updates
  656. # if extend_img is starting this frame...
  657. if extend_img.status == NOT_STARTED and tThisFlip >= 1-frameTolerance:
  658. # keep track of start time/frame for later
  659. extend_img.frameNStart = frameN # exact frame index
  660. extend_img.tStart = t # local t and not account for scr refresh
  661. extend_img.tStartRefresh = tThisFlipGlobal # on global time
  662. win.timeOnFlip(extend_img, 'tStartRefresh') # time at next scr refresh
  663. # add timestamp to datafile
  664. thisExp.timestampOnFlip(win, 'extend_img.started')
  665. # update status
  666. extend_img.status = STARTED
  667. extend_img.setAutoDraw(True)
  668. # if extend_img is active this frame...
  669. if extend_img.status == STARTED:
  670. # update params
  671. pass
  672. # if extend_img is stopping this frame...
  673. if extend_img.status == STARTED:
  674. # is it time to stop? (based on global clock, using actual start)
  675. if tThisFlipGlobal > extend_img.tStartRefresh + 6-frameTolerance:
  676. # keep track of stop time/frame for later
  677. extend_img.tStop = t # not accounting for scr refresh
  678. extend_img.frameNStop = frameN # exact frame index
  679. # add timestamp to datafile
  680. thisExp.timestampOnFlip(win, 'extend_img.stopped')
  681. # update status
  682. extend_img.status = FINISHED
  683. extend_img.setAutoDraw(False)
  684. # if attention is starting this frame...
  685. if attention.status == NOT_STARTED and tThisFlip >= 1-frameTolerance:
  686. # keep track of start time/frame for later
  687. attention.frameNStart = frameN # exact frame index
  688. attention.tStart = t # local t and not account for scr refresh
  689. attention.tStartRefresh = tThisFlipGlobal # on global time
  690. # add timestamp to datafile
  691. thisExp.addData('attention.started', tThisFlipGlobal)
  692. # update status
  693. attention.status = STARTED
  694. attention.play(when=win) # sync with win flip
  695. # if attention is stopping this frame...
  696. if attention.status == STARTED:
  697. # is it time to stop? (based on global clock, using actual start)
  698. if tThisFlipGlobal > attention.tStartRefresh + 1.0-frameTolerance:
  699. # keep track of stop time/frame for later
  700. attention.tStop = t # not accounting for scr refresh
  701. attention.frameNStop = frameN # exact frame index
  702. # add timestamp to datafile
  703. thisExp.timestampOnFlip(win, 'attention.stopped')
  704. # update status
  705. attention.status = FINISHED
  706. attention.stop()
  707. # update attention status according to whether it's playing
  708. if attention.isPlaying:
  709. attention.status = STARTED
  710. elif attention.isFinished:
  711. attention.status = FINISHED
  712. # Run 'Each Frame' code from code
  713. if i== 119:
  714. hand_device.start('extend')
  715. # send trigger
  716. current_true_label = settings.FINGERMODEL_IDS['extend']
  717. win.callOnFlip(trigger.send_trigger, current_true_label)
  718. i += 1
  719. # 每轮开始前空白等待1s + 反应时1s + 新版extend时间4.5s + 0.5s裕量 = 7s
  720. # if extend_wav is starting this frame...
  721. if extend_wav.status == NOT_STARTED and tThisFlip >= 1.8-frameTolerance:
  722. # keep track of start time/frame for later
  723. extend_wav.frameNStart = frameN # exact frame index
  724. extend_wav.tStart = t # local t and not account for scr refresh
  725. extend_wav.tStartRefresh = tThisFlipGlobal # on global time
  726. # add timestamp to datafile
  727. thisExp.addData('extend_wav.started', tThisFlipGlobal)
  728. # update status
  729. extend_wav.status = STARTED
  730. extend_wav.play(when=win) # sync with win flip
  731. # if extend_wav is stopping this frame...
  732. if extend_wav.status == STARTED:
  733. # is it time to stop? (based on global clock, using actual start)
  734. if tThisFlipGlobal > extend_wav.tStartRefresh + 2-frameTolerance:
  735. # keep track of stop time/frame for later
  736. extend_wav.tStop = t # not accounting for scr refresh
  737. extend_wav.frameNStop = frameN # exact frame index
  738. # add timestamp to datafile
  739. thisExp.timestampOnFlip(win, 'extend_wav.stopped')
  740. # update status
  741. extend_wav.status = FINISHED
  742. extend_wav.stop()
  743. # update extend_wav status according to whether it's playing
  744. if extend_wav.isPlaying:
  745. extend_wav.status = STARTED
  746. elif extend_wav.isFinished:
  747. extend_wav.status = FINISHED
  748. # check for quit (typically the Esc key)
  749. if defaultKeyboard.getKeys(keyList=["escape"]):
  750. thisExp.status = FINISHED
  751. if thisExp.status == FINISHED or endExpNow:
  752. endExperiment(thisExp, inputs=inputs, win=win)
  753. return
  754. # check if all components have finished
  755. if not continueRoutine: # a component has requested a forced-end of Routine
  756. routineForceEnded = True
  757. break
  758. continueRoutine = False # will revert to True if at least one component still running
  759. for thisComponent in extendComponents:
  760. if hasattr(thisComponent, "status") and thisComponent.status != FINISHED:
  761. continueRoutine = True
  762. break # at least one component has not yet finished
  763. # refresh the screen
  764. if continueRoutine: # don't flip if this routine is over or we'll get a blank screen
  765. win.flip()
  766. # --- Ending Routine "extend" ---
  767. for thisComponent in extendComponents:
  768. if hasattr(thisComponent, "setAutoDraw"):
  769. thisComponent.setAutoDraw(False)
  770. thisExp.addData('extend.stopped', globalClock.getTime())
  771. attention.pause() # ensure sound has stopped at end of Routine
  772. extend_wav.pause() # ensure sound has stopped at end of Routine
  773. # using non-slip timing so subtract the expected duration of this Routine (unless ended on request)
  774. if routineForceEnded:
  775. routineTimer.reset()
  776. else:
  777. routineTimer.addTime(-7.000000)
  778. # --- Prepare to start Routine "flex" ---
  779. continueRoutine = True
  780. # update component parameters for each repeat
  781. thisExp.addData('flex.started', globalClock.getTime())
  782. # Run 'Begin Routine' code from code_2
  783. i = 0
  784. flex_wav.setSound('static/audios/flex.wav', secs=2, hamming=True)
  785. flex_wav.setVolume(1.0, log=False)
  786. flex_wav.seek(0)
  787. # keep track of which components have finished
  788. flexComponents = [flex_img, flex_wav]
  789. for thisComponent in flexComponents:
  790. thisComponent.tStart = None
  791. thisComponent.tStop = None
  792. thisComponent.tStartRefresh = None
  793. thisComponent.tStopRefresh = None
  794. if hasattr(thisComponent, 'status'):
  795. thisComponent.status = NOT_STARTED
  796. # reset timers
  797. t = 0
  798. _timeToFirstFrame = win.getFutureFlipTime(clock="now")
  799. frameN = -1
  800. # --- Run Routine "flex" ---
  801. routineForceEnded = not continueRoutine
  802. while continueRoutine and routineTimer.getTime() < 6.0:
  803. # get current time
  804. t = routineTimer.getTime()
  805. tThisFlip = win.getFutureFlipTime(clock=routineTimer)
  806. tThisFlipGlobal = win.getFutureFlipTime(clock=None)
  807. frameN = frameN + 1 # number of completed frames (so 0 is the first frame)
  808. # update/draw components on each frame
  809. # *flex_img* updates
  810. # if flex_img is starting this frame...
  811. if flex_img.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance:
  812. # keep track of start time/frame for later
  813. flex_img.frameNStart = frameN # exact frame index
  814. flex_img.tStart = t # local t and not account for scr refresh
  815. flex_img.tStartRefresh = tThisFlipGlobal # on global time
  816. win.timeOnFlip(flex_img, 'tStartRefresh') # time at next scr refresh
  817. # add timestamp to datafile
  818. thisExp.timestampOnFlip(win, 'flex_img.started')
  819. # update status
  820. flex_img.status = STARTED
  821. flex_img.setAutoDraw(True)
  822. # if flex_img is active this frame...
  823. if flex_img.status == STARTED:
  824. # update params
  825. pass
  826. # if flex_img is stopping this frame...
  827. if flex_img.status == STARTED:
  828. # is it time to stop? (based on global clock, using actual start)
  829. if tThisFlipGlobal > flex_img.tStartRefresh + 6-frameTolerance:
  830. # keep track of stop time/frame for later
  831. flex_img.tStop = t # not accounting for scr refresh
  832. flex_img.frameNStop = frameN # exact frame index
  833. # add timestamp to datafile
  834. thisExp.timestampOnFlip(win, 'flex_img.stopped')
  835. # update status
  836. flex_img.status = FINISHED
  837. flex_img.setAutoDraw(False)
  838. # Run 'Each Frame' code from code_2
  839. if i == 59:
  840. hand_device.start(args.finger_model)
  841. # trigger
  842. current_true_label = settings.FINGERMODEL_IDS[args.finger_model]
  843. win.callOnFlip(trigger.send_trigger, current_true_label)
  844. i += 1
  845. # 反应时1s+新版气动手flex时间4.5s + 0.5s裕量 = 6s
  846. # if flex_wav is starting this frame...
  847. if flex_wav.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance:
  848. # keep track of start time/frame for later
  849. flex_wav.frameNStart = frameN # exact frame index
  850. flex_wav.tStart = t # local t and not account for scr refresh
  851. flex_wav.tStartRefresh = tThisFlipGlobal # on global time
  852. # add timestamp to datafile
  853. thisExp.addData('flex_wav.started', tThisFlipGlobal)
  854. # update status
  855. flex_wav.status = STARTED
  856. flex_wav.play(when=win) # sync with win flip
  857. # if flex_wav is stopping this frame...
  858. if flex_wav.status == STARTED:
  859. # is it time to stop? (based on global clock, using actual start)
  860. if tThisFlipGlobal > flex_wav.tStartRefresh + 2-frameTolerance:
  861. # keep track of stop time/frame for later
  862. flex_wav.tStop = t # not accounting for scr refresh
  863. flex_wav.frameNStop = frameN # exact frame index
  864. # add timestamp to datafile
  865. thisExp.timestampOnFlip(win, 'flex_wav.stopped')
  866. # update status
  867. flex_wav.status = FINISHED
  868. flex_wav.stop()
  869. # update flex_wav status according to whether it's playing
  870. if flex_wav.isPlaying:
  871. flex_wav.status = STARTED
  872. elif flex_wav.isFinished:
  873. flex_wav.status = FINISHED
  874. # check for quit (typically the Esc key)
  875. if defaultKeyboard.getKeys(keyList=["escape"]):
  876. thisExp.status = FINISHED
  877. if thisExp.status == FINISHED or endExpNow:
  878. endExperiment(thisExp, inputs=inputs, win=win)
  879. return
  880. # check if all components have finished
  881. if not continueRoutine: # a component has requested a forced-end of Routine
  882. routineForceEnded = True
  883. break
  884. continueRoutine = False # will revert to True if at least one component still running
  885. for thisComponent in flexComponents:
  886. if hasattr(thisComponent, "status") and thisComponent.status != FINISHED:
  887. continueRoutine = True
  888. break # at least one component has not yet finished
  889. # refresh the screen
  890. if continueRoutine: # don't flip if this routine is over or we'll get a blank screen
  891. win.flip()
  892. # --- Ending Routine "flex" ---
  893. for thisComponent in flexComponents:
  894. if hasattr(thisComponent, "setAutoDraw"):
  895. thisComponent.setAutoDraw(False)
  896. thisExp.addData('flex.stopped', globalClock.getTime())
  897. flex_wav.pause() # ensure sound has stopped at end of Routine
  898. # using non-slip timing so subtract the expected duration of this Routine (unless ended on request)
  899. if routineForceEnded:
  900. routineTimer.reset()
  901. else:
  902. routineTimer.addTime(-6.000000)
  903. # --- Prepare to start Routine "hold" ---
  904. continueRoutine = True
  905. # update component parameters for each repeat
  906. thisExp.addData('hold.started', globalClock.getTime())
  907. # Run 'Begin Routine' code from code_3
  908. win.callOnFlip(trigger.send_trigger, settings.FINGERMODEL_IDS['hold'])
  909. hold_wav.setSound('static/audios/hold.wav', secs=2, hamming=True)
  910. hold_wav.setVolume(1.0, log=False)
  911. hold_wav.seek(0)
  912. # keep track of which components have finished
  913. holdComponents = [hold_img, hold_wav]
  914. for thisComponent in holdComponents:
  915. thisComponent.tStart = None
  916. thisComponent.tStop = None
  917. thisComponent.tStartRefresh = None
  918. thisComponent.tStopRefresh = None
  919. if hasattr(thisComponent, 'status'):
  920. thisComponent.status = NOT_STARTED
  921. # reset timers
  922. t = 0
  923. _timeToFirstFrame = win.getFutureFlipTime(clock="now")
  924. frameN = -1
  925. # --- Run Routine "hold" ---
  926. routineForceEnded = not continueRoutine
  927. while continueRoutine and routineTimer.getTime() < 5.0:
  928. # get current time
  929. t = routineTimer.getTime()
  930. tThisFlip = win.getFutureFlipTime(clock=routineTimer)
  931. tThisFlipGlobal = win.getFutureFlipTime(clock=None)
  932. frameN = frameN + 1 # number of completed frames (so 0 is the first frame)
  933. # update/draw components on each frame
  934. # *hold_img* updates
  935. # if hold_img is starting this frame...
  936. if hold_img.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance:
  937. # keep track of start time/frame for later
  938. hold_img.frameNStart = frameN # exact frame index
  939. hold_img.tStart = t # local t and not account for scr refresh
  940. hold_img.tStartRefresh = tThisFlipGlobal # on global time
  941. win.timeOnFlip(hold_img, 'tStartRefresh') # time at next scr refresh
  942. # add timestamp to datafile
  943. thisExp.timestampOnFlip(win, 'hold_img.started')
  944. # update status
  945. hold_img.status = STARTED
  946. hold_img.setAutoDraw(True)
  947. # if hold_img is active this frame...
  948. if hold_img.status == STARTED:
  949. # update params
  950. pass
  951. # if hold_img is stopping this frame...
  952. if hold_img.status == STARTED:
  953. # is it time to stop? (based on global clock, using actual start)
  954. if tThisFlipGlobal > hold_img.tStartRefresh + 5-frameTolerance:
  955. # keep track of stop time/frame for later
  956. hold_img.tStop = t # not accounting for scr refresh
  957. hold_img.frameNStop = frameN # exact frame index
  958. # add timestamp to datafile
  959. thisExp.timestampOnFlip(win, 'hold_img.stopped')
  960. # update status
  961. hold_img.status = FINISHED
  962. hold_img.setAutoDraw(False)
  963. # if hold_wav is starting this frame...
  964. if hold_wav.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance:
  965. # keep track of start time/frame for later
  966. hold_wav.frameNStart = frameN # exact frame index
  967. hold_wav.tStart = t # local t and not account for scr refresh
  968. hold_wav.tStartRefresh = tThisFlipGlobal # on global time
  969. # add timestamp to datafile
  970. thisExp.addData('hold_wav.started', tThisFlipGlobal)
  971. # update status
  972. hold_wav.status = STARTED
  973. hold_wav.play(when=win) # sync with win flip
  974. # if hold_wav is stopping this frame...
  975. if hold_wav.status == STARTED:
  976. # is it time to stop? (based on global clock, using actual start)
  977. if tThisFlipGlobal > hold_wav.tStartRefresh + 2-frameTolerance:
  978. # keep track of stop time/frame for later
  979. hold_wav.tStop = t # not accounting for scr refresh
  980. hold_wav.frameNStop = frameN # exact frame index
  981. # add timestamp to datafile
  982. thisExp.timestampOnFlip(win, 'hold_wav.stopped')
  983. # update status
  984. hold_wav.status = FINISHED
  985. hold_wav.stop()
  986. # update hold_wav status according to whether it's playing
  987. if hold_wav.isPlaying:
  988. hold_wav.status = STARTED
  989. elif hold_wav.isFinished:
  990. hold_wav.status = FINISHED
  991. # check for quit (typically the Esc key)
  992. if defaultKeyboard.getKeys(keyList=["escape"]):
  993. thisExp.status = FINISHED
  994. if thisExp.status == FINISHED or endExpNow:
  995. endExperiment(thisExp, inputs=inputs, win=win)
  996. return
  997. # check if all components have finished
  998. if not continueRoutine: # a component has requested a forced-end of Routine
  999. routineForceEnded = True
  1000. break
  1001. continueRoutine = False # will revert to True if at least one component still running
  1002. for thisComponent in holdComponents:
  1003. if hasattr(thisComponent, "status") and thisComponent.status != FINISHED:
  1004. continueRoutine = True
  1005. break # at least one component has not yet finished
  1006. # refresh the screen
  1007. if continueRoutine: # don't flip if this routine is over or we'll get a blank screen
  1008. win.flip()
  1009. # --- Ending Routine "hold" ---
  1010. for thisComponent in holdComponents:
  1011. if hasattr(thisComponent, "setAutoDraw"):
  1012. thisComponent.setAutoDraw(False)
  1013. thisExp.addData('hold.stopped', globalClock.getTime())
  1014. hold_wav.pause() # ensure sound has stopped at end of Routine
  1015. # using non-slip timing so subtract the expected duration of this Routine (unless ended on request)
  1016. if routineForceEnded:
  1017. routineTimer.reset()
  1018. else:
  1019. routineTimer.addTime(-5.000000)
  1020. # --- Prepare to start Routine "rest" ---
  1021. continueRoutine = True
  1022. # update component parameters for each repeat
  1023. thisExp.addData('rest.started', globalClock.getTime())
  1024. # Run 'Begin Routine' code from code_4
  1025. i = 0
  1026. rest_wav1.setSound('static/audios/ding.wav', secs=1.0, hamming=True)
  1027. rest_wav1.setVolume(1.0, log=False)
  1028. rest_wav1.seek(0)
  1029. rest_wav2.setSound('static/audios/rest.wav', secs=2, hamming=True)
  1030. rest_wav2.setVolume(1.0, log=False)
  1031. rest_wav2.seek(0)
  1032. # keep track of which components have finished
  1033. restComponents = [rest_img, rest_wav1, rest_wav2]
  1034. for thisComponent in restComponents:
  1035. thisComponent.tStart = None
  1036. thisComponent.tStop = None
  1037. thisComponent.tStartRefresh = None
  1038. thisComponent.tStopRefresh = None
  1039. if hasattr(thisComponent, 'status'):
  1040. thisComponent.status = NOT_STARTED
  1041. # reset timers
  1042. t = 0
  1043. _timeToFirstFrame = win.getFutureFlipTime(clock="now")
  1044. frameN = -1
  1045. # --- Run Routine "rest" ---
  1046. routineForceEnded = not continueRoutine
  1047. while continueRoutine and routineTimer.getTime() < 6.0:
  1048. # get current time
  1049. t = routineTimer.getTime()
  1050. tThisFlip = win.getFutureFlipTime(clock=routineTimer)
  1051. tThisFlipGlobal = win.getFutureFlipTime(clock=None)
  1052. frameN = frameN + 1 # number of completed frames (so 0 is the first frame)
  1053. # update/draw components on each frame
  1054. # *rest_img* updates
  1055. # if rest_img is starting this frame...
  1056. if rest_img.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance:
  1057. # keep track of start time/frame for later
  1058. rest_img.frameNStart = frameN # exact frame index
  1059. rest_img.tStart = t # local t and not account for scr refresh
  1060. rest_img.tStartRefresh = tThisFlipGlobal # on global time
  1061. win.timeOnFlip(rest_img, 'tStartRefresh') # time at next scr refresh
  1062. # add timestamp to datafile
  1063. thisExp.timestampOnFlip(win, 'rest_img.started')
  1064. # update status
  1065. rest_img.status = STARTED
  1066. rest_img.setAutoDraw(True)
  1067. # if rest_img is active this frame...
  1068. if rest_img.status == STARTED:
  1069. # update params
  1070. pass
  1071. # if rest_img is stopping this frame...
  1072. if rest_img.status == STARTED:
  1073. # is it time to stop? (based on global clock, using actual start)
  1074. if tThisFlipGlobal > rest_img.tStartRefresh + 6-frameTolerance:
  1075. # keep track of stop time/frame for later
  1076. rest_img.tStop = t # not accounting for scr refresh
  1077. rest_img.frameNStop = frameN # exact frame index
  1078. # add timestamp to datafile
  1079. thisExp.timestampOnFlip(win, 'rest_img.stopped')
  1080. # update status
  1081. rest_img.status = FINISHED
  1082. rest_img.setAutoDraw(False)
  1083. # Run 'Each Frame' code from code_4
  1084. if i== 59:
  1085. hand_device.start('rest')
  1086. # trigger
  1087. win.callOnFlip(trigger.send_trigger, settings.FINGERMODEL_IDS['rest'])
  1088. i += 1
  1089. # if rest_wav1 is starting this frame...
  1090. if rest_wav1.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance:
  1091. # keep track of start time/frame for later
  1092. rest_wav1.frameNStart = frameN # exact frame index
  1093. rest_wav1.tStart = t # local t and not account for scr refresh
  1094. rest_wav1.tStartRefresh = tThisFlipGlobal # on global time
  1095. # add timestamp to datafile
  1096. thisExp.addData('rest_wav1.started', tThisFlipGlobal)
  1097. # update status
  1098. rest_wav1.status = STARTED
  1099. rest_wav1.play(when=win) # sync with win flip
  1100. # if rest_wav1 is stopping this frame...
  1101. if rest_wav1.status == STARTED:
  1102. # is it time to stop? (based on global clock, using actual start)
  1103. if tThisFlipGlobal > rest_wav1.tStartRefresh + 1.0-frameTolerance:
  1104. # keep track of stop time/frame for later
  1105. rest_wav1.tStop = t # not accounting for scr refresh
  1106. rest_wav1.frameNStop = frameN # exact frame index
  1107. # add timestamp to datafile
  1108. thisExp.timestampOnFlip(win, 'rest_wav1.stopped')
  1109. # update status
  1110. rest_wav1.status = FINISHED
  1111. rest_wav1.stop()
  1112. # update rest_wav1 status according to whether it's playing
  1113. if rest_wav1.isPlaying:
  1114. rest_wav1.status = STARTED
  1115. elif rest_wav1.isFinished:
  1116. rest_wav1.status = FINISHED
  1117. # if rest_wav2 is starting this frame...
  1118. if rest_wav2.status == NOT_STARTED and tThisFlip >= 0.8-frameTolerance:
  1119. # keep track of start time/frame for later
  1120. rest_wav2.frameNStart = frameN # exact frame index
  1121. rest_wav2.tStart = t # local t and not account for scr refresh
  1122. rest_wav2.tStartRefresh = tThisFlipGlobal # on global time
  1123. # add timestamp to datafile
  1124. thisExp.addData('rest_wav2.started', tThisFlipGlobal)
  1125. # update status
  1126. rest_wav2.status = STARTED
  1127. rest_wav2.play(when=win) # sync with win flip
  1128. # if rest_wav2 is stopping this frame...
  1129. if rest_wav2.status == STARTED:
  1130. # is it time to stop? (based on global clock, using actual start)
  1131. if tThisFlipGlobal > rest_wav2.tStartRefresh + 2-frameTolerance:
  1132. # keep track of stop time/frame for later
  1133. rest_wav2.tStop = t # not accounting for scr refresh
  1134. rest_wav2.frameNStop = frameN # exact frame index
  1135. # add timestamp to datafile
  1136. thisExp.timestampOnFlip(win, 'rest_wav2.stopped')
  1137. # update status
  1138. rest_wav2.status = FINISHED
  1139. rest_wav2.stop()
  1140. # update rest_wav2 status according to whether it's playing
  1141. if rest_wav2.isPlaying:
  1142. rest_wav2.status = STARTED
  1143. elif rest_wav2.isFinished:
  1144. rest_wav2.status = FINISHED
  1145. # check for quit (typically the Esc key)
  1146. if defaultKeyboard.getKeys(keyList=["escape"]):
  1147. thisExp.status = FINISHED
  1148. if thisExp.status == FINISHED or endExpNow:
  1149. endExperiment(thisExp, inputs=inputs, win=win)
  1150. return
  1151. # check if all components have finished
  1152. if not continueRoutine: # a component has requested a forced-end of Routine
  1153. routineForceEnded = True
  1154. break
  1155. continueRoutine = False # will revert to True if at least one component still running
  1156. for thisComponent in restComponents:
  1157. if hasattr(thisComponent, "status") and thisComponent.status != FINISHED:
  1158. continueRoutine = True
  1159. break # at least one component has not yet finished
  1160. # refresh the screen
  1161. if continueRoutine: # don't flip if this routine is over or we'll get a blank screen
  1162. win.flip()
  1163. # --- Ending Routine "rest" ---
  1164. for thisComponent in restComponents:
  1165. if hasattr(thisComponent, "setAutoDraw"):
  1166. thisComponent.setAutoDraw(False)
  1167. thisExp.addData('rest.stopped', globalClock.getTime())
  1168. rest_wav1.pause() # ensure sound has stopped at end of Routine
  1169. rest_wav2.pause() # ensure sound has stopped at end of Routine
  1170. # using non-slip timing so subtract the expected duration of this Routine (unless ended on request)
  1171. if routineForceEnded:
  1172. routineTimer.reset()
  1173. else:
  1174. routineTimer.addTime(-6.000000)
  1175. thisExp.nextEntry()
  1176. if thisSession is not None:
  1177. # if running in a Session with a Liaison client, send data up to now
  1178. thisSession.sendExperimentData()
  1179. # completed args.n_trials repeats of 'trials'
  1180. # --- Prepare to start Routine "end" ---
  1181. continueRoutine = True
  1182. # update component parameters for each repeat
  1183. thisExp.addData('end.started', globalClock.getTime())
  1184. # keep track of which components have finished
  1185. endComponents = [end_text]
  1186. for thisComponent in endComponents:
  1187. thisComponent.tStart = None
  1188. thisComponent.tStop = None
  1189. thisComponent.tStartRefresh = None
  1190. thisComponent.tStopRefresh = None
  1191. if hasattr(thisComponent, 'status'):
  1192. thisComponent.status = NOT_STARTED
  1193. # reset timers
  1194. t = 0
  1195. _timeToFirstFrame = win.getFutureFlipTime(clock="now")
  1196. frameN = -1
  1197. # --- Run Routine "end" ---
  1198. routineForceEnded = not continueRoutine
  1199. while continueRoutine and routineTimer.getTime() < 3.0:
  1200. # get current time
  1201. t = routineTimer.getTime()
  1202. tThisFlip = win.getFutureFlipTime(clock=routineTimer)
  1203. tThisFlipGlobal = win.getFutureFlipTime(clock=None)
  1204. frameN = frameN + 1 # number of completed frames (so 0 is the first frame)
  1205. # update/draw components on each frame
  1206. # *end_text* updates
  1207. # if end_text is starting this frame...
  1208. if end_text.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance:
  1209. # keep track of start time/frame for later
  1210. end_text.frameNStart = frameN # exact frame index
  1211. end_text.tStart = t # local t and not account for scr refresh
  1212. end_text.tStartRefresh = tThisFlipGlobal # on global time
  1213. win.timeOnFlip(end_text, 'tStartRefresh') # time at next scr refresh
  1214. # add timestamp to datafile
  1215. thisExp.timestampOnFlip(win, 'end_text.started')
  1216. # update status
  1217. end_text.status = STARTED
  1218. end_text.setAutoDraw(True)
  1219. # if end_text is active this frame...
  1220. if end_text.status == STARTED:
  1221. # update params
  1222. pass
  1223. # if end_text is stopping this frame...
  1224. if end_text.status == STARTED:
  1225. # is it time to stop? (based on global clock, using actual start)
  1226. if tThisFlipGlobal > end_text.tStartRefresh + 3-frameTolerance:
  1227. # keep track of stop time/frame for later
  1228. end_text.tStop = t # not accounting for scr refresh
  1229. end_text.frameNStop = frameN # exact frame index
  1230. # add timestamp to datafile
  1231. thisExp.timestampOnFlip(win, 'end_text.stopped')
  1232. # update status
  1233. end_text.status = FINISHED
  1234. end_text.setAutoDraw(False)
  1235. # check for quit (typically the Esc key)
  1236. if defaultKeyboard.getKeys(keyList=["escape"]):
  1237. thisExp.status = FINISHED
  1238. if thisExp.status == FINISHED or endExpNow:
  1239. endExperiment(thisExp, inputs=inputs, win=win)
  1240. return
  1241. # check if all components have finished
  1242. if not continueRoutine: # a component has requested a forced-end of Routine
  1243. routineForceEnded = True
  1244. break
  1245. continueRoutine = False # will revert to True if at least one component still running
  1246. for thisComponent in endComponents:
  1247. if hasattr(thisComponent, "status") and thisComponent.status != FINISHED:
  1248. continueRoutine = True
  1249. break # at least one component has not yet finished
  1250. # refresh the screen
  1251. if continueRoutine: # don't flip if this routine is over or we'll get a blank screen
  1252. win.flip()
  1253. # --- Ending Routine "end" ---
  1254. for thisComponent in endComponents:
  1255. if hasattr(thisComponent, "setAutoDraw"):
  1256. thisComponent.setAutoDraw(False)
  1257. thisExp.addData('end.stopped', globalClock.getTime())
  1258. # using non-slip timing so subtract the expected duration of this Routine (unless ended on request)
  1259. if routineForceEnded:
  1260. routineTimer.reset()
  1261. else:
  1262. routineTimer.addTime(-3.000000)
  1263. # mark experiment as finished
  1264. endExperiment(thisExp, win=win, inputs=inputs)
  1265. def saveData(thisExp):
  1266. """
  1267. Save data from this experiment
  1268. Parameters
  1269. ==========
  1270. thisExp : psychopy.data.ExperimentHandler
  1271. Handler object for this experiment, contains the data to save and information about
  1272. where to save it to.
  1273. """
  1274. filename = thisExp.dataFileName
  1275. # these shouldn't be strictly necessary (should auto-save)
  1276. thisExp.saveAsWideText(filename + '.csv', delim='auto')
  1277. thisExp.saveAsPickle(filename)
  1278. def endExperiment(thisExp, inputs=None, win=None):
  1279. """
  1280. End this experiment, performing final shut down operations.
  1281. This function does NOT close the window or end the Python process - use `quit` for this.
  1282. Parameters
  1283. ==========
  1284. thisExp : psychopy.data.ExperimentHandler
  1285. Handler object for this experiment, contains the data to save and information about
  1286. where to save it to.
  1287. inputs : dict
  1288. Dictionary of input devices by name.
  1289. win : psychopy.visual.Window
  1290. Window for this experiment.
  1291. """
  1292. if win is not None:
  1293. # remove autodraw from all current components
  1294. win.clearAutoDraw()
  1295. # Flip one final time so any remaining win.callOnFlip()
  1296. # and win.timeOnFlip() tasks get executed
  1297. win.flip()
  1298. # mark experiment handler as finished
  1299. thisExp.status = FINISHED
  1300. # shut down eyetracker, if there is one
  1301. if inputs is not None:
  1302. if 'eyetracker' in inputs and inputs['eyetracker'] is not None:
  1303. inputs['eyetracker'].setConnectionState(False)
  1304. logging.flush()
  1305. def quit(thisExp, win=None, inputs=None, thisSession=None):
  1306. """
  1307. Fully quit, closing the window and ending the Python process.
  1308. Parameters
  1309. ==========
  1310. win : psychopy.visual.Window
  1311. Window to close.
  1312. inputs : dict
  1313. Dictionary of input devices by name.
  1314. thisSession : psychopy.session.Session or None
  1315. Handle of the Session object this experiment is being run from, if any.
  1316. """
  1317. thisExp.abort() # or data files will save again on exit
  1318. # make sure everything is closed down
  1319. if win is not None:
  1320. # Flip one final time so any remaining win.callOnFlip()
  1321. # and win.timeOnFlip() tasks get executed before quitting
  1322. win.flip()
  1323. win.close()
  1324. if inputs is not None:
  1325. if 'eyetracker' in inputs and inputs['eyetracker'] is not None:
  1326. inputs['eyetracker'].setConnectionState(False)
  1327. logging.flush()
  1328. if thisSession is not None:
  1329. thisSession.stop()
  1330. # terminate Python process
  1331. core.quit()
  1332. # if running this experiment as a script...
  1333. if __name__ == '__main__':
  1334. # call all functions in order
  1335. expInfo = showExpInfoDlg(expInfo=expInfo)
  1336. thisExp = setupData(expInfo=expInfo)
  1337. logFile = setupLogging(filename=thisExp.dataFileName)
  1338. win = setupWindow(expInfo=expInfo)
  1339. inputs = setupInputs(expInfo=expInfo, thisExp=thisExp, win=win)
  1340. run(
  1341. expInfo=expInfo,
  1342. thisExp=thisExp,
  1343. win=win,
  1344. inputs=inputs
  1345. )
  1346. saveData(thisExp=thisExp)
  1347. quit(thisExp=thisExp, win=win, inputs=inputs)