En este post mostraremos como podemos comunicar dos placas Arduino usando UDP.
Para ello usaremos la placa MKR1000, que como vimos en el post Conociendo la placa Arduino MKR1000, tiene capacidad de conexión a WiFi. Aunque también podríamos usar el shield WiFi101 que usa la misma librería, en conjunto con otra placa Arduino.
Usaremos la clase UDP de la librería wifi101, aunque la misma clase esta disponible también en la librería wifi y ethernet que podríamos usar dependiendo de nuestro hardware.
Para el ejemplo usaremos dos placas MKR1000, en la placa 1 tendremos conectado un potenciometro y en la otra un servomotor, enviaremos el valor del potenciometro via UDP de la placa 1 a la placa 2, y el servomotor se movera de acuerdo al valor recibido.
Ejemplo 1 – Programa de la placa 1 (potenciometro)
#include <SPI.h> #include <WiFi101.h> #include <WiFiUdp.h> int status = WL_IDLE_STATUS; char ssid[] = "MiFibra-2F43"; // El nombre de tu red wifi char pass[] = "qz4x3a7p"; // la clave de tu red wifi unsigned int localPort = 2390; // numero del puerto de la placa para recibir mensajes IPAddress ipremoto(192, 168, 1, 131); //direccion IP de placa remota unsigned int puertoRemoto = 1500; //numero de puerto de la placa remota char msg[20]; //Matriz de caracteres WiFiUDP Udp; //nombre de la instancia void setup() { //Inicia el puerto serial y espera hasta que se complete: Serial.begin(9600); while (!Serial) { ; // espera la conexion del puerto serie. Solo es necesario para placas con puerto USB nativo // Remover este while si la placa no estara conectada al ordenador } // revision de la presencia del shield de comunicación: if (WiFi.status() == WL_NO_SHIELD) { Serial.println("El shield WiFi no esta presente"); // no continua: while (true); } // intenta conectar a la red wifi: while ( status != WL_CONNECTED) { Serial.print("Conectando a SSID: "); Serial.println(ssid); // Conecta a una red WPA/WPA2: status = WiFi.begin(ssid, pass); // espera 10 segundos por la coneccion: delay(10000); } Serial.println("Conectado a wifi"); printWiFiStatus(); Udp.begin(localPort); // Inicia el socket WiFiUDP, y escucha el puerto local } void loop() { int valorPot = analogRead(A1); //leo el valor del potenciometro sprintf(msg, "ValPot:%i", valorPot); // Crea una cadena de texto con el valor del potenciometro Serial.println(msg); //Imprimo la cadena de texto al monitor serie Udp.beginPacket(ipremoto, puertoRemoto); //configura el envio del paquete de datos Udp.write(msg); //coloca en el buffer los datos de salida Udp.endPacket(); //envia el paquete de datos delay(500); } void printWiFiStatus() { // imprime el nombre de la red a la cual estas conectado: Serial.print("SSID: "); Serial.println(WiFi.SSID()); // imprime la direcion IP del shield o placa con la cual estas conectado: IPAddress ip = WiFi.localIP(); Serial.print("IP Address: "); Serial.println(ip); // imprime la intensidad de señal recibida: long rssi = WiFi.RSSI(); Serial.print("signal strength (RSSI):"); Serial.print(rssi); Serial.println(" dBm"); }
La función sprintf es la que nos permite convertir un numero entero en una cadena de caracteres (matriz) para poder enviarla via udp.
Ejemplo 2 – Programa de la placa 2 (servomotor)
#include <SPI.h> #include <WiFi101.h> #include <WiFiUdp.h> #include <stdio.h> #include <Servo.h> int status = WL_IDLE_STATUS; char ssid[] = "MiRedWifi"; // El nombre de tu red wifi char pass[] = "MiClave"; // la clave de tu red wifi char convBuffer[4]; int valServo =0; char packetBuffer[20]; // buffer para guardar los datos entrantes unsigned int localPort = 1500; // numero del puerto de la placa para recibir mensajes Servo myservo; //nombre de la instancia servo WiFiUDP Udp; //nombre de la instancia UDP void setup() { myservo.attach(5); //el servo esta conectado en el pin 5 //Inicia el puerto serial y espera hasta que se complete: Serial.begin(9600); while (!Serial) { ; // espera la conexión del puerto serie. Solo es necesario para placas con puerto USB nativo } // revision de la presencia del shield de comunicación: if (WiFi.status() == WL_NO_SHIELD) { Serial.println("El shield WiFi no esta presente"); // no continua: while (true); } // intenta conectar a la red wifi: while ( status != WL_CONNECTED) { Serial.print("Conectando a SSID: "); Serial.println(ssid); // Conecta a una red WPA/WPA2: status = WiFi.begin(ssid, pass); // espera 10 segundos por la coneccion: delay(10000); } Serial.println("Conectado a wifi"); printWiFiStatus(); Udp.begin(localPort); // Inicia el socket WiFiUDP, y escucha el puerto local } void loop() { // Si hay datos disponibles, lee el paquete int packetSize = Udp.parsePacket(); if (packetSize) { Serial.print("Tamaño del paquete recibido "); Serial.println(packetSize); Serial.print("De "); IPAddress remoteIp = Udp.remoteIP(); Serial.print(remoteIp); Serial.print(", puerto "); Serial.println(Udp.remotePort()); // lee el paquete y lo guarda en el buffer int len = Udp.read(packetBuffer, 20); //lee el paquete y lo guarda en el buffer if (len > 0) packetBuffer[len] = 0; // coloca el caracter null al final de la cadena Serial.println("Contents:"); Serial.println(packetBuffer); convBuffer[0]=packetBuffer[7]; convBuffer[1]=packetBuffer[8]; convBuffer[2]=packetBuffer[9]; convBuffer[3]=packetBuffer[10]; convBuffer[4]=0; valServo=atoi(convBuffer); //convierte la cadena de caracteres a entero Serial.print("El valor extraido es:"); Serial.println(valServo); myservo.write(valServo); } } void printWiFiStatus() { // imprime el nombre de la red a la cual estas conectado: Serial.print("SSID: "); Serial.println(WiFi.SSID()); // imprime la direcion IP del shield o placa con la cual estas conectado: IPAddress ip = WiFi.localIP(); Serial.print("IP Address: "); Serial.println(ip); // imprime la intensidad de señal recibida: long rssi = WiFi.RSSI(); Serial.print("signal strength (RSSI):"); Serial.print(rssi); Serial.println(" dBm"); }
En este sketch la función atoi es la que nos permite convertir la cadena de caracteres a entero. ya que previamente conocemos su posición en el paquete de datos.
Como verificar que los datos se envían por UDP
Cuando solo tenemos una sola placa y necesitamos verificar si los datos se envían y como se reciben una buena alternativa es usar la aplicación packetsender la cual es muy fácil de configurar, es software libre y nos servirá para verificar nuestros sketch. solo debemos indicarle la dirección IP y el puerto.
Espero te sea de utilidad, si tienes alguna duda o quieres conocer un poco mas, nos encantaría recibir tus comentarios.
Tengo dos dudas.
La primera; en UDP no podemos enviar directament el valor numerico sin pasarlo a caracteres?
La segunda; porque quieres una matriz de 20 i al volver a convertirlo a numero, cojes los caracteres de las posiciones de la 7 a la 10?
Gracias