grasp_data_collection_no_release.py 61 KB

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