Latency when sending data to RGB LED between arduino and python

My project is this: Get pixel data from the screen, send it to arduino as a string of rgb triplets, arduino parses the data and outputs it to the leds. Problem is, there is a latency between the moment something changes on the screen and the led updates accordingly. It is not a consistent lag though, sometimes a whole second, sometimes half a second or less.

I couldn’t find any solutions through preliminary searches on google or on the forums, hence this post.

Here is the python code

    s = serial.Serial(9,57600, timeout=0.001)  # opening the serial port
    time.sleep(2)
    px=ImageGrab.grab().load()
    while(True):
        time.sleep(0.01)
        px=ImageGrab.grab().load()
        pixelValue=px[235,691]
        if pixelValue[0]>pixelValue[2] and pixelValue[0]>pixelValue[1]:
            pixelText='1,1,0'
        elif pixelValue[1]>pixelValue[2] and pixelValue[1]>pixelValue[0]:
            pixelText='1,0,1'
        elif pixelValue[2]>pixelValue[1]and pixelValue[2]>pixelValue[0]:
            pixelText='0,1,1'
        else:
            pixelText='1,1,1'
        pixelArray=pixelText
        for i in range (1,3):
            pixelValue=px[235,691-(i*8)]
            if pixelValue[0]>pixelValue[2] and pixelValue[0]>pixelValue[1]:
                pixelText=',1,1,1'
            elif pixelValue[1]>pixelValue[2] and pixelValue[1]>pixelValue[0]:
                pixelText=',1,0,1'
            elif pixelValue[2]>pixelValue[1]and pixelValue[2]>pixelValue[0]:
                pixelText=',0,1,1'
            else:
                pixelText=',1,1,1'
            pixelArray+=pixelText
        pixelArray=pixelArray+'g'
        s.write(pixelArray)
        print(pixelArray)
        print('\n')

Here is the arduino code

    //Pin connected to ST_CP of 74HC595
    int latchPin = 8;
    //Pin connected to SH_CP of 74HC595
    int clockPin = 12;
    ////Pin connected to DS of 74HC595
    int dataPin = 11;
      int temp;
    
    //holders for infromation you're going to pass to shifting function
    const int numRegisters=2;
    int i,j;
    byte dataArray[numRegisters+1];
    
    void setup() {
    
      //set pins to output because they are addressed in the main loop
      pinMode(latchPin, OUTPUT);
      Serial.begin(57600);
    
      //Arduino doesn't seem to have a way to write binary straight into the code 
      //so these values are in HEX.  Decimal would have been fine, too. 
    
      //function that blinks all the LEDs
      //gets passed the number of blinks and the pause time
      blinkAll_2Bytes(2,500); 
    }
    
    void loop() {
     for(i=0;i<numRegisters;i++)
          dataArray[i]=0;
    
    while (Serial.available() > 0) {
        for(i=0;i<numRegisters;i++){
          for(j=0;j<8;j++){
            dataArray[i]+=Serial.parseInt()*(1<<(7-j));
          }
        }
            //multiply the data coming in to convert binary to decimal
        // look for the next valid integer in the incoming serial stream:
        if (Serial.read() == 'g') {
        //load the light sequence you want from array]
        //ground latchPin and hold low for as long as you are transmitting
        digitalWrite(latchPin, 0);
        //move 'em out and reset the array
        for(i=0;i<numRegisters;i++){
          shiftOut(dataPin, clockPin, dataArray[i]); 
          //Serial.print(dataArray[i]);
          //Serial.print('\n');
          dataArray[i]=0; 
        } 
          //return the latch pin high to signal chip that it 
        //no longer needs to listen for information
        digitalWrite(latchPin, 1);
        //delay(300);
      
    }
    }
    }
    
    
    
    // the heart of the program
    void shiftOut(int myDataPin, int myClockPin, byte myDataOut) {
      // This shifts 8 bits out MSB first, 
      //on the rising edge of the clock,
      //clock idles low
    
      //internal function setup
      int i=0;
      int pinState;
      pinMode(myClockPin, OUTPUT);
      pinMode(myDataPin, OUTPUT);
    
      //clear everything out just in case to
      //prepare shift register for bit shifting
      digitalWrite(myDataPin, 0);
      digitalWrite(myClockPin, 0);
    
      //for each bit in the byte myDataOut?
      //NOTICE THAT WE ARE COUNTING DOWN in our for loop
      //This means that %00000001 or "1" will go through such
      //that it will be pin Q0 that lights. 
      for (i=7; i>=0; i--)  {
        digitalWrite(myClockPin, 0);
    
        //if the value passed to myDataOut and a bitmask result 
        // true then... so if we are at i=6 and our value is
        // %11010100 it would the code compares it to %01000000 
        // and proceeds to set pinState to 1.
        if ( myDataOut & (1<<i) ) {
          pinState= 1;
        }
        else {	
          pinState= 0;
        }
    
        //Sets the pin to HIGH or LOW depending on pinState
        digitalWrite(myDataPin, pinState);
        //register shifts bits on upstroke of clock pin  
        digitalWrite(myClockPin, 1);
        //zero the data pin after shift to prevent bleed through
        digitalWrite(myDataPin, 0);
      }
    
      //stop shifting
      digitalWrite(myClockPin, 0);
    }
    
    
    //blinks the whole register based on the number of times you want to 
    //blink "n" and the pause between them "d"
    //starts with a moment of darkness to make sure the first blink
    //has its full visual effect.
    void blinkAll_2Bytes(int n, int d) {
      digitalWrite(latchPin, 0);
      shiftOut(dataPin, clockPin, 0);
      shiftOut(dataPin, clockPin, 0);
      digitalWrite(latchPin, 1);
      delay(200);
      for (int x = 0; x < n; x++) {
        digitalWrite(latchPin, 0);
        shiftOut(dataPin, clockPin, 255);
        shiftOut(dataPin, clockPin, 255);
        digitalWrite(latchPin, 1);
        delay(d);
        digitalWrite(latchPin, 0);
        shiftOut(dataPin, clockPin, 0);
        shiftOut(dataPin, clockPin, 0);
        digitalWrite(latchPin, 1);
        delay(d);
      }
    }

So, in my case, a valid string to send from python would be

1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1g

Also worthy of note is that I can see in the python shell that the program goes through the loop multiple times a second while showing the pixel values updating almost instantly, leading me to believe that the arduino or the serial comms is the source of the problem.

Thanks ahead of time!

Forgot to mention, I'm using the Arduino Uno connected to a computer running Windows 7 and python 2.7.6.

You could pick up the pace, and use 115200 as the baud rate.

Once you determine that there is one byte to read, you then wait around for 16 ints to arrive. That could take time.

You really need to read serial data as it is available, storing the data, then parse the data when the g arrives. Do not use blocking functions like parseInt().