aboutsummaryrefslogtreecommitdiff
path: root/src/argaze/TobiiGlassesPro2
diff options
context:
space:
mode:
authorThéo de la Hogue2022-03-15 17:55:07 +0100
committerThéo de la Hogue2022-03-15 17:55:07 +0100
commitb46433c90764800d44299a229569d6d5b49ee1fb (patch)
treebb258ee7dd7724a9bf8aa220b0647e8de412c1e4 /src/argaze/TobiiGlassesPro2
parent9df6093fc56425e4b321a61d0b19210dab9b657b (diff)
downloadargaze-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.md161
-rw-r--r--src/argaze/TobiiGlassesPro2/TobiiController.py35
-rw-r--r--src/argaze/TobiiGlassesPro2/TobiiData.py96
-rw-r--r--src/argaze/TobiiGlassesPro2/TobiiVideo.py18
-rw-r--r--src/argaze/TobiiGlassesPro2/__init__.py4
-rw-r--r--src/argaze/TobiiGlassesPro2/utils/A4_calibration_target.pdf (renamed from src/argaze/TobiiGlassesPro2/utils/calibration_target_A4.pdf)bin1965 -> 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
index dfdbe0a..dfdbe0a 100644
--- a/src/argaze/TobiiGlassesPro2/utils/calibration_target_A4.pdf
+++ b/src/argaze/TobiiGlassesPro2/utils/A4_calibration_target.pdf
Binary files differ