psychopy.org | Reference | Downloads | Github

Sending markers to EEG through serial port

Hi

I am stuck with a problem related with sending triggers through serial port and I would be truly grateful if anyone could give any help / advice:

OS : Win 10

PsychoPy version : 1.90.1

What are you trying to achieve?:
I want to send triggers from a testing laptop to an EEG laptop.
The aim is to mark on the EEG trace the moment when a sound is presented, in order to subsequently analyse event-related potentials.

I am using Biosemi EEG system for EEG data collection.
I am using Biosemi USB trigger interface cable - which is recognized as a serial port Biosemi EEG ECG EMG BSPM NEURO amplifiers systems) for sending triggers from testing “Psychopy” laptop to EEG laptop.

Please find below an overview of the experiment / flow (simplified version for the purposes of solving the trigger issue):

I want to send a marker whenever sound_1 is presented.
Because I am not using a parallel port nor LabJack, I cannot use Builder’s I/O.

Therefore I introduced a code component as follows:

I want to present 3 different types of sounds, one sound per trial, in n trials.
I have 4 different conditions, which differ basically in the proportion of sound types.
I am presenting visual info at the same time.
I have defined the conditions/trials in an excel file (looptrials file) and the order of the conditions in another excel file (loopblocks file).

In the looptrials file I have 1 column identifying the type of sound as 0, 1 or 2. This column is named typesoundfile1.

With ‘‘port.write(b’$typesoundfile1’)’’ I mean that I want to send the number from column “typesoundfile1” corresponding to the trial row.

The good thing is that:

  1. There are triggers being sent every 5 seconds to the EEG trace.

The problems are:

  • The EEG laptop is receiving multiple types of triggers, but without any type of relationship with the numbers 0,1 and 2 present on column “typesoundfile1”: i.e. the numbers are different from 0,1 and 2 and vary independently from sound type.

While debugging this I have noticed that ‘‘port.write(b’1’)’’ sends the number 49 to the EEG. I have played around a bit to try finding a way to send 0, 1 and 2 but so far I have been unsuccessful…
I am also not sure about the most appropriate way to send trial-specific triggers based on info from an excel file…

Can anyone give some advice? Many thanks!!

Tiago

4 Likes

What you are currently doing is sending the bytes corresponding to the literal set of characters '$typesoundfile1'. By putting the variable name inside quotes, it is no longer a variable name pointing to a numerical value. It is just a sequence of characters.

Assuming that typesoundfile1 represents an integer variable, you could just try this directly:

port.write(typesoundfile1)

i.e. if this is an integer variable, then it is already effectively a number, not a character string that needs to be translated. But if it does need to be expressly converted to a particular byte representation, then try something like this:

port.write(typesoundfile1.to_bytes(length = 1, byteorder = 'little')) 

Note that the dollar sign has no particular meaning in the Python language: it is just a marker used in PsychoPy’s Builder interface to indicate to Builder itself that a value should not be taken literally but should be regarded as a Python expression.

NB just noticed that you use time.sleep() in your code component. You must remove that. Builder operates on a drawing cycle which requires it to actively do things on every screen refresh. By using this statement, you will be mucking up Builder’s timing control seriously and unpredictably. If you have a need for such a pause, it must be implemented differently.

Hi Michael

Thank you for your advice.

Indeed ‘‘typesoundfile1’’ represents an integer variable. Please see excel spreadsheet below:

image

At the moment this is basically a Stroop task combined with a Odd-ball task (sounds).

In the same routine/loop, $colour or $word in the builder can correctly access the date from this spreedsheet.

I have tried:

port.write(typesoundfile1)

in the code component: it does not produce any error but unfortunately there are no triggers going through… I suspect that it is not retrieving data from the column in the excel spreedsheet.

Your other suggestion:

port.write(typesoundfile1.to_bytes(length = 1, byteorder = 'little')) 

Generated an error:
image

Can I ask if anyone can recommend a way to send the integers from this excel spreedsheet column as triggers?

Also thank you for your comment about time.sleep(). To be honest I was suspicious about this and was going to double check… The trigger needs to be sent 1 second after routine onset, so I will look for an alternative!

Tiago

What about just port.write(bytes(typesoundfile1)) ?

To control timing, put this in the “begin routine” tab:

trigger_sent = False

and this in the “each frame” tab:

if t >= 1.0 and not trigger_sent:
    port.write(bytes(typesoundfile1)) # or whatever works
    trigger_sent = True

Hi Michael

It worked quite well, very grateful for your help! And now I understand better how to code this type of tasks.

Best

Tiago

Hi Louroprata,

I am setting up an EEG study using PsychoPy and Biosemi stuff just like you do, and I had the same question as you regarding sending markers through serial port, so all the questions and answers here really helped me (Thanks Michael!)!

Just wanted to be sure about this time.sleep() code, did you delete it in your code component the “begin routine” tab, and only included what Michael provided in the answer (trigger_sent = False)?

Many thanks!

Linda

Hi Michael,

I was wondering if you can help me identify the troubles that why aren’t the triggers appearing on the EEG recording Screen (ActView-Biosemi)?

I’m setting up an EEG study using PsychoPy and Biosemi stuff same as Louraprata, and I had the same question regarding sending markers through serial port. I believe that all the questions and answers provided by you and Louraprata on this page really helped me to navigate.

However, the product seemed a bit different for me, there was no error messages, nor triggers on the EEG recording screen.

Here is what I have tried to write in the code component:

"begin experiment"tab:
import serial
port = serial.Serial(port = ‘COM4’, baudrate = 9600) #COM4 is the right one

"begin routine:
trigger_sent = False

“each frame”
if t >= 1.0 and not trigger_sent: #I also want the trigger to be sent 1s after the routine onset
port.write(bytes(ConditionCode)) # ConditionCode is the variable name listed in the Excel file of TrialList
trigger_sent = True

“end experiment”
port.close()

I thought I got the codes right, but I actually don’t know.

On the other hand, I figured a couple of things were different from what Louraprata had, and I’m not sure if these could be the case:

  1. instead of using Biosemi USB trigger interface cable as Louraprata do, our lab is using Biosemi USB2 Receiver (https://www.biosemi.com/receiver.htm). It is still recognized as a serial port though.

  2. Strangely, the testing computer I’m using in the lab has no Microsoft Office installed (I was using my own laptop, now I’m waiting for response from ITs of my University),I don’t know if this could be a reason that the data wasn’t accessed from the spreadsheet, but other parameters defined in the spreadsheet were correctly presented on PsychoPy. (It could be a really stupid concern, but I just don’t know…).

Hope the information makes sense and doesn’t bother you too much,

Best,
Linda

PsychoPy can read Excel files itself, so don’t worry at all about whether Office is installed (in fact it is preferable for performance reasons to not have it installed on a lab machine, to reduce the number of background processes that can interfere with the timing of your experiments).

Otherwise, it is very difficult to debug serial port communications remotely. What might be best is if you install a serial port tester program on the target computer, rather than rely on your EEG system. This should show characters as they arrive from the experimental computer, and should allow you to debug the port settings and so on. Once that is working, the same settings should hopefully work for your EEG software.

Hi Michael,

Thank you so much for your reply!

I didn’t fully understand those stuff about serial port tester, so I asked a previous researcher in the lab, and got a suggestion to use code like port.write(str.encode(chr(ConditionCode))) instead of port.write(bytes(ConditionCode)). Somehow it worked well, so I’m using this code now…

Best,
Linda

Hi Linda,

I followed your conversations and code but sometimes it does not work. do you mind to share this code?
Thank you very much!
Leidy

Hi Tiago and Michael,

Thank you very much for this discussion. Tiago do you mind to post your final code. I am stuck, the code runs, but I do not get the triggers most of the time, and when I get them is only one trigger of one trial.

Thank you very much,
Leidy

Hi Leidy,

Sorry for the late reply, I didn’t realise there was a question here. Hope you have found a solution to proceed.

Anyway, here are my codes:

Begin Experiment:
#the port number should depend on your lab’s setting.

 import serial
 port = serial.Serial(port = 'COM4', baudrate = 9600)

Begin routine:

trigger_sent = False

Each frame:
#so the trigger is sent 1.032s after the routine starts, same onset as the picture stimuli # ConditionCode is the variable listed in the TrialList to distinguish conditions

if t >= 1.032 and not trigger_sent:
port.write(str.encode(chr(ConditionCode)))
trigger_sent = True

End experiment:

port.close()

Cheers,
Linda

Hi Michael, I hope you can help,
i have a similar problem that I havent solve yet. i have 5 different triggers, but when I write the code sometimes trigger 4 changes to 224 or trigger 2 to 192.
it records all the 80 trials, but with this different numbers. What can I do?