How to organise the timing for event triggers, stimulus presentation and keypresses?

Hi! I am trying to code an experiment in psychopy which uses pyserial to send various triggers at the beginning/end of trials. My question is a general one regarding the organisation of code around stimulus timing and when to send triggers & record keypresses. I am using clock-based timing.

I want to send a trigger upon window flipping of my stimulus and have the simulus drawn using clock-based timing. How do I send a trigger at the same time as flipping & at the end of the trial but not upon every loop of my while statement, if that makes sense?

fixation_cross(1)
tapping_clock.reset()

port.write('K'.encode()) # Start trigger
    
while tapping_clock.getTime() < 10:
      tapping_text.draw()
      win.flip()
    
port.write('k'.encode()) # End trigger

I’m having the same issue with the code below where I want to send a start trigger upon presentation of the letter and have the ending trigger at the end of the trial (2 seconds) with keypresses being searched for inbetween.

nback_clock.reset()
nback_kb.clock.reset()
    while nback_clock.getTime() < 2:
        if nback_clock.getTime() < 0.5:
                letter_present.draw()
        else:
                blank.draw()
        win.flip()
        port.write('F'.encode()) # Start trial trigger
        port.write('f'.encode()) # End trial trigger

        keys_n = nback_kb.getKeys(keyList = ['left', 'right']) 
        
        # Get responses 
        if len(keys_n) > 0:
            if corrAns == keys_n[-1].name:
                answer = 1
            elif corrAns != keys_n[-1].name:
                answer = 0
                
        elif keys_n in ['', [], None]:
            answer = 'None'
        
        else:
            answer = 'error'

Sorry for all the questions, I have used psychopy before but I am not particularly well-versed in coding in psychopy and how to structure trials in this way. I would appreciate any help or advice as I can code it, I’m just unsure as how to structure it. Thank you! :slight_smile:

Try using the win.callOnFlip method:

fixation_cross(1)
tapping_clock.reset()

win.callOnFlip(port.write, 'K'.encode())   # Send start trigger on next win.flip()
 
while tapping_clock.getTime() < 10:
      tapping_text.draw()
      win.flip()
    
port.write('k'.encode()) # End trigger
1 Like

Oh great thank you! That looks like exactly what I need! :slight_smile:

Would you know whether to put the end trigger just after the key check part of the code (the end)?

If you only want to send the start trigger the first time letter_present is drawn, and the end trigger right after a key is pressed. or after the 2 second timeout period:

    start_marker_sent = False
    end_marker_sent = False
    while nback_clock.getTime() < 2:
        if nback_clock.getTime() < 0.5:
                letter_present.draw()
                if start_marker_sent is False:
                    win.callOnFlip(port.write, 'F'.encode())
                    start_marker_sent = True
        else:
                blank.draw()
        win.flip()

        keys_n = nback_kb.getKeys(keyList = ['left', 'right']) 
        
        # Get responses 
        if len(keys_n) > 0:
            if corrAns == keys_n[-1].name:
                answer = 1
            elif corrAns != keys_n[-1].name:
                answer = 0
            
            if end_marker_sent is False:
                port.write('f'.encode()) # End trial trigger
                end_marker_sent = True
    
        elif keys_n in ['', [], None]:
            answer = 'None'
        
        else:
            answer = 'error'

    # send end marker if no keys were pressed (timeout)
    if end_marker_sent is False:
        port.write('f'.encode()) # End trial trigger
1 Like

Thank you so much!! If I want the marker just at the end of the 2 second period, I just remove the end_marker_sent variable and just put the end trigger at the end of the while loop?

Yes, that as well as the first end trial trigger that was being sent if a key was pressed.

1 Like

Yes I’ll put the end trigger after/outside of the while loop