Part 1: as a first approach, let’s try the simplest way to send data using UDP packets.
![](/posts/20210708-playing-with-arduino-nano-33-iot/arduino-nano-33-iot-raspberry-pi-4-rev-b_hu71139441865bd357bc024395a6462d07_1231309_660x0_resize_q75_box.jpg)
It’s not important at the moment: software or networking performance, throughput, etc. This is a first test to check the basics, there is a lot of room for improvements in the code, protocol, approach, which will be done in future iterations and based on the discoveries done in this test.
The experiment#
Packet contents#
Each packet contains a string, composed of 2 values separated by coma and with \n
at the end:
- value of an incremental counter
- the value of
micros()
For example:
Packet # | Content |
---|---|
1 | 1,33726393\n |
2 | 2,33728539\n |
3 | 3,33730495\n |
and so on.
Why micros()
? Because I want to experiment with a way to have a timestamp as part of the message.
Why use a string
? Because running netcat
in the Raspberry Pi will allow to easy check what we received.
This is the same reason why I added an \n
at the end.
Running the experiment: Arduino point of view#
While sending the packets from the Arduino, the status is written to the serial console, and this is what I got:
(...)
stats | iter=1797000 | err=9285 | msg/sec=507
stats | iter=1798000 | err=9285 | msg/sec=507
stats | iter=1799000 | err=9285 | msg/sec=507
stats | iter=1800000 | err=9285 | msg/sec=507
ENDED | Sent 1800001 UDP packets in 3545431 ms. with 9285 errors
Running the experiment: Raspberry Pi point of view#
On the Raspberry Pi, netcat
was listening for those UDP packets and the output was redirected to a file:
$ netcat -u -s 0.0.0.0 -p 4545 -l > netcat-output.txt
Once finished, the last lines of netcat-output.txt
were:
$ tail -n5 netcat-output.txt
1799996,3579146918
1799997,3579148832
1799998,3579150780
1799999,3579152790
1800000,3579154958
How the errors are counted?#
The return value of WiFiUDP.endPacket()
is used: that method
returns 0
if there was some error. See https://www.arduino.cc/en/Reference/WiFiNINAUDPEndPacket
for mor information.
On the Raspberry Pi, we can easilly check how many packets were actually received:
$ wc -l netcat-output.txt
1790712 netcat-output.txt
Results#
Description | Value |
---|---|
[1] Arduino: generated packets | 1,800,000 |
[2] Arduino: errors reported by WiFiUDP.endPacket() | 9,285 |
[3] Arduino: successfully sent packets (based on WiFiUDP.endPacket() | 1,790,715 |
[4] Raspberry Pi: packets received | 1,790,712 |
Errors in percentages#
Description | Values | Percentage |
---|---|---|
Packet that were not sent - as reported by WiFiUDP.endPacket() | 9,285 of 1,800,000 | 0.5158% |
Packet sent, but not received by Raspberry Pi | 3 of 1,790,715 | 0.000167531% |
Next steps#
- Refactor Arduino code
- Send data in binary format instead of strings
- Experiment with retries
- Experiment buffering data and send multiple data points per UDP message
- Experiment with different WiFi configuration
Appendix: snippet of Arduino code#
void floodUdp(int iters) {
int ret;
int ratio;
counter = 1;
errors = 0;
Serial.println("Flooding... :D");
udpStart = millis();
for (; iters == -1 || counter <= iters; counter++) {
if (counter % 1000 == 0) {
ratio = (counter) / ((millis() - udpStart) / 1000);
Serial.println(str + "stats | iter=" + counter + " | err=" + errors + " | msg/sec=" + ratio);
}
if (sendUdpToServer(serverHostname) != 1) {
errors++;
};
}
udpEnd = millis();
Serial.println(str + "ENDED | Sent " + counter + " UDP packets in " + (millis() - udpStart) + " ms. with " + errors + " errors");
}
int sendUdpToServer(char* ip) {
if (Udp.beginPacket(ip, 4545) != 1) {
Serial.println("[UDP] Udp.beginPacket() failed");
return -1;
}
String(counter).toCharArray(buf, 100);
Udp.write(buf);
Udp.write(sep);
String(micros()).toCharArray(buf, 100);
Udp.write(buf);
Udp.write(nl);
if (Udp.endPacket() != 1) {
Serial.print("e");
return -1;
}
return 1;
}
Appendix: Wifi configuration#
Configuration of hostapd running in Raspberry Pi:
# --------------------------------------------------------------------
# 2 Ghz (Arduino Nano 33 IoT)
# --------------------------------------------------------------------
interface=wlanrpi0
hw_mode=g
channel=10
ieee80211d=1
country_code=US
ieee80211n=1
wmm_enabled=1
ssid=********
auth_algs=1
wpa=2
wpa_key_mgmt=WPA-PSK
rsn_pairwise=CCMP
wpa_passphrase=********
macaddr_acl=1
accept_mac_file=/etc/hostapd/accept_mac.txt