1

I'm trying to stream sensor data from my Arduino (server), over my network, to my computer (client) in real-time.

While sensor data is coming in at a consistent rate per second, the time between messages is highly irregular.

I tested both UDP and TCP connections with both one directional and bidirectional communication on minimal examples to isolate this behavior.

I also tried adding delays, using different settings (SOCK_STREAM vs TCP_NO_DELAY), decreasing the message size, and adding headers to the message in attempt to synchronize the connection, if that was the issue.

In every case, the messages come in consistent, but in inconsistent burst like this:

enter image description here

*message is always "test", frame number printed instead for illustration

Why is this happening and how can I make time between messages more consistent/stable?


Below are the bare minimum examples I tested on:

One Directional (server -> client)

TCP Client

    import time
    import socket
    
    ADDRESS = "xxx.xxx.xxx.xxx"
    PORT = 80
    SIZE = 4
    
    sock = socket.socket(socket.AF_INET, socket.TCP_NODELAY)
    sock.connect((ADDRESS, PORT))
    
    print("Waiting for connection...")
    sock.recv(SIZE)
    print("Connected")
    
    t0 = 0
    f = 0
    while True:
        data = sock.recv(SIZE).decode()
        if f == 0:
            t0 = time.time()
            time.sleep(.0001)
    
        f += 1
        fps = int(f / (time.time() - t0))
        print(f"\r{f} FPS: {fps} data: {data}   ", end='')

TCP Server

    #include <WiFiNINA.h>
    
    WiFiServer server(80);
    
    void setup() {
      Serial.begin(115200);
      int status = WL_IDLE_STATUS;
      while (status != WL_CONNECTED) {
        status = WiFi.begin("ssid", "password");
        delay(1000);
      }
      server.begin();
    
      Serial.println("connected");
      Serial.print("SSID: ");
      Serial.println(WiFi.SSID());
      IPAddress ip = WiFi.localIP();
      Serial.println(ip);
    }
    
    void loop() {
      server.write("test");
      delay(16);
    }

UDP Client

import socket
import time

ADDRESS = "xxx.xxx.xxx.xxx"
PORT = 2390
SIZE = 4

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto(b"s", (ADDRESS, PORT))

print("Waiting for connection...")
sock.recvfrom(SIZE)
print("Connected")

t0 = 0
f = 0
while True:
    data, addr = sock.recvfrom(SIZE)
    data = data.decode()
    if f == 0:
        t0 = time.time()
        time.sleep(.0001)
    
    f += 1
    fps = int(f / (time.time() - t0))
    print(f"\r{f} FPS: {fps} data: {data}   ", end='')

UDP Server

#include <WiFiNINA.h>
#include <WiFiUdp.h>

WiFiUDP Udp;

void setup() {
  Serial.begin(115200);
  int status = WL_IDLE_STATUS;
  while (status != WL_CONNECTED) {
    status = WiFi.begin("ssid", "password");
    delay(1000);
  }
  Udp.begin(2390);

  Serial.println("connected");
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());
  IPAddress ip = WiFi.localIP();
  Serial.println(ip);
}

void loop() {
  Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
  Udp.write("test");
  Udp.endPacket();
  delay(16);
}
Bi Directional (server <> client)

TCP Client

import time
import socket

ADDRESS = "xxx.xxx.xxx.xxx"
PORT = 80
SIZE = 4

sock = socket.socket(socket.AF_INET, socket.TCP_NODELAY)
sock.connect((ADDRESS, PORT))

print("Waiting for connection...")
sock.send(b's')
sock.recv(SIZE)
print("Connected")

t0 = 0
f = 0
while True:
    sock.send(b's')
    data = sock.recv(SIZE).decode()
    if f == 0:
        t0 = time.time()
        time.sleep(.0001)

    f += 1
    fps = int(f / (time.time() - t0))
    print(f"\r{f} FPS: {fps} data: {data}   ", end='')

TCP Server

#include <SPI.h>
#include <WiFiNINA.h>

WiFiServer server(80);

boolean alreadyConnected = false;

void setup() {
  Serial.begin(9600);
  while (!Serial);

  Serial.print("Connecting to Wifi... ");
  int status = WL_IDLE_STATUS;
  while (status != WL_CONNECTED) {
    status = WiFi.begin("ssid", "password");
    delay(500);
  }
  Serial.println("connected.");
  server.begin();

  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());
  IPAddress ip = WiFi.localIP();
  Serial.println(ip);
}

void loop() {
  WiFiClient client = server.available();
  if (client) {
    if (!alreadyConnected) {
      client.flush();
      alreadyConnected = true;
    }
    if (client.available() > 0) {
      char thisChar = client.read();
      client.write("test");
    }
  }
}

UDP Client

import socket
import time

ADDRESS = "xxx.xxx.xxx.xxx"
PORT = 2390
SIZE = 4

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.sendto(b"s", (ADDRESS, PORT))

print("Waiting for connection...")
sock.recvfrom(SIZE)
print("Connected")

t0 = 0
f = 0
while True:
    sock.sendto(b"s", (ADDRESS, PORT))
    data, addr = sock.recvfrom(SIZE)
    data = data.decode()
    if f == 0:
        t0 = time.time()
        time.sleep(.0001)
    
    f += 1
    fps = int(f / (time.time() - t0))
    print(f"\r{f} FPS: {fps} data: {data}   ", end='')

UDP Server

#include <WiFiNINA.h>
#include <WiFiUdp.h>

WiFiUDP Udp;

void setup() {
  Serial.begin(115200);
  while (!Serial);
  Serial.print("Connecting to Wifi... ");
  int status = WL_IDLE_STATUS;
  while (status != WL_CONNECTED) {
    status = WiFi.begin("wifi", "password");
    delay(500);
  }
  Serial.println("connnected.");
  Udp.begin(2390);

  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());
  IPAddress ip = WiFi.localIP();
  Serial.println(ip);
}

void loop() {
  if (!Udp.parsePacket()) {
    return;
  }

  while (Udp.read() != -1);
  Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
  Udp.write("test");
  Udp.endPacket();
}
dandev
  • 83
  • 1
  • 7
  • This sounds like a network or hardware problem, not a code problem. – Barmar May 12 '23 at 00:16
  • The first thing I would do is rewrite your test programs in C, to rule out the Python interpreter as a culprit. (Python isn’t known for its speed) – Jeremy Friesner May 12 '23 at 00:24
  • @JeremyFriesner while Python may be slower than other languages, I'm not asking it to break encryption here. Receiving 4 bytes over socket at a consistent rate of at least 15 fps should be more than doable – dandev May 12 '23 at 00:40
  • How is your arduino connected to the server? I ask because it may be something in the physical layer. – hugos May 12 '23 at 02:32
  • @hugos I'm using an Arduino MKR wifi 1010 with a built in u-blox NINA-W102 radio module, so not any additional/external hardware to create the server – dandev May 12 '23 at 02:40
  • Got it. That makes sense. Another question: is the client running in your local machine or are you connected through SSH? – hugos May 12 '23 at 02:48
  • The reason this matters is that the jitter you observe might be due to the output itself. You are writing a new line for every incoming packet and SSH can be slow to catch up. – hugos May 12 '23 at 02:52
  • @hugos local machine :/ – dandev May 12 '23 at 02:57
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/253617/discussion-between-hugos-and-dandev). – hugos May 12 '23 at 03:01
  • @dandev agreed; my concern is that maybe once in a while the Python interpreter takes a little break to do some garbage collection, or something like that. – Jeremy Friesner May 12 '23 at 04:37

0 Answers0