1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 """
36 Additional ROS client API methods.
37 """
38
39 from __future__ import with_statement
40
41 import logging
42 import os
43 import socket
44 import struct
45 import sys
46 import time
47 import random
48
49 import roslib
50 import roslib.names
51 import roslib.network
52
53 import rospy.core
54 from rospy.core import logwarn, loginfo, logerr, logdebug
55 import rospy.exceptions
56 import rospy.names
57 import rospy.rostime
58
59 import rospy.impl.init
60 import rospy.impl.rosout
61 import rospy.impl.simtime
62
63 TIMEOUT_READY = 15.0
64
65
66 from rosgraph_msgs.msg import Log
67 DEBUG = Log.DEBUG
68 INFO = Log.INFO
69 WARN = Log.WARN
70 ERROR = Log.ERROR
71 FATAL = Log.FATAL
72
73 _rospy_to_logging_levels = {
74 DEBUG: logging.DEBUG,
75 INFO: logging.INFO,
76 WARN: logging.WARNING,
77 ERROR: logging.ERROR,
78 FATAL: logging.CRITICAL,
79 }
80
81
83 """
84 Register function to be called on shutdown. This function will be
85 called before Node begins teardown.
86 @param h: Function with zero args to be called on shutdown.
87 @type h: fn()
88 """
89 rospy.core.add_client_shutdown_hook(h)
90
106
108 """
109 Helper function for using sys.argv is ROS client libraries.
110 @return: copy of sys.argv with ROS remapping arguments removed
111 @rtype: [str]
112 """
113 import roslib.scriptutil
114 return roslib.scriptutil.myargv(argv=argv)
115
117 """
118 Uploads private params to the parameter server. Private params are specified
119 via command-line remappings.
120 """
121
122
123 import roslib.params
124 params = roslib.params.load_command_line_node_params(argv)
125 for param_name, param_value in params.iteritems():
126 logdebug("setting param %s to %s"%(param_name, param_value))
127 set_param(roslib.names.PRIV_NAME + param_name, param_value)
128
129 _init_node_args = None
130
131 -def init_node(name, argv=None, anonymous=False, log_level=INFO, disable_rostime=False, disable_rosout=False, disable_signals=False):
132 """
133 Register client node with the master under the specified name.
134 This MUST be called from the main Python thread unless
135 disable_signals is set to True. Duplicate calls to init_node are
136 only allowed if the arguments are identical as the side-effects of
137 this method are not reversible.
138
139 @param name: Node's name. This parameter must be a base name,
140 meaning that it cannot contain namespaces (i.e. '/')
141 @type name: str
142
143 @param argv: Command line arguments to this program, including
144 remapping arguments (default: sys.argv). If you provide argv
145 to init_node(), any previously created rospy data structure
146 (Publisher, Subscriber, Service) will have invalid
147 mappings. It is important that you call init_node() first if
148 you wish to provide your own argv.
149 @type argv: [str]
150
151 @param anonymous: if True, a name will be auto-generated for the
152 node using name as the base. This is useful when you wish to
153 have multiple instances of the same node and don't care about
154 their actual names (e.g. tools, guis). name will be used as
155 the stem of the auto-generated name. NOTE: you cannot remap
156 the name of an anonymous node.
157 @type anonymous: bool
158
159 @param log_level: log level for sending message to /rosout and log
160 file, which is INFO by default. For convenience, you may use
161 rospy.DEBUG, rospy.INFO, rospy.ERROR, rospy.WARN, rospy.FATAL
162 @type log_level: int
163
164 @param disable_signals: If True, rospy will not register its own
165 signal handlers. You must set this flag if (a) you are unable
166 to call init_node from the main thread and/or you are using
167 rospy in an environment where you need to control your own
168 signal handling (e.g. WX). If you set this to True, you should
169 call rospy.signal_shutdown(reason) to initiate clean shutdown.
170
171 NOTE: disable_signals is overridden to True if
172 roslib.is_interactive() is True.
173
174 @type disable_signals: bool
175
176 @param disable_rostime: for rostests only, suppresses
177 automatic subscription to rostime
178 @type disable_rostime: bool
179
180 @param disable_rosout: suppress auto-publication of rosout
181 @type disable_rostime: bool
182
183 @raise ROSInitException: if initialization/registration fails
184 @raise ValueError: if parameters are invalid (e.g. name contains a namespace or is otherwise illegal)
185 """
186 if argv is None:
187 argv = sys.argv
188 else:
189
190
191 rospy.names.reload_mappings(argv)
192
193
194 if roslib.names.SEP in name:
195 raise ValueError("namespaces are not allowed in node names")
196 if not roslib.names.is_legal_base_name(name):
197 import warnings
198 warnings.warn("'%s' is not a legal ROS base name. This may cause problems with other ROS tools"%name, stacklevel=2)
199
200 global _init_node_args
201
202
203
204 if _init_node_args:
205 if _init_node_args != (name, argv, anonymous, log_level, disable_rostime, disable_signals):
206 raise rospy.exceptions.ROSException("rospy.init_node() has already been called with different arguments: "+str(_init_node_args))
207 else:
208 return
209
210
211
212 disable_signals = disable_signals or roslib.is_interactive()
213 _init_node_args = (name, argv, anonymous, log_level, disable_rostime, disable_signals)
214
215 if not disable_signals:
216
217 rospy.core.register_signals()
218 else:
219 logdebug("signal handlers for rospy disabled")
220
221
222 mappings = rospy.names.get_mappings()
223 if '__name' in mappings:
224
225 name = roslib.names.resolve_name(mappings['__name'], rospy.core.get_caller_id())
226 if anonymous:
227 logdebug("[%s] WARNING: due to __name setting, anonymous setting is being changed to false"%name)
228 anonymous = False
229
230 if anonymous:
231
232
233 name = "%s_%s_%s"%(name, os.getpid(), int(time.time()*1000))
234
235 resolved_node_name = rospy.names.resolve_name(name)
236 rospy.core.configure_logging(resolved_node_name, level=_rospy_to_logging_levels[log_level])
237
238 rospy.names.initialize_mappings(resolved_node_name)
239
240 logger = logging.getLogger("rospy.client")
241 logger.info("init_node, name[%s], pid[%s]", resolved_node_name, os.getpid())
242
243
244 node = rospy.impl.init.start_node(os.environ, resolved_node_name)
245 rospy.core.set_node_uri(node.uri)
246 rospy.core.add_shutdown_hook(node.shutdown)
247
248 if rospy.core.is_shutdown():
249 logger.warn("aborting node initialization as shutdown has been triggered")
250 raise rospy.exceptions.ROSInitException("init_node interrupted before it could complete")
251
252
253 _init_node_params(argv, name)
254
255 rospy.core.set_initialized(True)
256
257 rospy.impl.rosout.load_rosout_handlers(log_level)
258 if not disable_rosout:
259 rospy.impl.rosout.init_rosout()
260 logdebug("init_node, name[%s], pid[%s]", resolved_node_name, os.getpid())
261 if not disable_rostime:
262 if not rospy.impl.simtime.init_simtime():
263 raise rospy.exceptions.ROSInitException("Failed to initialize time. Please check logs for additional details")
264 else:
265 rospy.rostime.set_rostime_initialized(True)
266
267
268 _master_proxy = None
269
271 """
272 Get a remote handle to the ROS Master.
273 This method can be called independent of running a ROS node,
274 though the ROS_MASTER_URI must be declared in the environment.
275
276 @return: ROS Master remote object
277 @rtype: L{rospy.MasterProxy}
278 @raise Exception: if server cannot be located or system cannot be
279 initialized
280 """
281 global _master_proxy
282 if _master_proxy is not None:
283 return _master_proxy
284 import roslib.rosenv
285 _master_proxy = rospy.msproxy.MasterProxy(roslib.rosenv.get_master_uri())
286 return _master_proxy
287
288
289
290
292 """
293 Retrieve list of topics that the master is reporting as being published.
294
295 @return: List of topic names and types: [[topic1, type1]...[topicN, typeN]]
296 @rtype: [[str, str]]
297 """
298 code, msg, val = get_master().getPublishedTopics(namespace)
299 if code != 1:
300 raise rospy.exceptions.ROSException("unable to get published topics: %s"%msg)
301 return val
302
307 if self.msg is None:
308 self.msg = msg
309
311 """
312 Receive one message from topic.
313
314 This will create a new subscription to the topic, receive one message, then unsubscribe.
315
316 @param topic: name of topic
317 @type topic: str
318 @param topic_type: topic type
319 @type topic_type: L{rospy.Message} class
320 @param timeout: timeout time in seconds
321 @type timeout: double
322 @return: Message
323 @rtype: L{rospy.Message}
324 @raise ROSException: if specified timeout is exceeded
325 @raise ROSInterruptException: if shutdown interrupts wait
326 """
327 wfm = _WFM()
328 s = None
329 try:
330 s = rospy.topics.Subscriber(topic, topic_type, wfm.cb)
331 if timeout is not None:
332 timeout_t = time.time() + timeout
333 while not rospy.core.is_shutdown() and wfm.msg is None:
334 time.sleep(0.01)
335 if time.time() >= timeout_t:
336 raise rospy.exceptions.ROSException("timeout exceeded while waiting for message on topic %s"%topic)
337
338 else:
339 while not rospy.core.is_shutdown() and wfm.msg is None:
340 time.sleep(0.01)
341 finally:
342 if s is not None:
343 s.unregister()
344 if rospy.core.is_shutdown():
345 raise rospy.exceptions.ROSInterruptException("rospy shutdown")
346 return wfm.msg
347
348
349
350
351
352 _param_server = None
360
361
363 _unspecified = _Unspecified()
364
366 """
367 Retrieve a parameter from the param server
368 @param default: (optional) default value to return if key is not set
369 @type default: any
370 @return: parameter value
371 @rtype: XmlRpcLegalValue
372 @raise ROSException: if parameter server reports an error
373 @raise KeyError: if value not set and default is not given
374 """
375 try:
376 _init_param_server()
377 return _param_server[param_name]
378 except KeyError:
379 if default != _unspecified:
380 return default
381 else:
382 raise
383
385 """
386 Retrieve list of parameter names.
387 @return: parameter names
388 @rtype: [str]
389 @raise ROSException: if parameter server reports an error
390 """
391 _init_param_server()
392 code, msg, val = _param_server.getParamNames()
393 if code != 1:
394 raise rospy.exceptions.ROSException("Unable to retrieve parameter names: %s"%msg)
395 else:
396 return val
397
399 """
400 Set a parameter on the param server
401 @param param_name: parameter name
402 @type param_name: str
403 @param param_value: parameter value
404 @type param_value: XmlRpcLegalValue
405 @raise ROSException: if parameter server reports an error
406 """
407
408 if not roslib.names.is_legal_name(param_name):
409 import warnings
410 warnings.warn("'%s' is not a legal ROS graph resource name. This may cause problems with other ROS tools"%param_name, stacklevel=2)
411
412 _init_param_server()
413 _param_server[param_name] = param_value
414
416 """
417 Search for a parameter on the param server
418 @param param_name: parameter name
419 @type param_name: str
420 @return: key of matching parameter or None if no matching parameter.
421 @rtype: str
422 @raise ROSException: if parameter server reports an error
423 """
424 _init_param_server()
425 return _param_server.search_param(param_name)
426
428 """
429 Delete a parameter on the param server
430 @param param_name: parameter name
431 @type param_name: str
432 @raise KeyError: if parameter is not set
433 @raise ROSException: if parameter server reports an error
434 """
435 _init_param_server()
436 del _param_server[param_name]
437
439 """
440 Test if parameter exists on the param server
441 @param param_name: parameter name
442 @type param_name: str
443 @raise ROSException: if parameter server reports an error
444 """
445 _init_param_server()
446 return param_name in _param_server
447
448
449
450
451
452
453
455 """
456 Convenience class for sleeping in a loop at a specified rate
457 """
458
468
470 """
471 Attempt sleep at the specified rate. sleep() takes into
472 account the time elapsed since the last successful
473 sleep().
474
475 @raise ROSInterruptException: if ROS time is set backwards or if
476 ROS shutdown occurs before sleep completes
477 """
478 curr_time = rospy.rostime.get_rostime()
479
480 if self.last_time > curr_time:
481 self.last_time = curr_time
482
483
484 elapsed = curr_time - self.last_time
485 sleep(self.sleep_dur - elapsed)
486 self.last_time = self.last_time + self.sleep_dur
487
488
489
490 if curr_time - self.last_time > self.sleep_dur * 2:
491 self.last_time = curr_time
492
493
541