Commit 4c1034f8 authored by Ahmad Reza's avatar Ahmad Reza
Browse files

-Working visualisation

parent f7f3b271
# Setting up the project
# Setting up and running the project the project
1. Install python 3.6
- Linux/Ubuntu: https://tecadmin.net/install-python-3-6-ubuntu-linuxmint/#
2. Use pip to install pyglet 1.2.4
- Linux/Ubuntu: $ sudo pip3.6 install pyglet
. Download the actual project from:
URL: https://gitlab.cs.uni-duesseldorf.de/cheraghi/SwarmNetworkSimulator/-/archive/master/SwarmNetworkSimulator-master.zip
. Unzip it:
-Linux/Ubuntu: $ unzip DownloadDirectory/SwarmNetworkSimulator-master.zip
3. Run the project
- - Linux/Ubuntu:
$ cd SwarmNetworkSimulator-maste
$ python3.6 main.py
# Usage
## Keyboard Shortcuts
- space: pause / unpause simulation
- ctrl+mouseclick: add/remove tile at mouse position
- cmd+s: take screenshot
- cmd+v: toggle video mode, see below
## Creating Videos
- use cmd+v to toggle video mode which takes a screenshot of every frame
- you can use ffmpeg to create a videos from your screenshots
```shell
ffmpeg -framerate 90 -pattern_type glob -i '*.png' -c:v libx264 -pix_fmt yuv420p -r 30 out.mov
```
#Config the project:
# Troubleshooting
- if you are on mac os and get an error message stating something along the lines of `ApplePersistenceIgnoreState: Existing state will not be touched.` when starting the simulator, open a terminal and execute the following command
```
defaults write org.python.python ApplePersistenceIgnoreState NO
```
[Simulator]
seedvalue = 20
seedvalue = 12
general_delay=0
max_round = 20
max_round = 10
[File]
world = two_particles_tiles_locations.py
#world = two_particles_tiles_locations.py
#world = tile_beside_particle.py
#world = two_particles_infront.py
#world= n_particle_on_a_line.py
world=rand_n_tile_one_particle.py
#world = world_five_rings_particle.py
#world=all_aims_in_1st_ring.py
#scenario = read_write.py
#scenario = scanning.py
scenario = create_delete.py
#scenario = create_delete.py
#scenario = scanning_for_all_aims.py
#scenario = take_drop_aims.py
scenario = take_drop_tile.py
#scenario = randome_walk.py
#scenario = search_for_tile_rw.py
[World]
size_x = 8
size_y = 8
size_x = 800
size_y = 600
max_particles=1000
......@@ -3,9 +3,9 @@
import configparser
import logging
from robotsOnTiles import world, sim
from robotsOnTiles import world, sim, vis
visualization=False
visualization=True
def main():
"""In the main function first the config is getting parsed and than
......@@ -25,14 +25,16 @@ def main():
logging.basicConfig(filename='system.log', filemode='w', level=logging.INFO, format='%(message)s')
logging.info('Started')
simulator = sim.Sim(seed=seedvalue, max_round=max_round)
simulator = sim.Sim(seed=seedvalue, max_round=max_round, scenario=scenario_file.strip('.py'))
sim_world=world.World( size_x=size_x, size_y=size_y, world_name=world_file, solution_name=scenario_file.strip('.py'),
seed=seedvalue, sim=simulator, max_particles=max_particles)
#sim_world.create_world(world_file)
if not visualization:
simulator.run( sim_world, scenario_file)
simulator.run(sim_world)
else:
pass
window = vis.VisWindow(sim_world, simulator)
window.run()
logging.info('Finished')
if __name__ == "__main__":
......
......@@ -33,7 +33,6 @@ class CsvParticleData:
self.id = particle_id
self.writer = writer
self.steps = 0
self.round_success=0
self.particle_created=0
self.particle_deleted=0
self.particles_dropped = 0
......@@ -136,6 +135,8 @@ class CsvRoundData:
self.location_deleted_sum = 0
self.memory_read_sum = 0
self.memory_write_sum = 0
self.success_round = None
self.success_counter = 0
self.tiles_taken = 0
self.tiles_dropped = 0
self.tiles_taken_sum = 0
......@@ -144,7 +145,7 @@ class CsvRoundData:
self.file_name = directory + '/rounds.csv'
self.csv_file = open(self.file_name, 'w', newline='')
self.writer_round = csv.writer(self.csv_file)
self.writer_round.writerow(['','Round Number', 'Round Success', 'Seed','Solution','Task',
self.writer_round.writerow(['','Round Number', 'Seed','Solution','Task',
'Location Counter',
'Location Created', 'Location Created Sum',
'Location Deleted', 'Location Deleted Sum','Location Read', 'Location Read Sum',
......@@ -156,6 +157,7 @@ class CsvRoundData:
'Particles Dropped', 'Particles Dropped Sum',
'Particle Read', 'Particle Read Sum', 'Particle Steps', 'Particle Steps Sum',
'Particles Taken', 'Particles Taken Sum', 'Particle Write', 'Particle Write Sum',
'Success Counter', 'Success Round',
'Tile Counter',
'Tiles Created', 'Tiles Created Sum', 'Tiles Deleted', 'Tiles Deleted Sum',
'Tiles Dropped', 'Tiles Dropped Sum', 'Tile Read', 'Tile Read Sum',
......@@ -171,8 +173,9 @@ class CsvRoundData:
def update_locations_num(self, act_locations_num):
self.locations_num = act_locations_num
def round_success(self):
self.round_success=1
def success(self, actual_round):
self.success_round=actual_round
self.success_counter=self.success_counter+1
def update_metrics(self, rounds, steps = 0,
particle_read = 0, tile_read = 0, location_read = 0, memory_read = 0,
......@@ -245,7 +248,7 @@ class CsvRoundData:
logging.debug("CSV: Ending writing_rounds")
def next_line(self, round):
csv_iterator = ['',round, self.round_success, self.seed, self.solution, self.task,
csv_iterator = ['',round, self.seed, self.solution, self.task,
self.locations_num, self.location_created, self.location_created_sum,
self.location_deleted, self.location_deleted_sum,
self.location_read, self.location_read_sum,
......@@ -258,6 +261,7 @@ class CsvRoundData:
self.steps, self.steps_sum,
self.particles_taken, self.particles_taken_sum,
self.particle_write, self.particle_write_sum,
self.success_counter, self.success_round,
self.tile_num, self.tile_created, self.tile_created_sum,
self.tile_deleted, self.tile_deleted_sum, self.tiles_dropped, self.tiles_dropped_sum,
self.tile_read, self.tile_read_sum, self.tiles_taken, self.tiles_taken_sum,
......@@ -281,17 +285,19 @@ class CsvRoundData:
self.location_deleted = 0
self.tiles_dropped = 0
self.tiles_taken = 0
self.round_success = 0
self.success_round = None
self.success_counter = 0
self.particles_taken = 0
self.particles_dropped = 0
def aggregate_metrics(self):
self.csv_file.close()
data = pd.DataFrame.from_csv(self.file_name)
data = pd.read_csv(self.file_name)
file_name = self.directory+"/aggregate_rounds.csv"
csv_file = open(file_name, 'w', newline='')
writer_round = csv.writer(csv_file)
writer_round.writerow(['Seed', 'Rounds Total', 'Solution', 'Task',
writer_round.writerow(['Seed', 'Rounds Total',
'Solution', 'Task',
'Location Counter',
'Location Created Sum', 'Location Created Avg',
'Location Created Min', 'Location Created Max',
......@@ -314,6 +320,8 @@ class CsvRoundData:
'Particle Write Sum', 'Particle Write Avg', 'Particle Write Min', 'Particle Write Max',
'Memory Read Sum', 'Memory Read Avg', 'Memory Read Min', 'Memory Read Max',
'Memory Write Sum', 'Memory Write Avg', 'Memory Write Min', 'Memory Write Max',
'Success Rate Sum', 'Success Rate Avg', 'Success Rate Min', 'Success Rate Max',
'Success Round Min', 'Success Round Max',
'Tile Counter',
'Tiles Created Sum', 'Tiles Created Avg', 'Tiles Created Min', 'Tiles Created Max',
'Tiles Deleted Sum', 'Tiles Deleted Avg', 'Tiles Deleted Min', 'Tiles Deleted Max',
......@@ -322,7 +330,9 @@ class CsvRoundData:
'Tiles Taken Sum', 'Tiles Taken Avg', 'Tiles Taken Min', 'Tiles Taken Max',
'Tile Write Sum', 'Tile Write Avg', 'Tile Write Min', 'Tile Write Max'])
csv_interator = [self.seed, data['Round Number'].count(), self.solution, self.task,
csv_interator = [self.seed, data['Round Number'].count(),
self.solution, self.task,
self.locations_num,
data['Location Created'].sum(), data['Location Created'].mean(),
......@@ -365,6 +375,12 @@ class CsvRoundData:
data['Memory Write'].sum(), data['Memory Write'].mean(), data['Memory Write'].min(),
data['Memory Write'].max(),
data['Success Counter'].sum(), data['Success Counter'].mean(), data['Success Counter'].min(),
data['Success Counter'].max(),
data['Success Round'].min() ,
data['Success Round'].max(),
self.tile_num,
data['Tiles Created'].sum(), data['Tiles Created'].mean(), data['Tiles Created'].min(),
data['Tiles Created'].max(),
......
......@@ -196,7 +196,9 @@ class Particle:
hop_list = []
for i in range(0, hop + 1):
hop_list.extend(self.scan_for_aim_in(aim, i))
list = self.scan_for_aim_in(aim, i)
if list != None:
hop_list.extend(list)
if len(hop_list) != 0:
return hop_list
else:
......@@ -508,30 +510,57 @@ class Particle:
logging.info("Could not delet tile on coords %s", str(coords))
return False
def take_tile(self, tile_id):
def take_tile(self):
"""
Takes a tile on the actual position
:param id: The id of the tile that should be taken
:return: True: successful taken; False: unsuccessful taken
"""
if self.carried_particle is None and self.carried_tile is None:
if self.coords in self.world.tile_map:
self.carried_tile = self.world.tile_map[self.coords]
if self.carried_tile.take(coords=self.coords):
logging.info("Tile has been taken")
self.world.csv_round_writer.update_metrics(self.world.sim.get_actual_round(), tiles_taken=1)
self.csv_particle_writer.write_particle(tiles_taken=1)
return True
else:
logging.info("Tile could not be taken")
return False
else:
logging.info("No tile on the actual position not in the world")
return False
else:
logging.info("Tile cannot taken because particle is carrieng either a tile or a particle")
return False
def take_tile_with(self, id):
"""
Takes a tile with a given tile id
:param tile_id: The id of the tile that should be taken
:param id: The id of the tile that should be taken
:return: True: successful taken; False: unsuccessful taken
"""
if self.carried_particle is None and self.carried_tile is None:
if tile_id in self.world.tile_id_map:
logging.info("Tile with tile id %s is in the world", str(tile_id))
self.carried_tile = self.world.tile_id_map[tile_id]
if id in self.world.tile_id_map:
logging.info("Tile with tile id %s is in the world", str(id))
self.carried_tile = self.world.tile_id_map[id]
if self.carried_tile.take(coords=self.coords):
logging.info("Tile with tile id %s has been taken", str(tile_id))
logging.info("Tile with tile id %s has been taken", str(id))
self.world.csv_round_writer.update_metrics(self.world.sim.get_actual_round(), tiles_taken=1)
self.csv_particle_writer.write_particle(tiles_taken=1)
return True
else:
logging.info("Tile with tile id %s could not be taken", str(tile_id))
logging.info("Tile with tile id %s could not be taken", str(id))
return False
else:
logging.info("Tile with tile id %s is not in the world", str(tile_id))
logging.info("Tile with tile id %s is not in the world", str(id))
return False
else:
logging.info("Tile cannot taken because particle is carrieng either a tile or a particle", str(tile_id))
logging.info("Tile cannot taken because particle is carrieng either a tile or a particle", str(id))
return False
def take_tile_in(self, dir):
......@@ -593,7 +622,7 @@ class Particle:
logging.info("Tile cannot taken because particle is carrieng either a tile or a particle")
return False
def drop_taken_tile(self):
def drop_tile(self):
"""
Drops the taken tile on the particles actual position
......@@ -788,7 +817,8 @@ class Particle:
else:
return False
def take_particle(self, id):
def take_particle_with(self, id):
"""
Takes a particle with a given tile id
......
......@@ -25,9 +25,9 @@ def create(world):
particle.create_location_in(dir=random.choice([0, 1, 2, 3, 4, 5]))
# particle.create_location_in(x=random.choice([0, 1, 2, 3, 4, 5]), y=random.choice([0, 2, 4, 6, 8 , 10]))
def scenario(self, world):
def scenario(sim, world):
two_particle_inverse_walk(world)
if self.get_actual_round() <= self.get_max_round() / 2:
if sim.get_actual_round() <= sim.get_max_round() / 2:
create(world)
else:
scan_and_delete_tile(world)
......
import logging
import random
E = 0
SE = 1
SW = 2
W = 3
NW = 4
NE = 5
S = 6 # S for stop and not south
direction = [E, SE, SW, W, NW, NE]
def scenario(sim, world):
for particle in world.particles:
particle.move_to(random.choice([0, 1, 2, 3, 4, 5]))
\ No newline at end of file
import logging
import random
E = 0
SE = 1
SW = 2
W = 3
NW = 4
NE = 5
S = 6 # S for stop and not south
direction = [E, SE, SW, W, NW, NE]
def scenario(sim, world):
for particle in world.particles:
#particle.move_to(random.choice([0, 1, 2, 3, 4, 5]))
particle.move_to(W)
if particle.coords in world.tile_map:
print("Found Tile")
world.csv_round_writer.success(sim.get_actual_round())
\ No newline at end of file
"""
This scenario just scans for particles that are within 5 hops range and prints them out.
"""
import logging
from locale import str
E = 0
SE = 1
SW = 2
W = 3
NW = 4
NE = 5
S = 6 # S for stop and not south
direction = [E, SE, SW, W, NW, NE]
def scenario(self, world):
all_aims_list=[]
if self.get_actual_round() == 1:
all_aims_list=world.particle_map[(0,0)].scan_for_aim_within(aim='tiles')
for list in all_aims_list:
if list.type=='tile':
print("tile", list.coords)
elif self.get_actual_round() == 2 :
world.particles[0].take_tile_in(E)
elif self.get_actual_round() == 4 :
world.particles[0].drop_tile()
elif self.get_actual_round() == 5:
world.particles[0].take_tile()
elif self.get_actual_round() == 6:
world.particles[0].drop_tile_in(W)
#elif self.get_actual_round() == 5 :
......@@ -5,19 +5,21 @@ The sim module everything for the simulator is provided.
import importlib
import random
class Sim:
def __init__(self, seed=1, max_round=10, solution="None"):
def __init__(self, seed=1, max_round=10, scenario="None"):
"""
:param seed: seed number for new random numbers
:param max_round: the max round number for terminating the simulator
:param solution: The name of solution/scenario that is going to be used
"""
random.seed(seed)
self.__max_round = max_round
self.__round_counter = 1
self.__seed=seed
self.__solution = solution
self.__scenario = scenario
def get_max_round(self):
"""
......@@ -42,18 +44,27 @@ class Sim:
:return:
"""
self.__round_counter += 1
def run(self, world, scenario):
def get_scenario(self):
"""
actual scenario name
:return: actual scenario name
"""
return self.__scenario
def run(self, world):
"""
:param world: The worlds object
:param scenario: The name of the scenario file
:return:
"""
if scenario is not None:
mod = importlib.import_module('robotsOnTiles.scenarios.'+scenario.strip('.py'))
if self.get_scenario() is not None:
random.seed(seed)
mod = importlib.import_module('robotsOnTiles.scenarios.'+self.get_scenario())
while self.get_actual_round() <= self.get_max_round():
mod.scenario(self, world)
world.csv_round_writer.next_line(self.get_actual_round())
......
......@@ -108,7 +108,8 @@ class Tile:
"""
if coords==0:
if self.__isCarried == False:
del self.world.tile_map[self.coords]
if self.coords in self.world.tile_map:
del self.world.tile_map[self.coords]
self.__isCarried = True
self.touch()
return True
......@@ -116,7 +117,8 @@ class Tile:
return False
else:
if self.__isCarried == False:
del self.world.tile_map[self.coords]
if self.coords in self.world.tile_map:
del self.world.tile_map[self.coords]
self.__isCarried = True
self.coords = coords
self.touch()
......
......@@ -2,9 +2,9 @@ import datetime, math, os, time
from pyglet.gl import *
from pyglet.window import mouse
import pyglet.window.key as key
import importlib
import copy
black = 1
gray = 2
red = 3
......@@ -111,13 +111,15 @@ class View:
class VisWindow(pyglet.window.Window):
def __init__(self, world):
super().__init__(window_width, window_height, resizable=window_resizable, vsync=False, caption="Simulator")
def __init__(self, world, sim):
#super().__init__(world.get_world_x_size(), world.get_world_y_size(), resizable=window_resizable, vsync=False, caption="Simulator")
super().__init__(world.get_world_x_size(), world.get_world_y_size(), resizable=window_resizable, vsync=False, caption="Simulator")
self.window_active = True
glClearColor(0.0, 0.0, 0.0, 0.0)
glClearDepth(1.0)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
self.world = world
self.sim = sim
self.init_tile_vertex_list()
self.init_particle_vertex_list()
self.view = View()
......@@ -162,7 +164,7 @@ class VisWindow(pyglet.window.Window):
if coords_coords not in self.world.tile_map:
# add tile and vertices
#tile = Tile(coords_coords[0], coords_coords[1])
self.world.create_tile(coords_coords[0], coords_coords[1])
self.world.add_tile(coords_coords[0], coords_coords[1])
tile = self.world.tile_map[float(coords_coords[0]), float(coords_coords[1])]
#self.tile_vertex_list.resize(4 * len(self.world.tiles), 4 * len(self.world.tiles))
self.tile_vertex_list.resize(4 * len(self.world.tiles), 8 * len(self.world.tiles))
......@@ -279,156 +281,74 @@ class VisWindow(pyglet.window.Window):
def update_tiles(self, update_all=False):
foreground = []
background = []
change_tile = False
if self.world.tiles_rm:
while self.world.tiles_rm:
rm_tile = self.world.tiles_rm.pop()
indices=[]
#self.tile_vertex_list.resize(4 * len(self.world.tiles), 8 * len(self.world.tiles))
if len(self.world.tiles) == 0:
#self.tile_vertex_list.delete()
pass
# self.tile_vertex_list.delete()
#self.tile_vertex_list.indices = list(range(4 * len(self.world.tiles), 8 * len(self.world.tiles)+8))
else:
self.tile_vertex_list.resize(4 * len(self.world.tiles), 8 * len(self.world.tiles))
self.tile_vertex_list.indices = list(range(0, 8 * len(self.world.tiles)+8))
#self.update_tile(len(self.world.tiles) - 1, tile)
for i, tile in enumerate(self.world.tiles):
for i, tile in enumerate(self.world.tiles):
if update_all or tile.modified:
self.update_tile(i, tile)
#indices += list(range(4 * i, 4 * i + 4))
#self.tile_vertex_list.indices = list(range(0, 8*len(self.world.tiles)))
elif self.world.new_tile_flag == True:
self.world.new_tile_flag = False
#indices += list(range(4 * i, 4 * i + 4))
if len(self.world.tiles) == 1:
print ("new size:", self.tile_vertex_list.get_size())
self.update_tile(len(self.world.tiles) - 1, self.world.new_tile)
self.tile_vertex_list.indices = list(range(0, 4 * len(self.world.tiles)))
else:
self.tile_vertex_list.resize(4 * len(self.world.tiles), 4* len(self.world.tiles))
print ("new size:", self.tile_vertex_list.get_size(), len(self.world.tiles))
self.update_tile(len(self.world.tiles) - 1, self.world.new_tile)
# self.tile_vertex_list.indices = list(range( 4* len(self.world.tiles), 4* len(self.world.tiles)))
self.tile_vertex_list.indices[ 4 * (len(self.world.tiles) - 1):
4 * (len(self.world.tiles) - 1) + 4] = range(
4 * (len(self.world.tiles) - 1), 4 * (len(self.world.tiles) - 1) + 4)
# self.tile_vertex_list.resize(4 * len(self.world.tiles), 4 * len(self.world.tiles))
# print ("new size:", self.tile_vertex_list.get_size())
# self.world.new_tile_flag = False
# indices = []
# # self.update_tile(i, tile)
# # for i, tile in enumerate(self.world.tiles):
# # count = 0
# # self.update_tile(i, tile)
# # indices += list(range(4 * i, 4 * i + 4))
# #self.tile_vertex_list.indices = list(range(0, 8*len(self.world.tiles)))
# self.tile_vertex_list.indices[4 * (len(self.world.tiles) - 1): 4 * (len(self.world.tiles) - 1) + 4] = range(
# 4 * (len(self.world.tiles) - 1), 4 * (len(self.world.tiles) - 1) + 4)
# self.update_tile(len(self.world.tiles) - 1, self.world.new_tile)
# count = 0
count = 0
for vertices in self.tile_vertex_list.vertices:
count += 1
print("NEWWWWWWNEW vertex ", vertices, "at ", count, " size ", self.tile_vertex_list.get_size())
else:
indices=[]
for i, tile in enumerate(self.world.tiles):
counter = 0
if update_all or tile.modified:
self.update_tile(i, tile)
tile.modified = False
for vertices in self.tile_vertex_list.vertices:
counter += 1
print(
"old vertex ", vertices, "at ", i, " and ", counter, " size ", self.tile_vertex_list.get_size())
indices += list(range(4 * i, 4 * i + 4))
if tile.get_tile_status:
foreground += indices
else:
background += indices
self.tile_vertex_list.indices = indices
#self.tile_vertex_list.resize(4 * len(self.world.tiles), 4 * len(self.world.tiles))