general_grasp_training.py 60 KB

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