2
0

general_grasp_training.py 60 KB

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