Psychopy and Pupil labs eye tracker

Hello All,

Has anyone tried to integrate pupil labs eye tracker into Psychopy?
I am new to research and programming. I have developed my experiment mainly through the builder interface of psychopy, I am now trying to synchronize timing between the 2 and I am struggling!!! The code for the stroop task is for the tobi eye tracker. I have also tried to implement the LSL protocol through one of the plugin available but no success as I am not sure how to receive the data.

I would appreciate any hints or help (baby language please :).

Thank you so much!

E

Hi elodie_rigal:
I’m running an experiment in psychopy wich involves pupil lab eye-tracker. Do you already know how to integrate them and synchronize timing ?
It would be very helpfull for me if you reply with a soluton, if you found one.
thanks you so much in advance!

Hello Pablo,

It’s been now a few months since I did this experiment. I used the code that you can find on Pupil Lab website https://docs.pupil-labs.com/#developer-docs but I ran the code on a separate python program (not directly from Psychopy) and was receiving the data on a separate port.
Here what I used to record the ‘gaze’.

Hope this helps.
E

import zmq
from msgpack import loads

context = zmq.Context()
# open a req port to talk to pupil
addr = '127.0.0.1'  # remote ip or localhost
req_port = "50020"  # same as in the pupil remote gui
req = context.socket(zmq.REQ)
req.connect("tcp://{}:{}".format(addr, req_port))
# ask for the sub port
req.send_string('SUB_PORT')
sub_port = req.recv_string()

# open a sub port to listen to pupil
sub = context.socket(zmq.SUB)
sub.connect("tcp://{}:{}".format(addr, sub_port))

# set subscriptions to topics
# recv just pupil/gaze/notifications
sub.setsockopt(zmq.SUBSCRIBE, 'pupil.')
# sub.setsockopt_string(zmq.SUBSCRIBE, 'gaze')
# sub.setsockopt_string(zmq.SUBSCRIBE, 'notify.')
# sub.setsockopt_string(zmq.SUBSCRIBE, 'logging.')
# or everything:
# sub.setsockopt_string(zmq.SUBSCRIBE, '')


print("pupil")
    except KeyboardInterrupt:
        break

Hi @Elodie_Rigal1
I’m trying to do the same thing. I have an experimentation that I created on psychopy and my participants will have eye tracking device. If you have time, can you explain to me more in details how to link psychopy and pupils. Is it on the same computer that you have both the experimentation and the eye tracking, or you work on two computers?
Thanks a lot for your help

Hello Elodie,

Do you have a paper or working paper related with this research?
I planning to run my economic experiments using Pupil Labs eye-trackers. So, I really need some guidance on how to conduct my research.

Thank you,
Sara

Hi everyone, I’m also trying to use the Pupil Labs eye tracker in an experiment with psychopy. There doesn’t seem to be so much out there and this is the only thread about Pupil Labs and psychopy… Did you all manage to connect the eye tracker with your experiment in psychopy?
Elodie wrote that she used code from the Pupil Labs website, but she ran the code on a separate python program… I’m still very new to python and psychopy, does this mean I need to run psychopy from pycharm or anaconda? Right now, I’m using the stand-alone version of psychopy. Does anyone know if I can connect to the eye tracker directly from psychopy?

Hi, I’m hoping to start work on controlling a Pupil Core tracker this week, so can hopefully share some tips as things progress.

There should be no reason not to be able to use standalone PsychoPy for this task. I suspect the reason the other poster used a separate Python script was to stream data from the tracker and record it - this would be difficult to do reliably from within a PsychoPy script that is also concerned with real-time stimulus presentation and response recording. I suspect (although haven’t started yet) that the simplest approach would be to use PsychoPy to control the experiment on the local computer and to remotely control the eye tracker, which means you could leave the data recording to happen on that separate computer, directly connected to the eye tracker via USB (rather than streaming the data over the network).

Hey Michael, thank you for you answer! I managed to connect eye tracker with my Psychopy experiment now and I actually have it running on the same computer. I’m not sure if that’s the ideal set-up but it works :slight_smile: I used some of the example scripts form pupil-helpers in the coder window of Psychopy, which was relatively easy to do. Next step is to send and receive triggers from my experiment so that I can link the eye data to events in my experiment… We’ll see how that goes!

Hi Jana,
could you please direct us towards the sources/scripts/codes using which one can connect pupil core with PsychoPy? Or perhaps show/send your own psychopy experiment? Also, how is your trigger working? I am also going to need to record data via pupil core and mark events in the signal (or initiate and stop recording using triggers at least), that’s why I am curious :slight_smile:
Any help would be greatly appreciated!
Best,
M.

Hi Martin,

So I’m using the standalone version of Psychopy and the code components to connect to the eye tracker. I used the code that Elodie also posted above. It took some trial and error until I managed to get it to run (same with the annotations) but it’s working now. Basically, I use a routine called “pupil-connect” at the beginning of the experiment, which contains this code:

if eyetracking == '1':
    import zmq
    import msgpack as serializer

    from time import sleep, time

    # Setup zmq context and remote helper
    ctx = zmq.Context()
    pupil_remote = zmq.Socket(ctx, zmq.REQ)
    pupil_remote.connect('tcp://127.0.0.1:50020')

    pupil_remote.send_string("PUB_PORT")
    pub_port = pupil_remote.recv_string()
    pub_socket = zmq.Socket(ctx, zmq.PUB)
    pub_socket.connect("tcp://127.0.0.1:" + str(pub_port))

    # set time to psychopy clock
    time_fn = core.monotonicClock.getTime

    # set pupil's time to psychopy time
    pupil_remote.send_string("T " + str(time_fn()))
    print(pupil_remote.recv_string())

    sleep(2.)

    # send notification:
    def notify(notification):
        """Sends ``notification`` to Pupil Remote"""
        topic = "notify." + notification["subject"]
        payload = serializer.dumps(notification, use_bin_type=True)
        pupil_remote.send_string(topic, flags=zmq.SNDMORE)
        pupil_remote.send(payload)
        return pupil_remote.recv_string()

    def send_trigger(trigger):
        payload = serializer.dumps(trigger, use_bin_type=True)
        pub_socket.send_string(trigger["topic"], flags=zmq.SNDMORE)
        pub_socket.send(payload)

    # Start the annotations plugin
    notify({"subject": "start_plugin", "name": "Annotation_Capture", "args": {}})

    # start recording
    pupil_remote.send_string('R')
    print(pupil_remote.recv_string())
    sleep(1.)
    

    def new_trigger(label, duration):
        return {
        "topic": "annotation",
        "label": label,
        "timestamp": time_fn(),
        "duration": duration,
        }

    label = "start_experiment"
    duration = 0.
    minimal_trigger = new_trigger(label, duration)
    send_trigger(minimal_trigger)
    sleep(1.)

else:
    continueRoutine = False

The code also contains the part of how to send annotations (see the annotations plugin and the trigger part). It’s still quite a journey but I hope this helps a bit!