psychopy.org | Reference | Downloads | Github

Word by word sentence presentation with parallel port output


#1

Hi

I am presenting sentences with different lengths. I am presenting them word by word.

  1. I generated a xlsx with the sentences in one column ($sentence)
  2. inserted a coder afterwards following instructions of a previous forum topic:

AT BEGIN ROUTINE:

# get the sentence for this trial and
# split it into a list of words:
words = sentence.split()

# count them (the length of the list):
numWords = len(words)
 
# how long the text component should display for:
totalDuration = numWords * 0.5 # time in seconds

fixationDuration = 1.0 # put in whatever your actual fixation duration is
currentWordIndex = -1 # will be useful later

AT EACH FRAME

# t is the time elapsed in the trial.
# Calculate what word we should be up to by seeing how many
# 500 ms periods have elapsed so far (& force it to be an integer):
checkIndex = int((t-fixationDuration)/0.5)

# see if we need to switch to a new word (including the very first one):
if checkIndex != currentWordIndex:
    currentWordIndex = checkIndex
    text.setText(words[currentWordIndex]) # update to the current word

The presentation runs fine. However, I would like to send a trigger via parallel port at a certain word in the sentence, sometimes is the last word of the sentence but not always. I guess I should generate anothervariable in the xlsx file with the number of the word in each sentence that needs the trigger and then add it to the coder.

I am new to psychopy so any help is welcome
thanks a lot


#2

Yes indeed.

But the first step is probably to create a separate Builder test experiment that just contains a parallel port component and check that you can actually send and receive appropriate messages to your external hardware. Once you have confirmed that works, it will be simple to incorporate the relevant command(s) into the code above.


#3

Thank you for your response.

yes the parallel port works, moving on to incorporate the triggers and find out the relevant command(s) :slight_smile:

Elena


#4

We can’t supply that for you, as parallel port protocols are unique to a particular situation (e.g. what data is sent, how long does the pulse last for, and so on). Presumably you know that info, as you’ve managed to get parallel port communication working on its own.

So tell us the details, and we can then show how to incorporate it into the code above.


#5

Hi Michael

Thanks again for your response. I am slow doing this because the computer with the functioning port is different from the one I build the paradigm from.

Anyway, the data that will be sent is a numerical variable containing the numerical code for the condition (in the xlsx file). The pulse will be 20 ms long. The address is the usual (address=0x0378)

I have been trying to send a visual output with a conditional: if currentWordIndex == word_num (this is a variable with the word number in the sentence when the trigger should be sent)
It worked for the visual input but I am doing something wrong when replacing the visual input with the command parallel.setData(cond)

Thanks so much again.
Best
Elena


#6

Do you get any errors? If so, please post them here. Otherwise, we are just guessing. But two possible issues:

You are using parallel as the name of your parallel port object, but that is likely also the name of the code library that is imported to deal with the parallel port. You should use a different name when you create your parallel port object. e.g. this is how Builder does it:

 p_port = parallel.ParallelPort(address=u'0x0378')

One thing to be aware of is that you might need to explicitly convert your ‘cond’ variable to an integer, e.g:

p_port.setData(int(cond)) 

Come back to us about this and then we can discuss pulse duration.


#7

test__triggers(5).psyexp (7.2 KB)

expe_test.xlsx (9.5 KB)

Hi, I attach the experiment and the associated excel file. It is a demo just to test all components, so I have still to introduce the whole pool of sentences, and intro and ITI etc. But if this works the rest should be no problem.

It seems to work as per the triggers part now. I would appreciate if you could have a look at the timing of the triggers to confirm It is fine.

At the end of the experiment I get an error " ‘Nonetype’ object has no attribute ‘split’

Thanks very much, again
Elena


#8

This is because you have blank cells in the last row of your conditions file. i.e. there is no valid content for the sentence on the last row of the file for the final iteration of the loop.

On the trigger front, your current code is this:

if currentWordIndex == trigger_w:
      p_port.setData(cond)
      core.wait(0.001)
      p_port.setData(0)

Note that this code runs on every frame (typically at 60 Hz), so your signal will actually be sent multiple times during the presentation of the word. Also, we should generally avoid using core.wait() in Builder scripts, it can muck up the timing (plus this is only waiting 1 ms, which is too short for your desired pulse duration of 20 ms). But also note that because we are stuck within Builder’s 60 Hz event loop, we can’t easily achieve a pulse width of exactly 20 ms, as this code runs only at a granularity of 16.7 ms intervals. So we will add a check to end the pulse if at least 20 ms have elapsed…

First, you need to have some code in the Begin routine tab so that we set things up so the pulse is only sent oncer per routine, and to catch any edge cases where perhaps the trial ended before we had the chance to terminate the pulse:

In the Begin Routine tab:

pulse_sent = False # keep track of whether a signal has been sent yet
# tidy any that may have not been terminated properly:
p_port.setData(0) 
pulse_terminated = True

In the Each Frame tab:

# send a signal at the beginning of the appropriate word:
if currentWordIndex == trigger_w:
    if not pulse_sent:
        p_port.setData(cond)
        pulse_start_time = t
        pulse_sent = True
        pulse_terminated = False

# terminate the signal at least 20 ms later:
if pulse_sent and not pulse_terminated:
    if t - pulse_start_time >= 0.020:
        p_port.setData(0)
        pulse_terminated = True

Hope that helps.


#9

Thanks a lot. It makes sense. Actually, as you say, I was seeing the triggers in the raw file that lasted for the duration of the word. I did not mind it because was only going to segment from the beginning of the pulse. But this is really much better!. (btw. I wrote 0.001 in a moment for another error with timing and forgot to change it, but meant 0.02).

It´s been very helpful, thanks again.


#10

It worked. Thanks again.