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