subscribers.py
Go to the documentation of this file.
1 # Software License Agreement (BSD License)
2 #
3 # Copyright (c) 2012, Willow Garage, Inc.
4 # Copyright (c) 2013, PAL Robotics SL
5 # All rights reserved.
6 #
7 # Redistribution and use in source and binary forms, with or without
8 # modification, are permitted provided that the following conditions
9 # are met:
10 #
11 # * Redistributions of source code must retain the above copyright
12 # notice, this list of conditions and the following disclaimer.
13 # * Redistributions in binary form must reproduce the above
14 # copyright notice, this list of conditions and the following
15 # disclaimer in the documentation and/or other materials provided
16 # with the distribution.
17 # * Neither the name of Willow Garage, Inc. nor the names of its
18 # contributors may be used to endorse or promote products derived
19 # from this software without specific prior written permission.
20 #
21 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 # COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 # INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 # BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 # ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 # POSSIBILITY OF SUCH DAMAGE.
33 
34 from threading import Lock
35 from rospy import Subscriber, logerr
36 from rostopic import get_topic_type
37 from rosbridge_library.internal import ros_loader, message_conversion
38 from rosbridge_library.internal.topics import TopicNotEstablishedException
39 from rosbridge_library.internal.topics import TypeConflictException
40 from rosbridge_library.internal.outgoing_message import OutgoingMessage
41 
42 """ Manages and interfaces with ROS Subscriber objects. A single subscriber
43 is shared between multiple clients
44 """
45 
46 
48  """ Handles multiple clients for a single subscriber.
49 
50  Converts msgs to JSON before handing them to callbacks. Due to subscriber
51  callbacks being called in separate threads, must lock whenever modifying
52  or accessing the subscribed clients. """
53 
54  def __init__(self, topic, msg_type=None):
55  """ Register a subscriber on the specified topic.
56 
57  Keyword arguments:
58  topic -- the name of the topic to register the subscriber on
59  msg_type -- (optional) the type to register the subscriber as. If not
60  provided, an attempt will be made to infer the topic type
61 
62  Throws:
63  TopicNotEstablishedException -- if no msg_type was specified by the
64  caller and the topic is not yet established, so a topic type cannot
65  be inferred
66  TypeConflictException -- if the msg_type was specified by the
67  caller and the topic is established, and the established type is
68  different to the user-specified msg_type
69 
70  """
71  # First check to see if the topic is already established
72  topic_type = get_topic_type(topic)[0]
73 
74  # If it's not established and no type was specified, exception
75  if msg_type is None and topic_type is None:
76  raise TopicNotEstablishedException(topic)
77 
78  # Use the established topic type if none was specified
79  if msg_type is None:
80  msg_type = topic_type
81 
82  # Load the message class, propagating any exceptions from bad msg types
83  msg_class = ros_loader.get_message_class(msg_type)
84 
85  # Make sure the specified msg type and established msg type are same
86  if topic_type is not None and topic_type != msg_class._type:
87  raise TypeConflictException(topic, topic_type, msg_class._type)
88 
89  # Create the subscriber and associated member variables
90  self.subscriptions = {}
91  self.lock = Lock()
92  self.topic = topic
93  self.msg_class = msg_class
94  self.subscriber = Subscriber(topic, msg_class, self.callback)
95 
96  def unregister(self):
97  self.subscriber.unregister()
98  with self.lock:
99  self.subscriptions.clear()
100 
101  def verify_type(self, msg_type):
102  """ Verify that the subscriber subscribes to messages of this type.
103 
104  Keyword arguments:
105  msg_type -- the type to check this subscriber against
106 
107  Throws:
108  Exception -- if ros_loader cannot load the specified msg type
109  TypeConflictException -- if the msg_type is different than the type of
110  this publisher
111 
112  """
113  if not ros_loader.get_message_class(msg_type) is self.msg_class:
114  raise TypeConflictException(self.topic,
115  self.msg_class._type, msg_type)
116  return
117 
118  def subscribe(self, client_id, callback):
119  """ Subscribe the specified client to this subscriber.
120 
121  Keyword arguments:
122  client_id -- the ID of the client subscribing
123  callback -- this client's callback, that will be called for incoming
124  messages
125 
126  """
127  with self.lock:
128  self.subscriptions[client_id] = callback
129  # If the topic is latched, add_callback will immediately invoke
130  # the given callback.
131  self.subscriber.impl.add_callback(self.callback, [callback])
132  self.subscriber.impl.remove_callback(self.callback, [callback])
133 
134  def unsubscribe(self, client_id):
135  """ Unsubscribe the specified client from this subscriber
136 
137  Keyword arguments:
138  client_id -- the ID of the client to unsubscribe
139 
140  """
141  with self.lock:
142  del self.subscriptions[client_id]
143 
144  def has_subscribers(self):
145  """ Return true if there are subscribers """
146  with self.lock:
147  ret = len(self.subscriptions) != 0
148  return ret
149 
150  def callback(self, msg, callbacks=None):
151  """ Callback for incoming messages on the rospy.Subscriber
152 
153  Passes the message to registered subscriber callbacks.
154 
155  Keyword Arguments:
156  msg - the ROS message coming from the subscriber
157  callbacks - subscriber callbacks to invoke
158 
159  """
160  outgoing = OutgoingMessage(msg)
161 
162  # Get the callbacks to call
163  if not callbacks:
164  with self.lock:
165  callbacks = self.subscriptions.values()
166 
167  # Pass the JSON to each of the callbacks
168  for callback in callbacks:
169  try:
170  callback(outgoing)
171  except Exception as exc:
172  # Do nothing if one particular callback fails except log it
173  logerr("Exception calling subscribe callback: %s", exc)
174  pass
175 
176 
178  """
179  Keeps track of client subscriptions
180  """
181 
182  def __init__(self):
183  self._subscribers = {}
184 
185  def subscribe(self, client_id, topic, callback, msg_type=None):
186  """ Subscribe to a topic
187 
188  Keyword arguments:
189  client_id -- the ID of the client making this subscribe request
190  topic -- the name of the topic to subscribe to
191  callback -- the callback to call for incoming messages on the topic
192  msg_type -- (optional) the type of the topic
193 
194  """
195  if not topic in self._subscribers:
196  self._subscribers[topic] = MultiSubscriber(topic, msg_type)
197 
198  if msg_type is not None:
199  self._subscribers[topic].verify_type(msg_type)
200 
201  self._subscribers[topic].subscribe(client_id, callback)
202 
203  def unsubscribe(self, client_id, topic):
204  """ Unsubscribe from a topic
205 
206  Keyword arguments:
207  client_id -- the ID of the client to unsubscribe
208  topic -- the topic to unsubscribe from
209 
210  """
211  if not topic in self._subscribers:
212  return
213 
214  self._subscribers[topic].unsubscribe(client_id)
215 
216  if not self._subscribers[topic].has_subscribers():
217  self._subscribers[topic].unregister()
218  del self._subscribers[topic]
219 
220 
221 manager = SubscriberManager()
222 
def subscribe(self, client_id, topic, callback, msg_type=None)
Definition: subscribers.py:185


rosbridge_library
Author(s): Jonathan Mace
autogenerated on Fri May 10 2019 02:17:02