Pygaze wait_for_saccade_end with timeout?
Hi all,
I was wondering if it is possible to use the wait_for_saccade_end() function with a timeout. Specifically, we are using an Eyelink and would like to wait for completed saccade OR until 2000 ms have passed.
Since wait_for_saccade_end() essentially block the scripts until a saccade has been made, we're having trouble implementing the later.
While I think it should be possible to adapt the pygaze version of the saccade detection to add a timeout parameter, the 'native' functionality that is called for Eyelink seems a lot harder to adapt.
So I was hoping someone else has tackled this problem before.
One workaround I am currently considering / testing, but seems quite crude is to run wait_for_saccade_end() in a new thread using the threading module, and adding a trace so the thread can be killed if needed (https://www.geeksforgeeks.org/python-different-ways-to-kill-a-thread/)
Kind regards,
Kerwin
Comments
Hi @kolfers ,
I would adapt the the
wait_for_event()function from PyGaze to break after a timeout.I blind-coded the example below (I don't have an eye tracker now to test) but it should convey the general idea of how wait for a saccade using the EyeLink's native event detection with a timeout. This script should simply go into an
inline_scriptitem.import pylink t0 = clock.get_time() saccade = False timeout = 2000 for ms in clock.loop_for(timeout): d = pylink.getEYELINK().getNextData() if d == pylink.STARTSACC: float_data = pylink.getEYELINK().getFloatData() tc = float_data.getTime() - eyetracker._get_eyelink_clock_async() if tc > t0: saccade = True breakOne workaround I am currently considering / testing, but seems quite crude is to run wait_for_saccade_end() in a new thread using the threading module, and adding a trace so the thread can be killed if needed
Threading is generally not a good idea for things like this because the timing is quite unreliable, and it's also easy to create race conditions that unpredictably make your experiment crash!
— Sebastiaan
Check out SigmundAI.eu for our OpenSesame AI assistant!
Hi Sebastiaan,
Thank you, that approach did the trick. I couldn't get the clock.loop_for to work though. Perhaps because of the imported clock from pygaze.libtime? In case someone else finds it useful in the future:
def wait_for_event_timeout(self, event, timeout): """See pygaze._eyetracker.baseeyetracker.BaseEyeTracker""" if not self.recording: raise Exception( "Error in libeyelink.libeyelink.wait_for_event(): Recording " "was not started before collecting eyelink data!") start_time = clock.get_time() check_time = False if isinstance(timeout,int) and timeout > 0: check_time = True end_time = start_time + timeout else: raise Exception("timeout (in ms) should be an integer larger than 0") if self.eye_used == None: self.set_eye_used() if self.eventdetection == 'native': # since the link buffer was not have been polled, old data has # accumulated in the buffer -- so ignore events that are old: t0 = clock.get_time() # time of call while True: if check_time and clock.get_time() >= end_time: return "timeout", clock.get_time d = pylink.getEYELINK().getNextData() if d == event: float_data = pylink.getEYELINK().getFloatData() # corresponding clock_time tc = float_data.getTime() - self._get_eyelink_clock_async() if tc > t0: return tc, float_data def wait_for_saccade_start_timeout(self,timeout=None): """See pygaze._eyetracker.baseeyetracker.BaseEyeTracker""" # # # # # # EyeLink method if self.eventdetection == 'native': t,d = self.wait_for_event_timeout(pylink.STARTSACC, timeout) if t == "timeout": return t, None return t, d.getStartGaze() def wait_for_saccade_end_timeout(self,timeout=None): """See pygaze._eyetracker.baseeyetracker.BaseEyeTracker""" # # # # # # EyeLink method if self.eventdetection == 'native': t,d = self.wait_for_event_timeout(pylink.ENDSACC,timeout) if t == "timeout": return t, None,None return t, d.getStartGaze(), d.getEndGaze()