I’m trying to use the same key to flip after multiple successive stimuli in PsychoPy but it keeps flipping successive screens as well then.
What I came up with was the following slight modification of one of the examples in the manual:
from psychopy import visual, core, event
win = visual.Window(monitor="testMonitor", units="deg")
stim1 = visual.TextStim(win, text="Stim 1", pos=(0,0))
stim2 = visual.TextStim(win, text="Stim 2", pos=(0,0))
stim3 = visual.TextStim(win, text="Stim 3", pos=(0,0))
while len(event.getKeys(['space'])) <= 0:
stim1.draw()
win.flip()
event.clearEvents()
print(event.getKeys()) # test if key buffer is really empty
win.flip()
# while len(event.getKeys(['return'])) <= 0:
# stim2.draw()
# win.flip()
# event.clearEvents()
# win.flip()
while len(event.getKeys(['space'])) <= 0:
stim3.draw()
win.flip()
event.clearEvents()
win.flip()
win.close()
core.quit()
However if I hit space on the first screen, it doesn’t just flip this screen. Instead it will flash stim3 for a split second and then immediately terminate. If on the other hand I use a different key for the second stimulus (replace 'space' with 'return' in the loop condition), that works fine.
My first suspicion was that event.clearEvents() somehow failed to clear the event buffer, so the space event from the first stimulus remained saved and also flipped the second stimulus. However in that case the stim3 shouldn’t be shown at all because the loop condition would immediately fail. Also, if I print out event.getKeys() at the indicated position above, it appears to be empty. Moreover, if I use a different key between the two space-triggered stimuli (remove comments from the stim2 section), suddenly all keys work just fine.
Does anybody have an idea what I’m doing wrong?
(Btw if you’re wondering: I modified the manual example by changing the loop where the program waits for input from a while True loop into while len(event.getKeys(['space'])) <= 0 which eliminates the need of using the exact same condition to break. I tested it with the original idiom just to be sure and the behaviour is the exact same as with my version.)
After some more testing found that deleting the win.flip()'s after each event.clearEvent() fixes the issue. I’m not quite sure why the additional flips (which I thought were necessary to clear the screen before drawing the new stimulus) would cause such a behaviour though. Can somebody explain?
Related
In my experiment, I have 10 trials, and at each trial, the participant has to press a key ("space") asap after seeing a change of colour in the animation. As feedback that confirms the key pressing, I'd like to move to the next trial (move to the next loop iteration) after the key was pressed. I tried to implement the idea in my code with break and continue, but it doesn't work:
for i in range(nTrials):
# Start with fixation cross
fixation.draw()
win.flip()
core.wait(2)
# Play the video for 200 frames
for Nframes in range(200):
optic_flow_movie.draw()
fixation.draw()
win.flip()
# Get Participants responses
keys = psychopy.event.getKeys(keyList=["space"],timeStamped=clock)
if (keys[0][0] == 'space') is True:
break
else:
continue
# Take only the timestamps from the variable key and store it in the variable RTs
RTs = [sublist[1:2] for sublist in keys] # This stores only the timestamps
RTs = [item for sublist in RTs for item in sublist] # This converts from list of lists to a flat list
Many thanks for your help !
It's not entirely clear what the structure of your trial is, but if you want to monitor responses during the animation, then the call to event.getKeys() needs to be embedded within the drawing loop (i.e. within for Nframes in range(200):). That way, you are checking for a keypress on every screen refresh, so the animation can be halted in realtime.
At the moment, the code shows the entire animation and only then checks the keyboard (but just once per trial). Regardless of what happens there, the next trial will begin, as that is the last code in the main trial loop (i.e. for i in range(nTrials):.
Lastly, the event module is deprecated for keyboard responses. You should really shift to the newer Keyboard class for much better performance:
https://www.psychopy.org/api/hardware/keyboard.html
https://discourse.psychopy.org/t/3-ways-to-get-keyboard-input-which-is-best/11184/3
To simplify this problem, let's say I simply want to be able to detect whether my gamepad's right thumbstick is being pushed up (but not horizontally, within some lenience), pushed to the right (but not up, within some lenience) or being pushed to the left (but not up, within some lenience).
Unfortunately, the lenience is required, but I haven't found a way to do it yet. Thusfar I have been using the inputs library:
https://pypi.org/project/inputs/
But it's not super well documented and as far as I can tell it doesn't let you compare an exact angle of the thumbstick at any one time.
Using their own example code, I have this snippet of a function:
def get_true_game_input():
inputArray = [0,0,0,0,0,0,0,0,0,0,0,0,0,0]
# All the different buttons that are important to be detected, including whether the thumbstick has been moved left, right, or up
events = get_gamepad()
for event in events:
if event.code == "ABS_RY":
if event.state >= 8000:
print("top Guard!")
inputArray[5] = 1
elif event.code == "ABS_RX":
if event.state >= 8000:
inputArray[6] = 1
print("right guard!")
elif event.state <= -8000:
inputArray[4] = 1
print("left guard!")
Which works up until one moves the stick, for example, upwards, then ever so slightly to the left or right, whereupon it will detect that instead.
The problem is that, with the way Inputs seems to work, events is always either empty, or of size 1. So it will either detect a horizontal movement or a vertical movement, and one will overwrite the other.
Is there some way to solve this? I am also open to rebuilding this using a different library, but cannot find any other. I am using a dualshock 4 controller using the DS4 Tool.
Any help or advice would be greatly appreciated. Thank you.
I am creating an experiment using Psychopy builder.
The participant is presented with an image containing numbers, e.g. 10 and 20.
They enter what they think is the mean of the numbers, 15 in this case, and then press the spacebar to move on to the next image.
I am trying to have it so there is a display/box on screen that shows them their entry, as with larger numbers in the hundreds of thousands and millions I think they might lose track of what they have pressed.
The ability to change their entry would be excellent also, but really I am most interested in them being able to see it on screen.
In builder I can't find a way to do this, and the ratings scale is not appropriate for huge numbers.
I found these solutions in code to do something that sounds like it:
http://www.psychopy.org/wiki/home.php/Snippets/LiveUpdatingText
However when I try to add them using the code insert function , or just adding them to the compiled script the screen locks up when I try to run the experiment. I am a novice at python, and am not sure where to start fixing this. Is what I'm trying to do possible?
I'm happy to provide some example code from the compiled builder experiment.
Thanks in advance!
Those code snippets are designed for Coder, where you control everything that is happening and when. The same thing can be done in Builder, but you will have to amend the code to fit in with Builder's event loop cycle. i.e. Builder does certain things at the start of an experiment, on every trial, on every screen refresh and so on. So you can't just insert this sort of code without modification, because, for example, it attempts to wait indefinitely for a keypress. Builder meanwhile, is checking the keyboard every screen refresh (typically at 60 Hz), so if you try to wait indefinitely for a keypress in code, you'll be halting Builder from doing everything else it needs to do.
In essence, you just need to break up the code into snippets that go in the appropriate tab in a Builder Code Component (for code to be executed at experiment start, on each frame, and so on), and avoid indefinite functions like event.waitKeys() in favour of instantaneous checking via event.getKeys()
e.g. to adapt the second example from Jonas Lindeløv, in the "Begin Routine" tab, put:
chars = list('0123456789.') # the valid characters
meanText = '' # start with an empty answer on each trial
In the "Each Frame" tab, put something like:
response = event.getKeys() # get a list of keys pressed at this instant
if len(response) > 0: # if there was one,
key = response[0] # just convenient shorthand
if key in chars:
meanText = meanText + response[0]
elif key == 'space':
meanText = meanText + ' '
elif key == 'backspace' and len(meanText) > 0:
meanText = meanText[:-1]
elif key == 'return':
thisExp.addData('Answer', meanText) # save the response
continueRoutine = False # finish this trial
# update the appropriate text stimulus with the current response value:
insertNameOfYourTextStimulusComponent.text = meanText
i'm currently developping a program that runs on a robot. The program needs to add positions to a list but you have to push a button to add a new position. This has to be inside a while loop. But when i press the button the function repeats itself multiple times instead of just 1. Here is the part of code:
while not self.done():
if self._io_left_lower.state:
self._gripper_left.open()
elif self._io_left_upper.state:
self._gripper_left.close()
if self._io_right_lower.state:
self._gripper_right.open()
elif self._io_right_upper.state:
self._gripper_right.close()
if self._io_left_nav.button0:
print("repeats")
#self._mapping.append([self._limb_left.joint_angles(), self._gripper_left.position()])
if self._io_right_nav.button0:
self._mapping.append([self._limb_right.joint_angles(), self._gripper_right.position()])
if self._io_left_nav.button1:
self.stop()
As you can see when the self._io_left_nav.button0 is pressed it will now just print 'repeats' several times but it has to to be printed just onces. same for the self._io_right_nav.button0.
If button0 is a physical button and your loop is polling the button state then it is normal that many iterations run in the time your button is being pressed. You have several options to solve this situation, two of them are:
Do not use a loop check the button but hardware interruptions used to keep an updated representation of your state.
If you still want to use your loop, you should detect button state changes instead checking its current state at each iteration. That may require your program to implement a noise filter.
A very simple way to implement the second option is to have a button state variable with a timestamp associated: At each loop iteration, if the difference between the current time and the timestamp is big enought then you should check if the current state is the same than the one stored in the variable. If not then you have detected a change. In any case, at this point you should update your state-timestamp variable.
This is an example:
from time import time
prevState = (False,time())
while not self.done():
current = time()
if self._io_left_nav.button0 and (current-prevState[1])*1000>2: #For example, 2 ms
if self._io_left_nav.button0 != prevState[0]:
print("repeats")
prevState = (self._io_left_nav.button0,time())
I presume that's some kind of flag, that the button was pressed.
If you don't clear the state, the condition in the if statement will evaluate true. Again, and again....
The following code is being looped - is in a loop - but when 'inputStr' changes, the display does not. Printing inputStr yields the expected results, though.
defFnt = pygame.font.Font("CP437.ttf", 72)
txtToRndr = defFnt.render(inputStr,False, (0,0,0))
disp.blit(txtToRndr, (100,300))
Download link; http://www.mediafire.com/download/a4hp9wgojxgiao9/functGroup.rar
If you print inputStr right before its rendered it prints for a bit then stops, meaning it isnt getting rendered after a certain point, Which i think is because this condition:
if (16-len(Gnots))>0:
it must be coming out false therefore the code to render the new text isnt being executed:
if you print Gnots after the condition, it prints it until its length is 16 items than stops
change the number 16 in the condition to say 1000 as a test than try typing and the text changes
Your code needs refactoring. As the other answer says, the main problem is that if-block (try changing it to if True:.
I would recommend capping the framerate but drawing every frame unconditionally, as this is simpler and more robust. You're also not clearing the screen each frame, and PyGame has nice key tokens (e.g. pygame.K_ESCAPE) which you should use instead of numbers. You're also loading the font each time you draw; you only need to do so once, at the top of your program.
Here's my PyGame basecode, which shows some of these best practices. In the draw() function, you'd add your fill call to clear the screen, and then all of your rendering code.
I can suggest the following after encountering similar issue.
Try updating the screen with your text by adding following line after your code:
pygame.display.update()
The issue of text not updating on screen was coming in my case as I was trying to take input from terminal and then updating in on pygame screen.