Ejemplo básico NS3: IoT y sensores

Como ya hemos comentado en las primeras secciones, hay numerosos ejemplos y test que te sirven de ayuda y como punto de partida, vamos a realizar un ejemplo básico intentando simular una red de sensores que mandan información a una pasarela (Gateway) o nodo central. El objetivo de este ejemplo es ir completándolo con otras funciones muy necesarias en simulación (Log, trazas, configuración, varias tecnologías, energía, etc.) en entradas posteriores. En el repositorio del tutorial, el archivo de inicio es basic-iot-sensors.cc.
Lo primero que vamos a realizar es crear 3 nodos (variable numsensors) y posicionarlos en un punto determinado (aleatorio). Utilizamos una función que crea un escenario con un radio (variable radio) determinado en metros y, a continuación, le pasamos el contenedor de nuestros nodos para que posicione, de forma aleatoria, dichos nodos;

NodeContainer nodes;
nodes.Create(numsensors);
MobilityHelper scenario = createscenario(radio);
scenario.Install (nodes);

Como ya indicamos en la entrada de topología , se crea un escenario mediante el MobilityHelper con la configuración deseada:

MobilityHelper createscenario(double radio)
{
MobilityHelper mobility;
mobility.SetPositionAllocator ("ns3::UniformDiscPositionAllocator",
"rho", DoubleValue (radio),
"X", DoubleValue (0.0),
"Y", DoubleValue (0.0),
"Z", DoubleValue (0.0));

mobility.SetMobilityModel ("ns3::ConstantPositionMobilityModel");
return mobility;
}



Del contenedor de nodos, creamos un centro de la estrella donde posicionaremos el primer nodo, que de ahora en adelante representará la pasarela:

MobilityHelper gatewayposition = createstarcenter();
gatewayposition.Install (nodes.Get(0));

Una vez creados los dispositivos y emplazados (la pasarela en la posición x,y,z a 0,0,0 y el resto de forma aleatoria), vamos a seguir configurando nuestros nodos, configurando una interfaz wifi en cada uno de los nodos. La tecnología inalámbrica WIFI está de sobra probada en NS3 y nos sirve de punto de partida para nuestro ejemplo.
Para la creación de NetDevice por cada Nodo e instalarlo en cada uno de los nodos, usaremos los asistentes, nos crearemos un asistente para la capa física (wifiPhy), la capa Mac (wifiMac) y el objeto que modela el canal inalámbrico (wifiChannel) y al cual deberemos conectar todos los objetos que modelan la capa física.

WifiHelper wifi;
YansWifiPhyHelper wifiPhy = YansWifiPhyHelper::Default ();
YansWifiChannelHelper wifiChannel = YansWifiChannelHelper::Default ();
WifiMacHelper wifiMac;
wifiMac.SetType ("ns3::AdhocWifiMac");
wifiPhy.SetChannel(wifiChannel.Create());
NetDeviceContainer devices = wifi.Install (wifiPhy, wifiMac, nodes);

En este caso para el modelado de la capa física y el canal utilizamos el modelo Yans. Es el modelo por defecto que se utiliza pero, obviamente, el El módulo wifi es uno de los más completos y estudiados con varios modelos disponibles.
El tipo de MAC es ns3::AdhocWifiMac que modela relaciones punto a punto entre dos dispositivos con Wifi. A continuación establecemos el canal en el asistente wifiPhy para que todos los objetos creados de la capa física compartan el canal y se puedan comunicar entre ellos. Estas configuraciones, en la parte wifi, son las configuraciones por defecto. Por último, instalamos usando el asistente general del wifi la capa física y la MAC en todos los nodos. El asistente de wifi nos devuelve un contenedor con los NetDevices creados (y asociados a los nodos):

NetDeviceContainer devices = wifi.Install (wifiPhy, wifiMac, nodes);

Hemos usado la configuración por defecto, este es uno de los puntos más importantes en cuanto a una simulación, tienes que definir claramente las métricas en las cuales estás interesados y modelar de forma simple el resto de elementos. Por ejemplo, si estás interesado en un protocolo de comunicaciones de la capa de aplicación y quieres validar su funcionalidad, la capa física/MAC que utilices debe ser modelada de la forma más simple posible.

Si por contra, estás interesado en modelar un nuevo algoritmo de control de flujo de 802.11ax, es la capa de aplicación la que debe modelar lo mínimo para generar el tráfico necesario para probar la funcionalidad.

Hasta aquí hemos creado el “Hardware” de nuestra simulación, vamos a instalar y configurar el resto de elementos.

Pasemos a la parte de configuración de la pila de protocolos, en este caso vamos a instalar y configurar una pila de protocolos TCP/IP, para ello creamos un asistente y lo instalamos en todos los nodos:

InternetStackHelper internet;
internet.Install (nodes);

Una vez instalada, configuramos la dirección de red y le asignamos direcciones IP a las interfaces de red instaladas en los nodos:

Ipv4AddressHelper ipv4;
ipv4.SetBase ("10.1.1.0", "255.255.255.0");
Ipv4InterfaceContainer i = ipv4.Assign (devices);

en este caso, usamos la dirección de red 10.1.1.0 con máscara 255.255.255.0 y se les asigna, de forma consecutiva, a cada uno de los NetDevices en el container “devices” creando un contenedor de interfaces ya configuradas.

El último paso de creación de nuestro escenario propiamente dicho es la creación de aplicaciones que creen tráfico. Vamos a instalar un servidor UDP en la pasarela (nodo 0) y lo configuramos para que escuche en el puerto 2000 :

uint16_t port = 2000;
UdpServerHelper server(port);
ApplicationContainer gatewayapps = server.Install(nodes.Get(0));
gatewayapps.Start(Seconds(1.0));
gatewayapps.Stop(Seconds(11.0));

Como vemos en el código de arriba, creamos un asistente de servidor en el puerto deseado y lo instalamos en el nodo 0. Por último indicamos los momentos en que arrancamos y paramos el servidor en este caso sobre el contenedor que se ha creado. Un paso similar hay que hacer en los clientes, debemos crear clientes software configurados para enviar una cantidad de tráfico al servidor que acabamos de instalar en el todo 0 (y que obtenemos con nodes.Get(0)).
Obtenemos la dirección IP del servidor (la 0) del contenedor de interfaces, establecemos el tamaño en 32 bytes, que para la información generada por un sensor es suficiente. En principio generaremos como mucho 10 paquetes:

Address gatewayAddress = Address(i.GetAddress (0));
uint32_t packetSize = 32;
uint32_t maxPacketCount = 10;

Con esta configuración, se crea un asistente de cliente, se establece el intervalo de envío y se configura el cliente:

UdpClientHelper client (gatewayAddress, port);
Time interPacketInterval = Seconds (0.5);
client.SetAttribute("PacketSize", UintegerValue(packetSize));
client.SetAttribute ("Interval", TimeValue (interPacketInterval));
client.SetAttribute ("MaxPackets", UintegerValue(maxPacketCount));

Hay que resaltar cómo se configura, mediante el método SetAttribute, cada una de las características, indicando su nombre y valor, este mecanismo es muy utilizado por los objetos NS3 para la configuración de parámetros.
Por último, instalamos en los nodos un cliente (incluyendo la pasarela que actuará como sensor/servidor) creándose otro contenedor de aplicaciones que debemos arrancar y parar. Hay que asegurarse que el servidor esté arrancado antes que los clientes, por eso arrancamos en el segundo 2 y paramos mas tarde para no perder información.

ApplicationContainer apps = client.Install(nodes);
apps.Start(Seconds(2.0));
apps.Stop(Seconds(10.0));

Por último, arrancamos el simulador:

Simulator::Stop (Hours (24));
Simulator::Run ();
Simulator::Destroy ();

Los detalles del simulador lo veremos en otra entrada.

Con esto terminamos nuestra simulación, colocando el archivo en el directorio scratch lo ejecutamos:

/ns-3.30.1$ ./waf --run basic-iot-sensors
Waf: Entering directory `ns-allinone-3.30.1/ns-3.30.1/build'
Waf: Leaving directory `/ns-allinone-3.30.1/ns-3.30.1/build'
Build commands will be stored in build/compile_commands.json
'build' finished successfully (1.747s)

Que compila y ejecuta nuestra simulación. Realmente no vemos ningún flujo de información por lo que no sabemos si todo ha ido bien, en próximas entradas veremos cómo obtener información, mediante log y trazas, de qué está pasando en nuestra simulación.