WT32-eth01 SENDUDP 10% packet loss

hey
i have a client side that sends udp struct via phiscal eth connection.
and i tried with both the :
#include <AsyncUDP.h>
and #include <WiFiUdp.h>
but i get an avearge of 10% packet loss.
i even introduced longer loop time of 5ms in order to try and reduce packetLoss but without success.
this is my code

#include <ETH.h>
#include <AsyncUDP.h>  // Works with Ethernet as well
#include <Wire.h>
#include <Adafruit_ADS1X15.h>
// Target IP and Port
IPAddress target_IP(192, 168, 1, 52);
const uint16_t target_Port = 1002;

// ESP32 Ethernet Configuration
IPAddress local_IP(192, 168, 1, 50);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);
IPAddress primaryDNS(8, 8, 8, 8);
IPAddress secondaryDNS(8, 8, 4, 4);

#define ETH_PHY_TYPE    ETH_PHY_LAN8720
#define ETH_ADDR        1
#define ETH_POWER_PIN   16
#define ETH_MDC_PIN     23
#define ETH_MDIO_PIN    18
#define ETH_CLK_MODE    ETH_CLOCK_GPIO17_OUT
Adafruit_ADS1115 ads; 
uint8_t mac[] = {0xDE, 0xAD, 0xBE, 0xEE, 0xFE, 0xEE};

// UDP Object (use AsyncUDP instead of WiFiUDP)
AsyncUDP udp;
int currentTime=0;
int perviousTime=0;
// Struct to send
struct msg {
  uint16_t Pitch;
  uint16_t Roll;
  uint16_t Avg_Roll;
  uint16_t Avg_Pitch;
  uint16_t stamp;
};
#define WINDOW_SIZE 8  // Define the window size for averaging
int16_t pitchWindow[WINDOW_SIZE] = {0};  // Circular buffer to store last 8 values
uint8_t windowIndex = 0;  // Current position in the buffer
int32_t sumPitch = 0;
void setup() {
  Serial.begin(115200);
  delay(1000);

  Serial.println("Initializing Ethernet...");
  ETH.begin(ETH_PHY_TYPE, ETH_ADDR, ETH_MDC_PIN, ETH_MDIO_PIN, ETH_POWER_PIN, ETH_CLK_MODE);
  ETH.macAddress(mac);
  delay(100);
  ETH.begin();
  ETH.config(local_IP, gateway, subnet, primaryDNS);

  // Wait for a valid IP address
  while (!ETH.localIP()) {
    Serial.println("Waiting for Ethernet connection...");
    delay(1000);
  }

  Serial.print("Ethernet Connected. IP Address: ");
  Serial.println(ETH.localIP());

  // No need to call begin() for AsyncUDP

  Wire.begin(15, 14); // SDA = IO15, SCL = IO14
  if (!ads.begin()) {
    Serial.println("Failed to initialize ADS1115!");
    while (1);
  }
  ads.setGain(GAIN_TWOTHIRDS);  // Set gain for 0-6.144V range
  ads.setDataRate(RATE_ADS1115_860SPS);   // Set highest data rate (860 SPS)
  Serial.println("ADS1115 initialized.");
}
uint16_t  SlidingWindow(int16_t rawValue)
{
   // Update the running sum: remove the oldest value, add the new one
  sumPitch -= pitchWindow[windowIndex];  // Remove the old value
  pitchWindow[windowIndex] = rawValue;   // Insert new value
  sumPitch += rawValue;  // Add new value to sum
  // Move index forward in circular buffer
  windowIndex = (windowIndex + 1) & (WINDOW_SIZE - 1);  // Faster modulo for 8 since its a bitwise AND
  // Compute average
  return sumPitch >> 3; 
}
void loop() {
  static uint32_t previousMicros = 0;
  uint32_t currentMicros = micros();

  // Check if 4000 microseconds (4 ms) have passed
 // if (currentMicros - previousMicros >= 5000) {
    previousMicros = currentMicros;
    
    // Fill struct with example data
    static uint16_t stamp = 0;
    
    int16_t rawValue = ads.readADC_SingleEnded(0);  // Read from A0
    //float voltage = rawValue * 6.144 / 32767.0;
    uint16_t avgPitch = SlidingWindow(rawValue);
    
    msg data;
    data.Pitch = rawValue;
    data.Roll = 0;
    data.Avg_Roll = 0;
    data.Avg_Pitch = avgPitch;
    data.stamp = stamp++;
    
    // Send UDP Packet
    udp.writeTo((uint8_t*)&data, sizeof(data), target_IP, target_Port);
//  }
}

Try increasing your loop time.

Obviously, UDP is a lossy protocol, so dropped packets are expected. If an Ethernet stack determines that there are "too many" UDP packets, it can discard them. The determination of "too many" is up to the stack, but I guess "too many" would be if a queue is full, or a buffers used up, etc.

What kind of device is the target 192.168.1.52?
Maybe it can't take UDP packets that fast.

What does the U in UDP stand for? YOU are responsible for either maintaining reliability of delivery, or the design is tolerant of unreliable data, your choice and responsibility.

i have tried that but the loose packet ratio remained at 10%

its a PC connected via a lan cable. but even when i increase the loop time the packet lost ratio remains at 10%

i would appreciate input that i can use rather than a general saying which doesn't help me.

I don't see a delay in your loop.

i marked it out
but i tested with 5ms and 4ms loop time

What app is running on the receiver computer?
The receiver device must empty the receive buffer before it can receive another packet. If there is a packet in the receive buffer, it won't take another.

the other side i udp server that i run on a python script .
using the socket library

Is the receiver device Python script small enough to post?

5ms is still not very much. Test with higher values like 50, 100 until you see no packet loss.
If you are using the Ethernet shield, it is quite slow relatively speaking.

If you use Wireshark, you could maybe see if packets are being sent, or lost in the Arduino side. Otherwise, if the loss is somewhere else in the network, you will have to trace inside those boxes (could be difficult).

Some people seem to think UDP is a way to bypass the overhead of TCP and get better performance. What they actually get is similar performance but unreliable transfer.

On the same ethernet localnet, I find UDP very reliable.

In protocols "reliable" does not mean the same thing as common usage. It means that the protocol has a mechanism to detect and recover lost packets. UDP does not have that. By design and definition UDP is not reliable. It doesn't mean "I tried it and it seems to work ok".

I'm out.

If the UDP sender and receiver are on the same localnet, the UDP protocol is reliable. The UDP protocol communicates with the first device on the route to the destination (receiver) and reports the result of that transaction. If not localnet, the router (gateway) will be the first device. If localnet, the first device is the destination. If that device receives the packet, it sends an ACK. If busy, sends a NACK. The first device on this network will be the destination (receiver). The result (return value) will indicate whether the receiver got the packet or not. Seems reliable to me.

We don't write your code; we give clues, pointers, and hints. You have literally almost got the code if you would just accept rather than fight. 10% loss is not surprising for the Unreliable Datagram Protocol. Do you need 100% reliability? If you do, then use TCP.