Code for timer not working with new versions of Psychopy

Hi,
I would like to share with you my code to get a timer during my experiment, only when two keys are pressed (‘up’, ‘down’).
The experimental condition lasts 10 minutes during which the time must be refreshed every 2 minutes. When keys are pressed, the timer appears at the center of the screen in two different colors (depending on the key) over a grey rectangle. Let’s call the two timer components ‘check’ and ‘clock’. ‘Check’ can be pressed for a maximum of 3 times within the 2 minutes. ‘Clock’ has no limits. The experiment has been created in the Builder and we added code components to it to get the clock. Rectangle and keys are set as components in the builder. Moreover, a text component has been added to define the timer by means of this formula: str(int(math.floor(round($t)/60))) + ':' + str(int(round($t)-60*math.floor(round($t)/60)))

The code to display the timer, and the whole experiment, work fine on a pc with Psychopy version 3.0.6 where triggers were set via parallel port. In my actual lab I can’t use parallel port to connect the pc stimulation to the EGI system with which I work. Thus, I need to set triggers via serial port by means of the library ‘egi pynetstation’ that is supported from version 2022 of Psychopy. Unfortunately, the same code is not working on Psychopy 2022.2.4.

Do you have any clue on why it is happening? Is there some update in the module clock of Psychopy?

When I press ‘check’ the rectangle appears for milliseconds and it can’t be pressed anymore. Whereas pressing ‘clock’ the rectangle appears and keeps displayed until the end of the routine. The timer never appears.

Any suggestion would help me a lot, thank you very much!

Here it is the code components for the timer:

  • For ‘check’

in Begin Routine tab

myClock.reset()


Checktime = 0
wrongtime = 0
keyCheckPressed = False
wrongCheck=False
CheckDelay = 2
wrongDelay = 0.5

refresh = 120
k = 0
i = 0
m = 1
r = 1

In Each frame tab

    t=myClock.getTime()
    
    for k in range (1,5):
        if 'down' in check_resp.keys:
            i = i + 1
            Checktime = t + CheckDelay
            keyCheckPressed = True
            if i<=3:
                check_txt.opacity = 1
                check_box.opacity = 1
                thisExp.addData('RT_check_'+str(r)+'_'+str(m), check_resp.rt)
                m = m + 1
                r = r + 1
    
            if i >=4:
                check_txt.opacity = 0
                check_box.opacity = 0
                thisExp.addData('RT_check_99_', check_resp.rt)
    
        if t > Checktime and keyCheckPressed:
                check_txt.opacity = 0
                check_box.opacity = 0
                keyCheckPressed = False
    
        check_resp_allKeys = []
        check_resp.keys = []
        check_resp.rt = []
    
        if round(t) == k*refresh:
            i = 0
            k = k+1
            m=1
  • For ‘clock’

in Begin Routine tab

myClock.reset()

Clocktime = 0
keyClockPressed = False
ClockDelay = 1
n = 1
p = 1
k=0
j=0

In Each frame tab

t=myClock.getTime()
    
    for k in range (1,5):
        if 'up' in clock_resp.keys and len(clock_resp.keys) > 0:
            Clocktime = t + ClockDelay
            keyClockPressed = True
            clock_txt.opacity = 1
            clock_box.opacity = 1
            thisExp.addData('RT_clock_'+str(p)+'_'+str(n),clock_resp.rt)
            n = n + 1
            p = p + 1
       
        clock_resp_allKeys = []
        clock_resp.keys = []
        clock_resp.rt = []
        
        if t > Clocktime and keyClockPressed:
            clock_txt.opacity = 0
            clock_box.opacity = 0
            keyClockPressed = False
            
        if round(t) == k*refresh:
            k = k+1
            j = k*10
            n = 1
            Clocktime = 0
            myClock.reset()

I haven’t looked in detail at the rest of your code but this needs to be reworked to reflect that fact that $ means “interpret this as code” not “this is a variable”.

Try

$str(int(math.floor(round(t)/60))) + ':' + str(int(round(t)-60*math.floor(round(t)/60)))

Thank you very much @wakecarter ! Applying your suggestion, the timer appears. But still we have a problem: the time appears correctly over the rectangle when key is pressed, however they don’t disappear after one second (as we wish).
Any suggestion on how to solve it? Thank you

Here it is the code we are using (in a code component into the Builder):

Begin Experiment tab

myClock = coreClock()

Begine Routine tab

myClock.reset()

Clocktime = 0
keyClockPressed = False
ClockDelay = 1

Each Frame tab

 t=myClock.getTime()

if clock_resp.keys:
   Clocktime = t + ClockDelay
   keyClockPressed = True
   clock_txt.setOpacity(1)
   clock_box.setOpacity(1)

if t > Clocktime and keyClockPressed:
   clock_txt.setOpacity(0)
   clock_box.setOpacity(0)
   keyClockPressed = False
    
clock_resp_allKeys = []
clock_resp.keys = []
clock_resp.rt = []

This is will true for every frame after the first key press. Try

if clock_resp.keys and keyClockPressed = False:

It gives a SyntaxError: invalid syntax.

Sorry

if clock_resp.keys and keyClockPressed == False:

Ok, thanks. The timer and the rectangle appear when key is pressed, but again they do not disappear. It seems like they are refreshing every second, looks like flashing.

Remove keyClockPressed = False from this section so it only happens once per routine.

Great, it works and only happens once. However, we need to make it happen more than once overall the routine. Any idea on how to apply it in the code?
Thank you very much for your help!

To recap, at the moment the code is:

Begine Routine tab

myClock.reset()

Clocktime = 0
keyClockPressed = False
ClockDelay = 1

Each Frame tab

 t=myClock.getTime()

if clock_resp.keys and keyClockPressed == False:
   Clocktime = t + ClockDelay
   keyClockPressed = True
   clock_txt.setOpacity(1)
   clock_box.setOpacity(1)

if t > Clocktime and keyClockPressed:
   clock_txt.setOpacity(0)
   clock_box.setOpacity(0)
     
clock_resp_allKeys = []
clock_resp.keys = []
clock_resp.rt = []

If you want to have multiple presses then the easiest option is to use the length of clock_resp.keys. Make sure the component is saving all responses and then use the following code:

Begine Routine tab

myClock.reset() # Not needed. t for routine time is automatic.

Clocktime = 0
keyClockPressed = False
keyClockPresses = 0
ClockDelay = 1

Each Frame tab

if clock_resp.keys:
   if len(clock_resp.keys) > keyClockPresses:
      Clocktime = t + ClockDelay
      keyClockPressed = True
      keyClockPresses += 1
      clock_txt.setOpacity(1)
      clock_box.setOpacity(1)

if t > Clocktime and keyClockPressed:
   clock_txt.setOpacity(0)
   clock_box.setOpacity(0)
   keyClockPressed = False
     

It works!! Thank you very much @wakecarter for your help, it’s been precious