Skip to main content

Sending data from Arduino - part 1

Horacio de Oro
Author
Horacio de Oro
Available to help you find and implement the right solution for your business. Expert on Google Cloud and AWS Architecture, Security, Kubernetes, Django, Python, PostgreSql.

Schedule a free consultation at 👉 calendly.com 👈

Part 1: as a first approach, let’s try the simplest way to send data using UDP packets.

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
11,33726393\n
22,33728539\n
33,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
#

DescriptionValue
[1] Arduino: generated packets1,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 received1,790,712

Errors in percentages
#

DescriptionValuesPercentage
Packet that were not sent - as reported by WiFiUDP.endPacket()9,285 of 1,800,0000.5158%
Packet sent, but not received by Raspberry Pi3 of 1,790,7150.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