Stimulus timing issue when eye tracker is connected

Hello!

I’ve run into an issue with stimulus timing while recording data from an eyelink eye tracker via iohub. Namely, when we collect eye tracking data for a reward learning task, some of the components of the task are presented for either too much or not enough time (or there’s no change). There are no issues when the same code is run without eye tracking.

Following are the observed deviations:
Main stimulus: ~.5 seconds shorter
ISI: ~1.0 seconds shorter
Feedback image: No change
ITI: ~1.5 seconds longer

I troubleshooted the code by commenting out the various eye tracking-related chunks (e.g. code that sends messages to eyewink, code that saves output in case of a quit, code that starts calibration, etc.), and it seems like the only thing that makes a difference is having the eye tracker record continuously. When we do not set the recording state on and off at the beginning/end of each trial, the timing is fine, but we then lose the ability to easily demarcate trials in the EDF.

I’m wondering if anyone might know what’s going on in the code that would so drastically and differentially affect the timing of the various trial components. The basic structure of each trial is: (recording on) stimulus presentation --> ISI --> feedback (recording off)–> ITI, Below is the code I’m using to turn the recording state on and off:

# start recording

# ------Prepare to start Routine "trial"-------
t = 0
trialClock.reset()  # clock
frameN = -1
continueRoutine = True
routineTimer.add(1.000000+ISI)
# update component parameters for each repeat
face_img.setImage(ImageName)
key_resp_trial = event.BuilderKeyResponse()
# keep track of which components have finished
trialComponents = [face_img, txtAccept, txtReject, key_resp_trial, fixation_ISI]
for thisComponent in trialComponents:
    if hasattr(thisComponent, 'status'):
        thisComponent.status = NOT_STARTED       
if eyetracker:
    heldFixation = True #unless otherwise
    io.clearEvents('all')
    eyetracker.setRecordingState(True)
    io.sendMessageEvent(text="tStart %i" %(trialsLoop.thisN))
    tracker.sendMessage("tStart %i" %(trialsLoop.thisN))
        
# stop recording

# -------Ending Routine "feedback"-------
for thisComponent in feedbackComponents:
    if hasattr(thisComponent, "setAutoDraw"):
        thisComponent.setAutoDraw(False)
    if eyetracker:
        eyetracker.setRecordingState(False)
        io.sendMessageEvent(text="tEnd %i" %(trialsLoop.thisN))
        tracker.sendMessage("tEnd %i" %(trialsLoop.thisN))
        trialsLoop.addData("heldFixation",heldFixation)
        trialsLoop.addData("position",gpos)

As far as I know, this is the default code to alternate between recording states, and I have no idea why that would mess with some (but not all) of the trial components times. Does anyone know what might be going on here? I’d be happy to provide more code from the experiment if that would help.

Thanks so much!

Hi David,

I think you have some more work to do in order to see where the timing errors occur. Basically you need to be logging times on some clock before and after each event to see where the timing occurs. If there is a problem with dropping frames, which could accumulateover time, you need to detect that too. This will help you see where “slop” occurs. For example, at the moment you reset the trial timer and the frame counter before a call to face_img.setImage(ImageName) That in itself can take more than one screen refresh, and so can be throwing out timing (regardless of using the eye tracker).

Obsessive time logging should help narrow down where any issues might be arising.

Hi @Michael

I am using PsychoPy 2021.2.3 for Windows 10. Experiment is created using Builder. There was no error, however, when eye-tracker is connected, that resulting in delay of the inter- trial interval, or even after the response button is pressed, the presentation is still going on for a while, and finally, order seems to be messed up, after the response of the participant, the fixation cross show up again for very short, so I guess it is related with timing. Without eye-tracking works fine! Could be a bug related with eye-tracking component in Builder? Thank you very much in advance.

Could you provide a minimal working project that shows the issue you are having? Which eye tracker where you using, the default MouseGaze simulator?
Thank you

Dear Sol,

Thank you very much for prompt reply. I am using eye-tracking device 'Eye-link 1000. Today, I found that if MouseGaze is in use, it is working correctly, no time issue, however, when I use real eye-tracking with the EyeLink, that somehow results in timing issues. For instance, I have a fixation dot (start 0, stop at 2000ms), next, the search-display (start at 500ms, stop 2000ms), and response component (start at 500, stop at 3000ms), and we have one more routine afterwards (start 0, stop at 500ms). Using eye tracking results in two particular problems, first, after I press a key response, only search display disappear, but wrongly, fixation cross stay at the screen for a while (I think around half a second), second of below that, and second problem, at some trials after I press response key, nothing happens, so I have to press again. Please find attached psyexp file and below that a few line from the log file.

71.1660 EXP dot: autoDraw = True
71.1742 EXP posit1: autoDraw = True
71.1742 EXP posit2: autoDraw = True
71.1742 EXP posit3: autoDraw = True
71.1742 EXP posit4: autoDraw = True
71.1742 EXP posit5: autoDraw = True
71.1742 EXP posit6: autoDraw = True
71.1742 EXP posit7: autoDraw = True
71.1742 EXP posit8: autoDraw = True
71.5284 DATA Keypress: j
73.1737 EXP posit1: autoDraw = False
73.1737 EXP posit2: autoDraw = False
73.1737 EXP posit3: autoDraw = False
73.1737 EXP posit4: autoDraw = False
73.1737 EXP posit5: autoDraw = False
73.1737 EXP posit6: autoDraw = False
73.1737 EXP posit7: autoDraw = False
73.1737 EXP posit8: autoDraw = False
73.6737 EXP dot: autoDraw = False
75.1730 EXP dot: autoDraw = False
75.1730 EXP posit1: autoDraw = False
75.1730 EXP posit2: autoDraw = False
75.1730 EXP posit3: autoDraw = False
75.1730 EXP posit4: autoDraw = False
75.1730 EXP posit5: autoDraw = False
75.1730 EXP posit6: autoDraw = False
75.1730 EXP posit7: autoDraw = False
75.1730 EXP posit8: autoDraw = False
75.1730 EXP text_6: autoDraw = True
76.0746 EXP New trial (rep=0, index=5): {‘ring1’: ‘c_red_ver.png’, ‘ring2’: ‘c_hor.png’, ‘ring3’: ‘c_ver.png’, ‘ring4’: ‘c_hor.png’, ‘ring5’: ‘r_ver.png’, ‘ring6’: ‘c_hor.png’, ‘ring7’: ‘r_ver.png’, ‘ring8’: ‘c_ver.png’, ‘corrAns’: ‘j’, ‘congruency’: ‘vertical’, ‘dist_status’: ‘present’, ‘targ_position’: ‘CL’, ‘swapping’: ‘romb’}
77.6753 EXP text_6: autoDraw = False

It sounds like you may have found some issue with the eye tracker Builder integration, but we can not reproduce with just the .pyexp file. Could you send a full project that we can run to try and debug? The simplier the project/experiment, the easier it will be to figure out what is going on. :wink:

Thanks again

Hi Sol,

do you have any email, here is not possible to upload. Thanks

Thank you for emailing the experiment. I will look at it in the next couple days and email you with any questions. Thanks again

Dear David, dear Sol,

I am currently facing timing issues with the Builder x EyeLink 1000 integration as well. I was wondering whether you have figured out any solution for this issue?

Any help is highly appreciated.

Thank you and all the best

Celina