Para esta entrada se hablará sobre el tema de redes sensoras, en donde
se desarrolló una simulación de una red sensora. En la simulación se
tomaron en cuenta 3 dimensiones en el eje x, y y z en el que z a que
tanta altura se encuentra el nodo; Imaginemos que los nodos son unas
antenas que se encuentran de manera estática en el aire dichas antenas
pueden percibir objetos pero con una cierta altitud de diferencia,
digamos que un objeto no identificado llamemosló enemigo dicho enemigo
pasa a 30 metros de la antena en donde su radio de percepción
onmidireccional es de cierto alcance 20 metros, entonces el enemigo
pasará desapercibido.
Esta simulación puede ser comparada en situaciones reales como la
detección de ciertos enemigos aereos usando UAVs en donde cada UAV
tiene cierto rango de alcance de vista.
A continuación mostrare la simulación en un video, donde se tienen dos
opciones en la primera parte que tuve problemas en donde se tenía que
tener una cierta matriz en donde cada cuadro tenía que tener un cierta
rango de altitud que al final simplemente se los incormporé a cada
nodo, y cada nodo puede transmitir un mensaje de propagación siempre y
cuando se encuentre en su rango de comunicación.
Video.
Ahora veamos algo de código (el cual se encuentra comentado).
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
from random import randint, random | |
from threading import Thread | |
from time import sleep | |
from sys import argv | |
from math import cos, sin, fabs | |
import pygame | |
#Metodo que retorna un color en RGB dado un numero | |
def asignColor(grupo): | |
return ((grupo * 5 + 7) % 256, (grupo * 13 + 41) % 256, (grupo * 29 + 13) % 256) | |
#Metodo que nos regresa un color verde en RGB | |
def verde(): | |
return (0,255,0) | |
#Metodo que nos regresa un color rojo en RGB | |
def rojo(): | |
return (255,0,0) | |
#Metodo que nos regresa un color amarillo en RGB | |
def amarillo(): | |
return (255,255,0) | |
#clase del enemigo | |
class Enemigo: | |
#En el constructor tomamos como parametro | |
# coordenadas (x, y), el color, el radio, una id que se genera de manera incremental y una vida | |
def __init__(self, ( x,y, z), color, radio, id, vida): | |
self.x = x | |
self.y = y | |
self.z = z | |
self.color = color | |
self.radio = radio | |
self.id = id | |
self.vida = vida | |
self.visible = True #Nos sirve para determinar si el nodo esta por ser removido | |
return | |
#Nos sirve para desplegar el enemigo en el canvas | |
def display(self): | |
#Dibuja el enemigo | |
pygame.draw.circle(WIN, self.color, (self.x, self.y), self.radio, 1) | |
#Dibuja un estatus del enemigo | |
WIN.blit( pygame.font.SysFont("Arial",10 ).render("ENEMIGO %s A: %s VIDA %s"%(self.id, self.z, self.vida),True,(0, 0, 0), (255, 255, 255) ), (self.x, self.y)) | |
#Barra de vida | |
pygame.draw.rect( WIN, (0, 0, 0), ( (self.x, self.y+10), (self.radio *2, self.radio * 0.5) ) ) | |
pygame.draw.rect( WIN, obtenerColorVida(self.vida), ( (self.x, self.y+10), ( ( (self.radio * 2 ) * ( ( self.vida ) * 1.0 / 100) ) , ( self.radio * 0.5 ) ) ) ) | |
return | |
#clase del nodo | |
class Nodo: | |
#En el constructor tomamos como parametro | |
# coordenadas (x, y), el color, el radio, una id que se genera de manera incremental y una vida | |
def __init__(self, (x, y, z), color, radio, id, vida): | |
self.x = x | |
self.y = y | |
self.z = z | |
self.color = color | |
self.radio = radio | |
self.id = id | |
self.vida = vida | |
self.mensaje = '' | |
self.estado = verde() | |
self.visible = True #Nos sirve para determinar si el nodo esta por ser removido | |
return | |
#Metodo que dado una lista de nodos verifica que se encuentren | |
#dentro del rango de transmision en caso de ser asi les pasa el mensaje | |
#y se le resta el costo de energia segun su tamanio y radio | |
def transmite(self, nodos): | |
for nodo in nodos: | |
if radioDeTransmision(self.radio, self.x, self.y, self.z, (nodo.x, nodo.y, nodo.z) ): | |
nodo.mensaje = self.mensaje | |
nodo.estado = nodo.cambiaAmarillo() | |
self.vida -= obtenerCostoEnergia(self.radio, self.mensaje) | |
#En caso quese obtenga vida de menos se le asigna un 0 para evitar confusiones | |
if self.vida < 0: | |
self.vida = 0 | |
return nodos | |
#Nos sirve para desplegar el nodo en el canvas | |
def display(self): | |
#Se dibuja el nodo (circulo) dado su radio y color | |
pygame.draw.circle(WIN, self.color, (self.x, self.y), self.radio, 1) | |
#Hardcoded Tuve unos problemas con la asignacion de color en lugar del color RGB deberian ir self.estado | |
if self.mensaje != '': | |
pygame.draw.circle(WIN, (255,0,0), (self.x, self.y), 5, 0) | |
else: | |
pygame.draw.circle(WIN, (0,255,0), (self.x, self.y), 5, 0) | |
#Se pinta el estatus del nodo | |
WIN.blit( pygame.font.SysFont("Arial",10 ).render("ID %s A %s VIDA %s MSG %s "%(self.id, self.z, self.vida, self.mensaje),True,(0, 0, 0), (255, 255, 255) ), (self.x, self.y)) | |
#Barra de vida del nodo | |
pygame.draw.rect( WIN, (0, 0, 0), ( (self.x, self.y+10), (self.radio*0.5, self.radio * 0.1) ) ) | |
pygame.draw.rect( WIN, obtenerColorVida(self.vida), ( (self.x, self.y+10), ( ( (self.radio * 0.5 ) * ( ( self.vida ) * 1.0 / 100) ) , ( self.radio * 0.1 ) ) ) ) | |
return | |
#Metodo que regresa el estado del nodo | |
def getEstado(self): | |
return self.estado | |
#Metodo que cambia de color el estado por rojo | |
def cambiaRojo(self): | |
self.estado = (255,0,0)#rojo() | |
return | |
#Metodo que cambia de color el estado a amarillo | |
def cambiaAmarillo(self): | |
self.estado = amarillo() | |
return | |
#Metodo que cambia de color el estado a verdde | |
def cambiaVerde(self): | |
self.estado = verde() | |
return | |
#Dada una coordenada se verifica que esten dentro de un radio | |
# y ademas de que se encuentre con una diferencia de altitud(z) dentro | |
#del porcentaj establecido regresa un True en otro caso sera un False | |
def radioDeTransmision(radio, xc, yc, zc, coordenada): | |
global porcentaje | |
x, y, z = coordenada | |
if ( ( ( x - xc ) ** 2 ) + ( ( y - yc ) ** 2 ) ) < ( radio ** 2 ) and (fabs(zc - z) < ( zc * porcentaje)): | |
return True | |
return False | |
#Segun la cantidad de vida dado nos regresara | |
#un color determinado en RGB | |
def obtenerColorVida(vida): | |
if vida >= 66: | |
color = ( 0, 255, 0 ) | |
elif vida < 66 and vida > 33: | |
color = ( 255, 245, 0 ) | |
else: | |
color = ( 255, 0, 0 ) | |
return color | |
#Tomando el radio y el largo del mensaje se obtendra | |
#el costo de transmision | |
def obtenerCostoEnergia(radio, mensaje): | |
return ( len(mensaje) * ( radio / 100 ) ) | |
#clase de Simulacion que hereda de la clase Thread | |
class Simulacion(Thread): | |
def __init__(self): | |
Thread.__init__(self) | |
self.nodos = list() | |
self.enemigos = list() | |
self.contador_enemigos = 0 | |
self.contador_nodos = 0 | |
self.altitudes = {} | |
return | |
def run(self): | |
#Toma el canvas (WIN), tiempo de retraso, el color de FONDO y la propabilodad de que a paresca un nodo | |
global WIN, tiempo, FONDO, p, pe | |
run = True | |
self.creaGrid() | |
#Se crea un nodo | |
self.creaNodo() | |
#Se despliega el nodo | |
self.nodos[0].display() | |
#Se actualiza el canvas | |
pygame.display.update() | |
#Se coloca un tiempo de retraso configurado | |
sleep(tiempo) | |
#Se crea una lista para enemigos por eliminar del canvas | |
enemigosEliminar = list() | |
#Se crea una lista para nodos por eliminar del canvas | |
nodosEliminar = list() | |
#Mientras run siga siendo True corre | |
while run: | |
#Itera cada evento seleccionado | |
for event in pygame.event.get(): | |
#En caso de usar QUIT cambiamos run a False | |
if event.type == pygame.QUIT: | |
run = False | |
#Limpieza del canvas | |
WIN.fill(FONDO) | |
self.creaGrid() | |
#Se iteran los enemigos | |
for e in xrange(len(self.enemigos)): | |
#En caso de que el enemigo no sea visible | |
#brinca el enemigo | |
if not self.enemigos[e].visible: | |
continue | |
#Se iteran los nodos | |
for n in xrange(len(self.nodos)): | |
#En caso de que los nodos no sea visible | |
#brinca el nodo | |
if not self.nodos[n].visible: | |
continue | |
#En caso de que el enemigo se encuentre en el radio del nodo se coloca | |
# como mensaje al nodo en el que se encuentra el enemigo | |
if radioDeTransmision(self.nodos[n].radio, \ | |
self.nodos[n].x, \ | |
self.nodos[n].y, \ | |
self.nodos[n].z, | |
(self.enemigos[e].x, self.enemigos[e].y, self.enemigos[e].z)): | |
# Se cambio de estado a rojo | |
self.nodos[n].cambiaRojo() | |
#DEBUG | |
print self.nodos[n].estado | |
#Cambia mensaje | |
self.nodos[n].mensaje = 'Enemigo en zona de %s '%(self.nodos[n].id) | |
#Mientras el random nos de un numero menor a la probabilidad de nodo | |
#este generara un nuevo nodo | |
if random() < p: | |
self.creaNodo() | |
#Mientras el random nos de un numero menor a la probabilidad de enemigo | |
#este generara un nuevo enemigo | |
if random() < pe: | |
self.creaEnemigo() | |
#Por cada enemigo se le quita cierta vida | |
#en caso que tenga vida menor a 0 se le coloca | |
# en su propiedad de que ya no sera visible | |
#despues se pintan los enemigos visibles | |
for e in xrange(len(self.enemigos)): | |
if self.enemigos[e].vida > 5: | |
self.enemigos[e].vida -= 5 | |
else: | |
enemigosEliminar.append(self.enemigos[e]) | |
self.enemigos[e].visible = False | |
if not self.enemigos[e].visible: | |
continue | |
self.enemigos[e].display() | |
#Se iteran todos los nodos se le quita cierta vida | |
#en caso que tenga vida menor a 0 se le coloca | |
#en su propiedad de que ya no sera visible | |
#despues se pintan los nodos visibles | |
for n in xrange(len(self.nodos)): | |
print self.nodos[n].id, self.nodos[n].vida | |
if self.nodos[n].vida > 0: | |
self.nodos[n].vida -= 5 | |
if self.nodos[n].mensaje != '': | |
self.nodos[n].transmite(self.nodos) | |
else: | |
nodosEliminar.append(self.nodos[n]) | |
self.nodos[n].visible = False | |
if not self.nodos[n].visible: | |
continue | |
self.nodos[n].display() | |
#Se actualiza el canvas | |
pygame.display.update() | |
#Se crea un retraso | |
sleep(tiempo) | |
#Se remueven los enemigos en la lista de enemigosEliminar | |
for e in enemigosEliminar: | |
try: | |
self.enemigos.remove(e) | |
except: | |
pass | |
#Se remueven los nodos en la lista de nodosEliminar | |
for n in nodosEliminar: | |
try: | |
self.nodos.remove(n) | |
except: | |
pass | |
return | |
#Pinta los nodos que se han comunicado | |
def pintaRedComunicacion(self, comunicacion): | |
global WIN | |
if len(comunicacion) >= 3: | |
print comunicacion | |
for i in xrange(len(comunicacion)): | |
if len(comunicacion) != i+1: | |
x1, y1 = comunicacion[i] | |
x2, y2 = comunicacion[i+1] | |
pygame.draw.line(WIN , (255, 0, 0), (x1, y1), (x2, y2), 1 ) | |
return | |
#Se crea un nodo enemigo | |
def creaEnemigo(self): | |
#Se toma la configuracion de su radio (re), vida (vidaEnemigo), porcentaje (margen) | |
global re, vidaEnemigo, porcentaje | |
#Contador de los enemigos creados | |
self.contador_enemigos += 1 | |
#Se le da una posicion al enemigo de manera aleatoria con un color rojo en RGB, una id con numero de enemigos y una vida propia | |
enemigo = Enemigo( ( randint( DIM * 0.10 , DIM * porcentaje ), randint( DIM * 0.10, DIM * porcentaje ), randint(0, altitude ) ), (255, 0, 0), re, self.contador_enemigos, vidaEnemigo) | |
#Se agrega a la lista de enemigos los enemigos | |
self.enemigos.append( enemigo ) | |
return | |
def creaNodo(self): | |
#Se toma la configuracion de su radio (re), vida (vidaEnemigo), porcentaje (margen) | |
global r, vidaNodo, porcentaje, altitude | |
#Contador de los nodos creados | |
self.contador_nodos+=1 | |
#Se le da una posicion al nodo de manera aleatoria con un color en RGB obtenido a partir del contador de nodos , una id osea el numero de nodos y una vida propia | |
nodo = Nodo( ( randint( DIM * 0.10 , DIM * porcentaje ), randint( DIM * 0.10, DIM * porcentaje ), randint(0, altitude ) ), asignColor( self.contador_nodos ), r, self.contador_nodos , vidaNodo) | |
#Se agrega el nodo a la lista de nodos | |
self.nodos.append( nodo ) | |
return | |
#Metodo que crea una red de cuadro en el que cada cuadro tiene una altitud establecida | |
def creaGrid(self): | |
#Se toman las variables de ventana, dimensiones, pedasos en que se partira la ventana y la altitude maxima | |
global WIN, DIM, CHUNKS, altitude | |
#Se obtienen las partes de la ventana | |
CHUNK = DIM/CHUNKS | |
print len(self.altitudes) | |
#En caso de ser la primera vez en dibujar la matriz se guardan en un dictionary las altitudes | |
# que se guardaran de manera aleatoria | |
if len(self.altitudes) == 0: | |
for y in xrange(CHUNKS): | |
for x in xrange(CHUNKS): | |
print ( (x * CHUNK, y), (x * CHUNK, y * CHUNK) ) | |
self.altitudes[( (x * CHUNK, y), (CHUNK, CHUNK) )] = ((randint(0, altitude)),( ( (x * CHUNK, y * CHUNK), (CHUNK * y, (x+1) * CHUNK) ) )) | |
#for c in xrange(CHUNKS): | |
# pygame.draw.line(WIN, (255, 0, 0), (CHUNK * c, 0), (CHUNK * c, CHUNK * CHUNKS)) | |
# pygame.draw.line(WIN, (255, 0, 0), (0, CHUNK * c), (CHUNK * CHUNKS, CHUNK * c)) | |
altiud, tam, aux, c = None, None, None, None | |
#Aqui se colocan los colores de los cuadros | |
for y in xrange(CHUNKS): | |
for x in xrange(CHUNKS): | |
altitud, tam = self.altitudes[( (x * CHUNK, y), (CHUNK,CHUNK) )] | |
print 'Creando rectangulos: ',altitud, tam | |
pygame.draw.rect(WIN, asignColor(altitud), tam, 100) | |
#Aqui se colocan los textos, se colocaron de esta manera porque si los iteraba en el | |
#for se iban a empalmar | |
for y in xrange(CHUNKS): | |
for x in xrange(CHUNKS): | |
altitud, tam = self.altitudes[( (x * CHUNK, y), (CHUNK,CHUNK) )] | |
c, aux = tam | |
cx, cy = c | |
cx = cx+CHUNKS/2.0 | |
cy = cy+CHUNKS/2.0 | |
# c = cx +10, cy +10 | |
WIN.blit( pygame.font.SysFont("Arial",10 ).render("%s"%(altitud), True, (0, 0, 0), (255, 255, 255) ), (cx, cy) ) | |
return | |
#Dimensiones del canvas | |
DIM = 1000 | |
#porcentaje del canvas | |
porcentaje = 0.6 | |
#color de fondo(blanco) | |
FONDO = ( 255, 255, 255) | |
#inicia pygame | |
pygame.init() | |
#se crea el canvas | |
WIN = pygame.display.set_mode((DIM, DIM)) | |
#Se coloca un titulo al canvas | |
pygame.display.set_caption('Simulacion de redes sensoras') | |
#Se rellena de un color al canvas | |
WIN.fill(FONDO) | |
#Parametro de tiempo | |
try: | |
tiempo = float(argv[1]) | |
except: | |
tiempo = 3 | |
#Parametro de probabilidad de nodo | |
try: | |
p = float(argv[2]) | |
except: | |
p = 0.6 | |
#Parametro de radio del nodo | |
try: | |
r = float(argv[3]) | |
except: | |
r = 200 | |
#Parametro de probabilidad de enemigo | |
try: | |
pe = float(argv[4]) | |
except: | |
pe = 0.4 | |
#Parametro de radio de enemigo | |
try: | |
re = float(argv[5]) | |
except: | |
re = 10 | |
#Parametro de vida del nodo | |
try: | |
vidaNodo = int(argv[6]) | |
except: | |
vidaNodo = 100 | |
#Parametro de vida del enemigo | |
try: | |
vidaEnemigo = int(argv[7]) | |
except: | |
vidaEnemigo = 20 | |
#Parametro de velocidad | |
try: | |
velocidad = int(argv[8]) | |
except: | |
velocidad = 10 | |
#Parametro de pedasos a partir la ventana | |
try: | |
CHUNKS = int(argv[9]) | |
except: | |
CHUNKS = 20 | |
#Parametro para la altitude maxima | |
try: | |
altitude = int(argv[10]) | |
except: | |
altitude = 200 | |
def main(): | |
#Crea una simulacion | |
s = Simulacion() | |
#corre simulacion | |
s.run() | |
main() |
Lo de mapear colores a alturas en principio es una buena idea, pero aquí es algo difícil interpretarlas. Yo hubiera esperado más nodos y mayor actividad entre ellos. 11 pts.
ResponderEliminar