If this template helps then use it. If not then just delete and start from scratch.
OS Ubuntu 22.04 LTS PsychoPy version 2024.1.4 Standard Standalone Installation? (y/n) y Do you want it to also run online? (y/n) n What are you trying to achieve?:
I want to send triggers to a Biosemi EEG system using a Neurospec MMBT-S interface box. While sending the triggers works, the triggers themselves are recorded with different values than intended. For example, sending ‘1’ is recorded as ‘49’. Also the triggers seem to be inverted, sending a ‘111’ is also received as a ‘49’.
The interface box is set up as described in the manual, running in pulse more. Using the simple mode did not work. There were no triggers in simple mode. In pulse mode, the MMBT-S sends the triggers as received from the sending computer. In addition, after 8 ms, the MMBT-S will automatically send a trigger ‘0’ to pull all pins to LOW.
**What have you tried to make it work?
If I change the code written by the builder serialPort.write(bytes('111',utf8')) to the code suggested in the interface manual to test the interface serialPort.write(bytes(bytearray([111]))) the triggers are sent as intended.
Any explanation for the strange trigger values? Any suggestions on how to get the intended trigger values using the Builder?
I think I know why I get ‘49’ as a trigger when sending ‘111’.
The command serialPort.write(bytes('111',utf8'))
converts the character string ‘111’ into a bytes object by encoding each character according to UTF-8. As ‘111’ is three separate characters, three separate bytes are generated:
The result is a bytes object with three bytes: \x31\x31\x31.
So the command writes three bytes with the values 49, 49 and 49 (the ASCII codes for the digits ‘1’).
The command seriaPort.write(bytes(bytearray([111])))on the other hand, creates a byte array with a single element that has the value 111. This value is then converted directly into a bytes object. In this case, only a single byte with the value 111 is written.
The command serialPort.write(bytes([111])) should send the correct trigger value of ‘111’. So enclosing the trigger value with [ ] in the Start data parameter of the serial port component should do the trick.
I notice when hovering over the Start parameter of the serial component that a hint is display. This hint says that “Data will be converted to bytes, so to specify a numeric value directly use $chr(…).” While this works for ranging from 0 - 127. Values over 127 will not be converted to the intended numeric value which basically restricts the use of the serial port.
Thanks for digging into that Jens, I never noticed that the bytes(chr(trigger)) doesn’t work above 127 (so only a 7-bit value ), Using chr(128) does return the same value as bytearray([128]) so the issue is the unicode->str conversion rather than the chr conversion itself.
Your fix looks good and, as a minimum, we’ll fix that in the docs/tooltip.
Going further, I’ve talked before with @Kimberley_Dundas and now with @TParsons about providing a “datatype” dropdown for options, so that the user doesn’t need to look up how to convert between different types of trigger. I’m imagining options for:
string (as currently, so you can send “yes”)
numeric (0-255)
binary (e.g. 00111010 which is convenient to visualise particular lines going up/down)
The code from builder would then be hard-coded accordingly in the script (eg. int(trigger, 2) for the binary setting)
I think this will help people to think about the fact that an 8-bit value can be represented in various interchangeable ways and you need to be aware of your format
Not being a programmer and knowing almost nothing about Python, I was happy to find a solution that worked for me. The solution you suggest would be a great improvement.
It seems that the work-around was only tested with 128 as a value above 127. Reduced to 7 bits, that is 0. With the Biosemi EEG system, we are trying to send code 254 to start saving the data and 255 to temporarily stop saving, between phases of the study. Our PsychoPy application also uses other triggers above 127. Preparing the trigger as trig=chr(triggerValue) with $trig as data to transmit over the serial port, or simply having $chr(triggerValue) as data to be transmitted produce the same effect. For the event codes, we could use a work-around that sends two bytes, the hundredth’s and the modulo base 100 (one as data and one as stop). But this does not work for sending the required values of 254 and 255. Not sending these signals means risking to run the experiment, having forgetten to save the data. Please inform me when the proposed improvement, i.e. using numeric(254), would become available.