rosros 0.2.5
Simple unified interface to ROS1 / ROS2 Python API
Loading...
Searching...
No Matches
core.py
Go to the documentation of this file.
1# -*- coding: utf-8 -*-
2"""
3ROS system and node functionality.
4
5------------------------------------------------------------------------------
6This file is part of rosros - simple unified interface to ROS1 / ROS2.
7Released under the BSD License.
8
9@author Erki Suurjaak
10@created 11.02.2022
11@modified 10.12.2023
12------------------------------------------------------------------------------
13"""
14## @namespace rosros.core
15import os
16
17ros1 = ros2 = None
18if os.getenv("ROS_VERSION") != "2":
19 from . import ros1
20else:
21 from . import ros2
22ros = ros1 or ros2
23
24
25
26AnyMsg = ros.AnyMsg
27
28
29Bag = ros.Bag
30
31
32def init_node(name, args=None, namespace=None, anonymous=False, log_level=None, enable_rosout=True,
33 multithreaded=True, reentrant=False):
34 """
35 Initializes ROS and creates ROS node.
36
37 @param name node name, without namespace
38 @param args list of command-line arguments for the node
39 @param namespace node namespace override
40 @param anonymous whether to auto-generate a unique name for the node,
41 using the given name as base
42 @param log_level level to set for ROS logging
43 (name like "DEBUG" or one of `logging` constants like `logging.DEBUG`)
44 @param enable_rosout `False` to suppress auto-publication of rosout
45 @param multithreaded ROS2 only, ignored in ROS1:
46 use `MultiThreadedExecutor` instead of `SingleThreadedExecutor`
47 @param reentrant ROS2 only, ignored in ROS1:
48 use `ReentrantCallbackGroup` instead of `MutuallyExclusiveCallbackGroup`
49 @return `None` in ROS1, `rclpy.node.Node` in ROS2
50 """
51 if ros1: args = (name, args, namespace, anonymous, log_level, enable_rosout)
52 else: args = (name, args, namespace, anonymous, log_level, multithreaded, reentrant)
53 return (ros1.init_node if ros1 else ros2.init_node)(*args)
54
55
56def init_params(defaults=None, **defaultkws):
57 """
58 Sets all parameters on node from defaults dictionary.
59
60 In ROS2, auto-declares unregistered parameters.
61
62 @param defaults nested dictionary with suitable keys and values for ROS
63 (keys must be valid namespace names,
64 list values must not contain nested values)
65 @param defaultkws parameters as key=value
66 @return full nested parameters dictionary, combined from given defaults
67 and externally set parameters on the node
68 """
69 return ros.init_params(defaults, **defaultkws)
70
71
72def delete_param(name):
73 """
74 Deletes parameter from the node.
76 @param name full name of the parameter in node namespace
77 @throws KeyError if parameter not set
78 """
79 ros.delete_param(name)
80
81
82def has_param(name):
83 """
84 Returns whether the parameter exists on the node.
85
86 @param name full name of the parameter in node namespace
87 """
88 return ros.has_param(name)
89
90
91def get_param_names():
92 """Returns the names of all parameters on the node."""
93 return ros.get_param_names()
94
95
96def get_params(nested=True):
97 """
98 Returns the current ROS node parameters, by default as nested dictionary.
99
100 @param nested return a nested dictionary,
101 like `{"my": {"name": 1}}` vs {"my.name": 1}
102 """
103 return ros.get_params(nested)
104
105
106def get_param(name, default=None, autoset=True):
107 """
108 Returns parameter value from the node.
109
110 @param default optional default to return if parameter unknown
111 @param autoset set default value to node as parameter value if unknown
112 @return parameter value, or default if parameter was unknown
113
114 @throws KeyError if parameter not set and default not given
115 """
116 return ros.get_param(name, default, autoset)
117
118
119def set_param(name, value, descriptor=None):
120 """
121 Sets a parameter on the node.
122
123 In ROS2, parameter will be auto-declared if unknown so far.
124
125 @param name full name of the parameter in node namespace
126 @param value parameter value to set
127 @param descriptor optional `rcl_interfaces.msg.ParameterDescriptor` in ROS2
128 @return the set value
129 """
130 if ros1: return ros1.set_param(name, value)
131 return ros2.set_param(name, value, descriptor)
132
134def start_spin():
135 """Sets ROS node spinning forever in a background thread."""
136 ros.start_spin()
137
138
139def spin():
140 """Spins ROS node forever."""
141 ros.spin()
142
144def spin_once(timeout=None):
145 """
146 Waits until timeout in ROS1; executes one ROS operation or waits until timeout in ROS2.
147
148 @param timeout time to wait at most, as seconds or ROS duration;
149 None or <0 waits forever
150 """
151 ros.spin_once(timeout)
152
154def spin_until_future_complete(future, timeout=None):
155 """
156 Spins ROS until future complete or timeout reached or ROS shut down.
158 @param future object with `concurrent.futures.Future`-conforming interface to complete
159 @param timeout time to wait, as seconds or ROS1 duration
160 """
161 ros.spin_until_future_complete(future, timeout)
162
163
164def ok():
165 """Returns whether ROS has been initialized and is not shut down."""
166 return ros.ok()
167
168
169def on_shutdown(callback, *args, **kwargs):
170 """
171 Registers function to be called on shutdown, after node has been torn down.
172
173 Function is called with given arguments.
174
175 Note: function may not get called if process is killed.
176 """
177 ros.on_shutdown(callback, *args, **kwargs)
179
180def shutdown(reason=None):
181 """
182 Shuts down live ROS node, if any.
183
184 @param reason shutdown reason to log, if any
185 """
186 ros.shutdown(reason)
187
188
189def create_publisher(topic, cls_or_typename, latch=False, queue_size=0, **qosargs):
190 """
191 Returns a ROS publisher instance.
192
193 @param topic name of topic to open
194 @param cls_or_typename ROS message class object like `std_msgs.msg.Bool`
195 or message type name like "std_msgs/Bool"
196 @param latch provide last published message to new subscribers
197 (sets `DurabilityPolicy.TRANSIENT_LOCAL` in ROS2)
198 @param queue_size queue size of outgoing messages (0 or None: infinite)
199 (sets QoS `depth` in ROS2)
200 @param qosargs additional key-value arguments for ROS2
201 `QoSProfile`, like `reliability` (uses only `depth`
202 and `durability`=TRANSIENT_LOCAL in ROS1)
203 @return `rospy.Publisher` or `rclpy.publisher.Publisher`,
204 either will support keyword arguments in `publish()`
205 and have `get_num_connections()`
206 """
207 if ros1:
208 queue_size = qosargs.get("depth", queue_size)
209 if qosargs.get("durability") == 1: # DurabilityPolicy.TRANSIENT_LOCAL
210 latch = True
211 return ros1.create_publisher(topic, cls_or_typename, latch, queue_size)
212 return ros2.create_publisher(topic, cls_or_typename, latch, queue_size, **qosargs)
213
214
215def create_subscriber(topic, cls_or_typename, callback, callback_args=None,
216 queue_size=0, raw=False, **qosargs):
217 """
218 Returns a ROS subscriber instance.
219
220 @param topic name of topic to listen to
221 @param cls_or_typename ROS message class object like `std_msgs.msg.Bool`
222 or message type name like "std_msgs/Bool"
223 @param callback callback function, invoked with received message,
224 and with additional arguments if given
225 @param callback_args additional arguments to pass to the callback, if any,
226 invoked as `callback(msg, callback_args)ยด
227 @param queue_size queue size of incoming messages (0 or None: infinite)
228 @param raw invoke callback with serialized message bytes,
229 make subscription with AnyMsg in ROS1
230 @param qosargs additional key-value arguments for ROS2
231 `QoSProfile`, like `reliability` (uses only `depth` in ROS1).
232 `__autodetect` will look up current publishers on the topic
233 and create a compatible QoS.
234 @return `rospy.Subscriber` or `rclpy.subscription.Subscription`
235 """
236 if ros1:
237 queue_size = qosargs.get("depth", queue_size)
238 return ros1.create_subscriber(topic, cls_or_typename, callback, callback_args,
239 queue_size, raw)
240 return ros2.create_subscriber(topic, cls_or_typename, callback, callback_args,
241 queue_size, raw, **qosargs)
242
243
244def create_service(service, cls_or_typename, callback, **qosargs):
245 """
246 Returns a ROS service server instance, for providing a service.
247
248 @param service name of service to provide
249 @param cls_or_typename ROS service class object like `std_srvs.srv.SetBool`
250 or service type name like `"std_srvs/SetBool"
251 @param callback callback function, invoked with `(request, response)`,
252 expected to return the populated response,
253 or a list/tuple/dictionary for populating the response.
254 If the function only takes one argument,
255 it is invoked with `(request)`.
256 @param qosargs additional key-value arguments for ROS2
257 `QoSProfile`, like `reliability` (ignored in ROS1)
258 @return `rospy.Service` or `rclpy.service.Service`
259 """
260 if ros1: return ros1.create_service(service, cls_or_typename, callback)
261 return ros2.create_service(service, cls_or_typename, callback, **qosargs)
262
263
264def create_client(service, cls_or_typename, **qosargs):
265 """
266 Returns a ROS service client instance, for invoking a service.
267
268 @param service name of service to invoke
269 @param cls_or_typename ROS service class object like `std_srvs.srv.SetBool`
270 or service type name like `"std_srvs/SetBool"
271 @param qosargs additional key-value arguments for ROS2
272 `QoSProfile`, like `reliability` (ignored in ROS1)
273 @return `rospy.ServiceProxy` or `rclpy.client.Client`,
274 either will have `call_async()` returning a future,
275 either will support keyword arguments in calls
276 and be callable itself
277 """
278 if ros1: return ros1.create_client(service, cls_or_typename)
279 return ros2.create_client(service, cls_or_typename, **qosargs)
280
281
282def create_timer(period, callback, oneshot=False, immediate=False):
283 """
284 Returns a ROS timer instance.
285
286 @param period desired period between callbacks, as seconds or ROS duration
287 @param callback callback function invoked on timer, with no arguments
288 @param oneshot whether to fire only once
289 @param immediate whether to fire once immediately instead of waiting one period
290 @return `rospy.Timer` or `rclpy.timer.Timer`
291 """
292 return ros.create_timer(period, callback, oneshot, immediate)
293
294
295def create_rate(frequency):
296 """
297 Returns a ROS rate instance, for sleeping at a fixed rate.
298
299 @param frequency rate to sleep at, in Hz
300 @return `rospy.Rate` or `rclpy.rate.Rate`
301 """
302 return ros.create_rate(frequency)
303
304
305def destroy_entity(item):
306 """Closes the given publisher, subscriber, service client, or service server instance."""
307 return ros.destroy_entity(item)
308
309
310def get_logger():
311 """
312 Returns `logging.Logger` for logging to ROS log handler.
313
314 Logging methods on the logger (`debug()`, `info()`, etc) accept additional keyword arguments:
315 - `__once__`: whether to log only once from call site
316 - `__throttle__`: seconds to skip logging from call site for
317 - `__throttle_identical__`: whether to skip logging identical consecutive texts from call site
318 (given log message excluding formatting arguments).
319 Combines with `__throttle__` to skip duplicates for a period.
320 """
321 return ros.get_logger()
322
323
324def get_rostime():
325 """Returns ROS time instance for current ROS clock time."""
326 return ros.get_rostime()
327
328
329def get_namespace():
330 """Returns ROS node namespace."""
331 return ros.get_namespace()
332
333
334def get_node_name():
335 """Returns ROS node full name with namespace."""
336 return ros.get_node_name()
337
339def get_nodes():
340 """Returns all ROS nodes, as `[node full name, ]`."""
341 return ros.get_nodes()
342
343
344def get_ros_version():
345 """Returns ROS version information, as {"major": "1" / "2", ?"minor": distro like "noetic"}."""
346 result = {"major": os.getenv("ROS_VERSION")}
347 if os.getenv("ROS_DISTRO"): result["minor"] = os.getenv("ROS_DISTRO")
348 return result
349
351def get_topics():
352 """Returns all available ROS topics, as `[(topic name, [type name, ]), ]`."""
353 return ros.get_topics()
354
355
356def get_services(node=None, namespace=None, include_types=True):
357 """
358 Returns all available ROS services, as `[(service name, [type name, ]), ]`.
359
360 @param node full name of the node to return services for, if any
361 @param namespace full or partial namespace to scope services from
362 @param include_types if false, type names will be returned as an empty list
363 """
364 return ros.get_services(node, namespace, include_types)
365
366
367def remap_name(name, namespace=None):
368 """
369 Returns the absolute remapped topic/service name if mapping exists.
371 @param name name to seek exact remapping for
372 @param namespace namespace to resolve relative and private names to,
373 by default current node namespace
374 @return remapped resolved name, or original if not mapped
375 """
376 return ros.remap_name(name, namespace)
377
378
379def resolve_name(name, namespace=None):
380 """
381 Returns absolute remapped name, namespaced under current node if relative or private.
382
383 @param namespace namespace to use if not current node full name
384 """
385 return ros.resolve_name(name, namespace)
386
387
388def register_init(node=None):
389 """
390 Informs `rosros` of ROS having been initialized outside of `init_node()`.
391
392 @param node mandatory `rclpy.node.Node` in ROS2
393 """
394 ros1.register_init() if ros1 else ros2.register_init(node)
395
396
397def sleep(duration):
398 """
399 Sleeps for the specified duration in ROS time.
400
401 Raises error on ROS shutdown or ROS time jumping backwards
402
403 @param duration time to sleep, as seconds or ROS duration, <=0 returns immediately
404 """
405 ros.sleep(duration)
406
407
408def wait_for_publisher(topic, timeout=None, cls_or_typename=None):
409 """
410 Blocks until topic has at least one publisher.
411
412 @param topic name of topic to open
413 @param timeout time to wait at most, as seconds or ROS duration;
414 None or <0 waits forever
415 @param cls_or_typename message type to expect if any,
416 as ROS message class object like `std_msgs.msg.Bool`
417 or message type name like "std_msgs/Bool"
418 @return whether a publisher is available
419 """
420 return ros.wait_for_publisher(topic, timeout, cls_or_typename)
421
422
423def wait_for_subscriber(topic, timeout=None, cls_or_typename=None):
424 """
425 Blocks until topic has at least one subscriber.
426
427 @param topic name of topic to open
428 @param timeout time to wait at most, as seconds or ROS duration;
429 None or <0 waits forever
430 @param cls_or_typename message type to expect if any,
431 as ROS message class object like `std_msgs.msg.Bool`
432 or message type name like "std_msgs/Bool"
433 @return whether a subscriber is available
434 """
435 return ros.wait_for_subscriber(topic, timeout, cls_or_typename)
436
437
438def wait_for_service(service, timeout=None, cls_or_typename=None):
439 """
440 Blocks until service is available.
441
442 @param service name of service
443 @param timeout time to wait at most, as seconds or ROS duration;
444 None or <0 waits forever
445 @param cls_or_typename service type to expect if any,
446 as ROS service class object like `std_msgs.msg.Bool`
447 or service type name like "std_srvs/SetBool"
448 @return whether the service is available
449 """
450 return ros.wait_for_service(service, timeout, cls_or_typename)
451
452
453__all__ = [
454 "ros1", "ros2", "AnyMsg", "Bag",
455 "create_client", "create_publisher", "create_rate", "create_service", "create_subscriber",
456 "create_timer", "delete_param", "destroy_entity", "get_logger", "get_namespace",
457 "get_node_name", "get_nodes", "get_param", "get_param_names", "get_params", "get_ros_version",
458 "get_rostime", "get_services", "get_topics", "has_param", "init_node", "init_params",
459 "ok", "on_shutdown", "register_init", "remap_name", "resolve_name", "set_param", "sleep",
460 "shutdown", "spin", "spin_once", "spin_until_future_complete", "start_spin",
461 "wait_for_publisher", "wait_for_subscriber", "wait_for_service"
462]
spin_once(timeout=None)
Waits until timeout in ROS1; executes one ROS operation or waits until timeout in ROS2.
Definition core.py:143
create_timer(period, callback, oneshot=False, immediate=False)
Returns a ROS timer instance.
Definition core.py:279
get_node_name()
Returns ROS node full name with namespace.
Definition core.py:321
get_rostime()
Returns ROS time instance for current ROS clock time.
Definition core.py:311
init_params(defaults=None, **defaultkws)
Sets all parameters on node from defaults dictionary.
Definition core.py:66
spin_until_future_complete(future, timeout=None)
Spins ROS until future complete or timeout reached or ROS shut down.
Definition core.py:153
create_subscriber(topic, cls_or_typename, callback, callback_args=None, queue_size=0, raw=False, **qosargs)
Returns a ROS subscriber instance.
Definition core.py:226
spin()
Spins ROS node forever.
Definition core.py:133
get_ros_version()
Returns ROS version information, as {"major": "1" / "2", ?"minor": distro like "noetic"}.
Definition core.py:331
wait_for_subscriber(topic, timeout=None, cls_or_typename=None)
Blocks until topic has at least one subscriber.
Definition core.py:418
start_spin()
Sets ROS node spinning forever in a background thread.
Definition core.py:128
get_params(nested=True)
Returns the current ROS node parameters, by default as nested dictionary.
Definition core.py:98
get_logger()
Returns `logging.Logger` for logging to ROS log handler.
Definition core.py:307
register_init(node=None)
Informs `rosros` of ROS having been initialized outside of `init_node()`.
Definition core.py:379
create_client(service, cls_or_typename, **qosargs)
Returns a ROS service client instance, for invoking a service.
Definition core.py:266
wait_for_publisher(topic, timeout=None, cls_or_typename=None)
Blocks until topic has at least one publisher.
Definition core.py:404
get_param_names()
Returns the names of all parameters on the node.
Definition core.py:88
get_services(node=None, namespace=None, include_types=True)
Returns all available ROS services, as `[(service name, [type name, ]), ]`.
Definition core.py:350
get_namespace()
Returns ROS node namespace.
Definition core.py:316
destroy_entity(item)
Closes the given publisher, subscriber, service client, or service server instance.
Definition core.py:292
create_publisher(topic, cls_or_typename, latch=False, queue_size=0, **qosargs)
Returns a ROS publisher instance.
Definition core.py:198
create_rate(frequency)
Returns a ROS rate instance, for sleeping at a fixed rate.
Definition core.py:288
get_nodes()
Returns all ROS nodes, as `[node full name, ]`.
Definition core.py:326
ok()
Returns whether ROS has been initialized and is not shut down.
Definition core.py:157
get_topics()
Returns all available ROS topics, as `[(topic name, [type name, ]), ]`.
Definition core.py:338
create_service(service, cls_or_typename, callback, **qosargs)
Returns a ROS service server instance, for providing a service.
Definition core.py:249
shutdown(reason=None)
Shuts down live ROS node, if any.
Definition core.py:178