def test_offline_goal(self): method_prefix = self.__message_prefix + "TestOfflineGoal" planner_prefix = method_prefix + "/Manager" m = Manager(activationThreshold=7, prefix=planner_prefix) topic_name = method_prefix + '/Topic' sensor = SimpleTopicSensor(topic=topic_name, message_type=Bool, initial_value=False) condition = Condition(sensor, BooleanActivator()) pddl_function_name = condition.getFunctionNames()[0] SetTrueBehavior(effect_name=pddl_function_name, topic_name=topic_name, name=method_prefix + "SetTrue", plannerPrefix=planner_prefix) goal = OfflineGoal('CentralGoal', planner_prefix=planner_prefix) goal.add_condition(condition) m.add_goal(goal) for x in range(0, 3, 1): m.step() rospy.sleep(0.1) goal.fetchStatus(3) self.assertTrue(goal.satisfied, 'Goal is not satisfied') goal.unregister()
def test_activator(self): method_prefix = self.__message_prefix + "TestOfflineGoal" planner_prefix = method_prefix + "Manager" m = Manager(activationThreshold=7, prefix=planner_prefix) topic_name = 'IncreaseTopicTest/Topic' sensor = TopicSensor(topic=topic_name, name='IncreaseTopicTestSensor', message_type=Int32, initial_value=0) activator = GreedyActivator() condition = Condition(sensor=sensor, activator=activator) IncreaserBehavior(topic_name=topic_name, effect_name=sensor.name, createLogFiles=True, planner_prefix=planner_prefix) goal = OfflineGoal(name=self.__message_prefix + 'CentralGoal', planner_prefix=planner_prefix) goal.add_condition(condition) m.add_goal(goal) number_of_steps = 15 for x in range(0, number_of_steps + 1 , 1): m.step() rospy.sleep(0.1) # it takes 2 steps until the activation has increased expected_behaviour_steps = number_of_steps - 2 self.assertEquals(expected_behaviour_steps, sensor.latestValue)
def test_conditions_in_multiple_levels(self): """ Testing conditions that are used as well on the highest manager hierarchy level as well as in a sub manager of a NetworkBehaviour. In particular one conditions is used as precondition, the other one as goal condition. """ method_prefix = self.__message_prefix + "/test_conditions_in_multiple_levels" pre_con_sensor = Sensor(name="Precon_sensor", initial_value=False) pre_con = Condition(pre_con_sensor, BooleanActivator(desiredValue=True)) topic_name = method_prefix + '/Topic' sensor = TopicSensor(topic=topic_name, message_type=Int32, initial_value=0) condition = Condition(sensor, ThresholdActivator(thresholdValue=3)) planner_prefix = method_prefix + "/Manager" m = Manager(activationThreshold=7, prefix=planner_prefix) goal = OfflineGoal('CentralGoal', planner_prefix=planner_prefix) goal.add_condition(condition) m.add_goal(goal) effect = Effect(sensor_name=sensor.name, indicator=1, sensor_type=int, activator_name=condition.activator.name) first_level_network = NetworkBehaviour(name=method_prefix + '/FirstLevel', planner_prefix=planner_prefix, createLogFiles=True) first_level_network.add_effects([effect]) first_level_network.add_precondition(pre_con) goal_with_same_cond = OfflineGoal('CentralGoal2', planner_prefix=planner_prefix) goal_with_same_cond.add_condition(condition) first_level_network.add_goal(goal_with_same_cond) increaser_behavior = IncreaserBehavior(effect_name=sensor.name, topic_name=topic_name, name=method_prefix + "TopicIncreaser", planner_prefix=first_level_network.get_manager_prefix()) increaser_behavior.add_precondition(pre_con) # activate the first_level_network increaser_Behavior for x in range(0, 3, 1): self.assertFalse(first_level_network._isExecuting) m.step() pre_con_sensor.update(True) rospy.sleep(0.1) self.assertTrue(first_level_network._isExecuting) for x in range(0, 4, 1): m.step() rospy.sleep(0.1) self.assertTrue(increaser_behavior._isExecuting)
def test_multiple_embedded_network_behaviors(self): """ Tests the case, that one network behavior is embedded into another network behavior. The goal requires to receive an int (3) in a topic. """ method_prefix = self.__message_prefix + "/test_multiple_embedded_network_behaviors" topic_name = method_prefix + '/Topic' sensor = SimpleTopicSensor(topic=topic_name, message_type=Int32, initial_value=0) condition = Condition(sensor, ThresholdActivator(thresholdValue=3)) planner_prefix = method_prefix + "/Manager" m = Manager(activationThreshold=7, prefix=planner_prefix) goal = OfflineGoal('CentralGoal', planner_prefix=planner_prefix) goal.add_condition(condition) m.add_goal(goal) effect = Effect(sensor_name=sensor.name, indicator=1, sensor_type=int, activator_name=condition.activator.name) first_level_network = NetworkBehavior(name=method_prefix + '/FirstLevel', plannerPrefix=planner_prefix, createLogFiles=True) first_level_network.add_effects_and_goals([(sensor, effect)]) second_level_network = NetworkBehavior( name=method_prefix + '/SecondLevel', plannerPrefix=first_level_network.get_manager_prefix(), createLogFiles=True) # Doesnt matter, whether the effects are added via the constructor or the add method. # Both methods are used here, to demonstrate both ways. second_level_network.add_effects_and_goals([(sensor, effect)]) pddl_function_name = condition.getFunctionNames()[0] increaser_behavior = IncreaserBehavior( effect_name=pddl_function_name, topic_name=topic_name, name=method_prefix + "TopicIncreaser", plannerPrefix=second_level_network.get_manager_prefix()) # activate the first_level_network, second_level_network and increaser_Behavior for x in range(0, 3, 1): self.assertFalse(first_level_network._isExecuting) m.step() rospy.sleep(0.1) self.assertTrue(first_level_network._isExecuting) for x in range(0, 3, 1): self.assertFalse(second_level_network._isExecuting) first_level_network.do_step() rospy.sleep(0.1) self.assertTrue(second_level_network._isExecuting) for x in range(0, 3, 1): self.assertFalse(increaser_behavior._isExecuting) second_level_network.do_step() rospy.sleep(0.1) self.assertTrue(increaser_behavior._isExecuting) # Satisfy goal for step in range(0, 3, 1): sensor.sync() self.assertEqual(step, sensor.value) second_level_network.do_step() rospy.sleep(0.1) goal.fetchStatus(3) self.assertTrue(goal.satisfied, 'Goal is not satisfied')
class NetworkBehavior(BehaviourBase): """ Behavior, which encapsulates an additional manager and behaviors. This allows to build hierarchies of hybrid behaviour planners. """ MANAGER_POSTFIX = "Manager" def __init__(self, name, requires_execution_steps=True, only_running_for_deciding_interruptible=Manager. USE_ONLY_RUNNING_BEHAVIOURS_FOR_INTERRUPTIBLE_DEFAULT_VALUE, correlations=None, always_update_activation=False, **kwargs): """ :param correlations: tuple <Effect> :param name: name of the behaviour that is also used to create the sub manager name together with the NetworkBehavior.MANAGER_POSTFIX :param requires_execution_steps: whether the execution steps should be caused from the parent manager or not. If not, the step method must be called manually :param always_update_activation: if set to True the entire activation calculation of the sub manager is updated on each behaviour computation update :param kwargs: args for the manager, except the prefix arg """ super(NetworkBehavior, self).__init__(name=name, requires_execution_steps=requires_execution_steps, **kwargs) self.requires_execution_steps = requires_execution_steps self.always_update_activation = always_update_activation manager_args = {} manager_args.update(kwargs) manager_args['prefix'] = self.get_manager_prefix() self.__manager = Manager(activated=False, use_only_running_behaviors_for_interRuptible= only_running_for_deciding_interruptible, **manager_args) self.__goal_name_prefix = name + "/Goals/" self.__goal_counter = 0 if correlations is not None: self.add_effects(correlations) def updateComputation(self, manager_step): super(NetworkBehavior, self).updateComputation(manager_step) if not self._isExecuting: self.__manager.send_discovery() def _restore_condition_name_from_pddl_function_name( self, pddl_function_name, sensor_name): return Activator.restore_condition_name_from_pddl_function_name( pddl_function_name=pddl_function_name, sensor_name=sensor_name) def get_manager_prefix(self): """ Return the manager prefix generated by the behaviour name and the MANAGER_POSTFIX :return: the manager prefix str """ return self._name + '/' + NetworkBehavior.MANAGER_POSTFIX def __generate_goal_name(self, effect): """ :param effect: instance of type Effect :return: unique name for goal """ # x as separator between counter an sensor names, to prevent conflict, caused by unusual names name = self.__goal_name_prefix + str( self.__goal_counter) + 'X' + effect.sensor_name self.__goal_counter += 1 return name def _create_goal(self, sensor, effect, goal_name, activator_name): """ Generate goals, which made the manager trying to work infinitely on the given effect, until the network is stopped. Therefore the goal shouldn't reachable (except the goal for boolean effects) :param sensor: instance of type Sensor :param effect: instance of type Effect :param goal_name: unique name for the goal :return: a goal, which causes the manager to work on the effect during the whole time """ if effect.sensor_type == str(bool): desired_value = True if effect.indicator > 0 else False activator = BooleanActivator(name=activator_name, desiredValue=desired_value) condition = Condition(activator=activator, sensor=sensor) return OfflineGoal(name=goal_name, planner_prefix=self.get_manager_prefix(), permanent=True, conditions={condition}) if effect.sensor_type == str(int) or effect.sensor_type == str(float): activator = GreedyActivator(maximize=effect.indicator > 0, step_size=abs(effect.indicator), name=activator_name) condition = Condition(activator=activator, sensor=sensor) return OfflineGoal(goal_name, planner_prefix=self.get_manager_prefix(), permanent=True, conditions={condition}) raise RuntimeError( msg='Cant create goal for effect type \'' + effect.sensor_type + '\'. Overwrite the method _create_goal to handle the type') @deprecated def add_correlations(self, correlations): """ Adds the given effects to the correlations of this Behavior. DEPRECATED: Use *add_effects* instead :param correlations: list of Effects """ self.add_effects(correlations) @deprecated def add_correlations_and_goals(self, sensor_correlations): """ Adds the given effects to the correlations of this Behavior. Furthermore creates a goal for each Effect and registers it at the nested Manager DEPRECATED: Use *add_effects_and_goals* instead :param sensor_correlations: list of tuples of (Sensor, Effect) """ self.add_effects_and_goals(sensor_correlations) def add_effects(self, effects): """ Adds the given effects to this Behavior. :param effects: list of Effects """ self._correlations.extend(effects) def add_effects_and_goals(self, sensor_effect): """ Adds the given effects to the correlations of this Behavior. Furthermore creates a goal for each Effect and registers it at the nested Manager :param sensor_effect: list of tuples of (Sensor, Effect) """ #TODO this might has to be revised for sensor, effect in sensor_effect: goal_name = self.__generate_goal_name(effect) if not effect.activator_name: activator_name = self._restore_condition_name_from_pddl_function_name( effect.sensor_name, sensor.name) else: activator_name = effect.activator_name goal = self._create_goal(sensor=sensor, effect=effect, goal_name=goal_name, activator_name=activator_name) self.__manager.add_goal(goal) self._correlations.append(effect) def add_goal(self, goal): """ Adds the given goal to nested manager :param goal: AbstractGoalRepresentation """ self.__manager.add_goal(goal) def updateComputation(self, manager_step): super(NetworkBehavior, self).updateComputation(manager_step) # only trigger the update if not already activated because then it would be executed anyhow if self.always_update_activation and not self.__manager.activated: self.__manager.update_activation(plan_if_necessary=False) def do_step(self): self.__manager.step() def start(self): self.__manager.activate() def stop(self): self.__manager.deactivate() def _is_interruptible(self): return self.__manager.is_interruptible()
class NetworkBehaviour(BehaviourBase): """ Behavior, which encapsulates an additional manager and behaviors. This allows to build hierarchies of hybrid behaviour planners. """ MANAGER_POSTFIX = "Manager" TYPE_STRING = "Network" def __init__(self, name, requires_execution_steps=True, only_running_for_deciding_interruptible=Manager. USE_ONLY_RUNNING_BEHAVIOURS_FOR_INTERRUPTIBLE_DEFAULT_VALUE, correlations=None, always_update_activation=False, guarantee_decision=False, **kwargs): """ :param correlations: tuple <Effect> :param name: name of the behaviour that is also used to create the sub manager name together with the NetworkBehaviour.MANAGER_POSTFIX :param requires_execution_steps: whether the execution steps should be caused from the parent manager or not. If not, the step method must be called manually :param always_update_activation: if set to True the entire activation calculation of the sub manager is updated on each behaviour computation update :param guarantee_decision: if there are executable behaviours in the local network, adjust the thresholds until at least one behaviour is selected :param kwargs: args for the manager, except the prefix arg """ super(NetworkBehaviour, self).__init__(name=name, requires_execution_steps=requires_execution_steps, **kwargs) if "interruptable" in kwargs: rhbplog.logwarn( "Interruptable parameter will be ignored in a NetworkBehaviour. Interruptable attribute is " "evaluated based on the running or registered parameters, " "see 'only_running_for_deciding_interruptible'") self.requires_execution_steps = requires_execution_steps self.always_update_activation = always_update_activation self.guarantee_decision = guarantee_decision manager_args = {} manager_args.update(kwargs) manager_args['prefix'] = self.get_manager_prefix() self.__manager = Manager(enabled=False, use_only_running_behaviors_for_interRuptible= only_running_for_deciding_interruptible, **manager_args) self.__goal_name_prefix = name + "/Goals/" self.__goal_counter = 0 if correlations is not None: self.add_effects(correlations) def get_manager_prefix(self): """ Return the manager prefix generated by the behaviour name and the MANAGER_POSTFIX :return: the manager prefix str """ return self._name + '/' + NetworkBehaviour.MANAGER_POSTFIX def __generate_goal_name(self, effect): """ :param effect: instance of type Effect :return: unique name for goal """ # x as separator between counter an sensor names, to prevent conflict, caused by unusual names name = self.__goal_name_prefix + str( self.__goal_counter) + 'X' + effect.sensor_name self.__goal_counter += 1 return name def _create_goal(self, sensor, effect, goal_name): """ Generate goals, which made the manager trying to work infinitely on the given effect, until the network is stopped. Therefore the goal shouldn't reachable (except the goal for boolean effects) :param sensor: instance of type Sensor :param effect: instance of type Effect :param goal_name: unique name for the goal :return: a goal, which causes the manager to work on the effect during the whole time :raises RuntimeError: if the creation of a goal for an effect of this type is not possible """ try: condition = create_condition_from_effect(effect=effect, sensor=sensor) return OfflineGoal(name=goal_name, planner_prefix=self.get_manager_prefix(), permanent=True, conditions={condition}) except RuntimeError: raise RuntimeError( msg="Can't create goal for effect type '" + effect.sensor_type + "'.Overwrite the method _create_goal to handle the type") @deprecated def add_correlations(self, correlations): """ Adds the given effects to the correlations of this Behavior. DEPRECATED: Use *add_effects* instead :param correlations: list of Effects """ self.add_effects(correlations) @deprecated def add_correlations_and_goals(self, sensor_correlations): """ Adds the given effects to the correlations of this Behavior. Furthermore creates a goal for each Effect and registers it at the nested Manager DEPRECATED: Use *add_effects_and_goals* instead :param sensor_correlations: list of tuples of (Sensor, Effect) """ self.add_effects_and_goals(sensor_correlations) def add_effects(self, effects): """ Adds the given effects to this Behavior. :param effects: list of Effects """ self._correlations.extend(effects) def add_effects_and_goals(self, sensor_effect): """ Adds the given effects to the correlations of this Behavior. Furthermore creates a goal for each Effect and registers it at the nested Manager :param sensor_effect: list of tuples of (Sensor, Effect) """ for sensor, effect in sensor_effect: goal_name = self.__generate_goal_name(effect) goal = self._create_goal(sensor=sensor, effect=effect, goal_name=goal_name) self.__manager.add_goal(goal) self._correlations.append(effect) def add_goal(self, goal): """ Adds the given goal to nested manager :param goal: AbstractGoalRepresentation """ self.__manager.add_goal(goal) def updateComputation(self, manager_step): super(NetworkBehaviour, self).updateComputation(manager_step) # only trigger the update if not already activated because then it would be executed anyhow if self.always_update_activation and not self.__manager.enabled: self.__manager.update_activation(plan_if_necessary=False) if not self._isExecuting: self.__manager.send_discovery() def do_step(self): self.__manager.step(guarantee_decision=self.guarantee_decision) def start(self): self.__manager.enable() def stop(self): self.__manager.disable() def _is_interruptible(self): return self.__manager.is_interruptible()