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 import logging
40 import os
41 import socket
42 import struct
43 import sys
44 import time
45 import random
46 import yaml
47
48 import rosgraph
49 import rosgraph.names
50
51 import roslib
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 from roscpp.srv import GetLoggers, GetLoggersResponse, SetLoggerLevel, SetLoggerLevelResponse
68 from roscpp.msg import Logger
69 from rospy.impl.tcpros_service import Service
70 DEBUG = Log.DEBUG
71 INFO = Log.INFO
72 WARN = Log.WARN
73 ERROR = Log.ERROR
74 FATAL = Log.FATAL
75
77 """
78 Remove ROS remapping arguments from sys.argv arguments.
79 @return: copy of sys.argv with ROS remapping arguments removed
80 @rtype: [str]
81 """
82 if argv is None:
83 argv = sys.argv
84 return [a for a in argv if not rosgraph.names.REMAP in a]
85
87 """
88 Load node param mappings (aka private parameters) encoded in
89 command-line arguments, e.g. _foo:=bar. See also rosgraph.names.load_mappings.
90 @param argv: command-line arguments
91 @param argv: [str]
92 @return: param->value remappings.
93 @rtype: {str: val}
94 @raises: ROSInitException
95 """
96 try:
97 mappings = {}
98 for arg in argv:
99 if rosgraph.names.REMAP in arg:
100 src, dst = [x.strip() for x in arg.split(rosgraph.names.REMAP)]
101 if src and dst:
102 if len(src) > 1 and src[0] == '_' and src[1] != '_':
103 mappings[src[1:]] = yaml.load(dst)
104 return mappings
105 except Exception as e:
106 raise rospy.exceptions.ROSInitException("invalid command-line parameters: %s"%(str(e)))
107
109 """
110 Register function to be called on shutdown. This function will be
111 called before Node begins teardown.
112 @param h: Function with zero args to be called on shutdown.
113 @type h: fn()
114 """
115 rospy.core.add_client_shutdown_hook(h)
116
132
133 _logging_level_names = {
134 logging.DEBUG: 'DEBUG',
135 logging.INFO: 'INFO',
136 logging.WARNING: 'WARN',
137 logging.ERROR: 'ERROR',
138 logging.CRITICAL: 'FATAL',
139 }
140
142 """
143 ROS service handler to get the levels of all active loggers.
144 """
145 ret = GetLoggersResponse()
146 for n in logging.Logger.manager.loggerDict.keys():
147 level = logging.getLogger(n).getEffectiveLevel()
148 level = _logging_level_names[level]
149 ret.loggers.append(Logger(n, level))
150 return ret
151
152 _names_to_logging_levels = {
153 'DEBUG': logging.DEBUG,
154 'INFO': logging.INFO,
155 'WARN': logging.WARNING,
156 'ERROR': logging.ERROR,
157 'FATAL': logging.CRITICAL,
158 }
159
161 """
162 ROS service handler to set the logging level for a particular logger
163 """
164 level = request.level.upper()
165 if level in _names_to_logging_levels:
166 logger = logging.getLogger(request.logger)
167 logger.setLevel(_names_to_logging_levels[level])
168 else:
169 logging.getLogger('rospy').error("Bad logging level: %s"%level)
170 ret = SetLoggerLevelResponse()
171 return ret
172
174 """
175 Uploads private params to the parameter server. Private params are specified
176 via command-line remappings.
177
178 @raises: ROSInitException
179 """
180
181
182 params = load_command_line_node_params(argv)
183 for param_name, param_value in params.items():
184 logdebug("setting param %s to %s"%(param_name, param_value))
185 set_param(rosgraph.names.PRIV_NAME + param_name, param_value)
186
187 _init_node_args = None
188
189 -def init_node(name, argv=None, anonymous=False, log_level=None, disable_rostime=False, disable_rosout=False, disable_signals=False):
190 """
191 Register client node with the master under the specified name.
192 This MUST be called from the main Python thread unless
193 disable_signals is set to True. Duplicate calls to init_node are
194 only allowed if the arguments are identical as the side-effects of
195 this method are not reversible.
196
197 @param name: Node's name. This parameter must be a base name,
198 meaning that it cannot contain namespaces (i.e. '/')
199 @type name: str
200
201 @param argv: Command line arguments to this program, including
202 remapping arguments (default: sys.argv). If you provide argv
203 to init_node(), any previously created rospy data structure
204 (Publisher, Subscriber, Service) will have invalid
205 mappings. It is important that you call init_node() first if
206 you wish to provide your own argv.
207 @type argv: [str]
208
209 @param anonymous: if True, a name will be auto-generated for the
210 node using name as the base. This is useful when you wish to
211 have multiple instances of the same node and don't care about
212 their actual names (e.g. tools, guis). name will be used as
213 the stem of the auto-generated name. NOTE: you cannot remap
214 the name of an anonymous node.
215 @type anonymous: bool
216
217 @param log_level: log level for sending message to /rosout and log
218 file, which is INFO by default. For convenience, you may use
219 rospy.DEBUG, rospy.INFO, rospy.ERROR, rospy.WARN, rospy.FATAL
220 @type log_level: int
221
222 @param disable_signals: If True, rospy will not register its own
223 signal handlers. You must set this flag if (a) you are unable
224 to call init_node from the main thread and/or you are using
225 rospy in an environment where you need to control your own
226 signal handling (e.g. WX). If you set this to True, you should
227 call rospy.signal_shutdown(reason) to initiate clean shutdown.
228
229 NOTE: disable_signals is overridden to True if
230 roslib.is_interactive() is True.
231
232 @type disable_signals: bool
233
234 @param disable_rostime: for internal testing only: suppresses
235 automatic subscription to rostime
236 @type disable_rostime: bool
237
238 @param disable_rosout: for internal testing only: suppress
239 auto-publication of rosout
240 @type disable_rostime: bool
241
242 @raise ROSInitException: if initialization/registration fails
243 @raise ValueError: if parameters are invalid (e.g. name contains a namespace or is otherwise illegal)
244 """
245 if argv is None:
246 argv = sys.argv
247 else:
248
249
250 rospy.names.reload_mappings(argv)
251
252
253 if rosgraph.names.SEP in name:
254 raise ValueError("namespaces are not allowed in node names")
255 if not rosgraph.names.is_legal_base_name(name):
256 import warnings
257 warnings.warn("'%s' is not a legal ROS base name. This may cause problems with other ROS tools"%name, stacklevel=2)
258
259 global _init_node_args
260
261
262
263 if _init_node_args:
264 if _init_node_args != (name, argv, anonymous, log_level, disable_rostime, disable_signals):
265 raise rospy.exceptions.ROSException("rospy.init_node() has already been called with different arguments: "+str(_init_node_args))
266 else:
267 return
268
269
270
271 disable_signals = disable_signals or roslib.is_interactive()
272 _init_node_args = (name, argv, anonymous, log_level, disable_rostime, disable_signals)
273
274 if not disable_signals:
275
276 rospy.core.register_signals()
277 else:
278 logdebug("signal handlers for rospy disabled")
279
280
281 mappings = rospy.names.get_mappings()
282 if '__name' in mappings:
283
284 name = rosgraph.names.resolve_name(mappings['__name'], rospy.core.get_caller_id())
285 if anonymous:
286 logdebug("[%s] WARNING: due to __name setting, anonymous setting is being changed to false"%name)
287 anonymous = False
288
289 if anonymous:
290
291
292 name = "%s_%s_%s"%(name, os.getpid(), int(time.time()*1000))
293
294 resolved_node_name = rospy.names.resolve_name(name)
295 rospy.core.configure_logging(resolved_node_name)
296
297 rospy.names.initialize_mappings(resolved_node_name)
298
299 logger = logging.getLogger("rospy.client")
300 logger.info("init_node, name[%s], pid[%s]", resolved_node_name, os.getpid())
301
302
303 node = rospy.impl.init.start_node(os.environ, resolved_node_name)
304 rospy.core.set_node_uri(node.uri)
305 rospy.core.add_shutdown_hook(node.shutdown)
306
307 if rospy.core.is_shutdown():
308 logger.warn("aborting node initialization as shutdown has been triggered")
309 raise rospy.exceptions.ROSInitException("init_node interrupted before it could complete")
310
311
312 _init_node_params(argv, name)
313
314 rospy.core.set_initialized(True)
315
316 if not disable_rosout:
317 rospy.impl.rosout.init_rosout()
318 rospy.impl.rosout.load_rosout_handlers(log_level)
319
320 if not disable_rostime:
321 if not rospy.impl.simtime.init_simtime():
322 raise rospy.exceptions.ROSInitException("Failed to initialize time. Please check logs for additional details")
323 else:
324 rospy.rostime.set_rostime_initialized(True)
325
326 logdebug("init_node, name[%s], pid[%s]", resolved_node_name, os.getpid())
327
328 Service('~get_loggers', GetLoggers, _get_loggers)
329 Service('~set_logger_level', SetLoggerLevel, _set_logger_level)
330
331
332
333 _master_proxy = None
334
336 """
337 Get a remote handle to the ROS Master.
338 This method can be called independent of running a ROS node,
339 though the ROS_MASTER_URI must be declared in the environment.
340
341 @return: ROS Master remote object
342 @rtype: L{rospy.MasterProxy}
343 @raise Exception: if server cannot be located or system cannot be
344 initialized
345 """
346 global _master_proxy
347 if _master_proxy is not None:
348 return _master_proxy
349 _master_proxy = rospy.msproxy.MasterProxy(rosgraph.get_master_uri())
350 return _master_proxy
351
352
353
354
356 """
357 Retrieve list of topics that the master is reporting as being published.
358
359 @return: List of topic names and types: [[topic1, type1]...[topicN, typeN]]
360 @rtype: [[str, str]]
361 """
362 code, msg, val = get_master().getPublishedTopics(namespace)
363 if code != 1:
364 raise rospy.exceptions.ROSException("unable to get published topics: %s"%msg)
365 return val
366
371 if self.msg is None:
372 self.msg = msg
373
375 """
376 Receive one message from topic.
377
378 This will create a new subscription to the topic, receive one message, then unsubscribe.
379
380 @param topic: name of topic
381 @type topic: str
382 @param topic_type: topic type
383 @type topic_type: L{rospy.Message} class
384 @param timeout: timeout time in seconds
385 @type timeout: double
386 @return: Message
387 @rtype: L{rospy.Message}
388 @raise ROSException: if specified timeout is exceeded
389 @raise ROSInterruptException: if shutdown interrupts wait
390 """
391 wfm = _WFM()
392 s = None
393 try:
394 s = rospy.topics.Subscriber(topic, topic_type, wfm.cb)
395 if timeout is not None:
396 timeout_t = time.time() + timeout
397 while not rospy.core.is_shutdown() and wfm.msg is None:
398 rospy.rostime.wallsleep(0.01)
399 if time.time() >= timeout_t:
400 raise rospy.exceptions.ROSException("timeout exceeded while waiting for message on topic %s"%topic)
401
402 else:
403 while not rospy.core.is_shutdown() and wfm.msg is None:
404 rospy.rostime.wallsleep(0.01)
405 finally:
406 if s is not None:
407 s.unregister()
408 if rospy.core.is_shutdown():
409 raise rospy.exceptions.ROSInterruptException("rospy shutdown")
410 return wfm.msg
411
412
413
414
415
416 _param_server = None
424
425
427 _unspecified = _Unspecified()
428
430 """
431 Retrieve a parameter from the param server
432
433 NOTE: this method is not thread-safe.
434
435 @param default: (optional) default value to return if key is not set
436 @type default: any
437 @return: parameter value
438 @rtype: XmlRpcLegalValue
439 @raise ROSException: if parameter server reports an error
440 @raise KeyError: if value not set and default is not given
441 """
442 try:
443 _init_param_server()
444 return _param_server[param_name]
445 except KeyError:
446 if default != _unspecified:
447 return default
448 else:
449 raise
450
452 """
453 Retrieve list of parameter names.
454
455 NOTE: this method is not thread-safe.
456
457 @return: parameter names
458 @rtype: [str]
459 @raise ROSException: if parameter server reports an error
460 """
461 _init_param_server()
462 code, msg, val = _param_server.getParamNames()
463 if code != 1:
464 raise rospy.exceptions.ROSException("Unable to retrieve parameter names: %s"%msg)
465 else:
466 return val
467
469 """
470 Set a parameter on the param server
471
472 NOTE: this method is not thread-safe.
473
474 @param param_name: parameter name
475 @type param_name: str
476 @param param_value: parameter value
477 @type param_value: XmlRpcLegalValue
478 @raise ROSException: if parameter server reports an error
479 """
480
481 if not rosgraph.names.is_legal_name(param_name):
482 import warnings
483 warnings.warn("'%s' is not a legal ROS graph resource name. This may cause problems with other ROS tools"%param_name, stacklevel=2)
484
485 _init_param_server()
486 _param_server[param_name] = param_value
487
489 """
490 Search for a parameter on the param server
491
492 NOTE: this method is not thread-safe.
493
494 @param param_name: parameter name
495 @type param_name: str
496 @return: key of matching parameter or None if no matching parameter.
497 @rtype: str
498 @raise ROSException: if parameter server reports an error
499 """
500 _init_param_server()
501 return _param_server.search_param(param_name)
502
504 """
505 Delete a parameter on the param server
506
507 NOTE: this method is not thread-safe.
508
509 @param param_name: parameter name
510 @type param_name: str
511 @raise KeyError: if parameter is not set
512 @raise ROSException: if parameter server reports an error
513 """
514 _init_param_server()
515 del _param_server[param_name]
516
518 """
519 Test if parameter exists on the param server
520
521 NOTE: this method is not thread-safe.
522
523 @param param_name: parameter name
524 @type param_name: str
525 @raise ROSException: if parameter server reports an error
526 """
527 _init_param_server()
528 return param_name in _param_server
529