diff --git a/pyrevolve/data_analisys/visualize_robot.py b/pyrevolve/data_analisys/visualize_robot.py index 93aec01c99..f61c42bc8c 100644 --- a/pyrevolve/data_analisys/visualize_robot.py +++ b/pyrevolve/data_analisys/visualize_robot.py @@ -71,7 +71,7 @@ def panoramic_rotation(robot_manager, robot: RevolveBot, vertical_angle_limit: f if z < min_z: chosen_orientation = orientation min_z = z - print(f"Chosen orientation for robot {robot.id} is {chosen_orientation}") + #print(f"Chosen orientation for robot {robot.id} is {chosen_orientation}") vec_list = [vecs[chosen_orientation] for vecs in robot_manager._orientation_vecs] diff --git a/pyrevolve/revolve_bot/measure/measure_body_3d.py b/pyrevolve/revolve_bot/measure/measure_body_3d.py index 02206db228..88036c1121 100644 --- a/pyrevolve/revolve_bot/measure/measure_body_3d.py +++ b/pyrevolve/revolve_bot/measure/measure_body_3d.py @@ -10,6 +10,8 @@ def __init__(self, body): # Absolute branching self.branching_modules_count = None + # Absolute T/X branching + self.tx_branching_modules_count = None # Relative branching self.branching = None # Absolute number of limbs @@ -70,6 +72,7 @@ def count_branching_bricks(self, module=None, init=True): try: if init: self.branching_modules_count = 0 + self.tx_branching_modules_count = 0 if module is None: module = self.body @@ -82,12 +85,22 @@ def count_branching_bricks(self, module=None, init=True): and not isinstance(child_module, BrickSensorModule): children_count += 1 self.count_branching_bricks(child_module, False) - if (isinstance(module, BrickModule) and children_count == 3) or \ - (isinstance(module, CoreModule) and children_count == 4): + module_connections = module.count_module_connections() + if module_connections >= 3: + self.tx_branching_modules_count += 1 + if module_connections == 4: self.branching_modules_count += 1 except Exception as e: logger.exception(f'Exception: {e}. \nFailed counting branching bricks') + def folding_no_branching(self): + pass + #TODO + + def folding_or_tbranching(self): + pass + #TODO + def measure_branching(self): """ Measure branching by dividing fully branching by possible branching modules @@ -516,6 +529,7 @@ def measurements_to_dict(self): return { 'branching': self.branching, 'branching_modules_count': self.branching_modules_count, + 'tx_branching_modules_count': self.tx_branching_modules_count, 'limbs': self.limbs, 'extremities': self.extremities, 'length_of_limbs': self.length_of_limbs, diff --git a/pyrevolve/revolve_bot/revolve_module.py b/pyrevolve/revolve_bot/revolve_module.py index dd21849f8c..75f73324f3 100644 --- a/pyrevolve/revolve_bot/revolve_module.py +++ b/pyrevolve/revolve_bot/revolve_module.py @@ -24,11 +24,23 @@ def grams(x): # Module Orientation class Orientation(Enum): - BACK = 0 + BACK = 0 # This is the parent attachment point (if any) FORWARD = 1 RIGHT = 2 LEFT = 3 + def opposite(self): + if self == self.BACK: + return self.FORWARD + elif self == self.FORWARD: + return self.BACK + elif self == self.RIGHT: + return self.LEFT + elif self == self.LEFT: + return self.RIGHT + else: + assert False + def short_repr(self): if self == self.BACK: return 'B' @@ -222,20 +234,66 @@ def possible_slots(self): (box_geometry[2] / -2.0, box_geometry[2] / 2.0), # Z ) - def has_children(self): + def has_children(self) -> bool: """ - Check wheter module has children + Check whether module has children :return: True if module has children """ - has_children = False + for i, child in self.iter_children(): + if child is not None: + return True + return False - if self.children == {1: None}: return False + def count_module_connections(self) -> int: + """ + Count how many connections the module has. + Connected TouchSensor and BrickSensor Modules are ignored + :return: number of connections + """ + if not self.has_children(): + return 1 - for i, child in enumerate(self.children): + children_count = 0 + for core_slot, child in self.iter_children(): if child is not None: - has_children = True + continue + if not isinstance(child, TouchSensorModule) and \ + not isinstance(child, BrickSensorModule): + children_count += 1 - return has_children + return children_count + 1 + + def is_folding(self) -> bool: + """ + Checks if the module is a folding point. + The module is a folding point if and only if it has one child and that child is not + attached opposite to the parent. + :return: True if the module is a folding point + """ + if not self.has_children(): + return False + + # Default parent slot is BACK + parent_slot = Orientation.BACK + + target_slot = None + for slot, child in self.iter_children(): + if slot == parent_slot: + continue + # is the child slot occupied? + if child is None: + continue + # ignore TouchSensor and BrickSensor modules + if isinstance(child, TouchSensorModule) or \ + isinstance(child, BrickSensorModule): + continue + # second slot found, not a fold + if target_slot is not None: + return False + target_slot = slot + + target_slot = Orientation(target_slot) + return parent_slot.opposite() != target_slot class CoreModule(RevolveModule): @@ -265,6 +323,38 @@ def to_sdf(self, tree_depth='', parent_link=None, child_link=None): parent_link.append(imu_sensor) return visual, collision, imu_sensor + def count_module_connections(self) -> int: + """ + Count how many connections the module has. + Connected TouchSensor and BrickSensor Modules are ignored + :return: number of connections + """ + # The CoreModule does not have a parent module + return super(CoreModule, self).count_module_connections() - 1 + + def is_folding(self) -> bool: + # parent slot is not supposed to be set + parent_slot = None + target_slot = None + for slot, child in self.iter_children(): + # is the child slot occupied? + if child is None: + continue + # ignore TouchSensor and BrickSensor modules + if isinstance(child, TouchSensorModule) or \ + isinstance(child, BrickSensorModule): + continue + if parent_slot is None: + parent_slot = slot + elif target_slot is None: + target_slot = slot + else: + # More than 2 children, this is not a fold + return False + if parent_slot is None or target_slot is None: + return False + return parent_slot.opposite() != target_slot + class ActiveHingeModule(RevolveModule): """ diff --git a/test_py/plasticonding/test_development.py b/test_py/plasticonding/test_development.py index d2e409a1f6..5065043a59 100644 --- a/test_py/plasticonding/test_development.py +++ b/test_py/plasticonding/test_development.py @@ -81,6 +81,7 @@ def test_measurements_body(self): connectivity2_abs = 4 connectivity3 = 1 connectivity4 = 1 + connectivity5 = 1 coverage = 0.44 effective_joints = 0.444 joints_abs = 6 @@ -101,6 +102,7 @@ def test_measurements_body(self): self.assertAlmostEqual(connectivity2_abs, m.extensiveness, 3) # self.assertAlmostEqual(connectivity3, m., 3) self.assertAlmostEqual(connectivity4, m.branching_modules_count, 3) + self.assertAlmostEqual(connectivity5, m.tx_branching_modules_count, 3) self.assertAlmostEqual(coverage, m.coverage, 3) self.assertAlmostEqual(effective_joints, m.joints, 3) self.assertAlmostEqual(joints_abs, m.hinge_count, 3)