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()
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 ManagerNode(object): """ ROS node wrapper for the rhbp manager/planner """ def __init__(self): rospy.init_node('behaviourPlannerManager', log_level=rospy.WARN) prefix = rospy.get_param("~prefix", "") self._manager = Manager(prefix=prefix) self.rate = rospy.Rate(rospy.get_param("~frequency", 1)) self.automatic_stepping = rospy.get_param("~automatic_stepping", True) if not self.automatic_stepping: rospy.logwarn("Started in manual stepping mode") self._init_services(prefix) def _init_services(self, prefix): """ init all services handlers :param prefix: manager prefix """ self._set_automatic_stepping_service = rospy.Service(prefix + '/' + 'set_automatic_stepping', SetStepping, self._set_stepping_callback) self._get_automatic_stepping_service = rospy.Service(prefix + '/' + 'get_automatic_stepping', GetStepping, self._get_stepping_callback) self._stepping_service = rospy.Service(prefix + '/' + 'step', Empty, self._step_callback) def _set_stepping_callback(self, request): """ Callback service for enabling or disabling automatic stepping in the given frequency :param request: """ self.automatic_stepping = request.automatic_stepping rospy.loginfo("Automatic Stepping changed to " + str(self.automatic_stepping)) return SetSteppingResponse() def _get_stepping_callback(self, request): """ Callback service for getting the current automatic stepping setting :param request: """ response = GetSteppingResponse(self.automatic_stepping) return response def _step_callback(self, request): """ Service callback for manual planning/manager steps :param request: """ if not self.automatic_stepping: self._manager.step() else: rospy.logwarn("No manual stepping if automatic stepping is enabled") return EmptyResponse() def run(self): """ Executing the node after initialization """ while (not rospy.is_shutdown()): if self.automatic_stepping: self._manager.step() else: self._manager.send_discovery() self.rate.sleep()