How difficult can it be to find sample code that provides a means to send UDP packets over an Ethernet link from a Raspberry Pi to an Arduino? Well, actually, pretty difficult. But, it turns out it’s straightforward to make that link.

What’s a UDP Packet?

If you want the gritty details, check out the article on Wikipedia. In short, the User Datagram Protocol is a packet sent from one computer application to another. It’s very basic, provides a checksum of the header and body, a port (a user- or application-defined identifier), but importantly, does not guarantee delivery, ordering, or duplicate protection! This means you could get the same message twice, or not at all, or not received in the order it was sent. If you choose to go this route, you should probably implement some basic handshaking between your two points to make sure both are in sync. So, this protocol is fine for many applications, but you probably wouldn’t enjoy a movie or song streamed this way.

What You’ll Need to Get Started

You’ll need a Raspberry Pi PLC and an Arduino PLC connected by Ethernet, and have installed the Arduino IDE and the Python3 software on your computer(s) – I have both installed on my Raspberry Pi. I’m also assuming that you are able to use both of these tools. You shouldn’t need to make any code changes – outside of creating the Arduino sketch and the Python script from the code below, and then setting the correct IP addresses, etc. as described below.

You’ll need to know the IP address of your Raspberry Pi. You’ll assign an IP address and a MAC address value to your Arduino (apparently the Arduino are not assigned either). And, you’ll have to assign values to the ports – the Arduino port may be the same as the Raspberry Pi port, but they don’t have to be. After you’ve set these values in the sketch (under the “// Required – always needed” comment in the Arduino-to-Raspberry-Pi-UDP.ino sketch below), it’s loaded into your Arduino. You need to make similar changes to your Raspberry Pi Python3 script (these values must match those in the Arduino sketch), and launch it next. The RPi script will begin sending sequentially numbered messages to the Arduino, which will respond with a copy of the message it received. Or, from the command line interface of the Raspberry Pi, you can launch the “netcat” application, and send text messages to the Arduino. Or, you can do both at the same time. From different Raspberry Pi’s!

There are actually two different ways to configure the UDP connection on the Arduino. There are some required settings – they have to be set for it to work. And, there are some optional settings (indicated with the “// Optional” comment in several locations), which allow it work differently, depending on your selection. For instance, if you don’t define the rpiAddress and rpiPort (the default configuration) then the Arduino will determine those values from the incoming packets. On the other hand, you may choose to set those values and the sketch will use them in the response messages back from the Arduino to the Raspberry Pi. You typically wouldn’t do this, but it serves to illustrate how to send a message from Arduino to the Raspberry Pi, without first having received an incoming message.

Arduino Sketch

// Arduino-to-Raspberry-Pi-UDP.ino

/*
   Copyright (c) 2021 Daedalus Logic Systems Corporation All rights reserved

   This program is free software: you can redistribute it and/or modify it
   under the terms of the GNU Lesser General Public License as published by
   the Free Software Foundation, either version 3 of the License, or (at your
   option) any later version.

   This program is distributed in the hope that it will be useful, but WITHOUT
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
   for more details.

   You should have received a copy of the GNU Lesser General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <Ethernet.h>
#include <EthernetUdp.h>

#define UDP_TX_PACKET_MAX_SIZE 256

// Load this sketch into the Aruino first, then use:
// "python3 Raspberry-Pi-to-Arduino-UDP.py" on Raspberry Pi to start sending messages
// or
// "nc -u 192.168.0.177 9999" on Raspberry Pi to start netcat CLI application, then type:
// Hello World!
// ^C to quit

// Required - always needed
EthernetUDP    arduinoPort;
const int      ARDUINO_CS_PIN   = 10;
const int      ARDUINO_PORT     = 55555;  // Note the Port values don't have to match
byte           arduinoMAC[]     = { 0x91, 0xE2, 0x0A, 0x0D, 0x25, 0x40};  // random values
byte           arduinoAddress[] = { 192, 168, 0, 177 };                   // unused value in last octet

// Optional - needed when remote (Raspberry Pi) IP Address/Port are unknown
EthernetUDP    rpiPort;
const int      RPI_PORT         = 54444;     // Note the Port values don't have to match
IPAddress      rpiAddress(192,168,0,95);    // IP address of Raspberry Pi

// buffers for receiving and sending data
char packetBuffer[UDP_TX_PACKET_MAX_SIZE];  // buffer to hold incoming packet,

void setup()
{
  // start the Ethernet
  Ethernet.init( ARDUINO_CS_PIN );
  Ethernet.begin( arduinoMAC, arduinoAddress );

  // Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {}

  // start UDP Port(s)
  arduinoPort.begin( ARDUINO_PORT );  // Required - always needed
  //rpiPort.begin( RPI_PORT );        // Optional - needed if remote site is fixed
}

void loop() {
  // if non-zero data is available, read a packet
  int packetSize = arduinoPort.parsePacket();
  if( packetSize )
  {
    // read the packet into empty packetBuffer
    memset( packetBuffer, 0, UDP_TX_PACKET_MAX_SIZE );
    arduinoPort.read( packetBuffer, UDP_TX_PACKET_MAX_SIZE );
    Serial.println( packetBuffer );

    // Echo the received packet back to the remote (Raspberry Pi) source
    // Typical - Send a reply to the IP address and port that sent us the packet we received
    arduinoPort.beginPacket( arduinoPort.remoteIP(), arduinoPort.remotePort() );
    arduinoPort.write( packetBuffer );
    arduinoPort.endPacket();
    
    // Optional - Send a reply to the known IP address and port defined by rpiPort and rpiAddress
    //rpiPort.beginPacket( rpiAddress, RPI_PORT );
    //rpiPort.write( packetBuffer );
    //rpiPort.endPacket();
  }
  
  delay( 1000 );
}

Raspberry Pi Python Script

Be sure to set the values in the Raspberry-Pi-to-Arduino-UDP.py script to the same values set in the Arduino-to-Raspberry-Pi-UDP.ino sketch.

# Raspberry-Pi-to-Arduino-UDP.py

"""
   Copyright (c) 2021 Daedalus Logic Systems Corporation All rights reserved

   This program is free software: you can redistribute it and/or modify it
   under the terms of the GNU Lesser General Public License as published by
   the Free Software Foundation, either version 3 of the License, or (at your
   option) any later version.

   This program is distributed in the hope that it will be useful, but WITHOUT
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
   for more details.

   You should have received a copy of the GNU Lesser General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.

 """

import socket
import time

bufferSize         = 256
msgFromRPi         = "Raspberry Pi to Arduino Ethernet UDP message "
rpiAddressPort     = ("192.168.0.95",  54444) # Note the Arduino and Raspberry Pi port values don't have to match
arduinoAddressPort = ("192.168.0.177", 55555) # But, the IP addresses & Ports must match the Arduino sketch values
 

# Bind socket to RPi
rpiSocket = socket.socket(family=socket.AF_INET, type=socket.SOCK_DGRAM)
rpiSocket.bind( rpiAddressPort );

msgNumber = 0
while True:
    rpiSocket.sendto( str.encode( msgFromRPi + str( msgNumber ) ), arduinoAddressPort )
    print( "rpiSocket Message sent to Arduino        b'" + msgFromRPi + str( msgNumber ) + "'" )
    msgNumber = msgNumber + 1

    msgFromArduino = rpiSocket.recvfrom(bufferSize)
    print( "rpiSocket Response received from Arduino {}".format(msgFromArduino[0]) )

    time.sleep( 1 )

Here are the first few lines of each output file:

Raspberry-Pi-to-Arduino-UDP-Output.txt

>>> %Run Raspberry-Pi-to-Arduino-UDP.py
rpiSocket Message sent to Arduino        b'Raspberry Pi to Arduino Ethernet UDP message 0'
rpiSocket Response received from Arduino b'Raspberry Pi to Arduino Ethernet UDP message 0'
rpiSocket Message sent to Arduino        b'Raspberry Pi to Arduino Ethernet UDP message 1'
rpiSocket Response received from Arduino b'Raspberry Pi to Arduino Ethernet UDP message 1'
rpiSocket Message sent to Arduino        b'Raspberry Pi to Arduino Ethernet UDP message 2'
rpiSocket Response received from Arduino b'Raspberry Pi to Arduino Ethernet UDP message 2'
rpiSocket Message sent to Arduino        b'Raspberry Pi to Arduino Ethernet UDP message 3'
rpiSocket Response received from Arduino b'Raspberry Pi to Arduino Ethernet UDP message 3'
rpiSocket Message sent to Arduino        b'Raspberry Pi to Arduino Ethernet UDP message 4'
rpiSocket Response received from Arduino b'Raspberry Pi to Arduino Ethernet UDP message 4'
rpiSocket Message sent to Arduino        b'Raspberry Pi to Arduino Ethernet UDP message 5'
rpiSocket Response received from Arduino b'Raspberry Pi to Arduino Ethernet UDP message 5'
Arduino-to-Raspberry-Pi-UDP-Output.txt

20:41:55.229 -> Raspberry Pi to Arduino Ethernet UDP message 0
20:41:57.232 -> Raspberry Pi to Arduino Ethernet UDP message 1
20:41:59.248 -> Raspberry Pi to Arduino Ethernet UDP message 2
20:42:01.251 -> Raspberry Pi to Arduino Ethernet UDP message 3
20:42:03.226 -> Raspberry Pi to Arduino Ethernet UDP message 4
20:42:05.228 -> Raspberry Pi to Arduino Ethernet UDP message 5

Last updated: 2021 May 21