Semana 15 Unidad 5: sensores y actuadores por red WiFi¶
Trayecto de acciones, tiempos y formas de trabajo¶
Actividad 1¶
- Fecha: octubre 14 de 2020 - 10 a.m.
- Descripción: protocolo de transporte UDP
- Recursos: ingresa al grupo de Teams
- Duración de la actividad: 1 hora 40 minutos.
- Forma de trabajo: grupal
Esta semana vamos a trabajar en otro protocolo de transporte que nos permite conectar sensores y actuadores en red inalámbrica. Se trata de UDP.
Ejercicio1: analizar el código¶
Para explorar UDP vamos a realizar un proyecto simple que ilustra el uso del protocolo. Se trata de un conjunto de actuadores distribuidos en el espacio y un coordinar central, un PC. Cada actuador enciende y apaga un puerto de entrada salida según lo indique el comando, recibido por UDP, que será enviado por el coordinador central. El coordinador cuenta con un dispositivo, que llamaremos bridge, quien recibirá por serial los comandos y los reenviará por UDP a los actuadores distribuidos.
El protocolo de comunicación serial es simple. Se trata de un protocolo ascii compuesto por tres caracteres. El primer carácter indica a cual actuador se enviará el comando. El segundo carácter el estado deseado para la salida (‘1’ on, ‘0’ off). Por último, se envía un carácter de sincronización (‘*’).
El código del bridge es el siguiente:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | #include <WiFi.h>
#include <WiFiUdp.h>
const char* ssid = "?";
const char* password = "?";
WiFiUDP udpDevice;
uint16_t localUdpPort = ?;
uint16_t UDPPort = ?;
#define MAX_LEDSERVERS 3
const char* hosts[MAX_LEDSERVERS] = {"?.?.?.?", "?.?.?.?", "?.?.?.?"};
#define SERIALMESSAGESIZE 3
uint32_t previousMillis = 0;
#define ALIVE 1000
#define D0 5
void setup() {
pinMode(D0, OUTPUT); // Initialize the LED_BUILTIN pin as an output
digitalWrite(D0, HIGH);
Serial.begin(115200);
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
// Print the IP address
Serial.println(WiFi.localIP());
udpDevice.begin(localUdpPort);
}
void networkTask() {
uint8_t LEDServer = 0;
uint8_t LEDValue = 0;
uint8_t syncChar;
// Serial event:
if (Serial.available() >= SERIALMESSAGESIZE) {
LEDServer = Serial.read() - '0';
LEDValue = Serial.read();
syncChar = Serial.read();
if ((LEDServer == 0) || (LEDServer > 3)) {
Serial.println("Servidor inválido (seleccione 1,2,3)");
return;
}
if (syncChar == '*') {
udpDevice.beginPacket(hosts[LEDServer - 1] , UDPPort);
udpDevice.write(LEDValue);
udpDevice.endPacket();
}
}
// UDP event:
uint8_t packetSize = udpDevice.parsePacket();
if (packetSize) {
Serial.print("Data from: ");
Serial.print(udpDevice.remoteIP());
Serial.print(":");
Serial.print(udpDevice.remotePort());
Serial.print(' ');
for (uint8_t i = 0; i < packetSize; i++) {
Serial.write(udpDevice.read());
}
}
}
void aliveTask() {
uint32_t currentMillis;
static uint8_t ledState = 0;
currentMillis = millis();
if ((currentMillis - previousMillis) >= ALIVE) {
previousMillis = currentMillis;
if (ledState == 0) {
digitalWrite(D0, HIGH);
ledState = 1;
}
else {
digitalWrite(D0, LOW);
ledState = 0;
}
}
}
void loop() {
networkTask();
aliveTask();
}
|
Nota que a diferencia de TCP/IP, con UDP no es necesario establecer una conexión. Los pasos necesario para enviar datos por UDP serán:
- Crear un objeto WiFiUDP
- Iniciar el objeto estableciendo un socket compuesto por la dirección IP y el puerto de escucha.
- Iniciar la construcción del paquete a transmitir con beginPacket(),
- Popular el buffer de transmisión con write.
- Enviar el paquete con endPacket().
El código de los actuadores distribuidos será:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | #include <WiFi.h>
#include <WiFiUdp.h>
const char* ssid = "?";
const char* password = "?";
WiFiUDP udpDevice;
uint16_t localUdpPort = ?;
uint32_t previousMillis = 0;
#define ALIVE 1000
#define D0 5
#define D8 18
void setup() {
pinMode(D0, OUTPUT); // Initialize the LED_BUILTIN pin as an output
digitalWrite(D0, HIGH);
pinMode(D8, OUTPUT);
digitalWrite(D8, LOW);
Serial.begin(115200);
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
// Print the IP address
Serial.println(WiFi.localIP());
udpDevice.begin(localUdpPort);
}
void networkTask() {
uint8_t data;
uint8_t packetSize = udpDevice.parsePacket();
if (packetSize) {
data = udpDevice.read();
if (data == '1') {
digitalWrite(D0, HIGH);
} else if (data == '0') {
digitalWrite(D0, LOW);
}
// send back a reply, to the IP address and port we got the packet from
udpDevice.beginPacket(udpDevice.remoteIP(), udpDevice.remotePort());
udpDevice.write('1');
udpDevice .endPacket();
}
}
void aliveTask() {
uint32_t currentMillis;
static uint8_t ledState = 0;
currentMillis = millis();
if ((currentMillis - previousMillis) >= ALIVE) {
previousMillis = currentMillis;
if (ledState == 0) digitalWrite(D8, HIGH);
else digitalWrite(D8, LOW);
}
}
void loop() {
networkTask();
aliveTask();
}
|
Los pasos para recibir datos por UDP son:
- Crear un objeto WiFiUDP
- Iniciar el objeto estableciendo un socket compuesto por la dirección IP y el puerto de escucha.
- Procesar el siguiente paquete UDP con parsePacket(). Esta acción devolverá el tamaño del paquete en bytes.
- Luego de llamar parsePacket() será posible utilizar los métodos read() y available().
- Leer el paquete.
En el ejemplo mostrado, nota que un actuador distribuido responderá al bridge con el carácter ‘1’ cada que reciba un paquete. De esta manera el bridge sabrá que el dato llegó a su destino.
Ejercicio 2: despliegue del ejercicio¶
Para desplegar este ejercicio necesitamos varios dispositivos: PC, ESP32.
Para desplegar el ejercicio es necesario identificar claramente las direcciones IP de cada uno de los actuadores remotos.
Utiliza un ESP32 para cada actuador y un ESP32 para el bridge. Como en este caso no contamos con tantos dispositivos entonces:
- Usar el ESP32 como bridge y como actuadores el celular y el computador.
- Utiliza los programas Hercules o ScriptCommunicator para simular la aplicación del PC y los actuadores.
RETO¶
Se trata de un programa en el PC que se comunica con un controlador ESP32. El controlador tiene conectados un sensor y un actuador.
- Usa hércules o scriptCommunicator para simular un programa en el computador que solicitará leer el sensor y modificar el actuador.
- El ESP32 tendrá conectado un pulsador y un LED (actuador).
- Desde el programa del PC debemos leer el valor del sensor y cambiar el estado del LED
- Define un protocolo binario para comunicar el PC y el ESP32 por UDP.
Actividad 2¶
- Fecha: octubre 14 a octubre 16 de 2020 - 10 a.m.
- Descripción: termina el RETO.
- Recursos: estudia el material de referencia
- Duración de la actividad: 5 horas.
- Forma de trabajo: individual.
Actividad 3¶
- Fecha: octubre 16 de 2020 - 10 a.m.
- Descripción: sustentación de los retos de la unidad 5: TCP y UDP y de la unidad 4.
- Recursos: ingresa al grupo de Teams
- Duración de la actividad: 1 hora 40 minutos.
- Forma de trabajo: sustentación individual.