Skip to content

Commit

Permalink
adds neon event component
Browse files Browse the repository at this point in the history
  • Loading branch information
domstoppable committed Sep 24, 2024
1 parent cd40eb4 commit f144f18
Show file tree
Hide file tree
Showing 10 changed files with 57 additions and 7 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
48 changes: 43 additions & 5 deletions psychopy_eyetracker_pupil_labs/pupil_labs/components.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from pathlib import Path

from psychopy.experiment.components import BaseVisualComponent, Param, getInitVals
from psychopy.experiment.components import BaseVisualComponent, BaseComponent, Param, getInitVals
from psychopy.localization import _translate


Expand All @@ -13,8 +13,8 @@ class AprilTagComponent(BaseVisualComponent):
_instances = []
_routine_start_written = False

def __init__(self, exp, parentName, marker_id=0, anchor="center", size=(0.2, 0.2), startType='time (s)', startVal=0.0, *args, **kwargs):
super().__init__(exp, parentName, size=size, startType=startType, startVal=startVal, *args, **kwargs)
def __init__(self, exp, parentName, name='aprilTag', marker_id=0, anchor="center", size=(0.2, 0.2), startType='time (s)', startVal=0.0, *args, **kwargs):
super().__init__(exp, parentName, name=name, size=size, startType=startType, startVal=startVal, *args, **kwargs)

self.type = 'Image'
self.url = "https://april.eecs.umich.edu/software/apriltag.html"
Expand Down Expand Up @@ -109,8 +109,8 @@ class AprilTagFrameComponent(BaseVisualComponent):
iconFile = Path(__file__).parent.parent / 'apriltag_frame.png'
tooltip = _translate('AprilTag: Markers to identify a screen surface')

def __init__(self, exp, parentName, h_count=4, v_count=3, marker_ids='', marker_size=0.125, marker_units="from exp settings", anchor="center", size=[2, 2], units="norm", startType='time (s)', startVal=0.0, *args, **kwargs):
super().__init__(exp, parentName, size=size, units=units, startType=startType, startVal=startVal, *args, **kwargs)
def __init__(self, exp, parentName, name='tagFrame', h_count=4, v_count=3, marker_ids='', marker_size=0.125, marker_units="from exp settings", anchor="center", size=[2, 2], units="norm", startType='time (s)', startVal=0.0, *args, **kwargs):
super().__init__(exp, parentName, name=name, size=size, units=units, startType=startType, startVal=startVal, *args, **kwargs)

self.type = 'Image'
self.url = "https://april.eecs.umich.edu/software/apriltag.html"
Expand Down Expand Up @@ -210,3 +210,41 @@ def writeRoutineStartCode(self, buff):
f" eyetracker.register_surface({inits['name']}.marker_verts, win_size_pix)\n")

buff.writeIndentedLines(code)


class NeonEventComponent(BaseComponent):
targets = ['PsychoPy']
categories = ['Eyetracking']
iconFile = Path(__file__).parent.parent / 'neon_event.png'
tooltip = _translate('Save a timestamped event in a Neon recording')

def __init__(self, exp, parentName, name='neonEvent', event_name='Event 1', timestamp_ns=0, startType='time (s)', startVal=0.0, stopType='duration (s)', stopVal=1.0, *args, **kwargs):
super().__init__(exp, parentName, name=name, startType=startType, startVal=startVal, stopType=stopType, stopVal=stopVal, *args, **kwargs)

self.url = "https://docs.pupil-labs.com/neon/data-collection/events/"
self.exp.requireImport('BasicComponent', 'psychopy_eyetracker_pupil_labs.pupil_labs.stimuli')

_allow3 = ['constant', 'set every repeat', 'set every frame'] # list
self.params['event_name'] = Param(
event_name, valType='str', inputType="single", allowedTypes=[], categ='Basic',
updates='constant', allowedUpdates=_allow3[:],
hint=_translate("The name of the event to be saved"),
canBePath=False,
label=_translate("Event Name"))

self.params['timestamp_ns'] = Param(timestamp_ns,
valType='int', categ='Basic',
updates='constant', allowedUpdates=_allow3[:],
hint=_translate("The timestamp of the event or `0` for automatic"),
label=_translate("Event timestamp (ns)"))

def writeInitCode(self, buff):
inits = getInitVals(self.params, 'PsychoPy')
buff.writeIndentedLines(f"{inits['name']} = BasicComponent()\n")

def writeRoutineStartCode(self, buff):
inits = getInitVals(self.params, 'PsychoPy')
code = (f"if eyetracker is not None and hasattr(eyetracker, 'send_event'):\n"
f" eyetracker.send_event({inits['event_name']}, {inits['timestamp_ns']})\n")

buff.writeIndentedLines(code)
7 changes: 6 additions & 1 deletion psychopy_eyetracker_pupil_labs/pupil_labs/neon/eyetracker.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,6 @@ def _poll(self):

gaze = self._device.receive_gaze_datum(timeout_seconds=0)
if gaze is not None and hasattr(gaze, 'pupil_diameter_left'):
print('add pupil sample')
self._add_pupil_sample(gaze, logged_time)

def _add_gaze_sample(self, surface_gaze, gaze_datum, logged_time):
Expand Down Expand Up @@ -451,6 +450,12 @@ def register_surface(self, tag_verts, window_size):

self._window_size = window_size

def send_event(self, event_name, timestamp_ns):
if timestamp_ns == 0:
timestamp_ns = None

self._device.send_event(event_name, event_timestamp_unix_ns=timestamp_ns)

def _psychopyTimeInTrackerTime(self, psychopy_time):
return psychopy_time + self._time_offset_estimate.time_offset_ms.mean / 1000

Expand Down
6 changes: 6 additions & 0 deletions psychopy_eyetracker_pupil_labs/pupil_labs/stimuli.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

from pupil_labs.real_time_screen_gaze import marker_generator

from psychopy.tools.attributetools import AttributeGetSetMixin


class AprilTagStim(ImageStim):
def __init__(self, marker_id=0, contrast=1.0, *args, **kwargs):
Expand Down Expand Up @@ -124,3 +126,7 @@ def _frame_positions(self, frame_size, marker_size, grid_counts):
])

return spacing * np.array(self._frame_grid(*grid_counts))


class BasicComponent(AttributeGetSetMixin):
pass
3 changes: 2 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "psychopy-eyetracker-pupil-labs"
version = "0.3.2"
version = "0.4.0"
description = "Extension package for PsychoPy which adds support for Pupil Labs eyetrackers."
readme = "README.md"
requires-python = ">= 3.7"
Expand Down Expand Up @@ -62,3 +62,4 @@ pupil_core = "psychopy_eyetracker_pupil_labs.pupil_labs.pupil_core"
[project.entry-points."psychopy.experiment.components"]
AprilTagComponent = "psychopy_eyetracker_pupil_labs.pupil_labs.components:AprilTagComponent"
AprilTagFrameComponent = "psychopy_eyetracker_pupil_labs.pupil_labs.components:AprilTagFrameComponent"
NeonEventComponent = "psychopy_eyetracker_pupil_labs.pupil_labs.components:NeonEventComponent"

0 comments on commit f144f18

Please sign in to comment.