Para esta semana se nos pidió realizar lo siguiente:
- Prepara una simulación simple de una red sensora (ad hoc) pequeña con nodos estáticos – con la herramienta de tu elección (puede ser ns u otra cosa o una combinación) en un terreno 3D (definido manualmente, con una función matemática o por ejemplo como un fractal.
- Comunicación con rangos ajustables y TTL.
- Estudia alguna propiedad de tu interés.
Una red de sensores es una red de ordenadores pequeñísimos (nodos), equipados con sensores, que colaboran en una tarea común.
Las redes de sensores están formadas por un grupo de sensores con ciertas capacidades sensitivas y de comunicación inalámbrica los cuales permiten formar redes ad hoc sin infraestructura física preestablecida ni administración central.
Las redes de sensores es un concepto relativamente nuevo en adquisición y tratamiento de datos con múltiples aplicaciones en distintos campos tales como entornos industriales, domótica, entornos militares, detección ambiental.
Para esta tarea decidí estudiar una propiedad, que es la detección de plagas en sembradíos. Para esto utilizando blender cree un terreno en tercera dimensión que simulara el sembradio. Por algunos problemas no me fue posible agregar esto mismo a la simulación que realicé en python así que en la simulación utilicé una imagen del terreno.
En la siguiente imagen se muestra el terreno que fue realizado en blender, batalle un poco y tuve que ver algunos tutoriales ya que nunca había utilizado esta herramienta y la verdad aprendí muchas cosas.
La simulación se hizo basada a la tarea pasada de mi compañero Juan Carlos, agregando código que hiciera lo que se nos pidió esta semana, así como también modificando algunas cosas como que los nodos fueran estáticos, agregando la "plaga" mediante puntos rojos que van apareciendo.
Lo que hace esta simulación es agregar 12 nodos sensores (es una variable que puede ajustarse), la plaga va apareciendo en cierta velocidad que también es ajustable en diferentes coordenadas dentro del canvas. Al aparecer la plaga se hace una verificación para saber si la plaga se encuentra dentro del radio de alcance del nodo sensor, si se da el caso de que se encuentre dentro del rango, se manda el mensaje de notificación a los nodos vecinos donde se dice que se detecto plaga en dicho sensor y también sale un mensaje en la terminal.
Se tiene un TTL definido que es ajustable, para que al terminar el 0 el mensaje ya no puede seguirse propagando.
Esta propiedad me pareció interesante, ya que hay muchos sembradios que se hechan a perder por causa de las plagas que se presentan en los mismos y en ocasiones hay veces que no se pueden salvar y se pierde mucha cosecha. Esta es una muy buena forma para ayudar a que esto no suceda.
El código de la simulación es el siguiente:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
from Tkinter import * | |
from threading import Thread | |
from sys import argv | |
from math import sqrt, ceil | |
from random import random, randint, expovariate | |
from time import sleep | |
import pygame | |
from PIL import ImageTk | |
# Clase que representa un mensaje | |
# El atributo ttl se disminuye cada vez que el mensaje salta | |
# de un nodo a otro | |
# El atributo estado cambia a False cuando ttl llega a cero | |
class Mensaje: | |
def __init__(self): | |
self.dato = "Se ha detectado placas" | |
self.ttl = 5 | |
self.estado = True | |
def bajaTTL(self): | |
self.ttl -= 1 | |
if(self.ttl <= 0): | |
self.estado = False | |
return | |
# Clase que representa un nodo | |
class Nodo: | |
def __init__(self,ID,c,r,b,v): | |
self.id = ID # ID unico del nodo | |
self.color = setColor() # Color para la visualizacion | |
self.coords = c # Coordenadas donde el nodo sera dibujado | |
self.radio = r # Radio de alcance del nodo | |
self.bateria = b # Bateria del nodo | |
self.costo = 1 # Costo energetico de cada paso | |
self.velocidad = v # Velocidad del movimiento | |
self.vecinos = list() # Vecinos dentro del radio de alcance | |
self.cola = [Mensaje() for i in range(3)] # Cola de mensajes disponibles | |
self.estado = True # Estado del nodo: True=Vivo, False=Muerto | |
self.instancias = None # Para guardar temporalmente las referencias a los dibujos | |
self.dibujar() # Dibujar el nodo | |
def morir(self): # Cuando el nodo muere | |
global canvas | |
canvas.delete(self.instancias["dibujo"]) # Eliminamos las instancias de los dibujos | |
canvas.delete(self.instancias["etiqueta"]) # en el canvas | |
canvas.delete(self.instancias["radio"]) | |
for c in self.instancias["conexiones"]: | |
canvas.delete(c) | |
# self.instancias = None # Eliminamos las instancias | |
# self.estado = False # Matamos el nodo | |
print "[O] El Nodo %d murio"%(self.id) | |
return | |
def verBateria(self): # Para disminuir la bateria en cada paso | |
self.bateria -= self.costo | |
# if(self.bateria <= 0): # Si la bateria llega a cero, | |
# self.morir() # el nodo muere | |
return | |
def transmitir(self): # Transmitir un mensaje a todos sus vecinos | |
if(self.cola): | |
mensaje = self.cola.pop(0) # Sacamos un mensaje | |
if(mensaje.estado): # Si el mensaje aun esta vivo | |
mensaje.bajaTTL() # Bajamos en un paso el TTL | |
for a, vecino in enumerate(self.vecinos): | |
self.vecinos[a].cola.append(mensaje) # Hacemos broadcast a los vecinos | |
return | |
def detectarVecinos(self, nodos): # Para escanear la zona | |
self.vecinos[:] = [] # en busca de vecinos | |
x1, y1 = self.coords | |
for n in nodos: # Se utiliza el teorema de pitagoras | |
x2,y2 = n.coords # para ver si algun nodo esta dentro del radio | |
dx = x1 - x2 # de alcance | |
dy = y1 - y2 | |
d = sqrt((dx**2)+(dy**2)) | |
if(d <= self.radio): # De ser asi, agregamos el nodo a la lista de vecinos | |
self.vecinos.append(n) | |
# if(len(self.vecinos) < 3): # Si no se detectan suficientes vecinos | |
# self.radio += 5 # Hacemos crecer el radio de alcance | |
# self.costo += 1 # Y el consumo de bateria crece tambien | |
return | |
def mover(self): # Para mover el nodo de forma pseudoaleatoria | |
global MAX_X, MAX_Y, MIN_X, MIN_Y | |
x,y = self.coords | |
dx = random()*self.velocidad # Se calcula que tanto de mover | |
dy = self.velocidad - dx | |
dx = sqrt(dx) | |
dy = sqrt(dy) | |
if random() > 0.5: | |
dx *= -1.0 | |
if random() > 0.5: | |
dy *= -1.0 | |
x += dx | |
y += dy | |
if(x > MAX_X): x = MAX_X | |
if(y > MAX_Y): y = MAX_Y | |
if(x < MIN_X): x = MIN_X | |
if(y < MIN_Y): y = MIN_Y | |
self.coords = (x, y) | |
return | |
def paso(self, nodos): # Lo que sucede cada vez que el nodo da un paso | |
if(self.estado): # Si el nodo esta vivo | |
# self.mover() # Se mueve | |
self.detectarVecinos(nodos) # Detecta sus vecinos | |
# self.transmitir() # Transmite el mensaje | |
self.dibujar() # Dibujamos lo que pasa | |
self.verBateria() # Consumimos bateria | |
return | |
def dibujar(self): # Para dibujar en la GUI | |
global canvas | |
x, y = self.coords | |
r = self.radio | |
sensores = [] | |
if(self.instancias is not None): # En cada paso borramos los dibujos anteriores | |
canvas.delete(self.instancias["dibujo"]) | |
canvas.delete(self.instancias["etiqueta"]) | |
canvas.delete(self.instancias["radio"]) | |
for c in self.instancias["conexiones"]: | |
canvas.delete(c) | |
self.instancias = None # Y eliminamos las instancias | |
dibujo = canvas.create_oval(x+5,y+5,x-5,y-5, fill='red', outline=self.color) # Un circulo para el nodo | |
radio = canvas.create_oval(x+r,y+r,x-r,y-r, outline=self.color) # Su radio de alcance | |
# print radio | |
etiqueta = canvas.create_text(x,y, text="%s - %d"%(self.id, len(self.cola))) # La etiqueta | |
sensores.append(self.coords) | |
# print sensores | |
x_ = randint(10, MAX_X) | |
coord = (randint(10, MAX_X), randint(10, MAX_Y)) # Damos unas coordenadas pseudoaleatorias | |
a,b = coord | |
plaga = canvas.create_oval(a+2,b+2,a-2,b-2, outline="black",fill="red",width=0.5) # Creamos plaga en coordenadas aleatorias | |
#print"Coordenada", sensores[3] | |
for i,j in sensores: | |
if (a in range(i-r,i+r) and b in range(j-r,j+r)) or (a+1 in range(i-r,i+r) and b+1 in range(j-r,j+r)) or (a+2 in range(i-r,i+r) and b+2 in range(j-r,j+r)) or (a-1 in range(i-r,i+r) and b-1 in range(j-r,j+r)) or (a-2 in range(i-r,i+r) and b-2 in range(j-r,j+r)): | |
self.transmitir() | |
print "Plaga detectada en sensor %d" %self.id | |
# coords_plaga = [] | |
#coords_plaga.append(int( | |
# print "plaga", canvas.coords(plaga) | |
conexiones = list() | |
for vecino in self.vecinos: # Dibujamos las posibles conexiones | |
xV, yV = vecino.coords | |
conexion = canvas.create_line(x,y,xV,yV,width=3, fill="black") | |
conexiones.append(conexion) # Guardamos las instancias | |
self.instancias = {"dibujo":dibujo, "etiqueta":etiqueta, "radio":radio, "conexiones":conexiones} | |
return | |
class Simulacion(Thread): # Para correr la simulacion | |
def __init__(self, n, v): # Creamos un hilo dedicado | |
Thread.__init__(self) | |
self.cantidad = n # Cantidad de nodos en la simulacion | |
self.velocidad = v # La velocidad de la simulacion | |
self.nodos = list() # La lista que contiene los nodos | |
def run(self): # Para correr la simulacion | |
while True: | |
if(len(self.nodos) > 0): # Mientras haya nodos vivos | |
for a, nodo in enumerate(self.nodos): # Recorremos la lista y sacamos uno a uno | |
if(nodo.estado): # Si elnodo esta vivo | |
nodo.paso(self.nodos) # Lo activamos | |
# else: # Si no | |
# self.nodos.pop(a) # Lo eliminamos | |
sleep(self.velocidad) # Dormimos un momento | |
return | |
class threadFunction(Thread): # Para correr una funcion en forma de hilo | |
def __init__(self, target, *args): | |
self._target = target # La funcion objetivo | |
self._args = args # Sus argumentos | |
Thread.__init__(self) # Iniciamos el hilo | |
def run(self): # Para llamar a la funcion | |
self._target(*self._args) | |
def generarNodos(simulacion): # Funcion que agrega los nodos tipo proceso de Poisson | |
global MAX_X, MAX_Y, MIN_RAD, MAX_RAD, MAX_BAT | |
a = 0 # Contador para generar los ID de los nodos | |
nodos = [] | |
while True: # Es un hilo dedicado | |
coordenadas = (randint(10, MAX_X), randint(10, MAX_Y)) # Damos unas coordenadas pseudoaleatorias | |
radio = randint(MIN_RAD, MAX_RAD) # Un radio inical | |
bateria = randint(50, MAX_BAT) # Un nivel de bateria inicial | |
velocidad = randint(1,100) # Una velocidad del nodo inicial | |
if(a<=12): | |
nodo = Nodo(a, coordenadas, radio, bateria, velocidad) # generamos el nodo | |
x,y = coordenadas | |
print "[O] Se agrego el Nodo Sensor %d en (%d, %d)"%(a,x,y) | |
simulacion.nodos.append(nodo) # Lo almacenamos en una lista | |
sleep(expovariate(3)) # Dormimos un momento | |
a += 1 # ID del siguiente nodo | |
nodos.append(coordenadas) | |
print nodos | |
def setColor(): # Para generar un color pseudoaleatorio | |
color = (randint(0,255), randint(0,255), randint(0,255)) | |
return '#%02x%02x%02x'%color # Necesitamos que sea hexadecimal | |
#def sensores: | |
# Funcion principal | |
# Toma de la linea de comandos una cantidad de nodos inicial | |
# y la velocidad de la simulacion | |
# Crea y lanza la simulacion | |
# Crea y lanza la funcion generadora de nodos | |
# Lanza el hilo de la interfaz grafica | |
def main(): | |
try: | |
cantidadNodos = int(argv[1]) | |
except: | |
cantidadNodos = 10 | |
try: | |
velocidad = float(argv[2]) | |
except: | |
velocidad = 0.2 | |
sim = Simulacion(cantidadNodos, velocidad) | |
gen = threadFunction(generarNodos, sim) | |
sim.start() | |
gen.start() | |
mainloop() | |
if(__name__=="__main__"): | |
RES_X, RES_Y = 640, 480 # Resolucion de la pantalla | |
MAX_X, MAX_Y = RES_X-10, RES_Y-10 # Limites para dibujar | |
MIN_X, MIN_Y = 10, 10 | |
MAX_BAT = 100 # Limites de la bateria | |
MIN_RAD, MAX_RAD = 20, int(ceil(RES_X*0.1)) # Limites del radio de los nodos | |
root = Tk() # Generamos la ventana | |
root.title("Simulacion red ad-hoc") # Titulo de la ventana | |
fondo = ImageTk.PhotoImage(file="terreno1.png") | |
canvas = Canvas(root, width=RES_X, height=RES_Y, background="pale green") # Canvas para dibujar | |
canvas.create_image(250,250,image=fondo) | |
canvas.pack() # Lo agregamos a la ventana principal | |
main() # Llamamos a la funcion principal |
El video de la simulación.
Referencias
Es.wikipedia.org (2001) Red de sensores - Wikipedia, la enciclopedia libre. [online] Available at:http://es.wikipedia.org/wiki/Red_de_sensores [Accessed: 24 May 2013].
Juan Carlos Espinosa Ceniceros (2013) [RT] Tarea 7: Simulación redes ad-hoc - Blogger [online] Available at: http://juankenny.blogspot.mx/2013/05/rt-tarea-7-simulacion-redes-ad-hoc.html [Accessed: 24 May 2013].
Tus nodos están en 2D (x, y)... 8 pts.
ResponderEliminar