This is a more detailed version of the four step guide to a functional application that's described on the Getting started page. This guide is aimed at the first-time user of Tobii Pro SDK, who perhaps also is pretty new to programming in Matlab/Octave.
The following text is meant to guide you - a new user of the Tobii Pro SDK (and maybe also new to eye tracking and programming in Matlab/Octave) - to writing your first eye tracking study application!
Prerequisites: Matlab and/or Octave and Pro SDK should be installed on your computer (see installation section on the Getting started page),
and there should be an eye tracker connected, either via USB or network.
This guide will not provide a complete runnable script that you can just copy-paste into your editor and run. Instead we try to describe the concepts and reasons behind the code, and you can choose to use (or copy-paste...) these snippets either in your existing Matlab/Octave code, or in a completely new file. However, if you want the simplest of scenarios, you can copy-paste every line of code described here, in the order they appear, into a new file, and it should run nicely.
Before you can start using Pro SDK functions in your Matlab or Octave application, you need to make sure the Tobii Pro SDK is available in your environment. This can be done by running your code in the same folder where you extracted the Tobii Pro SDK package, or alternatively, and as better way, you should add the path of the folder containing the Tobii Pro SDK to the Matlab or Octave environment.
addpath(genpath('path'))
Now you're ready to start working with Tobii Pro eye tracking!
In the EyeTrackingOperations
class there's a function for searching for eye trackers: find_all_eyetrackers()
.
So start by creating an instance of the EyeTrackingOperations
class:
tobii = EyeTrackingOperations();
find_all_eyetrackers()
and assign the output to a new variable: found_eyetrackers = tobii.find_all_eyetrackers()
find_all_eyetrackers()
is an array of EyeTracker
objects.
You can access the meta data of the (first) eye tracker, and print it, like this: my_eyetracker = found_eyetrackers(1) disp(["Address: ", my_eyetracker.Address]) disp(["Model: ", my_eyetracker.Model]) disp(["Name (It's OK if this is empty): ", my_eyetracker.Name]) disp(["Serial number: ", my_eyetracker.SerialNumber])
Let's be blunt, calibration is a bit complicated. So, if this is indeed your first eye tracking application, we recommend that you either skip calibration (all Tobii Pro eye trackers are pre-configured with a default calibration, so you will get gaze data even if you skip calibration), or use Tobii Pro Eye Tracker Manager to perform the calibration. You can calibrate the eye tracker with Tobii Pro Eye Tracker Manager before running your application, or call Tobii Pro Eye Tracker Manager with a command line parameter (from within your code) that launches directly into calibration mode. Read more here.
If you really want to dig into how to create your own calibration procedure, read the calibration part of the Common concepts area of this site,
and check out the calibration code example in the SDK reference guide.
The eye tracker outputs a gaze data sample at a regular interval (30, 60, 120, 300, etc, times per seconds, depending on the model and frequency setting). To get hold of this data, you tell the Tobii Pro SDK that you want to start collecting gaze data, using the method from the eye tracker object previously created.
my_eyetracker.get_gaze_data();The first call to this method simply starts the data callection and the subsequent calls return the data collected in between each call. This will start to collect gaze data in the background, so if you want to collect data for a second simply use:
pause(1);Now we are able to fetch the data collected during that time:
gaze_data = my_eyetracker.get_gaze_data();The gaze_data variable will be an array of objects of the
GazeData
class.
We can access the latest data point collected:
latest_gaze_data = gaze_data(end);Now you can access the data as the following example suggests:
fprintf('SystemRequestTimeStamp: %d\n',latest_gaze_data.SystemTimeStamp); fprintf('DeviceTimeStamp: %d\n',latest_gaze_data.DeviceTimeStamp); disp('Left Eye'); fprintf('GazePoint.OnDisplayArea: %.2f %.2f\n',latest_gaze_data.LeftEye.GazePoint.OnDisplayArea); fprintf('GazePoint.InUserCoordinateSystem: %.2f %.2f %.2f\n',latest_gaze_data.LeftEye.GazePoint.InUserCoordinateSystem); fprintf('GazePoint.Validity: %d\n',latest_gaze_data.LeftEye.GazePoint.Validity.value); fprintf('GazeOrigin.InUserCoordinateSystem: %.2f %.2f %.2f\n',latest_gaze_data.LeftEye.GazeOrigin.InUserCoordinateSystem); fprintf('GazeOrigin.InTrackBoxCoordinateSystem: %.2f %.2f %.2f\n',latest_gaze_data.LeftEye.GazeOrigin.InTrackBoxCoordinateSystem); fprintf('GazeOrigin.Validity: %d\n',latest_gaze_data.LeftEye.GazeOrigin.Validity.value); fprintf('Pupil.Diameter: %.2f\n',latest_gaze_data.LeftEye.Pupil.Diameter); fprintf('Pupil.Validity: %d\n',latest_gaze_data.LeftEye.Pupil.Validity.value); disp('Right Eye'); fprintf('GazePoint.OnDisplayArea: %.2f %.2f\n',latest_gaze_data.RightEye.GazePoint.OnDisplayArea); fprintf('GazePoint.InUserCoordinateSystem: %.2f %.2f %.2f\n',latest_gaze_data.RightEye.GazePoint.InUserCoordinateSystem); fprintf('GazePoint.Validity: %d\n',latest_gaze_data.RightEye.GazePoint.Validity.value); fprintf('GazeOrigin.InUserCoordinateSystem: %.2f %.2f %.2f\n',latest_gaze_data.RightEye.GazeOrigin.InUserCoordinateSystem); fprintf('GazeOrigin.InTrackBoxCoordinateSystem: %.2f %.2f %.2f\n',latest_gaze_data.RightEye.GazeOrigin.InTrackBoxCoordinateSystem); fprintf('GazeOrigin.Validity: %d\n',latest_gaze_data.RightEye.GazeOrigin.Validity.value); fprintf('Pupil.Diameter: %.2f\n',latest_gaze_data.RightEye.Pupil.Diameter); fprintf('Pupil.Validity: %d\n',latest_gaze_data.RightEye.Pupil.Validity.value);Please note that our MATLAB SDK handles temporary storage of gaze data for you (in between each
.get_gaze_data()call), unlike other languages' SDKs, by using a large, expandable buffer. This means that the risk of a stream buffer overflow is greatly reduced and you do not need to worry about data loss as much, since this temporary storage is handled very efficiently. However, if you have a very long-running experiment, e.g. longer than one hour, you may wish to call
.get_gaze_data()at appropriate points, such as between experiment stages, and store the data to a file. This helps prevent too much of the computer's RAM memory from being used up and slowing down the system. You should also generally avoid straining your computer through demanding tasks such as intense image manipulation or running heavy background programs during recording. This is because if the computer struggles to keep up overall, then it is likely that eye tracking data loss will also occur.
Now that we have collected the gaze data that we want, we should let the eye tracker (and SDK) know that we're done. You do this by stopping collection of gaze data:
my_eyetracker.stop_gaze_data()And that's all folks!