psychopy.org | Reference | Downloads | Github

Psychopy lagging when connecting with Labjack


#1

Hi everyone,

I’m trying to implement a MEG experiment with visual stimuli. I’m using Psychpy (version 1.85.6, Python version 2.7) with the Coder on a MacBook Pro (macOS Sierra 2017, version 10.12.5, 13-inch), which is connected to a Labjack (U3-LV) that sends signals to an Elekta trigger box via digital I/Os.

The design is as below: Each trial consists of 3 visual text appearing at 3 regions (1 per region); each should last for 500 ms (30 frames per region on a 60 HZ refresh rate). The experiment has 8 conditions (x 3 regions), requiring 24 binary-digit combinations, and therefore we need to use 5 FIOs of the labjack.

I was trying to ask labjack to send a specific digital 0/1 combination corresponding to a given condition in a given region at the onset of the visual text stimuli (if frame == 0). The relevant parts of the script are attached below. The stimuli and the digital 0/1 combinations are imported from an .csv file.

[Problem] When connected with Labjack (5 FIOs), Psychopy began to lag after the experiment ran for about 15~20 minutes, and the updates showing in the output window was delayed. Associated with this, some visual stimuli stayed on the screen longer than expected. The situation got worse later and sometimes Psychopy stopped responding.

Not sure if this is relevant, but it seemed that Psychopy required a lot of CPU to run with this script, sometime occupying ~99.5 or 99.9% of the CPU. This problem did not occur when Labjack was not connected, so I’m wondering whether it has to do with those lines that call for Labjack (while 30 frames are drawn at every region).

I have tried the following approaches but none of these solved the above problem:
(1) closing all other applications
(2) running on an oder version of PsychPy (version 1.83.04)
(3) calling the labjack at only one region (instead of three), and further using only 3 FIOs.

Does anyone have an idea about how to deal with this issue?
If I’m missing anything, I’ll be grateful if someone could please let me know.
Thank you!

Sincerely,
Lai

# Timings
framesIntertrial = 30       # in frames. ~ 500 ms on 60 Hz
framesFix = 30              # in frames. ~ 500 ms on 60 Hz
framesTar = 30              # in frames. ~ 500 ms on 60 Hz

# Set up labjacks U3
from psychopy.hardware.labjacks import U3
from labjack import u3
d = u3.U3()
--------
 # Displays trials. 
for trial in trialList:
        # Prepare trial here, before entering the time-critical period        
        stimRegion1.setText(trial['region1'])
        stimRegion2.setText(trial['region2'])
        stimRegion3.setText(trial['region3'])

# ACTION: THIS IS THE TIMING CRITICAL PART
        # Fixation
        win.callOnFlip(clock.reset)
        for frame in range(framesFix):            
            stimFix.draw()
            win.flip()      
            
        # Blank 
        for frame in range(framesTar):
            stimBlank.draw()
            win.flip()
            print frame    
        
        # Region 1
        for frame in range(framesTar):
            stimRegion1.draw()
            win.flip()
            print frame
            if frame == 0:
               d.setFIOState(2, int(trial['fio2x']))
               d.setFIOState(3, int(trial['fio3x']))
               d.setFIOState(4, int(trial['fio4x']))
               d.setFIOState(5, int(trial['fio5x']))
               d.setFIOState(6, int(trial['fio6x']))        

        # Blank 
        for frame in range(framesTar):
            stimBlank.draw()
            win.flip()
            print frame
                        
        # Region 2
        for frame in range(framesTar):
            stimRegion2.draw()
            win.flip()
            print frame
            if frame == 0:
               d.setFIOState(2, int(trial['fio2y']))
               d.setFIOState(3, int(trial['fio3y']))
               d.setFIOState(4, int(trial['fio4y']))
               d.setFIOState(5, int(trial['fio5y']))
               d.setFIOState(6, int(trial['fio6y'])) 
               
        # Blank 
        for frame in range(framesTar):
            stimBlank.draw()
            win.flip()
            print frame

        # Region 3
        for frame in range(framesTar):
            stimRegion3.draw()
            win.flip()
            print frame
            if frame == 0:
               d.setFIOState(2, int(trial['fio2z']))
               d.setFIOState(3, int(trial['fio3z']))
               d.setFIOState(4, int(trial['fio4z']))
               d.setFIOState(5, int(trial['fio5z']))
               d.setFIOState(6, int(trial['fio6z']))
                 #parallel.setData(int(trial['trigger3']))
                 
        # Blank 
        for frame in range(framesTar):
            stimBlank.draw()
            win.flip()
 
        # END OF TIMING CRITICAL SECTION

#2

Try deleting all of the print(frame) lines. Printing so often can cause issues. If you need info at such a rapid rate, try properly logging it rather than printing to screen during the experiment (http://www.psychopy.org/api/logging.html)


#3

Hi Michael,

Thank you for your reply!
I did try running the experiment without the line print(frame) before and got the lagging problem. That line was added only later when I was wondering whether the problem is associated with using frames; I will try logging it as you suggested.
Is there any other potential issue that could cause the lagging?


#4

This is drawing something up from the deep dark recesses of my memory. I seem to recall something about there being some delays in setting each pin, and that it might be best to set them all together (i.e. to construct an entire byte to send rather than set each bit separately).

I can’t find that thread, but check here:
http://www.psychopy.org/api/hardware/labjack.html

and here:

to make sure you are using PsychoPy’s modified U3 package and then you can access the setData() method: https://groups.google.com/d/msg/psychopy-users/4Fxoqbqt5lw/YsHfvypIP-sJ

Some discussion was here: https://labjack.com/forums/u3/bit-latency-digital-output-fio0-fio7 but I’m not sure that those sort of microsecond delays are causing your problem, but they can cause issues at the receiving end, as each bit is only available to be read very briefly before a new bit is set, wiping out the previous one.


#5

Hi Michael,

Thank you very much for your reply!

I tried to use the setData() function to “package” the 5 FIOS status together as you suggested, and now the lagging issue is solved. It took me quite some time to figure out how to use this function though, and below are what I have so far. If you perceive any issues, I would appreciate if you could please let me know.

In addition, your suggestion of logging the experiment with Psychopy’s package helped me to check the timestamps. With setData() used (instead of setting each FIO individually), the logging file showed that each regional text appeared about 0.5 sec though there were 0.0001~0.0002 sec differences.

Thank you so much!

Sincerely,
Lai

### Beginning 
from psychopy.hardware.labjacks import U3
from labjack import u3

def setData(self, byte, endian='big', address=6701):
    """Write 1 byte of data to the U3 port
    parameters:          
        - byte: the value to write (must be an integer 0:255)
        - endian: ['big' or 'small'] (ignoring) determines whether the first pin is the least significant bit or most significant bit
        - address: the memory address to send the byte to
        - 6008 = EIO (the DB15 connector)
        - 6700 = FIO
        - 6701 (default) = EIO (the DB15 connector)
        - 6702 = CIO
    """
        #Upper byte is the writemask, and lower byte is the 8 lines/bits to set. Bit 0 = line 0, bit 1 = line 1, bit 2 = line 2, etc.
    self.writeRegister(address, 0xFF00 + (byte&0xFF))

u3.U3.setData = setData
d = u3.U3()

### Trial begins 
for trial in trialList:
     # Region 1
        for frame in range(framesTar):
            win.logOnFlip('Region01:frame %i occurred' %frame, level = logging.EXP)
            stimRegion1.draw()
            win.flip()           
            if frame == 0:
               d.setData(int(trial['xByte']))

### Last part
d.setData(32)

#6

That is effectively perfect timing.