1
0

general_grasp_training.py 59 KB

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