def __init__(self, win, filename="TEST.EDF"): self.win = win EyeLink.__init__(self) self._filename = filename self.openDataFile(filename) #EyeLinkCustomDisplay.__init__(self) self._surfs = pygame.display.get_surface() pylink.flushGetkeyQueue() col = 128 pylink.setCalibrationColors( (0, 0, 0), (col, col, col)) #Sets the calibration target and background color self.sendCommand("screen_pixel_coords = 0 0 %d %d" % (self._surfs.get_width(), self._surfs.get_height())) self.sendMessage("DISPLAY_COORDS 0 0 %d %d" % (self._surfs.get_width(), self._surfs.get_height())) self.sendCommand("select_parser_configuration 0") self.setFileEventFilter( "LEFT,RIGHT,FIXATION,SACCADE,BLINK,MESSAGE,BUTTON") self.setFileSampleFilter("LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS") self.setLinkEventFilter("LEFT,RIGHT,FIXATION,SACCADE,BLINK,BUTTON") self.setLinkSampleFilter("LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS") self.sendCommand("button_function 5 'accept_target_fixation'") self.inner = visual.PatchStim(win, tex=None, mask='circle', units='pix', size=5, color=win.color) self.outer = visual.PatchStim(win, tex=None, mask='circle', units='pix', size=20, color=[128, 128, 128])
def __init__(self, display, filename="TEST.EDF"): EyeLink.__init__(self) self._disp = display self._filename = filename self.openDataFile(filename) self._surfs = [0,0,1920,1080]#self._disp.get_rect() pylink.flushGetkeyQueue() col = 128 print "1" pylink.setCalibrationColors((0, 0, 0), (col, col, col)) #Sets the calibration target and background color print int(self._surfs[3]/300) # pylink.setTargetSize(int(self._surfs[2]/70), int(self._surfs[3]/300)) #select best size for calibration target print "12" pylink.setCalibrationSounds("off", "off", "off") pylink.setDriftCorrectSounds("off", "off", "off") self.sendCommand("screen_pixel_coords = 0 0 %d %d" % (self._surfs[2], self._surfs[3])) self.sendMessage("DISPLAY_COORDS 0 0 %d %d" % (self._surfs[2], self._surfs[3])) #self.sendMessage("heuristic_filter" % (self._surfs[2], self._surfs[3])) #assert self.getTrackerVersion() == 2 self.sendCommand("select_parser_configuration 0") self.setFileEventFilter("LEFT,RIGHT,FIXATION,SACCADE,BLINK,MESSAGE,BUTTON") self.setFileSampleFilter("LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS") self.setLinkEventFilter("LEFT,RIGHT,FIXATION,SACCADE,BLINK,BUTTON") self.setLinkSampleFilter("LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS") print "2" self.sendCommand("button_function 5 'accept_target_fixation'")
def __init__(self, subjID, dataDir): self._init_graphics() self._init_datafiles(subjID, dataDir) self._init_tracker() self._init_calibration() pylink.flushGetkeyQueue() self.tracker.setOfflineMode() self.tracker.openDataFile(self.trackerDatafile)
def setup_eyelink(self): '''Thank you very much ''' # call for eyelink self.eyelink_tracker = pl.EyeLink("100.1.1.1") #parameters for eyelink self.monitor = monitors.Monitor('testMonitor') self.winSize = self.monitor.getSizePix() self.foreground = (250,250,250) self.background = (127,127,127) # create file self.edfFileName = "cbConfig" + str(self.subjectID) if len(self.edfFileName) > 8: self.edfFileName = self.edfFileName[0:8] pl.getEYELINK().openDataFile(self.edfFileName) pl.getEYELINK().setOfflineMode() #Eyelink - Gets the display surface and sends a mesage to EDF file; pl.getEYELINK().sendCommand("screen_pixel_coords = 0 0 %d %d"%(self.winSize[0]-1, self.winSize[1]-1)) pl.getEYELINK().sendMessage("Resolution %d %d" %((self.winSize[0]-1, self.winSize[1]-1))) pl.getEYELINK().sendMessage("EyeToScreen %d" %(self.monitor.getDistance())) pl.getEYELINK().sendMessage("MonitorWidth %d" %(self.monitor.getWidth())) #EyeLink - Set data file contents pl.getEYELINK().sendCommand("file_sample_data = LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS,HTARGET,INPUT") pl.getEYELINK().sendCommand("link_sample_data = LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS,HTARGET,INPUT") #EyeLink - Set Filter contents pl.getEYELINK().sendCommand("file_event_filter = LEFT,RIGHT,FIXATION,SACCADE,BLINK,MESSAGE,BUTTON,INPUT") pl.getEYELINK().sendCommand("link_event_filter = LEFT,RIGHT,FIXATION,SACCADE,BLINK,BUTTON,INPUT") #EyeLink - Set Calibration Environment pl.setCalibrationColors(self.foreground, self.background); #Sets the calibration target and background color - background color should match testing background pl.flushGetkeyQueue() pl.getEYELINK().setOfflineMode() winX = int(self.winSize[0]) winY = int(self.winSize[1]) pl.openGraphics((winX,winY),32) pl.getEYELINK().doTrackerSetup() pl.closeGraphics() pl.setCalibrationSounds("", "", ""); pl.setDriftCorrectSounds("", "off", "off"); # close configuration file event.clearEvents() pl.getEYELINK().closeDataFile() transferFileName = self.edfFileName + '.edf' # fileName pl.getEYELINK().receiveDataFile(self.edfFileName, transferFileName)
def __init__(self, window, edfname): # Pull out monitor info self.sres = window.size self.scenter = [self.sres[0] / 2.0, self.sres[1] / 2.0] self.win = window # Make filename fname = os.path.splitext(edfname)[0] # strip away extension if present assert re.match(r'\w+$', fname), 'Name must only include A-Z, 0-9, or _' assert len(fname) <= 8, 'Name must be <= 8 characters.' self.edfname = fname + '.edf' # Initialize connection with eyetracker try: self.tracker = pylink.EyeLink() self.realconnect = True except RuntimeError: self.tracker = pylink.EyeLink(None) self.realconnect = False # Check which eye is being recorded self.eye_used = self.tracker.eyeAvailable() # Make pylink accessible self.pylink = pylink # Open EDF self.tracker.openDataFile(self.edfname) pylink.flushGetkeyQueue() self.tracker.setOfflineMode() # Set content of edf file self.tracker.sendCommand( 'file_event_filter = LEFT,RIGHT,FIXATION,SACCADE,BLINK,MESSAGE,BUTTON,INPUT' ) self.tracker.sendCommand( 'link_event_filter = LEFT,RIGHT,FIXATION,SACCADE,BLINK,BUTTON') self.tracker.sendCommand( 'link_sample_data = LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS,HTARGET') self.tracker.sendCommand( 'file_sample_data = LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS,HTARGET,INPUT' ) # Set display coords for dataviewer self.tracker.sendMessage("screen_pixel_coords = 0 0 %d %d" % (x_size - 1, y_size - 1)) self.tracker.sendMessage("DISPLAY_COORDS 0 0 %d %d" % (x_size - 1, y_size - 1))
def __init__(self, window, edfname, address="100.1.1.1"): # Pull out monitor info self.sres = window.size self.scenter = [self.sres[0] / 2.0, self.sres[1] / 2.0] self.win = window # Make filename fname = os.path.splitext(edfname)[0] # strip away extension if present assert re.match(r'\w+$', fname), 'Name must only include A-Z, 0-9, or _' assert len(fname) <= 8, 'Name must be <= 8 characters.' self.edfname = fname + '.edf' # Initialize connection with eye-tracker try: self.tracker = pylink.EyeLink(address) self.realconnect = True except RuntimeError: self.tracker = pylink.EyeLink(None) self.realconnect = False # Make pylink accessible self.pylink = pylink # Open EDF #Close any open file first if self.tracker.getTrackerMode() == pylink.EL_RECORD_MODE: self.tracker.closeDataFile() self.tracker.openDataFile(self.edfname) pylink.flushGetkeyQueue() self.tracker.setOfflineMode() # Set content of edf file eftxt = 'LEFT,RIGHT,FIXATION,SACCADE,BLINK,MESSAGE,BUTTON,INPUT' self.tracker.sendCommand('file_event_filter = ' + eftxt) lftxt = 'LEFT,RIGHT,FIXATION,SACCADE,BLINK,BUTTON' self.tracker.sendCommand('link_event_filter = ' + lftxt) lstxt = 'LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS,HTARGET' self.tracker.sendCommand('link_sample_data = ' + lstxt) fstxt = 'LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS,HTARGET,INPUT' self.tracker.sendCommand('file_sample_data = ' + fstxt) # Set display coords for dataviewer disptxt = 'DISPLAY_COORDS 0 0 {} {}'.format(*self.sres) self.tracker.sendMessage(disptxt) # Check which eye is being recorded self.eye_used = self.tracker.eyeAvailable()
def _create_tracker(self): """ Creates tracker object upon initialization. """ if not self.eyetracker_on or not PYLINK_AVAILABLE: return None tracker = pylink.EyeLink(self.et_settings.get('address')) pylink.flushGetkeyQueue() tracker.setOfflineMode() tracker.sendCommand('set_idle_mode') # why? self.edf_name = datetime.now().strftime('%H_%M_%S.edf') tracker.openDataFile(self.edf_name) return tracker
def __init__(self, size=[1024, 768], calibscale=1., ip='100.1.1.1', \ bgcolor=[127, 127, 127], fgcolor=[255, 255, 255], \ targetdiameter=20, targethole=5, calibrationtype='HV9', \ calibrationpacing=.9, viewdistance=None, screenwidth=None): self.size = tuple(size) # connect to tracker and do initial config self.tracker = pylink.EyeLink(ip) self.eyeused = None # flush out any pending key presses and get back to offline mode in # case we crashed out while recording pylink.flushGetkeyQueue() self.tracker.setOfflineMode() self.fgcolor = fgcolor self.bgcolor = bgcolor self.targetdiameter = targetdiameter self.targethole = targethole # month, day, hour, minute. self.remotefilename = time.strftime('%m%d%H%M') self.tracker.openDataFile(self.remotefilename) self.calibsize = (numpy.array(self.size) * calibscale) calibarea = numpy.round(numpy.array(self.size) - self.calibsize) alldims = (calibarea[0], calibarea[1], self.calibsize[0], self.calibsize[1]) self.tracker.sendCommand('screen_pixel_coords = %d %d %d %d' % alldims) self.tracker.sendMessage("DISPLAY_COORDS %d %d %d %d" % alldims) self.tracker.sendMessage("SCREEN_COORDS 0 0 %d %d" % self.size) # for robustness we set a bunch of other parameters so that any # weird defaults get overwritten if viewdistance: self.tracker.sendCommand('simulation_screen_distance=%d' % \ (viewdistance * 10)) self.tracker.sendMessage('VIEW_DISTANCE %d' % (viewdistance * 10)) self.tracker.sendCommand('automatic_calibration_pacing=%d' % \ (calibrationpacing * 1000)) if screenwidth: self.tracker.sendMessage('SCREEN_WIDTH %d' % screenwidth) # NB this command is necessary whenever changing # screen_pixel_coords self.tracker.sendCommand('calibration_type=' + calibrationtype) if self.tracker.getTrackerVersion() == 2: self.tracker.sendCommand("select_parser_configuration 0") else: self.tracker.sendCommand("saccade_velocity_threshold = 35") self.tracker.sendCommand("saccade_acceleration_threshold = 9500") self.tracker.setFileEventFilter("LEFT,RIGHT,FIXATION,SACCADE,BLINK,MESSAGE,BUTTON") self.tracker.setFileSampleFilter("LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS") self.tracker.setLinkEventFilter("LEFT,RIGHT,FIXATION,SACCADE,BLINK,BUTTON") self.tracker.setLinkSampleFilter("LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS") self.tracker.sendCommand("button_function 5 'accept_target_fixation'") return
def stop(self): """Stops recording data from the eye tracker. Called automatically at the end of each trial unless ``P.manual_eyelink_recording`` is True, in which case it must be called manually in order to stop recording at any point. To resume recording after this method is called, use the :meth:`start` method. """ endRealTimeMode() pumpDelay(100) self.stopRecording() self.__recording = False self.sendMessage("TRIAL OK") flushGetkeyQueue()
def initialize_tracker(self): if not self.edf_open: raise RuntimeError( 'EDF file must be open before tracker can be initialized.') pl.flushGetkeyQueue() self.set_offline_mode() self.send_command("screen_pixel_coords = 0 0 %d %d" % self.resolution) self.send_message("DISPLAY_COORDS 0 0 %d %d" % self.resolution) self.tracker.setFileEventFilter( "LEFT,RIGHT,FIXATION,SACCADE,BLINK,MESSAGE,BUTTON") self.tracker.setFileSampleFilter("LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS") self.tracker.setLinkEventFilter( "LEFT,RIGHT,FIXATION,SACCADE,BLINK,BUTTON") self.tracker.setLinkSampleFilter("LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS")
def _setup(self): """The EyeLink-specific part of the setup process. """ self.version = self.getTrackerVersionString() self.__custom_display = ELCustomDisplay() openGraphicsEx(self.__custom_display) flushGetkeyQueue() self.setOfflineMode() self.sendCommand("screen_pixel_coords = 0 0 {0} {1}".format(P.screen_x-1, P.screen_y-1)) self.setLinkEventFilter("FIXATION,SACCADE,BLINK,LEFT,RIGHT") self.setLinkEventData("GAZE, GAZERES, AREA, VELOCITY") # Enables fix/sacc start events self.openDataFile(self.edf_filename) self.write("DISPLAY_COORDS 0 0 {0} {1}".format(P.screen_x-1, P.screen_y-1)) self.setSaccadeVelocityThreshold(P.saccadic_velocity_threshold) self.setAccelerationThreshold(P.saccadic_acceleration_threshold) self.setMotionThreshold(P.saccadic_motion_threshold) beginRealTimeMode(10)
def libeyelink(edfname): global realconnect global tracker global edfname # Make filename fname = os.path.splitext(edfname)[0] # strip away extension if present assert re.match(r'\w+$', fname), 'Name must only include A-Z, 0-9, or _' assert len(fname) <= 8, 'Name must be <= 8 characters.' edfname = fname + '.edf' # Initialize connection with eyetracker try: tracker = pylink.EyeLink() realconnect = True except RuntimeError: tracker = pylink.EyeLink(None) realconnect = False # Open EDF pylink.getEYELINK().openDataFile(edfname) pylink.flushGetkeyQueue() pylink.getEYELINK().setOfflineMode() # Set content of edf file pylink.getEYELINK().sendCommand( 'file_event_filter = LEFT,RIGHT,FIXATION,SACCADE,BLINK,MESSAGE,BUTTON,INPUT') pylink.getEYELINK().sendCommand( 'link_event_filter = LEFT,RIGHT,FIXATION,SACCADE,BLINK,BUTTON') pylink.getEYELINK().sendCommand( 'link_sample_data = LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS,HTARGET') pylink.getEYELINK().sendCommand( 'file_sample_data = LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS,HTARGET,INPUT') # Set display coords for dataviewer pylink.getEYELINK().sendMessage("screen_pixel_coords = 0 0 %d %d" %(w - 1, h - 1)) pylink.getEYELINK().sendMessage("DISPLAY_COORDS 0 0 %d %d" %(w - 1, h - 1))
def __init__(self, window, edfname): # Pull out monitor info self.sres = window.size self.win = window # Make filename self.edfname = edfname + '.edf' # Initialize connection with eye-tracker try: self.tracker = pylink.EyeLink() self.realconnect = True except: self.tracker = pylink.EyeLink(None) self.realconnect = False # Make pylink accessible self.pylink = pylink # Open EDF self.tracker.openDataFile(self.edfname) pylink.flushGetkeyQueue() self.tracker.setOfflineMode() # Set content of edf file eftxt = 'LEFT,RIGHT,FIXATION,SACCADE,BLINK,MESSAGE,BUTTON,INPUT' self.tracker.sendCommand('file_event_filter = ' + eftxt) lftxt = 'LEFT,RIGHT,FIXATION,SACCADE,BLINK,BUTTON' self.tracker.sendCommand('link_event_filter = ' + lftxt) lstxt = 'LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS,HTARGET' self.tracker.sendCommand('link_sample_data = ' + lstxt) fstxt = 'LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS,HTARGET,INPUT' self.tracker.sendCommand('file_sample_data = ' + fstxt) # Set display coords for dataviewer disptxt = 'DISPLAY_COORDS 0 0 {} {}'.format(*self.sres) self.tracker.sendMessage(disptxt)
def __init__(self, window, edfname): # Pull out monitor info self.sres = window.size self.win = window # Make filename self.edfname = edfname + '.edf' # Initialize connection with eye-tracker try: self.tracker = pylink.EyeLink() self.realconnect = True except: self.tracker = pylink.EyeLink(None) self.realconnect = False # Make pylink accessible self.pylink = pylink # Open EDF self.tracker.openDataFile(self.edfname) pylink.flushGetkeyQueue() self.tracker.setOfflineMode() #Gets the display surface and send msg; surf = pygame.display.get_surface() getEYELINK().sendCommand("screen_pixel_coords = 0 0 %d %d" %(surf.get_rect().w, surf.get_rect().h)) getEYELINK().sendMessage("DISPLAY_COORDS 0 0 %d %d" %(surf.get_rect().w, surf.get_rect().h)) tracker_software_ver = 0 eyelink_ver = getEYELINK().getTrackerVersion() if eyelink_ver == 3: tvstr = getEYELINK().getTrackerVersion() vindex = tvstr.find("EYELINK CL") tracker_software_ver = int(float(tvstr[(vindex + len("EYELINK CL")):].strip())) if eyelink_ver>=2: getEYELINK().sendCommand("select_parser_configuration 0") if eyelink_ver == 2: #turn off scenelink camera stuff getEYELINK().sendCommand("scene_camera_gazemap = NO")
def initialize_tracker(self): """Sends commands setting up basic settings that are unlikely to be changed. EDF file must be open before this function is called. Must be called before starting to record. """ if not self.edf_open: raise RuntimeError( 'EDF file must be open before tracker can be initialized.') pl.flushGetkeyQueue() self.set_offline_mode() self.send_command("screen_pixel_coords = 0 0 %d %d" % self.resolution) self.send_message("DISPLAY_COORDS 0 0 %d %d" % self.resolution) self.tracker.setFileEventFilter( "LEFT,RIGHT,FIXATION,SACCADE,BLINK,MESSAGE,BUTTON") self.tracker.setFileSampleFilter("LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS") self.tracker.setLinkEventFilter( "LEFT,RIGHT,FIXATION,SACCADE,BLINK,BUTTON") self.tracker.setLinkSampleFilter("LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS")
def EyelinkStart(dispsize, Name, win, bits=32, dummy=False, colors=((0, 0, 0), (192, 192, 192))): """ Performs startup routines for the EyeLink 1000 Plus eyetracker. **Author** : Wanja Mössing, WWU Münster | [email protected] \n *July 2017* Parameters: ----------- dispsize : tuple two-item tuple width & height in px Name : string filename for the edf. Doesn't have to, but can, end on '.edf' Maximum length is 8 (without '.edf'). Possible alphanumeric input: 'a-z', 'A-Z', '0-9', '-' & '_' win : window object You necessarily need to open a psychopy window first! bits : integer color-depth, defaults to 32 dummy : boolean Run tracker in dummy mode? colors : Tuple, Optional. Tuple with two RGB triplets Returns ------- 'el' the tracker object. This can be passed to other functions, although they can use pylink.getEYELINK() to find it automatically. """ print('. ') # get filename if '.edf' not in Name.lower(): if len(Name) > 8: print('EDF filename too long! (1-8 characters/letters)') raise SystemExit else: Name += '.edf' elif '.edf' in Name.lower(): if len(Name) > 12: print('EDF filename too long! (1-8 characters/letters)') raise SystemExit print('. ') # initialize tracker object if dummy: el = pylink.EyeLink(None) else: el = pylink.EyeLink("100.1.1.1") print('. ') # Open EDF file on host el.openDataFile(Name) print('. ') # set file preamble currentdir = path.basename(getcwd()) FilePreamble = "add_file_preamble_text \'" FilePreamble += "Eyetracking Dataset AE Busch WWU Muenster Experiment: " FilePreamble += currentdir + "\'" el.sendCommand(FilePreamble) print('. ') # this function calls the custom calibration routine # "EyeLinkCoreGraphicsPsychopy.py" genv = EyeLinkCoreGraphicsPsychoPy(el, win) pylink.openGraphicsEx(genv) print('. ') # set tracker offline to change configuration el.setOfflineMode() print('. ') # flush old keys pylink.flushGetkeyQueue() print('. ') # set sampling rate el.sendCommand('sample_rate 1000') print('. ') # Sets the display coordinate system and sends mesage to that # effect to EDF file; el.sendCommand("screen_pixel_coords = 0 0 %d %d" % (dispsize[0] - 1, dispsize[1] - 1)) el.sendMessage("DISPLAY_COORDS 0 0 %d %d" % (dispsize[0] - 1, dispsize[1] - 1)) print('. ') # select parser configuration for online saccade etc detection ELversion = el.getTrackerVersion() ELsoftVer = 0 if ELversion == 3: tmp = el.getTrackerVersionString() tmpidx = tmp.find('EYELINK CL') ELsoftVer = int(float(tmp[(tmpidx + len("EYELINK CL")):].strip())) if ELversion >= 2: el.sendCommand("select_parser_configuration 0") if ELversion == 2: # turn off scenelink stuff (that's an EL2 front-cam addon...) el.sendCommand("scene_camera_gazemap = NO") else: el.sendCommand("saccade_velocity_threshold = 35") el.sendCommand("saccade_acceleration_threshold = 9500") print('. ') # set EDF file contents AREA el.sendCommand("file_event_filter = LEFT,RIGHT,FIXATION," "SACCADE,BLINK,MESSAGE,BUTTON,INPUT") if ELsoftVer >= 4: el.sendCommand("file_sample_data = LEFT,RIGHT,GAZE,HREF," "AREA,HTARGET,GAZERES,STATUS,INPUT") else: el.sendCommand("file_sample_data = LEFT,RIGHT,GAZE,HREF," "AREA,GAZERES,STATUS,INPUT") print('. ') # set link data (online interaction)AREA el.sendCommand("link_event_filter = LEFT,RIGHT,FIXATION,SACCADE," "BLINK,MESSAGE,BUTTON,INPUT") if ELsoftVer >= 4: el.sendCommand("link_sample_data = LEFT,RIGHT,GAZE,GAZERES,AREA," "HTARGET,STATUS,INPUT") else: el.sendCommand("link_sample_data = LEFT,RIGHT,GAZE,GAZERES,AREA," "STATUS,INPUT") print('. ') # run initial calibration # 13-Pt Grid calibration el.sendCommand('calibration_type = HV13') EyelinkCalibrate(dispsize, el) print('. ') # put tracker in idle mode and wait 50ms, then really start it. el.sendMessage('SETUP_FINISHED') el.setOfflineMode() pylink.msecDelay(500) print('. ') # set to realtime mode pylink.beginRealTimeMode(200) # start recording # note: sending everything over the link *potentially* causes buffer # overflow. However, with modern PCs and EL1000+ this shouldn't be a real # problem el.startRecording(1, 1, 1, 1) # to activate parallel port readout without modifying the FINAL.INI on the # eyelink host pc, uncomment these lines # tyical settings for straight-through TTL cable (data pins -> data pins) el.sendCommand('write_ioport 0xA 0x20') el.sendCommand('create_button 1 8 0x01 0') el.sendCommand('create_button 2 8 0x02 0') el.sendCommand('create_button 3 8 0x04 0') el.sendCommand('create_button 4 8 0x08 0') el.sendCommand('create_button 5 8 0x10 0') el.sendCommand('create_button 6 8 0x20 0') el.sendCommand('create_button 7 8 0x40 0') el.sendCommand('create_button 8 8 0x80 0') el.sendCommand('input_data_ports = 8') el.sendCommand('input_data_masks = 0xFF') # tyical settings for crossover TTL cable (data pins -> status pins) # el.sendCommand('write_ioport 0xA 0x0') # el.sendCommand('create_button 1 9 0x20 1') # el.sendCommand('create_button 2 9 0x40 1') # el.sendCommand('create_button 3 9 0x08 1') # el.sendCommand('create_button 4 9 0x10 1') # el.sendCommand('create_button 5 9 0x80 0') # el.sendCommand('input_data_ports = 9') # el.sendCommand('input_data_masks = 0xFF') # mark end of Eyelinkstart in .edf el.sendMessage('>EndOfEyeLinkStart') # return Eyelink object return el
def __init__(self, win, clock, sj="TEST", autoCalibration=True, saccadeSensitivity=HIGH, calibrationType='HV9', calibrationTargetColor=WHITE, calibrationBgColor=BLACK, CalibrationSounds=False): ''' win: psychopy visual window used for the experiment clock: psychopy time clock recording time for whole experiment sj: Subject identifier string (affects EDF filename) autoCalibration: True: enable auto-pacing during calibration saccadeSensitivity: HIGH: Pursuit and neurological work LOW: Cognitive research calibrationType: H3: Horizontal 3-point HV3: 3-point calibration, poor linearization HV5: 5-point calibration, poor at corners HV9: 9-point calibration, best overall calibrationTargetColor and calibrationBgColor: RGB tuple, i.e., (255,0,0) for Red One of: BLACK, WHITE, GRAY calibrationSounds: True: enable feedback sounds when calibrating ''' self.edfFileName = str(sj) + ".EDF" print(self.edfFileName) inf = info.RunTimeInfo("J", "1", win, refreshTest=None, userProcsDetailed=False) self.screenSize = inf['windowSize_pix'] self.units = inf['windowUnits'] self.monitorName = inf['windowMonitor.name'] monitor = monitors.Monitor(self.monitorName) print("Connecting to eyetracker.") self.tracker = pylink.EyeLink() self.timeCorrection = clock.getTime() - self.tracker.trackerTime() print("Loading custom graphics") genv = EyeLinkCoreGraphicsPsychopy(self.tracker, win, self.screenSize) self.tracker.openDataFile(self.edfFileName) pylink.flushGetkeyQueue() self.tracker.setOfflineMode() self.tracker.sendCommand("screen_pixel_coords = 0 0 %d %d" % (tuple(self.screenSize))) self.tracker.setCalibrationType(calibrationType) self.tracker.sendMessage("DISPLAY_COORDS 0 0 %d %d" % (tuple(self.screenSize))) eyelink_ver = self.tracker.getTrackerVersion() if eyelink_ver == 3: tvstr = self.tracker.getTrackerVersionString() vindex = tvstr.find("EYELINK CL") tracker_software_ver = int( float(tvstr[(vindex + len("EYELINK CL")):].strip())) else: tracker_software_ver = 0 if eyelink_ver >= 2: self.tracker.sendCommand("select_parser_configuration %d" % saccadeSensitivity) else: if saccadeSensitivity == HIGH: svt, sat = 22, 5000 else: svt, sat = 30, 9500 self.tracker.sendCommand("saccade_velocity_threshold = %d" % svt) self.tracker.sendCommand("saccade_acceleration_threshold = %d" % sat) if eyelink_ver == 2: #turn off scenelink camera stuff self.tracker.sendCommand("scene_camera_gazemap = NO") # set EDF file contents self.tracker.sendCommand( "file_event_filter = LEFT,RIGHT,FIXATION,SACCADE,BLINK,MESSAGE,BUTTON" ) if tracker_software_ver >= 4: self.tracker.sendCommand( "file_sample_data = LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS,HTARGET" ) else: self.tracker.sendCommand( "file_sample_data = LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS") # set link data (used for gaze cursor) self.tracker.sendCommand( "link_event_filter = LEFT,RIGHT,FIXATION,SACCADE,BLINK,BUTTON") if tracker_software_ver >= 4: self.tracker.sendCommand( "link_sample_data = LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS,HTARGET" ) else: self.tracker.sendCommand( "link_sample_data = LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS") #Set the calibration settings: pylink.setCalibrationColors(calibrationTargetColor, calibrationBgColor) if CalibrationSounds: pylink.setCalibrationSounds("", "", "") pylink.setDriftCorrectSounds("", "off", "off") else: pylink.setCalibrationSounds("off", "off", "off") pylink.setDriftCorrectSounds("off", "off", "off") if autoCalibration: self.tracker.enableAutoCalibration else: self.tracker.disableAutoCalibration win.flip() print("Opening graphics") pylink.openGraphicsEx(genv) print("Begining tracker setup") self.tracker.doTrackerSetup() win.flip()
def clearAllEventBuffers(self): pylink.flushGetkeyQueue() self.tracker.resetData() self._iohub_server.eventBuffer.clear() for d in self._iohub_server.devices: d.clearEvents()
def __init__(self, win, clock, sj = "TEST", saccadeSensitivity = HIGH, calibrationType = 'HV9',calibrationTargetColor = WHITE,calibrationBgColor = BLACK, CalibrationSounds = False,screen=(1024,768)): '''win: psychopy visual window used for the experiment clock: psychopy time clock recording time for whole experiment sj: Subject identifier string (affects EDF filename) saccadeSensitivity: HIGH: Pursuit and neurological work LOW: Cognitive research calibrationType: H3: Horizontal 3-point HV3: 3-point calibration, poor linearization HV5: 5-point calibration, poor at corners HV9: 9-point calibration, best overall calibrationTargetColor and calibrationBgColor: RGB tuple, i.e., (255,0,0) for Red One of: BLACK, WHITE, GRAY calibrationSounds: True: enable feedback sounds when calibrating''' self.edfFileName = str(sj)+".EDF" # Subject name only can put 8 characters print("Connecting to eyetracker.") self.tracker = pylink.EyeLink() self.timeCorrection = clock.getTime() - self.tracker.trackerTime() print("Loading custom graphics") #Initializes Experiment Graphics genv = EyeLinkCoreGraphicsPsychopy(self.tracker, win, screen) pylink.openGraphicsEx(genv) # opendatafile self.tracker.openDataFile(self.edfFileName) #EyeLink Tracker Configuration pylink.flushGetkeyQueue();# Initializes the key queue used by getkey(). It may be called at any time to get rid any of old keys from the queue. self.tracker.setOfflineMode();#Places EyeLink tracker in off-line (idle) mode. Wait till the tracker has finished the mode transition self.tracker.sendCommand("screen_pixel_coords = 0 0 %d %d"%( tuple(screen) )) self.tracker.setCalibrationType(calibrationType) self.tracker.sendCommand("driftcorrect_cr_disable=OFF") #CF - OFF: turns on drift CORRECT; AUTO: Turns on drift CHECK; ON: Turns off both #self.tracker.sendCommand("generate_default_targets = NO") #self.tracker.sendCommand("calibration_targets = 512,384 512,417 512,351 402,384 622,384 402,417 622,417 402,351 622,351") #self.tracker.sendCommand("validation_targets = 512,384 512,417 512,351 402,384 622,384 402,417 622,417 402,351 622,351") self.tracker.sendMessage("DISPLAY_COORDS 0 0 %d %d"%( tuple(screen) )) eyelink_ver = self.tracker.getTrackerVersion() if eyelink_ver == 3: tvstr = self.tracker.getTrackerVersionString() vindex = tvstr.find("EYELINK CL") tracker_software_ver = int(float(tvstr[(vindex + len("EYELINK CL")):].strip())) else: tracker_software_ver = 0 if eyelink_ver>=2: self.tracker.sendCommand("select_parser_configuration %d" %saccadeSensitivity) else: if saccadeSensitivity == HIGH:svt, sat = 22, 5000 else: svt, sat = 30, 9500 self.tracker.sendCommand("saccade_velocity_threshold = %d" %svt) self.tracker.sendCommand("saccade_acceleration_threshold = %d" %sat) if eyelink_ver == 2: #turn off scenelink camera stuff self.tracker.sendCommand("scene_camera_gazemap = NO") # set EDF file contents self.tracker.setFileEventFilter("LEFT,RIGHT,FIXATION,SACCADE,BLINK,MESSAGE,BUTTON") if tracker_software_ver>=4:self.tracker.setFileSampleFilter("LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS,HTARGET") else:self.tracker.setFileSampleFilter("LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS") # set link data (used for gaze cursor) self.tracker.setLinkEventFilter("LEFT,RIGHT,FIXATION,SACCADE,BLINK,BUTTON") if tracker_software_ver>=4:self.tracker.setLinkSampleFilter("LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS,HTARGET") else:self.tracker.setLinkSampleFilter("LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS") #self.tracker.setAcceptTargetFixationButton(1) # This programs a specific button for use in drift correction. #Set the calibration settings: #pylink.setCalibrationColors(WHITE, BLACK) # Sets the calibration target and background color(foreground_color, background_color) if CalibrationSounds: pylink.setCalibrationSounds("", "", "") pylink.setDriftCorrectSounds("", "off", "off") else: pylink.setCalibrationSounds("off", "off", "off") pylink.setDriftCorrectSounds("off", "off", "off") print("Beginning tracker setup") self.tracker.doTrackerSetup()
def main(debug_mode): MyMonitor = utils.Monitor("labo-Tom-PC",1280,1024, distance = 72, width_cm = 36.6) print "Degrees per pixel: ", MyMonitor.degreesperpixel if debug_mode: dummy_mode = True full_screen = False else: dummy_mode= False full_screen = True ## there are 1600 trials START = 0 ## from what line of the table we should start NB_TRIALS = 800 BREAK_INTERVAL = 200 #200 ## display the take-a-break screen every XX trials FRAME_RATE = 100.0 ## not used for now calib_type = "HV13" ## try HV13 for 13 dots file_asking = raw_input("Start with: [N]ew file, [O]pen a file, [T]est file: \n") ## Ask questions on conditions, check if the file already exist: if file_asking=="N": if debug_mode: NB_TRIALS = int(raw_input("(debug mode) How many trials? ")) START = int(raw_input("From which trial would you like to start?")) info, table, path_to_table_file, path_to_eye_tracker_file = utils.initializeFromConditions(NB_TRIALS) elif file_asking == "O": import Tkinter, tkFileDialog root = Tkinter.Tk() root.withdraw() file_path = tkFileDialog.askopenfilename(title = "Open a Table file:") root.destroy() info, table, path_to_table_file, path_to_eye_tracker_file = utils.openTable(file_path) START = int(raw_input("From which trial would you like to continue?")) else: info, table, path_to_table_file, path_to_eye_tracker_file = utils.openTable("") print info if not dummy_mode: MyEyelink = pylink.EyeLink() MyMonitor.setFPSControl(0) else: ## this is my dummy, it works better than the official one MyEyelink = dummy.DummyEyeLink() MyMonitor.setFPSControl(FRAME_RATE) ## force 100 Hz during office-test ## switch to zero when running the experiment ## Initializes the graphics display.init() mouse.set_visible(False) ## do a new display surface if full_screen: display.set_mode((MyMonitor.w, MyMonitor.h), FULLSCREEN |DOUBLEBUF | HWSURFACE,32) else: display.set_mode((MyMonitor.w, MyMonitor.h), NOFRAME |DOUBLEBUF,32) surf = display.get_surface() MyEnv = utils.Environment(surf, MyMonitor, MyEyelink, table, info, calib_type = calib_type, units = 'deg') event = utils.runCalibration(MyEnv) ## Gets the new display surface and sends a mesage to EDF file; edfFileName = path_to_eye_tracker_file ## opens the EDF file. MyEyelink.openDataFile(edfFileName) pylink.flushGetkeyQueue(); MyEyelink.setOfflineMode(); utils.configEDFfile(MyEyelink) MyEyelink.sendMessage("Info Experiment: %s"%(str(info))) MyEyelink.sendCommand("screen_pixel_coords = 0 0 %d %d" %(surf.get_rect().w, surf.get_rect().h)) MyEyelink.sendMessage("DISPLAY_COORDS 0 0 %d %d" %(surf.get_rect().w, surf.get_rect().h)) error = 0 stop_time = time.time() print time.strftime("Experiment started at %H:%M:%S", time.localtime(stop_time)) try: if(MyEyelink.isConnected() and not MyEyelink.breakPressed()): print "Let's run the trials" error, saveFrames = run_trials.run_trials(MyEnv, START, BREAK_INTERVAL) except Exception, e: print "Caught:", e
w = window.winfo_screenwidth() h = window.winfo_screenheight() if not myDlg.OK: core.quit() result['name'] = ok_data[0] result['sex'] = ok_data[1] result['age'] = ok_data[2] # eyelinktracker = EyeLink(trackeraddress=None) eyelinktracker = EyeLink() # 眼动仪 pylink.openGraphics((w, h), 32) edfFileName = "%s.EDF" % result['name'] getEYELINK().openDataFile(edfFileName) pylink.flushGetkeyQueue() getEYELINK().setOfflineMode() getEYELINK().sendCommand("screen_pixel_coords = 0 0 %d %d" % (w - 1, h - 1)) getEYELINK().sendMessage("DISPLAY_COORDS 0 0 %d %d" % (w - 1, h - 1)) if getEYELINK().getTrackerVersion() == 2: getEYELINK().sendCommand("select_parser_configuration 0") else: getEYELINK().sendCommand("saccade_velocity_threshold = 35") getEYELINK().sendCommand("saccade_acceleration_threshold = 9500") getEYELINK().setFileEventFilter( "LEFT,RIGHT,FIXATION,SACCADE,BLINK,MESSAGE,BUTTON") getEYELINK().setFileSampleFilter("LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS") getEYELINK().setLinkEventFilter("LEFT,RIGHT,FIXATION,SACCADE,BLINK,BUTTON") getEYELINK().setLinkSampleFilter("LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS") getEYELINK().sendCommand("pupil_size_diameter = YES") pylink.setCalibrationColors(
def __init__(self, win, clock, sj = "TEST", autoCalibration=True, saccadeSensitivity = HIGH, calibrationType = 'HV9', calibrationTargetColor = WHITE, calibrationBgColor = BLACK, CalibrationSounds = False ): ''' win: psychopy visual window used for the experiment clock: psychopy time clock recording time for whole experiment sj: Subject identifier string (affects EDF filename) autoCalibration: True: enable auto-pacing during calibration saccadeSensitivity: HIGH: Pursuit and neurological work LOW: Cognitive research calibrationType: H3: Horizontal 3-point HV3: 3-point calibration, poor linearization HV5: 5-point calibration, poor at corners HV9: 9-point calibration, best overall calibrationTargetColor and calibrationBgColor: RGB tuple, i.e., (255,0,0) for Red One of: BLACK, WHITE, GRAY calibrationSounds: True: enable feedback sounds when calibrating ''' self.edfFileName = str(sj)+".EDF" print(self.edfFileName) inf = info.RunTimeInfo("J","1",win, refreshTest=None, userProcsDetailed=False) self.screenSize = inf['windowSize_pix'] self.units = inf['windowUnits'] self.monitorName = inf['windowMonitor.name'] monitor = monitors.Monitor(self.monitorName) print("Connecting to eyetracker.") self.tracker = pylink.EyeLink() self.timeCorrection = clock.getTime() - self.tracker.trackerTime() print("Loading custom graphics") genv = EyeLinkCoreGraphicsPsychopy(self.tracker, win, self.screenSize) self.tracker.openDataFile(self.edfFileName) pylink.flushGetkeyQueue(); self.tracker.setOfflineMode(); self.tracker.sendCommand("screen_pixel_coords = 0 0 %d %d" %( tuple(self.screenSize) )) self.tracker.setCalibrationType(calibrationType) self.tracker.sendMessage("DISPLAY_COORDS 0 0 %d %d" %( tuple(self.screenSize) )) eyelink_ver = self.tracker.getTrackerVersion() if eyelink_ver == 3: tvstr = self.tracker.getTrackerVersionString() vindex = tvstr.find("EYELINK CL") tracker_software_ver = int(float(tvstr[(vindex + len("EYELINK CL")):].strip())) else: tracker_software_ver = 0 if eyelink_ver>=2: self.tracker.sendCommand("select_parser_configuration %d" %saccadeSensitivity) else: if saccadeSensitivity == HIGH: svt, sat = 22, 5000 else: svt, sat = 30, 9500 self.tracker.sendCommand("saccade_velocity_threshold = %d" %svt) self.tracker.sendCommand("saccade_acceleration_threshold = %d" %sat) if eyelink_ver == 2: #turn off scenelink camera stuff self.tracker.sendCommand("scene_camera_gazemap = NO") # set EDF file contents self.tracker.sendCommand("file_event_filter = LEFT,RIGHT,FIXATION,SACCADE,BLINK,MESSAGE,BUTTON") if tracker_software_ver>=4: self.tracker.sendCommand("file_sample_data = LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS,HTARGET") else: self.tracker.sendCommand("file_sample_data = LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS") # set link data (used for gaze cursor) self.tracker.sendCommand("link_event_filter = LEFT,RIGHT,FIXATION,SACCADE,BLINK,BUTTON") if tracker_software_ver>=4: self.tracker.sendCommand("link_sample_data = LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS,HTARGET") else: self.tracker.sendCommand("link_sample_data = LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS") #Set the calibration settings: pylink.setCalibrationColors( calibrationTargetColor, calibrationBgColor) if CalibrationSounds: pylink.setCalibrationSounds("", "", "") pylink.setDriftCorrectSounds("", "off", "off") else: pylink.setCalibrationSounds("off", "off", "off") pylink.setDriftCorrectSounds("off", "off", "off") if autoCalibration: self.tracker.enableAutoCalibration else: self.tracker.disableAutoCalibration win.flip() print("Opening graphics") pylink.openGraphicsEx(genv) print("Begining tracker setup") self.tracker.doTrackerSetup() win.flip()
def __init__(self, display, resolution=settings.DISPSIZE, data_file=settings.LOGFILENAME + ".edf", fg_color=settings.FGC, bg_color=settings.BGC, eventdetection=settings.EVENTDETECTION, saccade_velocity_threshold=35, saccade_acceleration_threshold=9500, blink_threshold=settings.BLINKTHRESH, force_drift_correct=True, pupil_size_mode=settings.EYELINKPUPILSIZEMODE, **args): """See pygaze._eyetracker.baseeyetracker.BaseEyeTracker""" # try to import copy docstring (but ignore it if it fails, as we do # not need it for actual functioning of the code) try: copy_docstr(BaseEyeTracker, libeyelink) except: # we're not even going to show a warning, since the copied # docstring is useful for code editors; these load the docs # in a non-verbose manner, so warning messages would be lost pass global _eyelink # Make sure that we have a valid data file. The local_data_file may # contain a folder. The eyelink_data_file is only a basename, i.e. # without folder. The eyelink_data_file must be at most eight characters # and end with a `.edf` extension. self.local_data_file = data_file self.eyelink_data_file = os.path.basename(data_file) stem, ext = os.path.splitext(self.eyelink_data_file) if len(stem) > 8 or ext.lower() != '.edf': raise Exception( "The EyeLink cannot handle filenames longer than eight " "characters (excluding '.edf' extension).") # properties self.display = display self.fontsize = 18 self.scr = Screen(disptype=settings.DISPTYPE, mousevisible=False) self.kb = Keyboard(keylist=["escape", "q"], timeout=1) self.resolution = resolution self.recording = False self.saccade_velocity_treshold = saccade_velocity_threshold self.saccade_acceleration_treshold = saccade_acceleration_threshold self.blink_threshold = blink_threshold self.eye_used = None self.left_eye = 0 self.right_eye = 1 self.binocular = 2 self.pupil_size_mode = pupil_size_mode self.prevsample = (-1, -1) self.prevps = -1 # event detection properties # degrees; maximal distance from fixation start (if gaze wanders beyond # this, fixation has stopped) self.fixtresh = 1.5 # milliseconds; amount of time gaze has to linger within self.fixtresh # to be marked as a fixation self.fixtimetresh = 100 # degrees per second; saccade velocity threshold self.spdtresh = self.saccade_velocity_treshold # degrees per second**2; saccade acceleration threshold self.accthresh = self.saccade_acceleration_treshold self.set_detection_type(eventdetection) # weighted distance, used for determining whether a movement is due to # measurement error (1 is ok, higher is more conservative and will # result in only larger saccades to be detected) self.weightdist = 10 # distance between participant and screen in cm self.screendist = settings.SCREENDIST # distance between participant and screen in cm self.screensize = settings.SCREENSIZE self.pixpercm = (self.resolution[0]/float(self.screensize[0]) + \ self.resolution[1]/float(self.screensize[1])) / 2.0 # only initialize eyelink once if _eyelink == None: try: _eyelink = pylink.EyeLink() except: raise Exception( "Error in libeyelink.libeyelink.__init__(): Failed to " "connect to the tracker!") # determine software version of tracker self.tracker_software_ver = 0 self.eyelink_ver = pylink.getEYELINK().getTrackerVersion() if self.eyelink_ver == 3: tvstr = pylink.getEYELINK().getTrackerVersionString() vindex = tvstr.find("EYELINK CL") self.tracker_software_ver = int(float(tvstr[(vindex + \ len("EYELINK CL")):].strip())) if self.eyelink_ver == 1: self.eyelink_model = 'EyeLink I' elif self.eyelink_ver == 2: self.eyelink_model = 'EyeLink II' elif self.eyelink_ver == 3: self.eyelink_model = 'EyeLink 1000' else: self.eyelink_model = 'EyeLink (model unknown)' # Open graphics self.eyelink_graphics = EyelinkGraphics(self, _eyelink) pylink.openGraphicsEx(self.eyelink_graphics) # Optionally force drift correction. For some reason this must be done # as (one of) the first things, otherwise a segmentation fault occurs. if force_drift_correct: try: self.send_command('driftcorrect_cr_disable = OFF') except: print('Failed to force drift correction (EyeLink 1000 only)') # Set pupil-size mode if self.pupil_size_mode == 'area': pylink.getEYELINK().setPupilSizeDiameter(False) elif self.pupil_size_mode == 'diameter': pylink.getEYELINK().setPupilSizeDiameter(True) else: raise Exception( "pupil_size_mode should be 'area' or 'diameter', not %s" \ % self.pupil_size_mode) pylink.getEYELINK().openDataFile(self.eyelink_data_file) pylink.flushGetkeyQueue() pylink.getEYELINK().setOfflineMode() # notify eyelink of display resolution self.send_command("screen_pixel_coords = 0 0 %d %d" % \ (self.resolution[0], self.resolution[1])) # get some configuration stuff if self.eyelink_ver >= 2: self.send_command("select_parser_configuration 0") if self.eyelink_ver == 2: # turn off scenelink camera stuff self.send_command("scene_camera_gazemap = NO") # set EDF file contents (this specifies which data is written to the EDF # file) self.send_command( "file_event_filter = LEFT,RIGHT,FIXATION,SACCADE,BLINK,MESSAGE,BUTTON" ) if self.tracker_software_ver >= 4: self.send_command( "file_sample_data = LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS,HTARGET" ) else: self.send_command( "file_sample_data = LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS") # set link data (this specifies which data is sent through the link and # thus can be used in gaze contingent displays) self.send_command( "link_event_filter = LEFT,RIGHT,FIXATION,SACCADE,BLINK,BUTTON") if self.tracker_software_ver >= 4: self.send_command( "link_sample_data = LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS,HTARGET" ) else: self.send_command( "link_sample_data = LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS") # not quite sure what this means (according to Sebastiaan Mathot, it # might be the button that is used to end drift correction?) self.send_command("button_function 5 'accept_target_fixation'") if not self.connected(): raise Exception( "Error in libeyelink.libeyelink.__init__(): Failed to connect " "to the eyetracker!")
def __init__(self, resolution, data_file="default.edf", fg_color=(255, 255, 255), bg_color=(0, 0, 0), saccade_velocity_threshold=35, saccade_acceleration_threshold=9500): """ Initializes the connection to the Eyelink Parameters: _resolution: (width, height) tuple _data_file: the name of the EDF file Returns: True on connection success and False on connection failure """ global _eyelink self.data_file = data_file self.resolution = resolution self.recording = False self.saccade_velocity_treshold = saccade_velocity_threshold self.saccade_acceleration_treshold = saccade_acceleration_threshold self.eye_used = None self.left_eye = 0 self.right_eye = 1 self.binocular = 2 # Only initialize the eyelink once if _eyelink == None: try: _eyelink = pylink.EyeLink() except Exception as e: raise exceptions.runtime_error( "Failed to connect to the tracker: %s" % e) graphics_env = eyelink_graphics(_eyelink) pylink.openGraphicsEx(graphics_env) pylink.getEYELINK().openDataFile(self.data_file) pylink.flushGetkeyQueue() pylink.getEYELINK().setOfflineMode() # Notify the eyelink of the display resolution self.send_command("screen_pixel_coords = 0 0 %d %d" % (self.resolution[0], self.resolution[1])) # Determine the software version of the tracker self.tracker_software_ver = 0 self.eyelink_ver = pylink.getEYELINK().getTrackerVersion() if self.eyelink_ver == 3: tvstr = pylink.getEYELINK().getTrackerVersionString() vindex = tvstr.find("EYELINK CL") self.tracker_software_ver = int( float(tvstr[(vindex + len("EYELINK CL")):].strip())) # Set some configuration stuff (not sure what the parser and gazemap mean) if self.eyelink_ver >= 2: self.send_command("select_parser_configuration 0") if self.eyelink_ver == 2: #turn off scenelink camera stuff self.send_command("scene_camera_gazemap = NO") else: self.send_command("saccade_velocity_threshold = %d" % self.saccade_velocity_threshold) self.send_command("saccade_acceleration_threshold = %s" % self.saccade_acceleration_threshold) # Set EDF file contents. This specifies which data is written to the EDF file. self.send_command( "file_event_filter = LEFT,RIGHT,FIXATION,SACCADE,BLINK,MESSAGE,BUTTON" ) if self.tracker_software_ver >= 4: self.send_command( "file_sample_data = LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS,HTARGET" ) else: self.send_command( "file_sample_data = LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS") # Set link data. This specifies which data is sent through the link and thus can # be used in gaze contingent displays self.send_command( "link_event_filter = LEFT,RIGHT,FIXATION,SACCADE,BLINK,BUTTON") if self.tracker_software_ver >= 4: self.send_command( "link_sample_data = LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS,HTARGET" ) else: self.send_command( "link_sample_data = LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS") # Not sure what this means. Maybe the button that is used to end drift correction? self.send_command("button_function 5 'accept_target_fixation'") if not self.connected(): raise exceptions.runtime_error( "Failed to connect to the eyetracker")
def Start_exp(self): # --------------------------------------------------- # point de départ de l'expérience # --------------------------------------------------- pylink.openGraphics((self.screen_width_px, self.screen_height_px), 32) # Initialise les graphiques self.eyelink.openDataFile(self.edfFileName) # Ouvre le fichier EDF. # réinitialise les touches et réglez le mode de suivi en mode hors connexion. pylink.flushGetkeyQueue() self.eyelink.setOfflineMode() # Définit le système de coordonnées d'affichage et envoie un message à cet effet au fichier EDF; self.eyelink.sendCommand( "screen_pixel_coords = 0 0 %d %d" % (self.screen_width_px - 1, self.screen_height_px - 1)) self.eyelink.sendMessage( "DISPLAY_COORDS 0 0 %d %d" % (self.screen_width_px - 1, self.screen_height_px - 1)) # --------------------------------------------------- # NETOYER ??? version = 3 # --------------------------------------------------- tracker_software_ver = 0 eyelink_ver = self.eyelink.getTrackerVersion() if eyelink_ver == 3: tvstr = self.eyelink.getTrackerVersionString() vindex = tvstr.find("EYELINK CL") tracker_software_ver = int( float(tvstr[(vindex + len("EYELINK CL")):].strip())) if eyelink_ver >= 2: self.eyelink.sendCommand("select_parser_configuration 0") if eyelink_ver == 2: # Éteignez les caméras scenelink self.eyelink.sendCommand("scene_camera_gazemap = NO") else: self.eyelink.sendCommand("saccade_velocity_threshold = 35") self.eyelink.sendCommand("saccade_acceleration_threshold = 9500") # Définir le contenu du fichier EDF self.eyelink.sendCommand( "file_event_filter = LEFT,RIGHT,FIXATION,SACCADE,BLINK,MESSAGE,BUTTON,INPUT" ) if tracker_software_ver >= 4: self.eyelink.sendCommand( "file_sample_data = LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS,HTARGET,INPUT" ) else: self.eyelink.sendCommand( "file_sample_data = LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS,INPUT" ) # Définir les données du lien (utilisé pour le curseur du regard) self.eyelink.sendCommand( "link_event_filter = LEFT,RIGHT,FIXATION,FIXUPDATE,SACCADE,BLINK,BUTTON,INPUT" ) if tracker_software_ver >= 4: self.eyelink.sendCommand( "link_sample_data = LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS,HTARGET,INPUT" ) else: self.eyelink.sendCommand( "link_sample_data = LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS,INPUT" ) ############################# # Calibration ############################# pylink.setCalibrationColors( (255, 255, 255), (128, 128, 128) ) # Définit couleur de la cible d'étalonnage (blanc) et de l'arrière-plan (gris) pylink.setTargetSize(self.screen_width_px // 70, self.screen_width_px // 300) # Définit taille de la cible d'étalonnage pylink.setCalibrationSounds("", "", "") pylink.setDriftCorrectSounds("", "off", "off")
def EyelinkStart(dispsize, Name, win, bits=32, dummy=False, colors=((0, 0, 0), (192, 192, 192))): """ Performs startup routines for the EyeLink 1000 Plus eyetracker. **Author** : Wanja Mössing, WWU Münster | [email protected] \n *July 2017* Parameters: ----------- dispsize : tuple two-item tuple width & height in px Name : string filename for the edf. Doesn't have to, but can, end on '.edf' Maximum length is 8 (without '.edf'). Possible alphanumeric input: 'a-z', 'A-Z', '0-9', '-' & '_' win : window object You necessarily need to open a psychopy window first! bits : integer color-depth, defaults to 32 dummy : boolean Run tracker in dummy mode? colors : Tuple, Optional. Tuple with two RGB triplets Returns ------- 'el' the tracker object. This can be passed to other functions, although they can use pylink.getEYELINK() to find it automatically. """ print('. ') # get filename if '.edf' not in Name.lower(): if len(Name) > 8: print('EDF filename too long! (1-8 characters/letters)') raise SystemExit else: Name += '.edf' elif '.edf' in Name.lower(): if len(Name) > 12: print('EDF filename too long! (1-8 characters/letters)') raise SystemExit print('. ') # initialize tracker object if dummy: el = pylink.EyeLink(None) else: el = pylink.EyeLink("100.1.1.1") print('. ') # Open EDF file on host el.openDataFile(Name) print('. ') # set file preamble currentdir = path.basename(getcwd()) FilePreamble = "add_file_preamble_text \'" FilePreamble += "Eyetracking Dataset AE Busch WWU Muenster Experiment: " FilePreamble += currentdir + "\'" el.sendCommand(FilePreamble) print('. ') # this function calls the custom calibration routine # "EyeLinkCoreGraphicsPsychopy.py" genv = EyeLinkCoreGraphicsPsychoPy(el, win) pylink.openGraphicsEx(genv) print('. ') # set tracker offline to change configuration el.setOfflineMode() print('. ') # flush old keys pylink.flushGetkeyQueue() print('. ') # set sampling rate el.sendCommand('sample_rate 1000') print('. ') # Sets the display coordinate system and sends mesage to that # effect to EDF file; el.sendCommand("screen_pixel_coords = 0 0 %d %d" % (dispsize[0] - 1, dispsize[1] - 1)) el.sendMessage("DISPLAY_COORDS 0 0 %d %d" % (dispsize[0] - 1, dispsize[1] - 1)) print('. ') # select parser configuration for online saccade etc detection ELversion = el.getTrackerVersion() ELsoftVer = 0 if ELversion == 3: tmp = el.getTrackerVersionString() tmpidx = tmp.find('EYELINK CL') ELsoftVer = int(float(tmp[(tmpidx + len("EYELINK CL")):].strip())) if ELversion >= 2: el.sendCommand("select_parser_configuration 0") if ELversion == 2: # turn off scenelink stuff (that's an EL2 front-cam addon...) el.sendCommand("scene_camera_gazemap = NO") else: el.sendCommand("saccade_velocity_threshold = 35") el.sendCommand("saccade_acceleration_threshold = 9500") print('. ') # set EDF file contents AREA el.sendCommand("file_event_filter = LEFT,RIGHT,FIXATION," "SACCADE,BLINK,MESSAGE,BUTTON,INPUT") if ELsoftVer >= 4: el.sendCommand("file_sample_data = LEFT,RIGHT,GAZE,HREF," "AREA,HTARGET,GAZERES,STATUS,INPUT") else: el.sendCommand("file_sample_data = LEFT,RIGHT,GAZE,HREF," "AREA,GAZERES,STATUS,INPUT") print('. ') # set link data (online interaction)AREA el.sendCommand("link_event_filter = LEFT,RIGHT,FIXATION,SACCADE," "BLINK,MESSAGE,BUTTON,INPUT") if ELsoftVer >= 4: el.sendCommand("link_sample_data = LEFT,RIGHT,GAZE,GAZERES,AREA," "HTARGET,STATUS,INPUT") else: el.sendCommand("link_sample_data = LEFT,RIGHT,GAZE,GAZERES,AREA," "STATUS,INPUT") print('. ') # run initial calibration # 13-Pt Grid calibration el.sendCommand('calibration_type = HV13') el.doTrackerSetup(dispsize[0], dispsize[1]) # put tracker in idle mode and wait 50ms, then really start it. el.sendMessage('SETUP_FINISHED') el.setOfflineMode() pylink.msecDelay(500) # set to realtime mode pylink.beginRealTimeMode(200) # start recording # note: sending everything over the link *potentially* causes buffer # overflow. However, with modern PCs and EL1000+ this shouldn't be a real # problem el.startRecording(1, 1, 1, 1) # to activate parallel port readout without modifying the FINAL.INI on the # eyelink host pc, uncomment these lines # tyical settings for straight-through TTL cable (data pins -> data pins) el.sendCommand('write_ioport 0xA 0x20') el.sendCommand('create_button 1 8 0x01 0') el.sendCommand('create_button 2 8 0x02 0') el.sendCommand('create_button 3 8 0x04 0') el.sendCommand('create_button 4 8 0x08 0') el.sendCommand('create_button 5 8 0x10 0') el.sendCommand('create_button 6 8 0x20 0') el.sendCommand('create_button 7 8 0x40 0') el.sendCommand('create_button 8 8 0x80 0') el.sendCommand('input_data_ports = 8') el.sendCommand('input_data_masks = 0xFF') # tyical settings for crossover TTL cable (data pins -> status pins) # el.sendCommand('write_ioport 0xA 0x0') # el.sendCommand('create_button 1 9 0x20 1') # el.sendCommand('create_button 2 9 0x40 1') # el.sendCommand('create_button 3 9 0x08 1') # el.sendCommand('create_button 4 9 0x10 1') # el.sendCommand('create_button 5 9 0x80 0') # el.sendCommand('input_data_ports = 9') # el.sendCommand('input_data_masks = 0xFF') # mark end of Eyelinkstart in .edf el.sendMessage('>EndOfEyeLinkStart') # return Eyelink object return el
def doSim(self, trial, road, duration, tau, doEyetrack): # Measure sample rate in order to calculate delay buffer sample_rate = self.screen.measure_refresh_rate(2.0) print "Sample rate: " + str(sample_rate) #sample_rate = 60 self.doEyetrack = doEyetrack self.pos_ring = RingBuffer(self.center, int(math.floor(tau * sample_rate)) + 1) print("Ring Buffer:: size: " + str(self.pos_ring.size)) if doEyetrack: import pylink from EyeLinkCoreGraphicsVE import EyeLinkCoreGraphicsVE self.tracker = pylink.EyeLink() if self.tracker == None: print "Error: Eyelink is not connected" sys.exit() genv = EyeLinkCoreGraphicsVE(self.screen, self.tracker) pylink.openGraphicsEx(genv) #Opens the EDF file. edfFileName = "TRIAL" + str(trial) + ".EDF" self.tracker.openDataFile(edfFileName) pylink.flushGetkeyQueue() self.tracker.sendCommand("screen_pixel_coords = 0 0 %d %d" % (VisionEgg.config.VISIONEGG_SCREEN_W, VisionEgg.config.VISIONEGG_SCREEN_H)) tracker_software_ver = 0 eyelink_ver = self.tracker.getTrackerVersion() if eyelink_ver == 3: tvstr = self.tracker.getTrackerVersionString() vindex = tvstr.find("EYELINK CL") tracker_software_ver = int( float(tvstr[(vindex + len("EYELINK CL")):].strip())) if eyelink_ver >= 2: self.tracker.sendCommand("select_parser_configuration 0") if eyelink_ver == 2: #turn off scenelink camera stuff self.tracker.sendCommand("scene_camera_gazemap = NO") else: self.tracker.sendCommand("saccade_velocity_threshold = 35") self.tracker.sendCommand( "saccade_acceleration_threshold = 9500") # set EDF file contents self.tracker.sendCommand( "file_event_filter = LEFT,RIGHT,FIXATION,SACCADE,BLINK,MESSAGE,BUTTON" ) if tracker_software_ver >= 4: self.tracker.sendCommand( "file_sample_data = LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS,HTARGET" ) else: self.tracker.sendCommand( "file_sample_data = LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS") # set link data (used for gaze cursor) self.tracker.sendCommand( "link_event_filter = LEFT,RIGHT,FIXATION,SACCADE,BLINK,BUTTON") if tracker_software_ver >= 4: self.tracker.sendCommand( "link_sample_data = LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS,HTARGET" ) else: self.tracker.sendCommand( "link_sample_data = LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS") if not self.doneSetup: self.tracker.doTrackerSetup() self.doneSetup = True else: while 1: try: error = self.tracker.doDriftCorrect( self.screen.size[0] / 2, self.screen.size[1] / 2, 1, 1) if error != 27: # ?? from example break else: self.tracker.doTrackerSetup() except: break self.screen.parameters.bgcolor = 106.0 / 255.0, 147.0 / 255.0, 0.0 # Load road data from file and create an image roadArray = numpy.loadtxt('road' + str(road) + '.txt') # Convert to a Path roadPath = ImagePath.Path( map(lambda xy: (xy[0], xy[1]), roadArray.tolist())) # Use Path to create a plot of the road im = Image.new("RGB", (2000, 100), (50, 50, 50)) draw = ImageDraw.Draw(im) # draw each side of the road separately draw.line(roadPath[:4000], fill=(200, 200, 200)) draw.line(roadPath[4000:], fill=(200, 200, 200)) del draw # Lay out a road texture in the x-z plane roadTexture = Texture(im) del im eye_height = 2.5 vertices = [(-10, -eye_height, 0), (-10, -eye_height, -1000), (10, -eye_height, 0), (10, -eye_height, -1000)] rect = TextureStimulus3D(texture=roadTexture, lowerleft=vertices[0], lowerright=vertices[1], upperleft=vertices[2], upperright=vertices[3]) # We will use these later for our camera transforms self.camera_matrix = ModelView() self.frame_timer = FrameTimer() self.outf = open( 'steersim-' + str(trial) + '-' + str(road) + '-out.txt', 'wb') # Vewport for the road viewport3D = Viewport( screen=self.screen, projection=SimplePerspectiveProjection(fov_x=75.2), camera_matrix=self.camera_matrix, stimuli=[rect]) # Construct a sky sky_l = 0 sky_r = self.screen.size[0] sky_t = self.screen.size[1] sky_b = self.screen.size[1] / 2 sky_vertices = [(sky_l, sky_t, 0), (sky_r, sky_t, 0), (sky_r, sky_b, 0), (sky_l, sky_b, 0)] sky = Rectangle3D(color=(144.0 / 255.0, 190.0 / 255.0, 1.0), vertex1=sky_vertices[0], vertex2=sky_vertices[1], vertex3=sky_vertices[2], vertex4=sky_vertices[3]) wheelTexture = Texture('wheel.png') self.wheel = TextureStimulus(texture=wheelTexture, internal_format=gl.GL_RGBA, position=(self.center, -75), anchor='center') # display the sky in its own viewport viewport2D = Viewport(screen=self.screen) viewport2D.parameters.stimuli = [sky, self.wheel] self.init_state() askText = Text(text='Press a key to start', anchor='center', position=(self.center, self.screen.size[1] / 2)) splash = Viewport(screen=self.screen) splash.parameters.stimuli = [askText] self.askForNext = Presentation(go_duration=(0.5, 'seconds'), viewports=[splash]) self.askForNext.add_controller( None, None, FunctionController(during_go_func=self.wait_for_key)) self.askForNext.parameters.enter_go_loop = True self.askForNext.run_forever() self.simPres = Presentation(go_duration=(duration, 'seconds'), viewports=[viewport3D, viewport2D], handle_event_callbacks=[ (pygame.KEYDOWN, self.check_keypress) ]) self.simPres.add_controller( None, None, FunctionController(during_go_func=self.update)) if doEyetrack: startTime = pylink.currentTime() self.tracker.sendMessage("SYNCTIME %d" % (pylink.currentTime() - startTime)) error = self.tracker.startRecording(1, 1, 1, 1) self.tracker.sendMessage("PRES %d START" % (trial)) self.simPres.go() if doEyetrack: self.tracker.sendMessage("PRES %d END" % (trial)) self.tracker.stopRecording() # File transfer and cleanup! self.tracker.setOfflineMode() pylink.msecDelay(500) #Close the file and transfer it to Display PC self.tracker.closeDataFile() self.tracker.receiveDataFile(edfFileName, edfFileName) self.outf.close() if self.quit: raise SystemExit
def __init__(self, experiment, resolution, data_file=u'default.edf', fg_color=(255, 255, 255), bg_color=(0, 0, 0), saccade_velocity_threshold=35, saccade_acceleration_threshold=9500, force_drift_correct=False): """<DOC> Constructor. Initializes the connection to the Eyelink. Arguments: experiment -- The experiment object. resolution -- A (width, height) tuple. Keyword arguments: data_file -- The name of the EDF file. (default=u'default.edf') fg_color -- The foreground color for the calibration screen. # (default=255,255,255) bg_color -- The background color for the calibration screen. # (default=0,0,0) saccade_velocity_threshold -- The velocity threshold used for # saccade detection. (default=35) saccade_acceleration_threshold -- The acceleration threshold used # for saccade detection. # (default=9500) force_drift_correct -- Indicates whether drift correction # should be enabled. This is useful # only for Eyelink 1000 models, for # which drift correction is disabled # by default. (default=False) Returns: True on connection success and False on connection failure. </DOC>""" global _eyelink stem, ext = os.path.splitext(data_file) if len(stem) > 8 or len(ext) > 4: raise exceptions.runtime_error( \ u'The Eyelink cannot handle filenames longer than 8 characters (plus .EDF extension)') self.experiment = experiment self.data_file = data_file self.resolution = resolution self.recording = False self.cal_beep = True self.cal_target_size = 16 self.experiment.eyelink_esc_pressed = False self.saccade_velocity_treshold = saccade_velocity_threshold self.saccade_acceleration_treshold = saccade_acceleration_threshold self.eye_used = None self.left_eye = 0 self.right_eye = 1 self.binocular = 2 # Only initialize the eyelink once if _eyelink == None: try: _eyelink = pylink.EyeLink() except Exception as e: raise exceptions.runtime_error( \ u'Failed to connect to the tracker: %s' % e) graphics_env = eyelink_graphics(self.experiment, _eyelink) pylink.openGraphicsEx(graphics_env) # Optionally force drift correction. For some reason this must be done # as (one of) the first thingsm otherwise a segmentation fault occurs. if force_drift_correct: self.send_command('driftcorrect_cr_disable = OFF') pylink.getEYELINK().openDataFile(self.data_file) pylink.flushGetkeyQueue() pylink.getEYELINK().setOfflineMode() # Notify the eyelink of the display resolution self.send_command('screen_pixel_coords = 0 0 %d %d' % ( \ self.resolution[0], self.resolution[1])) # Determine the software version of the tracker self.tracker_software_ver = 0 self.eyelink_ver = pylink.getEYELINK().getTrackerVersion() if self.eyelink_ver == 3: tvstr = pylink.getEYELINK().getTrackerVersionString() vindex = tvstr.find("EYELINK CL") self.tracker_software_ver = int(float(tvstr[(vindex + \ len("EYELINK CL")):].strip())) # Some configuration stuff (not sure what the parser and gazemap mean) if self.eyelink_ver >= 2: self.send_command("select_parser_configuration 0") if self.eyelink_ver == 2: #turn off scenelink camera stuff self.send_command("scene_camera_gazemap = NO") else: self.send_command("saccade_velocity_threshold = %d" % \ self.saccade_velocity_threshold) self.send_command("saccade_acceleration_threshold = %s" % \ self.saccade_acceleration_threshold) # Set EDF file contents self.send_command( \ "file_event_filter = LEFT,RIGHT,FIXATION,SACCADE,BLINK,MESSAGE,BUTTON") if self.tracker_software_ver >= 4: self.send_command( \ "file_sample_data = LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS,HTARGET") else: self.send_command( \ "file_sample_data = LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS") # Set link data. This specifies which data is sent through the link and # thus be used in gaze contingent displays self.send_command( \ "link_event_filter = LEFT,RIGHT,FIXATION,SACCADE,BLINK,BUTTON") self.send_command( \ "link_event_data = GAZE,GAZERES,HREF,AREA,VELOCITY,STATUS") if self.tracker_software_ver >= 4: self.send_command( \ "link_sample_data = LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS,HTARGET") else: self.send_command( \ "link_sample_data = LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS") # Not sure what this means. Maybe the button that is used to end drift # correction? self.send_command("button_function 5 'accept_target_fixation'") # Make sure that we are connected to the eyelink before we start # further communication if not self.connected(): raise exceptions.runtime_error( \ "Failed to connect to the eyetracker")
def __init__(self, display, resolution=DISPSIZE, data_file=LOGFILENAME + ".edf", fg_color=FGC, bg_color=BGC, eventdetection=EVENTDETECTION, saccade_velocity_threshold=35, saccade_acceleration_threshold=9500, force_drift_correct=True, pupil_size_mode=EYELINKPUPILSIZEMODE, **args): """See pygaze._eyetracker.baseeyetracker.BaseEyeTracker""" # try to import copy docstring (but ignore it if it fails, as we do # not need it for actual functioning of the code) try: copy_docstr(BaseEyeTracker, libeyelink) except: # we're not even going to show a warning, since the copied # docstring is useful for code editors; these load the docs # in a non-verbose manner, so warning messages would be lost pass global _eyelink # Make sure that we have a valid data file. The local_data_file may # contain a folder. The eyelink_data_file is only a basename, i.e. # without folder. The eyelink_data_file must be at most eight characters # and end with a `.edf` extension. self.local_data_file = data_file self.eyelink_data_file = os.path.basename(data_file) stem, ext = os.path.splitext(self.eyelink_data_file) if len(stem) > 8 or ext.lower() != '.edf': raise Exception( "The EyeLink cannot handle filenames longer than eight " "characters (excluding '.edf' extension).") # properties self.display = display self.fontsize = 18 self.scr = Screen(disptype=DISPTYPE, mousevisible=False) self.kb = Keyboard(keylist=["escape", "q"], timeout=1) self.resolution = resolution self.recording = False self.saccade_velocity_treshold = saccade_velocity_threshold self.saccade_acceleration_treshold = saccade_acceleration_threshold self.eye_used = None self.left_eye = 0 self.right_eye = 1 self.binocular = 2 self.pupil_size_mode = pupil_size_mode self.prevsample = (-1, -1) self.prevps = -1 # event detection properties # degrees; maximal distance from fixation start (if gaze wanders beyond # this, fixation has stopped) self.fixtresh = 1.5 # milliseconds; amount of time gaze has to linger within self.fixtresh # to be marked as a fixation self.fixtimetresh = 100 # degrees per second; saccade velocity threshold self.spdtresh = self.saccade_velocity_treshold # degrees per second**2; saccade acceleration threshold self.accthresh = self.saccade_acceleration_treshold self.set_detection_type(eventdetection) # weighted distance, used for determining whether a movement is due to # measurement error (1 is ok, higher is more conservative and will # result in only larger saccades to be detected) self.weightdist = 10 # distance between participant and screen in cm self.screendist = SCREENDIST # distance between participant and screen in cm self.screensize = SCREENSIZE self.pixpercm = (self.resolution[0]/float(self.screensize[0]) + \ self.resolution[1]/float(self.screensize[1])) / 2.0 # only initialize eyelink once if _eyelink == None: try: _eyelink = pylink.EyeLink() except: raise Exception( "Error in libeyelink.libeyelink.__init__(): Failed to " "connect to the tracker!") # determine software version of tracker self.tracker_software_ver = 0 self.eyelink_ver = pylink.getEYELINK().getTrackerVersion() if self.eyelink_ver == 3: tvstr = pylink.getEYELINK().getTrackerVersionString() vindex = tvstr.find("EYELINK CL") self.tracker_software_ver = int(float(tvstr[(vindex + \ len("EYELINK CL")):].strip())) if self.eyelink_ver == 1: self.eyelink_model = 'EyeLink I' elif self.eyelink_ver == 2: self.eyelink_model = 'EyeLink II' elif self.eyelink_ver == 3: self.eyelink_model = 'EyeLink 1000' else: self.eyelink_model = 'EyeLink (model unknown)' # Open graphics self.eyelink_graphics = EyelinkGraphics(self, _eyelink) pylink.openGraphicsEx(self.eyelink_graphics) # Optionally force drift correction. For some reason this must be done # as (one of) the first things, otherwise a segmentation fault occurs. if force_drift_correct: self.send_command('driftcorrect_cr_disable = OFF') # Set pupil-size mode if self.pupil_size_mode == 'area': pylink.getEYELINK().setPupilSizeDiameter(False) elif self.pupil_size_mode == 'diameter': pylink.getEYELINK().setPupilSizeDiameter(True) else: raise Exception( "pupil_size_mode should be 'area' or 'diameter', not %s" \ % self.pupil_size_mode) pylink.getEYELINK().openDataFile(self.eyelink_data_file) pylink.flushGetkeyQueue() pylink.getEYELINK().setOfflineMode() # notify eyelink of display resolution self.send_command("screen_pixel_coords = 0 0 %d %d" % \ (self.resolution[0], self.resolution[1])) # get some configuration stuff if self.eyelink_ver >= 2: self.send_command("select_parser_configuration 0") if self.eyelink_ver == 2: # turn off scenelink camera stuff self.send_command("scene_camera_gazemap = NO") # set EDF file contents (this specifies which data is written to the EDF # file) self.send_command( "file_event_filter = LEFT,RIGHT,FIXATION,SACCADE,BLINK,MESSAGE,BUTTON" ) if self.tracker_software_ver >= 4: self.send_command( "file_sample_data = LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS,HTARGET" ) else: self.send_command( "file_sample_data = LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS") # set link data (this specifies which data is sent through the link and # thus can be used in gaze contingent displays) self.send_command( "link_event_filter = LEFT,RIGHT,FIXATION,SACCADE,BLINK,BUTTON") if self.tracker_software_ver >= 4: self.send_command( "link_sample_data = LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS,HTARGET" ) else: self.send_command( "link_sample_data = LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS") # not quite sure what this means (according to Sebastiaan Mathot, it # might be the button that is used to end drift correction?) self.send_command("button_function 5 'accept_target_fixation'") if not self.connected(): raise Exception( "Error in libeyelink.libeyelink.__init__(): Failed to connect " "to the eyetracker!")
def __init__(self, resolution, data_file = "default.edf", fg_color = (255, 255, 255), bg_color = (0, 0, 0), saccade_velocity_threshold = 35, saccade_acceleration_threshold = 9500): """ Initializes the connection to the Eyelink Parameters: _resolution: (width, height) tuple _data_file: the name of the EDF file Returns: True on connection success and False on connection failure """ global _eyelink self.data_file = data_file self.resolution = resolution self.recording = False self.saccade_velocity_treshold = saccade_velocity_threshold self.saccade_acceleration_treshold = saccade_acceleration_threshold self.eye_used = None self.left_eye = 0 self.right_eye = 1 self.binocular = 2 # Only initialize the eyelink once if _eyelink == None: try: _eyelink = pylink.EyeLink() except Exception as e: raise exceptions.runtime_error("Failed to connect to the tracker: %s" % e) graphics_env = eyelink_graphics(_eyelink) pylink.openGraphicsEx(graphics_env) pylink.getEYELINK().openDataFile(self.data_file) pylink.flushGetkeyQueue() pylink.getEYELINK().setOfflineMode() # Notify the eyelink of the display resolution self.send_command("screen_pixel_coords = 0 0 %d %d" % (self.resolution[0], self.resolution[1])) # Determine the software version of the tracker self.tracker_software_ver = 0 self.eyelink_ver = pylink.getEYELINK().getTrackerVersion() if self.eyelink_ver == 3: tvstr = pylink.getEYELINK().getTrackerVersionString() vindex = tvstr.find("EYELINK CL") self.tracker_software_ver = int(float(tvstr[(vindex + len("EYELINK CL")):].strip())) # Set some configuration stuff (not sure what the parser and gazemap mean) if self.eyelink_ver >= 2: self.send_command("select_parser_configuration 0") if self.eyelink_ver == 2: #turn off scenelink camera stuff self.send_command("scene_camera_gazemap = NO") else: self.send_command("saccade_velocity_threshold = %d" % self.saccade_velocity_threshold) self.send_command("saccade_acceleration_threshold = %s" % self.saccade_acceleration_threshold) # Set EDF file contents. This specifies which data is written to the EDF file. self.send_command("file_event_filter = LEFT,RIGHT,FIXATION,SACCADE,BLINK,MESSAGE,BUTTON") if self.tracker_software_ver >= 4: self.send_command("file_sample_data = LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS,HTARGET") else: self.send_command("file_sample_data = LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS") # Set link data. This specifies which data is sent through the link and thus can # be used in gaze contingent displays self.send_command("link_event_filter = LEFT,RIGHT,FIXATION,SACCADE,BLINK,BUTTON") if self.tracker_software_ver >= 4: self.send_command("link_sample_data = LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS,HTARGET") else: self.send_command("link_sample_data = LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS") # Not sure what this means. Maybe the button that is used to end drift correction? self.send_command("button_function 5 'accept_target_fixation'") if not self.connected(): raise exceptions.runtime_error("Failed to connect to the eyetracker")
def __init__(self,edfsubject): # Make filename self.fname = os.path.splitext(edfsubject)[0] # strip away extension if present assert re.match(r'\w+$', self.fname), 'Name must only include A-Z, 0-9, or _' assert len(self.fname) <= 8, 'Name must be <= 8 characters.' # Make filename self.edfname = self.fname + '.edf' # Initialize connection with eyetracker try: self.tracker = pylink.EyeLink() self.realconnect = True except RuntimeError: self.tracker = pylink.EyeLink(None) self.realconnect = False #properties #screen self.w = GetSystemMetrics(0) self.h = GetSystemMetrics(1) #find out which eye self.left_eye = 0 self.right_eye = 1 self.binocular = 2 #gaze-timing self.GCWINDOW = .5 #500 msec self.DURATION = 2 #2000 msec self.gbox = 200 #gaze boundary self.inbox = False self.Finished = False self.Fixation = True #gaze-bounding box self.sc = [self.w / 2.0, self.h / 2.0] #center of screen self.size = 100 #Length of one side of box self.xbdr = [self.sc[0] - self.size, self.sc[0] + self.size] self.ybdr = [self.sc[1] - self.size, self.sc[1] + self.size] #calibration self.cnum = 13 # 13 pt calibration self.paval = 1000 #Pacing of calibration, t in milliseconds #pupil self.red = 'red' self.green = 'green' self.blue = 'blue' # Open EDF pylink.getEYELINK().openDataFile(self.edfname) pylink.flushGetkeyQueue() pylink.getEYELINK().setOfflineMode() # notify eyelink of display resolution pylink.getEYELINK().sendCommand("screen_pixel_coords = 0 0 %d %d" %(self.w - 1, self.h - 1)) pylink.getEYELINK().sendMessage("DISPLAY_COORDS 0 0 %d %d" %(self.w - 1, self.h - 1)) # Set content of edf file pylink.getEYELINK().sendCommand( 'file_event_filter = LEFT,RIGHT,FIXATION,SACCADE,BLINK,MESSAGE,BUTTON,INPUT') pylink.getEYELINK().sendCommand( 'link_event_filter = LEFT,RIGHT,FIXATION,SACCADE,BLINK,BUTTON') pylink.getEYELINK().sendCommand( 'link_sample_data = LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS,HTARGET') pylink.getEYELINK().sendCommand( 'file_sample_data = LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS,HTARGET,INPUT') # Set display coords for dataviewer pylink.getEYELINK().sendMessage("screen_pixel_coords = 0 0 %d %d" %(self.w - 1, self.h - 1)) pylink.getEYELINK().sendMessage("DISPLAY_COORDS 0 0 %d %d" %(self.w - 1, self.h - 1))
def __init__(self, win, clock, sj="TEST", saccadeSensitivity=HIGH, calibrationType='HV9', calibrationTargetColor=WHITE, calibrationBgColor=BLACK, CalibrationSounds=False, screen=(1024, 768)): '''win: psychopy visual window used for the experiment clock: psychopy time clock recording time for whole experiment sj: Subject identifier string (affects EDF filename) saccadeSensitivity: HIGH: Pursuit and neurological work LOW: Cognitive research calibrationType: H3: Horizontal 3-point HV3: 3-point calibration, poor linearization HV5: 5-point calibration, poor at corners HV9: 9-point calibration, best overall calibrationTargetColor and calibrationBgColor: RGB tuple, i.e., (255,0,0) for Red One of: BLACK, WHITE, GRAY calibrationSounds: True: enable feedback sounds when calibrating''' self.edfFileName = str( sj) + ".EDF" # Subject name only can put 8 characters print("Connecting to eyetracker.") self.tracker = pylink.EyeLink() self.timeCorrection = clock.getTime() - self.tracker.trackerTime() print("Loading custom graphics") #Initializes Experiment Graphics genv = EyeLinkCoreGraphicsPsychopy(self.tracker, win, screen) pylink.openGraphicsEx(genv) # opendatafile self.tracker.openDataFile(self.edfFileName) #EyeLink Tracker Configuration pylink.flushGetkeyQueue() # Initializes the key queue used by getkey(). It may be called at any time to get rid any of old keys from the queue. self.tracker.setOfflineMode() #Places EyeLink tracker in off-line (idle) mode. Wait till the tracker has finished the mode transition self.tracker.sendCommand("screen_pixel_coords = 0 0 %d %d" % (tuple(screen))) self.tracker.setCalibrationType(calibrationType) self.tracker.sendCommand( "driftcorrect_cr_disable=OFF" ) #CF - OFF: turns on drift CORRECT; AUTO: Turns on drift CHECK; ON: Turns off both #self.tracker.sendCommand("generate_default_targets = NO") #self.tracker.sendCommand("calibration_targets = 512,384 512,417 512,351 402,384 622,384 402,417 622,417 402,351 622,351") #self.tracker.sendCommand("validation_targets = 512,384 512,417 512,351 402,384 622,384 402,417 622,417 402,351 622,351") self.tracker.sendMessage("DISPLAY_COORDS 0 0 %d %d" % (tuple(screen))) eyelink_ver = self.tracker.getTrackerVersion() if eyelink_ver == 3: tvstr = self.tracker.getTrackerVersionString() vindex = tvstr.find("EYELINK CL") tracker_software_ver = int( float(tvstr[(vindex + len("EYELINK CL")):].strip())) else: tracker_software_ver = 0 if eyelink_ver >= 2: self.tracker.sendCommand("select_parser_configuration %d" % saccadeSensitivity) else: if saccadeSensitivity == HIGH: svt, sat = 22, 5000 else: svt, sat = 30, 9500 self.tracker.sendCommand("saccade_velocity_threshold = %d" % svt) self.tracker.sendCommand("saccade_acceleration_threshold = %d" % sat) if eyelink_ver == 2: #turn off scenelink camera stuff self.tracker.sendCommand("scene_camera_gazemap = NO") # set EDF file contents self.tracker.setFileEventFilter( "LEFT,RIGHT,FIXATION,SACCADE,BLINK,MESSAGE,BUTTON") if tracker_software_ver >= 4: self.tracker.setFileSampleFilter( "LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS,HTARGET") else: self.tracker.setFileSampleFilter( "LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS") # set link data (used for gaze cursor) self.tracker.setLinkEventFilter( "LEFT,RIGHT,FIXATION,SACCADE,BLINK,BUTTON") if tracker_software_ver >= 4: self.tracker.setLinkSampleFilter( "LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS,HTARGET") else: self.tracker.setLinkSampleFilter( "LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS") #self.tracker.setAcceptTargetFixationButton(1) # This programs a specific button for use in drift correction. #Set the calibration settings: #pylink.setCalibrationColors(WHITE, BLACK) # Sets the calibration target and background color(foreground_color, background_color) if CalibrationSounds: pylink.setCalibrationSounds("", "", "") pylink.setDriftCorrectSounds("", "off", "off") else: pylink.setCalibrationSounds("off", "off", "off") pylink.setDriftCorrectSounds("off", "off", "off") print("Beginning tracker setup") self.tracker.doTrackerSetup()
def run(stim_path, idx_path, on_msec_length=300, off_msec_length=200, final_blank_sec_length=16, init_blank_sec_length=16, fix_pix_size=20, fix_button_prob=1 / 6., eyetracker=None, edf_path=None, **monitor_kwargs): """run one run of the experiment stim_path specifies the path of the unshuffled experiment stimuli, while idx_path specifies the path of the shuffled indices to use for this run. This function will load in the stimuli at stim_path and rearrange them using the indices found at idx_path, then simply go through those stimuli in order, showing each stimuli for `on_msec_length` msecs and then a blank screen for `off_msec_length` msecs (or as close as possible, given the monitor's refresh rate). For fixation, we show a stream of digits whose colors alternate between black and white, with a `fix_button_prob` chance of repeating. Digits are presented with alternating stimuli ON and OFF blocks, so that a digit will be shown for on_msec_length+off_msec_length msecs and then there will be nothing at fixation for the next on_msec_length+off_msec_length msecs. For now, you can't change this. All stimuli loaded in from stim_path will be shown. Arguments ============ stim_path: string, path to .npy file where stimuli are stored (as 3d array) idx_path: string, path to .npy file where shuffled indices are stored (as 1d array) on_msec_length: int, length of the ON blocks in milliseconds; that is, the length of time to display each stimulus before moving on off_msec_length: int, length of the OFF blocks in milliseconds; that is, the length of time to between stimuli fix_pix_size: int, the size of the fixation digits, in pixels. fix_button_prob: float. the probability that the fixation digit will repeat or the fixation dot will change color (will never repeat more than once in a row). For fixation digit, this probability is relative to each stimulus presentation / ON block starting; for fixation dot, it's each stimulus change (stimulus ON or OFF block starting). eyetracker: EyeLink object or None. if None, will not collect eyetracking data. if not None, will gather it. the EyeLink object must already be initialized (by calling the _setup_eyelink function, as is done in the expt function). if this is set, must also specify edf_path edf_path: str or None. if eyetracker is not None, this must be a string, which is where we will save the output of the eyetracker """ stimuli, idx, expt_params, monitor_kwargs = _set_params( stim_path, idx_path, on_msec_length, off_msec_length, fix_button_prob, final_blank_sec_length, init_blank_sec_length, **monitor_kwargs) win = visual.Window(**monitor_kwargs) win.mouseVisible = False # linear gamma ramp win.gammaRamp = np.tile(np.linspace(0, 1, 256), (3, 1)) fixation = visual.TextStim(win, next(expt_params['fixation_text']), height=fix_pix_size, color=None) fixation.color = next(expt_params['fixation_color']) # first one is special: we preload it, but we still want to include it in the iterator so the # numbers all match up (we don't draw or wait during the on part of the first iteration) img = visual.ImageStim(win, image=imagetools.array2image(stimuli[0]), size=expt_params['stim_size']) if eyetracker is not None: assert edf_path is not None, "edf_path must be set so we can save the eyetracker output!" eyetracker.openDataFile('temp.EDF') pylink.flushGetkeyQueue() eyetracker.startRecording(1, 1, 1, 1) wait_text = visual.TextStim( win, ("Press 5 to start\nq will quit this run\nescape will quit " "this session")) wait_text.draw() win.flip() # preload these to save time img.draw() fixation.draw() clock = core.Clock() # wait until receive 5, which is the scanner trigger all_keys = event.waitKeys(keyList=['5', 'q', 'escape'], timeStamped=clock) if 'q' in [k[0] for k in all_keys] or 'escape' in [k[0] for k in all_keys]: win.close() return all_keys, [], [], expt_params, idx keys_pressed = [(key[0], key[1]) for key in all_keys] timings = [("start", "off", clock.getTime())] fixation_info = [] for i, stim in enumerate(stimuli): if i > 0: # we don't wait the first time, and all these have been preloaded while we were waiting # for the scan trigger if "fixation_text" in expt_params: fixation.text = next(expt_params['fixation_text']) img.image = imagetools.array2image(stim) fixation.color = next(expt_params['fixation_color']) img.draw() fixation.draw() next_stim_time = (i * on_msec_length + i * off_msec_length - 2) / 1000. core.wait(abs(clock.getTime() - timings[0][2] - next_stim_time)) if eyetracker is not None: eyetracker.sendMessage("TRIALID %02d" % i) win.flip() timings.append(("stimulus_%d" % i, "on", clock.getTime())) fixation_info.append((fixation.text, clock.getTime())) fixation.draw() next_stim_time = ( (i + 1) * on_msec_length + i * off_msec_length - 1) / 1000. core.wait(abs(clock.getTime() - timings[0][2] - next_stim_time)) win.flip() timings.append(("stimulus_%d" % i, "off", clock.getTime())) all_keys = event.getKeys(timeStamped=clock) if all_keys: keys_pressed.extend([(key[0], key[1]) for key in all_keys]) if 'q' in [k[0] for k in all_keys] or 'escape' in [k[0] for k in all_keys]: break if eyetracker is not None: eyetracker.stopRecording() eyetracker.closeDataFile() eyetracker.receiveDataFile('temp.EDF', edf_path) win.close() return keys_pressed, fixation_info, timings, expt_params, idx