Tobii Pro SDK in Psychopy

Researchers in fields related to psychology have probably heard of PsychoPy; It is a Python-based software that made creating complex experiments much more accessible. However, adding eye tracking to our experiment can be difficult without previous experience. In this article I share script snippets to integrate a Tobii Pro eye tracker into a PsychoPy Builder experiment. These functions are available in the documentation of the SDK and here I am just showing an example of how they can be used. I have tested the scripts on the standalone PsychoPy on macOS. As mentioned on the SDK website, typing the following in terminal should install the SDK on our main python installation:

pip install tobii_research

After having installed the module we should make sure PsychoPy can find it by adding its path in PsychoPy’s settings. Then we can implement the bits and pieces needed to connect to the eye tracker and start recording. First off, right at the beginning of the experiment, we need to load the tobii_research module, look for available eye trackers and choose to the first one:

# import needed modules
import tobii_research as tr
# find eye trackers
found_eyetrackers = tr.find_all_eyetrackers()
# select first eye tracker
my_eyetracker = found_eyetrackers[0]

Then we need to create a list in which we save gaze data:

# create list in which we append gaze data
gaze_list = []

Then we create a call-back function that will append gaze data to the list every time it is called:

# create call back to get gaze data
# append device and eye tracker timestamps (ts and etts), gaze point left (gpl) and right (gpr)
def gaze_data_callback(gaze_data):
    gaze_list.append([gaze_data['system_time_stamp'],gaze_data['device_time_stamp'],gaze_data['left_gaze_point_on_display_area'],gaze_data['right_gaze_point_on_display_area']])

After that, we just need to call the function to start getting live data:

# start getting gaze data
my_eyetracker.subscribe_to(tr.EYETRACKER_GAZE_DATA, gaze_data_callback, as_dictionary=True)

Logging events as they occur in our experiment is very important, to be able to synchronize them with gaze data. To do so, we can add the time of trial start to the logged data in PsychoPy:

# load time module at the beginning of the experiment
import time

# get the time at the beginning of each trial (routine in PsychoPy's terms)
trialStartTime = time.time()

# save time to data, using the trial handler created by PsychoPy
trials.addData('trial.start',trialStartTime)

At the end of the experiment, after having shown all stimuli, we should disconnect from the eye tracker and save the gaze_list object that contains all our data:

# stop getting gaze data
my_eyetracker.unsubscribe_from(tr.EYETRACKER_GAZE_DATA, gaze_data_callback)

# load csv module and write gaze data to disk
import csv
with open(filename+'_et.csv', 'w') as f:
    w = csv.writer(f, delimiter=";")
    # add header for data selected in callback
    w.writerow(['ts','etts','gpl','gpr'])
    # iterate all items
    for row in gaze_list:
        # write row in csv
        w.writerow(row)

With these simple steps we can collect eye tracking data in our experiment. You can find a demo experiment with these modifications on github (both builder and coder).

Hope this can help you get started exploring eye tracking methods. Feel free to write me if you have any questions or suggestions.

P.S. In this article I did not get into calibration; It is more complicated than just connecting and getting gaze data from the eye tracker. It is worth mentioning that Tobii eye trackers have a built-in calibration that should work fairly well on most people. One could also use the Eye Tracker Manager to perform an individual calibration before running the experiment.