general_grasp_training.py 59 KB

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