Record keyboard presses relative to a user-created clock in the Builder

What are you trying to achieve?:
Our fMRI scanner sends signals that are interpreted as a keyboard press ‘6’. I want to end up with a list of times of each pulse relative to the first pulse in my data file.

What did you try to make it work?:
I’ve crudely solved this problem editing the code, but I would love to be able to achieve this in a neater way or ideally using Builder. What I’ve done so far is create a code component that starts a clock when the first pulse is detected. The start of this clock, however, is tied to the end of a routine (the ‘waiting for scanner’ routine which ends when it detects a ‘6’).

What this method doesn’t work for, though, is the subsequent 6s, which don’t end their respective routines. So, I simply added a ‘scanner check’ keyboard component to every routine that records 6s. After compiling from Builder, I edited the code to get the time relative to the first pulse clock if/when each of these components picks up a ‘6’, and append that time to a list. Then I added it to the data file with thisExp.addData. This seems clunky, though, and I wish I could achieve the same result with a code component in the Builder.

Does anyone know how I could make this work using the Builder?

Thanks :grinning:

You could use the variable t for this - t is always the time since the start of the routine. So you could store the time of the first pulse and, each frame, calculate t - timeOfFirstPulse via a Code component. If you send over the .psyexp file so I’ve got an idea of what your variables are called and what your overall procedure is like I can give you more specifics

1 Like

Thanks, @TParsons! My goal has changed slightly. Instead of storing the scanner pulses relative to the first pulse, I’d just like to record everything relative to the start of the experiment (globalClock).

So essentially what I’d like to do is – each time a 6 is recorded once the experimental trials begin, do something like:


Possible in the Builder, you think?

Link to .psyexp

Many thanks!!

You can also do that, yes! If you call:


This will give you the time elapsed since psychopy.core was imported (in Builder experiments, psychopy.core is imported at the very start of the experiment, in line 22)

1 Like

Thanks @TParsons . Apologies for not communicating clearly - what I’m unsure about how to do is the “check that a 6 was pressed and add the time to a list” part.

You mentioned that I could have a code component for each frame (is this each frame of the whole experiment?) Would you recommend something along the lines of this?

Beginning of exp:

scanner_pulses = []
scanner = keyboard.Keyboard()

Each frame:

scanner_keys = []
scanner_keys = scanner.getKeys('6', waitRelease = False)
if len(scanner_keys):

End of exp:
thisExp.addData('scanner_pulses', scanner_pulses)

When I tested this (while pressing 6 periodically during the exp), I ended up with scanner_pulses as an empty list in my data file.

Any thoughts? Thanks.

The Each Frame tab of a Code component only runs each frame of the Routine the Code component is in, I think the problem might be with how you set up scanner - rather than doing it in code, you could try making a Keyboard component in Builder in the same Routine as your Code component and refer to that instead

1 Like

Thanks @TParsons – I’ve gotten 99% of what I need by putting an “each frame” component in each of the relevant routines.

Strangely, though, neither core.getTime() nor globalClock.getTime() seem to be on the same “schedule” as the times in the data file. For example, I have a routine called “Fixation” that begins after the first scanner pulse is detected. In the data file, fixation_text.started = 56.33, but the first entry on my scanner_pulses list is 57.9. This is impossible since the first pulse is (indirectly) what triggers fixation_text.

Therefore, my question is: which clock are the times in the data file relative to? e.g. fixation_text.started

The start time of each component comes from a timer started at the beginning of its routine - so the 1.3s difference is most likely the time between starting the experiment (importing core.time at line 18) and beginning the first routine (after intialising all the components).

If you want to know what global time the routine timer started at, you could add a call to core.getTime() in the Begin Routine tab - this will get placed within a few (pretty inconsequential) lines of the routine timer starting, so the timing should be milliseconds off if anything.

1 Like

I resolved the issue thanks very much @TParsons