Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
T
test_gonogo
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Laura Rodríguez
test_gonogo
Commits
286c0bc5
Commit
286c0bc5
authored
Jun 04, 2025
by
Laura Rodríguez
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Initial commit
parents
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
306 additions
and
0 deletions
+306
-0
test_gonogo.py
+306
-0
No files found.
test_gonogo.py
0 → 100644
View file @
286c0bc5
mport
sys
import
random
import
time
from
matplotlib.pyplot
import
margins
import
pygame
from
PyQt6.QtWidgets
import
QApplication
,
QWidget
,
QVBoxLayout
,
QPushButton
,
QLabel
,
QMessageBox
from
PyQt6.QtCore
import
Qt
from
PyQt6.QtGui
import
QFont
from
pygaze
import
eyetracker
,
libinput
,
libscreen
,
liblog
from
pygaze
import
libtime
import
tobii_research
as
tr
import
constants
# Debe contener: DISPSIZE = (1920, 1080)
import
pandas
as
pd
# Importamos pandas para guardar los resultados en un archivo Excel
import
subprocess
# Para abrir el archivo con el programa predeterminado
import
os
# Para comprobar la existencia del archivo
# ============ FUNCIÓN DE CALIBRACIÓN ============
def
calibrate_tobii
(
self
):
try
:
print
(
"Buscando dispositivo..."
)
found_eyes
=
tr
.
find_all_eyetrackers
()
if
not
found_eyes
:
raise
Exception
(
"No se encontró ningún dispositivo Tobii Pro."
)
eye_tracker
=
found_eyes
[
0
]
print
(
f
"Dispositivo encontrado: {eye_tracker}"
)
self
.
disp
=
libscreen
.
Display
(
bgcolor
=
(
0
,
0
,
0
))
# Fondo negro
self
.
tracker
=
eyetracker
.
EyeTracker
(
self
.
disp
)
instruction_screen
=
libscreen
.
Screen
()
instruction_screen
.
clear
(
colour
=
(
0
,
0
,
0
))
instruction_screen
.
draw_text
(
"Presiona espacio para calibrar"
,
fontsize
=
24
,
colour
=
(
255
,
255
,
255
))
self
.
disp
.
fill
(
instruction_screen
)
self
.
disp
.
show
()
print
(
"Iniciando calibración..."
)
self
.
tracker
.
calibrate
()
print
(
"Calibración completada."
)
# self.tracker.close()
# disp.close()
return
True
except
Exception
as
e
:
print
(
f
"Error durante calibración: {e}"
)
return
False
# ============ TEST GO/NOGO ======================
def
run_gonogo_test
(
self
):
pygame
.
init
()
# self.disp = libscreen.Display(bgcolor=(0, 0, 0))
# self.tracker = eyetracker.EyeTracker(self.disp)
log
=
liblog
.
Logfile
()
log
.
write
([
"trialnr"
,
"trialtype"
,
"targetside"
,
"gaze_endpos"
,
"latency"
,
"correct"
])
SCREEN_WIDTH
,
SCREEN_HEIGHT
=
constants
.
DISPSIZE
CENTER
=
(
SCREEN_WIDTH
//
2
,
SCREEN_HEIGHT
//
2
)
TARGET_OFFSET
=
382
left_pos
=
(
CENTER
[
0
]
-
TARGET_OFFSET
,
CENTER
[
1
])
right_pos
=
(
CENTER
[
0
]
+
TARGET_OFFSET
,
CENTER
[
1
])
blackscreen
=
libscreen
.
Screen
()
blackscreen
.
clear
(
colour
=
(
0
,
0
,
0
))
inscreen
=
libscreen
.
Screen
()
inscreen
.
clear
(
colour
=
(
0
,
0
,
0
))
ins_text
=
(
"Mira la cruz central y presiona 'espacio'.
\n\n
"
"El color indicará la acción:
\n
"
"- Verde: mira al círculo blanco (Pro-sácadico)
\n
"
"- Rojo: mira al estímulo blanco y negro (Anti-sácadico)
\n
"
"- Naranja: NO mires a ningún estímulo (NoGo)
\n\n
"
"Presiona 'espacio' para comenzar.
\n
"
"Pulsa 'E' en cualquier momento para salir."
)
inscreen
.
draw_text
(
text
=
ins_text
,
fontsize
=
30
,
pos
=
CENTER
,
colour
=
(
255
,
255
,
255
),
center
=
True
)
fixscreen
=
libscreen
.
Screen
()
fixscreen
.
clear
(
colour
=
(
0
,
0
,
0
))
fixscreen
.
draw_fixation
(
fixtype
=
'cross'
,
diameter
=
57
,
pos
=
CENTER
,
colour
=
(
255
,
255
,
255
))
signal_screens
=
{
'PS'
:
libscreen
.
Screen
(),
'AS'
:
libscreen
.
Screen
(),
'NoGo'
:
libscreen
.
Screen
()
}
for
key
,
color
in
[(
'PS'
,
(
0
,
255
,
0
)),
(
'AS'
,
(
255
,
0
,
0
)),
(
'NoGo'
,
(
255
,
165
,
0
))]:
signal_screens
[
key
]
.
clear
(
colour
=
(
0
,
0
,
0
))
signal_screens
[
key
]
.
draw_circle
(
pos
=
CENTER
,
r
=
38
,
fill
=
True
,
colour
=
color
)
feedbackscreens
=
{
1
:
libscreen
.
Screen
(),
0
:
libscreen
.
Screen
()
}
feedbackscreens
[
1
]
.
clear
(
colour
=
(
0
,
0
,
0
))
feedbackscreens
[
1
]
.
draw_text
(
text
=
'Correcto'
,
fontsize
=
30
,
pos
=
CENTER
,
colour
=
(
0
,
255
,
0
),
center
=
True
)
feedbackscreens
[
0
]
.
clear
(
colour
=
(
0
,
0
,
0
))
feedbackscreens
[
0
]
.
draw_text
(
text
=
'Incorrecto'
,
fontsize
=
30
,
pos
=
CENTER
,
colour
=
(
255
,
0
,
0
),
center
=
True
)
self
.
disp
.
fill
(
inscreen
)
self
.
disp
.
show
()
waiting
=
True
while
waiting
:
for
event
in
pygame
.
event
.
get
():
if
event
.
type
==
pygame
.
KEYDOWN
:
if
event
.
key
==
pygame
.
K_SPACE
:
waiting
=
False
elif
event
.
key
==
pygame
.
K_e
:
pygame
.
quit
()
return
max_blocks
=
30
results
=
[]
try
:
for
block
in
range
(
max_blocks
):
trials
=
[
'PS'
,
'AS'
,
'NoGo'
]
# trials = ['PS', 'AS']
random
.
shuffle
(
trials
)
for
trialnr
,
trialtype
in
enumerate
(
trials
,
start
=
1
):
for
event
in
pygame
.
event
.
get
():
if
event
.
type
==
pygame
.
KEYDOWN
and
event
.
key
==
pygame
.
K_e
:
raise
KeyboardInterrupt
# Mostrar cruz de fijación
self
.
disp
.
fill
(
fixscreen
)
self
.
disp
.
show
()
libtime
.
pause
(
random
.
randint
(
750
,
1250
))
# Esperar que el usuario presione espacio
waiting
=
True
while
waiting
:
for
event
in
pygame
.
event
.
get
():
if
event
.
type
==
pygame
.
KEYDOWN
:
if
event
.
key
==
pygame
.
K_SPACE
:
waiting
=
False
elif
event
.
key
==
pygame
.
K_e
:
raise
KeyboardInterrupt
time
.
sleep
(
0.2
)
self
.
tracker
.
start_recording
()
# Mostrar señal central de color
self
.
disp
.
fill
(
signal_screens
[
trialtype
])
self
.
disp
.
show
()
time
.
sleep
(
0.8
)
self
.
disp
.
fill
(
blackscreen
)
self
.
disp
.
show
()
time
.
sleep
(
0.2
)
targetside
=
random
.
choice
([
'left'
,
'right'
])
target_pos
=
left_pos
if
targetside
==
'left'
else
right_pos
nontarget_pos
=
right_pos
if
targetside
==
'left'
else
left_pos
dualstim_screen
=
libscreen
.
Screen
()
dualstim_screen
.
clear
(
colour
=
(
0
,
0
,
0
))
dualstim_screen
.
draw_circle
(
pos
=
nontarget_pos
,
r
=
28
,
fill
=
True
,
colour
=
(
255
,
255
,
255
))
dualstim_screen
.
draw_circle
(
pos
=
target_pos
,
r
=
38
,
fill
=
True
,
colour
=
(
255
,
255
,
255
))
dualstim_screen
.
draw_circle
(
pos
=
target_pos
,
r
=
32
,
fill
=
True
,
colour
=
(
0
,
0
,
0
))
dualstim_screen
.
draw_circle
(
pos
=
target_pos
,
r
=
28
,
fill
=
True
,
colour
=
(
255
,
255
,
255
))
self
.
disp
.
fill
(
dualstim_screen
)
self
.
disp
.
show
()
t0
=
pygame
.
time
.
get_ticks
()
self
.
tracker
.
log
(
f
"target {targetside}"
)
# try:
t1
,
startpos
=
self
.
tracker
.
wait_for_saccade_start
()
endtime
,
startpos
,
endpos
=
self
.
tracker
.
wait_for_saccade_end
()
# except Exception:
# print("La estoy liando")
# t1 = pygame.time.get_ticks()
# endtime = pygame.time.get_ticks()
# endpos = constants.DISPSIZE[0]/2 # o (SCREEN_WIDTH//2, SCREEN_HEIGHT//2), posición central para 'NoGo'
latency
=
(
t1
-
t0
)
/
1000
self
.
tracker
.
stop_recording
()
# midpoint = SCREEN_WIDTH / 2
# margin = 100
# endpos=None
if
trialtype
==
'PS'
:
correct
=
int
(
(
targetside
==
'left'
and
endpos
[
0
]
<=
constants
.
DISPSIZE
[
0
]
/
2
)
or
(
targetside
==
'right'
and
endpos
[
0
]
>=
constants
.
DISPSIZE
[
0
]
/
2
)
)
print
(
correct
)
elif
trialtype
==
'AS'
:
correct
=
int
(
(
targetside
==
'left'
and
endpos
[
0
]
>=
constants
.
DISPSIZE
[
0
]
/
2
)
or
(
targetside
==
'right'
and
endpos
[
0
]
<=
constants
.
DISPSIZE
[
0
]
/
2
)
)
elif
trialtype
==
'NoGo'
:
correct
=
int
(
constants
.
DISPSIZE
[
0
]
/
2
<
endpos
[
0
]
<=
constants
.
DISPSIZE
[
0
]
/
2
)
if
correct
>=
0
:
dualstim_screen
.
clear
(
colour
=
(
0
,
0
,
0
))
self
.
disp
.
show
()
self
.
disp
.
fill
(
feedbackscreens
[
correct
])
self
.
disp
.
show
()
time
.
sleep
(
0.5
)
results
.
append
([
trialnr
,
trialtype
,
targetside
,
endpos
,
round
(
latency
,
3
),
correct
])
except
KeyboardInterrupt
:
print
(
"Test interrumpido por el usuario con la tecla 'E'."
)
finally
:
log
.
close
()
self
.
tracker
.
close
()
self
.
disp
.
close
()
print
(
"Test Go/NoGo finalizado."
)
df
=
pd
.
DataFrame
(
results
,
columns
=
[
"trialnr"
,
"trialtype"
,
"targetside"
,
"gaze_endpos"
,
"latency"
,
"correct"
])
df
.
to_excel
(
"gonogo_results.xlsx"
,
index
=
False
)
print
(
"Resultados guardados en 'gonogo_results.xlsx'."
)
# ============ INTERFAZ PYQT ===================
class
EyeTrackingApp
(
QWidget
):
def
__init__
(
self
):
super
()
.
__init__
()
self
.
setWindowTitle
(
"Test Go/NoGo con Tobii"
)
self
.
setGeometry
(
100
,
100
,
400
,
300
)
self
.
calibrated
=
False
self
.
setup_ui
()
self
.
disp
=
None
self
.
tracker
=
None
def
setup_ui
(
self
):
self
.
setStyleSheet
(
"background-color: #e6f0ff;"
)
layout
=
QVBoxLayout
()
title
=
QLabel
(
"Test Go/NoGo con Tobii"
)
title
.
setFont
(
QFont
(
"Arial"
,
18
,
QFont
.
Weight
.
Bold
))
title
.
setAlignment
(
Qt
.
AlignmentFlag
.
AlignCenter
)
layout
.
addWidget
(
title
)
self
.
btn_calibrate
=
QPushButton
(
"Calibrar"
)
self
.
btn_calibrate
.
setFont
(
QFont
(
"Arial"
,
14
))
self
.
btn_calibrate
.
setStyleSheet
(
"background-color: #3399ff; color: white; padding: 10px; border-radius: 5px;"
)
self
.
btn_calibrate
.
clicked
.
connect
(
self
.
calibrate
)
layout
.
addWidget
(
self
.
btn_calibrate
)
self
.
btn_test
=
QPushButton
(
"Iniciar test Go/NoGo"
)
self
.
btn_test
.
setFont
(
QFont
(
"Arial"
,
14
))
self
.
btn_test
.
setStyleSheet
(
"background-color: #3399ff; color: white; padding: 10px; border-radius: 5px;"
)
self
.
btn_test
.
clicked
.
connect
(
self
.
start_test
)
layout
.
addWidget
(
self
.
btn_test
)
self
.
btn_results
=
QPushButton
(
"Consultar resultados"
)
self
.
btn_results
.
setFont
(
QFont
(
"Arial"
,
14
))
self
.
btn_results
.
setStyleSheet
(
"background-color: #3399ff; color: white; padding: 10px; border-radius: 5px;"
)
self
.
btn_results
.
clicked
.
connect
(
self
.
view_results
)
layout
.
addWidget
(
self
.
btn_results
)
self
.
setLayout
(
layout
)
def
calibrate
(
self
):
result
=
calibrate_tobii
(
self
)
if
result
:
self
.
calibrated
=
True
QMessageBox
.
information
(
self
,
"Calibración"
,
"Calibración completada con éxito."
)
else
:
QMessageBox
.
critical
(
self
,
"Error"
,
"La calibración ha fallado."
)
def
start_test
(
self
):
# if not self.calibrated:
# QMessageBox.warning(self, "Calibración requerida", "Debes calibrar antes de realizar el test.")
# return
run_gonogo_test
(
self
)
def
view_results
(
self
):
file_path
=
"gonogo_results.xlsx"
# Verificamos si el archivo existe antes de intentar abrirlo
if
os
.
path
.
exists
(
file_path
):
try
:
# Abrimos el archivo con el programa predeterminado (Windows)
subprocess
.
Popen
([
file_path
],
shell
=
True
)
except
Exception
as
e
:
QMessageBox
.
critical
(
self
,
"Error"
,
f
"No se pudo abrir el archivo Excel. {e}"
)
else
:
QMessageBox
.
warning
(
self
,
"Archivo no encontrado"
,
"El archivo de resultados no existe."
)
if
__name__
==
"__main__"
:
app
=
QApplication
(
sys
.
argv
)
window
=
EyeTrackingApp
()
window
.
show
()
sys
.
exit
(
app
.
exec
())
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment