Sending a lot of UDP packets to Ethernet Shield

Hi everyone,

I recently started working on an interactive LED light installation where I’m using Unity to send a bunch of data to an Arduino with an Ethernet Shield over UDP. The Arduino receives packets in the form of char arrays like, “i, 255, 255, 200”, where ‘i’ is the index of the light that should be modified (0-144, as there are 144 LEDs per strand), and the final 3 values are the RGB components for that light. The Arduino parses this string, converts each item to an integer, and then activates or deactivates (if RGB is 0) the appropriate LED (I’m using Adafruit’s Neopixel library to manage this). The lights need to be highly responsive and at times, I may be sending close to 144 of these packets to the Arduino each frame (if the entire light strand changes). Currently, there’s a ton of lag, causing the lights to update very slowly, and I’m wondering if it’s possibly something that I’m doing in my Arduino code:

#include <Adafruit_NeoPixel.h>
#include <string.h>
#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h> 

byte mac[] = {  
  0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 };
IPAddress ip(192, 168, 15, 101);
unsigned int localPort = 80;  
EthernetUDP Udp;
char packetBuffer[UDP_TX_PACKET_MAX_SIZE]; //Buffer to hold incoming packet,

#define NUM_LEDS 144
#define DATA_PIN 6

Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUM_LEDS, DATA_PIN, NEO_GRB + NEO_KHZ800);

void setup() {
  Ethernet.begin(mac, ip);
  Udp.begin(localPort);
  strip.begin();
  strip.show();
}

void loop() {
  //If there's data available, read a packet
  int packetSize = Udp.parsePacket();

  if(packetSize)
  {
    // read the packet into packetBufffer
    Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);

    String str(packetBuffer);

    //For parsing 
    int beginIdx = 0;
    int idx = str.indexOf(',');

    String arg;
    int itemIndex = 0;
    int ledPos, r, g;
    char charBuffer[UDP_TX_PACKET_MAX_SIZE];
    
    while (idx != -1)
    {
      arg = str.substring(beginIdx, idx);
      switch(itemIndex) {
      case 0:
        //LED index
        ledPos = arg.toInt();
        break;
      case 1:
        //R
        r = arg.toInt();
        break;
      case 2: 
        //G
        g = arg.toInt();
        break;  
      }
      beginIdx = idx + 1;
      idx = str.indexOf(",", beginIdx);
      itemIndex++;
    }
    //Get the last item in the string
    int b = str.substring(beginIdx, str.length()).toInt();
    
    //Debugging
    //    Serial.println(ledPos);
    //    Serial.println(r);
    //    Serial.println(g);
    //    Serial.println(b);
    if(r == 1) {
      strip.setPixelColor(ledPos, strip.Color(127, 127, 127));
      strip.show();
    }
    else {
      strip.setPixelColor(ledPos, 0);
      strip.show();
    }
  }
}

Any help would be greatly appreciated. Thank you!!

Currently, there's a ton of lag, causing the lights to update very slowly, and I'm wondering if it's possibly something that I'm doing in my Arduino code

Define "ton of lag" and "very slowly"! How many updates are possible per second?

Regarding your code: Don't use the String class! It's probably the worst part of code included in the IDE (unfortunately). In your case I would not send the values in ASCII but just send 4 bytes, the first is the LED index, the other three are the RGB values. This way you don't have to interpret/parse the UDP packet and you can use the values immediately. Also it's better if you can include as many update values as possible in one packet because the Arduino is quite busy with updating the strips. The WS2812 drivers don't use a clock signal anymore (as the WS2801 did) and therefor the timing is critical. To ensure that timing the interrupts are disabled during string update, so you may only receive one packet during a complete string update. The more updates this packet includes the faster the response from the string.

One update of the string needs almost 5ms which is quite a long time in network terms. After each packet received you update the string so the next packet gets processed 5ms later at best.

How about changing the nature of what you send. Instead of just sending the current RGB value for any LED. you could instead send it a target rgb value to get to followed by a time (in milliseconds) to get there.

This way, instead of sending a whole raft of packets to fade an LED to a different colour, you'd just send the one packet at the start. Then leave the arduino to interpolate the intermediate values and timings required.

A further enhancement could be to include a startTime for the transition you are sending. This way you could send these instructions in advance and let the arduino put them into a buffer area and stay ahead of the game.

So changing the default UDP_TX_PACKET_MAX_SIZE to 192 bytes (rather than 24) definitely helped the latency issue. Now, I'm sending the equivalent of 48 LED's worth of updates (192 bytes / 4 bytes per LED) in each packet.

However, another problem has arisen where certain LEDs get "stuck" between the transmission of UDP packets. I think this is happens among a quick string of packets, where a specific LED is quickly turned on and off. In this case, a packet may be dropped or skipped that would otherwise correctly activate/deactivate a given LED. I think this is a timing issue that can be separately addressed.

How many packets per second are you sending? Why are you sending the data in a string? It is much faster, easier, and smaller to send the data as bytes. The numbers are from 0 to 144, correct?