Problems with skipping routines conditionally in Builder

OS (e.g. Win10): MacOS Mojave
PsychoPy version (e.g. 1.84.x): v3.1.2
Standard Standalone? (y/n) Yes
What are you trying to achieve?:
I want to conditionally run routines based on keyboard responses given.

In this task, I have a fixation routine, trial routine and break screen routine. The fixation should stay on the screen until a button is pressed. If “s” is pressed, it should go to the trial routine, if 'b" is pressed it should go to the break screen routine and if “t” is pressed it should terminate the loop.

In the trial routine, if “b” is pressed it should go to the break screen, if “t” is pressed then it should terminate the loop but if nothing is pressed then it should skip the break screen routine and restart the loop.

What did you try to make it work?:
Currently, I can successfully get the trial routine to run in response to pressing ‘s’ during the fixation routine. In a code component, under the Begin Routine tab on the trial routine, I’ve successfully used this:

#display the trial if 's' was pressed during fixation
#i.e., if any key that wasn't 's' was pressed 
#then don't run the "trial" routine and move onto the next routine
# keyboardPress is the keyboard component during fixation
if keyboardPress.keys != 's' :
    continueRoutine = False 

And I can use ‘t’ to terminate the loop on all routines. On each routine I have a code component that looks like this under the Each Frame tab, uses this:

#End the block 'trials' if 't' is pressed
if keyboardResponseTrial.keys == 't':
    trials.finished=True 

But I can’t get the breakscreen to display if ‘b’ is pressed during fixation or the trial routines. Here’s the code component I’ve used on the breakscreen routine, under the Begin Routine tab, that isn’t working (I’m not getting an error, it’s just not happening).

#display the breakscreen if b is pressed
#i.e., if any key that isn't 'b' is pressed 
#then don't run the "breakScreen" routine
# keyboardPress is the keyboard component during fixation
# keyboardResponseTrial is the keyboard component during trial
if keyboardPress.keys != 'b' or keyboardResponseTrial.keys != 'b':
    continueRoutine=False 

Any guidance or advice as to why this breakscreen routine won’t conditionally display when the correct key is pressed on prior routines would be greatly appreciated!

2 Likes

Sometimes the easiest thing to do to debug logic like this is just to insert some (temporary) debugging print statements, e.g.

print(keyboardPress.keys)
print(keyboardResponseTrial.keys)
print(keyboardPress.keys != 'b' or keyboardResponseTrial.keys != 'b')

if keyboardPress.keys != 'b' or keyboardResponseTrial.keys != 'b':
    print('Not continuing')
    continueRoutine=False 

I think that might help to show that the test should probably be:

# only run this routine if the user asked for a break on either earlier routine:
if keyboardPress.keys == 'b' or keyboardResponseTrial.keys == 'b':
    continueRoutine=False 

i.e. at the moment I think the logic is effectively demanding that the user press 'b' on both routines, which isn’t possible.

Also the loop-ending code above doesn’t need to be in the “every frame” tab, it only needs to run once per loop iteration (e.g. in an “end routine” tab).

This loop.finished property doesn’t take immediate effect: it is only checked once all of the routines have completed in a given loop iteration (i.e. unlike continueRoutine, which does have an immediate effect, checked once per screen refresh). So you could just have this code run once, in the “end routine” tab of your final routine:

# End the block 'trials' if 't' was pressed
if keyboardPress.keys == 't' or keyboardResponseTrial.keys == 't'
    trials.finished = True 
1 Like

Hi Michael.

It still never occurs to me to add print statements to debug…a good tip!

Your suggestion definitely helped point me in the right direction and I think I’m almost there - thanks for that!

I think continueRoutine=False is a wrong way to build conditional routines, it might easily fail with video, and code that is associated with routine and frame runs instead of being skipped with the routine. That is the reason that if you have video you easily get an OSError associated with OpenGL.

Instead I use a loop where I put conditional into number of loops, which correctly skips or not the routine. That should be the preferred way.

For a more verbose opinion see: Implementing "conditional routines"