Goal: learn about the effects on performance when packing more than a single data point per UDP packet.
The code used here is available at GitLab.
Experiment with multiple data point per UDP packet
Experiment setup
Experiment was run using this script.
- simple python script
- uses
subprocess
to runnetcat
in the background to capture all the UDP packets sent by Arduino - communicates with Arduino using
pyserial
, ONLY to launch tests
Packets received by Raspberry Pi (using
netcat
) was parsed using this script.
Arduino code
This is based on the same code from “Method 3” of the previous post.
A struct
is used to represent a single data point. At the moment
there is no need for msg_type
, but probably a mechanism will be needed
to identify what kind of measurement this data point represents
(for example: position, temperature, angle, G force, etc.).
struct message {
unsigned int msg_type;
unsigned int value;
unsigned int timestamp;
};
Then a big array is defined, to hold MULTI_ARR_SIZE
data points:
#define MULTI_ARR_SIZE 128
message msg_buff_multi_array[MULTI_ARR_SIZE];
The experiment consisted in sending packets with different amount of data points,
ranging from 1 Data point per packet, up to MULTI_ARR_SIZE
data points per packet:
for (unsigned int data_points = 1; data_points <= MULTI_ARR_SIZE; len++) {
for (int i=0; i<1000; i++) {
send_multiple_datapoint(ip, data_points);
}
}
The send_multiple_datapoint()
function is very simple:
- stores in
msg_type
the amount of data points included in the packet (this value is used in the Raspberry Pi to make sure the packet contains all the data that was sent from the Arduino, and plays a key role in some of the findings…) - the value is not important, but in a real world application, it would be the value read from some sensor
void send_multiple_datapoint(char *ip, unsigned int data_points) {
Udp.beginPacket(ip, 4545);
msg_buff_multi_array[0].msg_type = data_points;
msg_buff_multi_array[0].value = counter;
msg_buff_multi_array[0].timestamp = micros();
Udp.write((byte *) &msg_buff_multi_array, sizeof(message) * len);
Udp.endPacket();
}
Here only 1 data point is fill with data, and the other data points won’t have any value, but that’s ok for now, since the idea is to measure how the amount of data affects performance, so the focus is on the size of the data, and not in how much time the data acquisition takes.
Real source code
Real code used to run these tests can be found at udp.cpp.
Results
Data points per packet | Packets per second | Data points per second |
---|---|---|
1 | 726 | 726 |
50 | 327 | 16,361 |
100 | 209 | 20,995 |
125 | 178 | 22,253 |
As expected, when a UDP packet contains more than data points, it gets bigger, and the amount of packets per seconds is inversely proportional to the packet size.
Also as expected, in terms of data points per seconds, it is much more efficient to include multiple data points in each UDP packet.
Chart: packets per seconds / data points per second
Transmission errors
So far, so good. More than 20,000 data points per seconds looks good for our needs. But, are in fact all those packets reaching the Raspberry Pi?
Let’s add information about errors to the same table:
Data points per packet | Packets per second | Data points per second | Udp.endPacket() errors | Packets received by RPI |
---|---|---|---|---|
1 | 726 | 726 | 19 | 981 |
50 | 327 | 16,361 | 0 | 1000 |
100 | 209 | 20,995 | 0 | 1000 |
125 | 178 | 22,253 | 0 | 1000 |
126 | 177 | 22,305 | 0 | ? |
127 | 176 | 22,343 | 0 | ? |
128 | 175 | 22,386 | 0 | ? |
When analyzing the packets received by the Raspberry Pi, the script failed when trying to parse packets containing more than 126 data points per packet.
The problem was: only the first 1,500 bytes of the packets were received.
After adjusting the script that parsed the packets, by assuming that packets bigger than 1500 bytes are going to be truncated, everything worked again.
Data points per packet | Packets per second | Data points per second | Udp.endPacket() errors | Packets received by RPI | Complete packets received by RPI |
---|---|---|---|---|---|
1 | 726 | 726 | 19 | 981 | 981 |
50 | 327 | 16,361 | 0 | 1000 | 1000 |
100 | 209 | 20,995 | 0 | 1000 | 1000 |
125 | 178 | 22,253 | 0 | 1000 | 1000 |
126 | 177 | 22,305 | 0 | 1000 | 0 |
127 | 176 | 22,343 | 0 | 1000 | 0 |
128 | 175 | 22,386 | 0 | 1000 | 0 |
1500 bytes limit
This will require further investigation. Potential causes:
- limitation of hardware (wifi or Arduino)?
- limitation of wifi library?
- configuration?
- MTU?
- lack of support for IP fragmentation?