psychopy.org | Reference | Downloads | Github

Using responseEmulator

I am trying to set up a response emulator to simulate key presses (basically i’m too lazy to press 100s of keys each time i want to check the script)
the only information i can find is on builder view and ive tried using the code output of these but i just cant get it to work!

this is the code i have for setting it up:

from psychopy.hardware.emulator import responseEmulator

info = {}
info ['participant']=''
info ['useMonkey'] = 'n','y'
dlg = gui.DlgFromDict(info)
if dlg.OK == False:
    core.quit() 

if str(info['useMonkey'])== 'y':
    Monkey=True
else:
    Monkey=False

and then after the part of my trial waiting for a key press i have this:

if Monkey:
    simulated_responses=[(0.3,'left')]
    responder=ResponseEmulator(simulated_responses)
    responder.start()

but when i run the trial it still just sits there until I’ve manually pressed the key
can you see what im doing wrong?

Thanks for helping!

Tried to replicate issue and get the following trace:

Exception in thread Thread-2:
Traceback (most recent call last):
  File "C:\Anaconda\lib\threading.py", line 801, in __bootstrap_inner
    self.run()
  File "C:\Anaconda\lib\site-packages\psychopy\hardware\emulator.py", line 45, in run
    core.wait(float(onset) - last_onset)
  File "C:\Anaconda\lib\site-packages\psychopy\clock.py", line 223, in wait
    win.winHandle.dispatch_events()  # pump events
  File "C:\Anaconda\lib\site-packages\pyglet\window\win32\__init__.py", line 591, in dispatch_events
    app.platform_event_loop.start()
  File "C:\Anaconda\lib\site-packages\pyglet\app\win32.py", line 95, in start
    'thread that imports pyglet.app')
RuntimeError: EventLoop.run() must be called from the same thread that imports pyglet.app

But the rest of the experiment runs normally. So it looks like it may be a threading bug in responseEmulator

yes, i had been getting that error but i didn’t realise it was for the response emulator,
does this mean there’s nothing i can do?

So this miminal working example works for me:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from __future__ import print_function
from psychopy.hardware.emulator import ResponseEmulator
from psychopy.event import waitKeys

simulated_responses=[(0.3, 'left')]
responder=ResponseEmulator(simulated_responses)
responder.start()

keys = waitKeys(timeStamped=responder.clock)
print(keys)

Does it work for you, too? You don’t provide the entire code you’re using (e.g., there’s at least some import statements missing). Which version of PsychoPy are you using?

1 Like

This works for me too.

Might have to do with operating systems if it’s a threading issue?

It works for me under Windows 7.

that example is working for me, but my script still isn’t
I’m using windows 10 and the newest version of PsychoPY.

Here’s a more complete version of the code:

from psychopy import visual, event, core, data, gui 
from psychopy.hardware.emulator import ResponseEmulator

info = {}
info ['participant']=''
info ['useMonkey'] = 'n','y'
dlg = gui.DlgFromDict(info)
if dlg.OK == False:
    core.quit()  # user pressed cancel

 win=visual.Window(monitor='testMonitor', fullscr=False, size=(800,800),units='pix', color=[0.506,0.506,0.506])

info['fixTime']=0.68
info['faceTime']=0.907
info['cueTime']=0.507
info['dateStr']=data.getDateStr()
filename="data/"+info['participant']+'_'+info['dateStr']

if str(info['useMonkey'])== 'y':
    Monkey=True
else:
    Monkey=False

fixation=visual.TextStim(win, color='white', pos=[0,0], height=50, text="+")
target=visual.ImageStim(win, size=80, pos=[300,0],image=None, mask='gauss', color='blue')
imageStat=visual.ImageStim(win, pos=[0,0], size=(250,250), image='sin')
imageCue=visual.ImageStim(win, pos=[0,0], size=(250,250), image='sin')

respClock=core.Clock()

runTrials=True
while runTrials==True:
    trials = data.TrialHandler(nReps=1, method='random', originPath=-1, trialList=data.importConditions('main.xlsx')) #change back to practice
    for thisTrial in trials:
        fixation.draw()
        win.flip()
        core.wait(info['fixTime'])
    
        imageStat.setImage(thisTrial['fix'])
        imageStat.draw()
        win.flip()
        core.wait(info['faceTime'])
    
        imageCue.setImage(thisTrial['pic'])
        imageCue.draw()
        win.flip()
        core.wait(info['cueTime'])
    
        fixation.draw()
        win.flip()
        core.wait(thisTrial['SOA'])
    
        target.setPos([thisTrial['pos'],0])
        fixation.draw()
        target.draw()
        win.flip()
        respClock.reset()
        keys=event.waitKeys(keyList=['left', 'right','escape'])
        resp=keys[0]
        if Monkey:
            simulated_responses=[(0.3,'left')]
            responder=ResponseEmulator(simulated_responses)
            responder.start()
        if resp == 'escape':
            core.quit()

and this is the error I’m getting:

RuntimeError: EventLoop.run() must be called from the same thread that imports pyglet.app

I think one issue is that you initially set this value to a tuple:

info ['useMonkey'] = 'n','y'

Instead, just set it to ‘y’

info ['useMonkey'] = 'y'

and then the conditional statement will become True

if str(info['useMonkey'])== 'y':

In your case, adding some print statements into the code would reveal that Monkey was not being set to what you expected it to be. This is a powerful strategy for debugging.

Also, you need to start the responder thread before doing any of the other stuff (.draw(), win.flip(), core.wait(). It looks like you do the other stuff and only then start the responder thread. You’ll need to move the if Monkey: block outside the for loop.

Finally, the list that you give to the responder should contain ALL of the (time, response) items, not just a single one. Only start one responder thread, and start it once, and it will do its thing.

Minor point: you could rewrite the 4 line if - then statement in one line:

Monkey = bool(info['useMonkey'] == 'y')
1 Like

the reason i had it set to y or n is because this is an option that can be selected in the dialogue box at the start of the experiment - however i tried your print idea and it confirmed that monkey is indeed being set to the value i expect.

as for moving it outside the loop do you mean here:

while runTrials==True:
    trials = data.TrialHandler(nReps=1, method='random', originPath=-1,         trialList=data.importConditions('main.xlsx')) #change back to practice
    if Monkey:
        simulated_responses=[(0.3,'left')]
        responder=ResponseEmulator(simulated_responses)
        responder.start()
        for thisTrial in trials:
            fixation.draw()
            win.flip()
            core.wait(info['fixTime'])

            imageStat.setImage(thisTrial['fix'])
            imageStat.draw()
            win.flip()
            core.wait(info['faceTime'])

            imageCue.setImage(thisTrial['pic'])
            imageCue.draw()
            win.flip()
            core.wait(info['cueTime'])

            fixation.draw()
            win.flip()
            core.wait(thisTrial['SOA'])

            target.setPos([thisTrial['pos'],0])
            fixation.draw()
            target.draw()
            win.flip()
            respClock.reset()
            keys=event.waitKeys(keyList=['left', 'right','escape'])
            resp=keys[0]
   
            if resp == 'escape':
                core.quit()

if so I just tried this and its still coming up with the same error message
also is there any shortcut for setting the timings and keys to all trials, because i have 64 trials in my loop and that would be a lot of values to input individually!

Ah, great. I missed that this would only be one value when coming out of the dialog. Good.

Almost but not quite. Unident the for loop:

while runTrials:
    trials = ... # change back to practice
    if Monkey:
        simulated_responses=[(0.3,'left')]
        responder=ResponseEmulator(simulated_responses)
        responder.start()
    for thisTrial in trials:

Do you get the error when not using the responder monkey? If so, work that out first.

You’ll need to work out the time values you want, depending on your script timing. You can make a list of times and a list of responses, and then zip then together:

times = range(64)  # these are just place-holder values, to illustrate using zip
responses = 'a' * 64
simulated_responses = zip(times, responses)

OK so I’ve tried un-indenting those lines and it still isn’t working,
also no, the error doesn’t come up when the monkey is turned off

the problem with this zip idea is that the timings for each condition vary randomly , so not sure how id get round this! - could i get it to pull something from the conditions file?

The error message and traceback mean that pyglet is not happy for a specific reason:

RuntimeError: EventLoop.run() must be called from the same thread that imports pyglet.app

I don’t understand why EventLoop.run() would be called from a different thread for you (but not for Richard’s minimal demo). Are you running your experiment from the Coder? Spyder debug mode? command line? This might give some clue.

Re the zip idea: To get the same sequence of random numbers, you can provide a seed to the random functions. (Its pseudorandom, not true random.)

1 Like

Ive been running my experiment from the coder (i think! - just the main code window)

Hello,

the problem has been solved (ish)
it seems that the ResponseEmulator function is currently not working in the newest version of PsychoPy
(it doesn’t work for coder or builder view - even when running the same script that works in the older version)

thanks for all your help