Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions pyrevolve/revolve_bot/brain_nn.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ def FromYaml(yaml_object):
params.generate_params(yaml_object['params'][k_node])
brain.params[k_node] = params

return brain

def to_yaml(self):
yaml_dict_brain = OrderedDict()

Expand Down
50 changes: 29 additions & 21 deletions pyrevolve/revolve_bot/measure.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ def count_branching_bricks(self, module=None):
for core_slot, child_module in module.iter_children():
if child_module is None:
continue
children_count += 1
if not isinstance(child_module, TouchSensorModule) and not isinstance(child_module, BrickSensorModule):
children_count += 1
self.count_branching_bricks(child_module)
if (isinstance(module, BrickModule) and children_count == 3) or (isinstance(module, CoreModule) and children_count == 4):
self.branching_modules_count += 1
Expand Down Expand Up @@ -70,25 +71,27 @@ def measure_branching(self):
def calculate_extremities_extensiveness(self, module=None, extremities=False, extensiveness=False):
"""
Calculate extremities or extensiveness in body
@param extremities: calculate extremities in body if true
@param extensiveness: calculate extensiveness in body if true
"""
try:
if module is None:
module = self.body

if module.has_children():
children_count = 0
for core_slot, child_module in module.iter_children():
if child_module is None:
continue
children_count = 0
for core_slot, child_module in module.iter_children():
if child_module is None:
continue
if not isinstance(child_module, TouchSensorModule):
children_count += 1
if extremities:
self.calculate_extremities_extensiveness(child_module, True, False)
if extensiveness:
self.calculate_extremities_extensiveness(child_module, False, True)
if children_count == 1 and not isinstance(module, CoreModule) and extremities:
self.extremities += 1
if children_count == 2 and not isinstance(module, CoreModule) and extensiveness:
self.extensiveness += 1
if extremities:
self.calculate_extremities_extensiveness(child_module, True, False)
if extensiveness:
self.calculate_extremities_extensiveness(child_module, False, True)
if children_count == 0 and not (isinstance(module, CoreModule) or isinstance(module, TouchSensorModule)) and extremities:
self.extremities += 1
if children_count == 1 and not (isinstance(module, CoreModule) or isinstance(module, TouchSensorModule)) and extensiveness:
self.extensiveness += 1
except Exception as e:
print('Failed calculating extremities or extensiveness')
print('Exception: {}'.format(e))
Expand All @@ -104,7 +107,7 @@ def measure_limbs(self):
if self.absolute_size < 6:
practical_limit_limbs = self.absolute_size - 1
else:
practical_limit_limbs = 2 * math.floor((self.absolute_size-6)/3) + (self.absolute_size - 6) % 3 + 4
practical_limit_limbs = 2 * math.floor((self.absolute_size - 6) / 3) + ((self.absolute_size - 6) % 3) + 4
self.calculate_extremities_extensiveness(None, True, False)
if self.extremities == 0:
self.limbs = 0
Expand Down Expand Up @@ -181,7 +184,6 @@ def count_active_hinges(self, module=None):
try:
if module is None:
module = self.body

if module.has_children():
if isinstance(module, ActiveHingeModule):
self.active_hinges_count += 1
Expand All @@ -204,7 +206,10 @@ def measure_joints(self):
self.joints = 0
return 0
self.count_active_hinges()
practical_limit_active_hinges = math.floor((self.absolute_size-1)/2)
practical_limit_active_hinges = self.absolute_size - 2
if self.active_hinges_count == 0:
self.joints = 0
return 0
self.joints = self.active_hinges_count / practical_limit_active_hinges
return self.joints

Expand All @@ -227,8 +232,9 @@ def measure_absolute_size(self, module=None):
:return:
"""
try:
self.calculate_count()
self.absolute_size = self.brick_count + self.hinge_count + 1
if self.absolute_size is None:
self.calculate_count()
self.absolute_size = self.brick_count + self.hinge_count + 1
return self.absolute_size
except Exception as e:
print('Failed measuring absolute size')
Expand Down Expand Up @@ -298,9 +304,9 @@ def measure_all(self):
self.measure_coverage()
self.measure_symmetry()
self.measure_branching()
return self.get_all_measurements()
return self.measurement_to_dict()

def get_all_measurements(self):
def measurement_to_dict(self):
"""
Return dict of all measurements
:return:
Expand All @@ -309,7 +315,9 @@ def get_all_measurements(self):
'branching': self.branching,
'branching_modules_count': self.branching_modules_count,
'limbs': self.limbs,
'extremeties': self.extremities,
'length_of_limbs': self.length_of_limbs,
'extensiveness': self.extensiveness,
'coverage': self.coverage,
'joints': self.joints,
'hinge_count': self.hinge_count,
Expand Down
60 changes: 60 additions & 0 deletions pyrevolve/revolve_bot/render/brain_graph.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from graphviz import Digraph, render
# belong to TODO
import fnmatch


class BrainGraph:
def __init__(self, brain, name='brain', typename='brain'):
self.graph = Digraph(typename, filename=name, format='png')
self.brain = brain

def add_node(self, node_id, node_type, text):
"""
Add node to graph
@param node_id: id of node
@param node_type: type of node
@param text: text to show inside node
"""
if node_type == 'Input':
self.graph.attr('node', shape='circle')
elif node_type == 'Oscillator':
self.graph.attr('node', shape='square')
self.graph.node(node_id, label=text)

def add_edge(self, source_id, desitnation_id, label):
"""
Add edge to graph
@param source_id: id of source node
@param destination_id: id of destination node
@param label: label of edge
"""
self.graph.edge(source_id, desitnation_id, label)

def save_graph(self):
"""
Save graph
"""
self.graph.render()

def brain_to_graph(self):
"""
Export complete brain to graph
"""

nodes = self.brain.nodes
params = self.brain.params
# belongs to TODO
duplicates = fnmatch.filter(nodes, 'node*-*')
for node in nodes:
# TODO REMOVE condition WHEN duplicated nodes bug is fixed -- duplicated nodes end in '-[0-9]+' or '-core[0-9]+' (node2-2, node2-core1)
if node not in duplicates:
node_id = nodes[node].id
text = node_id
if node_id in params:
param = params[node_id]
text += '\n Oscillator {0} \n period: {1} \n phase_offset: {2} \n amplitude: {3}'.format(
nodes[node].part_id, params[node_id].period, params[node_id].phase_offset, params[node_id].amplitude)
self.add_node(node_id, nodes[node].type, text)

for connection in self.brain.connections:
self.add_edge(str(connection.src), str(connection.dst), str(connection.weight))
5 changes: 3 additions & 2 deletions pyrevolve/revolve_bot/render/grid.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,11 @@ def move_back(self):
Grid.y_pos = last_movement[1]
Grid.orientation = last_movement[2]

def add_to_visited(self):
def add_to_visited(self, include_sensors=True, is_sensor=False):
"""Add current position to visited coordinates list"""
self.calculate_orientation()
self.visited_coordinates.append([Grid.x_pos, Grid.y_pos])
if (include_sensors and is_sensor) or not is_sensor:
self.visited_coordinates.append([Grid.x_pos, Grid.y_pos])
Grid.movement_stack.append([Grid.x_pos, Grid.y_pos, Grid.orientation])

def calculate_grid_dimensions(self):
Expand Down
4 changes: 1 addition & 3 deletions pyrevolve/revolve_bot/render/render.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,7 @@ def traverse_path_of_robot(self, module, slot, include_sensors=True):
"""
if isinstance(module, ActiveHingeModule) or isinstance(module, BrickModule) or isinstance(module, TouchSensorModule) or isinstance(module, BrickSensorModule):
self.grid.move_by_slot(slot)
if include_sensors or (isinstance(module, ActiveHingeModule) or isinstance(module, BrickModule)):
self.grid.add_to_visited()

self.grid.add_to_visited(include_sensors, isinstance(module, TouchSensorModule))
if module.has_children():
# Traverse path of children of module
for core_slot, child_module in module.iter_children():
Expand Down
19 changes: 17 additions & 2 deletions pyrevolve/revolve_bot/revolve_bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from .brain_nn import BrainNN

from .render.render import Render
from .render.brain_graph import BrainGraph
from .measure import Measure

import xml.etree.ElementTree
Expand Down Expand Up @@ -118,8 +119,7 @@ def load_yaml(self, text):
brain_type = yaml_brain['type']

if brain_type == 'neural-network':
self._brain = BrainNN()
self._brain.FromYaml(yaml_brain)
self._brain = BrainNN.FromYaml(yaml_brain)

else:
self._brain = None
Expand Down Expand Up @@ -252,6 +252,21 @@ def _update_substrate(self,
new_direction,
substrate_coordinates_map)

def render_brain(self, img_path):
"""
Render image of brain
@param img_path: path to where to store image
"""
if self._brain == None:
raise RuntimeError('Brain not initialized')
else:
try:
brain_graph = BrainGraph(self._brain, img_path)
brain_graph.brain_to_graph()
brain_graph.save_graph()
except:
print('Failed rendering brain')

def render2d(self, img_path):
"""
Render 2d representation of robot and store as png
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ PyYAML>=3.11
protobuf>=3.0.0
psutil==3.4.2
pycairo>=1.18.0
graphviz>=0.10.1

-e git+https://github.com/ci-group/pygazebo.git@py2to3#egg=pygazebo