static_link_graph_handler.py
Go to the documentation of this file.
00001 #
00002 # License: BSD
00003 #
00004 #   https://raw.github.com/robotics-in-concert/rocon_concert/license/LICENSE
00005 #
00006 # Used for running services that are defined by a multi-master style
00007 # roslaunch - aka a link graph. In these services, the entities are all
00008 # fixed and locked in (as well as their connections) from the start of the
00009 # service to its termination.
00010 #
00011 ##############################################################################
00012 # Imports
00013 ##############################################################################
00014 
00015 import copy
00016 import rospy
00017 
00018 import rocon_std_msgs.msg as rocon_std_msgs
00019 import concert_msgs.msg as concert_msgs
00020 import concert_service_utilities
00021 import scheduler_msgs.msg as scheduler_msgs
00022 import std_msgs.msg as std_msgs
00023 import concert_schedulers
00024 import yaml
00025 import rocon_uri
00026 import rocon_python_comms
00027 
00028 ##############################################################################
00029 # Classes
00030 ##############################################################################
00031 
00032 
00033 class StaticLinkGraphHandler(object):
00034     __slots__ = [
00035         '_name',
00036         '_description',
00037         '_priority',
00038         '_uuid',
00039         '_linkgraph',
00040         '_requester',
00041         'spin',
00042         '_subscribers',
00043         '_disabled'
00044     ]
00045 
00046     def __init__(self, name, description, priority, key, linkgraph):
00047         '''
00048           @param name
00049           @type str
00050 
00051           @param description
00052           @type string
00053 
00054           @param key
00055           @type uuid.UUID
00056 
00057           @param linkgraph
00058           @type concert_msgs.LinkGraph
00059         '''
00060         self._name = name
00061         self._description = description
00062         self._priority = priority
00063         self._uuid = key
00064         self._linkgraph = linkgraph
00065         self._disabled = False
00066         self._setup_resource_pool_requester()
00067         self._setup_ros_subscribers()
00068 
00069     def spin(self):
00070         while not rospy.is_shutdown() and not self._disabled:
00071             rospy.rostime.wallsleep(0.5)  # same period as rospy.client's spin
00072 
00073     def _setup_ros_subscribers(self):
00074         self._subscribers = {}
00075         # put the shutdown topic in the root of the service space
00076         self._subscribers['shutdown'] = rospy.Subscriber('shutdown', std_msgs.Empty, self._ros_subscriber_shutdown)
00077 
00078     def _ros_subscriber_shutdown(self, unused_msg):
00079         '''
00080           Typically called by the service manager when it wants to disable this service.
00081           Note: if the node is shutting down we don't want to run this code as it runs into all sorts
00082           of unreliable ros pubsub communication. Instead, we deallocate (stop apps and uninvite) via
00083           a shutdown hook in the conductor.
00084 
00085           @param unused_msg : it's just a signal to trigger this callback
00086           @type std_msgs.Empty
00087         '''
00088         rospy.loginfo("Service : disabling [%s]" % self._name)
00089         self._requester.cancel_all_requests()
00090         self._disabled = True
00091 
00092     def _setup_resource_pool_requester(self):
00093         '''
00094           Setup the resource groups, then feed it into and Initialise the
00095           resource pool requester, It looks everything from thereon.
00096         '''
00097         resource_groups = []
00098         for node in self._linkgraph.nodes:
00099             resources = []
00100             resource = _node_to_resource(node, self._linkgraph)
00101             for unused_i in range(node.max):
00102                 resources.append(copy.deepcopy(resource))
00103             resource_groups.append(concert_schedulers.ResourcePoolGroup(node.min, resources))
00104         try:
00105             scheduler_requests_topic_name = concert_service_utilities.find_scheduler_requests_topic()
00106             #rospy.loginfo("Service : found scheduler [%s][%s]" % (topic_name))
00107         except rocon_python_comms.NotFoundException as e:
00108             rospy.logerr("Service : %s [%s]" % (str(e), self._name))
00109             return  # raise an exception here?
00110         self._requester = concert_schedulers.ResourcePoolRequester(
00111                                             resource_groups,
00112                                             feedback=self._requester_feedback,
00113                                             high_priority=self._priority,
00114                                             uuid=self._uuid,
00115                                             topic=scheduler_requests_topic_name
00116                                             )
00117 
00118     def _requester_feedback(self, request_set):
00119         '''
00120           Callback used to act on feedback coming from the scheduler request handler.
00121 
00122           @param request_set : a snapshot of the state of all requests from this requester
00123           @type concert_scheduler_requests.transition.RequestSet
00124         '''
00125         pass
00126 
00127 ##############################################################################
00128 # Methods
00129 ##############################################################################
00130 
00131 
00132 def load_linkgraph_from_yaml(yaml):
00133     """
00134         Loading a linkgraph from yaml and returns its name, and linkgraph
00135 
00136         :param str yaml: the link graph as a string loaded from yaml
00137 
00138         @return name - name of linkgraph
00139         @rtype str
00140         @return linkgraph
00141         @rtype concert_msgs.msg.LinkGraph
00142     """
00143     lg = concert_msgs.LinkGraph()
00144     name = yaml['name']
00145     for node in yaml['nodes']:
00146         node['min'] = node['min'] if 'min' in node else 1
00147         node['max'] = node['max'] if 'max' in node else 1
00148         node['force_name_matching'] = node['force_name_matching'] if 'force_name_matching' in node else False
00149         node['parameters'] = node['parameters'] if 'parameters' in node else {}
00150         lg.nodes.append(concert_msgs.LinkNode(node['id'], node['uri'], node['min'], node['max'], node['force_name_matching'],node['parameters']))
00151     for topic in yaml['topics']:
00152         lg.topics.append(concert_msgs.LinkConnection(topic['id'], topic['type']))
00153     if 'service' in yaml:
00154         for service in yaml['services']:
00155             lg.services.append(concert_msgs.LinkConnection(service['id'], service['type']))
00156     for action in yaml['actions']:
00157         lg.actions.append(concert_msgs.LinkConnection(action['id'], action['type']))
00158     for edge in yaml['edges']:
00159         lg.edges.append(concert_msgs.LinkEdge(edge['start'], edge['finish'], edge['remap_from'], edge['remap_to']))
00160 
00161     return name, lg
00162 
00163 
00164 def load_linkgraph_from_file(filename):
00165     """
00166         Loading a linkgraph from file and returns its name, and linkgraph
00167 
00168         @param filename - yaml file
00169         @type str
00170 
00171         @return name - name of linkgraph
00172         @rtype str
00173         @return linkgraph
00174         @rtype concert_msgs.msg.LinkGraph
00175     """
00176     with open(filename) as f:
00177         impl = yaml.load(f)
00178         name, lg = load_linkgraph_from_yaml(impl)
00179 
00180     return name, lg
00181 
00182 
00183 def _node_to_resource(node, linkgraph):
00184     '''
00185       Convert linkgraph information for a particular node to a scheduler_msgs.Resource type.
00186 
00187       @param node : a node from the linkgraph
00188       @type concert_msgs.LinkNode
00189 
00190       @param linkgraph : the entire linkgraph (used to lookup the node's edges)
00191       @type concert_msgs.LinkGraph
00192 
00193       @return resource
00194       @rtype scheduler_msgs.Resource
00195     '''
00196     resource = scheduler_msgs.Resource()
00197     resource.rapp = rocon_uri.parse(node.resource).rapp
00198     resource.uri = node.resource
00199     resource.remappings = [rocon_std_msgs.Remapping(e.remap_from, e.remap_to) for e in linkgraph.edges if e.start == node.id or e.finish == node.id]
00200     resource.parameters = [rocon_std_msgs.KeyValue(key,str(val)) for key, val in node.parameters.items()]
00201     return resource


concert_service_link_graph
Author(s): Daniel Stonier, Jihoon Lee
autogenerated on Thu Jun 6 2019 18:17:48