Etiquetas: , , ,

En este tutorial veremos cómo conseguir que una Raspberry Pi y un ESP32 se comuniquen utilizando el protocolo UDP. Cuando los dispositivos están conectados a la misma red WiFi, pueden comunicarse de manera muy sencilla mediante el intercambio de paquetes de datos utilizando el protocolo UDP. Como tanto la Raspberry Pi y el ESP32 tienen conectividad WiFi a bordo, es bastante sencillo de configurar un protocolo UDP entre los dos.

En este ejemplo, la Raspberry Pi actuará como servidor y el ESP32 como cliente.

N.B.: Este tutorial puede transponerse fácilmente a un ESP8266 (código de cliente extra al final del artículo).

Hardware

  • Ordenador
  • Raspberry Pi
  • NodeMCU ESP32 x1 o superior (o ESP8266)
  • Cable USB A macho

Código del servidor Raspberry Pi

Para comunicarnos utilizando el protocolo UDP, simplemente crearemos el servidor udp, que podrá leer y escribir en el puerto localPort. La biblioteca socket se utiliza para abrir una conexión entre dos dispositivos.

El constructor de socket espera dos parámetros, la familia de direcciones (en este caso direcciones de Internet) y el tipo de socket (en este caso UDP).

sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM) ## Internet,UDP

El socket debe estar enlazado a un puerto de la máquina sock.bind((hostname, localPort)). Poniendo un carácter vacío en lugar de hostname (equivalente a 0.0.0.0) permite enlazar el socket a todas las interfaces locales.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

#Libraries
import socket	#https://wiki.python.org/moin/UdpCommunication

#Parameters
localPort=8888
bufferSize=1024

#Objects
sock = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)  ## Internet,UDP

# function init 
def init():
	sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
	sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) #enable broadcasting mode
	sock.bind(('', localPort))
	print("UDP server : {}:{}".format(get_ip_address(),localPort))

# function main 
def main():
	while True:
		data, addr = sock.recvfrom(1024) # get data
		print("received message: {} from {}\n".format(data,addr))
    
		sock.sendto("RPi received OK",addr)  # write data
  

# function get_ip_address 
def get_ip_address():
	"""get host ip address"""
	ip_address = '';
	s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
	s.connect(("8.8.8.8",80))
	ip_address = s.getsockname()[0]
	s.close()
	return ip_address




if __name__ == '__main__':
	init()
	main()

N.B.: La función get_ip_address() implementa un método para obtener la dirección IP de la Raspberry Pi abriendo un socket temporalmente. También puede utilizar la biblioteca os con el comando ifconfig.

Anota la dirección IP y el puerto de la Raspberry Pi para poder copiarlos en el código del cliente:

  • Dirección IP: 192.168.1.46
  • Número de puerto: 8888

ESP32 Código de cliente UDP

En el código del cliente, vamos a conectarnos al servidor utilizando la dirección IP y el puerto anotados anteriormente (en este caso 192.168.1.46:8888).

N.B.: No olvides cambiar los valores de ssid y password para que el ESP32 se conecte a la misma red que la Raspberry Pi.

#include <WiFi.h>
#include <WiFiUdp.h>
WiFiUDP udp;

char packetBuffer[255];
unsigned int localPort = 9999;
char *serverip = "192.168.1.46";
unsigned int serverport = 8888;

const char *ssid = "******";
const char *password = "********";

void setup() {
  Serial.begin(115200);
  // Connect to Wifi network.
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500); Serial.print(F("."));
  }
  udp.begin(localPort);
  Serial.printf("UDP Client : %s:%i \n", WiFi.localIP().toString().c_str(), localPort);
}

void loop() {
  int packetSize = udp.parsePacket();
  if (packetSize) {
    Serial.print(" Received packet from : "); Serial.println(udp.remoteIP());
    int len = udp.read(packetBuffer, 255);
    Serial.printf("Data : %s\n", packetBuffer);
    Serial.println();
  }
  delay(500);
  Serial.print("[Client Connected] "); Serial.println(WiFi.localIP());
  udp.beginPacket(serverip, serverport);
  char buf[30];
  unsigned long testID = millis();
  sprintf(buf, "ESP32 send millis: %lu", testID);
  udp.printf(buf);
  udp.endPacket();
}

Resultados

Cuando las dos tarjetas se conectan al WiFi, podemos ver que se intercambia información entre las dos tarjetas. Entonces es posible controlar un dispositivo conectado al cliente desde el servidor o viceversa.

raspberrypi-esp32-server-result Comunicación UDP entre Raspberry Pi y ESP32
raspberrypi-esp32-client-result Comunicación UDP entre Raspberry Pi y ESP32

N.B.: En general, las direcciones IP se asignan automáticamente. Como las direcciones se definen «duramente» en el código, es preferible configurar tus dispositivos para que tengan una dirección IP estática en lugar de dinámica. Esto le evitará tener que modificar el código cada vez que se enciendan.

Bonus: Comunicación UDP entre Raspberry Pi y dos clientes ESP32

Una vez establecida la comunicación, es posible añadir varios clientes. En este ejemplo, añadimos un cliente ESP8266

Código cliente UDP ESP8266

Es fácil transformar el código del ESP32 para adaptarlo al ESP8266 modificando el nombre de la librería Wifi. También cambiamos el valor del puerto 9696

N.B.: Cuando añada un cliente, asegúrese de que tiene un emparejamiento de direcciones de

#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
WiFiUDP udp;

char packetBuffer[255];
unsigned int localPort = 9696;
char *serverip = "192.168.1.46";
unsigned int serverport = 8888;

const char *ssid = "******";
const char *password = "******";


void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500); Serial.print(F("."));
  }
  udp.begin(localPort);
  Serial.printf("UDP Client : %s:%i \n", WiFi.localIP().toString().c_str(), localPort);
}


void loop() {
  int packetSize = udp.parsePacket();
  if (packetSize) {
    Serial.print(" Received packet from : "); Serial.println(udp.remoteIP());
    int len = udp.read(packetBuffer, 255);
    Serial.printf("Data : %s\n", packetBuffer);
    Serial.println();
  }
  delay(500);
  Serial.print("[Client Connected] "); Serial.println(WiFi.localIP());
  udp.beginPacket(serverip, serverport);
  char buf[30];
  unsigned long testID = millis();
  sprintf(buf, "ESP8266 send millis: %lu", testID);
  udp.printf(buf);
  udp.endPacket();
}

Resultadoss

Podemos ver que las direcciones y los valores intercambiados por ESP32 y ESP8266 son diferentes.

raspberrypi-esp32-esp8266-server-result Comunicación UDP entre Raspberry Pi y ESP32
raspberrypi-esp8266-client-result Comunicación UDP entre Raspberry Pi y ESP32

Aplicaciones

  •  Crear una red de ordenadores y/o microcontroladores para gestionar diferentes dispositivos o sensores.

Fuentes