viernes, 24 de mayo de 2013

Laboratorio 13. Redes Sensoras

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:







#!/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
view raw redsensora.py hosted with ❤ by GitHub

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].

1 comentario: