grasp_data_collection_no_release.py 61 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496
  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 18:41
  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() < 7.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 >= 1-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 == 119:
  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 + 反应时1s + 新版flex时间4.5s + 0.5s裕量 = 7s。
  690. # flex trigger打出5s(flex图片显示7s)后,hold图片显示。
  691. # if flex_wav is starting this frame...
  692. if flex_wav.status == NOT_STARTED and tThisFlip >= 1.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 >= 1-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(-7.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. # 生成3~10s的随机持续时间
  785. random_duration = random.uniform(3, 10)
  786. thisExp.addData('random_duration', random_duration)
  787. #print(f"Holding duration is {random_duration} seconds.")
  788. hold_wav.setSound('static/audios/hold.wav', secs=2.5, hamming=True)
  789. hold_wav.setVolume(1.0, log=False)
  790. hold_wav.seek(0)
  791. # keep track of which components have finished
  792. holdComponents = [hold_img, hold_wav]
  793. for thisComponent in holdComponents:
  794. thisComponent.tStart = None
  795. thisComponent.tStop = None
  796. thisComponent.tStartRefresh = None
  797. thisComponent.tStopRefresh = None
  798. if hasattr(thisComponent, 'status'):
  799. thisComponent.status = NOT_STARTED
  800. # reset timers
  801. t = 0
  802. _timeToFirstFrame = win.getFutureFlipTime(clock="now")
  803. frameN = -1
  804. # --- Run Routine "hold" ---
  805. routineForceEnded = not continueRoutine
  806. while continueRoutine:
  807. # get current time
  808. t = routineTimer.getTime()
  809. tThisFlip = win.getFutureFlipTime(clock=routineTimer)
  810. tThisFlipGlobal = win.getFutureFlipTime(clock=None)
  811. frameN = frameN + 1 # number of completed frames (so 0 is the first frame)
  812. # update/draw components on each frame
  813. # *hold_img* updates
  814. # if hold_img is starting this frame...
  815. if hold_img.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance:
  816. # keep track of start time/frame for later
  817. hold_img.frameNStart = frameN # exact frame index
  818. hold_img.tStart = t # local t and not account for scr refresh
  819. hold_img.tStartRefresh = tThisFlipGlobal # on global time
  820. win.timeOnFlip(hold_img, 'tStartRefresh') # time at next scr refresh
  821. # add timestamp to datafile
  822. thisExp.timestampOnFlip(win, 'hold_img.started')
  823. # update status
  824. hold_img.status = STARTED
  825. hold_img.setAutoDraw(True)
  826. # if hold_img is active this frame...
  827. if hold_img.status == STARTED:
  828. # update params
  829. pass
  830. # Run 'Each Frame' code from code_3
  831. current_time = t
  832. if current_time < random_duration:
  833. continueRoutine = True
  834. else:
  835. continueRoutine = False
  836. # if hold_wav is starting this frame...
  837. if hold_wav.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance:
  838. # keep track of start time/frame for later
  839. hold_wav.frameNStart = frameN # exact frame index
  840. hold_wav.tStart = t # local t and not account for scr refresh
  841. hold_wav.tStartRefresh = tThisFlipGlobal # on global time
  842. # add timestamp to datafile
  843. thisExp.addData('hold_wav.started', tThisFlipGlobal)
  844. # update status
  845. hold_wav.status = STARTED
  846. hold_wav.play(when=win) # sync with win flip
  847. # if hold_wav is stopping this frame...
  848. if hold_wav.status == STARTED:
  849. # is it time to stop? (based on global clock, using actual start)
  850. if tThisFlipGlobal > hold_wav.tStartRefresh + 2.5-frameTolerance:
  851. # keep track of stop time/frame for later
  852. hold_wav.tStop = t # not accounting for scr refresh
  853. hold_wav.frameNStop = frameN # exact frame index
  854. # add timestamp to datafile
  855. thisExp.timestampOnFlip(win, 'hold_wav.stopped')
  856. # update status
  857. hold_wav.status = FINISHED
  858. hold_wav.stop()
  859. # update hold_wav status according to whether it's playing
  860. if hold_wav.isPlaying:
  861. hold_wav.status = STARTED
  862. elif hold_wav.isFinished:
  863. hold_wav.status = FINISHED
  864. # check for quit (typically the Esc key)
  865. if defaultKeyboard.getKeys(keyList=["escape"]):
  866. thisExp.status = FINISHED
  867. if thisExp.status == FINISHED or endExpNow:
  868. endExperiment(thisExp, inputs=inputs, win=win)
  869. return
  870. # check if all components have finished
  871. if not continueRoutine: # a component has requested a forced-end of Routine
  872. routineForceEnded = True
  873. break
  874. continueRoutine = False # will revert to True if at least one component still running
  875. for thisComponent in holdComponents:
  876. if hasattr(thisComponent, "status") and thisComponent.status != FINISHED:
  877. continueRoutine = True
  878. break # at least one component has not yet finished
  879. # refresh the screen
  880. if continueRoutine: # don't flip if this routine is over or we'll get a blank screen
  881. win.flip()
  882. # --- Ending Routine "hold" ---
  883. for thisComponent in holdComponents:
  884. if hasattr(thisComponent, "setAutoDraw"):
  885. thisComponent.setAutoDraw(False)
  886. thisExp.addData('hold.stopped', globalClock.getTime())
  887. hold_wav.pause() # ensure sound has stopped at end of Routine
  888. # the Routine "hold" was not non-slip safe, so reset the non-slip timer
  889. routineTimer.reset()
  890. # --- Prepare to start Routine "extend" ---
  891. continueRoutine = True
  892. # update component parameters for each repeat
  893. thisExp.addData('extend.started', globalClock.getTime())
  894. # Run 'Begin Routine' code from code
  895. i = 0
  896. extend_wav.setSound('static/audios/extend.wav', secs=2, hamming=True)
  897. extend_wav.setVolume(1.0, log=False)
  898. extend_wav.seek(0)
  899. # keep track of which components have finished
  900. extendComponents = [extend_img, extend_wav]
  901. for thisComponent in extendComponents:
  902. thisComponent.tStart = None
  903. thisComponent.tStop = None
  904. thisComponent.tStartRefresh = None
  905. thisComponent.tStopRefresh = None
  906. if hasattr(thisComponent, 'status'):
  907. thisComponent.status = NOT_STARTED
  908. # reset timers
  909. t = 0
  910. _timeToFirstFrame = win.getFutureFlipTime(clock="now")
  911. frameN = -1
  912. # --- Run Routine "extend" ---
  913. routineForceEnded = not continueRoutine
  914. while continueRoutine and routineTimer.getTime() < 6.0:
  915. # get current time
  916. t = routineTimer.getTime()
  917. tThisFlip = win.getFutureFlipTime(clock=routineTimer)
  918. tThisFlipGlobal = win.getFutureFlipTime(clock=None)
  919. frameN = frameN + 1 # number of completed frames (so 0 is the first frame)
  920. # update/draw components on each frame
  921. # *extend_img* updates
  922. # if extend_img is starting this frame...
  923. if extend_img.status == NOT_STARTED and tThisFlip >= 0-frameTolerance:
  924. # keep track of start time/frame for later
  925. extend_img.frameNStart = frameN # exact frame index
  926. extend_img.tStart = t # local t and not account for scr refresh
  927. extend_img.tStartRefresh = tThisFlipGlobal # on global time
  928. win.timeOnFlip(extend_img, 'tStartRefresh') # time at next scr refresh
  929. # add timestamp to datafile
  930. thisExp.timestampOnFlip(win, 'extend_img.started')
  931. # update status
  932. extend_img.status = STARTED
  933. extend_img.setAutoDraw(True)
  934. # if extend_img is active this frame...
  935. if extend_img.status == STARTED:
  936. # update params
  937. pass
  938. # if extend_img is stopping this frame...
  939. if extend_img.status == STARTED:
  940. # is it time to stop? (based on global clock, using actual start)
  941. if tThisFlipGlobal > extend_img.tStartRefresh + 6-frameTolerance:
  942. # keep track of stop time/frame for later
  943. extend_img.tStop = t # not accounting for scr refresh
  944. extend_img.frameNStop = frameN # exact frame index
  945. # add timestamp to datafile
  946. thisExp.timestampOnFlip(win, 'extend_img.stopped')
  947. # update status
  948. extend_img.status = FINISHED
  949. extend_img.setAutoDraw(False)
  950. # Run 'Each Frame' code from code
  951. if i== 59:
  952. hand_device.start('extend')
  953. # send trigger
  954. current_true_label = settings.FINGERMODEL_IDS['extend']
  955. win.callOnFlip(trigger.send_trigger, current_true_label)
  956. i += 1
  957. # 反应时1s + 新版extend时间4.5s + 0.5s裕量 = 6s
  958. # extend 图片出现后6s,extend trigger后5s,rest图片出现
  959. # if extend_wav is starting this frame...
  960. if extend_wav.status == NOT_STARTED and tThisFlip >= 0-frameTolerance:
  961. # keep track of start time/frame for later
  962. extend_wav.frameNStart = frameN # exact frame index
  963. extend_wav.tStart = t # local t and not account for scr refresh
  964. extend_wav.tStartRefresh = tThisFlipGlobal # on global time
  965. # add timestamp to datafile
  966. thisExp.addData('extend_wav.started', tThisFlipGlobal)
  967. # update status
  968. extend_wav.status = STARTED
  969. extend_wav.play(when=win) # sync with win flip
  970. # if extend_wav is stopping this frame...
  971. if extend_wav.status == STARTED:
  972. # is it time to stop? (based on global clock, using actual start)
  973. if tThisFlipGlobal > extend_wav.tStartRefresh + 2-frameTolerance:
  974. # keep track of stop time/frame for later
  975. extend_wav.tStop = t # not accounting for scr refresh
  976. extend_wav.frameNStop = frameN # exact frame index
  977. # add timestamp to datafile
  978. thisExp.timestampOnFlip(win, 'extend_wav.stopped')
  979. # update status
  980. extend_wav.status = FINISHED
  981. extend_wav.stop()
  982. # update extend_wav status according to whether it's playing
  983. if extend_wav.isPlaying:
  984. extend_wav.status = STARTED
  985. elif extend_wav.isFinished:
  986. extend_wav.status = FINISHED
  987. # check for quit (typically the Esc key)
  988. if defaultKeyboard.getKeys(keyList=["escape"]):
  989. thisExp.status = FINISHED
  990. if thisExp.status == FINISHED or endExpNow:
  991. endExperiment(thisExp, inputs=inputs, win=win)
  992. return
  993. # check if all components have finished
  994. if not continueRoutine: # a component has requested a forced-end of Routine
  995. routineForceEnded = True
  996. break
  997. continueRoutine = False # will revert to True if at least one component still running
  998. for thisComponent in extendComponents:
  999. if hasattr(thisComponent, "status") and thisComponent.status != FINISHED:
  1000. continueRoutine = True
  1001. break # at least one component has not yet finished
  1002. # refresh the screen
  1003. if continueRoutine: # don't flip if this routine is over or we'll get a blank screen
  1004. win.flip()
  1005. # --- Ending Routine "extend" ---
  1006. for thisComponent in extendComponents:
  1007. if hasattr(thisComponent, "setAutoDraw"):
  1008. thisComponent.setAutoDraw(False)
  1009. thisExp.addData('extend.stopped', globalClock.getTime())
  1010. extend_wav.pause() # ensure sound has stopped at end of Routine
  1011. # using non-slip timing so subtract the expected duration of this Routine (unless ended on request)
  1012. if routineForceEnded:
  1013. routineTimer.reset()
  1014. else:
  1015. routineTimer.addTime(-6.000000)
  1016. # --- Prepare to start Routine "rest" ---
  1017. continueRoutine = True
  1018. # update component parameters for each repeat
  1019. thisExp.addData('rest.started', globalClock.getTime())
  1020. # Run 'Begin Routine' code from code_4
  1021. i = 0
  1022. rest_wav1.setSound('static/audios/rest.wav', secs=2, hamming=True)
  1023. rest_wav1.setVolume(1.0, log=False)
  1024. rest_wav1.seek(0)
  1025. # keep track of which components have finished
  1026. restComponents = [rest_img, rest_wav1]
  1027. for thisComponent in restComponents:
  1028. thisComponent.tStart = None
  1029. thisComponent.tStop = None
  1030. thisComponent.tStartRefresh = None
  1031. thisComponent.tStopRefresh = None
  1032. if hasattr(thisComponent, 'status'):
  1033. thisComponent.status = NOT_STARTED
  1034. # reset timers
  1035. t = 0
  1036. _timeToFirstFrame = win.getFutureFlipTime(clock="now")
  1037. frameN = -1
  1038. # --- Run Routine "rest" ---
  1039. routineForceEnded = not continueRoutine
  1040. while continueRoutine and routineTimer.getTime() < 6.0:
  1041. # get current time
  1042. t = routineTimer.getTime()
  1043. tThisFlip = win.getFutureFlipTime(clock=routineTimer)
  1044. tThisFlipGlobal = win.getFutureFlipTime(clock=None)
  1045. frameN = frameN + 1 # number of completed frames (so 0 is the first frame)
  1046. # update/draw components on each frame
  1047. # *rest_img* updates
  1048. # if rest_img is starting this frame...
  1049. if rest_img.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance:
  1050. # keep track of start time/frame for later
  1051. rest_img.frameNStart = frameN # exact frame index
  1052. rest_img.tStart = t # local t and not account for scr refresh
  1053. rest_img.tStartRefresh = tThisFlipGlobal # on global time
  1054. win.timeOnFlip(rest_img, 'tStartRefresh') # time at next scr refresh
  1055. # add timestamp to datafile
  1056. thisExp.timestampOnFlip(win, 'rest_img.started')
  1057. # update status
  1058. rest_img.status = STARTED
  1059. rest_img.setAutoDraw(True)
  1060. # if rest_img is active this frame...
  1061. if rest_img.status == STARTED:
  1062. # update params
  1063. pass
  1064. # if rest_img is stopping this frame...
  1065. if rest_img.status == STARTED:
  1066. # is it time to stop? (based on global clock, using actual start)
  1067. if tThisFlipGlobal > rest_img.tStartRefresh + 6-frameTolerance:
  1068. # keep track of stop time/frame for later
  1069. rest_img.tStop = t # not accounting for scr refresh
  1070. rest_img.frameNStop = frameN # exact frame index
  1071. # add timestamp to datafile
  1072. thisExp.timestampOnFlip(win, 'rest_img.stopped')
  1073. # update status
  1074. rest_img.status = FINISHED
  1075. rest_img.setAutoDraw(False)
  1076. # Run 'Each Frame' code from code_4
  1077. if i== 59:
  1078. # hand_device.start('rest')
  1079. # trigger
  1080. win.callOnFlip(trigger.send_trigger, settings.FINGERMODEL_IDS['rest'])
  1081. i += 1
  1082. # if rest_wav1 is starting this frame...
  1083. if rest_wav1.status == NOT_STARTED and tThisFlip >= 0-frameTolerance:
  1084. # keep track of start time/frame for later
  1085. rest_wav1.frameNStart = frameN # exact frame index
  1086. rest_wav1.tStart = t # local t and not account for scr refresh
  1087. rest_wav1.tStartRefresh = tThisFlipGlobal # on global time
  1088. # add timestamp to datafile
  1089. thisExp.addData('rest_wav1.started', tThisFlipGlobal)
  1090. # update status
  1091. rest_wav1.status = STARTED
  1092. rest_wav1.play(when=win) # sync with win flip
  1093. # if rest_wav1 is stopping this frame...
  1094. if rest_wav1.status == STARTED:
  1095. # is it time to stop? (based on global clock, using actual start)
  1096. if tThisFlipGlobal > rest_wav1.tStartRefresh + 2-frameTolerance:
  1097. # keep track of stop time/frame for later
  1098. rest_wav1.tStop = t # not accounting for scr refresh
  1099. rest_wav1.frameNStop = frameN # exact frame index
  1100. # add timestamp to datafile
  1101. thisExp.timestampOnFlip(win, 'rest_wav1.stopped')
  1102. # update status
  1103. rest_wav1.status = FINISHED
  1104. rest_wav1.stop()
  1105. # update rest_wav1 status according to whether it's playing
  1106. if rest_wav1.isPlaying:
  1107. rest_wav1.status = STARTED
  1108. elif rest_wav1.isFinished:
  1109. rest_wav1.status = FINISHED
  1110. # check for quit (typically the Esc key)
  1111. if defaultKeyboard.getKeys(keyList=["escape"]):
  1112. thisExp.status = FINISHED
  1113. if thisExp.status == FINISHED or endExpNow:
  1114. endExperiment(thisExp, inputs=inputs, win=win)
  1115. return
  1116. # check if all components have finished
  1117. if not continueRoutine: # a component has requested a forced-end of Routine
  1118. routineForceEnded = True
  1119. break
  1120. continueRoutine = False # will revert to True if at least one component still running
  1121. for thisComponent in restComponents:
  1122. if hasattr(thisComponent, "status") and thisComponent.status != FINISHED:
  1123. continueRoutine = True
  1124. break # at least one component has not yet finished
  1125. # refresh the screen
  1126. if continueRoutine: # don't flip if this routine is over or we'll get a blank screen
  1127. win.flip()
  1128. # --- Ending Routine "rest" ---
  1129. for thisComponent in restComponents:
  1130. if hasattr(thisComponent, "setAutoDraw"):
  1131. thisComponent.setAutoDraw(False)
  1132. thisExp.addData('rest.stopped', globalClock.getTime())
  1133. rest_wav1.pause() # ensure sound has stopped at end of Routine
  1134. # using non-slip timing so subtract the expected duration of this Routine (unless ended on request)
  1135. if routineForceEnded:
  1136. routineTimer.reset()
  1137. else:
  1138. routineTimer.addTime(-6.000000)
  1139. thisExp.nextEntry()
  1140. if thisSession is not None:
  1141. # if running in a Session with a Liaison client, send data up to now
  1142. thisSession.sendExperimentData()
  1143. # completed args.n_trials repeats of 'trials'
  1144. # --- Prepare to start Routine "end" ---
  1145. continueRoutine = True
  1146. # update component parameters for each repeat
  1147. thisExp.addData('end.started', globalClock.getTime())
  1148. # keep track of which components have finished
  1149. endComponents = [end_text]
  1150. for thisComponent in endComponents:
  1151. thisComponent.tStart = None
  1152. thisComponent.tStop = None
  1153. thisComponent.tStartRefresh = None
  1154. thisComponent.tStopRefresh = None
  1155. if hasattr(thisComponent, 'status'):
  1156. thisComponent.status = NOT_STARTED
  1157. # reset timers
  1158. t = 0
  1159. _timeToFirstFrame = win.getFutureFlipTime(clock="now")
  1160. frameN = -1
  1161. # --- Run Routine "end" ---
  1162. routineForceEnded = not continueRoutine
  1163. while continueRoutine and routineTimer.getTime() < 3.0:
  1164. # get current time
  1165. t = routineTimer.getTime()
  1166. tThisFlip = win.getFutureFlipTime(clock=routineTimer)
  1167. tThisFlipGlobal = win.getFutureFlipTime(clock=None)
  1168. frameN = frameN + 1 # number of completed frames (so 0 is the first frame)
  1169. # update/draw components on each frame
  1170. # *end_text* updates
  1171. # if end_text is starting this frame...
  1172. if end_text.status == NOT_STARTED and tThisFlip >= 0.0-frameTolerance:
  1173. # keep track of start time/frame for later
  1174. end_text.frameNStart = frameN # exact frame index
  1175. end_text.tStart = t # local t and not account for scr refresh
  1176. end_text.tStartRefresh = tThisFlipGlobal # on global time
  1177. win.timeOnFlip(end_text, 'tStartRefresh') # time at next scr refresh
  1178. # add timestamp to datafile
  1179. thisExp.timestampOnFlip(win, 'end_text.started')
  1180. # update status
  1181. end_text.status = STARTED
  1182. end_text.setAutoDraw(True)
  1183. # if end_text is active this frame...
  1184. if end_text.status == STARTED:
  1185. # update params
  1186. pass
  1187. # if end_text is stopping this frame...
  1188. if end_text.status == STARTED:
  1189. # is it time to stop? (based on global clock, using actual start)
  1190. if tThisFlipGlobal > end_text.tStartRefresh + 3-frameTolerance:
  1191. # keep track of stop time/frame for later
  1192. end_text.tStop = t # not accounting for scr refresh
  1193. end_text.frameNStop = frameN # exact frame index
  1194. # add timestamp to datafile
  1195. thisExp.timestampOnFlip(win, 'end_text.stopped')
  1196. # update status
  1197. end_text.status = FINISHED
  1198. end_text.setAutoDraw(False)
  1199. # check for quit (typically the Esc key)
  1200. if defaultKeyboard.getKeys(keyList=["escape"]):
  1201. thisExp.status = FINISHED
  1202. if thisExp.status == FINISHED or endExpNow:
  1203. endExperiment(thisExp, inputs=inputs, win=win)
  1204. return
  1205. # check if all components have finished
  1206. if not continueRoutine: # a component has requested a forced-end of Routine
  1207. routineForceEnded = True
  1208. break
  1209. continueRoutine = False # will revert to True if at least one component still running
  1210. for thisComponent in endComponents:
  1211. if hasattr(thisComponent, "status") and thisComponent.status != FINISHED:
  1212. continueRoutine = True
  1213. break # at least one component has not yet finished
  1214. # refresh the screen
  1215. if continueRoutine: # don't flip if this routine is over or we'll get a blank screen
  1216. win.flip()
  1217. # --- Ending Routine "end" ---
  1218. for thisComponent in endComponents:
  1219. if hasattr(thisComponent, "setAutoDraw"):
  1220. thisComponent.setAutoDraw(False)
  1221. thisExp.addData('end.stopped', globalClock.getTime())
  1222. # using non-slip timing so subtract the expected duration of this Routine (unless ended on request)
  1223. if routineForceEnded:
  1224. routineTimer.reset()
  1225. else:
  1226. routineTimer.addTime(-3.000000)
  1227. # mark experiment as finished
  1228. endExperiment(thisExp, win=win, inputs=inputs)
  1229. def saveData(thisExp):
  1230. """
  1231. Save data from this experiment
  1232. Parameters
  1233. ==========
  1234. thisExp : psychopy.data.ExperimentHandler
  1235. Handler object for this experiment, contains the data to save and information about
  1236. where to save it to.
  1237. """
  1238. filename = thisExp.dataFileName
  1239. # these shouldn't be strictly necessary (should auto-save)
  1240. thisExp.saveAsWideText(filename + '.csv', delim='auto')
  1241. thisExp.saveAsPickle(filename)
  1242. def endExperiment(thisExp, inputs=None, win=None):
  1243. """
  1244. End this experiment, performing final shut down operations.
  1245. This function does NOT close the window or end the Python process - use `quit` for this.
  1246. Parameters
  1247. ==========
  1248. thisExp : psychopy.data.ExperimentHandler
  1249. Handler object for this experiment, contains the data to save and information about
  1250. where to save it to.
  1251. inputs : dict
  1252. Dictionary of input devices by name.
  1253. win : psychopy.visual.Window
  1254. Window for this experiment.
  1255. """
  1256. if win is not None:
  1257. # remove autodraw from all current components
  1258. win.clearAutoDraw()
  1259. # Flip one final time so any remaining win.callOnFlip()
  1260. # and win.timeOnFlip() tasks get executed
  1261. win.flip()
  1262. # mark experiment handler as finished
  1263. thisExp.status = FINISHED
  1264. # shut down eyetracker, if there is one
  1265. if inputs is not None:
  1266. if 'eyetracker' in inputs and inputs['eyetracker'] is not None:
  1267. inputs['eyetracker'].setConnectionState(False)
  1268. logging.flush()
  1269. def quit(thisExp, win=None, inputs=None, thisSession=None):
  1270. """
  1271. Fully quit, closing the window and ending the Python process.
  1272. Parameters
  1273. ==========
  1274. win : psychopy.visual.Window
  1275. Window to close.
  1276. inputs : dict
  1277. Dictionary of input devices by name.
  1278. thisSession : psychopy.session.Session or None
  1279. Handle of the Session object this experiment is being run from, if any.
  1280. """
  1281. thisExp.abort() # or data files will save again on exit
  1282. # make sure everything is closed down
  1283. if win is not None:
  1284. # Flip one final time so any remaining win.callOnFlip()
  1285. # and win.timeOnFlip() tasks get executed before quitting
  1286. win.flip()
  1287. win.close()
  1288. if inputs is not None:
  1289. if 'eyetracker' in inputs and inputs['eyetracker'] is not None:
  1290. inputs['eyetracker'].setConnectionState(False)
  1291. logging.flush()
  1292. if thisSession is not None:
  1293. thisSession.stop()
  1294. # terminate Python process
  1295. core.quit()
  1296. # if running this experiment as a script...
  1297. if __name__ == '__main__':
  1298. # call all functions in order
  1299. expInfo = showExpInfoDlg(expInfo=expInfo)
  1300. thisExp = setupData(expInfo=expInfo)
  1301. logFile = setupLogging(filename=thisExp.dataFileName)
  1302. win = setupWindow(expInfo=expInfo)
  1303. inputs = setupInputs(expInfo=expInfo, thisExp=thisExp, win=win)
  1304. run(
  1305. expInfo=expInfo,
  1306. thisExp=thisExp,
  1307. win=win,
  1308. inputs=inputs
  1309. )
  1310. saveData(thisExp=thisExp)
  1311. quit(thisExp=thisExp, win=win, inputs=inputs)