general_grasp_training.py 59 KB

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