diff options
author | Théo de la Hogue | 2022-03-15 17:55:07 +0100 |
---|---|---|
committer | Théo de la Hogue | 2022-03-15 17:55:07 +0100 |
commit | b46433c90764800d44299a229569d6d5b49ee1fb (patch) | |
tree | bb258ee7dd7724a9bf8aa220b0647e8de412c1e4 /src/argaze/TobiiGlassesPro2 | |
parent | 9df6093fc56425e4b321a61d0b19210dab9b657b (diff) | |
download | argaze-b46433c90764800d44299a229569d6d5b49ee1fb.zip argaze-b46433c90764800d44299a229569d6d5b49ee1fb.tar.gz argaze-b46433c90764800d44299a229569d6d5b49ee1fb.tar.bz2 argaze-b46433c90764800d44299a229569d6d5b49ee1fb.tar.xz |
Adding utils submodule. Writing documention.
Diffstat (limited to 'src/argaze/TobiiGlassesPro2')
-rw-r--r-- | src/argaze/TobiiGlassesPro2/README.md | 161 | ||||
-rw-r--r-- | src/argaze/TobiiGlassesPro2/TobiiController.py | 35 | ||||
-rw-r--r-- | src/argaze/TobiiGlassesPro2/TobiiData.py | 96 | ||||
-rw-r--r-- | src/argaze/TobiiGlassesPro2/TobiiVideo.py | 18 | ||||
-rw-r--r-- | src/argaze/TobiiGlassesPro2/__init__.py | 4 | ||||
-rw-r--r-- | src/argaze/TobiiGlassesPro2/utils/A4_calibration_target.pdf (renamed from src/argaze/TobiiGlassesPro2/utils/calibration_target_A4.pdf) | bin | 1965 -> 1965 bytes |
6 files changed, 169 insertions, 145 deletions
diff --git a/src/argaze/TobiiGlassesPro2/README.md b/src/argaze/TobiiGlassesPro2/README.md index 378deb5..fcacf41 100644 --- a/src/argaze/TobiiGlassesPro2/README.md +++ b/src/argaze/TobiiGlassesPro2/README.md @@ -1,113 +1,76 @@ -# TobiiGlassesPro2 +Class interface to handle TobbiGlassesPro2 data and video stream. +It is based on [TobiiGlassesPyController package](https://github.com/ddetommaso/TobiiGlassesPyController). -_This module provides a class interface to handle TobbiGlassesPro2 data and video stream. -It is based on [TobiiGlassesPyController package](https://github.com/ddetommaso/TobiiGlassesPyController)._ +## Utils -## To connect Tobii glasses on Mac OS +Print **A4_calibration_target.pdf** onto A4 paper sheet to get markers at expected dimensions. -* Install DHCP server: brew install isc-dhcp +## Local network configuration + +If the tobii Glasses aren't connected to a router, here is how to configure a local DHCP server to enable device connection. + +* Install DHCP server: +``` +brew install isc-dhcp +``` * Setup DHCP server: - * /usr/local/etc/dhcpd.conf - * /usr/local/etc/master.conf -* Setup USB LAN Interface: - * ip: 192.168.1.1 - * subnet: 255.255.255.0 - * router: 192.168.1.254 +**/usr/local/etc/dhcpd.conf** +``` +# NECESSARY TO BE A DHCP SERVER +authoritative; -* Launch Tobii glasses interface to enable USB LAN Interface before to Launch DHCP server. +# DHCP CONFIGURATION INFORMATION +default-lease-time 43200; +max-lease-time 86400; +server-name "dhcpserver.robotron.lan"; -* Launch DHCP server: sudo /usr/local/sbin/dhcpd +# DNS SERVERS DHCP WILL PUSH TO CLIENTS +option domain-name-servers 192.168.1.1; -* Kill DHCP server: sudo kill `cat /usr/local/var/dhcpd/dhcpd.pid` +# SEARCH DOMAINS DHCP WILL PUSH TO CLIENTS +option domain-name "robotron.lan"; -* Watch DHCP server: sudo log stream --info --debug --predicate "process == 'dhcpd'" +# DHCP STATIC IP ASSIGNMENTS FILE +include "/usr/local/etc/master.conf"; -## Tobii data structure +# SUBNET FOR IP ADDRESSES MANUALLY/STATICALLY ASSIGNED ONLY +subnet 192.168.1.0 netmask 255.255.255.0 { + option broadcast-address 192.168.1.255; + option subnet-mask 255.255.255.0; + option routers 192.168.1.254; +} +``` -Each data frame have the following structure: +**/usr/local/etc/master.conf** ``` -{ - 'mems': { - 'ac': { - 'ts': 1042711827, - 's': 0, - 'ac': [0.549, -9.868, 2.203] - }, - 'gy': { - 'ts': 1042723807, - 's': 0, - 'gy': [2.94, -2.384, 1.428] - } - }, - 'right_eye': { - 'pc': { - 'ts': 1042743553, - 's': 0, 'gidx': 39971, - 'pc': [-35.24, -25.51, -31.66], - 'eye': 'right' - }, - 'pd': { - 'ts': 1042743553, - 's': 0, - 'gidx': 39971, - 'pd': 3.72, - 'eye': 'right' - }, - 'gd': { - 'ts': 1042743553, - 's': 0, - 'gidx': 39971, - 'gd': [0.1833, 0.307, 0.9339], - 'eye': 'right' - } - }, - 'left_eye': { - 'pc': { - 'ts': 1042743553, - 's': 0, - 'gidx': 39971, - 'pc': [29.96, -27.92, -40.9], - 'eye': 'left' - }, - 'pd': { - 'ts': 1042743553, - 's': 0, - 'gidx': 39971, - 'pd': 4.42, - 'eye': 'left' - }, - 'gd': { - 'ts': 1042743553, - 's': 0, - 'gidx': 39971, - 'gd': [0.1528, 0.2977, 0.9423], - 'eye': 'left' - } - }, - 'gp': { - 'ts': 1042743553, - 's': 0, - 'gidx': 39971, - 'l': 82832, - 'gp': [0.3975, 0.2228] - }, - 'gp3': { - 'ts': 1042743553, - 's': 0, - 'gidx': 39971, - 'gp3': [313.64, 542.2, 1728.85] - }, - 'pts': { - 'ts': 1042123917, - 's': 0, - 'pts': 93695, - 'pv': 7 - }, - 'vts': { - 'ts': -1 - } -} -```
\ No newline at end of file +# Static IP assignments +## SUBNET - 192.168.1.0/24 +host tobiiglasses { hardware ethernet 74:fe:48:34:7c:92; fixed-address 192.168.1.10; } +``` +Replace 74:fe:48:34:7c:92 by the correct MAC address. + +* Setup USB LAN Interface: +``` +ip: 192.168.1.1 +subnet: 255.255.255.0 +router: 192.168.1.254 +``` + +* Launch Tobii glasses interface to enable USB LAN Interface before to Launch DHCP server. + +* Launch DHCP server: +``` +sudo /usr/local/sbin/dhcpd +``` +* Kill DHCP server: +``` +sudo kill `cat /usr/local/var/dhcpd/dhcpd.pid` +``` + +* Watch DHCP server activity: +``` +sudo log stream --info --debug --predicate "process == 'dhcpd'" +``` diff --git a/src/argaze/TobiiGlassesPro2/TobiiController.py b/src/argaze/TobiiGlassesPro2/TobiiController.py index aafa225..10af5fe 100644 --- a/src/argaze/TobiiGlassesPro2/TobiiController.py +++ b/src/argaze/TobiiGlassesPro2/TobiiController.py @@ -1,24 +1,33 @@ +#!/usr/bin/env python + import tobiiglassesctrl class TobiiController(tobiiglassesctrl.TobiiGlassesController): + """As TobiiController inherits from TobiiGlassesPyController, here is its [code](https://github.com/ddetommaso/TobiiGlassesPyController/blob/master/tobiiglassesctrl/controller.py).""" + + project_id = None + """Project identifier.""" + + participant_id = None + """Participant identifier.""" + + calibration_id = None + """Calibration identifier.""" - # initialisation def __init__(self, ip_address, project_name, participant_id): + """Create a project, a participant and start calibration.""" super().__init__(ip_address, video_scene = True) - # edit project and participant - project_id = super().create_project(project_name) - participant_id = super().create_participant(project_id, project_name) - ''' - # start calibration - input("Position Tobbi glasses calibration target then presse 'Enter' to start calibration.") - calibration_id = super().create_calibration(project_id, participant_id) - super().start_calibration(calibration_id) - - if not super().wait_until_calibration_is_done(calibration_id): - ogging.error('TobiiController.__init__() : Calibration has failed') - ''' + self.project_id = super().create_project(project_name) + self.participant_id = super().create_participant(project_id, project_name) + + input('Position Tobbi glasses calibration target then presse \'Enter\' to start calibration.') + self.calibration_id = super().create_calibration(self.project_id, self.participant_id) + super().start_calibration(self.calibration_id) + + if not super().wait_until_calibration_is_done(self.calibration_id): + raise Error('Tobii calibration failed') # destruction def __del__(self): diff --git a/src/argaze/TobiiGlassesPro2/TobiiData.py b/src/argaze/TobiiGlassesPro2/TobiiData.py index 6bfc89e..8e0a8b3 100644 --- a/src/argaze/TobiiGlassesPro2/TobiiData.py +++ b/src/argaze/TobiiGlassesPro2/TobiiData.py @@ -1,12 +1,18 @@ +#!/usr/bin/env python + import threading import time +from argaze.TobiiGlassesPro2 import TobiiController + class TobiiDataThread(threading.Thread): + """Handle data reception in a separate thread.""" - # initialisation - def __init__(self, controller): + def __init__(self, controller: TobiiController.TobiiController): + """Initialise thread super class and prepare data reception.""" threading.Thread.__init__(self) + self.stop_event = threading.Event() self.read_lock = threading.Lock() @@ -15,18 +21,16 @@ class TobiiDataThread(threading.Thread): self.fps = self.controller.get_et_freq() self.sleep = 1./self.fps - self.__ac_buffer = [] # accelerometer - self.__gy_buffer = [] # gyroscope - self.__gp_buffer = [] # gaze point - self.__pts_buffer = [] # presentation timestamp + self.__ac_buffer = [] + self.__gy_buffer = [] + self.__gp_buffer = [] + self.__pts_buffer = [] self.__start_ts = 0 - # destruction def __del__(self): pass - # extract ac data def __get_ac(self, data): ac_value = data['mems']['ac']['ac'] @@ -41,7 +45,6 @@ class TobiiDataThread(threading.Thread): return ac_data - # extract gy data def __get_gy(self, data): gy_value = data['mems']['gy']['gy'] @@ -56,7 +59,6 @@ class TobiiDataThread(threading.Thread): return gy_data - # extract gp data def __get_gp(self, data): gp_value = data['gp']['gp'] @@ -70,7 +72,6 @@ class TobiiDataThread(threading.Thread): return gp_data - # extract pts data def __get_pts(self, data): pts_value = data['pts']['pts'] @@ -83,8 +84,8 @@ class TobiiDataThread(threading.Thread): return pts_data - # thread start def run(self): + """Data reception function.""" while not self.stop_event.isSet(): @@ -148,8 +149,19 @@ class TobiiDataThread(threading.Thread): self.read_lock.release() - # read ac data - def read_accelerometer_data(self, timestamp): + def read_accelerometer_data(self, timestamp: int = -1): + """Get accelerometer data at a given timestamp. + **Returns:** accelerometer dictionary + ``` + { + 'TIMESTAMP': int, + 'TIME': int, + 'X': float, + 'Y': float, + 'Z': float + } + ``` + """ if len(self.__ac_buffer): @@ -166,8 +178,9 @@ class TobiiDataThread(threading.Thread): return {} - # read ac buffer def read_accelerometer_buffer(self): + """Get accelerometer data buffer. + **Returns:** accelerometer dictionary array""" self.read_lock.acquire() @@ -177,8 +190,19 @@ class TobiiDataThread(threading.Thread): return ac_buffer - # read gy data - def read_gyroscope_data(self, timestamp): + def read_gyroscope_data(self, timestamp: int = -1): + """Get gyroscope data at a given timestamp. + **Returns:** gyroscope dictionary + ``` + { + 'TIMESTAMP': int, + 'TIME': int, + 'X': float, + 'Y': float, + 'Z': float + } + ``` + """ if len(self.__gy_buffer): @@ -195,8 +219,9 @@ class TobiiDataThread(threading.Thread): return {} - # read gy buffer def read_gyroscope_buffer(self): + """Get gyroscope data buffer. + **Returns:** gyroscope dictionary array""" self.read_lock.acquire() @@ -206,8 +231,18 @@ class TobiiDataThread(threading.Thread): return gy_buffer - # read gp data - def read_gaze_data(self, timestamp): + def read_gaze_data(self, timestamp: int = -1): + """Get gaze data at a given timestamp. + **Returns:** gaze dictionary + ``` + { + 'TIMESTAMP': int, + 'TIME': int, + 'X': float, + 'Y': float + } + ``` + """ if len(self.__gp_buffer): @@ -224,8 +259,9 @@ class TobiiDataThread(threading.Thread): return {} - # read gp buffer def read_gaze_buffer(self): + """Get gaze data buffer. + **Returns:** gaze dictionary array""" self.read_lock.acquire() @@ -235,8 +271,17 @@ class TobiiDataThread(threading.Thread): return gp_buffer - # read pts data - def read_pts_data(self, timestamp): + def read_pts_data(self, timestamp: int = -1): + """Get Presentation Time Stamp (pts) data at a given timestamp. + **Returns:** pts dictionary + ``` + { + 'TIMESTAMP': int, + 'TIME': int, + 'PTS': int + } + ``` + """ if len(self.__pts_buffer): @@ -253,8 +298,9 @@ class TobiiDataThread(threading.Thread): return {} - # read pts buffer def read_pts_buffer(self): + """Get Presentation Time Stamp (pts) data buffer. + **Returns:** pts dictionary array""" self.read_lock.acquire() @@ -264,8 +310,8 @@ class TobiiDataThread(threading.Thread): return pts_buffer - # thread stop def stop(self): + """Stop data reception definitively.""" self.stop_event.set() threading.Thread.join(self) diff --git a/src/argaze/TobiiGlassesPro2/TobiiVideo.py b/src/argaze/TobiiGlassesPro2/TobiiVideo.py index 8777a02..babc30b 100644 --- a/src/argaze/TobiiGlassesPro2/TobiiVideo.py +++ b/src/argaze/TobiiGlassesPro2/TobiiVideo.py @@ -1,12 +1,15 @@ +#!/usr/bin/env python + import threading import av import numpy class TobiiVideoThread(threading.Thread): + """Handle video camera stream capture in a separate thread.""" - # initialisation def __init__(self, controller): + """Initialise thread super class and prepare camera video stream reception.""" threading.Thread.__init__(self) self.stop_event = threading.Event() @@ -25,12 +28,11 @@ class TobiiVideoThread(threading.Thread): self.read_lock.release() - # destruction def __del__(self): pass - # thread start def run(self): + """Video camera stream capture function.""" # start Tobii glasses stream capture self.__container = av.open(f'rtsp://{self.controller.get_address()}:8554/live/scene', options={'rtsp_transport': 'tcp'}) @@ -48,12 +50,11 @@ class TobiiVideoThread(threading.Thread): self.__height = f.height self.__pts_buffer.append({'TIME':f.time, 'PTS': f.pts}) - #print(f'Tobii Video Frame: pts = {f.pts}, time = {f.time}, format = {f.width}, {f.height}') - self.read_lock.release() - # read frame def read(self) : + """Read video frame. + **Returns:** frame, frame width, frame height, frame time, frame pts.""" # if stopped, return blank frame if self.stop_event.isSet(): @@ -77,8 +78,9 @@ class TobiiVideoThread(threading.Thread): return frame_copy, width_copy, height_copy, time_copy, pts_copy - # read pts buffer + def read_pts_buffer(self): + """Get Presentation Time Stamp data buffer.""" self.read_lock.acquire() @@ -88,8 +90,8 @@ class TobiiVideoThread(threading.Thread): return pts_buffer - # thread stop def stop(self): + """Stop video camera stream capture definitively.""" self.stop_event.set() threading.Thread.join(self) diff --git a/src/argaze/TobiiGlassesPro2/__init__.py b/src/argaze/TobiiGlassesPro2/__init__.py index 3884106..7d712c6 100644 --- a/src/argaze/TobiiGlassesPro2/__init__.py +++ b/src/argaze/TobiiGlassesPro2/__init__.py @@ -1 +1,5 @@ +""" +.. include:: README.md +""" +__docformat__ = "restructuredtext" __all__ = ['TobiiController', 'TobiiData', 'TobiiVideo']
\ No newline at end of file diff --git a/src/argaze/TobiiGlassesPro2/utils/calibration_target_A4.pdf b/src/argaze/TobiiGlassesPro2/utils/A4_calibration_target.pdf Binary files differindex dfdbe0a..dfdbe0a 100644 --- a/src/argaze/TobiiGlassesPro2/utils/calibration_target_A4.pdf +++ b/src/argaze/TobiiGlassesPro2/utils/A4_calibration_target.pdf |