00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
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
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)
00072
00073 def _setup_ros_subscribers(self):
00074 self._subscribers = {}
00075
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
00107 except rocon_python_comms.NotFoundException as e:
00108 rospy.logerr("Service : %s [%s]" % (str(e), self._name))
00109 return
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
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