Compare commits
306 Commits
jacob/wait
...
runtime_in
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
10e482ee5c | ||
|
|
c8734b3e1d | ||
|
|
8447d36206 | ||
|
|
969067242b | ||
|
|
32859cdf3c | ||
|
|
30210a2c02 | ||
|
|
d871af007a | ||
|
|
29577dab24 | ||
|
|
000f788b65 | ||
|
|
ca17caf6c4 | ||
|
|
e7e9a298c0 | ||
|
|
8571b28664 | ||
|
|
7e0d063154 | ||
|
|
113dc01dc7 | ||
|
|
aac28e7b9f | ||
|
|
24e533eba7 | ||
|
|
ca1fe2b41b | ||
|
|
57900a9f44 | ||
|
|
363861f70c | ||
|
|
9555859691 | ||
|
|
78a568d14a | ||
|
|
9ff28439d1 | ||
|
|
bfcc29e64b | ||
|
|
927b9de2a5 | ||
|
|
5af57f8010 | ||
|
|
0ce81c4fed | ||
|
|
a2484be7c3 | ||
|
|
833efe0e2d | ||
|
|
554ad022a6 | ||
|
|
a3e5d0a91a | ||
|
|
b8fd304546 | ||
|
|
71a06985af | ||
|
|
73d555b402 | ||
|
|
a5368e6fe4 | ||
|
|
20e9cd17f6 | ||
|
|
cb08c79a0a | ||
|
|
bff59925de | ||
|
|
1a796b5515 | ||
|
|
cbd48c0eb4 | ||
|
|
18dd05fba5 | ||
|
|
232262c02a | ||
|
|
6c4afb3a70 | ||
|
|
b6a803f48c | ||
|
|
dbe555a3c3 | ||
|
|
1a9b117d53 | ||
|
|
11778f5048 | ||
|
|
399f4df739 | ||
|
|
e7890b7c62 | ||
|
|
b589b490c3 | ||
|
|
72c05ecee0 | ||
|
|
968ce0a03f | ||
|
|
3062dec77e | ||
|
|
9ea55ba620 | ||
|
|
f57f4077fd | ||
|
|
006d1fa1df | ||
|
|
b1e834a8df | ||
|
|
28e4b1bd73 | ||
|
|
35a5d6a66c | ||
|
|
01b19247f1 | ||
|
|
15ea024d48 | ||
|
|
ce5a2614fa | ||
|
|
beda0966db | ||
|
|
1fd5a96561 | ||
|
|
be8c5d01c6 | ||
|
|
97c5c11c25 | ||
|
|
7d660acc05 | ||
|
|
ab71df3ce1 | ||
|
|
37adc03c11 | ||
|
|
3db2ece145 | ||
|
|
1bbb03302a | ||
|
|
c63f9eae0f | ||
|
|
a73e0bd23b | ||
|
|
c5491a4e58 | ||
|
|
3fb012e2e9 | ||
|
|
9c1c9896a3 | ||
|
|
c091fe1a45 | ||
|
|
a20a295a3b | ||
|
|
86335dd4ac | ||
|
|
432bf21f02 | ||
|
|
1ac37b692c | ||
|
|
338eed0c06 | ||
|
|
66b19448b0 | ||
|
|
a00ef22d6d | ||
|
|
e5d20474da | ||
|
|
91bc312190 | ||
|
|
82f1fbff0b | ||
|
|
7c6785176a | ||
|
|
586932ebf8 | ||
|
|
edbfe1404b | ||
|
|
6f22443513 | ||
|
|
e5d13a2478 | ||
|
|
d119157948 | ||
|
|
85c0af4fa0 | ||
|
|
2d32d03ba3 | ||
|
|
28890bf126 | ||
|
|
b9b1468d15 | ||
|
|
3aca271ef5 | ||
|
|
dec766228d | ||
|
|
95837d34f1 | ||
|
|
145933b037 | ||
|
|
6a8c61c026 | ||
|
|
978439191f | ||
|
|
7bc05da5d1 | ||
|
|
4744fb6f50 | ||
|
|
d0e1e837b5 | ||
|
|
92d4f3e347 | ||
|
|
ea8daa3784 | ||
|
|
df994e435d | ||
|
|
93222cc2cd | ||
|
|
11b5f8db21 | ||
|
|
6167a575b3 | ||
|
|
dab9f5e0a3 | ||
|
|
3d69031d2a | ||
|
|
b953bdddf8 | ||
|
|
64e4c72791 | ||
|
|
f6056beaa0 | ||
|
|
37b589dc85 | ||
|
|
6dd3a0377b | ||
|
|
33dae5d679 | ||
|
|
f43a9198eb | ||
|
|
3c8e89d17c | ||
|
|
546ddf87fe | ||
|
|
dbded5c0d6 | ||
|
|
86a9d5882e | ||
|
|
8e6a6fb32d | ||
|
|
b3f57033a9 | ||
|
|
38581cc860 | ||
|
|
790e529ba3 | ||
|
|
5c688303b3 | ||
|
|
02802bcc38 | ||
|
|
491475f232 | ||
|
|
b8b64b4c08 | ||
|
|
ee67c211c5 | ||
|
|
82ddd44140 | ||
|
|
a1980678ae | ||
|
|
c24e485084 | ||
|
|
d99157d731 | ||
|
|
248d911ea5 | ||
|
|
76aae4f799 | ||
|
|
6815022909 | ||
|
|
85a7046ac3 | ||
|
|
6c06a29050 | ||
|
|
03fa731d23 | ||
|
|
0699aeb851 | ||
|
|
06e6da414a | ||
|
|
12de518956 | ||
|
|
eac0063176 | ||
|
|
492770c12f | ||
|
|
d302e3c628 | ||
|
|
011ea39e99 | ||
|
|
49c2dd4813 | ||
|
|
6afec4805c | ||
|
|
9ae35e347e | ||
|
|
0f58bb8700 | ||
|
|
8b9cabfb9d | ||
|
|
2e39e09803 | ||
|
|
91f0b64493 | ||
|
|
3bd6900f98 | ||
|
|
f2f7ffdf53 | ||
|
|
16914e31a1 | ||
|
|
4e3c6be76a | ||
|
|
79241a3cdc | ||
|
|
9c5ad79b63 | ||
|
|
d8e1aed520 | ||
|
|
c5a16dce11 | ||
|
|
32c03dde2d | ||
|
|
4f778199b4 | ||
|
|
025cd5ccc8 | ||
|
|
4c8cfa39f8 | ||
|
|
891fff0153 | ||
|
|
43db06dad7 | ||
|
|
0d1747e066 | ||
|
|
2520d398c7 | ||
|
|
d3c0049b24 | ||
|
|
c54a6f1cd2 | ||
|
|
9ec0393e63 | ||
|
|
bca3fd7da1 | ||
|
|
8afef51cfd | ||
|
|
3123f5a643 | ||
|
|
aa18ef51cc | ||
|
|
1688f05aea | ||
|
|
80f93d1dbb | ||
|
|
5e314c253e | ||
|
|
6b321edb4f | ||
|
|
8093648ee3 | ||
|
|
9583ec7855 | ||
|
|
2d6e6364cd | ||
|
|
5613d613cf | ||
|
|
7a2ee23281 | ||
|
|
802bfc2c74 | ||
|
|
152dbc6e38 | ||
|
|
9342c257b8 | ||
|
|
d2e563afd5 | ||
|
|
8ac848bbc2 | ||
|
|
b2b676d317 | ||
|
|
ee20dd31e6 | ||
|
|
0775e2f6e7 | ||
|
|
321c74c2b3 | ||
|
|
536df11ee0 | ||
|
|
6f6e9e8ce9 | ||
|
|
39dad4d9a7 | ||
|
|
87d754b219 | ||
|
|
e03e98220d | ||
|
|
f7bb88fc8f | ||
|
|
0781ea543c | ||
|
|
e0e96681d9 | ||
|
|
b1f31e0eaa | ||
|
|
e2aeb1028b | ||
|
|
94264320b4 | ||
|
|
b135e89c1e | ||
|
|
c59793618a | ||
|
|
5ecc5b6c19 | ||
|
|
2d7bd9f4cb | ||
|
|
0fd866d201 | ||
|
|
82950f1141 | ||
|
|
4a343a1f23 | ||
|
|
a569214273 | ||
|
|
942b74c8bd | ||
|
|
d107a844ea | ||
|
|
301957515a | ||
|
|
d04319a438 | ||
|
|
d5ec258080 | ||
|
|
9e445bdb91 | ||
|
|
fa3a6fa597 | ||
|
|
81df5843f3 | ||
|
|
f3a5187775 | ||
|
|
2801553d61 | ||
|
|
001f0fb620 | ||
|
|
665e37784a | ||
|
|
ecb81ef2c3 | ||
|
|
d0cd6bb0a4 | ||
|
|
fd08f0dbe7 | ||
|
|
2dd09ae274 | ||
|
|
679fb2ba33 | ||
|
|
4fcd05db72 | ||
|
|
d7764b4322 | ||
|
|
893b9b4f82 | ||
|
|
b918bd4c25 | ||
|
|
3b1144f1e0 | ||
|
|
6c0a46bcc8 | ||
|
|
3cddb4edab | ||
|
|
d5f3d35fbe | ||
|
|
bf752c75f5 | ||
|
|
01f6ebdd3d | ||
|
|
7bf52dd8a6 | ||
|
|
1b28f389c2 | ||
|
|
e8cbfe6a1b | ||
|
|
0c01a43a4f | ||
|
|
133088e9a3 | ||
|
|
3d42c9a5df | ||
|
|
5c4f809f2a | ||
|
|
f7a301441a | ||
|
|
00f2d563be | ||
|
|
64ee7d6822 | ||
|
|
0750dc418a | ||
|
|
0d6d9e6778 | ||
|
|
86c079de31 | ||
|
|
fb8519070c | ||
|
|
e1095adeee | ||
|
|
4ecb3dd090 | ||
|
|
0034929eef | ||
|
|
dbb717cd6e | ||
|
|
e9e398d2d4 | ||
|
|
7d8b2690ff | ||
|
|
55d2f67b90 | ||
|
|
39bfb30eb0 | ||
|
|
1c61751540 | ||
|
|
0251f70fe8 | ||
|
|
07b6ea0ff4 | ||
|
|
56f68f9c44 | ||
|
|
18fcd9138b | ||
|
|
f245b4cc81 | ||
|
|
d488535f36 | ||
|
|
72443ff295 | ||
|
|
a3383c309a | ||
|
|
5dad229662 | ||
|
|
2e4c97ac56 | ||
|
|
0659d829ce | ||
|
|
1fc2d58799 | ||
|
|
c15eb1eaac | ||
|
|
d051b8aa20 | ||
|
|
6806cdf825 | ||
|
|
79c2dd8e8b | ||
|
|
fba080cf34 | ||
|
|
bff6916e8f | ||
|
|
b8df9347a1 | ||
|
|
ec70642c55 | ||
|
|
14aba06922 | ||
|
|
1c2bd84725 | ||
|
|
c4a68b4199 | ||
|
|
085f161230 | ||
|
|
893679e44f | ||
|
|
a62287bf8d | ||
|
|
98ab933a73 | ||
|
|
a9c6521466 | ||
|
|
41fedb7beb | ||
|
|
98fc7fecc2 | ||
|
|
f9f90e0226 | ||
|
|
61fcc766f8 | ||
|
|
091a8bcf86 | ||
|
|
6af478d0ba | ||
|
|
06a4ee01d4 | ||
|
|
7b94f288e5 | ||
|
|
7226725d2f | ||
|
|
1037822a63 | ||
|
|
95adde2a19 |
13
.github/workflows/mirror-rolling-to-master.yaml
vendored
Normal file
13
.github/workflows/mirror-rolling-to-master.yaml
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
name: Mirror rolling to master
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ rolling ]
|
||||
|
||||
jobs:
|
||||
mirror-to-master:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: zofrex/mirror-branch@v1
|
||||
with:
|
||||
target-branch: master
|
||||
2
CODEOWNERS
Normal file
2
CODEOWNERS
Normal file
@@ -0,0 +1,2 @@
|
||||
# This file was generated by https://github.com/audrow/update-ros2-repos
|
||||
* @ivanpauno @hidmic @wjwwood
|
||||
@@ -8,10 +8,11 @@ rclcpp provides the standard C++ API for interacting with ROS 2.
|
||||
|
||||
`#include "rclcpp/rclcpp.hpp"` allows use of the most common elements of the ROS 2 system.
|
||||
|
||||
Visit the [rclcpp API documentation](http://docs.ros2.org/latest/api/rclcpp/) for a complete list of its main components.
|
||||
The link to the latest API documentation can be found on the rclcpp package info page, at the [ROS Index](https://index.ros.org/p/rclcpp/).
|
||||
|
||||
|
||||
### Examples
|
||||
|
||||
The ROS 2 tutorials [Writing a simple publisher and subscriber](https://index.ros.org/doc/ros2/Tutorials/Writing-A-Simple-Cpp-Publisher-And-Subscriber/)
|
||||
and [Writing a simple service and client](https://index.ros.org/doc/ros2/Tutorials/Writing-A-Simple-Cpp-Service-And-Client/)
|
||||
The ROS 2 tutorials [Writing a simple publisher and subscriber](https://docs.ros.org/en/rolling/Tutorials/Writing-A-Simple-Cpp-Publisher-And-Subscriber.html).
|
||||
and [Writing a simple service and client](https://docs.ros.org/en/rolling/Tutorials/Writing-A-Simple-Cpp-Service-And-Client.html)
|
||||
contain some examples of rclcpp APIs in use.
|
||||
|
||||
@@ -2,6 +2,308 @@
|
||||
Changelog for package rclcpp
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
19.3.0 (2023-03-01)
|
||||
-------------------
|
||||
* Fix memory leak in tracetools::get_symbol() (`#2104 <https://github.com/ros2/rclcpp/issues/2104>`_)
|
||||
* Service introspection (`#1985 <https://github.com/ros2/rclcpp/issues/1985>`_)
|
||||
* Allow publishing borrowed messages with intra-process enabled (`#2108 <https://github.com/ros2/rclcpp/issues/2108>`_)
|
||||
* to fix flaky test about TestTimeSource.callbacks (`#2111 <https://github.com/ros2/rclcpp/issues/2111>`_)
|
||||
* Contributors: Brian, Chen Lihui, Christophe Bedard, Miguel Company
|
||||
|
||||
19.2.0 (2023-02-24)
|
||||
-------------------
|
||||
* to create a sublogger while getting child of Logger (`#1717 <https://github.com/ros2/rclcpp/issues/1717>`_)
|
||||
* Fix documentation of Context class (`#2107 <https://github.com/ros2/rclcpp/issues/2107>`_)
|
||||
* fixes for rmw callbacks in qos_event class (`#2102 <https://github.com/ros2/rclcpp/issues/2102>`_)
|
||||
* Contributors: Alberto Soragna, Chen Lihui, Silvio Traversaro
|
||||
|
||||
19.1.0 (2023-02-14)
|
||||
-------------------
|
||||
* Add support for timers on reset callback (`#1979 <https://github.com/ros2/rclcpp/issues/1979>`_)
|
||||
* Topic node guard condition in executor (`#2074 <https://github.com/ros2/rclcpp/issues/2074>`_)
|
||||
* Fix bug on the disorder of calling shutdown callback (`#2097 <https://github.com/ros2/rclcpp/issues/2097>`_)
|
||||
* Contributors: Barry Xu, Chen Lihui, mauropasse
|
||||
|
||||
19.0.0 (2023-01-30)
|
||||
-------------------
|
||||
* Add default constructor to NodeInterfaces (`#2094 <https://github.com/ros2/rclcpp/issues/2094>`_)
|
||||
* Fix clock state cached time to be a copy, not a reference. (`#2092 <https://github.com/ros2/rclcpp/issues/2092>`_)
|
||||
* Fix -Wmaybe-uninitialized warning (`#2081 <https://github.com/ros2/rclcpp/issues/2081>`_)
|
||||
* Fix the keep_last warning when using system defaults. (`#2082 <https://github.com/ros2/rclcpp/issues/2082>`_)
|
||||
* Add in a fix for older compilers. (`#2075 <https://github.com/ros2/rclcpp/issues/2075>`_)
|
||||
* Contributors: Alexander Hans, Chris Lalancette, Shane Loretz
|
||||
|
||||
18.0.0 (2022-12-29)
|
||||
-------------------
|
||||
* Implement Unified Node Interface (NodeInterfaces class) (`#2041 <https://github.com/ros2/rclcpp/issues/2041>`_)
|
||||
* Do not throw exception if trying to dequeue an empty intra-process buffer (`#2061 <https://github.com/ros2/rclcpp/issues/2061>`_)
|
||||
* Move event callback binding to PublisherBase and SubscriptionBase (`#2066 <https://github.com/ros2/rclcpp/issues/2066>`_)
|
||||
* Implement validity checks for rclcpp::Clock (`#2040 <https://github.com/ros2/rclcpp/issues/2040>`_)
|
||||
* Explicitly set callback type (`#2059 <https://github.com/ros2/rclcpp/issues/2059>`_)
|
||||
* Fix logging macros to build with msvc and cpp20 (`#2063 <https://github.com/ros2/rclcpp/issues/2063>`_)
|
||||
* Add clock type to node_options (`#1982 <https://github.com/ros2/rclcpp/issues/1982>`_)
|
||||
* Fix nullptr dereference in prune_requests_older_than (`#2008 <https://github.com/ros2/rclcpp/issues/2008>`_)
|
||||
* Remove templating on to_rcl_subscription_options (`#2056 <https://github.com/ros2/rclcpp/issues/2056>`_)
|
||||
* Fix SharedFuture from async_send_request never becoming valid (`#2044 <https://github.com/ros2/rclcpp/issues/2044>`_)
|
||||
* Add in a warning for a KeepLast depth of 0. (`#2048 <https://github.com/ros2/rclcpp/issues/2048>`_)
|
||||
* Mark rclcpp::Clock::now() as const (`#2050 <https://github.com/ros2/rclcpp/issues/2050>`_)
|
||||
* Fix a case that did not throw ParameterUninitializedException (`#2036 <https://github.com/ros2/rclcpp/issues/2036>`_)
|
||||
* Update maintainers (`#2043 <https://github.com/ros2/rclcpp/issues/2043>`_)
|
||||
* Contributors: Alberto Soragna, Audrow Nash, Chen Lihui, Chris Lalancette, Jeffery Hsu, Lei Liu, Mateusz Szczygielski, Shane Loretz, andrei, mauropasse, methylDragon
|
||||
|
||||
17.1.0 (2022-11-02)
|
||||
-------------------
|
||||
* MultiThreadExecutor number of threads is at least 2+ in default. (`#2032 <https://github.com/ros2/rclcpp/issues/2032>`_)
|
||||
* Fix bug that a callback not reached (`#1640 <https://github.com/ros2/rclcpp/issues/1640>`_)
|
||||
* Set the minimum number of threads of the Multithreaded executor to 2 (`#2030 <https://github.com/ros2/rclcpp/issues/2030>`_)
|
||||
* check thread whether joinable before join (`#2019 <https://github.com/ros2/rclcpp/issues/2019>`_)
|
||||
* Set cpplint test timeout to 3 minutes (`#2022 <https://github.com/ros2/rclcpp/issues/2022>`_)
|
||||
* Make sure to include-what-you-use in the node_interfaces. (`#2018 <https://github.com/ros2/rclcpp/issues/2018>`_)
|
||||
* Do not clear entities callbacks on destruction (`#2002 <https://github.com/ros2/rclcpp/issues/2002>`_)
|
||||
* fix mismatched issue if using zero_allocate (`#1995 <https://github.com/ros2/rclcpp/issues/1995>`_)
|
||||
* Contributors: Alexis Paques, Chen Lihui, Chris Lalancette, Cristóbal Arroyo, Tomoya Fujita, mauropasse, uupks
|
||||
|
||||
17.0.0 (2022-09-13)
|
||||
-------------------
|
||||
* Make ParameterService and Sync/AsyncParameterClient accept rclcpp::QoS (`#1978 <https://github.com/ros2/rclcpp/issues/1978>`_)
|
||||
* support regex match for parameter client (`#1992 <https://github.com/ros2/rclcpp/issues/1992>`_)
|
||||
* operator+= and operator-= for Duration (`#1988 <https://github.com/ros2/rclcpp/issues/1988>`_)
|
||||
* Revert "Revert "Add a create_timer method to Node and `LifecycleNode` classes (`#1975 <https://github.com/ros2/rclcpp/issues/1975>`_)" (`#2009 <https://github.com/ros2/rclcpp/issues/2009>`_) (`#2010 <https://github.com/ros2/rclcpp/issues/2010>`_)
|
||||
* force compiler warning if callback handles not captured (`#2000 <https://github.com/ros2/rclcpp/issues/2000>`_)
|
||||
* Revert "Add a `create_timer` method to `Node` and `LifecycleNode` classes (`#1975 <https://github.com/ros2/rclcpp/issues/1975>`_)" (`#2009 <https://github.com/ros2/rclcpp/issues/2009>`_)
|
||||
* Add a `create_timer` method to `Node` and `LifecycleNode` classes (`#1975 <https://github.com/ros2/rclcpp/issues/1975>`_)
|
||||
* [docs] add note about callback lifetime for {on, post}_set_parameter_callback (`#1981 <https://github.com/ros2/rclcpp/issues/1981>`_)
|
||||
* fix memory leak (`#1994 <https://github.com/ros2/rclcpp/issues/1994>`_)
|
||||
* Support pre-set and post-set parameter callbacks in addition to on-set-parameter-callback. (`#1947 <https://github.com/ros2/rclcpp/issues/1947>`_)
|
||||
* Make create_service accept rclcpp::QoS (`#1969 <https://github.com/ros2/rclcpp/issues/1969>`_)
|
||||
* Make create_client accept rclcpp::QoS (`#1964 <https://github.com/ros2/rclcpp/issues/1964>`_)
|
||||
* Fix the documentation for rclcpp::ok to be accurate. (`#1965 <https://github.com/ros2/rclcpp/issues/1965>`_)
|
||||
* use regex for wildcard matching (`#1839 <https://github.com/ros2/rclcpp/issues/1839>`_)
|
||||
* Revert "Introduce executors new spin_for method, replace spin_until_future_complete with spin_until_complete. (`#1821 <https://github.com/ros2/rclcpp/issues/1821>`_) (`#1874 <https://github.com/ros2/rclcpp/issues/1874>`_)" (`#1956 <https://github.com/ros2/rclcpp/issues/1956>`_)
|
||||
* Introduce executors new spin_for method, replace spin_until_future_complete with spin_until_complete. (`#1821 <https://github.com/ros2/rclcpp/issues/1821>`_) (`#1874 <https://github.com/ros2/rclcpp/issues/1874>`_)
|
||||
* test adjustment for LoanedMessage. (`#1951 <https://github.com/ros2/rclcpp/issues/1951>`_)
|
||||
* fix virtual dispatch issues identified by clang-tidy (`#1816 <https://github.com/ros2/rclcpp/issues/1816>`_)
|
||||
* Remove unused on_parameters_set_callback\_ (`#1945 <https://github.com/ros2/rclcpp/issues/1945>`_)
|
||||
* Fix subscription.is_serialized() for callbacks with message info (`#1950 <https://github.com/ros2/rclcpp/issues/1950>`_)
|
||||
* wait for subscriptions on another thread. (`#1940 <https://github.com/ros2/rclcpp/issues/1940>`_)
|
||||
* Fix documentation of `RCLCPP\_[INFO,WARN,...]` (`#1943 <https://github.com/ros2/rclcpp/issues/1943>`_)
|
||||
* Always trigger guard condition waitset (`#1923 <https://github.com/ros2/rclcpp/issues/1923>`_)
|
||||
* Add statistics for handle_loaned_message (`#1927 <https://github.com/ros2/rclcpp/issues/1927>`_)
|
||||
* Drop wrong template specialization (`#1926 <https://github.com/ros2/rclcpp/issues/1926>`_)
|
||||
* Contributors: Alberto Soragna, Andrew Symington, Barry Xu, Brian, Chen Lihui, Chris Lalancette, Daniel Reuter, Deepanshu Bansal, Hubert Liberacki, Ivan Santiago Paunovic, Jochen Sprickerhof, Nikolai Morin, Shane Loretz, Tomoya Fujita, Tyler Weaver, William Woodall, schrodinbug
|
||||
|
||||
16.2.0 (2022-05-03)
|
||||
-------------------
|
||||
* Update get_parameter_from_event to follow the function description (`#1922 <https://github.com/ros2/rclcpp/issues/1922>`_)
|
||||
* Add 'best available' QoS enum values and methods (`#1920 <https://github.com/ros2/rclcpp/issues/1920>`_)
|
||||
* Contributors: Barry Xu, Jacob Perron
|
||||
|
||||
16.1.0 (2022-04-29)
|
||||
-------------------
|
||||
* use reinterpret_cast for function pointer conversion. (`#1919 <https://github.com/ros2/rclcpp/issues/1919>`_)
|
||||
* Contributors: Tomoya Fujita
|
||||
|
||||
16.0.1 (2022-04-13)
|
||||
-------------------
|
||||
* remove DEFINE_CONTENT_FILTER cmake option (`#1914 <https://github.com/ros2/rclcpp/issues/1914>`_)
|
||||
* Contributors: Chen Lihui
|
||||
|
||||
16.0.0 (2022-04-08)
|
||||
-------------------
|
||||
* remove things that were deprecated during galactic (`#1913 <https://github.com/ros2/rclcpp/issues/1913>`_)
|
||||
* Contributors: William Woodall
|
||||
|
||||
15.4.0 (2022-04-05)
|
||||
-------------------
|
||||
* add take_data_by_entity_id API to waitable (`#1892 <https://github.com/ros2/rclcpp/issues/1892>`_)
|
||||
* add content-filtered-topic interfaces (`#1561 <https://github.com/ros2/rclcpp/issues/1561>`_)
|
||||
* Contributors: Alberto Soragna, Chen Lihui
|
||||
|
||||
15.3.0 (2022-03-30)
|
||||
-------------------
|
||||
* [NodeParameters] Set name in param info pre-check (`#1908 <https://github.com/ros2/rclcpp/issues/1908>`_)
|
||||
* Add test-dep ament_cmake_google_benchmark (`#1904 <https://github.com/ros2/rclcpp/issues/1904>`_)
|
||||
* Add publish by loaned message in GenericPublisher (`#1856 <https://github.com/ros2/rclcpp/issues/1856>`_)
|
||||
* Contributors: Abrar Rahman Protyasha, Barry Xu, Gaël Écorchard
|
||||
|
||||
15.2.0 (2022-03-24)
|
||||
-------------------
|
||||
* Add missing ament dependency on rcl_interfaces (`#1903 <https://github.com/ros2/rclcpp/issues/1903>`_)
|
||||
* Update data callback tests to account for all published samples (`#1900 <https://github.com/ros2/rclcpp/issues/1900>`_)
|
||||
* Increase timeout for acknowledgments to account for slower Connext settings (`#1901 <https://github.com/ros2/rclcpp/issues/1901>`_)
|
||||
* clang-tidy: explicit constructors (`#1782 <https://github.com/ros2/rclcpp/issues/1782>`_)
|
||||
* Add client/service QoS getters (`#1784 <https://github.com/ros2/rclcpp/issues/1784>`_)
|
||||
* Fix a bunch more rosdoc2 issues in rclcpp. (`#1897 <https://github.com/ros2/rclcpp/issues/1897>`_)
|
||||
* time_until_trigger returns max time if timer is cancelled (`#1893 <https://github.com/ros2/rclcpp/issues/1893>`_)
|
||||
* Micro-optimizations in rclcpp (`#1896 <https://github.com/ros2/rclcpp/issues/1896>`_)
|
||||
* Contributors: Andrea Sorbini, Chris Lalancette, Mauro Passerino, Scott K Logan, William Woodall
|
||||
|
||||
15.1.0 (2022-03-01)
|
||||
-------------------
|
||||
* spin_all with a zero timeout. (`#1878 <https://github.com/ros2/rclcpp/issues/1878>`_)
|
||||
* Add RMW listener APIs (`#1579 <https://github.com/ros2/rclcpp/issues/1579>`_)
|
||||
* Remove fastrtps customization on tests (`#1887 <https://github.com/ros2/rclcpp/issues/1887>`_)
|
||||
* Install headers to include/${PROJECT_NAME} (`#1888 <https://github.com/ros2/rclcpp/issues/1888>`_)
|
||||
* Use ament_generate_version_header (`#1886 <https://github.com/ros2/rclcpp/issues/1886>`_)
|
||||
* use universal reference to support rvalue. (`#1883 <https://github.com/ros2/rclcpp/issues/1883>`_)
|
||||
* fix one subscription can wait_for_message twice (`#1870 <https://github.com/ros2/rclcpp/issues/1870>`_)
|
||||
* Add return value version of get_parameter_or (`#1813 <https://github.com/ros2/rclcpp/issues/1813>`_)
|
||||
* Cleanup time source object lifetimes (`#1867 <https://github.com/ros2/rclcpp/issues/1867>`_)
|
||||
* add is_spinning() method to executor base class
|
||||
* Contributors: Alberto Soragna, Chen Lihui, Chris Lalancette, Kenji Miyake, Miguel Company, Shane Loretz, Tomoya Fujita, iRobot ROS
|
||||
|
||||
15.0.0 (2022-01-14)
|
||||
-------------------
|
||||
* Cleanup the TypeAdapt tests (`#1858 <https://github.com/ros2/rclcpp/issues/1858>`_)
|
||||
* Cleanup includes (`#1857 <https://github.com/ros2/rclcpp/issues/1857>`_)
|
||||
* Fix include order and relative paths for cpplint (`#1859 <https://github.com/ros2/rclcpp/issues/1859>`_)
|
||||
* Rename stringstream in macros to a more unique name (`#1862 <https://github.com/ros2/rclcpp/issues/1862>`_)
|
||||
* Add non transform capabilities for intra-process (`#1849 <https://github.com/ros2/rclcpp/issues/1849>`_)
|
||||
* Fix rclcpp documentation build (`#1779 <https://github.com/ros2/rclcpp/issues/1779>`_)
|
||||
* Contributors: Chris Lalancette, Doug Smith, Gonzo, Jacob Perron, Michel Hidalgo
|
||||
|
||||
14.1.0 (2022-01-05)
|
||||
-------------------
|
||||
* Use UninitializedStaticallyTypedParameterException (`#1689 <https://github.com/ros2/rclcpp/issues/1689>`_)
|
||||
* Add wait_for_all_acked support (`#1662 <https://github.com/ros2/rclcpp/issues/1662>`_)
|
||||
* Add tests for function templates of declare_parameter (`#1747 <https://github.com/ros2/rclcpp/issues/1747>`_)
|
||||
* Contributors: Barry Xu, Bi0T1N, M. Mostafa Farzan
|
||||
|
||||
14.0.0 (2021-12-17)
|
||||
-------------------
|
||||
* Fixes for uncrustify 0.72 (`#1844 <https://github.com/ros2/rclcpp/issues/1844>`_)
|
||||
* use private member to keep the all reference underneath. (`#1845 <https://github.com/ros2/rclcpp/issues/1845>`_)
|
||||
* Make node base sharable (`#1832 <https://github.com/ros2/rclcpp/issues/1832>`_)
|
||||
* Add Clock::sleep_for() (`#1828 <https://github.com/ros2/rclcpp/issues/1828>`_)
|
||||
* Synchronize rcl and std::chrono steady clocks in Clock::sleep_until (`#1830 <https://github.com/ros2/rclcpp/issues/1830>`_)
|
||||
* Use rclcpp::guard_condition (`#1612 <https://github.com/ros2/rclcpp/issues/1612>`_)
|
||||
* Call CMake function to generate version header (`#1805 <https://github.com/ros2/rclcpp/issues/1805>`_)
|
||||
* Use parantheses around logging macro parameter (`#1820 <https://github.com/ros2/rclcpp/issues/1820>`_)
|
||||
* Remove author by request (`#1818 <https://github.com/ros2/rclcpp/issues/1818>`_)
|
||||
* Update maintainers (`#1817 <https://github.com/ros2/rclcpp/issues/1817>`_)
|
||||
* min_forward & min_backward thresholds must not be disabled (`#1815 <https://github.com/ros2/rclcpp/issues/1815>`_)
|
||||
* Re-add Clock::sleep_until (`#1814 <https://github.com/ros2/rclcpp/issues/1814>`_)
|
||||
* Fix lifetime of context so it remains alive while its dependent node handles are still in use (`#1754 <https://github.com/ros2/rclcpp/issues/1754>`_)
|
||||
* Add the interface for pre-shutdown callback (`#1714 <https://github.com/ros2/rclcpp/issues/1714>`_)
|
||||
* Take message ownership from moved LoanedMessage (`#1808 <https://github.com/ros2/rclcpp/issues/1808>`_)
|
||||
* Suppress clang dead-store warnings in the benchmarks. (`#1802 <https://github.com/ros2/rclcpp/issues/1802>`_)
|
||||
* Wait for publisher and subscription to match (`#1777 <https://github.com/ros2/rclcpp/issues/1777>`_)
|
||||
* Fix unused QoS profile for clock subscription and make ClockQoS the default (`#1801 <https://github.com/ros2/rclcpp/issues/1801>`_)
|
||||
* Contributors: Abrar Rahman Protyasha, Barry Xu, Chen Lihui, Chris Lalancette, Grey, Jacob Perron, Nikolai Morin, Shane Loretz, Tomoya Fujita, mauropasse
|
||||
|
||||
13.1.0 (2021-10-18)
|
||||
-------------------
|
||||
* Fix dangerous std::bind capture in TimeSource implementation. (`#1768 <https://github.com/ros2/rclcpp/issues/1768>`_)
|
||||
* Fix dangerous std::bind capture in ParameterEventHandler implementation. (`#1770 <https://github.com/ros2/rclcpp/issues/1770>`_)
|
||||
* Handle sigterm, in the same way sigint is being handled. (`#1771 <https://github.com/ros2/rclcpp/issues/1771>`_)
|
||||
* rclcpp::Node copy constructor: make copy of node_waitables\_ member. (`#1799 <https://github.com/ros2/rclcpp/issues/1799>`_)
|
||||
* Extend NodeGraph to match what rcl provides. (`#1484 <https://github.com/ros2/rclcpp/issues/1484>`_)
|
||||
* Context::sleep_for(): replace recursion with do-while to avoid potential stack-overflow. (`#1765 <https://github.com/ros2/rclcpp/issues/1765>`_)
|
||||
* extend_sub_namespace(): Verify string::empty() before calling string::front(). (`#1764 <https://github.com/ros2/rclcpp/issues/1764>`_)
|
||||
* Deprecate the `void shared_ptr<MessageT>` subscription callback signatures. (`#1713 <https://github.com/ros2/rclcpp/issues/1713>`_)
|
||||
* Contributors: Abrar Rahman Protyasha, Chris Lalancette, Emerson Knapp, Geoffrey Biggs, Ivan Santiago Paunovic, Jorge Perez, Tomoya Fujita, William Woodall, Yong-Hao Zou, livanov93
|
||||
|
||||
13.0.0 (2021-08-23)
|
||||
-------------------
|
||||
* Remove can_be_nullptr assignment check for QNX case. (`#1752 <https://github.com/ros2/rclcpp/issues/1752>`_)
|
||||
* Update client API to be able to remove pending requests. (`#1734 <https://github.com/ros2/rclcpp/issues/1734>`_)
|
||||
* Fix: Allow to add a node while spinning in the StaticSingleThreadedExecutor. (`#1690 <https://github.com/ros2/rclcpp/issues/1690>`_)
|
||||
* Add tracing instrumentation for executor and message taking. (`#1738 <https://github.com/ros2/rclcpp/issues/1738>`_)
|
||||
* Fix: Reset timer trigger time before execute in StaticSingleThreadedExecutor. (`#1739 <https://github.com/ros2/rclcpp/issues/1739>`_)
|
||||
* Use FindPython3 and make python3 dependency explicit. (`#1745 <https://github.com/ros2/rclcpp/issues/1745>`_)
|
||||
* Use rosidl_get_typesupport_target(). (`#1729 <https://github.com/ros2/rclcpp/issues/1729>`_)
|
||||
* Fix returning invalid namespace if sub_namespace is empty. (`#1658 <https://github.com/ros2/rclcpp/issues/1658>`_)
|
||||
* Add free function to wait for a subscription message. (`#1705 <https://github.com/ros2/rclcpp/issues/1705>`_)
|
||||
* Use rcpputils/scope_exit.hpp and remove rclcpp/scope_exit.hpp. (`#1727 <https://github.com/ros2/rclcpp/issues/1727>`_)
|
||||
* Contributors: Ahmed Sobhy, Christophe Bedard, Ivan Santiago Paunovic, Karsten Knese, M. Hofstätter, Mauro Passerino, Shane Loretz, mauropasse
|
||||
|
||||
12.0.0 (2021-07-26)
|
||||
-------------------
|
||||
* Remove unsafe get_callback_groups API.
|
||||
Callers should change to using for_each_callback_group(), or
|
||||
store the callback groups they need internally.
|
||||
* Add in callback_groups_for_each.
|
||||
The main reason to add this method in is to make accesses to the
|
||||
callback_groups\_ vector thread-safe. By having a
|
||||
callback_groups_for_each that accepts a std::function, we can
|
||||
just have the callers give us the callback they are interested
|
||||
in, and we can take care of the locking.
|
||||
The rest of this fairly large PR is cleaning up all of the places
|
||||
that use get_callback_groups() to instead use
|
||||
callback_groups_for_each().
|
||||
* Use a different mechanism to avoid timers being scheduled multiple times by the MultiThreadedExecutor (`#1692 <https://github.com/ros2/rclcpp/issues/1692>`_)
|
||||
* Fix windows CI (`#1726 <https://github.com/ros2/rclcpp/issues/1726>`_)
|
||||
Fix bug in AnyServiceCallback introduced in `#1709 <https://github.com/ros2/rclcpp/issues/1709>`_.
|
||||
* Contributors: Chris Lalancette, Ivan Santiago Paunovic
|
||||
|
||||
11.2.0 (2021-07-21)
|
||||
-------------------
|
||||
* Support to defer to send a response in services. (`#1709 <https://github.com/ros2/rclcpp/issues/1709>`_)
|
||||
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
|
||||
* Fix documentation bug. (`#1719 <https://github.com/ros2/rclcpp/issues/1719>`_)
|
||||
Signed-off-by: William Woodall <william@osrfoundation.org>
|
||||
* Contributors: Ivan Santiago Paunovic, William Woodall
|
||||
|
||||
11.1.0 (2021-07-13)
|
||||
-------------------
|
||||
* Removed left over ``is_initialized()`` implementation (`#1711 <https://github.com/ros2/rclcpp/issues/1711>`_)
|
||||
Leftover from https://github.com/ros2/rclcpp/pull/1622
|
||||
* Fixed declare parameter methods for int and float vectors (`#1696 <https://github.com/ros2/rclcpp/issues/1696>`_)
|
||||
* Cleaned up implementation of the intra-process manager (`#1695 <https://github.com/ros2/rclcpp/issues/1695>`_)
|
||||
* Added the node name to an executor ``runtime_error`` (`#1686 <https://github.com/ros2/rclcpp/issues/1686>`_)
|
||||
* Fixed a typo "Attack" -> "Attach" (`#1687 <https://github.com/ros2/rclcpp/issues/1687>`_)
|
||||
* Removed use of std::allocator<>::rebind (`#1678 <https://github.com/ros2/rclcpp/issues/1678>`_)
|
||||
rebind is deprecated in c++17 and removed in c++20
|
||||
* Contributors: Alberto Soragna, Chen Lihui, Chris Lalancette, Petter Nilsson, Steve Macenski, William Woodall
|
||||
|
||||
11.0.0 (2021-05-18)
|
||||
-------------------
|
||||
* Allow declare uninitialized parameters (`#1673 <https://github.com/ros2/rclcpp/issues/1673>`_)
|
||||
* Fix syntax issue with gcc (`#1674 <https://github.com/ros2/rclcpp/issues/1674>`_)
|
||||
* [service] Don't use a weak_ptr to avoid leaking (`#1668 <https://github.com/ros2/rclcpp/issues/1668>`_)
|
||||
* Contributors: Ivan Santiago Paunovic, Jacob Perron, William Woodall
|
||||
|
||||
10.0.0 (2021-05-11)
|
||||
-------------------
|
||||
* Fix doc typo (`#1663 <https://github.com/ros2/rclcpp/issues/1663>`_)
|
||||
* [rclcpp] Type Adaptation feature (`#1557 <https://github.com/ros2/rclcpp/issues/1557>`_)
|
||||
* Do not attempt to use void allocators for memory allocation. (`#1657 <https://github.com/ros2/rclcpp/issues/1657>`_)
|
||||
* Keep custom allocator in publisher and subscription options alive. (`#1647 <https://github.com/ros2/rclcpp/issues/1647>`_)
|
||||
* Fix get_publishers_subscriptions_info_by_topic test in test_node.cpp (`#1648 <https://github.com/ros2/rclcpp/issues/1648>`_)
|
||||
* Use OnShutdown callback handle instead of OnShutdown callback (`#1639 <https://github.com/ros2/rclcpp/issues/1639>`_)
|
||||
* use dynamic_pointer_cast to detect allocator mismatch in intra process manager (`#1643 <https://github.com/ros2/rclcpp/issues/1643>`_)
|
||||
* Increase cppcheck timeout to 500s (`#1634 <https://github.com/ros2/rclcpp/issues/1634>`_)
|
||||
* Clarify node parameters docs (`#1631 <https://github.com/ros2/rclcpp/issues/1631>`_)
|
||||
* Contributors: Audrow Nash, Barry Xu, Jacob Perron, Michel Hidalgo, Shane Loretz, William Woodall
|
||||
|
||||
9.0.2 (2021-04-14)
|
||||
------------------
|
||||
* Avoid returning loan when none was obtained. (`#1629 <https://github.com/ros2/rclcpp/issues/1629>`_)
|
||||
* Use a different implementation of mutex two priorities (`#1628 <https://github.com/ros2/rclcpp/issues/1628>`_)
|
||||
* Do not test the value of the history policy when testing the get_publishers/subscriptions_info_by_topic() methods (`#1626 <https://github.com/ros2/rclcpp/issues/1626>`_)
|
||||
* Check first parameter type and range before calling the user validation callbacks (`#1627 <https://github.com/ros2/rclcpp/issues/1627>`_)
|
||||
* Contributors: Ivan Santiago Paunovic, Miguel Company
|
||||
|
||||
9.0.1 (2021-04-12)
|
||||
------------------
|
||||
* Restore test exception for Connext (`#1625 <https://github.com/ros2/rclcpp/issues/1625>`_)
|
||||
* Fix race condition in TimeSource clock thread setup (`#1623 <https://github.com/ros2/rclcpp/issues/1623>`_)
|
||||
* Contributors: Andrea Sorbini, Michel Hidalgo
|
||||
|
||||
9.0.0 (2021-04-06)
|
||||
------------------
|
||||
* remove deprecated code which was deprecated in foxy and should be removed in galactic (`#1622 <https://github.com/ros2/rclcpp/issues/1622>`_)
|
||||
* Change index.ros.org -> docs.ros.org. (`#1620 <https://github.com/ros2/rclcpp/issues/1620>`_)
|
||||
* Unique network flows (`#1496 <https://github.com/ros2/rclcpp/issues/1496>`_)
|
||||
* Add spin_some support to the StaticSingleThreadedExecutor (`#1338 <https://github.com/ros2/rclcpp/issues/1338>`_)
|
||||
* Add publishing instrumentation (`#1600 <https://github.com/ros2/rclcpp/issues/1600>`_)
|
||||
* Create load_parameters and delete_parameters methods (`#1596 <https://github.com/ros2/rclcpp/issues/1596>`_)
|
||||
* refactor AnySubscriptionCallback and add/deprecate callback signatures (`#1598 <https://github.com/ros2/rclcpp/issues/1598>`_)
|
||||
* Add generic publisher and generic subscription for serialized messages (`#1452 <https://github.com/ros2/rclcpp/issues/1452>`_)
|
||||
* use context from `node_base\_` for clock executor. (`#1617 <https://github.com/ros2/rclcpp/issues/1617>`_)
|
||||
* updating quality declaration links (re: `ros2/docs.ros2.org#52 <https://github.com/ros2/docs.ros2.org/issues/52>`_) (`#1615 <https://github.com/ros2/rclcpp/issues/1615>`_)
|
||||
* Contributors: Ananya Muddukrishna, BriceRenaudeau, Chris Lalancette, Christophe Bedard, Nikolai Morin, Tomoya Fujita, William Woodall, mauropasse, shonigmann
|
||||
|
||||
8.2.0 (2021-03-31)
|
||||
------------------
|
||||
* Initialize integers in test_parameter_event_handler.cpp to avoid undefined behavior (`#1609 <https://github.com/ros2/rclcpp/issues/1609>`_)
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
cmake_minimum_required(VERSION 3.12)
|
||||
|
||||
project(rclcpp)
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
find_package(ament_cmake_ros REQUIRED)
|
||||
find_package(ament_index_cpp REQUIRED)
|
||||
find_package(builtin_interfaces REQUIRED)
|
||||
find_package(libstatistics_collector REQUIRED)
|
||||
find_package(rcl REQUIRED)
|
||||
@@ -20,9 +21,11 @@ find_package(rosidl_typesupport_cpp REQUIRED)
|
||||
find_package(statistics_msgs REQUIRED)
|
||||
find_package(tracetools REQUIRED)
|
||||
|
||||
# Default to C++14
|
||||
# TODO(wjwwood): remove this when gtest can build on its own, when using target_compile_features()
|
||||
# Default to C++17
|
||||
if(NOT CMAKE_CXX_STANDARD)
|
||||
set(CMAKE_CXX_STANDARD 14)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
endif()
|
||||
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
# About -Wno-sign-conversion: With Clang, -Wconversion implies -Wsign-conversion. There are a number of
|
||||
@@ -39,24 +42,31 @@ set(${PROJECT_NAME}_SRCS
|
||||
src/rclcpp/clock.cpp
|
||||
src/rclcpp/context.cpp
|
||||
src/rclcpp/contexts/default_context.cpp
|
||||
src/rclcpp/detail/mutex_two_priorities.cpp
|
||||
src/rclcpp/detail/add_guard_condition_to_rcl_wait_set.cpp
|
||||
src/rclcpp/detail/resolve_parameter_overrides.cpp
|
||||
src/rclcpp/detail/rmw_implementation_specific_payload.cpp
|
||||
src/rclcpp/detail/rmw_implementation_specific_publisher_payload.cpp
|
||||
src/rclcpp/detail/rmw_implementation_specific_subscription_payload.cpp
|
||||
src/rclcpp/detail/utilities.cpp
|
||||
src/rclcpp/duration.cpp
|
||||
src/rclcpp/dynamic_typesupport/dynamic_message.cpp
|
||||
src/rclcpp/dynamic_typesupport/dynamic_message_type.cpp
|
||||
src/rclcpp/dynamic_typesupport/dynamic_message_type_builder.cpp
|
||||
src/rclcpp/dynamic_typesupport/dynamic_message_type_support.cpp
|
||||
src/rclcpp/dynamic_typesupport/dynamic_serialization_support.cpp
|
||||
src/rclcpp/event.cpp
|
||||
src/rclcpp/exceptions/exceptions.cpp
|
||||
src/rclcpp/executable_list.cpp
|
||||
src/rclcpp/executor.cpp
|
||||
src/rclcpp/executors.cpp
|
||||
src/rclcpp/expand_topic_or_service_name.cpp
|
||||
src/rclcpp/executors/multi_threaded_executor.cpp
|
||||
src/rclcpp/executors/single_threaded_executor.cpp
|
||||
src/rclcpp/executors/static_executor_entities_collector.cpp
|
||||
src/rclcpp/executors/static_single_threaded_executor.cpp
|
||||
src/rclcpp/expand_topic_or_service_name.cpp
|
||||
src/rclcpp/future_return_code.cpp
|
||||
src/rclcpp/generic_publisher.cpp
|
||||
src/rclcpp/generic_subscription.cpp
|
||||
src/rclcpp/graph_listener.cpp
|
||||
src/rclcpp/guard_condition.cpp
|
||||
src/rclcpp/init_options.cpp
|
||||
@@ -66,8 +76,8 @@ set(${PROJECT_NAME}_SRCS
|
||||
src/rclcpp/memory_strategies.cpp
|
||||
src/rclcpp/memory_strategy.cpp
|
||||
src/rclcpp/message_info.cpp
|
||||
src/rclcpp/network_flow_endpoint.cpp
|
||||
src/rclcpp/node.cpp
|
||||
src/rclcpp/node_options.cpp
|
||||
src/rclcpp/node_interfaces/node_base.cpp
|
||||
src/rclcpp/node_interfaces/node_clock.cpp
|
||||
src/rclcpp/node_interfaces/node_graph.cpp
|
||||
@@ -78,17 +88,19 @@ set(${PROJECT_NAME}_SRCS
|
||||
src/rclcpp/node_interfaces/node_timers.cpp
|
||||
src/rclcpp/node_interfaces/node_topics.cpp
|
||||
src/rclcpp/node_interfaces/node_waitables.cpp
|
||||
src/rclcpp/node_options.cpp
|
||||
src/rclcpp/parameter.cpp
|
||||
src/rclcpp/parameter_value.cpp
|
||||
src/rclcpp/parameter_client.cpp
|
||||
src/rclcpp/parameter_event_handler.cpp
|
||||
src/rclcpp/parameter_events_filter.cpp
|
||||
src/rclcpp/parameter_map.cpp
|
||||
src/rclcpp/parameter_service.cpp
|
||||
src/rclcpp/parameter_value.cpp
|
||||
src/rclcpp/publisher_base.cpp
|
||||
src/rclcpp/qos.cpp
|
||||
src/rclcpp/qos_event.cpp
|
||||
src/rclcpp/event_handler.cpp
|
||||
src/rclcpp/qos_overriding_options.cpp
|
||||
src/rclcpp/dynamic_subscription.cpp
|
||||
src/rclcpp/serialization.cpp
|
||||
src/rclcpp/serialized_message.cpp
|
||||
src/rclcpp/service.cpp
|
||||
@@ -99,11 +111,14 @@ set(${PROJECT_NAME}_SRCS
|
||||
src/rclcpp/time_source.cpp
|
||||
src/rclcpp/timer.cpp
|
||||
src/rclcpp/type_support.cpp
|
||||
src/rclcpp/typesupport_helpers.cpp
|
||||
src/rclcpp/utilities.cpp
|
||||
src/rclcpp/wait_set_policies/detail/write_preferring_read_write_lock.cpp
|
||||
src/rclcpp/waitable.cpp
|
||||
)
|
||||
|
||||
find_package(Python3 REQUIRED COMPONENTS Interpreter)
|
||||
|
||||
# "watch" template for changes
|
||||
configure_file(
|
||||
"resource/logging.hpp.em"
|
||||
@@ -117,7 +132,7 @@ set(python_code_logging
|
||||
string(REPLACE ";" "$<SEMICOLON>" python_code_logging "${python_code_logging}")
|
||||
add_custom_command(OUTPUT include/rclcpp/logging.hpp
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory "include/rclcpp"
|
||||
COMMAND ${PYTHON_EXECUTABLE} ARGS -c "${python_code_logging}"
|
||||
COMMAND Python3::Interpreter ARGS -c "${python_code_logging}"
|
||||
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/logging.hpp.em.watch"
|
||||
COMMENT "Expanding logging.hpp.em"
|
||||
VERBATIM
|
||||
@@ -141,7 +156,7 @@ foreach(interface_file ${interface_files})
|
||||
string(REPLACE ";" "$<SEMICOLON>" python_${interface_name}_traits "${python_${interface_name}_traits}")
|
||||
add_custom_command(OUTPUT include/rclcpp/node_interfaces/${interface_name}_traits.hpp
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory "include/rclcpp/node_interfaces"
|
||||
COMMAND ${PYTHON_EXECUTABLE} ARGS -c "${python_${interface_name}_traits}"
|
||||
COMMAND Python3::Interpreter ARGS -c "${python_${interface_name}_traits}"
|
||||
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${interface_name}_traits.hpp.em.watch"
|
||||
COMMENT "Expanding interface_traits.hpp.em into ${interface_name}_traits.hpp"
|
||||
VERBATIM
|
||||
@@ -161,7 +176,7 @@ foreach(interface_file ${interface_files})
|
||||
string(REPLACE ";" "$<SEMICOLON>" python_get_${interface_name} "${python_get_${interface_name}}")
|
||||
add_custom_command(OUTPUT include/rclcpp/node_interfaces/get_${interface_name}.hpp
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory "include/rclcpp/node_interfaces"
|
||||
COMMAND ${PYTHON_EXECUTABLE} ARGS -c "${python_get_${interface_name}}"
|
||||
COMMAND Python3::Interpreter ARGS -c "${python_get_${interface_name}}"
|
||||
DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/get_${interface_name}.hpp.em.watch"
|
||||
COMMENT "Expanding get_interface.hpp.em into get_${interface_file}.hpp"
|
||||
VERBATIM
|
||||
@@ -170,17 +185,23 @@ foreach(interface_file ${interface_files})
|
||||
include/rclcpp/node_interfaces/get_${interface_name}.hpp)
|
||||
endforeach()
|
||||
|
||||
add_library(${PROJECT_NAME}
|
||||
${${PROJECT_NAME}_SRCS})
|
||||
add_library(${PROJECT_NAME} ${${PROJECT_NAME}_SRCS})
|
||||
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_17)
|
||||
# TODO(wjwwood): address all deprecation warnings and then remove this
|
||||
if(WIN32)
|
||||
target_compile_definitions(${PROJECT_NAME} PUBLIC "_SILENCE_ALL_CXX17_DEPRECATION_WARNINGS")
|
||||
endif()
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>"
|
||||
"$<INSTALL_INTERFACE:include>")
|
||||
"$<INSTALL_INTERFACE:include/${PROJECT_NAME}>")
|
||||
target_link_libraries(${PROJECT_NAME} ${CMAKE_THREAD_LIBS_INIT})
|
||||
# specific order: dependents before dependencies
|
||||
ament_target_dependencies(${PROJECT_NAME}
|
||||
"ament_index_cpp"
|
||||
"libstatistics_collector"
|
||||
"rcl"
|
||||
"rcl_interfaces"
|
||||
"rcl_yaml_param_parser"
|
||||
"rcpputils"
|
||||
"rcutils"
|
||||
@@ -204,11 +225,15 @@ install(
|
||||
RUNTIME DESTINATION bin
|
||||
)
|
||||
|
||||
# specific order: dependents before dependencies
|
||||
ament_export_include_directories(include)
|
||||
# Export old-style CMake variables
|
||||
ament_export_include_directories("include/${PROJECT_NAME}")
|
||||
ament_export_libraries(${PROJECT_NAME})
|
||||
|
||||
# Export modern CMake targets
|
||||
ament_export_targets(${PROJECT_NAME})
|
||||
|
||||
# specific order: dependents before dependencies
|
||||
ament_export_dependencies(ament_index_cpp)
|
||||
ament_export_dependencies(libstatistics_collector)
|
||||
ament_export_dependencies(rcl)
|
||||
ament_export_dependencies(rcpputils)
|
||||
@@ -233,5 +258,16 @@ ament_package()
|
||||
|
||||
install(
|
||||
DIRECTORY include/ ${CMAKE_CURRENT_BINARY_DIR}/include/
|
||||
DESTINATION include
|
||||
DESTINATION include/${PROJECT_NAME}
|
||||
)
|
||||
|
||||
if(TEST cppcheck)
|
||||
# must set the property after ament_package()
|
||||
set_tests_properties(cppcheck PROPERTIES TIMEOUT 500)
|
||||
endif()
|
||||
|
||||
if(TEST cpplint)
|
||||
set_tests_properties(cpplint PROPERTIES TIMEOUT 180)
|
||||
endif()
|
||||
|
||||
ament_generate_version_header(${PROJECT_NAME})
|
||||
|
||||
@@ -21,13 +21,22 @@ GENERATE_LATEX = NO
|
||||
ENABLE_PREPROCESSING = YES
|
||||
MACRO_EXPANSION = YES
|
||||
EXPAND_ONLY_PREDEF = YES
|
||||
PREDEFINED = RCLCPP_PUBLIC=
|
||||
PREDEFINED += DOXYGEN_ONLY
|
||||
PREDEFINED += RCLCPP_LOCAL=
|
||||
PREDEFINED += RCLCPP_PUBLIC=
|
||||
PREDEFINED += RCLCPP_PUBLIC_TYPE=
|
||||
PREDEFINED += RCUTILS_WARN_UNUSED=
|
||||
PREDEFINED += RCPPUTILS_TSA_GUARDED_BY(x)=
|
||||
PREDEFINED += RCPPUTILS_TSA_PT_GUARDED_BY(x)=
|
||||
PREDEFINED += RCPPUTILS_TSA_REQUIRES(x)=
|
||||
|
||||
DOT_GRAPH_MAX_NODES = 101
|
||||
|
||||
# Tag files that do not exist will produce a warning and cross-project linking will not work.
|
||||
TAGFILES += "../../../../doxygen_tag_files/cppreference-doxygen-web.tag.xml=http://en.cppreference.com/w/"
|
||||
#TAGFILES += "../../../../doxygen_tag_files/cppreference-doxygen-web.tag.xml=http://en.cppreference.com/w/"
|
||||
# Consider changing "latest" to the version you want to reference (e.g. beta1 or 1.0.0)
|
||||
TAGFILES += "../../../../doxygen_tag_files/rcl.tag=http://docs.ros2.org/latest/api/rcl/"
|
||||
TAGFILES += "../../../../doxygen_tag_files/rmw.tag=http://docs.ros2.org/latest/api/rmw/"
|
||||
TAGFILES += "../../../../doxygen_tag_files/rcutils.tag=http://docs.ros2.org/latest/api/rcutils/"
|
||||
#TAGFILES += "../../../../doxygen_tag_files/rcl.tag=http://docs.ros2.org/latest/api/rcl/"
|
||||
#TAGFILES += "../../../../doxygen_tag_files/rmw.tag=http://docs.ros2.org/latest/api/rmw/"
|
||||
#TAGFILES += "../../../../doxygen_tag_files/rcutils.tag=http://docs.ros2.org/latest/api/rcutils/"
|
||||
# Uncomment to generate tag files for cross-project linking.
|
||||
#GENERATE_TAGFILE = "../../../../doxygen_tag_files/rclcpp.tag"
|
||||
|
||||
BIN
rclcpp/doc/param_callback_design.png
Normal file
BIN
rclcpp/doc/param_callback_design.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 164 KiB |
29
rclcpp/doc/proposed_node_parameter_callbacks.md
Normal file
29
rclcpp/doc/proposed_node_parameter_callbacks.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Proposed node parameters callback Design
|
||||
|
||||
## Introduction:
|
||||
|
||||
The original requirement came in **gazebo_ros_pkgs** for setting individual wheel slip parameters based on global wheel slip value [link to original issue](https://github.com/ros-simulation/gazebo_ros_pkgs/pull/1365).
|
||||
|
||||
The main requirement is to set one or more parameters after another parameter is set successfully.
|
||||
|
||||
Additionally, it would be nice if users could be notified locally (via a callback) when parameters have been set successfully (i.e. post validation).
|
||||
|
||||
Related discussion can be found in [#609](https://github.com/ros2/rclcpp/issues/609) [#1789](https://github.com/ros2/rclcpp/pull/1789)
|
||||
|
||||
With the current parameters API, the `add_on_set_parameters_callback` is intended for validation of parameter values before they are set, it should **not** cause any side-effects.
|
||||
|
||||
There is also the `ParameterEventHandler` that publishes changes to node parameters on `/parameter_events` topic for external nodes to see. Though the node could subscribe to the `/parameter_events` topic to be notified of changes to its own parameters, it is less than ideal since there is a delay caused by waiting for an executor to process the callback.
|
||||
|
||||
We propose adding a `PostSetParametersCallbackHandle` for successful parameter set similar to `OnSetParametersCallbackHandle` for parameter validation. Also, we propose adding a `PreSetParametersCallbackHandle` useful for modifying list of parameters being set.
|
||||
|
||||
The validation callback is often abused to trigger side effects in the code, for instance updating class attributes even before a parameter has been set successfully. Instead of relying on the `/parameter_events` topic to be notified of parameter changes, users can register a callback with a new API, `add_post_set_parameters_callback`.
|
||||
|
||||
It is possible to use the proposed `add_post_set_parameters_callback` for setting additional parameters, but this might result in infinite recursion and does not allow those additional parameters to be set atomically with the original parameter(s) changed.
|
||||
To workaround these issues, we propose adding a "pre set" callback type that can be registered with `add_pre_set_parameters_callback`, which will be triggered before the validation callbacks and can be used to modify the parameter list.
|
||||
|
||||

|
||||
|
||||
## Alternatives
|
||||
|
||||
* Users could call `set_parameter` while processing a message from the `/parameter_events` topic, however, there is extra overhead in having to create subscription (as noted earlier).
|
||||
* Users could call `set_parameter` inside the "on set" parameters callback, however it is not well-defined how side-effects should handle cases where parameter validation fails.
|
||||
@@ -15,6 +15,7 @@
|
||||
#ifndef RCLCPP__ALLOCATOR__ALLOCATOR_COMMON_HPP_
|
||||
#define RCLCPP__ALLOCATOR__ALLOCATOR_COMMON_HPP_
|
||||
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
|
||||
#include "rcl/allocator.h"
|
||||
@@ -39,6 +40,22 @@ void * retyped_allocate(size_t size, void * untyped_allocator)
|
||||
return std::allocator_traits<Alloc>::allocate(*typed_allocator, size);
|
||||
}
|
||||
|
||||
template<typename Alloc>
|
||||
void * retyped_zero_allocate(size_t number_of_elem, size_t size_of_elem, void * untyped_allocator)
|
||||
{
|
||||
auto typed_allocator = static_cast<Alloc *>(untyped_allocator);
|
||||
if (!typed_allocator) {
|
||||
throw std::runtime_error("Received incorrect allocator type");
|
||||
}
|
||||
size_t size = number_of_elem * size_of_elem;
|
||||
void * allocated_memory =
|
||||
std::allocator_traits<Alloc>::allocate(*typed_allocator, size);
|
||||
if (allocated_memory) {
|
||||
std::memset(allocated_memory, 0, size);
|
||||
}
|
||||
return allocated_memory;
|
||||
}
|
||||
|
||||
template<typename T, typename Alloc>
|
||||
void retyped_deallocate(void * untyped_pointer, void * untyped_allocator)
|
||||
{
|
||||
@@ -73,6 +90,7 @@ rcl_allocator_t get_rcl_allocator(Alloc & allocator)
|
||||
rcl_allocator_t rcl_allocator = rcl_get_default_allocator();
|
||||
#ifndef _WIN32
|
||||
rcl_allocator.allocate = &retyped_allocate<Alloc>;
|
||||
rcl_allocator.zero_allocate = &retyped_zero_allocate<Alloc>;
|
||||
rcl_allocator.deallocate = &retyped_deallocate<T, Alloc>;
|
||||
rcl_allocator.reallocate = &retyped_reallocate<T, Alloc>;
|
||||
rcl_allocator.state = &allocator;
|
||||
|
||||
@@ -41,7 +41,7 @@ public:
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
AllocatorDeleter(const AllocatorDeleter<T> & a)
|
||||
explicit AllocatorDeleter(const AllocatorDeleter<T> & a)
|
||||
{
|
||||
allocator_ = a.get_allocator();
|
||||
}
|
||||
@@ -95,7 +95,7 @@ void set_allocator_for_deleter(AllocatorDeleter<T> * deleter, Alloc * alloc)
|
||||
template<typename Alloc, typename T>
|
||||
using Deleter = typename std::conditional<
|
||||
std::is_same<typename std::allocator_traits<Alloc>::template rebind_alloc<T>,
|
||||
typename std::allocator<void>::template rebind<T>::other>::value,
|
||||
std::allocator<T>>::value,
|
||||
std::default_delete<T>,
|
||||
AllocatorDeleter<Alloc>
|
||||
>::type;
|
||||
|
||||
@@ -50,12 +50,6 @@ struct AnyExecutable
|
||||
std::shared_ptr<void> data;
|
||||
};
|
||||
|
||||
namespace executor
|
||||
{
|
||||
|
||||
using AnyExecutable [[deprecated("use rclcpp::AnyExecutable instead")]] = AnyExecutable;
|
||||
|
||||
} // namespace executor
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__ANY_EXECUTABLE_HPP_
|
||||
|
||||
@@ -15,10 +15,12 @@
|
||||
#ifndef RCLCPP__ANY_SERVICE_CALLBACK_HPP_
|
||||
#define RCLCPP__ANY_SERVICE_CALLBACK_HPP_
|
||||
|
||||
#include <variant>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "rclcpp/function_traits.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
@@ -29,93 +31,208 @@
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template<typename T, typename = void>
|
||||
struct can_be_nullptr : std::false_type {};
|
||||
|
||||
// Some lambdas define a comparison with nullptr,
|
||||
// but we see a warning that they can never be null when using it.
|
||||
// We also test if `T &` can be assigned to `nullptr` to avoid the issue.
|
||||
template<typename T>
|
||||
#ifdef __QNXNTO__
|
||||
struct can_be_nullptr<T, std::void_t<
|
||||
decltype(std::declval<T>() == nullptr)>>: std::true_type {};
|
||||
#else
|
||||
struct can_be_nullptr<T, std::void_t<
|
||||
decltype(std::declval<T>() == nullptr), decltype(std::declval<T &>() = nullptr)>>
|
||||
: std::true_type {};
|
||||
#endif
|
||||
} // namespace detail
|
||||
|
||||
// Forward declare
|
||||
template<typename ServiceT>
|
||||
class Service;
|
||||
|
||||
template<typename ServiceT>
|
||||
class AnyServiceCallback
|
||||
{
|
||||
private:
|
||||
using SharedPtrCallback = std::function<
|
||||
void (
|
||||
const std::shared_ptr<typename ServiceT::Request>,
|
||||
std::shared_ptr<typename ServiceT::Response>
|
||||
)>;
|
||||
using SharedPtrWithRequestHeaderCallback = std::function<
|
||||
void (
|
||||
const std::shared_ptr<rmw_request_id_t>,
|
||||
const std::shared_ptr<typename ServiceT::Request>,
|
||||
std::shared_ptr<typename ServiceT::Response>
|
||||
)>;
|
||||
|
||||
SharedPtrCallback shared_ptr_callback_;
|
||||
SharedPtrWithRequestHeaderCallback shared_ptr_with_request_header_callback_;
|
||||
|
||||
public:
|
||||
AnyServiceCallback()
|
||||
: shared_ptr_callback_(nullptr), shared_ptr_with_request_header_callback_(nullptr)
|
||||
: callback_(std::monostate{})
|
||||
{}
|
||||
|
||||
AnyServiceCallback(const AnyServiceCallback &) = default;
|
||||
|
||||
template<
|
||||
typename CallbackT,
|
||||
typename std::enable_if<
|
||||
typename std::enable_if_t<!detail::can_be_nullptr<CallbackT>::value, int> = 0>
|
||||
void
|
||||
set(CallbackT && callback)
|
||||
{
|
||||
// Workaround Windows issue with std::bind
|
||||
if constexpr (
|
||||
rclcpp::function_traits::same_arguments<
|
||||
CallbackT,
|
||||
SharedPtrCallback
|
||||
>::value
|
||||
>::type * = nullptr
|
||||
>
|
||||
void set(CallbackT callback)
|
||||
{
|
||||
shared_ptr_callback_ = callback;
|
||||
>::value)
|
||||
{
|
||||
callback_.template emplace<SharedPtrCallback>(callback);
|
||||
} else if constexpr ( // NOLINT, can't satisfy both cpplint and uncrustify
|
||||
rclcpp::function_traits::same_arguments<
|
||||
CallbackT,
|
||||
SharedPtrWithRequestHeaderCallback
|
||||
>::value)
|
||||
{
|
||||
callback_.template emplace<SharedPtrWithRequestHeaderCallback>(callback);
|
||||
} else if constexpr ( // NOLINT
|
||||
rclcpp::function_traits::same_arguments<
|
||||
CallbackT,
|
||||
SharedPtrDeferResponseCallback
|
||||
>::value)
|
||||
{
|
||||
callback_.template emplace<SharedPtrDeferResponseCallback>(callback);
|
||||
} else if constexpr ( // NOLINT
|
||||
rclcpp::function_traits::same_arguments<
|
||||
CallbackT,
|
||||
SharedPtrDeferResponseCallbackWithServiceHandle
|
||||
>::value)
|
||||
{
|
||||
callback_.template emplace<SharedPtrDeferResponseCallbackWithServiceHandle>(callback);
|
||||
} else {
|
||||
// the else clause is not needed, but anyways we should only be doing this instead
|
||||
// of all the above workaround ...
|
||||
callback_ = std::forward<CallbackT>(callback);
|
||||
}
|
||||
}
|
||||
|
||||
template<
|
||||
typename CallbackT,
|
||||
typename std::enable_if<
|
||||
typename std::enable_if_t<detail::can_be_nullptr<CallbackT>::value, int> = 0>
|
||||
void
|
||||
set(CallbackT && callback)
|
||||
{
|
||||
if (!callback) {
|
||||
throw std::invalid_argument("AnyServiceCallback::set(): callback cannot be nullptr");
|
||||
}
|
||||
// Workaround Windows issue with std::bind
|
||||
if constexpr (
|
||||
rclcpp::function_traits::same_arguments<
|
||||
CallbackT,
|
||||
SharedPtrCallback
|
||||
>::value)
|
||||
{
|
||||
callback_.template emplace<SharedPtrCallback>(callback);
|
||||
} else if constexpr ( // NOLINT
|
||||
rclcpp::function_traits::same_arguments<
|
||||
CallbackT,
|
||||
SharedPtrWithRequestHeaderCallback
|
||||
>::value
|
||||
>::type * = nullptr
|
||||
>
|
||||
void set(CallbackT callback)
|
||||
{
|
||||
shared_ptr_with_request_header_callback_ = callback;
|
||||
>::value)
|
||||
{
|
||||
callback_.template emplace<SharedPtrWithRequestHeaderCallback>(callback);
|
||||
} else if constexpr ( // NOLINT
|
||||
rclcpp::function_traits::same_arguments<
|
||||
CallbackT,
|
||||
SharedPtrDeferResponseCallback
|
||||
>::value)
|
||||
{
|
||||
callback_.template emplace<SharedPtrDeferResponseCallback>(callback);
|
||||
} else if constexpr ( // NOLINT
|
||||
rclcpp::function_traits::same_arguments<
|
||||
CallbackT,
|
||||
SharedPtrDeferResponseCallbackWithServiceHandle
|
||||
>::value)
|
||||
{
|
||||
callback_.template emplace<SharedPtrDeferResponseCallbackWithServiceHandle>(callback);
|
||||
} else {
|
||||
// the else clause is not needed, but anyways we should only be doing this instead
|
||||
// of all the above workaround ...
|
||||
callback_ = std::forward<CallbackT>(callback);
|
||||
}
|
||||
}
|
||||
|
||||
void dispatch(
|
||||
std::shared_ptr<rmw_request_id_t> request_header,
|
||||
std::shared_ptr<typename ServiceT::Request> request,
|
||||
std::shared_ptr<typename ServiceT::Response> response)
|
||||
// template<typename Allocator = std::allocator<typename ServiceT::Response>>
|
||||
std::shared_ptr<typename ServiceT::Response>
|
||||
dispatch(
|
||||
const std::shared_ptr<rclcpp::Service<ServiceT>> & service_handle,
|
||||
const std::shared_ptr<rmw_request_id_t> & request_header,
|
||||
std::shared_ptr<typename ServiceT::Request> request)
|
||||
{
|
||||
TRACEPOINT(callback_start, static_cast<const void *>(this), false);
|
||||
if (shared_ptr_callback_ != nullptr) {
|
||||
if (std::holds_alternative<std::monostate>(callback_)) {
|
||||
// TODO(ivanpauno): Remove the set method, and force the users of this class
|
||||
// to pass a callback at construnciton.
|
||||
throw std::runtime_error{"unexpected request without any callback set"};
|
||||
}
|
||||
if (std::holds_alternative<SharedPtrDeferResponseCallback>(callback_)) {
|
||||
const auto & cb = std::get<SharedPtrDeferResponseCallback>(callback_);
|
||||
cb(request_header, std::move(request));
|
||||
return nullptr;
|
||||
}
|
||||
if (std::holds_alternative<SharedPtrDeferResponseCallbackWithServiceHandle>(callback_)) {
|
||||
const auto & cb = std::get<SharedPtrDeferResponseCallbackWithServiceHandle>(callback_);
|
||||
cb(service_handle, request_header, std::move(request));
|
||||
return nullptr;
|
||||
}
|
||||
// auto response = allocate_shared<typename ServiceT::Response, Allocator>();
|
||||
auto response = std::make_shared<typename ServiceT::Response>();
|
||||
if (std::holds_alternative<SharedPtrCallback>(callback_)) {
|
||||
(void)request_header;
|
||||
shared_ptr_callback_(request, response);
|
||||
} else if (shared_ptr_with_request_header_callback_ != nullptr) {
|
||||
shared_ptr_with_request_header_callback_(request_header, request, response);
|
||||
} else {
|
||||
throw std::runtime_error("unexpected request without any callback set");
|
||||
const auto & cb = std::get<SharedPtrCallback>(callback_);
|
||||
cb(std::move(request), response);
|
||||
} else if (std::holds_alternative<SharedPtrWithRequestHeaderCallback>(callback_)) {
|
||||
const auto & cb = std::get<SharedPtrWithRequestHeaderCallback>(callback_);
|
||||
cb(request_header, std::move(request), response);
|
||||
}
|
||||
TRACEPOINT(callback_end, static_cast<const void *>(this));
|
||||
return response;
|
||||
}
|
||||
|
||||
void register_callback_for_tracing()
|
||||
{
|
||||
#ifndef TRACETOOLS_DISABLED
|
||||
if (shared_ptr_callback_) {
|
||||
TRACEPOINT(
|
||||
rclcpp_callback_register,
|
||||
static_cast<const void *>(this),
|
||||
tracetools::get_symbol(shared_ptr_callback_));
|
||||
} else if (shared_ptr_with_request_header_callback_) {
|
||||
TRACEPOINT(
|
||||
rclcpp_callback_register,
|
||||
static_cast<const void *>(this),
|
||||
tracetools::get_symbol(shared_ptr_with_request_header_callback_));
|
||||
}
|
||||
std::visit(
|
||||
[this](auto && arg) {
|
||||
if (TRACEPOINT_ENABLED(rclcpp_callback_register)) {
|
||||
char * symbol = tracetools::get_symbol(arg);
|
||||
DO_TRACEPOINT(
|
||||
rclcpp_callback_register,
|
||||
static_cast<const void *>(this),
|
||||
symbol);
|
||||
std::free(symbol);
|
||||
}
|
||||
}, callback_);
|
||||
#endif // TRACETOOLS_DISABLED
|
||||
}
|
||||
|
||||
private:
|
||||
using SharedPtrCallback = std::function<
|
||||
void (
|
||||
std::shared_ptr<typename ServiceT::Request>,
|
||||
std::shared_ptr<typename ServiceT::Response>
|
||||
)>;
|
||||
using SharedPtrWithRequestHeaderCallback = std::function<
|
||||
void (
|
||||
std::shared_ptr<rmw_request_id_t>,
|
||||
std::shared_ptr<typename ServiceT::Request>,
|
||||
std::shared_ptr<typename ServiceT::Response>
|
||||
)>;
|
||||
using SharedPtrDeferResponseCallback = std::function<
|
||||
void (
|
||||
std::shared_ptr<rmw_request_id_t>,
|
||||
std::shared_ptr<typename ServiceT::Request>
|
||||
)>;
|
||||
using SharedPtrDeferResponseCallbackWithServiceHandle = std::function<
|
||||
void (
|
||||
std::shared_ptr<rclcpp::Service<ServiceT>>,
|
||||
std::shared_ptr<rmw_request_id_t>,
|
||||
std::shared_ptr<typename ServiceT::Request>
|
||||
)>;
|
||||
|
||||
std::variant<
|
||||
std::monostate,
|
||||
SharedPtrCallback,
|
||||
SharedPtrWithRequestHeaderCallback,
|
||||
SharedPtrDeferResponseCallback,
|
||||
SharedPtrDeferResponseCallbackWithServiceHandle> callback_;
|
||||
};
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,11 +16,14 @@
|
||||
#define RCLCPP__CALLBACK_GROUP_HPP_
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "rclcpp/client.hpp"
|
||||
#include "rclcpp/context.hpp"
|
||||
#include "rclcpp/guard_condition.hpp"
|
||||
#include "rclcpp/publisher_base.hpp"
|
||||
#include "rclcpp/service.hpp"
|
||||
#include "rclcpp/subscription_base.hpp"
|
||||
@@ -95,6 +98,10 @@ public:
|
||||
CallbackGroupType group_type,
|
||||
bool automatically_add_to_executor_with_node = true);
|
||||
|
||||
/// Default destructor.
|
||||
RCLCPP_PUBLIC
|
||||
~CallbackGroup();
|
||||
|
||||
template<typename Function>
|
||||
rclcpp::SubscriptionBase::SharedPtr
|
||||
find_subscription_ptrs_if(Function func) const
|
||||
@@ -138,6 +145,14 @@ public:
|
||||
const CallbackGroupType &
|
||||
type() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void collect_all_ptrs(
|
||||
std::function<void(const rclcpp::SubscriptionBase::SharedPtr &)> sub_func,
|
||||
std::function<void(const rclcpp::ServiceBase::SharedPtr &)> service_func,
|
||||
std::function<void(const rclcpp::ClientBase::SharedPtr &)> client_func,
|
||||
std::function<void(const rclcpp::TimerBase::SharedPtr &)> timer_func,
|
||||
std::function<void(const rclcpp::Waitable::SharedPtr &)> waitable_func) const;
|
||||
|
||||
/// Return a reference to the 'associated with executor' atomic boolean.
|
||||
/**
|
||||
* When a callback group is added to an executor this boolean is checked
|
||||
@@ -163,6 +178,16 @@ public:
|
||||
bool
|
||||
automatically_add_to_executor_with_node() const;
|
||||
|
||||
/// Defer creating the notify guard condition and return it.
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::GuardCondition::SharedPtr
|
||||
get_notify_guard_condition(const rclcpp::Context::SharedPtr context_ptr);
|
||||
|
||||
/// Trigger the notify guard condition.
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
trigger_notify_guard_condition();
|
||||
|
||||
protected:
|
||||
RCLCPP_DISABLE_COPY(CallbackGroup)
|
||||
|
||||
@@ -205,6 +230,9 @@ protected:
|
||||
std::vector<rclcpp::Waitable::WeakPtr> waitable_ptrs_;
|
||||
std::atomic_bool can_be_taken_from_;
|
||||
const bool automatically_add_to_executor_with_node_;
|
||||
// defer the creation of the guard condition
|
||||
std::shared_ptr<rclcpp::GuardCondition> notify_guard_condition_ = nullptr;
|
||||
std::recursive_mutex notify_guard_condition_mutex_;
|
||||
|
||||
private:
|
||||
template<typename TypeT, typename Function>
|
||||
@@ -222,13 +250,6 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
namespace callback_group
|
||||
{
|
||||
|
||||
using CallbackGroupType [[deprecated("use rclcpp::CallbackGroupType instead")]] = CallbackGroupType;
|
||||
using CallbackGroup [[deprecated("use rclcpp::CallbackGroup instead")]] = CallbackGroup;
|
||||
|
||||
} // namespace callback_group
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__CALLBACK_GROUP_HPP_
|
||||
|
||||
@@ -16,35 +16,107 @@
|
||||
#define RCLCPP__CLIENT_HPP_
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <future>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional> // NOLINT, cpplint doesn't think this is a cpp std header
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <variant> // NOLINT
|
||||
#include <vector>
|
||||
|
||||
#include "rcl/client.h"
|
||||
#include "rcl/error_handling.h"
|
||||
#include "rcl/event_callback.h"
|
||||
#include "rcl/service_introspection.h"
|
||||
#include "rcl/wait.h"
|
||||
|
||||
#include "rclcpp/clock.hpp"
|
||||
#include "rclcpp/detail/cpp_callback_trampoline.hpp"
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
#include "rclcpp/expand_topic_or_service_name.hpp"
|
||||
#include "rclcpp/function_traits.hpp"
|
||||
#include "rclcpp/logging.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/node_graph_interface.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
#include "rclcpp/type_support_decl.hpp"
|
||||
#include "rclcpp/utilities.hpp"
|
||||
#include "rclcpp/expand_topic_or_service_name.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
#include "rcutils/logging_macros.h"
|
||||
|
||||
#include "rmw/error_handling.h"
|
||||
#include "rmw/impl/cpp/demangle.hpp"
|
||||
#include "rmw/rmw.h"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template<typename FutureT>
|
||||
struct FutureAndRequestId
|
||||
{
|
||||
FutureT future;
|
||||
int64_t request_id;
|
||||
|
||||
FutureAndRequestId(FutureT impl, int64_t req_id)
|
||||
: future(std::move(impl)), request_id(req_id)
|
||||
{}
|
||||
|
||||
/// Allow implicit conversions to `std::future` by reference.
|
||||
operator FutureT &() {return this->future;}
|
||||
|
||||
/// Deprecated, use the `future` member variable instead.
|
||||
/**
|
||||
* Allow implicit conversions to `std::future` by value.
|
||||
* \deprecated
|
||||
*/
|
||||
[[deprecated("FutureAndRequestId: use .future instead of an implicit conversion")]]
|
||||
operator FutureT() {return this->future;}
|
||||
|
||||
// delegate future like methods in the std::future impl_
|
||||
|
||||
/// See std::future::get().
|
||||
auto get() {return this->future.get();}
|
||||
/// See std::future::valid().
|
||||
bool valid() const noexcept {return this->future.valid();}
|
||||
/// See std::future::wait().
|
||||
void wait() const {return this->future.wait();}
|
||||
/// See std::future::wait_for().
|
||||
template<class Rep, class Period>
|
||||
std::future_status wait_for(
|
||||
const std::chrono::duration<Rep, Period> & timeout_duration) const
|
||||
{
|
||||
return this->future.wait_for(timeout_duration);
|
||||
}
|
||||
/// See std::future::wait_until().
|
||||
template<class Clock, class Duration>
|
||||
std::future_status wait_until(
|
||||
const std::chrono::time_point<Clock, Duration> & timeout_time) const
|
||||
{
|
||||
return this->future.wait_until(timeout_time);
|
||||
}
|
||||
|
||||
// Rule of five, we could use the rule of zero here, but better be explicit as some of the
|
||||
// methods are deleted.
|
||||
|
||||
/// Move constructor.
|
||||
FutureAndRequestId(FutureAndRequestId && other) noexcept = default;
|
||||
/// Deleted copy constructor, each instance is a unique owner of the future.
|
||||
FutureAndRequestId(const FutureAndRequestId & other) = delete;
|
||||
/// Move assignment.
|
||||
FutureAndRequestId & operator=(FutureAndRequestId && other) noexcept = default;
|
||||
/// Deleted copy assignment, each instance is a unique owner of the future.
|
||||
FutureAndRequestId & operator=(const FutureAndRequestId & other) = delete;
|
||||
/// Destructor.
|
||||
~FutureAndRequestId() = default;
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
namespace node_interfaces
|
||||
{
|
||||
class NodeBaseInterface;
|
||||
@@ -61,7 +133,7 @@ public:
|
||||
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual ~ClientBase();
|
||||
virtual ~ClientBase() = default;
|
||||
|
||||
/// Take the next response for this client as a type erased pointer.
|
||||
/**
|
||||
@@ -150,6 +222,123 @@ public:
|
||||
bool
|
||||
exchange_in_use_by_wait_set_state(bool in_use_state);
|
||||
|
||||
/// Get the actual request publsher QoS settings, after the defaults have been determined.
|
||||
/**
|
||||
* The actual configuration applied when using RMW_QOS_POLICY_*_SYSTEM_DEFAULT
|
||||
* can only be resolved after the creation of the client, and it
|
||||
* depends on the underlying rmw implementation.
|
||||
* If the underlying setting in use can't be represented in ROS terms,
|
||||
* it will be set to RMW_QOS_POLICY_*_UNKNOWN.
|
||||
* May throw runtime_error when an unexpected error occurs.
|
||||
*
|
||||
* \return The actual request publsher qos settings.
|
||||
* \throws std::runtime_error if failed to get qos settings
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::QoS
|
||||
get_request_publisher_actual_qos() const;
|
||||
|
||||
/// Get the actual response subscription QoS settings, after the defaults have been determined.
|
||||
/**
|
||||
* The actual configuration applied when using RMW_QOS_POLICY_*_SYSTEM_DEFAULT
|
||||
* can only be resolved after the creation of the client, and it
|
||||
* depends on the underlying rmw implementation.
|
||||
* If the underlying setting in use can't be represented in ROS terms,
|
||||
* it will be set to RMW_QOS_POLICY_*_UNKNOWN.
|
||||
* May throw runtime_error when an unexpected error occurs.
|
||||
*
|
||||
* \return The actual response subscription qos settings.
|
||||
* \throws std::runtime_error if failed to get qos settings
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::QoS
|
||||
get_response_subscription_actual_qos() const;
|
||||
|
||||
/// Set a callback to be called when each new response is received.
|
||||
/**
|
||||
* The callback receives a size_t which is the number of responses received
|
||||
* since the last time this callback was called.
|
||||
* Normally this is 1, but can be > 1 if responses were received before any
|
||||
* callback was set.
|
||||
*
|
||||
* Since this callback is called from the middleware, you should aim to make
|
||||
* it fast and not blocking.
|
||||
* If you need to do a lot of work or wait for some other event, you should
|
||||
* spin it off to another thread, otherwise you risk blocking the middleware.
|
||||
*
|
||||
* Calling it again will clear any previously set callback.
|
||||
*
|
||||
* An exception will be thrown if the callback is not callable.
|
||||
*
|
||||
* This function is thread-safe.
|
||||
*
|
||||
* If you want more information available in the callback, like the client
|
||||
* or other information, you may use a lambda with captures or std::bind.
|
||||
*
|
||||
* \sa rmw_client_set_on_new_response_callback
|
||||
* \sa rcl_client_set_on_new_response_callback
|
||||
*
|
||||
* \param[in] callback functor to be called when a new response is received
|
||||
*/
|
||||
void
|
||||
set_on_new_response_callback(std::function<void(size_t)> callback)
|
||||
{
|
||||
if (!callback) {
|
||||
throw std::invalid_argument(
|
||||
"The callback passed to set_on_new_response_callback "
|
||||
"is not callable.");
|
||||
}
|
||||
|
||||
auto new_callback =
|
||||
[callback, this](size_t number_of_responses) {
|
||||
try {
|
||||
callback(number_of_responses);
|
||||
} catch (const std::exception & exception) {
|
||||
RCLCPP_ERROR_STREAM(
|
||||
node_logger_,
|
||||
"rclcpp::ClientBase@" << this <<
|
||||
" caught " << rmw::impl::cpp::demangle(exception) <<
|
||||
" exception in user-provided callback for the 'on new response' callback: " <<
|
||||
exception.what());
|
||||
} catch (...) {
|
||||
RCLCPP_ERROR_STREAM(
|
||||
node_logger_,
|
||||
"rclcpp::ClientBase@" << this <<
|
||||
" caught unhandled exception in user-provided callback " <<
|
||||
"for the 'on new response' callback");
|
||||
}
|
||||
};
|
||||
|
||||
std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
|
||||
|
||||
// Set it temporarily to the new callback, while we replace the old one.
|
||||
// This two-step setting, prevents a gap where the old std::function has
|
||||
// been replaced but the middleware hasn't been told about the new one yet.
|
||||
set_on_new_response_callback(
|
||||
rclcpp::detail::cpp_callback_trampoline<decltype(new_callback), const void *, size_t>,
|
||||
static_cast<const void *>(&new_callback));
|
||||
|
||||
// Store the std::function to keep it in scope, also overwrites the existing one.
|
||||
on_new_response_callback_ = new_callback;
|
||||
|
||||
// Set it again, now using the permanent storage.
|
||||
set_on_new_response_callback(
|
||||
rclcpp::detail::cpp_callback_trampoline<
|
||||
decltype(on_new_response_callback_), const void *, size_t>,
|
||||
static_cast<const void *>(&on_new_response_callback_));
|
||||
}
|
||||
|
||||
/// Unset the callback registered for new responses, if any.
|
||||
void
|
||||
clear_on_new_response_callback()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
|
||||
if (on_new_response_callback_) {
|
||||
set_on_new_response_callback(nullptr, nullptr);
|
||||
on_new_response_callback_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
RCLCPP_DISABLE_COPY(ClientBase)
|
||||
|
||||
@@ -165,19 +354,30 @@ protected:
|
||||
const rcl_node_t *
|
||||
get_rcl_node_handle() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
set_on_new_response_callback(rcl_event_callback_t callback, const void * user_data);
|
||||
|
||||
rclcpp::node_interfaces::NodeGraphInterface::WeakPtr node_graph_;
|
||||
std::shared_ptr<rcl_node_t> node_handle_;
|
||||
std::shared_ptr<rclcpp::Context> context_;
|
||||
rclcpp::Logger node_logger_;
|
||||
|
||||
std::shared_ptr<rcl_client_t> client_handle_;
|
||||
|
||||
std::atomic<bool> in_use_by_wait_set_{false};
|
||||
|
||||
std::recursive_mutex callback_mutex_;
|
||||
std::function<void(size_t)> on_new_response_callback_{nullptr};
|
||||
};
|
||||
|
||||
template<typename ServiceT>
|
||||
class Client : public ClientBase
|
||||
{
|
||||
public:
|
||||
using Request = typename ServiceT::Request;
|
||||
using Response = typename ServiceT::Response;
|
||||
|
||||
using SharedRequest = typename ServiceT::Request::SharedPtr;
|
||||
using SharedResponse = typename ServiceT::Response::SharedPtr;
|
||||
|
||||
@@ -187,6 +387,7 @@ public:
|
||||
using SharedPromise = std::shared_ptr<Promise>;
|
||||
using SharedPromiseWithRequest = std::shared_ptr<PromiseWithRequest>;
|
||||
|
||||
using Future = std::future<SharedResponse>;
|
||||
using SharedFuture = std::shared_future<SharedResponse>;
|
||||
using SharedFutureWithRequest = std::shared_future<std::pair<SharedRequest, SharedResponse>>;
|
||||
|
||||
@@ -195,6 +396,64 @@ public:
|
||||
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(Client)
|
||||
|
||||
/// A convenient Client::Future and request id pair.
|
||||
/**
|
||||
* Public members:
|
||||
* - future: a std::future<SharedResponse>.
|
||||
* - request_id: the request id associated with the future.
|
||||
*
|
||||
* All the other methods are equivalent to the ones std::future provides.
|
||||
*/
|
||||
struct FutureAndRequestId
|
||||
: detail::FutureAndRequestId<std::future<SharedResponse>>
|
||||
{
|
||||
using detail::FutureAndRequestId<std::future<SharedResponse>>::FutureAndRequestId;
|
||||
|
||||
/// Deprecated, use `.future.share()` instead.
|
||||
/**
|
||||
* Allow implicit conversions to `std::shared_future` by value.
|
||||
* \deprecated
|
||||
*/
|
||||
[[deprecated(
|
||||
"FutureAndRequestId: use .future.share() instead of an implicit conversion")]]
|
||||
operator SharedFuture() {return this->future.share();}
|
||||
|
||||
// delegate future like methods in the std::future impl_
|
||||
|
||||
/// See std::future::share().
|
||||
SharedFuture share() noexcept {return this->future.share();}
|
||||
};
|
||||
|
||||
/// A convenient Client::SharedFuture and request id pair.
|
||||
/**
|
||||
* Public members:
|
||||
* - future: a std::shared_future<SharedResponse>.
|
||||
* - request_id: the request id associated with the future.
|
||||
*
|
||||
* All the other methods are equivalent to the ones std::shared_future provides.
|
||||
*/
|
||||
struct SharedFutureAndRequestId
|
||||
: detail::FutureAndRequestId<std::shared_future<SharedResponse>>
|
||||
{
|
||||
using detail::FutureAndRequestId<std::shared_future<SharedResponse>>::FutureAndRequestId;
|
||||
};
|
||||
|
||||
/// A convenient Client::SharedFutureWithRequest and request id pair.
|
||||
/**
|
||||
* Public members:
|
||||
* - future: a std::shared_future<SharedResponse>.
|
||||
* - request_id: the request id associated with the future.
|
||||
*
|
||||
* All the other methods are equivalent to the ones std::shared_future provides.
|
||||
*/
|
||||
struct SharedFutureWithRequestAndRequestId
|
||||
: detail::FutureAndRequestId<std::shared_future<std::pair<SharedRequest, SharedResponse>>>
|
||||
{
|
||||
using detail::FutureAndRequestId<
|
||||
std::shared_future<std::pair<SharedRequest, SharedResponse>>
|
||||
>::FutureAndRequestId;
|
||||
};
|
||||
|
||||
/// Default constructor.
|
||||
/**
|
||||
* The constructor for a Client is almost never called directly.
|
||||
@@ -211,15 +470,13 @@ public:
|
||||
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph,
|
||||
const std::string & service_name,
|
||||
rcl_client_options_t & client_options)
|
||||
: ClientBase(node_base, node_graph)
|
||||
: ClientBase(node_base, node_graph),
|
||||
srv_type_support_handle_(rosidl_typesupport_cpp::get_service_type_support_handle<ServiceT>())
|
||||
{
|
||||
using rosidl_typesupport_cpp::get_service_type_support_handle;
|
||||
auto service_type_support_handle =
|
||||
get_service_type_support_handle<ServiceT>();
|
||||
rcl_ret_t ret = rcl_client_init(
|
||||
this->get_client_handle().get(),
|
||||
this->get_rcl_node_handle(),
|
||||
service_type_support_handle,
|
||||
srv_type_support_handle_,
|
||||
service_name.c_str(),
|
||||
&client_options);
|
||||
if (ret != RCL_RET_OK) {
|
||||
@@ -292,34 +549,89 @@ public:
|
||||
std::shared_ptr<rmw_request_id_t> request_header,
|
||||
std::shared_ptr<void> response) override
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(pending_requests_mutex_);
|
||||
auto typed_response = std::static_pointer_cast<typename ServiceT::Response>(response);
|
||||
int64_t sequence_number = request_header->sequence_number;
|
||||
// TODO(esteve) this should throw instead since it is not expected to happen in the first place
|
||||
if (this->pending_requests_.count(sequence_number) == 0) {
|
||||
RCUTILS_LOG_ERROR_NAMED(
|
||||
"rclcpp",
|
||||
"Received invalid sequence number. Ignoring...");
|
||||
std::optional<CallbackInfoVariant>
|
||||
optional_pending_request = this->get_and_erase_pending_request(request_header->sequence_number);
|
||||
if (!optional_pending_request) {
|
||||
return;
|
||||
}
|
||||
auto tuple = this->pending_requests_[sequence_number];
|
||||
auto call_promise = std::get<0>(tuple);
|
||||
auto callback = std::get<1>(tuple);
|
||||
auto future = std::get<2>(tuple);
|
||||
this->pending_requests_.erase(sequence_number);
|
||||
// Unlock here to allow the service to be called recursively from one of its callbacks.
|
||||
lock.unlock();
|
||||
|
||||
call_promise->set_value(typed_response);
|
||||
callback(future);
|
||||
auto & value = *optional_pending_request;
|
||||
auto typed_response = std::static_pointer_cast<typename ServiceT::Response>(
|
||||
std::move(response));
|
||||
if (std::holds_alternative<Promise>(value)) {
|
||||
auto & promise = std::get<Promise>(value);
|
||||
promise.set_value(std::move(typed_response));
|
||||
} else if (std::holds_alternative<CallbackTypeValueVariant>(value)) {
|
||||
auto & inner = std::get<CallbackTypeValueVariant>(value);
|
||||
const auto & callback = std::get<CallbackType>(inner);
|
||||
auto & promise = std::get<Promise>(inner);
|
||||
auto & future = std::get<SharedFuture>(inner);
|
||||
promise.set_value(std::move(typed_response));
|
||||
callback(std::move(future));
|
||||
} else if (std::holds_alternative<CallbackWithRequestTypeValueVariant>(value)) {
|
||||
auto & inner = std::get<CallbackWithRequestTypeValueVariant>(value);
|
||||
const auto & callback = std::get<CallbackWithRequestType>(inner);
|
||||
auto & promise = std::get<PromiseWithRequest>(inner);
|
||||
auto & future = std::get<SharedFutureWithRequest>(inner);
|
||||
auto & request = std::get<SharedRequest>(inner);
|
||||
promise.set_value(std::make_pair(std::move(request), std::move(typed_response)));
|
||||
callback(std::move(future));
|
||||
}
|
||||
}
|
||||
|
||||
SharedFuture
|
||||
/// Send a request to the service server.
|
||||
/**
|
||||
* This method returns a `FutureAndRequestId` instance
|
||||
* that can be passed to Executor::spin_until_future_complete() to
|
||||
* wait until it has been completed.
|
||||
*
|
||||
* If the future never completes,
|
||||
* e.g. the call to Executor::spin_until_future_complete() times out,
|
||||
* Client::remove_pending_request() must be called to clean the client internal state.
|
||||
* Not doing so will make the `Client` instance to use more memory each time a response is not
|
||||
* received from the service server.
|
||||
*
|
||||
* ```cpp
|
||||
* auto future = client->async_send_request(my_request);
|
||||
* if (
|
||||
* rclcpp::FutureReturnCode::TIMEOUT ==
|
||||
* executor->spin_until_future_complete(future, timeout))
|
||||
* {
|
||||
* client->remove_pending_request(future);
|
||||
* // handle timeout
|
||||
* } else {
|
||||
* handle_response(future.get());
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* \param[in] request request to be send.
|
||||
* \return a FutureAndRequestId instance.
|
||||
*/
|
||||
FutureAndRequestId
|
||||
async_send_request(SharedRequest request)
|
||||
{
|
||||
return async_send_request(request, [](SharedFuture) {});
|
||||
Promise promise;
|
||||
auto future = promise.get_future();
|
||||
auto req_id = async_send_request_impl(
|
||||
*request,
|
||||
std::move(promise));
|
||||
return FutureAndRequestId(std::move(future), req_id);
|
||||
}
|
||||
|
||||
/// Send a request to the service server and schedule a callback in the executor.
|
||||
/**
|
||||
* Similar to the previous overload, but a callback will automatically be called when a response is received.
|
||||
*
|
||||
* If the callback is never called, because we never got a reply for the service server, remove_pending_request()
|
||||
* has to be called with the returned request id or prune_pending_requests().
|
||||
* Not doing so will make the `Client` instance use more memory each time a response is not
|
||||
* received from the service server.
|
||||
* In this case, it's convenient to setup a timer to cleanup the pending requests.
|
||||
* See for example the `examples_rclcpp_async_client` package in https://github.com/ros2/examples.
|
||||
*
|
||||
* \param[in] request request to be send.
|
||||
* \param[in] cb callback that will be called when we get a response for this request.
|
||||
* \return the request id representing the request just sent.
|
||||
*/
|
||||
template<
|
||||
typename CallbackT,
|
||||
typename std::enable_if<
|
||||
@@ -329,23 +641,28 @@ public:
|
||||
>::value
|
||||
>::type * = nullptr
|
||||
>
|
||||
SharedFuture
|
||||
SharedFutureAndRequestId
|
||||
async_send_request(SharedRequest request, CallbackT && cb)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(pending_requests_mutex_);
|
||||
int64_t sequence_number;
|
||||
rcl_ret_t ret = rcl_send_request(get_client_handle().get(), request.get(), &sequence_number);
|
||||
if (RCL_RET_OK != ret) {
|
||||
rclcpp::exceptions::throw_from_rcl_error(ret, "failed to send request");
|
||||
}
|
||||
|
||||
SharedPromise call_promise = std::make_shared<Promise>();
|
||||
SharedFuture f(call_promise->get_future());
|
||||
pending_requests_[sequence_number] =
|
||||
std::make_tuple(call_promise, std::forward<CallbackType>(cb), f);
|
||||
return f;
|
||||
Promise promise;
|
||||
auto shared_future = promise.get_future().share();
|
||||
auto req_id = async_send_request_impl(
|
||||
*request,
|
||||
std::make_tuple(
|
||||
CallbackType{std::forward<CallbackT>(cb)},
|
||||
shared_future,
|
||||
std::move(promise)));
|
||||
return SharedFutureAndRequestId{std::move(shared_future), req_id};
|
||||
}
|
||||
|
||||
/// Send a request to the service server and schedule a callback in the executor.
|
||||
/**
|
||||
* Similar to the previous method, but you can get both the request and response in the callback.
|
||||
*
|
||||
* \param[in] request request to be send.
|
||||
* \param[in] cb callback that will be called when we get a response for this request.
|
||||
* \return the request id representing the request just sent.
|
||||
*/
|
||||
template<
|
||||
typename CallbackT,
|
||||
typename std::enable_if<
|
||||
@@ -355,29 +672,196 @@ public:
|
||||
>::value
|
||||
>::type * = nullptr
|
||||
>
|
||||
SharedFutureWithRequest
|
||||
SharedFutureWithRequestAndRequestId
|
||||
async_send_request(SharedRequest request, CallbackT && cb)
|
||||
{
|
||||
SharedPromiseWithRequest promise = std::make_shared<PromiseWithRequest>();
|
||||
SharedFutureWithRequest future_with_request(promise->get_future());
|
||||
|
||||
auto wrapping_cb = [future_with_request, promise, request,
|
||||
cb = std::forward<CallbackWithRequestType>(cb)](SharedFuture future) {
|
||||
auto response = future.get();
|
||||
promise->set_value(std::make_pair(request, response));
|
||||
cb(future_with_request);
|
||||
};
|
||||
|
||||
async_send_request(request, wrapping_cb);
|
||||
|
||||
return future_with_request;
|
||||
PromiseWithRequest promise;
|
||||
auto shared_future = promise.get_future().share();
|
||||
auto req_id = async_send_request_impl(
|
||||
*request,
|
||||
std::make_tuple(
|
||||
CallbackWithRequestType{std::forward<CallbackT>(cb)},
|
||||
request,
|
||||
shared_future,
|
||||
std::move(promise)));
|
||||
return SharedFutureWithRequestAndRequestId{std::move(shared_future), req_id};
|
||||
}
|
||||
|
||||
/// Cleanup a pending request.
|
||||
/**
|
||||
* This notifies the client that we have waited long enough for a response from the server
|
||||
* to come, we have given up and we are not waiting for a response anymore.
|
||||
*
|
||||
* Not calling this will make the client start using more memory for each request
|
||||
* that never got a reply from the server.
|
||||
*
|
||||
* \param[in] request_id request id returned by async_send_request().
|
||||
* \return true when a pending request was removed, false if not (e.g. a response was received).
|
||||
*/
|
||||
bool
|
||||
remove_pending_request(int64_t request_id)
|
||||
{
|
||||
std::lock_guard guard(pending_requests_mutex_);
|
||||
return pending_requests_.erase(request_id) != 0u;
|
||||
}
|
||||
|
||||
/// Cleanup a pending request.
|
||||
/**
|
||||
* Convenient overload, same as:
|
||||
*
|
||||
* `Client::remove_pending_request(this, future.request_id)`.
|
||||
*/
|
||||
bool
|
||||
remove_pending_request(const FutureAndRequestId & future)
|
||||
{
|
||||
return this->remove_pending_request(future.request_id);
|
||||
}
|
||||
|
||||
/// Cleanup a pending request.
|
||||
/**
|
||||
* Convenient overload, same as:
|
||||
*
|
||||
* `Client::remove_pending_request(this, future.request_id)`.
|
||||
*/
|
||||
bool
|
||||
remove_pending_request(const SharedFutureAndRequestId & future)
|
||||
{
|
||||
return this->remove_pending_request(future.request_id);
|
||||
}
|
||||
|
||||
/// Cleanup a pending request.
|
||||
/**
|
||||
* Convenient overload, same as:
|
||||
*
|
||||
* `Client::remove_pending_request(this, future.request_id)`.
|
||||
*/
|
||||
bool
|
||||
remove_pending_request(const SharedFutureWithRequestAndRequestId & future)
|
||||
{
|
||||
return this->remove_pending_request(future.request_id);
|
||||
}
|
||||
|
||||
/// Clean all pending requests.
|
||||
/**
|
||||
* \return number of pending requests that were removed.
|
||||
*/
|
||||
size_t
|
||||
prune_pending_requests()
|
||||
{
|
||||
std::lock_guard guard(pending_requests_mutex_);
|
||||
auto ret = pending_requests_.size();
|
||||
pending_requests_.clear();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/// Clean all pending requests older than a time_point.
|
||||
/**
|
||||
* \param[in] time_point Requests that were sent before this point are going to be removed.
|
||||
* \param[inout] pruned_requests Removed requests id will be pushed to the vector
|
||||
* if a pointer is provided.
|
||||
* \return number of pending requests that were removed.
|
||||
*/
|
||||
template<typename AllocatorT = std::allocator<int64_t>>
|
||||
size_t
|
||||
prune_requests_older_than(
|
||||
std::chrono::time_point<std::chrono::system_clock> time_point,
|
||||
std::vector<int64_t, AllocatorT> * pruned_requests = nullptr)
|
||||
{
|
||||
std::lock_guard guard(pending_requests_mutex_);
|
||||
auto old_size = pending_requests_.size();
|
||||
for (auto it = pending_requests_.begin(), last = pending_requests_.end(); it != last; ) {
|
||||
if (it->second.first < time_point) {
|
||||
if (pruned_requests) {
|
||||
pruned_requests->push_back(it->first);
|
||||
}
|
||||
it = pending_requests_.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
return old_size - pending_requests_.size();
|
||||
}
|
||||
|
||||
/// Configure client introspection.
|
||||
/**
|
||||
* \param[in] clock clock to use to generate introspection timestamps
|
||||
* \param[in] qos_service_event_pub QoS settings to use when creating the introspection publisher
|
||||
* \param[in] introspection_state the state to set introspection to
|
||||
*/
|
||||
void
|
||||
configure_introspection(
|
||||
Clock::SharedPtr clock, const QoS & qos_service_event_pub,
|
||||
rcl_service_introspection_state_t introspection_state)
|
||||
{
|
||||
rcl_publisher_options_t pub_opts = rcl_publisher_get_default_options();
|
||||
pub_opts.qos = qos_service_event_pub.get_rmw_qos_profile();
|
||||
|
||||
rcl_ret_t ret = rcl_client_configure_service_introspection(
|
||||
client_handle_.get(),
|
||||
node_handle_.get(),
|
||||
clock->get_clock_handle(),
|
||||
srv_type_support_handle_,
|
||||
pub_opts,
|
||||
introspection_state);
|
||||
|
||||
if (RCL_RET_OK != ret) {
|
||||
rclcpp::exceptions::throw_from_rcl_error(ret, "failed to configure client introspection");
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
using CallbackTypeValueVariant = std::tuple<CallbackType, SharedFuture, Promise>;
|
||||
using CallbackWithRequestTypeValueVariant = std::tuple<
|
||||
CallbackWithRequestType, SharedRequest, SharedFutureWithRequest, PromiseWithRequest>;
|
||||
|
||||
using CallbackInfoVariant = std::variant<
|
||||
std::promise<SharedResponse>,
|
||||
CallbackTypeValueVariant,
|
||||
CallbackWithRequestTypeValueVariant>;
|
||||
|
||||
int64_t
|
||||
async_send_request_impl(const Request & request, CallbackInfoVariant value)
|
||||
{
|
||||
int64_t sequence_number;
|
||||
std::lock_guard<std::mutex> lock(pending_requests_mutex_);
|
||||
rcl_ret_t ret = rcl_send_request(get_client_handle().get(), &request, &sequence_number);
|
||||
if (RCL_RET_OK != ret) {
|
||||
rclcpp::exceptions::throw_from_rcl_error(ret, "failed to send request");
|
||||
}
|
||||
pending_requests_.try_emplace(
|
||||
sequence_number,
|
||||
std::make_pair(std::chrono::system_clock::now(), std::move(value)));
|
||||
return sequence_number;
|
||||
}
|
||||
|
||||
std::optional<CallbackInfoVariant>
|
||||
get_and_erase_pending_request(int64_t request_number)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(pending_requests_mutex_);
|
||||
auto it = this->pending_requests_.find(request_number);
|
||||
if (it == this->pending_requests_.end()) {
|
||||
RCUTILS_LOG_DEBUG_NAMED(
|
||||
"rclcpp",
|
||||
"Received invalid sequence number. Ignoring...");
|
||||
return std::nullopt;
|
||||
}
|
||||
auto value = std::move(it->second.second);
|
||||
this->pending_requests_.erase(request_number);
|
||||
return value;
|
||||
}
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(Client)
|
||||
|
||||
std::map<int64_t, std::tuple<SharedPromise, CallbackType, SharedFuture>> pending_requests_;
|
||||
std::unordered_map<
|
||||
int64_t,
|
||||
std::pair<
|
||||
std::chrono::time_point<std::chrono::system_clock>,
|
||||
CallbackInfoVariant>>
|
||||
pending_requests_;
|
||||
std::mutex pending_requests_mutex_;
|
||||
|
||||
private:
|
||||
const rosidl_service_type_support_t * srv_type_support_handle_;
|
||||
};
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
#include "rclcpp/contexts/default_context.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/time.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
@@ -76,7 +77,110 @@ public:
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
Time
|
||||
now();
|
||||
now() const;
|
||||
|
||||
/**
|
||||
* Sleep until a specified Time, according to clock type.
|
||||
*
|
||||
* Notes for RCL_ROS_TIME clock type:
|
||||
* - Can sleep forever if ros time is active and received clock never reaches `until`
|
||||
* - If ROS time enabled state changes during the sleep, this method will immediately return
|
||||
* false. There is not a consistent choice of sleeping time when the time source changes,
|
||||
* so this is up to the caller to call again if needed.
|
||||
*
|
||||
* \warning When using gcc < 10 or when using gcc >= 10 and pthreads lacks the function
|
||||
* `pthread_cond_clockwait`, steady clocks may sleep using the system clock.
|
||||
* If so, steady clock sleep times can be affected by system clock time jumps.
|
||||
* Depending on the steady clock's epoch and resolution in comparison to the system clock's,
|
||||
* an overflow when converting steady clock durations to system clock times may cause
|
||||
* undefined behavior.
|
||||
* For more info see these issues:
|
||||
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=41861
|
||||
* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58931
|
||||
*
|
||||
* \param until absolute time according to current clock type to sleep until.
|
||||
* \param context the rclcpp context the clock should use to check that ROS is still initialized.
|
||||
* \return true immediately if `until` is in the past
|
||||
* \return true when the time `until` is reached
|
||||
* \return false if time cannot be reached reliably, for example from shutdown or a change
|
||||
* of time source.
|
||||
* \throws std::runtime_error if the context is invalid
|
||||
* \throws std::runtime_error if `until` has a different clock type from this clock
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
sleep_until(
|
||||
Time until,
|
||||
Context::SharedPtr context = contexts::get_global_default_context());
|
||||
|
||||
/**
|
||||
* Sleep for a specified Duration.
|
||||
*
|
||||
* Equivalent to
|
||||
*
|
||||
* ```cpp
|
||||
* clock->sleep_until(clock->now() + rel_time, context)
|
||||
* ```
|
||||
*
|
||||
* The function will return immediately if `rel_time` is zero or negative.
|
||||
*
|
||||
* \param rel_time the length of time to sleep for.
|
||||
* \param context the rclcpp context the clock should use to check that ROS is still initialized.
|
||||
* \return true when the end time is reached
|
||||
* \return false if time cannot be reached reliably, for example from shutdown or a change
|
||||
* of time source.
|
||||
* \throws std::runtime_error if the context is invalid
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
sleep_for(
|
||||
Duration rel_time,
|
||||
Context::SharedPtr context = contexts::get_global_default_context());
|
||||
|
||||
/**
|
||||
* Check if the clock is started.
|
||||
*
|
||||
* A started clock is a clock that reflects non-zero time.
|
||||
* Typically a clock will be unstarted if it is using RCL_ROS_TIME with ROS time and
|
||||
* nothing has been published on the clock topic yet.
|
||||
*
|
||||
* \return true if clock is started
|
||||
* \throws std::runtime_error if the clock is not rcl_clock_valid
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
started();
|
||||
|
||||
/**
|
||||
* Wait until clock to start.
|
||||
*
|
||||
* \rclcpp::Clock::started
|
||||
* \param context the context to wait in
|
||||
* \return true if clock was already started or became started
|
||||
* \throws std::runtime_error if the context is invalid or clock is not rcl_clock_valid
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
wait_until_started(Context::SharedPtr context = contexts::get_global_default_context());
|
||||
|
||||
/**
|
||||
* Wait for clock to start, with timeout.
|
||||
*
|
||||
* The timeout is waited in steady time.
|
||||
*
|
||||
* \rclcpp::Clock::started
|
||||
* \param timeout the maximum time to wait for.
|
||||
* \param context the context to wait in.
|
||||
* \param wait_tick_ns the time to wait between each iteration of the wait loop (in nanoseconds).
|
||||
* \return true if clock was or became valid
|
||||
* \throws std::runtime_error if the context is invalid or clock is not rcl_clock_valid
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
wait_until_started(
|
||||
const rclcpp::Duration & timeout,
|
||||
Context::SharedPtr context = contexts::get_global_default_context(),
|
||||
const rclcpp::Duration & wait_tick_ns = rclcpp::Duration(0, static_cast<uint32_t>(1e7)));
|
||||
|
||||
/**
|
||||
* Returns the clock of the type `RCL_ROS_TIME` is active.
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <typeindex>
|
||||
#include <typeinfo>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@@ -47,11 +48,28 @@ public:
|
||||
/// Forward declare WeakContextsWrapper
|
||||
class WeakContextsWrapper;
|
||||
|
||||
class ShutdownCallbackHandle
|
||||
{
|
||||
friend class Context;
|
||||
|
||||
public:
|
||||
using ShutdownCallbackType = std::function<void ()>;
|
||||
|
||||
private:
|
||||
std::weak_ptr<ShutdownCallbackType> callback;
|
||||
};
|
||||
|
||||
using OnShutdownCallbackHandle = ShutdownCallbackHandle;
|
||||
using PreShutdownCallbackHandle = ShutdownCallbackHandle;
|
||||
|
||||
/// Context which encapsulates shared state between nodes and other similar entities.
|
||||
/**
|
||||
* A context also represents the lifecycle between init and shutdown of rclcpp.
|
||||
* It is often used in conjunction with rclcpp::init, or rclcpp::init_local,
|
||||
* and rclcpp::shutdown.
|
||||
* Nodes may be attached to a particular context by passing to the rclcpp::Node
|
||||
* constructor a rclcpp::NodeOptions instance in which the Context is set via
|
||||
* rclcpp::NodeOptions::context.
|
||||
* Nodes will be automatically removed from the context when destructed.
|
||||
* Contexts may be shutdown by calling rclcpp::shutdown.
|
||||
*/
|
||||
class Context : public std::enable_shared_from_this<Context>
|
||||
{
|
||||
@@ -63,7 +81,7 @@ public:
|
||||
* Every context which is constructed is added to a global vector of contexts,
|
||||
* which is used by the signal handler to conditionally shutdown each context
|
||||
* on SIGINT.
|
||||
* See the shutdown_on_sigint option in the InitOptions class.
|
||||
* See the shutdown_on_signal option in the InitOptions class.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
Context();
|
||||
@@ -80,8 +98,8 @@ public:
|
||||
*
|
||||
* Note that this function does not setup any signal handlers, so if you want
|
||||
* it to be shutdown by the signal handler, then you need to either install
|
||||
* them manually with rclcpp::install_signal_handers() or use rclcpp::init().
|
||||
* In addition to installing the signal handlers, the shutdown_on_sigint
|
||||
* them manually with rclcpp::install_signal_handlers() or use rclcpp::init().
|
||||
* In addition to installing the signal handlers, the shutdown_on_signal
|
||||
* of the InitOptions needs to be `true` for this context to be shutdown by
|
||||
* the signal handler, otherwise it will be passed over.
|
||||
*
|
||||
@@ -112,7 +130,7 @@ public:
|
||||
void
|
||||
init(
|
||||
int argc,
|
||||
char const * const argv[],
|
||||
char const * const * argv,
|
||||
const rclcpp::InitOptions & init_options = rclcpp::InitOptions());
|
||||
|
||||
/// Return true if the context is valid, otherwise false.
|
||||
@@ -168,6 +186,11 @@ public:
|
||||
*
|
||||
* This function is thread-safe.
|
||||
*
|
||||
* Note that if you override this method, but leave shutdown to be called in
|
||||
* the destruction of this base class, it will not call the overridden
|
||||
* version from your base class.
|
||||
* So you need to ensure you call your class's shutdown() in its destructor.
|
||||
*
|
||||
* \param[in] reason the description of why shutdown happened
|
||||
* \return true if shutdown was successful, false if context was already shutdown
|
||||
* \throw various exceptions derived from rclcpp::exceptions::RCLError, if rcl_shutdown fails
|
||||
@@ -177,7 +200,7 @@ public:
|
||||
bool
|
||||
shutdown(const std::string & reason);
|
||||
|
||||
using OnShutdownCallback = std::function<void ()>;
|
||||
using OnShutdownCallback = OnShutdownCallbackHandle::ShutdownCallbackType;
|
||||
|
||||
/// Add a on_shutdown callback to be called when shutdown is called for this context.
|
||||
/**
|
||||
@@ -185,7 +208,7 @@ public:
|
||||
* to last step in shutdown().
|
||||
*
|
||||
* When shutdown occurs due to the signal handler, these callbacks are run
|
||||
* asynchronoulsy in the dedicated singal handling thread.
|
||||
* asynchronously in the dedicated singal handling thread.
|
||||
*
|
||||
* Also, shutdown() may be called from the destructor of this function.
|
||||
* Therefore, it is not safe to throw exceptions from these callbacks.
|
||||
@@ -203,23 +226,82 @@ public:
|
||||
OnShutdownCallback
|
||||
on_shutdown(OnShutdownCallback callback);
|
||||
|
||||
/// Return the shutdown callbacks as const.
|
||||
/// Add a on_shutdown callback to be called when shutdown is called for this context.
|
||||
/**
|
||||
* Using the returned reference is not thread-safe with calls that modify
|
||||
* the list of "on shutdown" callbacks, i.e. on_shutdown().
|
||||
* These callbacks will be called in the order they are added as the second
|
||||
* to last step in shutdown().
|
||||
*
|
||||
* When shutdown occurs due to the signal handler, these callbacks are run
|
||||
* asynchronously in the dedicated signal handling thread.
|
||||
*
|
||||
* Also, shutdown() may be called from the destructor of this function.
|
||||
* Therefore, it is not safe to throw exceptions from these callbacks.
|
||||
* Instead, log errors or use some other mechanism to indicate an error has
|
||||
* occurred.
|
||||
*
|
||||
* On shutdown callbacks may be registered before init and after shutdown,
|
||||
* and persist on repeated init's.
|
||||
*
|
||||
* \param[in] callback the on_shutdown callback to be registered
|
||||
* \return the created callback handle
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
const std::vector<OnShutdownCallback> &
|
||||
get_on_shutdown_callbacks() const;
|
||||
virtual
|
||||
OnShutdownCallbackHandle
|
||||
add_on_shutdown_callback(OnShutdownCallback callback);
|
||||
|
||||
/// Remove an registered on_shutdown callbacks.
|
||||
/**
|
||||
* \param[in] callback_handle the on_shutdown callback handle to be removed.
|
||||
* \return true if the callback is found and removed, otherwise false.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
bool
|
||||
remove_on_shutdown_callback(const OnShutdownCallbackHandle & callback_handle);
|
||||
|
||||
using PreShutdownCallback = PreShutdownCallbackHandle::ShutdownCallbackType;
|
||||
|
||||
/// Add a pre_shutdown callback to be called before shutdown is called for this context.
|
||||
/**
|
||||
* These callbacks will be called in the order they are added.
|
||||
*
|
||||
* When shutdown occurs due to the signal handler, these callbacks are run
|
||||
* asynchronously in the dedicated signal handling thread.
|
||||
*
|
||||
* \param[in] callback the pre_shutdown callback to be registered
|
||||
* \return the created callback handle
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
PreShutdownCallbackHandle
|
||||
add_pre_shutdown_callback(PreShutdownCallback callback);
|
||||
|
||||
/// Remove an registered pre_shutdown callback.
|
||||
/**
|
||||
* \param[in] callback_handle the pre_shutdown callback handle to be removed.
|
||||
* \return true if the callback is found and removed, otherwise false.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
bool
|
||||
remove_pre_shutdown_callback(const PreShutdownCallbackHandle & callback_handle);
|
||||
|
||||
/// Return the shutdown callbacks.
|
||||
/**
|
||||
* Using the returned reference is not thread-safe with calls that modify
|
||||
* the list of "on shutdown" callbacks, i.e. on_shutdown().
|
||||
* Returned callbacks are a copy of the registered callbacks.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<OnShutdownCallback> &
|
||||
get_on_shutdown_callbacks();
|
||||
std::vector<OnShutdownCallback>
|
||||
get_on_shutdown_callbacks() const;
|
||||
|
||||
/// Return the pre-shutdown callbacks.
|
||||
/**
|
||||
* Returned callbacks are a copy of the registered callbacks.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<PreShutdownCallback>
|
||||
get_pre_shutdown_callbacks() const;
|
||||
|
||||
/// Return the internal rcl context.
|
||||
RCLCPP_PUBLIC
|
||||
@@ -232,7 +314,7 @@ public:
|
||||
*
|
||||
* - this context is shutdown()
|
||||
* - this context is destructed (resulting in shutdown)
|
||||
* - this context has shutdown_on_sigint=true and SIGINT occurs (resulting in shutdown)
|
||||
* - this context has shutdown_on_signal=true and SIGINT/SIGTERM occurs (resulting in shutdown)
|
||||
* - interrupt_all_sleep_for() is called
|
||||
*
|
||||
* \param[in] nanoseconds A std::chrono::duration representing how long to sleep for.
|
||||
@@ -244,7 +326,6 @@ public:
|
||||
|
||||
/// Interrupt any blocking sleep_for calls, causing them to return immediately and return true.
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
interrupt_all_sleep_for();
|
||||
|
||||
@@ -277,7 +358,6 @@ protected:
|
||||
// Called by constructor and destructor to clean up by finalizing the
|
||||
// shutdown rcl context and preparing for a new init cycle.
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
clean_up();
|
||||
|
||||
@@ -299,8 +379,11 @@ private:
|
||||
// attempt to acquire another sub context.
|
||||
std::recursive_mutex sub_contexts_mutex_;
|
||||
|
||||
std::vector<OnShutdownCallback> on_shutdown_callbacks_;
|
||||
std::mutex on_shutdown_callbacks_mutex_;
|
||||
std::vector<std::shared_ptr<OnShutdownCallback>> on_shutdown_callbacks_;
|
||||
mutable std::mutex on_shutdown_callbacks_mutex_;
|
||||
|
||||
std::vector<std::shared_ptr<PreShutdownCallback>> pre_shutdown_callbacks_;
|
||||
mutable std::mutex pre_shutdown_callbacks_mutex_;
|
||||
|
||||
/// Condition variable for timed sleep (see sleep_for).
|
||||
std::condition_variable interrupt_condition_variable_;
|
||||
@@ -309,6 +392,31 @@ private:
|
||||
|
||||
/// Keep shared ownership of global vector of weak contexts
|
||||
std::shared_ptr<WeakContextsWrapper> weak_contexts_;
|
||||
|
||||
enum class ShutdownType
|
||||
{
|
||||
pre_shutdown,
|
||||
on_shutdown
|
||||
};
|
||||
|
||||
using ShutdownCallback = ShutdownCallbackHandle::ShutdownCallbackType;
|
||||
|
||||
template<ShutdownType shutdown_type>
|
||||
RCLCPP_LOCAL
|
||||
ShutdownCallbackHandle
|
||||
add_shutdown_callback(
|
||||
ShutdownCallback callback);
|
||||
|
||||
template<ShutdownType shutdown_type>
|
||||
RCLCPP_LOCAL
|
||||
bool
|
||||
remove_shutdown_callback(
|
||||
const ShutdownCallbackHandle & callback_handle);
|
||||
|
||||
template<ShutdownType shutdown_type>
|
||||
RCLCPP_LOCAL
|
||||
std::vector<rclcpp::Context::ShutdownCallback>
|
||||
get_shutdown_callback() const;
|
||||
};
|
||||
|
||||
/// Return a copy of the list of context shared pointers.
|
||||
|
||||
@@ -36,22 +36,6 @@ RCLCPP_PUBLIC
|
||||
DefaultContext::SharedPtr
|
||||
get_global_default_context();
|
||||
|
||||
namespace default_context
|
||||
{
|
||||
|
||||
using DefaultContext
|
||||
[[deprecated("use rclcpp::contexts::DefaultContext instead")]] = DefaultContext;
|
||||
|
||||
[[deprecated("use rclcpp::contexts::get_global_default_context() instead")]]
|
||||
RCLCPP_PUBLIC
|
||||
inline
|
||||
DefaultContext::SharedPtr
|
||||
get_global_default_context()
|
||||
{
|
||||
return rclcpp::contexts::get_global_default_context();
|
||||
}
|
||||
|
||||
} // namespace default_context
|
||||
} // namespace contexts
|
||||
} // namespace rclcpp
|
||||
|
||||
|
||||
@@ -20,10 +20,40 @@
|
||||
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_services_interface.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
#include "rmw/rmw.h"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
/// Create a service client with a given type.
|
||||
/**
|
||||
* \param[in] node_base NodeBaseInterface implementation of the node on which
|
||||
* to create the client.
|
||||
* \param[in] node_graph NodeGraphInterface implementation of the node on which
|
||||
* to create the client.
|
||||
* \param[in] node_services NodeServicesInterface implementation of the node on
|
||||
* which to create the client.
|
||||
* \param[in] service_name The name on which the service is accessible.
|
||||
* \param[in] qos Quality of service profile for client.
|
||||
* \param[in] group Callback group to handle the reply to service calls.
|
||||
* \return Shared pointer to the created client.
|
||||
*/
|
||||
template<typename ServiceT>
|
||||
typename rclcpp::Client<ServiceT>::SharedPtr
|
||||
create_client(
|
||||
std::shared_ptr<node_interfaces::NodeBaseInterface> node_base,
|
||||
std::shared_ptr<node_interfaces::NodeGraphInterface> node_graph,
|
||||
std::shared_ptr<node_interfaces::NodeServicesInterface> node_services,
|
||||
const std::string & service_name,
|
||||
const rclcpp::QoS & qos = rclcpp::ServicesQoS(),
|
||||
rclcpp::CallbackGroup::SharedPtr group = nullptr)
|
||||
{
|
||||
return create_client<ServiceT>(
|
||||
node_base, node_graph, node_services,
|
||||
service_name,
|
||||
qos.get_rmw_qos_profile(),
|
||||
group);
|
||||
}
|
||||
|
||||
/// Create a service client with a given type.
|
||||
/// \internal
|
||||
|
||||
69
rclcpp/include/rclcpp/create_generic_publisher.hpp
Normal file
69
rclcpp/include/rclcpp/create_generic_publisher.hpp
Normal file
@@ -0,0 +1,69 @@
|
||||
// Copyright 2020, Apex.AI Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__CREATE_GENERIC_PUBLISHER_HPP_
|
||||
#define RCLCPP__CREATE_GENERIC_PUBLISHER_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "rclcpp/generic_publisher.hpp"
|
||||
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
|
||||
#include "rclcpp/publisher_options.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
#include "rclcpp/typesupport_helpers.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
/// Create and return a GenericPublisher.
|
||||
/**
|
||||
* The returned pointer will never be empty, but this function can throw various exceptions, for
|
||||
* instance when the message's package can not be found on the AMENT_PREFIX_PATH.
|
||||
*
|
||||
* \param topics_interface NodeTopicsInterface pointer used in parts of the setup
|
||||
* \param topic_name Topic name
|
||||
* \param topic_type Topic type
|
||||
* \param qos %QoS settings
|
||||
* \param options %Publisher options.
|
||||
* Not all publisher options are currently respected, the only relevant options for this
|
||||
* publisher are `event_callbacks`, `use_default_callbacks`, and `%callback_group`.
|
||||
*/
|
||||
template<typename AllocatorT = std::allocator<void>>
|
||||
std::shared_ptr<GenericPublisher> create_generic_publisher(
|
||||
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr topics_interface,
|
||||
const std::string & topic_name,
|
||||
const std::string & topic_type,
|
||||
const rclcpp::QoS & qos,
|
||||
const rclcpp::PublisherOptionsWithAllocator<AllocatorT> & options = (
|
||||
rclcpp::PublisherOptionsWithAllocator<AllocatorT>()
|
||||
)
|
||||
)
|
||||
{
|
||||
auto ts_lib = rclcpp::get_typesupport_library(topic_type, "rosidl_typesupport_cpp");
|
||||
auto pub = std::make_shared<GenericPublisher>(
|
||||
topics_interface->get_node_base_interface(),
|
||||
std::move(ts_lib),
|
||||
topic_name,
|
||||
topic_type,
|
||||
qos,
|
||||
options);
|
||||
topics_interface->add_publisher(pub, options.callback_group);
|
||||
return pub;
|
||||
}
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__CREATE_GENERIC_PUBLISHER_HPP_
|
||||
79
rclcpp/include/rclcpp/create_generic_subscription.hpp
Normal file
79
rclcpp/include/rclcpp/create_generic_subscription.hpp
Normal file
@@ -0,0 +1,79 @@
|
||||
// Copyright 2020, Apex.AI Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__CREATE_GENERIC_SUBSCRIPTION_HPP_
|
||||
#define RCLCPP__CREATE_GENERIC_SUBSCRIPTION_HPP_
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "rcl/subscription.h"
|
||||
#include "rclcpp/generic_subscription.hpp"
|
||||
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
#include "rclcpp/serialized_message.hpp"
|
||||
#include "rclcpp/subscription_options.hpp"
|
||||
#include "rclcpp/typesupport_helpers.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
/// Create and return a GenericSubscription.
|
||||
/**
|
||||
* The returned pointer will never be empty, but this function can throw various exceptions, for
|
||||
* instance when the message's package can not be found on the AMENT_PREFIX_PATH.
|
||||
*
|
||||
* \param topics_interface NodeTopicsInterface pointer used in parts of the setup.
|
||||
* \param topic_name Topic name
|
||||
* \param topic_type Topic type
|
||||
* \param qos %QoS settings
|
||||
* \param callback Callback for new messages of serialized form
|
||||
* \param options %Publisher options.
|
||||
* Not all publisher options are currently respected, the only relevant options for this
|
||||
* publisher are `event_callbacks`, `use_default_callbacks`, and `%callback_group`.
|
||||
*/
|
||||
template<typename AllocatorT = std::allocator<void>>
|
||||
std::shared_ptr<GenericSubscription> create_generic_subscription(
|
||||
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr topics_interface,
|
||||
const std::string & topic_name,
|
||||
const std::string & topic_type,
|
||||
const rclcpp::QoS & qos,
|
||||
std::function<void(std::shared_ptr<rclcpp::SerializedMessage>)> callback,
|
||||
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options = (
|
||||
rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>()
|
||||
)
|
||||
)
|
||||
{
|
||||
auto ts_lib = rclcpp::get_typesupport_library(
|
||||
topic_type, "rosidl_typesupport_cpp");
|
||||
|
||||
auto subscription = std::make_shared<GenericSubscription>(
|
||||
topics_interface->get_node_base_interface(),
|
||||
std::move(ts_lib),
|
||||
topic_name,
|
||||
topic_type,
|
||||
qos,
|
||||
callback,
|
||||
options);
|
||||
|
||||
topics_interface->add_subscription(subscription, options.callback_group);
|
||||
|
||||
return subscription;
|
||||
}
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__CREATE_GENERIC_SUBSCRIPTION_HPP_
|
||||
@@ -92,7 +92,7 @@ template<
|
||||
typename NodeT>
|
||||
std::shared_ptr<PublisherT>
|
||||
create_publisher(
|
||||
NodeT & node,
|
||||
NodeT && node,
|
||||
const std::string & topic_name,
|
||||
const rclcpp::QoS & qos,
|
||||
const rclcpp::PublisherOptionsWithAllocator<AllocatorT> & options = (
|
||||
|
||||
@@ -26,6 +26,32 @@
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
/// Create a service with a given type.
|
||||
/**
|
||||
* \param[in] node_base NodeBaseInterface implementation of the node on which
|
||||
* to create the service.
|
||||
* \param[in] node_services NodeServicesInterface implementation of the node on
|
||||
* which to create the service.
|
||||
* \param[in] service_name The name on which the service is accessible.
|
||||
* \param[in] callback The callback to call when the service gets a request.
|
||||
* \param[in] qos Quality of service profile for the service.
|
||||
* \param[in] group Callback group to handle the reply to service calls.
|
||||
* \return Shared pointer to the created service.
|
||||
*/
|
||||
template<typename ServiceT, typename CallbackT>
|
||||
typename rclcpp::Service<ServiceT>::SharedPtr
|
||||
create_service(
|
||||
std::shared_ptr<node_interfaces::NodeBaseInterface> node_base,
|
||||
std::shared_ptr<node_interfaces::NodeServicesInterface> node_services,
|
||||
const std::string & service_name,
|
||||
CallbackT && callback,
|
||||
const rclcpp::QoS & qos,
|
||||
rclcpp::CallbackGroup::SharedPtr group)
|
||||
{
|
||||
return create_service<ServiceT, CallbackT>(
|
||||
node_base, node_services, service_name,
|
||||
std::forward<CallbackT>(callback), qos.get_rmw_qos_profile(), group);
|
||||
}
|
||||
|
||||
/// Create a service with a given type.
|
||||
/// \internal
|
||||
|
||||
@@ -47,11 +47,11 @@ template<
|
||||
typename MessageT,
|
||||
typename CallbackT,
|
||||
typename AllocatorT,
|
||||
typename CallbackMessageT,
|
||||
typename SubscriptionT,
|
||||
typename MessageMemoryStrategyT,
|
||||
typename NodeParametersT,
|
||||
typename NodeTopicsT>
|
||||
typename NodeTopicsT,
|
||||
typename ROSMessageType = typename SubscriptionT::ROSMessageType>
|
||||
typename std::shared_ptr<SubscriptionT>
|
||||
create_subscription(
|
||||
NodeParametersT & node_parameters,
|
||||
@@ -70,7 +70,7 @@ create_subscription(
|
||||
using rclcpp::node_interfaces::get_node_topics_interface;
|
||||
auto node_topics_interface = get_node_topics_interface(node_topics);
|
||||
|
||||
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics<CallbackMessageT>>
|
||||
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics<ROSMessageType>>
|
||||
subscription_topic_stats = nullptr;
|
||||
|
||||
if (rclcpp::detail::resolve_enable_topic_statistics(
|
||||
@@ -92,11 +92,11 @@ create_subscription(
|
||||
qos);
|
||||
|
||||
subscription_topic_stats = std::make_shared<
|
||||
rclcpp::topic_statistics::SubscriptionTopicStatistics<CallbackMessageT>
|
||||
rclcpp::topic_statistics::SubscriptionTopicStatistics<ROSMessageType>
|
||||
>(node_topics_interface->get_node_base_interface()->get_name(), publisher);
|
||||
|
||||
std::weak_ptr<
|
||||
rclcpp::topic_statistics::SubscriptionTopicStatistics<CallbackMessageT>
|
||||
rclcpp::topic_statistics::SubscriptionTopicStatistics<ROSMessageType>
|
||||
> weak_subscription_topic_stats(subscription_topic_stats);
|
||||
auto sub_call_back = [weak_subscription_topic_stats]() {
|
||||
auto subscription_topic_stats = weak_subscription_topic_stats.lock();
|
||||
@@ -153,7 +153,6 @@ create_subscription(
|
||||
* \tparam MessageT
|
||||
* \tparam CallbackT
|
||||
* \tparam AllocatorT
|
||||
* \tparam CallbackMessageT
|
||||
* \tparam SubscriptionT
|
||||
* \tparam MessageMemoryStrategyT
|
||||
* \tparam NodeT
|
||||
@@ -171,13 +170,8 @@ template<
|
||||
typename MessageT,
|
||||
typename CallbackT,
|
||||
typename AllocatorT = std::allocator<void>,
|
||||
typename CallbackMessageT =
|
||||
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type,
|
||||
typename SubscriptionT = rclcpp::Subscription<CallbackMessageT, AllocatorT>,
|
||||
typename MessageMemoryStrategyT = rclcpp::message_memory_strategy::MessageMemoryStrategy<
|
||||
CallbackMessageT,
|
||||
AllocatorT
|
||||
>,
|
||||
typename SubscriptionT = rclcpp::Subscription<MessageT, AllocatorT>,
|
||||
typename MessageMemoryStrategyT = typename SubscriptionT::MessageMemoryStrategyType,
|
||||
typename NodeT>
|
||||
typename std::shared_ptr<SubscriptionT>
|
||||
create_subscription(
|
||||
@@ -194,7 +188,7 @@ create_subscription(
|
||||
)
|
||||
{
|
||||
return rclcpp::detail::create_subscription<
|
||||
MessageT, CallbackT, AllocatorT, CallbackMessageT, SubscriptionT, MessageMemoryStrategyT>(
|
||||
MessageT, CallbackT, AllocatorT, SubscriptionT, MessageMemoryStrategyT>(
|
||||
node, node, topic_name, qos, std::forward<CallbackT>(callback), options, msg_mem_strat);
|
||||
}
|
||||
|
||||
@@ -206,13 +200,8 @@ template<
|
||||
typename MessageT,
|
||||
typename CallbackT,
|
||||
typename AllocatorT = std::allocator<void>,
|
||||
typename CallbackMessageT =
|
||||
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type,
|
||||
typename SubscriptionT = rclcpp::Subscription<CallbackMessageT, AllocatorT>,
|
||||
typename MessageMemoryStrategyT = rclcpp::message_memory_strategy::MessageMemoryStrategy<
|
||||
CallbackMessageT,
|
||||
AllocatorT
|
||||
>>
|
||||
typename SubscriptionT = rclcpp::Subscription<MessageT, AllocatorT>,
|
||||
typename MessageMemoryStrategyT = typename SubscriptionT::MessageMemoryStrategyType>
|
||||
typename std::shared_ptr<SubscriptionT>
|
||||
create_subscription(
|
||||
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr & node_parameters,
|
||||
@@ -229,7 +218,7 @@ create_subscription(
|
||||
)
|
||||
{
|
||||
return rclcpp::detail::create_subscription<
|
||||
MessageT, CallbackT, AllocatorT, CallbackMessageT, SubscriptionT, MessageMemoryStrategyT>(
|
||||
MessageT, CallbackT, AllocatorT, SubscriptionT, MessageMemoryStrategyT>(
|
||||
node_parameters, node_topics, topic_name, qos,
|
||||
std::forward<CallbackT>(callback), options, msg_mem_strat);
|
||||
}
|
||||
|
||||
@@ -23,85 +23,29 @@
|
||||
|
||||
#include "rclcpp/duration.hpp"
|
||||
#include "rclcpp/node_interfaces/get_node_base_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/get_node_clock_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/get_node_timers_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_clock_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_timers_interface.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
/// Create a timer with a given clock
|
||||
/// \internal
|
||||
template<typename CallbackT>
|
||||
typename rclcpp::TimerBase::SharedPtr
|
||||
create_timer(
|
||||
std::shared_ptr<node_interfaces::NodeBaseInterface> node_base,
|
||||
std::shared_ptr<node_interfaces::NodeTimersInterface> node_timers,
|
||||
rclcpp::Clock::SharedPtr clock,
|
||||
rclcpp::Duration period,
|
||||
CallbackT && callback,
|
||||
rclcpp::CallbackGroup::SharedPtr group = nullptr)
|
||||
namespace detail
|
||||
{
|
||||
auto timer = rclcpp::GenericTimer<CallbackT>::make_shared(
|
||||
clock,
|
||||
period.to_chrono<std::chrono::nanoseconds>(),
|
||||
std::forward<CallbackT>(callback),
|
||||
node_base->get_context());
|
||||
|
||||
node_timers->add_timer(timer, group);
|
||||
return timer;
|
||||
}
|
||||
|
||||
/// Create a timer with a given clock
|
||||
template<typename NodeT, typename CallbackT>
|
||||
typename rclcpp::TimerBase::SharedPtr
|
||||
create_timer(
|
||||
NodeT node,
|
||||
rclcpp::Clock::SharedPtr clock,
|
||||
rclcpp::Duration period,
|
||||
CallbackT && callback,
|
||||
rclcpp::CallbackGroup::SharedPtr group = nullptr)
|
||||
{
|
||||
return create_timer(
|
||||
rclcpp::node_interfaces::get_node_base_interface(node),
|
||||
rclcpp::node_interfaces::get_node_timers_interface(node),
|
||||
clock,
|
||||
period,
|
||||
std::forward<CallbackT>(callback),
|
||||
group);
|
||||
}
|
||||
|
||||
/// Convenience method to create a timer with node resources.
|
||||
/// Perform a safe cast to a timer period in nanoseconds
|
||||
/**
|
||||
*
|
||||
* \tparam DurationRepT
|
||||
* \tparam DurationT
|
||||
* \tparam CallbackT
|
||||
* \param period period to execute callback. This duration must be 0 <= period < nanoseconds::max()
|
||||
* \param callback callback to execute via the timer period
|
||||
* \param group
|
||||
* \param node_base
|
||||
* \param node_timers
|
||||
* \return
|
||||
* \throws std::invalid argument if either node_base or node_timers
|
||||
* are null, or period is negative or too large
|
||||
* \return period, expressed as chrono::duration::nanoseconds
|
||||
* \throws std::invalid_argument if period is negative or too large
|
||||
*/
|
||||
template<typename DurationRepT, typename DurationT, typename CallbackT>
|
||||
typename rclcpp::WallTimer<CallbackT>::SharedPtr
|
||||
create_wall_timer(
|
||||
std::chrono::duration<DurationRepT, DurationT> period,
|
||||
CallbackT callback,
|
||||
rclcpp::CallbackGroup::SharedPtr group,
|
||||
node_interfaces::NodeBaseInterface * node_base,
|
||||
node_interfaces::NodeTimersInterface * node_timers)
|
||||
template<typename DurationRepT, typename DurationT>
|
||||
std::chrono::nanoseconds
|
||||
safe_cast_to_period_in_ns(std::chrono::duration<DurationRepT, DurationT> period)
|
||||
{
|
||||
if (node_base == nullptr) {
|
||||
throw std::invalid_argument{"input node_base cannot be null"};
|
||||
}
|
||||
|
||||
if (node_timers == nullptr) {
|
||||
throw std::invalid_argument{"input node_timers cannot be null"};
|
||||
}
|
||||
|
||||
if (period < std::chrono::duration<DurationRepT, DurationT>::zero()) {
|
||||
throw std::invalid_argument{"timer period cannot be negative"};
|
||||
}
|
||||
@@ -132,12 +76,135 @@ create_wall_timer(
|
||||
"Casting timer period to nanoseconds resulted in integer overflow."};
|
||||
}
|
||||
|
||||
return period_ns;
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
/// Create a timer with a given clock
|
||||
/// \internal
|
||||
template<typename CallbackT>
|
||||
typename rclcpp::TimerBase::SharedPtr
|
||||
create_timer(
|
||||
std::shared_ptr<node_interfaces::NodeBaseInterface> node_base,
|
||||
std::shared_ptr<node_interfaces::NodeTimersInterface> node_timers,
|
||||
rclcpp::Clock::SharedPtr clock,
|
||||
rclcpp::Duration period,
|
||||
CallbackT && callback,
|
||||
rclcpp::CallbackGroup::SharedPtr group = nullptr)
|
||||
{
|
||||
return create_timer(
|
||||
clock,
|
||||
period.to_chrono<std::chrono::nanoseconds>(),
|
||||
std::forward<CallbackT>(callback),
|
||||
group,
|
||||
node_base.get(),
|
||||
node_timers.get());
|
||||
}
|
||||
|
||||
/// Create a timer with a given clock
|
||||
template<typename NodeT, typename CallbackT>
|
||||
typename rclcpp::TimerBase::SharedPtr
|
||||
create_timer(
|
||||
NodeT node,
|
||||
rclcpp::Clock::SharedPtr clock,
|
||||
rclcpp::Duration period,
|
||||
CallbackT && callback,
|
||||
rclcpp::CallbackGroup::SharedPtr group = nullptr)
|
||||
{
|
||||
return create_timer(
|
||||
clock,
|
||||
period.to_chrono<std::chrono::nanoseconds>(),
|
||||
std::forward<CallbackT>(callback),
|
||||
group,
|
||||
rclcpp::node_interfaces::get_node_base_interface(node).get(),
|
||||
rclcpp::node_interfaces::get_node_timers_interface(node).get());
|
||||
}
|
||||
|
||||
/// Convenience method to create a general timer with node resources.
|
||||
/**
|
||||
*
|
||||
* \tparam DurationRepT
|
||||
* \tparam DurationT
|
||||
* \tparam CallbackT
|
||||
* \param clock clock to be used
|
||||
* \param period period to execute callback. This duration must be 0 <= period < nanoseconds::max()
|
||||
* \param callback callback to execute via the timer period
|
||||
* \param group callback group
|
||||
* \param node_base node base interface
|
||||
* \param node_timers node timer interface
|
||||
* \return shared pointer to a generic timer
|
||||
* \throws std::invalid_argument if either clock, node_base or node_timers
|
||||
* are nullptr, or period is negative or too large
|
||||
*/
|
||||
template<typename DurationRepT, typename DurationT, typename CallbackT>
|
||||
typename rclcpp::GenericTimer<CallbackT>::SharedPtr
|
||||
create_timer(
|
||||
rclcpp::Clock::SharedPtr clock,
|
||||
std::chrono::duration<DurationRepT, DurationT> period,
|
||||
CallbackT callback,
|
||||
rclcpp::CallbackGroup::SharedPtr group,
|
||||
node_interfaces::NodeBaseInterface * node_base,
|
||||
node_interfaces::NodeTimersInterface * node_timers)
|
||||
{
|
||||
if (clock == nullptr) {
|
||||
throw std::invalid_argument{"clock cannot be null"};
|
||||
}
|
||||
if (node_base == nullptr) {
|
||||
throw std::invalid_argument{"input node_base cannot be null"};
|
||||
}
|
||||
if (node_timers == nullptr) {
|
||||
throw std::invalid_argument{"input node_timers cannot be null"};
|
||||
}
|
||||
|
||||
const std::chrono::nanoseconds period_ns = detail::safe_cast_to_period_in_ns(period);
|
||||
|
||||
// Add a new generic timer.
|
||||
auto timer = rclcpp::GenericTimer<CallbackT>::make_shared(
|
||||
std::move(clock), period_ns, std::move(callback), node_base->get_context());
|
||||
node_timers->add_timer(timer, group);
|
||||
return timer;
|
||||
}
|
||||
|
||||
/// Convenience method to create a wall timer with node resources.
|
||||
/**
|
||||
*
|
||||
* \tparam DurationRepT
|
||||
* \tparam DurationT
|
||||
* \tparam CallbackT
|
||||
* \param period period to execute callback. This duration must be 0 <= period < nanoseconds::max()
|
||||
* \param callback callback to execute via the timer period
|
||||
* \param group callback group
|
||||
* \param node_base node base interface
|
||||
* \param node_timers node timer interface
|
||||
* \return shared pointer to a wall timer
|
||||
* \throws std::invalid_argument if either node_base or node_timers
|
||||
* are null, or period is negative or too large
|
||||
*/
|
||||
template<typename DurationRepT, typename DurationT, typename CallbackT>
|
||||
typename rclcpp::WallTimer<CallbackT>::SharedPtr
|
||||
create_wall_timer(
|
||||
std::chrono::duration<DurationRepT, DurationT> period,
|
||||
CallbackT callback,
|
||||
rclcpp::CallbackGroup::SharedPtr group,
|
||||
node_interfaces::NodeBaseInterface * node_base,
|
||||
node_interfaces::NodeTimersInterface * node_timers)
|
||||
{
|
||||
if (node_base == nullptr) {
|
||||
throw std::invalid_argument{"input node_base cannot be null"};
|
||||
}
|
||||
|
||||
if (node_timers == nullptr) {
|
||||
throw std::invalid_argument{"input node_timers cannot be null"};
|
||||
}
|
||||
|
||||
const std::chrono::nanoseconds period_ns = detail::safe_cast_to_period_in_ns(period);
|
||||
|
||||
// Add a new wall timer.
|
||||
auto timer = rclcpp::WallTimer<CallbackT>::make_shared(
|
||||
period_ns, std::move(callback), node_base->get_context());
|
||||
node_timers->add_timer(timer, group);
|
||||
return timer;
|
||||
}
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__CREATE_TIMER_HPP_
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
// Copyright 2021 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__DETAIL__ADD_GUARD_CONDITION_TO_RCL_WAIT_SET_HPP_
|
||||
#define RCLCPP__DETAIL__ADD_GUARD_CONDITION_TO_RCL_WAIT_SET_HPP_
|
||||
|
||||
#include "rclcpp/guard_condition.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
/// Adds the guard condition to a waitset
|
||||
/**
|
||||
* \param[in] wait_set reference to a wait set where to add the guard condition
|
||||
* \param[in] guard_condition reference to the guard_condition to be added
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_guard_condition_to_rcl_wait_set(
|
||||
rcl_wait_set_t & wait_set,
|
||||
const rclcpp::GuardCondition & guard_condition);
|
||||
|
||||
} // namespace detail
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__DETAIL__ADD_GUARD_CONDITION_TO_RCL_WAIT_SET_HPP_
|
||||
70
rclcpp/include/rclcpp/detail/cpp_callback_trampoline.hpp
Normal file
70
rclcpp/include/rclcpp/detail/cpp_callback_trampoline.hpp
Normal file
@@ -0,0 +1,70 @@
|
||||
// Copyright 2021 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__DETAIL__CPP_CALLBACK_TRAMPOLINE_HPP_
|
||||
#define RCLCPP__DETAIL__CPP_CALLBACK_TRAMPOLINE_HPP_
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
/// Trampoline pattern for wrapping std::function into C-style callbacks.
|
||||
/**
|
||||
* A common pattern in C is for a function to take a function pointer and a
|
||||
* void pointer for "user data" which is passed to the function pointer when it
|
||||
* is called from within C.
|
||||
*
|
||||
* It works by using the user data pointer to store a pointer to a
|
||||
* std::function instance.
|
||||
* So when called from C, this function will cast the user data to the right
|
||||
* std::function type and call it.
|
||||
*
|
||||
* This should allow you to use free functions, lambdas with and without
|
||||
* captures, and various kinds of std::bind instances.
|
||||
*
|
||||
* The interior of this function is likely to be executed within a C runtime,
|
||||
* so no exceptions should be thrown at this point, and doing so results in
|
||||
* undefined behavior.
|
||||
*
|
||||
* \tparam UserDataRealT Declared type of the passed function
|
||||
* \tparam UserDataT Deduced type based on what is passed for user data,
|
||||
* usually this type is either `void *` or `const void *`.
|
||||
* \tparam Args the arguments being passed to the callback
|
||||
* \tparam ReturnT the return type of this function and the callback, default void
|
||||
* \param user_data the function pointer, possibly type erased
|
||||
* \param args the arguments to be forwarded to the callback
|
||||
* \returns whatever the callback returns, if anything
|
||||
*/
|
||||
template<
|
||||
typename UserDataRealT,
|
||||
typename UserDataT,
|
||||
typename ... Args,
|
||||
typename ReturnT = void
|
||||
>
|
||||
ReturnT
|
||||
cpp_callback_trampoline(UserDataT user_data, Args ... args) noexcept
|
||||
{
|
||||
auto & actual_callback = *static_cast<const UserDataRealT *>(user_data);
|
||||
return actual_callback(args ...);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__DETAIL__CPP_CALLBACK_TRAMPOLINE_HPP_
|
||||
@@ -1,75 +0,0 @@
|
||||
// Copyright 2021 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__DETAIL__MUTEX_TWO_PRIORITIES_HPP_
|
||||
#define RCLCPP__DETAIL__MUTEX_TWO_PRIORITIES_HPP_
|
||||
|
||||
#include <mutex>
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
/// \internal A mutex that has two locking mechanism, one with higher priority than the other.
|
||||
/**
|
||||
* After the current mutex owner release the lock, a thread that used the high
|
||||
* priority mechanism will have priority over threads that used the low priority mechanism.
|
||||
*/
|
||||
class MutexTwoPriorities
|
||||
{
|
||||
public:
|
||||
class HighPriorityLockable
|
||||
{
|
||||
public:
|
||||
explicit HighPriorityLockable(MutexTwoPriorities & parent);
|
||||
|
||||
void lock();
|
||||
|
||||
void unlock();
|
||||
|
||||
private:
|
||||
MutexTwoPriorities & parent_;
|
||||
};
|
||||
|
||||
class LowPriorityLockable
|
||||
{
|
||||
public:
|
||||
explicit LowPriorityLockable(MutexTwoPriorities & parent);
|
||||
|
||||
void lock();
|
||||
|
||||
void unlock();
|
||||
|
||||
private:
|
||||
MutexTwoPriorities & parent_;
|
||||
};
|
||||
|
||||
HighPriorityLockable
|
||||
get_high_priority_lockable();
|
||||
|
||||
LowPriorityLockable
|
||||
get_low_priority_lockable();
|
||||
|
||||
private:
|
||||
// Implementation detail: the idea here is that only one low priority thread can be
|
||||
// trying to take the data_ mutex while the others are excluded by the barrier_ mutex.
|
||||
// All high priority threads are already waiting for the data_ mutex.
|
||||
std::mutex barrier_;
|
||||
std::mutex data_;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__DETAIL__MUTEX_TWO_PRIORITIES_HPP_
|
||||
@@ -104,6 +104,7 @@ declare_parameter_or_get(
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DOXYGEN_ONLY
|
||||
/// \internal Declare QoS parameters for the given entity.
|
||||
/**
|
||||
* \tparam NodeT Node pointer or reference type.
|
||||
@@ -116,12 +117,23 @@ declare_parameter_or_get(
|
||||
* \param default_qos User provided qos. It will be used as a default for the parameters declared.
|
||||
* \return qos profile based on the user provided parameter overrides.
|
||||
*/
|
||||
template<typename NodeT, typename EntityQosParametersTraits>
|
||||
rclcpp::QoS
|
||||
declare_qos_parameters(
|
||||
const ::rclcpp::QosOverridingOptions & options,
|
||||
NodeT & node,
|
||||
const std::string & topic_name,
|
||||
const ::rclcpp::QoS & default_qos,
|
||||
EntityQosParametersTraits);
|
||||
|
||||
#else
|
||||
|
||||
template<typename NodeT, typename EntityQosParametersTraits>
|
||||
std::enable_if_t<
|
||||
rclcpp::node_interfaces::has_node_parameters_interface<
|
||||
(rclcpp::node_interfaces::has_node_parameters_interface<
|
||||
decltype(std::declval<typename rcpputils::remove_pointer<NodeT>::type>())>::value ||
|
||||
std::is_same<typename std::decay_t<NodeT>,
|
||||
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr>::value,
|
||||
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr>::value),
|
||||
rclcpp::QoS>
|
||||
declare_qos_parameters(
|
||||
const ::rclcpp::QosOverridingOptions & options,
|
||||
@@ -204,6 +216,8 @@ declare_qos_parameters(
|
||||
return default_qos;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/// \internal Helper function to get a rmw qos policy value from a string.
|
||||
#define RCLCPP_DETAIL_APPLY_QOS_OVERRIDE_FROM_PARAMETER_STRING( \
|
||||
kind_lower, kind_upper, parameter_value, rclcpp_qos) \
|
||||
|
||||
@@ -0,0 +1,166 @@
|
||||
// Copyright 2021 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__DETAIL__SUBSCRIPTION_CALLBACK_TYPE_HELPER_HPP_
|
||||
#define RCLCPP__DETAIL__SUBSCRIPTION_CALLBACK_TYPE_HELPER_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
#include "rclcpp/function_traits.hpp"
|
||||
#include "rclcpp/message_info.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
/// Template metaprogramming helper used to resolve the callback argument into a std::function.
|
||||
/**
|
||||
* Sometimes the CallbackT is a std::function already, but it could also be a
|
||||
* function pointer, lambda, bind, or some variant of those.
|
||||
* In some cases, like a lambda where the arguments can be converted between one
|
||||
* another, e.g. std::function<void (shared_ptr<...>)> and
|
||||
* std::function<void (unique_ptr<...>)>, you need to make that not ambiguous
|
||||
* by checking the arguments independently using function traits rather than
|
||||
* rely on overloading the two std::function types.
|
||||
*
|
||||
* This issue, with the lambda's, can be demonstrated with this minimal program:
|
||||
*
|
||||
* \code{.cpp}
|
||||
* #include <functional>
|
||||
* #include <memory>
|
||||
*
|
||||
* void f(std::function<void (std::shared_ptr<int>)>) {}
|
||||
* void f(std::function<void (std::unique_ptr<int>)>) {}
|
||||
*
|
||||
* int main() {
|
||||
* // Fails to compile with an "ambiguous call" error.
|
||||
* f([](std::shared_ptr<int>){});
|
||||
*
|
||||
* // Works.
|
||||
* std::function<void (std::shared_ptr<int>)> cb = [](std::shared_ptr<int>){};
|
||||
* f(cb);
|
||||
* }
|
||||
* \endcode
|
||||
*
|
||||
* If this program ever starts working in a future version of C++, this class
|
||||
* may become redundant.
|
||||
*
|
||||
* This helper works by using SFINAE with rclcpp::function_traits::same_arguments<>
|
||||
* to narrow down the exact std::function<> type for the given CallbackT.
|
||||
*/
|
||||
template<typename MessageT, typename CallbackT, typename Enable = void>
|
||||
struct SubscriptionCallbackTypeHelper
|
||||
{
|
||||
using callback_type = typename rclcpp::function_traits::as_std_function<CallbackT>::type;
|
||||
};
|
||||
|
||||
template<typename MessageT, typename CallbackT>
|
||||
struct SubscriptionCallbackTypeHelper<
|
||||
MessageT,
|
||||
CallbackT,
|
||||
typename std::enable_if_t<
|
||||
rclcpp::function_traits::same_arguments<
|
||||
CallbackT,
|
||||
std::function<void(std::shared_ptr<const MessageT>)>
|
||||
>::value
|
||||
>
|
||||
>
|
||||
{
|
||||
using callback_type = std::function<void (std::shared_ptr<const MessageT>)>;
|
||||
};
|
||||
|
||||
template<typename MessageT, typename CallbackT>
|
||||
struct SubscriptionCallbackTypeHelper<
|
||||
MessageT,
|
||||
CallbackT,
|
||||
typename std::enable_if_t<
|
||||
rclcpp::function_traits::same_arguments<
|
||||
CallbackT,
|
||||
std::function<void(std::shared_ptr<const MessageT>, const rclcpp::MessageInfo &)>
|
||||
>::value
|
||||
>
|
||||
>
|
||||
{
|
||||
using callback_type =
|
||||
std::function<void (std::shared_ptr<const MessageT>, const rclcpp::MessageInfo &)>;
|
||||
};
|
||||
|
||||
template<typename MessageT, typename CallbackT>
|
||||
struct SubscriptionCallbackTypeHelper<
|
||||
MessageT,
|
||||
CallbackT,
|
||||
typename std::enable_if_t<
|
||||
rclcpp::function_traits::same_arguments<
|
||||
CallbackT,
|
||||
std::function<void(const std::shared_ptr<const MessageT> &)>
|
||||
>::value
|
||||
>
|
||||
>
|
||||
{
|
||||
using callback_type = std::function<void (const std::shared_ptr<const MessageT> &)>;
|
||||
};
|
||||
|
||||
template<typename MessageT, typename CallbackT>
|
||||
struct SubscriptionCallbackTypeHelper<
|
||||
MessageT,
|
||||
CallbackT,
|
||||
typename std::enable_if_t<
|
||||
rclcpp::function_traits::same_arguments<
|
||||
CallbackT,
|
||||
std::function<void(const std::shared_ptr<const MessageT> &, const rclcpp::MessageInfo &)>
|
||||
>::value
|
||||
>
|
||||
>
|
||||
{
|
||||
using callback_type =
|
||||
std::function<void (const std::shared_ptr<const MessageT> &, const rclcpp::MessageInfo &)>;
|
||||
};
|
||||
|
||||
template<typename MessageT, typename CallbackT>
|
||||
struct SubscriptionCallbackTypeHelper<
|
||||
MessageT,
|
||||
CallbackT,
|
||||
typename std::enable_if_t<
|
||||
rclcpp::function_traits::same_arguments<
|
||||
CallbackT,
|
||||
std::function<void(std::shared_ptr<MessageT>)>
|
||||
>::value
|
||||
>
|
||||
>
|
||||
{
|
||||
using callback_type = std::function<void (std::shared_ptr<MessageT>)>;
|
||||
};
|
||||
|
||||
template<typename MessageT, typename CallbackT>
|
||||
struct SubscriptionCallbackTypeHelper<
|
||||
MessageT,
|
||||
CallbackT,
|
||||
typename std::enable_if_t<
|
||||
rclcpp::function_traits::same_arguments<
|
||||
CallbackT,
|
||||
std::function<void(std::shared_ptr<MessageT>, const rclcpp::MessageInfo &)>
|
||||
>::value
|
||||
>
|
||||
>
|
||||
{
|
||||
using callback_type =
|
||||
std::function<void (std::shared_ptr<MessageT>, const rclcpp::MessageInfo &)>;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__DETAIL__SUBSCRIPTION_CALLBACK_TYPE_HELPER_HPP_
|
||||
47
rclcpp/include/rclcpp/detail/template_contains.hpp
Normal file
47
rclcpp/include/rclcpp/detail/template_contains.hpp
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright 2022 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__DETAIL__TEMPLATE_CONTAINS_HPP_
|
||||
#define RCLCPP__DETAIL__TEMPLATE_CONTAINS_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
/// Template meta-function that checks if a given T is contained in the list Us.
|
||||
template<typename T, typename ... Us>
|
||||
struct template_contains;
|
||||
|
||||
template<typename ... Args>
|
||||
inline constexpr bool template_contains_v = template_contains<Args ...>::value;
|
||||
|
||||
template<typename T, typename NextT, typename ... Us>
|
||||
struct template_contains<T, NextT, Us ...>
|
||||
{
|
||||
enum { value = (std::is_same_v<T, NextT>|| template_contains_v<T, Us ...>)};
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct template_contains<T>
|
||||
{
|
||||
enum { value = false };
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__DETAIL__TEMPLATE_CONTAINS_HPP_
|
||||
49
rclcpp/include/rclcpp/detail/template_unique.hpp
Normal file
49
rclcpp/include/rclcpp/detail/template_unique.hpp
Normal file
@@ -0,0 +1,49 @@
|
||||
// Copyright 2022 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__DETAIL__TEMPLATE_UNIQUE_HPP_
|
||||
#define RCLCPP__DETAIL__TEMPLATE_UNIQUE_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "rclcpp/detail/template_contains.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
/// Template meta-function that checks if a given list Ts contains unique types.
|
||||
template<typename ... Ts>
|
||||
struct template_unique;
|
||||
|
||||
template<typename ... Args>
|
||||
inline constexpr bool template_unique_v = template_unique<Args ...>::value;
|
||||
|
||||
template<typename NextT, typename ... Ts>
|
||||
struct template_unique<NextT, Ts ...>
|
||||
{
|
||||
enum { value = !template_contains_v<NextT, Ts ...>&& template_unique_v<Ts ...>};
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct template_unique<T>
|
||||
{
|
||||
enum { value = true };
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__DETAIL__TEMPLATE_UNIQUE_HPP_
|
||||
@@ -30,7 +30,7 @@ namespace detail
|
||||
|
||||
std::vector<std::string>
|
||||
get_unparsed_ros_arguments(
|
||||
int argc, char const * const argv[],
|
||||
int argc, char const * const * argv,
|
||||
rcl_arguments_t * arguments,
|
||||
rcl_allocator_t allocator);
|
||||
|
||||
|
||||
@@ -38,13 +38,6 @@ public:
|
||||
*/
|
||||
Duration(int32_t seconds, uint32_t nanoseconds);
|
||||
|
||||
/// Construct duration from the specified nanoseconds.
|
||||
[[deprecated(
|
||||
"Use Duration::from_nanoseconds instead or std::chrono_literals. For example:"
|
||||
"rclcpp::Duration::from_nanoseconds(int64_variable);"
|
||||
"rclcpp::Duration(0ns);")]]
|
||||
explicit Duration(rcl_duration_value_t nanoseconds);
|
||||
|
||||
/// Construct duration from the specified std::chrono::nanoseconds.
|
||||
explicit Duration(std::chrono::nanoseconds nanoseconds);
|
||||
|
||||
@@ -99,9 +92,13 @@ public:
|
||||
Duration
|
||||
operator+(const rclcpp::Duration & rhs) const;
|
||||
|
||||
Duration & operator+=(const rclcpp::Duration & rhs);
|
||||
|
||||
Duration
|
||||
operator-(const rclcpp::Duration & rhs) const;
|
||||
|
||||
Duration & operator-=(const rclcpp::Duration & rhs);
|
||||
|
||||
/// Get the maximum representable value.
|
||||
/**
|
||||
* \return the maximum representable value
|
||||
@@ -113,6 +110,9 @@ public:
|
||||
Duration
|
||||
operator*(double scale) const;
|
||||
|
||||
Duration &
|
||||
operator*=(double scale);
|
||||
|
||||
/// Get duration in nanosecods
|
||||
/**
|
||||
* \return the duration in nanoseconds as a rcl_duration_value_t.
|
||||
|
||||
176
rclcpp/include/rclcpp/dynamic_subscription.hpp
Normal file
176
rclcpp/include/rclcpp/dynamic_subscription.hpp
Normal file
@@ -0,0 +1,176 @@
|
||||
// Copyright 2022 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__DYNAMIC_SUBSCRIPTION_HPP_
|
||||
#define RCLCPP__DYNAMIC_SUBSCRIPTION_HPP_
|
||||
|
||||
#include <rosidl_dynamic_typesupport/identifier.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "rcpputils/shared_library.hpp"
|
||||
|
||||
#include "rclcpp/callback_group.hpp"
|
||||
#include "rclcpp/dynamic_typesupport/dynamic_message_type_support.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
#include "rclcpp/serialized_message.hpp"
|
||||
#include "rclcpp/subscription_base.hpp"
|
||||
#include "rclcpp/typesupport_helpers.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
/// %Subscription for messages whose type descriptions are obtained at runtime.
|
||||
/**
|
||||
* Since the type is not known at compile time, this is not a template, and the dynamic library
|
||||
* containing type support information has to be identified and loaded based on the type name.
|
||||
*
|
||||
* NOTE(methylDragon): No considerations for intra-process handling are made.
|
||||
*/
|
||||
class DynamicSubscription : public rclcpp::SubscriptionBase
|
||||
{
|
||||
public:
|
||||
// cppcheck-suppress unknownMacro
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(DynamicSubscription)
|
||||
|
||||
template<typename AllocatorT = std::allocator<void>>
|
||||
DynamicSubscription(
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||
rclcpp::dynamic_typesupport::DynamicMessageTypeSupport::SharedPtr type_support,
|
||||
const std::string & topic_name,
|
||||
const rclcpp::QoS & qos,
|
||||
std::function<void(
|
||||
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr,
|
||||
const rosidl_runtime_c__type_description__TypeDescription &
|
||||
)> callback,
|
||||
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options,
|
||||
bool use_take_dynamic_message = true)
|
||||
: SubscriptionBase(
|
||||
node_base,
|
||||
type_support->get_const_rosidl_message_type_support(),
|
||||
topic_name,
|
||||
options.to_rcl_subscription_options(
|
||||
qos),
|
||||
options.event_callbacks,
|
||||
options.use_default_callbacks,
|
||||
use_take_dynamic_message ? SubscriptionType::DYNAMIC_MESSAGE_DIRECT : SubscriptionType::DYNAMIC_MESSAGE_FROM_SERIALIZED), // NOLINT
|
||||
ts_(type_support),
|
||||
callback_(callback),
|
||||
serialization_support_(nullptr),
|
||||
dynamic_message_(nullptr),
|
||||
dynamic_message_type_(nullptr)
|
||||
{
|
||||
if (!type_support) {
|
||||
throw std::runtime_error("DynamicMessageTypeSupport cannot be nullptr!");
|
||||
}
|
||||
|
||||
if (type_support->get_const_rosidl_message_type_support().typesupport_identifier !=
|
||||
rosidl_get_dynamic_typesupport_identifier())
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"DynamicSubscription must use dynamic type introspection type support!");
|
||||
}
|
||||
|
||||
serialization_support_ = type_support->get_shared_dynamic_serialization_support();
|
||||
dynamic_message_type_ = type_support->get_shared_dynamic_message_type()->clone_shared();
|
||||
dynamic_message_ = type_support->get_shared_dynamic_message()->clone_shared();
|
||||
}
|
||||
|
||||
// TODO(methylDragon):
|
||||
/// Deferred type description constructor, only usable if the middleware implementation supports
|
||||
/// type discovery
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual ~DynamicSubscription() = default;
|
||||
|
||||
// Same as create_serialized_message() as the subscription is to serialized_messages only
|
||||
RCLCPP_PUBLIC
|
||||
std::shared_ptr<void> create_message() override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
std::shared_ptr<rclcpp::SerializedMessage> create_serialized_message() override;
|
||||
|
||||
/// Cast the message to a rclcpp::SerializedMessage and call the callback.
|
||||
RCLCPP_PUBLIC
|
||||
void handle_message(
|
||||
std::shared_ptr<void> & message, const rclcpp::MessageInfo & message_info) override;
|
||||
|
||||
/// Handle dispatching rclcpp::SerializedMessage to user callback.
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
handle_serialized_message(
|
||||
const std::shared_ptr<rclcpp::SerializedMessage> & serialized_message,
|
||||
const rclcpp::MessageInfo & message_info) override;
|
||||
|
||||
/// This function is currently not implemented.
|
||||
RCLCPP_PUBLIC
|
||||
void handle_loaned_message(
|
||||
void * loaned_message, const rclcpp::MessageInfo & message_info) override;
|
||||
|
||||
// Same as return_serialized_message() as the subscription is to serialized_messages only
|
||||
RCLCPP_PUBLIC
|
||||
void return_message(std::shared_ptr<void> & message) override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void return_serialized_message(std::shared_ptr<rclcpp::SerializedMessage> & message) override;
|
||||
|
||||
|
||||
// DYNAMIC TYPE ==================================================================================
|
||||
// TODO(methylDragon): Reorder later
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::dynamic_typesupport::DynamicMessageType::SharedPtr
|
||||
get_shared_dynamic_message_type() override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr get_shared_dynamic_message() override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::dynamic_typesupport::DynamicSerializationSupport::SharedPtr
|
||||
get_shared_dynamic_serialization_support() override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr create_dynamic_message() override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void return_dynamic_message(
|
||||
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message) override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void handle_dynamic_message(
|
||||
const rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message,
|
||||
const rclcpp::MessageInfo & message_info) override;
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(DynamicSubscription)
|
||||
|
||||
rclcpp::dynamic_typesupport::DynamicMessageTypeSupport::SharedPtr ts_;
|
||||
std::function<void(
|
||||
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr,
|
||||
const rosidl_runtime_c__type_description__TypeDescription &
|
||||
)> callback_;
|
||||
|
||||
rclcpp::dynamic_typesupport::DynamicSerializationSupport::SharedPtr serialization_support_;
|
||||
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr dynamic_message_;
|
||||
rclcpp::dynamic_typesupport::DynamicMessageType::SharedPtr dynamic_message_type_;
|
||||
};
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__DYNAMIC_SUBSCRIPTION_HPP_
|
||||
@@ -0,0 +1,327 @@
|
||||
// Copyright 2023 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DETAIL__DYNAMIC_MESSAGE_IMPL_HPP_
|
||||
#define RCLCPP__DYNAMIC_TYPESUPPORT__DETAIL__DYNAMIC_MESSAGE_IMPL_HPP_
|
||||
|
||||
#include <rosidl_dynamic_typesupport/types.h>
|
||||
#include <rosidl_dynamic_typesupport/api/dynamic_data.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
|
||||
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_HPP_
|
||||
#include "rclcpp/dynamic_typesupport/dynamic_message.hpp"
|
||||
#endif
|
||||
|
||||
|
||||
#define __DYNAMIC_MESSAGE_GET_VALUE_BY_ID_FN(ValueT, FunctionT) \
|
||||
template<> \
|
||||
ValueT \
|
||||
DynamicMessage::get_value<ValueT>(rosidl_dynamic_typesupport_member_id_t id) \
|
||||
{ \
|
||||
ValueT out; \
|
||||
rosidl_dynamic_typesupport_dynamic_data_get_ ## FunctionT ## _value( \
|
||||
&rosidl_dynamic_data_, id, &out); \
|
||||
return out; \
|
||||
}
|
||||
|
||||
#define __DYNAMIC_MESSAGE_GET_VALUE_BY_NAME_FN(ValueT, FunctionT) \
|
||||
template<> \
|
||||
ValueT \
|
||||
DynamicMessage::get_value<ValueT>(const std::string & name) \
|
||||
{ \
|
||||
return get_value<ValueT>(get_member_id(name)); \
|
||||
}
|
||||
|
||||
#define __DYNAMIC_MESSAGE_SET_VALUE_BY_ID_FN(ValueT, FunctionT) \
|
||||
template<> \
|
||||
void \
|
||||
DynamicMessage::set_value<ValueT>(rosidl_dynamic_typesupport_member_id_t id, ValueT value) \
|
||||
{ \
|
||||
rosidl_dynamic_typesupport_dynamic_data_set_ ## FunctionT ## _value( \
|
||||
&rosidl_dynamic_data_, id, value); \
|
||||
}
|
||||
|
||||
#define __DYNAMIC_MESSAGE_SET_VALUE_BY_NAME_FN(ValueT, FunctionT) \
|
||||
template<> \
|
||||
void \
|
||||
DynamicMessage::set_value<ValueT>(const std::string & name, ValueT value) \
|
||||
{ \
|
||||
set_value<ValueT>(get_member_id(name), value); \
|
||||
}
|
||||
|
||||
#define __DYNAMIC_MESSAGE_INSERT_VALUE(ValueT, FunctionT) \
|
||||
template<> \
|
||||
rosidl_dynamic_typesupport_member_id_t \
|
||||
DynamicMessage::insert_value<ValueT>(ValueT value) \
|
||||
{ \
|
||||
rosidl_dynamic_typesupport_member_id_t out; \
|
||||
rosidl_dynamic_typesupport_dynamic_data_insert_ ## FunctionT ## _value( \
|
||||
&rosidl_dynamic_data_, value, &out); \
|
||||
return out; \
|
||||
}
|
||||
|
||||
#define DYNAMIC_MESSAGE_DEFINITIONS(ValueT, FunctionT) \
|
||||
__DYNAMIC_MESSAGE_GET_VALUE_BY_ID_FN(ValueT, FunctionT) \
|
||||
__DYNAMIC_MESSAGE_GET_VALUE_BY_NAME_FN(ValueT, FunctionT) \
|
||||
__DYNAMIC_MESSAGE_SET_VALUE_BY_ID_FN(ValueT, FunctionT) \
|
||||
__DYNAMIC_MESSAGE_SET_VALUE_BY_NAME_FN(ValueT, FunctionT) \
|
||||
__DYNAMIC_MESSAGE_INSERT_VALUE(ValueT, FunctionT)
|
||||
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace dynamic_typesupport
|
||||
{
|
||||
|
||||
/**
|
||||
* Since we're in a ROS layer, these should support all ROS interface C++ types as found in:
|
||||
* https://docs.ros.org/en/rolling/Concepts/About-ROS-Interfaces.html
|
||||
*
|
||||
* Explicitly:
|
||||
* - Basic types: bool, byte, char
|
||||
* - Float types: float, double
|
||||
* - Int types: int8_t, int16_t, int32_t, int64_t
|
||||
* - Unsigned int types: uint8_t, uint16_t, uint32_t, uint64_t
|
||||
* - String types: std::string, std::u16string
|
||||
*/
|
||||
|
||||
DYNAMIC_MESSAGE_DEFINITIONS(bool, bool);
|
||||
// DYNAMIC_MESSAGE_DEFINITIONS(std::byte, byte);
|
||||
DYNAMIC_MESSAGE_DEFINITIONS(char, char);
|
||||
DYNAMIC_MESSAGE_DEFINITIONS(float, float32);
|
||||
DYNAMIC_MESSAGE_DEFINITIONS(double, float64);
|
||||
DYNAMIC_MESSAGE_DEFINITIONS(int8_t, int8);
|
||||
DYNAMIC_MESSAGE_DEFINITIONS(int16_t, int16);
|
||||
DYNAMIC_MESSAGE_DEFINITIONS(int32_t, int32);
|
||||
DYNAMIC_MESSAGE_DEFINITIONS(int64_t, int64);
|
||||
DYNAMIC_MESSAGE_DEFINITIONS(uint8_t, uint8);
|
||||
DYNAMIC_MESSAGE_DEFINITIONS(uint16_t, uint16);
|
||||
DYNAMIC_MESSAGE_DEFINITIONS(uint32_t, uint32);
|
||||
DYNAMIC_MESSAGE_DEFINITIONS(uint64_t, uint64);
|
||||
// DYNAMIC_MESSAGE_DEFINITIONS(std::string, std::string);
|
||||
// DYNAMIC_MESSAGE_DEFINITIONS(std::u16string, std::u16string);
|
||||
|
||||
// Byte and String getters have a different implementation and are defined below
|
||||
|
||||
|
||||
// BYTE ============================================================================================
|
||||
template<>
|
||||
std::byte
|
||||
DynamicMessage::get_value<std::byte>(rosidl_dynamic_typesupport_member_id_t id)
|
||||
{
|
||||
unsigned char out;
|
||||
rosidl_dynamic_typesupport_dynamic_data_get_byte_value(&get_rosidl_dynamic_data(), id, &out);
|
||||
return static_cast<std::byte>(out);
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
std::byte
|
||||
DynamicMessage::get_value<std::byte>(const std::string & name)
|
||||
{
|
||||
return get_value<std::byte>(get_member_id(name));
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
void
|
||||
DynamicMessage::set_value<std::byte>(
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::byte value)
|
||||
{
|
||||
rosidl_dynamic_typesupport_dynamic_data_set_byte_value(
|
||||
&rosidl_dynamic_data_, id, static_cast<unsigned char>(value));
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
void
|
||||
DynamicMessage::set_value<std::byte>(const std::string & name, const std::byte value)
|
||||
{
|
||||
set_value<std::byte>(get_member_id(name), value);
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
rosidl_dynamic_typesupport_member_id_t
|
||||
DynamicMessage::insert_value<std::byte>(const std::byte value)
|
||||
{
|
||||
rosidl_dynamic_typesupport_member_id_t out;
|
||||
rosidl_dynamic_typesupport_dynamic_data_insert_byte_value(
|
||||
&rosidl_dynamic_data_, static_cast<unsigned char>(value), &out);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
// STRINGS =========================================================================================
|
||||
template<>
|
||||
std::string
|
||||
DynamicMessage::get_value<std::string>(rosidl_dynamic_typesupport_member_id_t id)
|
||||
{
|
||||
size_t buf_length;
|
||||
char * buf = nullptr;
|
||||
rosidl_dynamic_typesupport_dynamic_data_get_string_value(
|
||||
&get_rosidl_dynamic_data(), id, &buf, &buf_length);
|
||||
auto out = std::string(buf, buf_length);
|
||||
delete buf;
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
std::u16string
|
||||
DynamicMessage::get_value<std::u16string>(rosidl_dynamic_typesupport_member_id_t id)
|
||||
{
|
||||
size_t buf_length;
|
||||
char16_t * buf = nullptr;
|
||||
rosidl_dynamic_typesupport_dynamic_data_get_wstring_value(
|
||||
&get_rosidl_dynamic_data(), id, &buf, &buf_length);
|
||||
auto out = std::u16string(buf, buf_length);
|
||||
delete buf;
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
std::string
|
||||
DynamicMessage::get_value<std::string>(const std::string & name)
|
||||
{
|
||||
return get_value<std::string>(get_member_id(name));
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
std::u16string
|
||||
DynamicMessage::get_value<std::u16string>(const std::string & name)
|
||||
{
|
||||
return get_value<std::u16string>(get_member_id(name));
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
void
|
||||
DynamicMessage::set_value<std::string>(
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::string value)
|
||||
{
|
||||
rosidl_dynamic_typesupport_dynamic_data_set_string_value(
|
||||
&rosidl_dynamic_data_, id, value.c_str(), value.size());
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
void
|
||||
DynamicMessage::set_value<std::u16string>(
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::u16string value)
|
||||
{
|
||||
rosidl_dynamic_typesupport_dynamic_data_set_wstring_value(
|
||||
&rosidl_dynamic_data_, id, value.c_str(), value.size());
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
void
|
||||
DynamicMessage::set_value<std::string>(const std::string & name, const std::string value)
|
||||
{
|
||||
set_value<std::string>(get_member_id(name), value);
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
void
|
||||
DynamicMessage::set_value<std::u16string>(const std::string & name, const std::u16string value)
|
||||
{
|
||||
set_value<std::u16string>(get_member_id(name), value);
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
rosidl_dynamic_typesupport_member_id_t
|
||||
DynamicMessage::insert_value<std::string>(const std::string value)
|
||||
{
|
||||
rosidl_dynamic_typesupport_member_id_t out;
|
||||
rosidl_dynamic_typesupport_dynamic_data_insert_string_value(
|
||||
&rosidl_dynamic_data_, value.c_str(), value.size(), &out);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
template<>
|
||||
rosidl_dynamic_typesupport_member_id_t
|
||||
DynamicMessage::insert_value<std::u16string>(const std::u16string value)
|
||||
{
|
||||
rosidl_dynamic_typesupport_member_id_t out;
|
||||
rosidl_dynamic_typesupport_dynamic_data_insert_wstring_value(
|
||||
&rosidl_dynamic_data_, value.c_str(), value.size(), &out);
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
// THROW FOR UNSUPPORTED TYPES =====================================================================
|
||||
template<typename ValueT>
|
||||
ValueT
|
||||
DynamicMessage::get_value(rosidl_dynamic_typesupport_member_id_t id)
|
||||
{
|
||||
throw rclcpp::exceptions::UnimplementedError("get_value is not implemented for input type");
|
||||
}
|
||||
|
||||
|
||||
template<typename ValueT>
|
||||
ValueT
|
||||
DynamicMessage::get_value(const std::string & name)
|
||||
{
|
||||
throw rclcpp::exceptions::UnimplementedError("get_value is not implemented for input type");
|
||||
}
|
||||
|
||||
|
||||
template<typename ValueT>
|
||||
void
|
||||
DynamicMessage::set_value(
|
||||
rosidl_dynamic_typesupport_member_id_t id, ValueT value)
|
||||
{
|
||||
throw rclcpp::exceptions::UnimplementedError("set_value is not implemented for input type");
|
||||
}
|
||||
|
||||
|
||||
template<typename ValueT>
|
||||
void
|
||||
DynamicMessage::set_value(const std::string & name, ValueT value)
|
||||
{
|
||||
throw rclcpp::exceptions::UnimplementedError("set_value is not implemented for input type");
|
||||
}
|
||||
|
||||
|
||||
template<typename ValueT>
|
||||
rosidl_dynamic_typesupport_member_id_t
|
||||
DynamicMessage::insert_value(ValueT value)
|
||||
{
|
||||
throw rclcpp::exceptions::UnimplementedError("insert_value is not implemented for input type");
|
||||
}
|
||||
|
||||
|
||||
} // namespace dynamic_typesupport
|
||||
} // namespace rclcpp
|
||||
|
||||
#undef __DYNAMIC_MESSAGE_GET_VALUE_BY_ID_FN
|
||||
#undef __DYNAMIC_MESSAGE_GET_VALUE_BY_NAME_FN
|
||||
#undef __DYNAMIC_MESSAGE_SET_VALUE_BY_ID_FN
|
||||
#undef __DYNAMIC_MESSAGE_SET_VALUE_BY_NAME_FN
|
||||
#undef __DYNAMIC_MESSAGE_INSERT_VALUE
|
||||
#undef DYNAMIC_MESSAGE_DEFINITIONS
|
||||
|
||||
#endif // RCLCPP__DYNAMIC_TYPESUPPORT__DETAIL__DYNAMIC_MESSAGE_IMPL_HPP_
|
||||
@@ -0,0 +1,189 @@
|
||||
// Copyright 2023 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DETAIL__DYNAMIC_MESSAGE_TYPE_BUILDER_IMPL_HPP_
|
||||
#define RCLCPP__DYNAMIC_TYPESUPPORT__DETAIL__DYNAMIC_MESSAGE_TYPE_BUILDER_IMPL_HPP_
|
||||
|
||||
#include <rosidl_dynamic_typesupport/types.h>
|
||||
#include <rosidl_dynamic_typesupport/api/dynamic_type.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
|
||||
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_BUILDER_HPP_
|
||||
#include "rclcpp/dynamic_typesupport/dynamic_message_type_builder.hpp"
|
||||
#endif
|
||||
|
||||
|
||||
#define __DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_MEMBER_FN(MemberT, FunctionT) \
|
||||
template<> \
|
||||
void \
|
||||
DynamicMessageTypeBuilder::add_member<MemberT>( \
|
||||
rosidl_dynamic_typesupport_member_id_t id, \
|
||||
const std::string & name, \
|
||||
const std::string & default_value) \
|
||||
{ \
|
||||
rosidl_dynamic_typesupport_dynamic_type_builder_add_ ## FunctionT ## _member( \
|
||||
&rosidl_dynamic_type_builder_, \
|
||||
id, name.c_str(), name.size(), default_value.c_str(), default_value.size()); \
|
||||
}
|
||||
|
||||
#define __DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_ARRAY_MEMBER_FN(MemberT, FunctionT) \
|
||||
template<> \
|
||||
void \
|
||||
DynamicMessageTypeBuilder::add_array_member<MemberT>( \
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, \
|
||||
size_t array_length, \
|
||||
const std::string & default_value) \
|
||||
{ \
|
||||
rosidl_dynamic_typesupport_dynamic_type_builder_add_ ## FunctionT ## _array_member( \
|
||||
&rosidl_dynamic_type_builder_, \
|
||||
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(), \
|
||||
array_length); \
|
||||
}
|
||||
|
||||
#define __DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_UNBOUNDED_SEQUENCE_MEMBER_FN(MemberT, FunctionT) \
|
||||
template<> \
|
||||
void \
|
||||
DynamicMessageTypeBuilder::add_unbounded_sequence_member<MemberT>( \
|
||||
rosidl_dynamic_typesupport_member_id_t id, \
|
||||
const std::string & name, \
|
||||
const std::string & default_value) \
|
||||
{ \
|
||||
rosidl_dynamic_typesupport_dynamic_type_builder_add_ ## FunctionT ## \
|
||||
_unbounded_sequence_member( \
|
||||
&rosidl_dynamic_type_builder_, \
|
||||
id, name.c_str(), name.size(), default_value.c_str(), default_value.size()); \
|
||||
}
|
||||
|
||||
#define __DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_BOUNDED_SEQUENCE_MEMBER_FN(MemberT, FunctionT) \
|
||||
template<> \
|
||||
void \
|
||||
DynamicMessageTypeBuilder::add_bounded_sequence_member<MemberT>( \
|
||||
rosidl_dynamic_typesupport_member_id_t id, \
|
||||
const std::string & name, \
|
||||
size_t sequence_bound, \
|
||||
const std::string & default_value) \
|
||||
{ \
|
||||
rosidl_dynamic_typesupport_dynamic_type_builder_add_ ## FunctionT ## _bounded_sequence_member( \
|
||||
&rosidl_dynamic_type_builder_, \
|
||||
id, name.c_str(), name.size(), default_value.c_str(), default_value.size(), \
|
||||
sequence_bound); \
|
||||
}
|
||||
|
||||
#define DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(MemberT, FunctionT) \
|
||||
__DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_MEMBER_FN(MemberT, FunctionT) \
|
||||
__DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_ARRAY_MEMBER_FN(MemberT, FunctionT) \
|
||||
__DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_UNBOUNDED_SEQUENCE_MEMBER_FN(MemberT, FunctionT) \
|
||||
__DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_BOUNDED_SEQUENCE_MEMBER_FN(MemberT, FunctionT) \
|
||||
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace dynamic_typesupport
|
||||
{
|
||||
|
||||
/**
|
||||
* Since we're in a ROS layer, these should support all ROS interface C++ types as found in:
|
||||
* https://docs.ros.org/en/rolling/Concepts/About-ROS-Interfaces.html
|
||||
*
|
||||
* Explicitly:
|
||||
* - Basic types: bool, byte, char
|
||||
* - Float types: float, double
|
||||
* - Int types: int8_t, int16_t, int32_t, int64_t
|
||||
* - Unsigned int types: uint8_t, uint16_t, uint32_t, uint64_t
|
||||
* - String types: std::string, std::u16string
|
||||
*/
|
||||
|
||||
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(bool, bool);
|
||||
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(std::byte, byte);
|
||||
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(char, char);
|
||||
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(float, float32);
|
||||
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(double, float64);
|
||||
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(int8_t, int8);
|
||||
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(int16_t, int16);
|
||||
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(int32_t, int32);
|
||||
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(int64_t, int64);
|
||||
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(uint8_t, uint8);
|
||||
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(uint16_t, uint16);
|
||||
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(uint32_t, uint32);
|
||||
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(uint64_t, uint64);
|
||||
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(std::string, string);
|
||||
DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS(std::u16string, wstring);
|
||||
|
||||
|
||||
// THROW FOR UNSUPPORTED TYPES =====================================================================
|
||||
template<typename MemberT>
|
||||
void
|
||||
DynamicMessageTypeBuilder::add_member(
|
||||
rosidl_dynamic_typesupport_member_id_t id,
|
||||
const std::string & name,
|
||||
const std::string & default_value)
|
||||
{
|
||||
throw rclcpp::exceptions::UnimplementedError(
|
||||
"add_member is not implemented for input type");
|
||||
}
|
||||
|
||||
|
||||
template<typename MemberT>
|
||||
void
|
||||
DynamicMessageTypeBuilder::add_array_member(
|
||||
rosidl_dynamic_typesupport_member_id_t id,
|
||||
const std::string & name,
|
||||
size_t array_length, const std::string & default_value)
|
||||
{
|
||||
throw rclcpp::exceptions::UnimplementedError(
|
||||
"add_array_member is not implemented for input type");
|
||||
}
|
||||
|
||||
|
||||
template<typename MemberT>
|
||||
void
|
||||
DynamicMessageTypeBuilder::add_unbounded_sequence_member(
|
||||
rosidl_dynamic_typesupport_member_id_t id,
|
||||
const std::string & name,
|
||||
const std::string & default_value)
|
||||
{
|
||||
throw rclcpp::exceptions::UnimplementedError(
|
||||
"add_unbounded_sequence_member is not implemented for input type");
|
||||
}
|
||||
|
||||
|
||||
template<typename MemberT>
|
||||
void
|
||||
DynamicMessageTypeBuilder::add_bounded_sequence_member(
|
||||
rosidl_dynamic_typesupport_member_id_t id,
|
||||
const std::string & name,
|
||||
size_t sequence_bound,
|
||||
const std::string & default_value)
|
||||
{
|
||||
throw rclcpp::exceptions::UnimplementedError(
|
||||
"add_bounded_sequence_member is not implemented for input type");
|
||||
}
|
||||
|
||||
|
||||
} // namespace dynamic_typesupport
|
||||
} // namespace rclcpp
|
||||
|
||||
#undef __DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_MEMBER_FN
|
||||
#undef __DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_ARRAY_MEMBER_FN
|
||||
#undef __DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_UNBOUNDED_SEQUENCE_MEMBER_FN
|
||||
#undef __DYNAMIC_MESSAGE_TYPE_BUILDER_ADD_BOUNDED_SEQUENCE_MEMBER_FN
|
||||
#undef DYNAMIC_MESSAGE_TYPE_BUILDER_DEFINITIONS
|
||||
|
||||
#endif // RCLCPP__DYNAMIC_TYPESUPPORT__DETAIL__DYNAMIC_MESSAGE_TYPE_BUILDER_IMPL_HPP_
|
||||
432
rclcpp/include/rclcpp/dynamic_typesupport/dynamic_message.hpp
Normal file
432
rclcpp/include/rclcpp/dynamic_typesupport/dynamic_message.hpp
Normal file
@@ -0,0 +1,432 @@
|
||||
// Copyright 2023 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_HPP_
|
||||
#define RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_HPP_
|
||||
|
||||
#include <rcl/allocator.h>
|
||||
#include <rcl/types.h>
|
||||
#include <rosidl_dynamic_typesupport/types.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "rclcpp/dynamic_typesupport/dynamic_message_type.hpp"
|
||||
#include "rclcpp/dynamic_typesupport/dynamic_serialization_support.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace dynamic_typesupport
|
||||
{
|
||||
|
||||
class DynamicMessageType;
|
||||
class DynamicMessageTypeBuilder;
|
||||
|
||||
/// Utility wrapper class for rosidl_dynamic_typesupport_dynamic_data_t
|
||||
/**
|
||||
* This class:
|
||||
* - Exposes getter methods for the struct
|
||||
* - Exposes the underlying serialization support API
|
||||
*
|
||||
* Ownership:
|
||||
* - This class borrows the rosidl_dynamic_typesupport_serialization_support_t stored in the passed
|
||||
* DynamicSerializationSupport. So it cannot outlive the DynamicSerializationSupport.
|
||||
* - The DynamicSerializationSupport's rosidl_dynamic_typesupport_serialization_support_t pointer
|
||||
* must point to the same location in memory as the stored raw pointer!
|
||||
*
|
||||
* Note: This class is meant to map to the lower level rosidl_dynamic_typesupport_dynamic_data_t,
|
||||
* even though rosidl_dynamic_typesupport_dynamic_data_t is equivalent to
|
||||
* rosidl_dynamic_typesupport_dynamic_data_t, exposing the fundamental methods available to
|
||||
* rosidl_dynamic_typesupport_dynamic_data_t, allowing the user to access the data's fields.
|
||||
*/
|
||||
class DynamicMessage : public std::enable_shared_from_this<DynamicMessage>
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_ALIASES_ONLY(DynamicMessage)
|
||||
|
||||
// CONSTRUCTION ==================================================================================
|
||||
// Most constructors require a passed in DynamicSerializationSupport::SharedPtr, to extend the
|
||||
// lifetime of the serialization support (if the constructor cannot otherwise get it from args).
|
||||
//
|
||||
// In cases where a dynamic data pointer is passed, the serialization support composed by
|
||||
// the data should be the exact same object managed by the DynamicSerializationSupport,
|
||||
// otherwise the lifetime management will not work properly.
|
||||
|
||||
/// Construct a new DynamicMessage with the provided dynamic type builder, using its allocator
|
||||
RCLCPP_PUBLIC
|
||||
explicit DynamicMessage(std::shared_ptr<DynamicMessageTypeBuilder> dynamic_type_builder);
|
||||
|
||||
/// Construct a new DynamicMessage with the provided dynamic type builder and allocator
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessage(
|
||||
std::shared_ptr<DynamicMessageTypeBuilder> dynamic_type_builder,
|
||||
rcl_allocator_t allocator);
|
||||
|
||||
/// Construct a new DynamicMessage with the provided dynamic type, using its allocator
|
||||
RCLCPP_PUBLIC
|
||||
explicit DynamicMessage(std::shared_ptr<DynamicMessageType> dynamic_type);
|
||||
|
||||
/// Construct a new DynamicMessage with the provided dynamic type and allocator
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessage(
|
||||
std::shared_ptr<DynamicMessageType> dynamic_type,
|
||||
rcl_allocator_t allocator);
|
||||
|
||||
/// Assume ownership of struct
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessage(
|
||||
DynamicSerializationSupport::SharedPtr serialization_support,
|
||||
rosidl_dynamic_typesupport_dynamic_data_t && rosidl_dynamic_data);
|
||||
|
||||
/// Loaning constructor
|
||||
/// Must only be called with a rosidl dynaimc data object obtained from loaning!
|
||||
// NOTE(methylDragon): I'd put this in protected, but I need this exposed to
|
||||
// enable_shared_from_this...
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessage(
|
||||
DynamicMessage::SharedPtr parent_data,
|
||||
rosidl_dynamic_typesupport_dynamic_data_t && rosidl_loaned_data);
|
||||
|
||||
// NOTE(methylDragon): Deliberately no constructor from description to nudge users towards using
|
||||
// construction from dynamic type/builder, which is more efficient
|
||||
|
||||
/// Move constructor
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessage(DynamicMessage && other) noexcept;
|
||||
|
||||
/// Move assignment
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessage & operator=(DynamicMessage && other) noexcept;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual ~DynamicMessage();
|
||||
|
||||
|
||||
// GETTERS =======================================================================================
|
||||
RCLCPP_PUBLIC
|
||||
const std::string
|
||||
get_serialization_library_identifier() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
const std::string
|
||||
get_name() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
rosidl_dynamic_typesupport_dynamic_data_t &
|
||||
get_rosidl_dynamic_data();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
const rosidl_dynamic_typesupport_dynamic_data_t &
|
||||
get_rosidl_dynamic_data() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
DynamicSerializationSupport::SharedPtr
|
||||
get_shared_dynamic_serialization_support();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
DynamicSerializationSupport::ConstSharedPtr
|
||||
get_shared_dynamic_serialization_support() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
size_t
|
||||
get_item_count() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
rosidl_dynamic_typesupport_member_id_t
|
||||
get_member_id(size_t index) const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
rosidl_dynamic_typesupport_member_id_t
|
||||
get_member_id(const std::string & name) const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
rosidl_dynamic_typesupport_member_id_t
|
||||
get_array_index(size_t index) const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
rosidl_dynamic_typesupport_member_id_t
|
||||
get_array_index(const std::string & name) const;
|
||||
|
||||
|
||||
// METHODS =======================================================================================
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessage
|
||||
clone(rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessage::SharedPtr
|
||||
clone_shared(rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessage
|
||||
init_from_type(
|
||||
DynamicMessageType & type, rcl_allocator_t allocator = rcl_get_default_allocator()) const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessage::SharedPtr
|
||||
init_from_type_shared(
|
||||
DynamicMessageType & type, rcl_allocator_t allocator = rcl_get_default_allocator()) const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
equals(const DynamicMessage & other) const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessage::SharedPtr
|
||||
loan_value(
|
||||
rosidl_dynamic_typesupport_member_id_t id,
|
||||
rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessage::SharedPtr
|
||||
loan_value(
|
||||
const std::string & name,
|
||||
rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
clear_all_values();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
clear_nonkey_values();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
clear_value(rosidl_dynamic_typesupport_member_id_t id);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
clear_value(const std::string & name);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
clear_sequence();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
rosidl_dynamic_typesupport_member_id_t
|
||||
insert_sequence_data();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
remove_sequence_data(rosidl_dynamic_typesupport_member_id_t index);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
serialize(rcl_serialized_message_t & buffer);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
deserialize(rcl_serialized_message_t & buffer);
|
||||
|
||||
|
||||
// MEMBER ACCESS TEMPLATES =======================================================================
|
||||
/**
|
||||
* Since we're in a ROS layer, these should support all ROS interface C++ types as found in:
|
||||
* https://docs.ros.org/en/rolling/Concepts/About-ROS-Interfaces.html
|
||||
*
|
||||
* Explicitly:
|
||||
* - Basic types: bool, byte, char
|
||||
* - Float types: float, double
|
||||
* - Int types: int8_t, int16_t, int32_t, int64_t
|
||||
* - Unsigned int types: uint8_t, uint16_t, uint32_t, uint64_t
|
||||
* - String types: std::string, std::u16string
|
||||
*/
|
||||
|
||||
template<typename ValueT>
|
||||
ValueT
|
||||
get_value(rosidl_dynamic_typesupport_member_id_t id);
|
||||
|
||||
template<typename ValueT>
|
||||
ValueT
|
||||
get_value(const std::string & name);
|
||||
|
||||
template<typename ValueT>
|
||||
void
|
||||
set_value(rosidl_dynamic_typesupport_member_id_t id, ValueT value);
|
||||
|
||||
template<typename ValueT>
|
||||
void
|
||||
set_value(const std::string & name, ValueT value);
|
||||
|
||||
template<typename ValueT>
|
||||
rosidl_dynamic_typesupport_member_id_t
|
||||
insert_value(ValueT value);
|
||||
|
||||
|
||||
// FIXED STRING MEMBER ACCESS ====================================================================
|
||||
RCLCPP_PUBLIC
|
||||
const std::string
|
||||
get_fixed_string_value(rosidl_dynamic_typesupport_member_id_t id, size_t string_length);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
const std::string
|
||||
get_fixed_string_value(const std::string & name, size_t string_length);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
const std::u16string
|
||||
get_fixed_wstring_value(rosidl_dynamic_typesupport_member_id_t id, size_t wstring_length);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
const std::u16string
|
||||
get_fixed_wstring_value(const std::string & name, size_t wstring_length);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
set_fixed_string_value(
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::string value, size_t string_length);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
set_fixed_string_value(const std::string & name, const std::string value, size_t string_length);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
set_fixed_wstring_value(
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::u16string value, size_t wstring_length);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
set_fixed_wstring_value(
|
||||
const std::string & name, const std::u16string value, size_t wstring_length);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
rosidl_dynamic_typesupport_member_id_t
|
||||
insert_fixed_string_value(const std::string value, size_t string_length);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
rosidl_dynamic_typesupport_member_id_t
|
||||
insert_fixed_wstring_value(const std::u16string value, size_t wstring_length);
|
||||
|
||||
|
||||
// BOUNDED STRING MEMBER ACCESS ==================================================================
|
||||
RCLCPP_PUBLIC
|
||||
const std::string
|
||||
get_bounded_string_value(rosidl_dynamic_typesupport_member_id_t id, size_t string_bound);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
const std::string
|
||||
get_bounded_string_value(const std::string & name, size_t string_bound);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
const std::u16string
|
||||
get_bounded_wstring_value(rosidl_dynamic_typesupport_member_id_t id, size_t wstring_bound);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
const std::u16string
|
||||
get_bounded_wstring_value(const std::string & name, size_t wstring_bound);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
set_bounded_string_value(
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::string value, size_t string_bound);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
set_bounded_string_value(const std::string & name, const std::string value, size_t string_bound);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
set_bounded_wstring_value(
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::u16string value, size_t wstring_bound);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
set_bounded_wstring_value(
|
||||
const std::string & name, const std::u16string value, size_t wstring_bound);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
rosidl_dynamic_typesupport_member_id_t
|
||||
insert_bounded_string_value(const std::string value, size_t string_bound);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
rosidl_dynamic_typesupport_member_id_t
|
||||
insert_bounded_wstring_value(const std::u16string value, size_t wstring_bound);
|
||||
|
||||
|
||||
// NESTED MEMBER ACCESS ==========================================================================
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessage
|
||||
get_complex_value(
|
||||
rosidl_dynamic_typesupport_member_id_t id,
|
||||
rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessage
|
||||
get_complex_value(
|
||||
const std::string & name,
|
||||
rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessage::SharedPtr
|
||||
get_complex_value_shared(
|
||||
rosidl_dynamic_typesupport_member_id_t id,
|
||||
rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessage::SharedPtr
|
||||
get_complex_value_shared(
|
||||
const std::string & name,
|
||||
rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
set_complex_value(rosidl_dynamic_typesupport_member_id_t id, DynamicMessage & value);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
set_complex_value(const std::string & name, DynamicMessage & value);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
rosidl_dynamic_typesupport_member_id_t
|
||||
insert_complex_value_copy(const DynamicMessage & value);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
rosidl_dynamic_typesupport_member_id_t
|
||||
insert_complex_value(DynamicMessage & value);
|
||||
|
||||
protected:
|
||||
// NOTE(methylDragon):
|
||||
// This is just here to extend the lifetime of the serialization support
|
||||
// It isn't actually used by the builder since the builder should compose its own support
|
||||
//
|
||||
// ... Though ideally it should be the exact same support as the one stored in the
|
||||
// DynamicSerializationSupport
|
||||
DynamicSerializationSupport::SharedPtr serialization_support_;
|
||||
|
||||
rosidl_dynamic_typesupport_dynamic_data_t rosidl_dynamic_data_;
|
||||
bool is_loaned_;
|
||||
|
||||
// Used for returning the loaned value, and lifetime management
|
||||
DynamicMessage::SharedPtr parent_data_;
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(DynamicMessage)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessage();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
match_serialization_support_(
|
||||
const DynamicSerializationSupport & serialization_support,
|
||||
const rosidl_dynamic_typesupport_dynamic_data_t & dynamic_data);
|
||||
};
|
||||
|
||||
} // namespace dynamic_typesupport
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_HPP_
|
||||
@@ -0,0 +1,197 @@
|
||||
// Copyright 2023 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_HPP_
|
||||
#define RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_HPP_
|
||||
|
||||
#include <rcl/allocator.h>
|
||||
#include <rosidl_dynamic_typesupport/types.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "rclcpp/dynamic_typesupport/dynamic_serialization_support.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace dynamic_typesupport
|
||||
{
|
||||
|
||||
class DynamicMessage;
|
||||
class DynamicMessageTypeBuilder;
|
||||
|
||||
/// Utility wrapper class for `rosidl_dynamic_typesupport_dynamic_type_t`
|
||||
/**
|
||||
* This class:
|
||||
* - Exposes getter methods for the struct
|
||||
* - Exposes the underlying serialization support API
|
||||
*
|
||||
* Ownership:
|
||||
* - This class borrows the `rosidl_dynamic_typesupport_serialization_support_t` stored in the
|
||||
* passed `DynamicSerializationSupport`.
|
||||
* So it cannot outlive the `DynamicSerializationSupport`.
|
||||
* - The `DynamicSerializationSupport`'s `rosidl_dynamic_typesupport_serialization_support_t`
|
||||
* pointer must point to the same location in memory as the stored raw pointer!
|
||||
*
|
||||
* This class is meant to map to the lower level `rosidl_dynamic_typesupport_dynamic_type_t`,
|
||||
* which can be constructed via `DynamicMessageTypeBuilder`, which maps to
|
||||
* `rosidl_dynamic_typesupport_dynamic_type_builder_t`.
|
||||
*
|
||||
* The usual method of obtaining a `DynamicMessageType` is through construction of
|
||||
* `rosidl_message_type_support_t` via `rcl_dynamic_message_type_support_handle_create()`, then
|
||||
* taking ownership of its contents. But `DynamicMessageTypeBuilder` can also be used to obtain
|
||||
* `DynamicMessageType` by constructing it bottom-up instead, since it exposes the lower_level
|
||||
* rosidl methods.
|
||||
*/
|
||||
class DynamicMessageType : public std::enable_shared_from_this<DynamicMessageType>
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_ALIASES_ONLY(DynamicMessageType)
|
||||
|
||||
// CONSTRUCTION ==================================================================================
|
||||
// Most constructors require a passed in `DynamicSerializationSupport::SharedPtr`, to extend the
|
||||
// lifetime of the serialization support (if the constructor cannot otherwise get it from args).
|
||||
//
|
||||
// In cases where a dynamic type pointer is passed, the serialization support composed by
|
||||
// the type should be the exact same object managed by the `DynamicSerializationSupport`,
|
||||
// otherwise the lifetime management will not work properly.
|
||||
|
||||
/// Construct a new `DynamicMessageType` with the provided dynamic type builder,
|
||||
/// using its allocator
|
||||
RCLCPP_PUBLIC
|
||||
explicit DynamicMessageType(std::shared_ptr<DynamicMessageTypeBuilder> dynamic_type_builder);
|
||||
|
||||
/// Construct a new `DynamicMessageType` with the provided dynamic type builder and allocator
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessageType(
|
||||
std::shared_ptr<DynamicMessageTypeBuilder> dynamic_type_builder,
|
||||
rcl_allocator_t allocator);
|
||||
|
||||
/// Assume ownership of struct
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessageType(
|
||||
DynamicSerializationSupport::SharedPtr serialization_support,
|
||||
rosidl_dynamic_typesupport_dynamic_type_t && rosidl_dynamic_type);
|
||||
|
||||
/// From description
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessageType(
|
||||
DynamicSerializationSupport::SharedPtr serialization_support,
|
||||
const rosidl_runtime_c__type_description__TypeDescription & description,
|
||||
rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||
|
||||
/// Move constructor
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessageType(DynamicMessageType && other) noexcept;
|
||||
|
||||
/// Move assignment
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessageType & operator=(DynamicMessageType && other) noexcept;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual ~DynamicMessageType();
|
||||
|
||||
/// Swaps the serialization support if `serialization_support` is populated
|
||||
/**
|
||||
* The user can call this with another description to reconfigure the type without changing the
|
||||
* serialization support
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
init_from_description(
|
||||
const rosidl_runtime_c__type_description__TypeDescription & description,
|
||||
rcl_allocator_t allocator = rcl_get_default_allocator(),
|
||||
DynamicSerializationSupport::SharedPtr serialization_support = nullptr);
|
||||
|
||||
// GETTERS =======================================================================================
|
||||
RCLCPP_PUBLIC
|
||||
const std::string
|
||||
get_serialization_library_identifier() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
const std::string
|
||||
get_name() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
size_t
|
||||
get_member_count() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
rosidl_dynamic_typesupport_dynamic_type_t &
|
||||
get_rosidl_dynamic_type();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
const rosidl_dynamic_typesupport_dynamic_type_t &
|
||||
get_rosidl_dynamic_type() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
DynamicSerializationSupport::SharedPtr
|
||||
get_shared_dynamic_serialization_support();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
DynamicSerializationSupport::ConstSharedPtr
|
||||
get_shared_dynamic_serialization_support() const;
|
||||
|
||||
|
||||
// METHODS =======================================================================================
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessageType
|
||||
clone(rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessageType::SharedPtr
|
||||
clone_shared(rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
equals(const DynamicMessageType & other) const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessage
|
||||
build_dynamic_message(rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
std::shared_ptr<DynamicMessage>
|
||||
build_dynamic_message_shared(rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||
|
||||
protected:
|
||||
// NOTE(methylDragon):
|
||||
// This is just here to extend the lifetime of the serialization support
|
||||
// It isn't actually used by the builder since the builder should compose its own support
|
||||
//
|
||||
// ... Though ideally it should be the exact same support as the one stored in the
|
||||
// `DynamicSerializationSupport`
|
||||
DynamicSerializationSupport::SharedPtr serialization_support_;
|
||||
|
||||
rosidl_dynamic_typesupport_dynamic_type_t rosidl_dynamic_type_;
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(DynamicMessageType)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessageType();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
match_serialization_support_(
|
||||
const DynamicSerializationSupport & serialization_support,
|
||||
const rosidl_dynamic_typesupport_dynamic_type_t & rosidl_dynamic_type);
|
||||
};
|
||||
|
||||
} // namespace dynamic_typesupport
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_HPP_
|
||||
@@ -0,0 +1,409 @@
|
||||
// Copyright 2023 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_BUILDER_HPP_
|
||||
#define RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_BUILDER_HPP_
|
||||
|
||||
#include <rcl/allocator.h>
|
||||
#include <rosidl_dynamic_typesupport/types.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "rclcpp/dynamic_typesupport/dynamic_serialization_support.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace dynamic_typesupport
|
||||
{
|
||||
|
||||
class DynamicMessage;
|
||||
class DynamicMessageType;
|
||||
|
||||
/// Utility wrapper class for `rosidl_dynamic_typesupport_dynamic_type_builder_t *`
|
||||
/**
|
||||
* This class:
|
||||
* - Manages the lifetime of the raw pointer.
|
||||
* - Exposes getter methods to get the raw pointer and shared pointers
|
||||
* - Exposes the underlying serialization support API
|
||||
*
|
||||
* Ownership:
|
||||
* - This class borrows the rosidl_dynamic_typesupport_serialization_support_t stored in the passed
|
||||
* `DynamicSerializationSupport`.
|
||||
* So it cannot outlive the `DynamicSerializationSupport`.
|
||||
* - The `DynamicSerializationSupport`'s `rosidl_dynamic_typesupport_serialization_support_t`
|
||||
* pointer must point to the same location in memory as the stored raw pointer!
|
||||
*
|
||||
* This class is meant to map to rosidl_dynamic_typesupport_dynamic_type_builder_t, facilitating the
|
||||
* construction of dynamic types bottom-up in the C++ layer.
|
||||
*
|
||||
* The usual method of obtaining a `DynamicMessageType` is through construction of
|
||||
* `rosidl_message_type_support_t` via `rcl_dynamic_message_type_support_handle_create()`, then
|
||||
* taking ownership of its contents.
|
||||
* But `DynamicMessageTypeBuilder` can also be used to obtain `DynamicMessageType` by constructing
|
||||
* it bottom-up instead, since it exposes the lower_level rosidl methods.
|
||||
*/
|
||||
class DynamicMessageTypeBuilder : public std::enable_shared_from_this<DynamicMessageTypeBuilder>
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_ALIASES_ONLY(DynamicMessageTypeBuilder)
|
||||
|
||||
// CONSTRUCTION ==================================================================================
|
||||
// All constructors require a passed in `DynamicSerializationSupport::SharedPtr`, to extend the
|
||||
// lifetime of the serialization support.
|
||||
//
|
||||
// In cases where a dynamic type builder pointer is passed, the serialization support composed by
|
||||
// the builder should be the exact same object managed by the `DynamicSerializationSupport`,
|
||||
// otherwise the lifetime management will not work properly.
|
||||
|
||||
/// Construct a new `DynamicMessageTypeBuilder` with the provided serialization support using its
|
||||
/// allocator
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessageTypeBuilder(
|
||||
DynamicSerializationSupport::SharedPtr serialization_support,
|
||||
const std::string & name);
|
||||
|
||||
/// Construct a new `DynamicMessageTypeBuilder` with the provided serialization support and
|
||||
/// allocator
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessageTypeBuilder(
|
||||
DynamicSerializationSupport::SharedPtr serialization_support,
|
||||
const std::string & name,
|
||||
rcl_allocator_t allocator);
|
||||
|
||||
/// Assume ownership of struct
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessageTypeBuilder(
|
||||
DynamicSerializationSupport::SharedPtr serialization_support,
|
||||
rosidl_dynamic_typesupport_dynamic_type_builder_t && dynamic_type_builder);
|
||||
|
||||
/// From description
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessageTypeBuilder(
|
||||
DynamicSerializationSupport::SharedPtr serialization_support,
|
||||
const rosidl_runtime_c__type_description__TypeDescription & description,
|
||||
rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||
|
||||
/// Move constructor
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessageTypeBuilder(DynamicMessageTypeBuilder && other) noexcept;
|
||||
|
||||
/// Move assignment
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessageTypeBuilder & operator=(DynamicMessageTypeBuilder && other) noexcept;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual ~DynamicMessageTypeBuilder();
|
||||
|
||||
/// Swaps the serialization support if serialization_support is populated
|
||||
/**
|
||||
* The user can call this with another description to reconfigure the type without changing the
|
||||
* serialization support
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
init_from_description(
|
||||
const rosidl_runtime_c__type_description__TypeDescription & description,
|
||||
rcl_allocator_t allocator = rcl_get_default_allocator(),
|
||||
DynamicSerializationSupport::SharedPtr serialization_support = nullptr);
|
||||
|
||||
|
||||
// GETTERS =======================================================================================
|
||||
RCLCPP_PUBLIC
|
||||
const std::string
|
||||
get_serialization_library_identifier() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
const std::string
|
||||
get_name() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
rosidl_dynamic_typesupport_dynamic_type_builder_t &
|
||||
get_rosidl_dynamic_type_builder();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
const rosidl_dynamic_typesupport_dynamic_type_builder_t &
|
||||
get_rosidl_dynamic_type_builder() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
DynamicSerializationSupport::SharedPtr
|
||||
get_shared_dynamic_serialization_support();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
DynamicSerializationSupport::ConstSharedPtr
|
||||
get_shared_dynamic_serialization_support() const;
|
||||
|
||||
|
||||
// METHODS =======================================================================================
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
set_name(const std::string & name);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessageTypeBuilder
|
||||
clone(rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessageTypeBuilder::SharedPtr
|
||||
clone_shared(rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
clear(rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessage
|
||||
build_dynamic_message(rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessage::SharedPtr
|
||||
build_dynamic_message_shared(rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessageType
|
||||
build_dynamic_message_type(rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessageType::SharedPtr
|
||||
build_dynamic_message_type_shared(rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||
|
||||
|
||||
// ADD MEMBERS TEMPLATES =========================================================================
|
||||
/**
|
||||
* Since we're in a ROS layer, these should support all ROS interface C++ types as found in:
|
||||
* https://docs.ros.org/en/rolling/Concepts/About-ROS-Interfaces.html
|
||||
*
|
||||
* Explicitly:
|
||||
* - Basic types: bool, byte, char
|
||||
* - Float types: float, double
|
||||
* - Int types: int8_t, int16_t, int32_t, int64_t
|
||||
* - Unsigned int types: uint8_t, uint16_t, uint32_t, uint64_t
|
||||
* - String types: std::string, std::u16string
|
||||
*/
|
||||
|
||||
template<typename MemberT>
|
||||
void
|
||||
add_member(
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||
const std::string & default_value = "");
|
||||
|
||||
template<typename MemberT>
|
||||
void
|
||||
add_array_member(
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t array_length,
|
||||
const std::string & default_value = "");
|
||||
|
||||
template<typename MemberT>
|
||||
void
|
||||
add_unbounded_sequence_member(
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||
const std::string & default_value = "");
|
||||
|
||||
template<typename MemberT>
|
||||
void
|
||||
add_bounded_sequence_member(
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t sequence_bound,
|
||||
const std::string & default_value = "");
|
||||
|
||||
|
||||
// ADD FIXED STRING MEMBERS ======================================================================
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_fixed_string_member(
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t string_length,
|
||||
const std::string & default_value = "");
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_fixed_wstring_member(
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t wstring_length,
|
||||
const std::string & default_value = "");
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_fixed_string_array_member(
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||
size_t string_length, size_t array_length, const std::string & default_value = "");
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_fixed_wstring_array_member(
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||
size_t wstring_length, size_t array_length, const std::string & default_value = "");
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_fixed_string_unbounded_sequence_member(
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t string_length,
|
||||
const std::string & default_value = "");
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_fixed_wstring_unbounded_sequence_member(
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t wstring_length,
|
||||
const std::string & default_value = "");
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_fixed_string_bounded_sequence_member(
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||
size_t string_length, size_t sequence_bound, const std::string & default_value = "");
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_fixed_wstring_bounded_sequence_member(
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||
size_t wstring_length, size_t sequence_bound, const std::string & default_value = "");
|
||||
|
||||
|
||||
// ADD BOUNDED STRING MEMBERS ====================================================================
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_bounded_string_member(
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t string_bound,
|
||||
const std::string & default_value = "");
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_bounded_wstring_member(
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t wstring_bound,
|
||||
const std::string & default_value = "");
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_bounded_string_array_member(
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||
size_t string_bound, size_t array_length, const std::string & default_value = "");
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_bounded_wstring_array_member(
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||
size_t wstring_bound, size_t array_length, const std::string & default_value = "");
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_bounded_string_unbounded_sequence_member(
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t string_bound,
|
||||
const std::string & default_value = "");
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_bounded_wstring_unbounded_sequence_member(
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::string & name, size_t wstring_bound,
|
||||
const std::string & default_value = "");
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_bounded_string_bounded_sequence_member(
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||
size_t string_bound, size_t sequence_bound, const std::string & default_value = "");
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_bounded_wstring_bounded_sequence_member(
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||
size_t wstring_bound, size_t sequence_bound, const std::string & default_value = "");
|
||||
|
||||
|
||||
// ADD NESTED MEMBERS ============================================================================
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_complex_member(
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||
DynamicMessageType & nested_type, const std::string & default_value = "");
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_complex_array_member(
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||
DynamicMessageType & nested_type, size_t array_length, const std::string & default_value = "");
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_complex_unbounded_sequence_member(
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||
DynamicMessageType & nested_type, const std::string & default_value = "");
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_complex_bounded_sequence_member(
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||
DynamicMessageType & nested_type, size_t sequence_bound,
|
||||
const std::string & default_value = "");
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_complex_member_builder(
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||
DynamicMessageTypeBuilder & nested_type_builder, const std::string & default_value = "");
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_complex_array_member_builder(
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||
DynamicMessageTypeBuilder & nested_type_builder, size_t array_length,
|
||||
const std::string & default_value = "");
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_complex_unbounded_sequence_member_builder(
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||
DynamicMessageTypeBuilder & nested_type_builder, const std::string & default_value = "");
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_complex_bounded_sequence_member_builder(
|
||||
rosidl_dynamic_typesupport_member_id_t id, const std::string & name,
|
||||
DynamicMessageTypeBuilder & nested_type_builder, size_t sequence_bound,
|
||||
const std::string & default_value = "");
|
||||
|
||||
protected:
|
||||
// NOTE(methylDragon):
|
||||
// This is just here to extend the lifetime of the serialization support
|
||||
// It isn't actually used by the builder since the builder should compose its own support
|
||||
//
|
||||
// ... Though ideally it should be the exact same support as the one stored in the
|
||||
// `DynamicSerializationSupport`
|
||||
DynamicSerializationSupport::SharedPtr serialization_support_;
|
||||
|
||||
rosidl_dynamic_typesupport_dynamic_type_builder_t rosidl_dynamic_type_builder_;
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(DynamicMessageTypeBuilder)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessageTypeBuilder();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
init_from_serialization_support_(
|
||||
DynamicSerializationSupport::SharedPtr serialization_support,
|
||||
const std::string & name,
|
||||
rcl_allocator_t allocator);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
match_serialization_support_(
|
||||
const DynamicSerializationSupport & serialization_support,
|
||||
const rosidl_dynamic_typesupport_dynamic_type_builder_t & dynamic_type_builder);
|
||||
};
|
||||
|
||||
} // namespace dynamic_typesupport
|
||||
} // namespace rclcpp
|
||||
|
||||
|
||||
#endif // RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_BUILDER_HPP_
|
||||
@@ -0,0 +1,166 @@
|
||||
// Copyright 2023 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_SUPPORT_HPP_
|
||||
#define RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_SUPPORT_HPP_
|
||||
|
||||
#include <rcl/allocator.h>
|
||||
|
||||
#include <rosidl_dynamic_typesupport/dynamic_message_type_support_struct.h>
|
||||
#include <rosidl_dynamic_typesupport/types.h>
|
||||
#include <rosidl_runtime_c/message_type_support_struct.h>
|
||||
#include <rosidl_runtime_c/type_description/type_description__struct.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "rclcpp/dynamic_typesupport/dynamic_message.hpp"
|
||||
#include "rclcpp/dynamic_typesupport/dynamic_message_type.hpp"
|
||||
#include "rclcpp/dynamic_typesupport/dynamic_serialization_support.hpp"
|
||||
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace dynamic_typesupport
|
||||
{
|
||||
|
||||
/// Utility wrapper class for `rosidl_message_type_support_t` containing managed
|
||||
/// instances of the typesupport handle impl.
|
||||
/**
|
||||
*
|
||||
* NOTE: This class is the recommended way to obtain the dynamic message type
|
||||
* support struct, instead of `rcl_dynamic_message_type_support_handle_init()`,
|
||||
* because this class will manage the lifetimes for you.
|
||||
*
|
||||
* Do NOT call rcl_dynamic_message_type_support_handle_fini
|
||||
*
|
||||
* This class:
|
||||
* - Exposes getter methods for the struct
|
||||
* - Stores shared pointers to wrapper classes that expose the underlying
|
||||
* serialization support API
|
||||
*
|
||||
* Ownership:
|
||||
* - This class, similarly to the `rosidl_dynamic_typesupport_serialization_support_t`, must outlive
|
||||
* all downstream usages of the serialization support.
|
||||
*/
|
||||
class DynamicMessageTypeSupport : public std::enable_shared_from_this<DynamicMessageTypeSupport>
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_ALIASES_ONLY(DynamicMessageTypeSupport)
|
||||
|
||||
// CONSTRUCTION ==================================================================================
|
||||
/// From description
|
||||
/// Does NOT take ownership of the description (copies instead.)
|
||||
/// Constructs type support top-down (calling `rcl_dynamic_message_type_support_handle_create()`)
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessageTypeSupport(
|
||||
const rosidl_runtime_c__type_description__TypeDescription & description,
|
||||
const std::string & serialization_library_name = "",
|
||||
rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||
|
||||
/// From description, for provided serialization support
|
||||
/// Does NOT take ownership of the description (copies instead.)
|
||||
/// Constructs type support top-down (calling `rosidl_dynamic_message_type_support_handle_init()`)
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessageTypeSupport(
|
||||
DynamicSerializationSupport::SharedPtr serialization_support,
|
||||
const rosidl_runtime_c__type_description__TypeDescription & description,
|
||||
rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||
|
||||
/// Assume ownership of managed types
|
||||
/// Does NOT take ownership of the description (copies instead.)
|
||||
///
|
||||
/// The serialization support used to construct all managed SharedPtrs must match.
|
||||
/// The structure of the provided `description` must match the `dynamic_message_type`
|
||||
/// The structure of the provided `dynamic_message_type` must match the `dynamic_message
|
||||
///
|
||||
/// In this case, the user would have constructed the type support bototm-up (by creating the
|
||||
/// respective dynamic members.)
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessageTypeSupport(
|
||||
DynamicSerializationSupport::SharedPtr serialization_support,
|
||||
DynamicMessageType::SharedPtr dynamic_message_type,
|
||||
DynamicMessage::SharedPtr dynamic_message,
|
||||
const rosidl_runtime_c__type_description__TypeDescription & description,
|
||||
rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual ~DynamicMessageTypeSupport();
|
||||
|
||||
|
||||
// GETTERS =======================================================================================
|
||||
RCLCPP_PUBLIC
|
||||
const std::string
|
||||
get_serialization_library_identifier() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
const rosidl_message_type_support_t &
|
||||
get_const_rosidl_message_type_support();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
const rosidl_message_type_support_t &
|
||||
get_const_rosidl_message_type_support() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
const rosidl_runtime_c__type_description__TypeDescription &
|
||||
get_rosidl_runtime_c_type_description() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
DynamicSerializationSupport::SharedPtr
|
||||
get_shared_dynamic_serialization_support();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
DynamicSerializationSupport::ConstSharedPtr
|
||||
get_shared_dynamic_serialization_support() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessageType::SharedPtr
|
||||
get_shared_dynamic_message_type();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessageType::ConstSharedPtr
|
||||
get_shared_dynamic_message_type() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessage::SharedPtr
|
||||
get_shared_dynamic_message();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessage::ConstSharedPtr
|
||||
get_shared_dynamic_message() const;
|
||||
|
||||
protected:
|
||||
RCLCPP_DISABLE_COPY(DynamicMessageTypeSupport)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
rosidl_message_type_support_t &
|
||||
get_rosidl_message_type_support();
|
||||
|
||||
private:
|
||||
RCLCPP_PUBLIC
|
||||
DynamicMessageTypeSupport();
|
||||
|
||||
DynamicSerializationSupport::SharedPtr serialization_support_;
|
||||
DynamicMessageType::SharedPtr dynamic_message_type_;
|
||||
DynamicMessage::SharedPtr dynamic_message_;
|
||||
|
||||
rosidl_message_type_support_t rosidl_message_type_support_;
|
||||
};
|
||||
|
||||
} // namespace dynamic_typesupport
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_MESSAGE_TYPE_SUPPORT_HPP_
|
||||
@@ -0,0 +1,98 @@
|
||||
// Copyright 2023 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_SERIALIZATION_SUPPORT_HPP_
|
||||
#define RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_SERIALIZATION_SUPPORT_HPP_
|
||||
|
||||
#include <rcl/allocator.h>
|
||||
#include <rosidl_dynamic_typesupport/api/serialization_support.h>
|
||||
#include <rosidl_dynamic_typesupport/types.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace dynamic_typesupport
|
||||
{
|
||||
|
||||
/// Utility wrapper class for rosidl_dynamic_typesupport_serialization_support_t
|
||||
/**
|
||||
* This class:
|
||||
* - Exposes getter methods for the struct
|
||||
* - Exposes the underlying serialization support API
|
||||
*
|
||||
* Ownership:
|
||||
* - This class, similarly to the rosidl_dynamic_typesupport_serialization_support_t, must outlive
|
||||
* all downstream usages of the serialization support.
|
||||
*/
|
||||
class DynamicSerializationSupport : public std::enable_shared_from_this<DynamicSerializationSupport>
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_ALIASES_ONLY(DynamicSerializationSupport)
|
||||
|
||||
// CONSTRUCTION ==================================================================================
|
||||
RCLCPP_PUBLIC
|
||||
explicit DynamicSerializationSupport(rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||
|
||||
/// Get the rmw middleware implementation specific serialization support (configured by name)
|
||||
RCLCPP_PUBLIC
|
||||
DynamicSerializationSupport(
|
||||
const std::string & serialization_library_name,
|
||||
rcl_allocator_t allocator = rcl_get_default_allocator());
|
||||
|
||||
/// Assume ownership of struct
|
||||
RCLCPP_PUBLIC
|
||||
explicit DynamicSerializationSupport(
|
||||
rosidl_dynamic_typesupport_serialization_support_t && rosidl_serialization_support);
|
||||
|
||||
/// Move constructor
|
||||
RCLCPP_PUBLIC
|
||||
DynamicSerializationSupport(DynamicSerializationSupport && other) noexcept;
|
||||
|
||||
/// Move assignment
|
||||
RCLCPP_PUBLIC
|
||||
DynamicSerializationSupport & operator=(DynamicSerializationSupport && other) noexcept;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual ~DynamicSerializationSupport();
|
||||
|
||||
|
||||
// GETTERS =======================================================================================
|
||||
RCLCPP_PUBLIC
|
||||
const std::string
|
||||
get_serialization_library_identifier() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
rosidl_dynamic_typesupport_serialization_support_t &
|
||||
get_rosidl_serialization_support();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
const rosidl_dynamic_typesupport_serialization_support_t &
|
||||
get_rosidl_serialization_support() const;
|
||||
|
||||
protected:
|
||||
RCLCPP_DISABLE_COPY(DynamicSerializationSupport)
|
||||
|
||||
private:
|
||||
rosidl_dynamic_typesupport_serialization_support_t rosidl_serialization_support_;
|
||||
};
|
||||
|
||||
} // namespace dynamic_typesupport
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__DYNAMIC_TYPESUPPORT__DYNAMIC_SERIALIZATION_SUPPORT_HPP_
|
||||
311
rclcpp/include/rclcpp/event_handler.hpp
Normal file
311
rclcpp/include/rclcpp/event_handler.hpp
Normal file
@@ -0,0 +1,311 @@
|
||||
// Copyright 2019 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__EVENT_HANDLER_HPP_
|
||||
#define RCLCPP__EVENT_HANDLER_HPP_
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include "rcl/error_handling.h"
|
||||
#include "rcl/event_callback.h"
|
||||
#include "rmw/impl/cpp/demangle.hpp"
|
||||
#include "rmw/incompatible_qos_events_statuses.h"
|
||||
#include "rmw/events_statuses/incompatible_type.h"
|
||||
|
||||
#include "rcutils/logging_macros.h"
|
||||
|
||||
#include "rclcpp/detail/cpp_callback_trampoline.hpp"
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
#include "rclcpp/function_traits.hpp"
|
||||
#include "rclcpp/logging.hpp"
|
||||
#include "rclcpp/waitable.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
using QOSDeadlineRequestedInfo = rmw_requested_deadline_missed_status_t;
|
||||
using QOSDeadlineOfferedInfo = rmw_offered_deadline_missed_status_t;
|
||||
using QOSLivelinessChangedInfo = rmw_liveliness_changed_status_t;
|
||||
using QOSLivelinessLostInfo = rmw_liveliness_lost_status_t;
|
||||
using QOSMessageLostInfo = rmw_message_lost_status_t;
|
||||
using QOSOfferedIncompatibleQoSInfo = rmw_offered_qos_incompatible_event_status_t;
|
||||
using QOSRequestedIncompatibleQoSInfo = rmw_requested_qos_incompatible_event_status_t;
|
||||
|
||||
using IncompatibleTypeInfo = rmw_incompatible_type_status_t;
|
||||
using MatchedInfo = rmw_matched_status_t;
|
||||
|
||||
using QOSDeadlineRequestedCallbackType = std::function<void (QOSDeadlineRequestedInfo &)>;
|
||||
using QOSDeadlineOfferedCallbackType = std::function<void (QOSDeadlineOfferedInfo &)>;
|
||||
using QOSLivelinessChangedCallbackType = std::function<void (QOSLivelinessChangedInfo &)>;
|
||||
using QOSLivelinessLostCallbackType = std::function<void (QOSLivelinessLostInfo &)>;
|
||||
using QOSMessageLostCallbackType = std::function<void (QOSMessageLostInfo &)>;
|
||||
using QOSOfferedIncompatibleQoSCallbackType = std::function<void (QOSOfferedIncompatibleQoSInfo &)>;
|
||||
using QOSRequestedIncompatibleQoSCallbackType =
|
||||
std::function<void (QOSRequestedIncompatibleQoSInfo &)>;
|
||||
|
||||
using IncompatibleTypeCallbackType = std::function<void (IncompatibleTypeInfo &)>;
|
||||
using PublisherMatchedCallbackType = std::function<void (MatchedInfo &)>;
|
||||
using SubscriptionMatchedCallbackType = std::function<void (MatchedInfo &)>;
|
||||
|
||||
/// Contains callbacks for various types of events a Publisher can receive from the middleware.
|
||||
struct PublisherEventCallbacks
|
||||
{
|
||||
QOSDeadlineOfferedCallbackType deadline_callback;
|
||||
QOSLivelinessLostCallbackType liveliness_callback;
|
||||
QOSOfferedIncompatibleQoSCallbackType incompatible_qos_callback;
|
||||
IncompatibleTypeCallbackType incompatible_type_callback;
|
||||
PublisherMatchedCallbackType matched_callback;
|
||||
};
|
||||
|
||||
/// Contains callbacks for non-message events that a Subscription can receive from the middleware.
|
||||
struct SubscriptionEventCallbacks
|
||||
{
|
||||
QOSDeadlineRequestedCallbackType deadline_callback;
|
||||
QOSLivelinessChangedCallbackType liveliness_callback;
|
||||
QOSRequestedIncompatibleQoSCallbackType incompatible_qos_callback;
|
||||
QOSMessageLostCallbackType message_lost_callback;
|
||||
IncompatibleTypeCallbackType incompatible_type_callback;
|
||||
SubscriptionMatchedCallbackType matched_callback;
|
||||
};
|
||||
|
||||
class UnsupportedEventTypeException : public exceptions::RCLErrorBase, public std::runtime_error
|
||||
{
|
||||
public:
|
||||
RCLCPP_PUBLIC
|
||||
UnsupportedEventTypeException(
|
||||
rcl_ret_t ret,
|
||||
const rcl_error_state_t * error_state,
|
||||
const std::string & prefix);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
UnsupportedEventTypeException(
|
||||
const exceptions::RCLErrorBase & base_exc,
|
||||
const std::string & prefix);
|
||||
};
|
||||
|
||||
class EventHandlerBase : public Waitable
|
||||
{
|
||||
public:
|
||||
enum class EntityType : std::size_t
|
||||
{
|
||||
Event,
|
||||
};
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual ~EventHandlerBase();
|
||||
|
||||
/// Get the number of ready events
|
||||
RCLCPP_PUBLIC
|
||||
size_t
|
||||
get_number_of_ready_events() override;
|
||||
|
||||
/// Add the Waitable to a wait set.
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_to_wait_set(rcl_wait_set_t * wait_set) override;
|
||||
|
||||
/// Check if the Waitable is ready.
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
is_ready(rcl_wait_set_t * wait_set) override;
|
||||
|
||||
/// Set a callback to be called when each new event instance occurs.
|
||||
/**
|
||||
* The callback receives a size_t which is the number of events that occurred
|
||||
* since the last time this callback was called.
|
||||
* Normally this is 1, but can be > 1 if events occurred before any
|
||||
* callback was set.
|
||||
*
|
||||
* The callback also receives an int identifier argument.
|
||||
* This is needed because a Waitable may be composed of several distinct entities,
|
||||
* such as subscriptions, services, etc.
|
||||
* The application should provide a generic callback function that will be then
|
||||
* forwarded by the waitable to all of its entities.
|
||||
* Before forwarding, a different value for the identifier argument will be
|
||||
* bond to the function.
|
||||
* This implies that the provided callback can use the identifier to behave
|
||||
* differently depending on which entity triggered the waitable to become ready.
|
||||
*
|
||||
* Since this callback is called from the middleware, you should aim to make
|
||||
* it fast and not blocking.
|
||||
* If you need to do a lot of work or wait for some other event, you should
|
||||
* spin it off to another thread, otherwise you risk blocking the middleware.
|
||||
*
|
||||
* Calling it again will clear any previously set callback.
|
||||
*
|
||||
* An exception will be thrown if the callback is not callable.
|
||||
*
|
||||
* This function is thread-safe.
|
||||
*
|
||||
* If you want more information available in the callback, like the qos event
|
||||
* or other information, you may use a lambda with captures or std::bind.
|
||||
*
|
||||
* \sa rmw_event_set_callback
|
||||
* \sa rcl_event_set_callback
|
||||
*
|
||||
* \param[in] callback functor to be called when a new event occurs
|
||||
*/
|
||||
void
|
||||
set_on_ready_callback(std::function<void(size_t, int)> callback) override
|
||||
{
|
||||
if (!callback) {
|
||||
throw std::invalid_argument(
|
||||
"The callback passed to set_on_ready_callback "
|
||||
"is not callable.");
|
||||
}
|
||||
|
||||
// Note: we bind the int identifier argument to this waitable's entity types
|
||||
auto new_callback =
|
||||
[callback, this](size_t number_of_events) {
|
||||
try {
|
||||
callback(number_of_events, static_cast<int>(EntityType::Event));
|
||||
} catch (const std::exception & exception) {
|
||||
RCLCPP_ERROR_STREAM(
|
||||
// TODO(wjwwood): get this class access to the node logger it is associated with
|
||||
rclcpp::get_logger("rclcpp"),
|
||||
"rclcpp::EventHandlerBase@" << this <<
|
||||
" caught " << rmw::impl::cpp::demangle(exception) <<
|
||||
" exception in user-provided callback for the 'on ready' callback: " <<
|
||||
exception.what());
|
||||
} catch (...) {
|
||||
RCLCPP_ERROR_STREAM(
|
||||
rclcpp::get_logger("rclcpp"),
|
||||
"rclcpp::EventHandlerBase@" << this <<
|
||||
" caught unhandled exception in user-provided callback " <<
|
||||
"for the 'on ready' callback");
|
||||
}
|
||||
};
|
||||
|
||||
std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
|
||||
|
||||
// Set it temporarily to the new callback, while we replace the old one.
|
||||
// This two-step setting, prevents a gap where the old std::function has
|
||||
// been replaced but the middleware hasn't been told about the new one yet.
|
||||
set_on_new_event_callback(
|
||||
rclcpp::detail::cpp_callback_trampoline<decltype(new_callback), const void *, size_t>,
|
||||
static_cast<const void *>(&new_callback));
|
||||
|
||||
// Store the std::function to keep it in scope, also overwrites the existing one.
|
||||
on_new_event_callback_ = new_callback;
|
||||
|
||||
// Set it again, now using the permanent storage.
|
||||
set_on_new_event_callback(
|
||||
rclcpp::detail::cpp_callback_trampoline<
|
||||
decltype(on_new_event_callback_), const void *, size_t>,
|
||||
static_cast<const void *>(&on_new_event_callback_));
|
||||
}
|
||||
|
||||
/// Unset the callback registered for new events, if any.
|
||||
void
|
||||
clear_on_ready_callback() override
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
|
||||
if (on_new_event_callback_) {
|
||||
set_on_new_event_callback(nullptr, nullptr);
|
||||
on_new_event_callback_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
set_on_new_event_callback(rcl_event_callback_t callback, const void * user_data);
|
||||
|
||||
std::recursive_mutex callback_mutex_;
|
||||
std::function<void(size_t)> on_new_event_callback_{nullptr};
|
||||
|
||||
rcl_event_t event_handle_;
|
||||
size_t wait_set_event_index_;
|
||||
};
|
||||
|
||||
using QOSEventHandlerBase [[deprecated("Use rclcpp::EventHandlerBase")]] = EventHandlerBase;
|
||||
|
||||
template<typename EventCallbackT, typename ParentHandleT>
|
||||
class EventHandler : public EventHandlerBase
|
||||
{
|
||||
public:
|
||||
template<typename InitFuncT, typename EventTypeEnum>
|
||||
EventHandler(
|
||||
const EventCallbackT & callback,
|
||||
InitFuncT init_func,
|
||||
ParentHandleT parent_handle,
|
||||
EventTypeEnum event_type)
|
||||
: parent_handle_(parent_handle), event_callback_(callback)
|
||||
{
|
||||
event_handle_ = rcl_get_zero_initialized_event();
|
||||
rcl_ret_t ret = init_func(&event_handle_, parent_handle.get(), event_type);
|
||||
if (ret != RCL_RET_OK) {
|
||||
if (ret == RCL_RET_UNSUPPORTED) {
|
||||
UnsupportedEventTypeException exc(ret, rcl_get_error_state(), "Failed to initialize event");
|
||||
rcl_reset_error();
|
||||
throw exc;
|
||||
} else {
|
||||
rclcpp::exceptions::throw_from_rcl_error(ret, "Failed to initialize event");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Take data so that the callback cannot be scheduled again
|
||||
std::shared_ptr<void>
|
||||
take_data() override
|
||||
{
|
||||
EventCallbackInfoT callback_info;
|
||||
rcl_ret_t ret = rcl_take_event(&event_handle_, &callback_info);
|
||||
if (ret != RCL_RET_OK) {
|
||||
RCUTILS_LOG_ERROR_NAMED(
|
||||
"rclcpp",
|
||||
"Couldn't take event info: %s", rcl_get_error_string().str);
|
||||
return nullptr;
|
||||
}
|
||||
return std::static_pointer_cast<void>(std::make_shared<EventCallbackInfoT>(callback_info));
|
||||
}
|
||||
|
||||
std::shared_ptr<void>
|
||||
take_data_by_entity_id(size_t id) override
|
||||
{
|
||||
(void)id;
|
||||
return take_data();
|
||||
}
|
||||
|
||||
/// Execute any entities of the Waitable that are ready.
|
||||
void
|
||||
execute(std::shared_ptr<void> & data) override
|
||||
{
|
||||
if (!data) {
|
||||
throw std::runtime_error("'data' is empty");
|
||||
}
|
||||
auto callback_ptr = std::static_pointer_cast<EventCallbackInfoT>(data);
|
||||
event_callback_(*callback_ptr);
|
||||
callback_ptr.reset();
|
||||
}
|
||||
|
||||
private:
|
||||
using EventCallbackInfoT = typename std::remove_reference<typename
|
||||
rclcpp::function_traits::function_traits<EventCallbackT>::template argument_type<0>>::type;
|
||||
|
||||
ParentHandleT parent_handle_;
|
||||
EventCallbackT event_callback_;
|
||||
};
|
||||
|
||||
template<typename EventCallbackT, typename ParentHandleT>
|
||||
using QOSEventHandler [[deprecated("Use rclcpp::EventHandler")]] = EventHandler<EventCallbackT,
|
||||
ParentHandleT>;
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__EVENT_HANDLER_HPP_
|
||||
@@ -109,6 +109,8 @@ public:
|
||||
: std::runtime_error(msg) {}
|
||||
};
|
||||
|
||||
typedef void (* reset_error_function_t)();
|
||||
|
||||
/// Throw a C++ std::exception which was created based on an rcl error.
|
||||
/**
|
||||
* Passing nullptr for reset_error is safe and will avoid calling any function
|
||||
@@ -129,7 +131,7 @@ throw_from_rcl_error [[noreturn]] (
|
||||
rcl_ret_t ret,
|
||||
const std::string & prefix = "",
|
||||
const rcl_error_state_t * error_state = nullptr,
|
||||
void (* reset_error)() = rcl_reset_error);
|
||||
reset_error_function_t reset_error = rcl_reset_error);
|
||||
/* *INDENT-ON* */
|
||||
|
||||
class RCLErrorBase
|
||||
@@ -254,6 +256,23 @@ public:
|
||||
{}
|
||||
};
|
||||
|
||||
/// Thrown if user attempts to create an uninitialized statically typed parameter
|
||||
/**
|
||||
* (see https://github.com/ros2/rclcpp/issues/1691)
|
||||
*/
|
||||
class UninitializedStaticallyTypedParameterException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
/// Construct an instance.
|
||||
/**
|
||||
* \param[in] name the name of the parameter.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
explicit UninitializedStaticallyTypedParameterException(const std::string & name)
|
||||
: std::runtime_error("Statically typed parameter '" + name + "' must be initialized.")
|
||||
{}
|
||||
};
|
||||
|
||||
/// Thrown if parameter is already declared.
|
||||
class ParameterAlreadyDeclaredException : public std::runtime_error
|
||||
{
|
||||
@@ -282,17 +301,16 @@ class ParameterModifiedInCallbackException : public std::runtime_error
|
||||
using std::runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
/// Thrown when a parameter override wasn't provided and one was required.
|
||||
class NoParameterOverrideProvided : public std::runtime_error
|
||||
/// Thrown when an uninitialized parameter is accessed.
|
||||
class ParameterUninitializedException : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
/// Construct an instance.
|
||||
/**
|
||||
* \param[in] name the name of the parameter.
|
||||
* \param[in] message custom exception message.
|
||||
*/
|
||||
explicit NoParameterOverrideProvided(const std::string & name)
|
||||
: std::runtime_error("parameter '" + name + "' requires an user provided parameter override")
|
||||
explicit ParameterUninitializedException(const std::string & name)
|
||||
: std::runtime_error("parameter '" + name + "' is not initialized")
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
@@ -29,7 +29,9 @@
|
||||
|
||||
#include "rcl/guard_condition.h"
|
||||
#include "rcl/wait.h"
|
||||
#include "rcpputils/scope_exit.hpp"
|
||||
|
||||
#include "rclcpp/context.hpp"
|
||||
#include "rclcpp/contexts/default_context.hpp"
|
||||
#include "rclcpp/guard_condition.hpp"
|
||||
#include "rclcpp/executor_options.hpp"
|
||||
@@ -39,7 +41,6 @@
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/utilities.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
#include "rclcpp/scope_exit.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
@@ -304,7 +305,9 @@ public:
|
||||
* If the time that waitables take to be executed is longer than the period on which new waitables
|
||||
* become ready, this method will execute work repeatedly until `max_duration` has elapsed.
|
||||
*
|
||||
* \param[in] max_duration The maximum amount of time to spend executing work. Must be positive.
|
||||
* \param[in] max_duration The maximum amount of time to spend executing work, must be >= 0.
|
||||
* `0` is potentially block forever until no more work is available.
|
||||
* \throw std::invalid_argument if max_duration is less than 0.
|
||||
* Note that spin_all() may take longer than this time as it only returns once max_duration has
|
||||
* been exceeded.
|
||||
*/
|
||||
@@ -312,6 +315,16 @@ public:
|
||||
virtual void
|
||||
spin_all(std::chrono::nanoseconds max_duration);
|
||||
|
||||
|
||||
/// Collect work once and execute the next available work, optionally within a duration.
|
||||
/**
|
||||
* This function can be overridden. The default implementation is suitable for
|
||||
* a single-thread model of execution.
|
||||
* Adding subscriptions, timers, services, etc. with blocking callbacks will cause this function
|
||||
* to block (which may have unintended consequences).
|
||||
* \param[in] timeout The maximum amount of time to spend waiting for work.
|
||||
* `-1` is potentially block forever waiting for work.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual void
|
||||
spin_once(std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));
|
||||
@@ -353,7 +366,7 @@ public:
|
||||
if (spinning.exchange(true)) {
|
||||
throw std::runtime_error("spin_until_future_complete() called while already spinning");
|
||||
}
|
||||
RCLCPP_SCOPE_EXIT(this->spinning.store(false); );
|
||||
RCPPUTILS_SCOPE_EXIT(this->spinning.store(false); );
|
||||
while (rclcpp::ok(this->context_) && spinning.load()) {
|
||||
// Do one item of work.
|
||||
spin_once_impl(timeout_left);
|
||||
@@ -400,13 +413,39 @@ public:
|
||||
void
|
||||
set_memory_strategy(memory_strategy::MemoryStrategy::SharedPtr memory_strategy);
|
||||
|
||||
/// Returns true if the executor is currently spinning.
|
||||
/**
|
||||
* This function can be called asynchronously from any thread.
|
||||
* \return True if the executor is currently spinning.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
is_spinning();
|
||||
|
||||
protected:
|
||||
/// Add a node to executor, execute the next available unit of work, and remove the node.
|
||||
/**
|
||||
* Implementation of spin_node_once using std::chrono::nanoseconds
|
||||
* \param[in] node Shared pointer to the node to add.
|
||||
* \param[in] timeout How long to wait for work to become available. Negative values cause
|
||||
* spin_node_once to block indefinitely (the default behavior). A timeout of 0 causes this
|
||||
* function to be non-blocking.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
spin_node_once_nanoseconds(
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node,
|
||||
std::chrono::nanoseconds timeout);
|
||||
|
||||
/// Collect work and execute available work, optionally within a duration.
|
||||
/**
|
||||
* Implementation of spin_some and spin_all.
|
||||
* The exhaustive flag controls if the function will re-collect available work within the duration.
|
||||
*
|
||||
* \param[in] max_duration The maximum amount of time to spend executing work, or 0 for no limit.
|
||||
* \param[in] exhaustive when set to true, continue to collect work and execute (spin_all)
|
||||
* when set to false, return when all collected work is executed (spin_some)
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
spin_some_impl(std::chrono::nanoseconds max_duration, bool exhaustive);
|
||||
@@ -421,30 +460,60 @@ protected:
|
||||
void
|
||||
execute_any_executable(AnyExecutable & any_exec);
|
||||
|
||||
/// Run subscription executable.
|
||||
/**
|
||||
* Do necessary setup and tear-down as well as executing the subscription.
|
||||
* \param[in] subscription Subscription to execute
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
static void
|
||||
execute_subscription(
|
||||
rclcpp::SubscriptionBase::SharedPtr subscription);
|
||||
|
||||
/// Run timer executable.
|
||||
/**
|
||||
* Do necessary setup and tear-down as well as executing the timer callback.
|
||||
* \param[in] timer Timer to execute
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
static void
|
||||
execute_timer(rclcpp::TimerBase::SharedPtr timer);
|
||||
|
||||
/// Run service server executable.
|
||||
/**
|
||||
* Do necessary setup and tear-down as well as executing the service server callback.
|
||||
* \param[in] service Service to execute
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
static void
|
||||
execute_service(rclcpp::ServiceBase::SharedPtr service);
|
||||
|
||||
/// Run service client executable.
|
||||
/**
|
||||
* Do necessary setup and tear-down as well as executing the service client callback.
|
||||
* \param[in] service Service to execute
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
static void
|
||||
execute_client(rclcpp::ClientBase::SharedPtr client);
|
||||
|
||||
/// Block until more work becomes avilable or timeout is reached.
|
||||
/**
|
||||
* Builds a set of waitable entities, which are passed to the middleware.
|
||||
* After building wait set, waits on middleware to notify.
|
||||
* \param[in] timeout duration to wait for new work to become available.
|
||||
* \throws std::runtime_error if the wait set can be cleared
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
wait_for_work(std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));
|
||||
|
||||
/// Find node associated with a callback group
|
||||
/**
|
||||
* \param[in] weak_groups_to_nodes map of callback groups to nodes
|
||||
* \param[in] group callback group to find assocatiated node
|
||||
* \return Pointer to associated node if found, else nullptr
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr
|
||||
get_node_by_group(
|
||||
@@ -454,6 +523,7 @@ protected:
|
||||
/// Return true if the node has been added to this executor.
|
||||
/**
|
||||
* \param[in] node_ptr a shared pointer that points to a node base interface
|
||||
* \param[in] weak_groups_to_nodes map to nodes to lookup
|
||||
* \return true if the node is associated with the executor, otherwise false
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
@@ -462,6 +532,11 @@ protected:
|
||||
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
|
||||
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes) const;
|
||||
|
||||
/// Find the callback group associated with a timer
|
||||
/**
|
||||
* \param[in] timer Timer to find associated callback group
|
||||
* \return Pointer to callback group node if found, else nullptr
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::CallbackGroup::SharedPtr
|
||||
get_group_by_timer(rclcpp::TimerBase::SharedPtr timer);
|
||||
@@ -489,16 +564,54 @@ protected:
|
||||
WeakCallbackGroupsToNodesMap & weak_groups_to_nodes,
|
||||
bool notify = true) RCPPUTILS_TSA_REQUIRES(mutex_);
|
||||
|
||||
/// Check for executable in ready state and populate union structure.
|
||||
/**
|
||||
* \param[out] any_executable populated union structure of ready executable
|
||||
* \return true if an executable was ready and any_executable was populated,
|
||||
* otherwise false
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
get_next_ready_executable(AnyExecutable & any_executable);
|
||||
|
||||
/// Check for executable in ready state and populate union structure.
|
||||
/**
|
||||
* This is the implementation of get_next_ready_executable that takes into
|
||||
* account the current state of callback groups' association with nodes and
|
||||
* executors.
|
||||
*
|
||||
* This checks in a particular order for available work:
|
||||
* * Timers
|
||||
* * Subscriptions
|
||||
* * Services
|
||||
* * Clients
|
||||
* * Waitable
|
||||
*
|
||||
* If the next executable is not associated with this executor/node pair,
|
||||
* then this method will return false.
|
||||
*
|
||||
* \param[out] any_executable populated union structure of ready executable
|
||||
* \param[in] weak_groups_to_nodes mapping of callback groups to nodes
|
||||
* \return true if an executable was ready and any_executable was populated,
|
||||
* otherwise false
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
get_next_ready_executable_from_map(
|
||||
AnyExecutable & any_executable,
|
||||
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes);
|
||||
|
||||
/// Wait for executable in ready state and populate union structure.
|
||||
/**
|
||||
* If an executable is ready, it will return immediately, otherwise
|
||||
* block based on the timeout for work to become ready.
|
||||
*
|
||||
* \param[out] any_executable populated union structure of ready executable
|
||||
* \param[in] timeout duration of time to wait for work, a negative value
|
||||
* (the defualt behavior), will make this function block indefinitely
|
||||
* \return true if an executable was ready and any_executable was populated,
|
||||
* otherwise false
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
get_next_executable(
|
||||
@@ -524,7 +637,7 @@ protected:
|
||||
std::atomic_bool spinning;
|
||||
|
||||
/// Guard condition for signaling the rmw layer to wake up for special events.
|
||||
rcl_guard_condition_t interrupt_guard_condition_ = rcl_get_zero_initialized_guard_condition();
|
||||
rclcpp::GuardCondition interrupt_guard_condition_;
|
||||
|
||||
std::shared_ptr<rclcpp::GuardCondition> shutdown_guard_condition_;
|
||||
|
||||
@@ -544,18 +657,27 @@ protected:
|
||||
RCLCPP_DISABLE_COPY(Executor)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
virtual void
|
||||
spin_once_impl(std::chrono::nanoseconds timeout);
|
||||
|
||||
typedef std::map<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr,
|
||||
const rcl_guard_condition_t *,
|
||||
const rclcpp::GuardCondition *,
|
||||
std::owner_less<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>>
|
||||
WeakNodesToGuardConditionsMap;
|
||||
|
||||
typedef std::map<rclcpp::CallbackGroup::WeakPtr,
|
||||
const rclcpp::GuardCondition *,
|
||||
std::owner_less<rclcpp::CallbackGroup::WeakPtr>>
|
||||
WeakCallbackGroupsToGuardConditionsMap;
|
||||
|
||||
/// maps nodes to guard conditions
|
||||
WeakNodesToGuardConditionsMap
|
||||
weak_nodes_to_guard_conditions_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
|
||||
|
||||
/// maps callback groups to guard conditions
|
||||
WeakCallbackGroupsToGuardConditionsMap
|
||||
weak_groups_to_guard_conditions_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
|
||||
|
||||
/// maps callback groups associated to nodes
|
||||
WeakCallbackGroupsToNodesMap
|
||||
weak_groups_associated_with_executor_to_nodes_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
|
||||
@@ -571,14 +693,11 @@ protected:
|
||||
/// nodes that are associated with the executor
|
||||
std::list<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>
|
||||
weak_nodes_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
|
||||
|
||||
/// shutdown callback handle registered to Context
|
||||
rclcpp::OnShutdownCallbackHandle shutdown_callback_handle_;
|
||||
};
|
||||
|
||||
namespace executor
|
||||
{
|
||||
|
||||
using Executor [[deprecated("use rclcpp::Executor instead")]] = rclcpp::Executor;
|
||||
|
||||
} // namespace executor
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__EXECUTOR_HPP_
|
||||
|
||||
@@ -38,20 +38,6 @@ struct ExecutorOptions
|
||||
size_t max_conditions;
|
||||
};
|
||||
|
||||
namespace executor
|
||||
{
|
||||
|
||||
using ExecutorArgs [[deprecated("use rclcpp::ExecutorOptions instead")]] = ExecutorOptions;
|
||||
|
||||
[[deprecated("use rclcpp::ExecutorOptions() instead")]]
|
||||
inline
|
||||
rclcpp::ExecutorOptions
|
||||
create_default_executor_arguments()
|
||||
{
|
||||
return rclcpp::ExecutorOptions();
|
||||
}
|
||||
|
||||
} // namespace executor
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__EXECUTOR_OPTIONS_HPP_
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "rclcpp/detail/mutex_two_priorities.hpp"
|
||||
#include "rclcpp/executor.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/memory_strategies.hpp"
|
||||
@@ -48,12 +47,12 @@ public:
|
||||
*
|
||||
* \param options common options for all executors
|
||||
* \param number_of_threads number of threads to have in the thread pool,
|
||||
* the default 0 will use the number of cpu cores found instead
|
||||
* the default 0 will use the number of cpu cores found (minimum of 2)
|
||||
* \param yield_before_execute if true std::this_thread::yield() is called
|
||||
* \param timeout maximum time to wait
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
MultiThreadedExecutor(
|
||||
explicit MultiThreadedExecutor(
|
||||
const rclcpp::ExecutorOptions & options = rclcpp::ExecutorOptions(),
|
||||
size_t number_of_threads = 0,
|
||||
bool yield_before_execute = false,
|
||||
@@ -82,12 +81,10 @@ protected:
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(MultiThreadedExecutor)
|
||||
|
||||
detail::MutexTwoPriorities wait_mutex_;
|
||||
std::mutex wait_mutex_;
|
||||
size_t number_of_threads_;
|
||||
bool yield_before_execute_;
|
||||
std::chrono::nanoseconds next_exec_timeout_;
|
||||
|
||||
std::set<TimerBase::SharedPtr> scheduled_timers_;
|
||||
};
|
||||
|
||||
} // namespace executors
|
||||
|
||||
@@ -57,17 +57,19 @@ public:
|
||||
/**
|
||||
* \param p_wait_set A reference to the wait set to be used in the executor
|
||||
* \param memory_strategy Shared pointer to the memory strategy to set.
|
||||
* \param executor_guard_condition executor's guard condition
|
||||
* \throws std::runtime_error if memory strategy is null
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
init(
|
||||
rcl_wait_set_t * p_wait_set,
|
||||
rclcpp::memory_strategy::MemoryStrategy::SharedPtr memory_strategy,
|
||||
rcl_guard_condition_t * executor_guard_condition);
|
||||
rclcpp::memory_strategy::MemoryStrategy::SharedPtr memory_strategy);
|
||||
|
||||
/// Finalize StaticExecutorEntitiesCollector to clear resources
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
is_init() {return initialized_;}
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
fini();
|
||||
@@ -100,7 +102,7 @@ public:
|
||||
* \throws std::runtime_error if it couldn't add guard condition to wait set
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
void
|
||||
add_to_wait_set(rcl_wait_set_t * wait_set) override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
@@ -297,7 +299,8 @@ private:
|
||||
|
||||
/// Return true if the node belongs to the collector
|
||||
/**
|
||||
* \param[in] group_ptr a node base interface shared pointer
|
||||
* \param[in] node_ptr a node base interface shared pointer
|
||||
* \param[in] weak_groups_to_nodes map to nodes to lookup
|
||||
* \return boolean whether a node belongs the collector
|
||||
*/
|
||||
bool
|
||||
@@ -326,7 +329,7 @@ private:
|
||||
WeakCallbackGroupsToNodesMap weak_groups_to_nodes_associated_with_executor_;
|
||||
|
||||
typedef std::map<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr,
|
||||
const rcl_guard_condition_t *,
|
||||
const rclcpp::GuardCondition *,
|
||||
std::owner_less<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>>
|
||||
WeakNodesToGuardConditionsMap;
|
||||
WeakNodesToGuardConditionsMap weak_nodes_to_guard_conditions_;
|
||||
@@ -334,11 +337,18 @@ private:
|
||||
/// List of weak nodes registered in the static executor
|
||||
std::list<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr> weak_nodes_;
|
||||
|
||||
// Mutex to protect vector of new nodes.
|
||||
std::mutex new_nodes_mutex_;
|
||||
std::vector<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr> new_nodes_;
|
||||
|
||||
/// Wait set for managing entities that the rmw layer waits on.
|
||||
rcl_wait_set_t * p_wait_set_ = nullptr;
|
||||
|
||||
/// Executable list: timers, subscribers, clients, services and waitables
|
||||
rclcpp::experimental::ExecutableList exec_list_;
|
||||
|
||||
/// Bool to check if the entities collector has been initialized
|
||||
bool initialized_ = false;
|
||||
};
|
||||
|
||||
} // namespace executors
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#ifndef RCLCPP__EXECUTORS__STATIC_SINGLE_THREADED_EXECUTOR_HPP_
|
||||
#define RCLCPP__EXECUTORS__STATIC_SINGLE_THREADED_EXECUTOR_HPP_
|
||||
|
||||
#include <chrono>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <memory>
|
||||
@@ -78,6 +79,43 @@ public:
|
||||
void
|
||||
spin() override;
|
||||
|
||||
/// Static executor implementation of spin some
|
||||
/**
|
||||
* This non-blocking function will execute entities that
|
||||
* were ready when this API was called, until timeout or no
|
||||
* more work available. Entities that got ready while
|
||||
* executing work, won't be taken into account here.
|
||||
*
|
||||
* Example:
|
||||
* while(condition) {
|
||||
* spin_some();
|
||||
* sleep(); // User should have some sync work or
|
||||
* // sleep to avoid a 100% CPU usage
|
||||
* }
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
spin_some(std::chrono::nanoseconds max_duration = std::chrono::nanoseconds(0)) override;
|
||||
|
||||
/// Static executor implementation of spin all
|
||||
/**
|
||||
* This non-blocking function will execute entities until timeout (must be >= 0)
|
||||
* or no more work available.
|
||||
* If timeout is `0`, potentially it blocks forever until no more work is available.
|
||||
* If new entities get ready while executing work available, they will be executed
|
||||
* as long as the timeout hasn't expired.
|
||||
*
|
||||
* Example:
|
||||
* while(condition) {
|
||||
* spin_all();
|
||||
* sleep(); // User should have some sync work or
|
||||
* // sleep to avoid a 100% CPU usage
|
||||
* }
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
spin_all(std::chrono::nanoseconds max_duration) override;
|
||||
|
||||
/// Add a callback group to an executor.
|
||||
/**
|
||||
* \sa rclcpp::Executor::add_callback_group
|
||||
@@ -155,113 +193,23 @@ public:
|
||||
std::vector<rclcpp::CallbackGroup::WeakPtr>
|
||||
get_automatically_added_callback_groups_from_nodes() override;
|
||||
|
||||
/// Spin (blocking) until the future is complete, it times out waiting, or rclcpp is interrupted.
|
||||
/**
|
||||
* \param[in] future The future to wait on. If this function returns SUCCESS, the future can be
|
||||
* accessed without blocking (though it may still throw an exception).
|
||||
* \param[in] timeout Optional timeout parameter, which gets passed to
|
||||
* Executor::execute_ready_executables.
|
||||
* `-1` is block forever, `0` is non-blocking.
|
||||
* If the time spent inside the blocking loop exceeds this timeout, return a TIMEOUT return
|
||||
* code.
|
||||
* \return The return code, one of `SUCCESS`, `INTERRUPTED`, or `TIMEOUT`.
|
||||
*
|
||||
* Example usage:
|
||||
* rclcpp::executors::StaticSingleThreadedExecutor exec;
|
||||
* // ... other part of code like creating node
|
||||
* // define future
|
||||
* exec.add_node(node);
|
||||
* exec.spin_until_future_complete(future);
|
||||
*/
|
||||
template<typename FutureT, typename TimeRepT = int64_t, typename TimeT = std::milli>
|
||||
rclcpp::FutureReturnCode
|
||||
spin_until_future_complete(
|
||||
FutureT & future,
|
||||
std::chrono::duration<TimeRepT, TimeT> timeout = std::chrono::duration<TimeRepT, TimeT>(-1))
|
||||
{
|
||||
std::future_status status = future.wait_for(std::chrono::seconds(0));
|
||||
if (status == std::future_status::ready) {
|
||||
return rclcpp::FutureReturnCode::SUCCESS;
|
||||
}
|
||||
|
||||
auto end_time = std::chrono::steady_clock::now();
|
||||
std::chrono::nanoseconds timeout_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
timeout);
|
||||
if (timeout_ns > std::chrono::nanoseconds::zero()) {
|
||||
end_time += timeout_ns;
|
||||
}
|
||||
std::chrono::nanoseconds timeout_left = timeout_ns;
|
||||
|
||||
entities_collector_->init(&wait_set_, memory_strategy_, &interrupt_guard_condition_);
|
||||
RCLCPP_SCOPE_EXIT(entities_collector_->fini());
|
||||
|
||||
while (rclcpp::ok(this->context_)) {
|
||||
// Do one set of work.
|
||||
entities_collector_->refresh_wait_set(timeout_left);
|
||||
execute_ready_executables();
|
||||
// Check if the future is set, return SUCCESS if it is.
|
||||
status = future.wait_for(std::chrono::seconds(0));
|
||||
if (status == std::future_status::ready) {
|
||||
return rclcpp::FutureReturnCode::SUCCESS;
|
||||
}
|
||||
// If the original timeout is < 0, then this is blocking, never TIMEOUT.
|
||||
if (timeout_ns < std::chrono::nanoseconds::zero()) {
|
||||
continue;
|
||||
}
|
||||
// Otherwise check if we still have time to wait, return TIMEOUT if not.
|
||||
auto now = std::chrono::steady_clock::now();
|
||||
if (now >= end_time) {
|
||||
return rclcpp::FutureReturnCode::TIMEOUT;
|
||||
}
|
||||
// Subtract the elapsed time from the original timeout.
|
||||
timeout_left = std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - now);
|
||||
}
|
||||
|
||||
// The future did not complete before ok() returned false, return INTERRUPTED.
|
||||
return rclcpp::FutureReturnCode::INTERRUPTED;
|
||||
}
|
||||
|
||||
/// Not yet implemented, see https://github.com/ros2/rclcpp/issues/1219 for tracking
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
spin_some(std::chrono::nanoseconds max_duration = std::chrono::nanoseconds(0)) override
|
||||
{
|
||||
(void)max_duration;
|
||||
throw rclcpp::exceptions::UnimplementedError(
|
||||
"spin_some is not implemented for StaticSingleThreadedExecutor, use spin or "
|
||||
"spin_until_future_complete");
|
||||
}
|
||||
|
||||
/// Not yet implemented, see https://github.com/ros2/rclcpp/issues/1219 for tracking
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
spin_all(std::chrono::nanoseconds) override
|
||||
{
|
||||
throw rclcpp::exceptions::UnimplementedError(
|
||||
"spin_all is not implemented for StaticSingleThreadedExecutor, use spin or "
|
||||
"spin_until_future_complete");
|
||||
}
|
||||
|
||||
/// Not yet implemented, see https://github.com/ros2/rclcpp/issues/1219 for tracking
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
spin_once(std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1)) override
|
||||
{
|
||||
(void)timeout;
|
||||
throw rclcpp::exceptions::UnimplementedError(
|
||||
"spin_once is not implemented for StaticSingleThreadedExecutor, use spin or "
|
||||
"spin_until_future_complete");
|
||||
}
|
||||
|
||||
protected:
|
||||
/// Check which executables in ExecutableList struct are ready from wait_set and execute them.
|
||||
/**
|
||||
* \param[in] exec_list Structure that can hold subscriptionbases, timerbases, etc
|
||||
* \param[in] timeout Optional timeout parameter.
|
||||
* @brief Executes ready executables from wait set.
|
||||
* @param spin_once if true executes only the first ready executable.
|
||||
* @return true if any executable was ready.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
execute_ready_executables(bool spin_once = false);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
execute_ready_executables();
|
||||
spin_some_impl(std::chrono::nanoseconds max_duration, bool exhaustive);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
spin_once_impl(std::chrono::nanoseconds timeout) override;
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(StaticSingleThreadedExecutor)
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#define RCLCPP__EXPERIMENTAL__BUFFERS__INTRA_PROCESS_BUFFER_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
|
||||
@@ -15,10 +15,6 @@
|
||||
#ifndef RCLCPP__EXPERIMENTAL__BUFFERS__RING_BUFFER_IMPLEMENTATION_HPP_
|
||||
#define RCLCPP__EXPERIMENTAL__BUFFERS__RING_BUFFER_IMPLEMENTATION_HPP_
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
@@ -90,8 +86,7 @@ public:
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
|
||||
if (!has_data_()) {
|
||||
RCLCPP_ERROR(rclcpp::get_logger("rclcpp"), "Calling dequeue on empty intra-process buffer");
|
||||
throw std::runtime_error("Calling dequeue on empty intra-process buffer");
|
||||
return BufferT();
|
||||
}
|
||||
|
||||
auto request = std::move(ring_buffer_[read_index_]);
|
||||
|
||||
@@ -16,14 +16,13 @@
|
||||
#define RCLCPP__EXPERIMENTAL__CREATE_INTRA_PROCESS_BUFFER_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
#include "rcl/subscription.h"
|
||||
|
||||
#include "rclcpp/experimental/buffers/intra_process_buffer.hpp"
|
||||
#include "rclcpp/experimental/buffers/ring_buffer_implementation.hpp"
|
||||
#include "rclcpp/intra_process_buffer_type.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
@@ -37,13 +36,13 @@ template<
|
||||
typename rclcpp::experimental::buffers::IntraProcessBuffer<MessageT, Alloc, Deleter>::UniquePtr
|
||||
create_intra_process_buffer(
|
||||
IntraProcessBufferType buffer_type,
|
||||
rmw_qos_profile_t qos,
|
||||
const rclcpp::QoS & qos,
|
||||
std::shared_ptr<Alloc> allocator)
|
||||
{
|
||||
using MessageSharedPtr = std::shared_ptr<const MessageT>;
|
||||
using MessageUniquePtr = std::unique_ptr<MessageT, Deleter>;
|
||||
|
||||
size_t buffer_size = qos.depth;
|
||||
size_t buffer_size = qos.depth();
|
||||
|
||||
using rclcpp::experimental::buffers::IntraProcessBuffer;
|
||||
typename IntraProcessBuffer<MessageT, Alloc, Deleter>::UniquePtr buffer;
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#ifndef RCLCPP__EXPERIMENTAL__EXECUTABLE_LIST_HPP_
|
||||
#define RCLCPP__EXPERIMENTAL__EXECUTABLE_LIST_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "rclcpp/client.hpp"
|
||||
|
||||
@@ -19,24 +19,24 @@
|
||||
|
||||
#include <shared_mutex>
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <exception>
|
||||
#include <map>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <typeinfo>
|
||||
|
||||
#include "rclcpp/allocator/allocator_deleter.hpp"
|
||||
#include "rclcpp/experimental/ros_message_intra_process_buffer.hpp"
|
||||
#include "rclcpp/experimental/subscription_intra_process.hpp"
|
||||
#include "rclcpp/experimental/subscription_intra_process_base.hpp"
|
||||
#include "rclcpp/experimental/subscription_intra_process_buffer.hpp"
|
||||
#include "rclcpp/logger.hpp"
|
||||
#include "rclcpp/logging.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/publisher_base.hpp"
|
||||
#include "rclcpp/type_adapter.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
@@ -172,16 +172,19 @@ public:
|
||||
*
|
||||
* \param intra_process_publisher_id the id of the publisher of this message.
|
||||
* \param message the message that is being stored.
|
||||
* \param allocator for allocations when buffering messages.
|
||||
*/
|
||||
template<
|
||||
typename MessageT,
|
||||
typename Alloc = std::allocator<void>,
|
||||
typename Deleter = std::default_delete<MessageT>>
|
||||
typename ROSMessageType,
|
||||
typename Alloc,
|
||||
typename Deleter = std::default_delete<MessageT>
|
||||
>
|
||||
void
|
||||
do_intra_process_publish(
|
||||
uint64_t intra_process_publisher_id,
|
||||
std::unique_ptr<MessageT, Deleter> message,
|
||||
std::shared_ptr<typename allocator::AllocRebind<MessageT, Alloc>::allocator_type> allocator)
|
||||
typename allocator::AllocRebind<MessageT, Alloc>::allocator_type & allocator)
|
||||
{
|
||||
using MessageAllocTraits = allocator::AllocRebind<MessageT, Alloc>;
|
||||
using MessageAllocatorT = typename MessageAllocTraits::allocator_type;
|
||||
@@ -202,7 +205,8 @@ public:
|
||||
// None of the buffers require ownership, so we promote the pointer
|
||||
std::shared_ptr<MessageT> msg = std::move(message);
|
||||
|
||||
this->template add_shared_msg_to_buffers<MessageT>(msg, sub_ids.take_shared_subscriptions);
|
||||
this->template add_shared_msg_to_buffers<MessageT, Alloc, Deleter, ROSMessageType>(
|
||||
msg, sub_ids.take_shared_subscriptions);
|
||||
} else if (!sub_ids.take_ownership_subscriptions.empty() && // NOLINT
|
||||
sub_ids.take_shared_subscriptions.size() <= 1)
|
||||
{
|
||||
@@ -215,8 +219,7 @@ public:
|
||||
concatenated_vector.end(),
|
||||
sub_ids.take_ownership_subscriptions.begin(),
|
||||
sub_ids.take_ownership_subscriptions.end());
|
||||
|
||||
this->template add_owned_msg_to_buffers<MessageT, Alloc, Deleter>(
|
||||
this->template add_owned_msg_to_buffers<MessageT, Alloc, Deleter, ROSMessageType>(
|
||||
std::move(message),
|
||||
concatenated_vector,
|
||||
allocator);
|
||||
@@ -225,24 +228,26 @@ public:
|
||||
{
|
||||
// Construct a new shared pointer from the message
|
||||
// for the buffers that do not require ownership
|
||||
auto shared_msg = std::allocate_shared<MessageT, MessageAllocatorT>(*allocator, *message);
|
||||
auto shared_msg = std::allocate_shared<MessageT, MessageAllocatorT>(allocator, *message);
|
||||
|
||||
this->template add_shared_msg_to_buffers<MessageT>(
|
||||
this->template add_shared_msg_to_buffers<MessageT, Alloc, Deleter, ROSMessageType>(
|
||||
shared_msg, sub_ids.take_shared_subscriptions);
|
||||
this->template add_owned_msg_to_buffers<MessageT, Alloc, Deleter>(
|
||||
this->template add_owned_msg_to_buffers<MessageT, Alloc, Deleter, ROSMessageType>(
|
||||
std::move(message), sub_ids.take_ownership_subscriptions, allocator);
|
||||
}
|
||||
}
|
||||
|
||||
template<
|
||||
typename MessageT,
|
||||
typename Alloc = std::allocator<void>,
|
||||
typename Deleter = std::default_delete<MessageT>>
|
||||
typename ROSMessageType,
|
||||
typename Alloc,
|
||||
typename Deleter = std::default_delete<MessageT>
|
||||
>
|
||||
std::shared_ptr<const MessageT>
|
||||
do_intra_process_publish_and_return_shared(
|
||||
uint64_t intra_process_publisher_id,
|
||||
std::unique_ptr<MessageT, Deleter> message,
|
||||
std::shared_ptr<typename allocator::AllocRebind<MessageT, Alloc>::allocator_type> allocator)
|
||||
typename allocator::AllocRebind<MessageT, Alloc>::allocator_type & allocator)
|
||||
{
|
||||
using MessageAllocTraits = allocator::AllocRebind<MessageT, Alloc>;
|
||||
using MessageAllocatorT = typename MessageAllocTraits::allocator_type;
|
||||
@@ -263,27 +268,26 @@ public:
|
||||
// If there are no owning, just convert to shared.
|
||||
std::shared_ptr<MessageT> shared_msg = std::move(message);
|
||||
if (!sub_ids.take_shared_subscriptions.empty()) {
|
||||
this->template add_shared_msg_to_buffers<MessageT>(
|
||||
this->template add_shared_msg_to_buffers<MessageT, Alloc, Deleter, ROSMessageType>(
|
||||
shared_msg, sub_ids.take_shared_subscriptions);
|
||||
}
|
||||
return shared_msg;
|
||||
} else {
|
||||
// Construct a new shared pointer from the message for the buffers that
|
||||
// do not require ownership and to return.
|
||||
auto shared_msg = std::allocate_shared<MessageT, MessageAllocatorT>(*allocator, *message);
|
||||
auto shared_msg = std::allocate_shared<MessageT, MessageAllocatorT>(allocator, *message);
|
||||
|
||||
if (!sub_ids.take_shared_subscriptions.empty()) {
|
||||
this->template add_shared_msg_to_buffers<MessageT>(
|
||||
this->template add_shared_msg_to_buffers<MessageT, Alloc, Deleter, ROSMessageType>(
|
||||
shared_msg,
|
||||
sub_ids.take_shared_subscriptions);
|
||||
}
|
||||
if (!sub_ids.take_ownership_subscriptions.empty()) {
|
||||
this->template add_owned_msg_to_buffers<MessageT, Alloc, Deleter>(
|
||||
this->template add_owned_msg_to_buffers<MessageT, Alloc, Deleter, ROSMessageType>(
|
||||
std::move(message),
|
||||
sub_ids.take_ownership_subscriptions,
|
||||
allocator);
|
||||
}
|
||||
|
||||
return shared_msg;
|
||||
}
|
||||
}
|
||||
@@ -303,25 +307,6 @@ public:
|
||||
get_subscription_intra_process(uint64_t intra_process_subscription_id);
|
||||
|
||||
private:
|
||||
struct SubscriptionInfo
|
||||
{
|
||||
SubscriptionInfo() = default;
|
||||
|
||||
rclcpp::experimental::SubscriptionIntraProcessBase::WeakPtr subscription;
|
||||
rmw_qos_profile_t qos;
|
||||
const char * topic_name;
|
||||
bool use_take_shared_method;
|
||||
};
|
||||
|
||||
struct PublisherInfo
|
||||
{
|
||||
PublisherInfo() = default;
|
||||
|
||||
rclcpp::PublisherBase::WeakPtr publisher;
|
||||
rmw_qos_profile_t qos;
|
||||
const char * topic_name;
|
||||
};
|
||||
|
||||
struct SplittedSubscriptions
|
||||
{
|
||||
std::vector<uint64_t> take_shared_subscriptions;
|
||||
@@ -329,10 +314,10 @@ private:
|
||||
};
|
||||
|
||||
using SubscriptionMap =
|
||||
std::unordered_map<uint64_t, SubscriptionInfo>;
|
||||
std::unordered_map<uint64_t, rclcpp::experimental::SubscriptionIntraProcessBase::WeakPtr>;
|
||||
|
||||
using PublisherMap =
|
||||
std::unordered_map<uint64_t, PublisherInfo>;
|
||||
std::unordered_map<uint64_t, rclcpp::PublisherBase::WeakPtr>;
|
||||
|
||||
using PublisherToSubscriptionIdsMap =
|
||||
std::unordered_map<uint64_t, SplittedSubscriptions>;
|
||||
@@ -348,71 +333,181 @@ private:
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
can_communicate(PublisherInfo pub_info, SubscriptionInfo sub_info) const;
|
||||
can_communicate(
|
||||
rclcpp::PublisherBase::SharedPtr pub,
|
||||
rclcpp::experimental::SubscriptionIntraProcessBase::SharedPtr sub) const;
|
||||
|
||||
template<typename MessageT>
|
||||
template<
|
||||
typename MessageT,
|
||||
typename Alloc,
|
||||
typename Deleter,
|
||||
typename ROSMessageType>
|
||||
void
|
||||
add_shared_msg_to_buffers(
|
||||
std::shared_ptr<const MessageT> message,
|
||||
std::vector<uint64_t> subscription_ids)
|
||||
{
|
||||
using ROSMessageTypeAllocatorTraits = allocator::AllocRebind<ROSMessageType, Alloc>;
|
||||
using ROSMessageTypeAllocator = typename ROSMessageTypeAllocatorTraits::allocator_type;
|
||||
using ROSMessageTypeDeleter = allocator::Deleter<ROSMessageTypeAllocator, ROSMessageType>;
|
||||
|
||||
using PublishedType = typename rclcpp::TypeAdapter<MessageT>::custom_type;
|
||||
using PublishedTypeAllocatorTraits = allocator::AllocRebind<PublishedType, Alloc>;
|
||||
using PublishedTypeAllocator = typename PublishedTypeAllocatorTraits::allocator_type;
|
||||
using PublishedTypeDeleter = allocator::Deleter<PublishedTypeAllocator, PublishedType>;
|
||||
|
||||
for (auto id : subscription_ids) {
|
||||
auto subscription_it = subscriptions_.find(id);
|
||||
if (subscription_it == subscriptions_.end()) {
|
||||
throw std::runtime_error("subscription has unexpectedly gone out of scope");
|
||||
}
|
||||
auto subscription_base = subscription_it->second.subscription.lock();
|
||||
if (subscription_base) {
|
||||
auto subscription = std::static_pointer_cast<
|
||||
rclcpp::experimental::SubscriptionIntraProcess<MessageT>
|
||||
>(subscription_base);
|
||||
|
||||
subscription->provide_intra_process_message(message);
|
||||
} else {
|
||||
auto subscription_base = subscription_it->second.lock();
|
||||
if (subscription_base == nullptr) {
|
||||
subscriptions_.erase(id);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto subscription = std::dynamic_pointer_cast<
|
||||
rclcpp::experimental::SubscriptionIntraProcessBuffer<PublishedType,
|
||||
PublishedTypeAllocator, PublishedTypeDeleter, ROSMessageType>
|
||||
>(subscription_base);
|
||||
if (subscription != nullptr) {
|
||||
subscription->provide_intra_process_data(message);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto ros_message_subscription = std::dynamic_pointer_cast<
|
||||
rclcpp::experimental::SubscriptionROSMsgIntraProcessBuffer<ROSMessageType,
|
||||
ROSMessageTypeAllocator, ROSMessageTypeDeleter>
|
||||
>(subscription_base);
|
||||
if (nullptr == ros_message_subscription) {
|
||||
throw std::runtime_error(
|
||||
"failed to dynamic cast SubscriptionIntraProcessBase to "
|
||||
"SubscriptionIntraProcessBuffer<MessageT, Alloc, Deleter>, or to "
|
||||
"SubscriptionROSMsgIntraProcessBuffer<ROSMessageType,ROSMessageTypeAllocator,"
|
||||
"ROSMessageTypeDeleter> which can happen when the publisher and "
|
||||
"subscription use different allocator types, which is not supported");
|
||||
}
|
||||
|
||||
if constexpr (rclcpp::TypeAdapter<MessageT>::is_specialized::value) {
|
||||
ROSMessageType ros_msg;
|
||||
rclcpp::TypeAdapter<MessageT>::convert_to_ros_message(*message, ros_msg);
|
||||
ros_message_subscription->provide_intra_process_message(
|
||||
std::make_shared<ROSMessageType>(ros_msg));
|
||||
} else {
|
||||
if constexpr (std::is_same<MessageT, ROSMessageType>::value) {
|
||||
ros_message_subscription->provide_intra_process_message(message);
|
||||
} else {
|
||||
if constexpr (std::is_same<typename rclcpp::TypeAdapter<MessageT,
|
||||
ROSMessageType>::ros_message_type, ROSMessageType>::value)
|
||||
{
|
||||
ROSMessageType ros_msg;
|
||||
rclcpp::TypeAdapter<MessageT, ROSMessageType>::convert_to_ros_message(
|
||||
*message, ros_msg);
|
||||
ros_message_subscription->provide_intra_process_message(
|
||||
std::make_shared<ROSMessageType>(ros_msg));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<
|
||||
typename MessageT,
|
||||
typename Alloc = std::allocator<void>,
|
||||
typename Deleter = std::default_delete<MessageT>>
|
||||
typename Alloc,
|
||||
typename Deleter,
|
||||
typename ROSMessageType>
|
||||
void
|
||||
add_owned_msg_to_buffers(
|
||||
std::unique_ptr<MessageT, Deleter> message,
|
||||
std::vector<uint64_t> subscription_ids,
|
||||
std::shared_ptr<typename allocator::AllocRebind<MessageT, Alloc>::allocator_type> allocator)
|
||||
typename allocator::AllocRebind<MessageT, Alloc>::allocator_type & allocator)
|
||||
{
|
||||
using MessageAllocTraits = allocator::AllocRebind<MessageT, Alloc>;
|
||||
using MessageUniquePtr = std::unique_ptr<MessageT, Deleter>;
|
||||
|
||||
using ROSMessageTypeAllocatorTraits = allocator::AllocRebind<ROSMessageType, Alloc>;
|
||||
using ROSMessageTypeAllocator = typename ROSMessageTypeAllocatorTraits::allocator_type;
|
||||
using ROSMessageTypeDeleter = allocator::Deleter<ROSMessageTypeAllocator, ROSMessageType>;
|
||||
|
||||
using PublishedType = typename rclcpp::TypeAdapter<MessageT>::custom_type;
|
||||
using PublishedTypeAllocatorTraits = allocator::AllocRebind<PublishedType, Alloc>;
|
||||
using PublishedTypeAllocator = typename PublishedTypeAllocatorTraits::allocator_type;
|
||||
using PublishedTypeDeleter = allocator::Deleter<PublishedTypeAllocator, PublishedType>;
|
||||
|
||||
for (auto it = subscription_ids.begin(); it != subscription_ids.end(); it++) {
|
||||
auto subscription_it = subscriptions_.find(*it);
|
||||
if (subscription_it == subscriptions_.end()) {
|
||||
throw std::runtime_error("subscription has unexpectedly gone out of scope");
|
||||
}
|
||||
auto subscription_base = subscription_it->second.subscription.lock();
|
||||
if (subscription_base) {
|
||||
auto subscription = std::static_pointer_cast<
|
||||
rclcpp::experimental::SubscriptionIntraProcess<MessageT>
|
||||
>(subscription_base);
|
||||
auto subscription_base = subscription_it->second.lock();
|
||||
if (subscription_base == nullptr) {
|
||||
subscriptions_.erase(subscription_it);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto subscription = std::dynamic_pointer_cast<
|
||||
rclcpp::experimental::SubscriptionIntraProcessBuffer<PublishedType,
|
||||
PublishedTypeAllocator, PublishedTypeDeleter, ROSMessageType>
|
||||
>(subscription_base);
|
||||
if (subscription != nullptr) {
|
||||
if (std::next(it) == subscription_ids.end()) {
|
||||
// If this is the last subscription, give up ownership
|
||||
subscription->provide_intra_process_message(std::move(message));
|
||||
subscription->provide_intra_process_data(std::move(message));
|
||||
// Last message delivered, break from for loop
|
||||
break;
|
||||
} else {
|
||||
// Copy the message since we have additional subscriptions to serve
|
||||
MessageUniquePtr copy_message;
|
||||
Deleter deleter = message.get_deleter();
|
||||
auto ptr = MessageAllocTraits::allocate(*allocator.get(), 1);
|
||||
MessageAllocTraits::construct(*allocator.get(), ptr, *message);
|
||||
copy_message = MessageUniquePtr(ptr, deleter);
|
||||
auto ptr = MessageAllocTraits::allocate(allocator, 1);
|
||||
MessageAllocTraits::construct(allocator, ptr, *message);
|
||||
|
||||
subscription->provide_intra_process_message(std::move(copy_message));
|
||||
subscription->provide_intra_process_data(std::move(MessageUniquePtr(ptr, deleter)));
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
auto ros_message_subscription = std::dynamic_pointer_cast<
|
||||
rclcpp::experimental::SubscriptionROSMsgIntraProcessBuffer<ROSMessageType,
|
||||
ROSMessageTypeAllocator, ROSMessageTypeDeleter>
|
||||
>(subscription_base);
|
||||
if (nullptr == ros_message_subscription) {
|
||||
throw std::runtime_error(
|
||||
"failed to dynamic cast SubscriptionIntraProcessBase to "
|
||||
"SubscriptionIntraProcessBuffer<MessageT, Alloc, Deleter>, or to "
|
||||
"SubscriptionROSMsgIntraProcessBuffer<ROSMessageType,ROSMessageTypeAllocator,"
|
||||
"ROSMessageTypeDeleter> which can happen when the publisher and "
|
||||
"subscription use different allocator types, which is not supported");
|
||||
}
|
||||
|
||||
if constexpr (rclcpp::TypeAdapter<MessageT>::is_specialized::value) {
|
||||
ROSMessageTypeAllocator ros_message_alloc(allocator);
|
||||
auto ptr = ros_message_alloc.allocate(1);
|
||||
ros_message_alloc.construct(ptr);
|
||||
ROSMessageTypeDeleter deleter;
|
||||
allocator::set_allocator_for_deleter(&deleter, &allocator);
|
||||
rclcpp::TypeAdapter<MessageT>::convert_to_ros_message(*message, *ptr);
|
||||
auto ros_msg = std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>(ptr, deleter);
|
||||
ros_message_subscription->provide_intra_process_message(std::move(ros_msg));
|
||||
} else {
|
||||
subscriptions_.erase(subscription_it);
|
||||
if constexpr (std::is_same<MessageT, ROSMessageType>::value) {
|
||||
if (std::next(it) == subscription_ids.end()) {
|
||||
// If this is the last subscription, give up ownership
|
||||
ros_message_subscription->provide_intra_process_message(std::move(message));
|
||||
// Last message delivered, break from for loop
|
||||
break;
|
||||
} else {
|
||||
// Copy the message since we have additional subscriptions to serve
|
||||
Deleter deleter = message.get_deleter();
|
||||
allocator::set_allocator_for_deleter(&deleter, &allocator);
|
||||
auto ptr = MessageAllocTraits::allocate(allocator, 1);
|
||||
MessageAllocTraits::construct(allocator, ptr, *message);
|
||||
|
||||
ros_message_subscription->provide_intra_process_message(
|
||||
std::move(MessageUniquePtr(ptr, deleter)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
// Copyright 2021 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__EXPERIMENTAL__ROS_MESSAGE_INTRA_PROCESS_BUFFER_HPP_
|
||||
#define RCLCPP__EXPERIMENTAL__ROS_MESSAGE_INTRA_PROCESS_BUFFER_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "rcl/error_handling.h"
|
||||
|
||||
#include "rclcpp/any_subscription_callback.hpp"
|
||||
#include "rclcpp/context.hpp"
|
||||
#include "rclcpp/experimental/subscription_intra_process_base.hpp"
|
||||
#include "tracetools/tracetools.h"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
|
||||
template<
|
||||
typename RosMessageT,
|
||||
typename Alloc = std::allocator<void>,
|
||||
typename Deleter = std::default_delete<void>
|
||||
>
|
||||
class SubscriptionROSMsgIntraProcessBuffer : public SubscriptionIntraProcessBase
|
||||
{
|
||||
public:
|
||||
using ROSMessageTypeAllocatorTraits = allocator::AllocRebind<RosMessageT, Alloc>;
|
||||
using ROSMessageTypeAllocator = typename ROSMessageTypeAllocatorTraits::allocator_type;
|
||||
using ROSMessageTypeDeleter = allocator::Deleter<ROSMessageTypeAllocator, RosMessageT>;
|
||||
|
||||
using ConstMessageSharedPtr = std::shared_ptr<const RosMessageT>;
|
||||
using MessageUniquePtr = std::unique_ptr<RosMessageT, ROSMessageTypeDeleter>;
|
||||
|
||||
SubscriptionROSMsgIntraProcessBuffer(
|
||||
rclcpp::Context::SharedPtr context,
|
||||
const std::string & topic_name,
|
||||
const rclcpp::QoS & qos_profile)
|
||||
: SubscriptionIntraProcessBase(context, topic_name, qos_profile)
|
||||
{}
|
||||
|
||||
virtual ~SubscriptionROSMsgIntraProcessBuffer()
|
||||
{}
|
||||
|
||||
virtual void
|
||||
provide_intra_process_message(ConstMessageSharedPtr message) = 0;
|
||||
|
||||
virtual void
|
||||
provide_intra_process_message(MessageUniquePtr message) = 0;
|
||||
};
|
||||
|
||||
} // namespace experimental
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__EXPERIMENTAL__ROS_MESSAGE_INTRA_PROCESS_BUFFER_HPP_
|
||||
@@ -15,23 +15,22 @@
|
||||
#ifndef RCLCPP__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_HPP_
|
||||
#define RCLCPP__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_HPP_
|
||||
|
||||
#include <rmw/rmw.h>
|
||||
#include <rmw/types.h>
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "rcl/error_handling.h"
|
||||
#include "rcl/types.h"
|
||||
|
||||
#include "rclcpp/any_subscription_callback.hpp"
|
||||
#include "rclcpp/context.hpp"
|
||||
#include "rclcpp/experimental/buffers/intra_process_buffer.hpp"
|
||||
#include "rclcpp/experimental/create_intra_process_buffer.hpp"
|
||||
#include "rclcpp/experimental/subscription_intra_process_base.hpp"
|
||||
#include "rclcpp/experimental/subscription_intra_process_buffer.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
#include "rclcpp/type_support_decl.hpp"
|
||||
#include "rclcpp/waitable.hpp"
|
||||
#include "tracetools/tracetools.h"
|
||||
|
||||
namespace rclcpp
|
||||
@@ -41,57 +40,53 @@ namespace experimental
|
||||
|
||||
template<
|
||||
typename MessageT,
|
||||
typename Alloc = std::allocator<void>,
|
||||
typename Deleter = std::default_delete<MessageT>,
|
||||
typename CallbackMessageT = MessageT>
|
||||
class SubscriptionIntraProcess : public SubscriptionIntraProcessBase
|
||||
typename SubscribedType,
|
||||
typename SubscribedTypeAlloc = std::allocator<SubscribedType>,
|
||||
typename SubscribedTypeDeleter = std::default_delete<SubscribedType>,
|
||||
typename ROSMessageType = SubscribedType,
|
||||
typename Alloc = std::allocator<void>
|
||||
>
|
||||
class SubscriptionIntraProcess
|
||||
: public SubscriptionIntraProcessBuffer<
|
||||
SubscribedType,
|
||||
SubscribedTypeAlloc,
|
||||
SubscribedTypeDeleter,
|
||||
ROSMessageType
|
||||
>
|
||||
{
|
||||
using SubscriptionIntraProcessBufferT = SubscriptionIntraProcessBuffer<
|
||||
SubscribedType,
|
||||
SubscribedTypeAlloc,
|
||||
SubscribedTypeDeleter,
|
||||
ROSMessageType
|
||||
>;
|
||||
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(SubscriptionIntraProcess)
|
||||
|
||||
using MessageAllocTraits = allocator::AllocRebind<MessageT, Alloc>;
|
||||
using MessageAlloc = typename MessageAllocTraits::allocator_type;
|
||||
using ConstMessageSharedPtr = std::shared_ptr<const MessageT>;
|
||||
using MessageUniquePtr = std::unique_ptr<MessageT, Deleter>;
|
||||
|
||||
using BufferUniquePtr = typename rclcpp::experimental::buffers::IntraProcessBuffer<
|
||||
MessageT,
|
||||
Alloc,
|
||||
Deleter
|
||||
>::UniquePtr;
|
||||
using MessageAllocTraits =
|
||||
typename SubscriptionIntraProcessBufferT::SubscribedTypeAllocatorTraits;
|
||||
using MessageAlloc = typename SubscriptionIntraProcessBufferT::SubscribedTypeAllocator;
|
||||
using ConstMessageSharedPtr = typename SubscriptionIntraProcessBufferT::ConstDataSharedPtr;
|
||||
using MessageUniquePtr = typename SubscriptionIntraProcessBufferT::SubscribedTypeUniquePtr;
|
||||
using BufferUniquePtr = typename SubscriptionIntraProcessBufferT::BufferUniquePtr;
|
||||
|
||||
SubscriptionIntraProcess(
|
||||
AnySubscriptionCallback<CallbackMessageT, Alloc> callback,
|
||||
AnySubscriptionCallback<MessageT, Alloc> callback,
|
||||
std::shared_ptr<Alloc> allocator,
|
||||
rclcpp::Context::SharedPtr context,
|
||||
const std::string & topic_name,
|
||||
rmw_qos_profile_t qos_profile,
|
||||
const rclcpp::QoS & qos_profile,
|
||||
rclcpp::IntraProcessBufferType buffer_type)
|
||||
: SubscriptionIntraProcessBase(topic_name, qos_profile),
|
||||
: SubscriptionIntraProcessBuffer<SubscribedType, SubscribedTypeAlloc,
|
||||
SubscribedTypeDeleter, ROSMessageType>(
|
||||
std::make_shared<SubscribedTypeAlloc>(*allocator),
|
||||
context,
|
||||
topic_name,
|
||||
qos_profile,
|
||||
buffer_type),
|
||||
any_callback_(callback)
|
||||
{
|
||||
if (!std::is_same<MessageT, CallbackMessageT>::value) {
|
||||
throw std::runtime_error("SubscriptionIntraProcess wrong callback type");
|
||||
}
|
||||
|
||||
// Create the intra-process buffer.
|
||||
buffer_ = rclcpp::experimental::create_intra_process_buffer<MessageT, Alloc, Deleter>(
|
||||
buffer_type,
|
||||
qos_profile,
|
||||
allocator);
|
||||
|
||||
// Create the guard condition.
|
||||
rcl_guard_condition_options_t guard_condition_options =
|
||||
rcl_guard_condition_get_default_options();
|
||||
|
||||
gc_ = rcl_get_zero_initialized_guard_condition();
|
||||
rcl_ret_t ret = rcl_guard_condition_init(
|
||||
&gc_, context->get_rcl_context().get(), guard_condition_options);
|
||||
|
||||
if (RCL_RET_OK != ret) {
|
||||
throw std::runtime_error("SubscriptionIntraProcess init error initializing guard condition");
|
||||
}
|
||||
|
||||
TRACEPOINT(
|
||||
rclcpp_subscription_callback_added,
|
||||
static_cast<const void *>(this),
|
||||
@@ -104,33 +99,24 @@ public:
|
||||
#endif
|
||||
}
|
||||
|
||||
~SubscriptionIntraProcess()
|
||||
{
|
||||
if (rcl_guard_condition_fini(&gc_) != RCL_RET_OK) {
|
||||
RCUTILS_LOG_ERROR_NAMED(
|
||||
"rclcpp",
|
||||
"Failed to destroy guard condition: %s",
|
||||
rcutils_get_error_string().str);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
is_ready(rcl_wait_set_t * wait_set)
|
||||
{
|
||||
(void) wait_set;
|
||||
return buffer_->has_data();
|
||||
}
|
||||
virtual ~SubscriptionIntraProcess() = default;
|
||||
|
||||
std::shared_ptr<void>
|
||||
take_data()
|
||||
take_data() override
|
||||
{
|
||||
ConstMessageSharedPtr shared_msg;
|
||||
MessageUniquePtr unique_msg;
|
||||
|
||||
if (any_callback_.use_take_shared_method()) {
|
||||
shared_msg = buffer_->consume_shared();
|
||||
shared_msg = this->buffer_->consume_shared();
|
||||
if (!shared_msg) {
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
unique_msg = buffer_->consume_unique();
|
||||
unique_msg = this->buffer_->consume_unique();
|
||||
if (!unique_msg) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return std::static_pointer_cast<void>(
|
||||
std::make_shared<std::pair<ConstMessageSharedPtr, MessageUniquePtr>>(
|
||||
@@ -139,39 +125,12 @@ public:
|
||||
);
|
||||
}
|
||||
|
||||
void execute(std::shared_ptr<void> & data)
|
||||
void execute(std::shared_ptr<void> & data) override
|
||||
{
|
||||
execute_impl<CallbackMessageT>(data);
|
||||
}
|
||||
|
||||
void
|
||||
provide_intra_process_message(ConstMessageSharedPtr message)
|
||||
{
|
||||
buffer_->add_shared(std::move(message));
|
||||
trigger_guard_condition();
|
||||
}
|
||||
|
||||
void
|
||||
provide_intra_process_message(MessageUniquePtr message)
|
||||
{
|
||||
buffer_->add_unique(std::move(message));
|
||||
trigger_guard_condition();
|
||||
}
|
||||
|
||||
bool
|
||||
use_take_shared_method() const
|
||||
{
|
||||
return buffer_->use_take_shared_method();
|
||||
}
|
||||
|
||||
private:
|
||||
void
|
||||
trigger_guard_condition()
|
||||
{
|
||||
rcl_ret_t ret = rcl_trigger_guard_condition(&gc_);
|
||||
(void)ret;
|
||||
execute_impl<SubscribedType>(data);
|
||||
}
|
||||
|
||||
protected:
|
||||
template<typename T>
|
||||
typename std::enable_if<std::is_same<T, rcl_serialized_message_t>::value, void>::type
|
||||
execute_impl(std::shared_ptr<void> & data)
|
||||
@@ -185,7 +144,7 @@ private:
|
||||
execute_impl(std::shared_ptr<void> & data)
|
||||
{
|
||||
if (!data) {
|
||||
throw std::runtime_error("'data' is empty");
|
||||
return;
|
||||
}
|
||||
|
||||
rmw_message_info_t msg_info;
|
||||
@@ -205,8 +164,7 @@ private:
|
||||
shared_ptr.reset();
|
||||
}
|
||||
|
||||
AnySubscriptionCallback<CallbackMessageT, Alloc> any_callback_;
|
||||
BufferUniquePtr buffer_;
|
||||
AnySubscriptionCallback<MessageT, Alloc> any_callback_;
|
||||
};
|
||||
|
||||
} // namespace experimental
|
||||
|
||||
@@ -15,17 +15,17 @@
|
||||
#ifndef RCLCPP__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_BASE_HPP_
|
||||
#define RCLCPP__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_BASE_HPP_
|
||||
|
||||
#include <rmw/rmw.h>
|
||||
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "rcl/error_handling.h"
|
||||
#include "rcl/wait.h"
|
||||
#include "rmw/impl/cpp/demangle.hpp"
|
||||
|
||||
#include "rclcpp/type_support_decl.hpp"
|
||||
#include "rclcpp/guard_condition.hpp"
|
||||
#include "rclcpp/logging.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
#include "rclcpp/waitable.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
@@ -38,32 +38,48 @@ class SubscriptionIntraProcessBase : public rclcpp::Waitable
|
||||
public:
|
||||
RCLCPP_SMART_PTR_ALIASES_ONLY(SubscriptionIntraProcessBase)
|
||||
|
||||
enum class EntityType : std::size_t
|
||||
{
|
||||
Subscription,
|
||||
};
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
SubscriptionIntraProcessBase(const std::string & topic_name, rmw_qos_profile_t qos_profile)
|
||||
: topic_name_(topic_name), qos_profile_(qos_profile)
|
||||
SubscriptionIntraProcessBase(
|
||||
rclcpp::Context::SharedPtr context,
|
||||
const std::string & topic_name,
|
||||
const rclcpp::QoS & qos_profile)
|
||||
: gc_(context), topic_name_(topic_name), qos_profile_(qos_profile)
|
||||
{}
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual ~SubscriptionIntraProcessBase() = default;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
size_t
|
||||
get_number_of_ready_guard_conditions() {return 1;}
|
||||
get_number_of_ready_guard_conditions() override {return 1;}
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
add_to_wait_set(rcl_wait_set_t * wait_set);
|
||||
void
|
||||
add_to_wait_set(rcl_wait_set_t * wait_set) override;
|
||||
|
||||
virtual bool
|
||||
is_ready(rcl_wait_set_t * wait_set) = 0;
|
||||
bool
|
||||
is_ready(rcl_wait_set_t * wait_set) override = 0;
|
||||
|
||||
std::shared_ptr<void>
|
||||
take_data() override = 0;
|
||||
|
||||
std::shared_ptr<void>
|
||||
take_data_by_entity_id(size_t id) override
|
||||
{
|
||||
(void)id;
|
||||
return take_data();
|
||||
}
|
||||
|
||||
void
|
||||
execute(std::shared_ptr<void> & data) override = 0;
|
||||
|
||||
virtual
|
||||
std::shared_ptr<void>
|
||||
take_data() = 0;
|
||||
|
||||
virtual void
|
||||
execute(std::shared_ptr<void> & data) = 0;
|
||||
|
||||
virtual bool
|
||||
bool
|
||||
use_take_shared_method() const = 0;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
@@ -71,19 +87,113 @@ public:
|
||||
get_topic_name() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
rmw_qos_profile_t
|
||||
QoS
|
||||
get_actual_qos() const;
|
||||
|
||||
protected:
|
||||
std::recursive_mutex reentrant_mutex_;
|
||||
rcl_guard_condition_t gc_;
|
||||
/// Set a callback to be called when each new message arrives.
|
||||
/**
|
||||
* The callback receives a size_t which is the number of messages received
|
||||
* since the last time this callback was called.
|
||||
* Normally this is 1, but can be > 1 if messages were received before any
|
||||
* callback was set.
|
||||
*
|
||||
* The callback also receives an int identifier argument.
|
||||
* This is needed because a Waitable may be composed of several distinct entities,
|
||||
* such as subscriptions, services, etc.
|
||||
* The application should provide a generic callback function that will be then
|
||||
* forwarded by the waitable to all of its entities.
|
||||
* Before forwarding, a different value for the identifier argument will be
|
||||
* bound to the function.
|
||||
* This implies that the provided callback can use the identifier to behave
|
||||
* differently depending on which entity triggered the waitable to become ready.
|
||||
*
|
||||
* Calling it again will clear any previously set callback.
|
||||
*
|
||||
* An exception will be thrown if the callback is not callable.
|
||||
*
|
||||
* This function is thread-safe.
|
||||
*
|
||||
* If you want more information available in the callback, like the subscription
|
||||
* or other information, you may use a lambda with captures or std::bind.
|
||||
*
|
||||
* \param[in] callback functor to be called when a new message is received.
|
||||
*/
|
||||
void
|
||||
set_on_ready_callback(std::function<void(size_t, int)> callback) override
|
||||
{
|
||||
if (!callback) {
|
||||
throw std::invalid_argument(
|
||||
"The callback passed to set_on_ready_callback "
|
||||
"is not callable.");
|
||||
}
|
||||
|
||||
// Note: we bind the int identifier argument to this waitable's entity types
|
||||
auto new_callback =
|
||||
[callback, this](size_t number_of_events) {
|
||||
try {
|
||||
callback(number_of_events, static_cast<int>(EntityType::Subscription));
|
||||
} catch (const std::exception & exception) {
|
||||
RCLCPP_ERROR_STREAM(
|
||||
// TODO(wjwwood): get this class access to the node logger it is associated with
|
||||
rclcpp::get_logger("rclcpp"),
|
||||
"rclcpp::SubscriptionIntraProcessBase@" << this <<
|
||||
" caught " << rmw::impl::cpp::demangle(exception) <<
|
||||
" exception in user-provided callback for the 'on ready' callback: " <<
|
||||
exception.what());
|
||||
} catch (...) {
|
||||
RCLCPP_ERROR_STREAM(
|
||||
rclcpp::get_logger("rclcpp"),
|
||||
"rclcpp::SubscriptionIntraProcessBase@" << this <<
|
||||
" caught unhandled exception in user-provided callback " <<
|
||||
"for the 'on ready' callback");
|
||||
}
|
||||
};
|
||||
|
||||
std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
|
||||
on_new_message_callback_ = new_callback;
|
||||
|
||||
if (unread_count_ > 0) {
|
||||
if (qos_profile_.history() == HistoryPolicy::KeepAll) {
|
||||
on_new_message_callback_(unread_count_);
|
||||
} else {
|
||||
// Use qos profile depth as upper bound for unread_count_
|
||||
on_new_message_callback_(std::min(unread_count_, qos_profile_.depth()));
|
||||
}
|
||||
unread_count_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// Unset the callback registered for new messages, if any.
|
||||
void
|
||||
clear_on_ready_callback() override
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
|
||||
on_new_message_callback_ = nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::recursive_mutex callback_mutex_;
|
||||
std::function<void(size_t)> on_new_message_callback_ {nullptr};
|
||||
size_t unread_count_{0};
|
||||
rclcpp::GuardCondition gc_;
|
||||
|
||||
private:
|
||||
virtual void
|
||||
trigger_guard_condition() = 0;
|
||||
|
||||
void
|
||||
invoke_on_new_message()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(this->callback_mutex_);
|
||||
if (this->on_new_message_callback_) {
|
||||
this->on_new_message_callback_(1);
|
||||
} else {
|
||||
this->unread_count_++;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::string topic_name_;
|
||||
rmw_qos_profile_t qos_profile_;
|
||||
QoS qos_profile_;
|
||||
};
|
||||
|
||||
} // namespace experimental
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
// Copyright 2021 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_BUFFER_HPP_
|
||||
#define RCLCPP__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_BUFFER_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
#include "rcl/error_handling.h"
|
||||
#include "rcl/guard_condition.h"
|
||||
#include "rcl/wait.h"
|
||||
|
||||
#include "rclcpp/experimental/buffers/intra_process_buffer.hpp"
|
||||
#include "rclcpp/experimental/create_intra_process_buffer.hpp"
|
||||
#include "rclcpp/experimental/subscription_intra_process_base.hpp"
|
||||
#include "rclcpp/experimental/ros_message_intra_process_buffer.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
#include "rclcpp/type_support_decl.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
|
||||
template<
|
||||
typename SubscribedType,
|
||||
typename Alloc = std::allocator<SubscribedType>,
|
||||
typename Deleter = std::default_delete<SubscribedType>,
|
||||
/// MessageT::ros_message_type if MessageT is a TypeAdapter,
|
||||
/// otherwise just MessageT.
|
||||
typename ROSMessageType = SubscribedType
|
||||
>
|
||||
class SubscriptionIntraProcessBuffer : public SubscriptionROSMsgIntraProcessBuffer<ROSMessageType,
|
||||
typename allocator::AllocRebind<ROSMessageType, Alloc>::allocator_type,
|
||||
allocator::Deleter<typename allocator::AllocRebind<ROSMessageType, Alloc>::allocator_type,
|
||||
ROSMessageType>>
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(SubscriptionIntraProcessBuffer)
|
||||
|
||||
using SubscribedTypeAllocatorTraits = allocator::AllocRebind<SubscribedType, Alloc>;
|
||||
using SubscribedTypeAllocator = typename SubscribedTypeAllocatorTraits::allocator_type;
|
||||
using SubscribedTypeDeleter = allocator::Deleter<SubscribedTypeAllocator, SubscribedType>;
|
||||
|
||||
using ROSMessageTypeAllocatorTraits = allocator::AllocRebind<ROSMessageType, Alloc>;
|
||||
using ROSMessageTypeAllocator = typename ROSMessageTypeAllocatorTraits::allocator_type;
|
||||
using ROSMessageTypeDeleter = allocator::Deleter<ROSMessageTypeAllocator, ROSMessageType>;
|
||||
|
||||
using ConstMessageSharedPtr = std::shared_ptr<const ROSMessageType>;
|
||||
using MessageUniquePtr = std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>;
|
||||
|
||||
using ConstDataSharedPtr = std::shared_ptr<const SubscribedType>;
|
||||
using SubscribedTypeUniquePtr = std::unique_ptr<SubscribedType, SubscribedTypeDeleter>;
|
||||
|
||||
using BufferUniquePtr = typename rclcpp::experimental::buffers::IntraProcessBuffer<
|
||||
SubscribedType,
|
||||
Alloc,
|
||||
SubscribedTypeDeleter
|
||||
>::UniquePtr;
|
||||
|
||||
SubscriptionIntraProcessBuffer(
|
||||
std::shared_ptr<Alloc> allocator,
|
||||
rclcpp::Context::SharedPtr context,
|
||||
const std::string & topic_name,
|
||||
const rclcpp::QoS & qos_profile,
|
||||
rclcpp::IntraProcessBufferType buffer_type)
|
||||
: SubscriptionROSMsgIntraProcessBuffer<ROSMessageType, ROSMessageTypeAllocator,
|
||||
ROSMessageTypeDeleter>(
|
||||
context, topic_name, qos_profile),
|
||||
subscribed_type_allocator_(*allocator)
|
||||
{
|
||||
allocator::set_allocator_for_deleter(&subscribed_type_deleter_, &subscribed_type_allocator_);
|
||||
|
||||
// Create the intra-process buffer.
|
||||
buffer_ = rclcpp::experimental::create_intra_process_buffer<SubscribedType, Alloc,
|
||||
SubscribedTypeDeleter>(
|
||||
buffer_type,
|
||||
qos_profile,
|
||||
std::make_shared<Alloc>(subscribed_type_allocator_));
|
||||
}
|
||||
|
||||
bool
|
||||
is_ready(rcl_wait_set_t * wait_set) override
|
||||
{
|
||||
(void) wait_set;
|
||||
return buffer_->has_data();
|
||||
}
|
||||
|
||||
SubscribedTypeUniquePtr
|
||||
convert_ros_message_to_subscribed_type_unique_ptr(const ROSMessageType & msg)
|
||||
{
|
||||
if constexpr (!std::is_same<SubscribedType, ROSMessageType>::value) {
|
||||
auto ptr = SubscribedTypeAllocatorTraits::allocate(subscribed_type_allocator_, 1);
|
||||
SubscribedTypeAllocatorTraits::construct(subscribed_type_allocator_, ptr);
|
||||
rclcpp::TypeAdapter<SubscribedType, ROSMessageType>::convert_to_custom(msg, *ptr);
|
||||
return SubscribedTypeUniquePtr(ptr, subscribed_type_deleter_);
|
||||
} else {
|
||||
throw std::runtime_error(
|
||||
"convert_ros_message_to_subscribed_type_unique_ptr "
|
||||
"unexpectedly called without TypeAdapter");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
provide_intra_process_message(ConstMessageSharedPtr message) override
|
||||
{
|
||||
if constexpr (std::is_same<SubscribedType, ROSMessageType>::value) {
|
||||
buffer_->add_shared(std::move(message));
|
||||
trigger_guard_condition();
|
||||
} else {
|
||||
buffer_->add_shared(convert_ros_message_to_subscribed_type_unique_ptr(*message));
|
||||
trigger_guard_condition();
|
||||
}
|
||||
this->invoke_on_new_message();
|
||||
}
|
||||
|
||||
void
|
||||
provide_intra_process_message(MessageUniquePtr message) override
|
||||
{
|
||||
if constexpr (std::is_same<SubscribedType, ROSMessageType>::value) {
|
||||
buffer_->add_unique(std::move(message));
|
||||
trigger_guard_condition();
|
||||
} else {
|
||||
buffer_->add_unique(convert_ros_message_to_subscribed_type_unique_ptr(*message));
|
||||
trigger_guard_condition();
|
||||
}
|
||||
this->invoke_on_new_message();
|
||||
}
|
||||
|
||||
void
|
||||
provide_intra_process_data(ConstDataSharedPtr message)
|
||||
{
|
||||
buffer_->add_shared(std::move(message));
|
||||
trigger_guard_condition();
|
||||
this->invoke_on_new_message();
|
||||
}
|
||||
|
||||
void
|
||||
provide_intra_process_data(SubscribedTypeUniquePtr message)
|
||||
{
|
||||
buffer_->add_unique(std::move(message));
|
||||
trigger_guard_condition();
|
||||
this->invoke_on_new_message();
|
||||
}
|
||||
|
||||
bool
|
||||
use_take_shared_method() const override
|
||||
{
|
||||
return buffer_->use_take_shared_method();
|
||||
}
|
||||
|
||||
protected:
|
||||
void
|
||||
trigger_guard_condition() override
|
||||
{
|
||||
this->gc_.trigger();
|
||||
}
|
||||
|
||||
BufferUniquePtr buffer_;
|
||||
SubscribedTypeAllocator subscribed_type_allocator_;
|
||||
SubscribedTypeDeleter subscribed_type_deleter_;
|
||||
};
|
||||
|
||||
} // namespace experimental
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_BUFFER_HPP_
|
||||
@@ -80,10 +80,12 @@ struct function_traits<ReturnTypeT (*)(Args ...)>: function_traits<ReturnTypeT(A
|
||||
|
||||
// std::bind for object methods
|
||||
template<typename ClassT, typename ReturnTypeT, typename ... Args, typename ... FArgs>
|
||||
#if defined _LIBCPP_VERSION // libc++ (Clang)
|
||||
#if defined DOXYGEN_ONLY
|
||||
struct function_traits<std::bind<ReturnTypeT (ClassT::*)(Args ...), FArgs ...>>
|
||||
#elif defined _LIBCPP_VERSION // libc++ (Clang)
|
||||
struct function_traits<std::__bind<ReturnTypeT (ClassT::*)(Args ...), FArgs ...>>
|
||||
#elif defined _GLIBCXX_RELEASE // glibc++ (GNU C++ >= 7.1)
|
||||
struct function_traits<std::_Bind<ReturnTypeT(ClassT::*(FArgs ...))(Args ...)>>
|
||||
struct function_traits<std::_Bind<ReturnTypeT(ClassT::* (FArgs ...))(Args ...)>>
|
||||
#elif defined __GLIBCXX__ // glibc++ (GNU C++)
|
||||
struct function_traits<std::_Bind<std::_Mem_fn<ReturnTypeT (ClassT::*)(Args ...)>(FArgs ...)>>
|
||||
#elif defined _MSC_VER // MS Visual Studio
|
||||
@@ -97,10 +99,12 @@ struct function_traits<
|
||||
|
||||
// std::bind for object const methods
|
||||
template<typename ClassT, typename ReturnTypeT, typename ... Args, typename ... FArgs>
|
||||
#if defined _LIBCPP_VERSION // libc++ (Clang)
|
||||
#if defined DOXYGEN_ONLY
|
||||
struct function_traits<std::bind<ReturnTypeT (ClassT::*)(Args ...) const, FArgs ...>>
|
||||
#elif defined _LIBCPP_VERSION // libc++ (Clang)
|
||||
struct function_traits<std::__bind<ReturnTypeT (ClassT::*)(Args ...) const, FArgs ...>>
|
||||
#elif defined _GLIBCXX_RELEASE // glibc++ (GNU C++ >= 7.1)
|
||||
struct function_traits<std::_Bind<ReturnTypeT(ClassT::*(FArgs ...))(Args ...) const>>
|
||||
struct function_traits<std::_Bind<ReturnTypeT(ClassT::* (FArgs ...))(Args ...) const>>
|
||||
#elif defined __GLIBCXX__ // glibc++ (GNU C++)
|
||||
struct function_traits<std::_Bind<std::_Mem_fn<ReturnTypeT (ClassT::*)(Args ...) const>(FArgs ...)>>
|
||||
#elif defined _MSC_VER // MS Visual Studio
|
||||
@@ -114,7 +118,9 @@ struct function_traits<
|
||||
|
||||
// std::bind for free functions
|
||||
template<typename ReturnTypeT, typename ... Args, typename ... FArgs>
|
||||
#if defined _LIBCPP_VERSION // libc++ (Clang)
|
||||
#if defined DOXYGEN_ONLY
|
||||
struct function_traits<std::bind<ReturnTypeT( &)(Args ...), FArgs ...>>
|
||||
#elif defined _LIBCPP_VERSION // libc++ (Clang)
|
||||
struct function_traits<std::__bind<ReturnTypeT( &)(Args ...), FArgs ...>>
|
||||
#elif defined __GLIBCXX__ // glibc++ (GNU C++)
|
||||
struct function_traits<std::_Bind<ReturnTypeT(*(FArgs ...))(Args ...)>>
|
||||
@@ -162,6 +168,32 @@ struct same_arguments : std::is_same<
|
||||
>
|
||||
{};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<typename ReturnTypeT, typename ... Args>
|
||||
struct as_std_function_helper;
|
||||
|
||||
template<typename ReturnTypeT, typename ... Args>
|
||||
struct as_std_function_helper<ReturnTypeT, std::tuple<Args ...>>
|
||||
{
|
||||
using type = std::function<ReturnTypeT(Args ...)>;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<
|
||||
typename FunctorT,
|
||||
typename FunctionTraits = function_traits<FunctorT>
|
||||
>
|
||||
struct as_std_function
|
||||
{
|
||||
using type = typename detail::as_std_function_helper<
|
||||
typename FunctionTraits::return_type,
|
||||
typename FunctionTraits::arguments
|
||||
>::type;
|
||||
};
|
||||
|
||||
} // namespace function_traits
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
117
rclcpp/include/rclcpp/generic_publisher.hpp
Normal file
117
rclcpp/include/rclcpp/generic_publisher.hpp
Normal file
@@ -0,0 +1,117 @@
|
||||
// Copyright 2018, Bosch Software Innovations GmbH.
|
||||
// Copyright 2021, Apex.AI Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__GENERIC_PUBLISHER_HPP_
|
||||
#define RCLCPP__GENERIC_PUBLISHER_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "rcpputils/shared_library.hpp"
|
||||
|
||||
#include "rclcpp/callback_group.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
|
||||
#include "rclcpp/publisher_base.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
#include "rclcpp/serialized_message.hpp"
|
||||
#include "rclcpp/typesupport_helpers.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
#include "rmw/rmw.h"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
/// %Publisher for serialized messages whose type is not known at compile time.
|
||||
/**
|
||||
* Since the type is not known at compile time, this is not a template, and the dynamic library
|
||||
* containing type support information has to be identified and loaded based on the type name.
|
||||
*
|
||||
* It does not support intra-process handling.
|
||||
*/
|
||||
class GenericPublisher : public rclcpp::PublisherBase
|
||||
{
|
||||
public:
|
||||
// cppcheck-suppress unknownMacro
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(GenericPublisher)
|
||||
|
||||
/// Constructor.
|
||||
/**
|
||||
* In order to properly publish to a topic, this publisher needs to be added to
|
||||
* the node_topic_interface of the node passed into this constructor.
|
||||
*
|
||||
* \sa rclcpp::Node::create_generic_publisher() or rclcpp::create_generic_publisher() for
|
||||
* creating an instance of this class and adding it to the node_topic_interface.
|
||||
*
|
||||
* \param node_base Pointer to parent node's NodeBaseInterface
|
||||
* \param ts_lib Type support library, needs to correspond to topic_type
|
||||
* \param topic_name Topic name
|
||||
* \param topic_type Topic type
|
||||
* \param qos %QoS settings
|
||||
* \param options %Publisher options.
|
||||
* Not all publisher options are currently respected, the only relevant options for this
|
||||
* publisher are `event_callbacks`, `use_default_callbacks`, and `%callback_group`.
|
||||
*/
|
||||
template<typename AllocatorT = std::allocator<void>>
|
||||
GenericPublisher(
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||
std::shared_ptr<rcpputils::SharedLibrary> ts_lib,
|
||||
const std::string & topic_name,
|
||||
const std::string & topic_type,
|
||||
const rclcpp::QoS & qos,
|
||||
const rclcpp::PublisherOptionsWithAllocator<AllocatorT> & options)
|
||||
: rclcpp::PublisherBase(
|
||||
node_base,
|
||||
topic_name,
|
||||
*rclcpp::get_typesupport_handle(topic_type, "rosidl_typesupport_cpp", *ts_lib),
|
||||
options.template to_rcl_publisher_options<rclcpp::SerializedMessage>(qos),
|
||||
// NOTE(methylDragon): Passing these args separately is necessary for event binding
|
||||
options.event_callbacks,
|
||||
options.use_default_callbacks),
|
||||
ts_lib_(ts_lib)
|
||||
{}
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual ~GenericPublisher() = default;
|
||||
|
||||
/// Publish a rclcpp::SerializedMessage.
|
||||
RCLCPP_PUBLIC
|
||||
void publish(const rclcpp::SerializedMessage & message);
|
||||
|
||||
/**
|
||||
* Publish a rclcpp::SerializedMessage via loaned message after de-serialization.
|
||||
*
|
||||
* \param message a serialized message
|
||||
* \throws anything rclcpp::exceptions::throw_from_rcl_error can show
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void publish_as_loaned_msg(const rclcpp::SerializedMessage & message);
|
||||
|
||||
private:
|
||||
// The type support library should stay loaded, so it is stored in the GenericPublisher
|
||||
std::shared_ptr<rcpputils::SharedLibrary> ts_lib_;
|
||||
|
||||
void * borrow_loaned_message();
|
||||
void deserialize_message(
|
||||
const rmw_serialized_message_t & serialized_message,
|
||||
void * deserialized_msg);
|
||||
void publish_loaned_message(void * loaned_message);
|
||||
};
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__GENERIC_PUBLISHER_HPP_
|
||||
162
rclcpp/include/rclcpp/generic_subscription.hpp
Normal file
162
rclcpp/include/rclcpp/generic_subscription.hpp
Normal file
@@ -0,0 +1,162 @@
|
||||
// Copyright 2018, Bosch Software Innovations GmbH.
|
||||
// Copyright 2021, Apex.AI Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__GENERIC_SUBSCRIPTION_HPP_
|
||||
#define RCLCPP__GENERIC_SUBSCRIPTION_HPP_
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "rcpputils/shared_library.hpp"
|
||||
|
||||
#include "rclcpp/callback_group.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
#include "rclcpp/serialized_message.hpp"
|
||||
#include "rclcpp/subscription_base.hpp"
|
||||
#include "rclcpp/typesupport_helpers.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
/// %Subscription for serialized messages whose type is not known at compile time.
|
||||
/**
|
||||
* Since the type is not known at compile time, this is not a template, and the dynamic library
|
||||
* containing type support information has to be identified and loaded based on the type name.
|
||||
*
|
||||
* It does not support intra-process handling.
|
||||
*/
|
||||
class GenericSubscription : public rclcpp::SubscriptionBase
|
||||
{
|
||||
public:
|
||||
// cppcheck-suppress unknownMacro
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(GenericSubscription)
|
||||
|
||||
/// Constructor.
|
||||
/**
|
||||
* In order to properly subscribe to a topic, this subscription needs to be added to
|
||||
* the node_topic_interface of the node passed into this constructor.
|
||||
*
|
||||
* \sa rclcpp::Node::create_generic_subscription() or rclcpp::create_generic_subscription() for
|
||||
* creating an instance of this class and adding it to the node_topic_interface.
|
||||
*
|
||||
* \param node_base Pointer to parent node's NodeBaseInterface
|
||||
* \param ts_lib Type support library, needs to correspond to topic_type
|
||||
* \param topic_name Topic name
|
||||
* \param topic_type Topic type
|
||||
* \param qos %QoS settings
|
||||
* \param callback Callback for new messages of serialized form
|
||||
* \param options %Subscription options.
|
||||
* Not all subscription options are currently respected, the only relevant options for this
|
||||
* subscription are `event_callbacks`, `use_default_callbacks`, `ignore_local_publications`, and
|
||||
* `%callback_group`.
|
||||
*/
|
||||
template<typename AllocatorT = std::allocator<void>>
|
||||
GenericSubscription(
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||
const std::shared_ptr<rcpputils::SharedLibrary> ts_lib,
|
||||
const std::string & topic_name,
|
||||
const std::string & topic_type,
|
||||
const rclcpp::QoS & qos,
|
||||
// TODO(nnmm): Add variant for callback with message info. See issue #1604.
|
||||
std::function<void(std::shared_ptr<rclcpp::SerializedMessage>)> callback,
|
||||
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options)
|
||||
: SubscriptionBase(
|
||||
node_base,
|
||||
*rclcpp::get_typesupport_handle(topic_type, "rosidl_typesupport_cpp", *ts_lib),
|
||||
topic_name,
|
||||
options.to_rcl_subscription_options(qos),
|
||||
options.event_callbacks,
|
||||
options.use_default_callbacks,
|
||||
SubscriptionType::SERIALIZED_MESSAGE),
|
||||
callback_(callback),
|
||||
ts_lib_(ts_lib)
|
||||
{}
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual ~GenericSubscription() = default;
|
||||
|
||||
// Same as create_serialized_message() as the subscription is to serialized_messages only
|
||||
RCLCPP_PUBLIC
|
||||
std::shared_ptr<void> create_message() override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
std::shared_ptr<rclcpp::SerializedMessage> create_serialized_message() override;
|
||||
|
||||
/// Cast the message to a rclcpp::SerializedMessage and call the callback.
|
||||
RCLCPP_PUBLIC
|
||||
void handle_message(
|
||||
std::shared_ptr<void> & message, const rclcpp::MessageInfo & message_info) override;
|
||||
|
||||
/// Handle dispatching rclcpp::SerializedMessage to user callback.
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
handle_serialized_message(
|
||||
const std::shared_ptr<rclcpp::SerializedMessage> & serialized_message,
|
||||
const rclcpp::MessageInfo & message_info) override;
|
||||
|
||||
/// This function is currently not implemented.
|
||||
RCLCPP_PUBLIC
|
||||
void handle_loaned_message(
|
||||
void * loaned_message, const rclcpp::MessageInfo & message_info) override;
|
||||
|
||||
// Same as return_serialized_message() as the subscription is to serialized_messages only
|
||||
RCLCPP_PUBLIC
|
||||
void return_message(std::shared_ptr<void> & message) override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void return_serialized_message(std::shared_ptr<rclcpp::SerializedMessage> & message) override;
|
||||
|
||||
|
||||
// DYNAMIC TYPE ==================================================================================
|
||||
// TODO(methylDragon): Reorder later
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::dynamic_typesupport::DynamicMessageType::SharedPtr get_shared_dynamic_message_type()
|
||||
override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr get_shared_dynamic_message() override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::dynamic_typesupport::DynamicSerializationSupport::SharedPtr
|
||||
get_shared_dynamic_serialization_support() override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr create_dynamic_message() override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void return_dynamic_message(
|
||||
rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message) override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void handle_dynamic_message(
|
||||
const rclcpp::dynamic_typesupport::DynamicMessage::SharedPtr & message,
|
||||
const rclcpp::MessageInfo & message_info) override;
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(GenericSubscription)
|
||||
|
||||
std::function<void(std::shared_ptr<rclcpp::SerializedMessage>)> callback_;
|
||||
// The type support library should stay loaded, so it is stored in the GenericSubscription
|
||||
std::shared_ptr<rcpputils::SharedLibrary> ts_lib_;
|
||||
};
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__GENERIC_SUBSCRIPTION_HPP_
|
||||
98
rclcpp/include/rclcpp/get_message_type_support_handle.hpp
Normal file
98
rclcpp/include/rclcpp/get_message_type_support_handle.hpp
Normal file
@@ -0,0 +1,98 @@
|
||||
// Copyright 2021 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__GET_MESSAGE_TYPE_SUPPORT_HANDLE_HPP_
|
||||
#define RCLCPP__GET_MESSAGE_TYPE_SUPPORT_HANDLE_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "rosidl_runtime_cpp/traits.hpp"
|
||||
#include "rosidl_runtime_cpp/message_type_support_decl.hpp"
|
||||
#include "rosidl_typesupport_cpp/message_type_support.hpp"
|
||||
|
||||
#include "rclcpp/type_adapter.hpp"
|
||||
|
||||
/// Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
#ifdef DOXYGEN_ONLY
|
||||
|
||||
/// Returns the message type support for the given `MessageT` type.
|
||||
/**
|
||||
* \tparam MessageT an actual ROS message type or an adapted type using `rclcpp::TypeAdapter`
|
||||
*/
|
||||
template<typename MessageT>
|
||||
constexpr const rosidl_message_type_support_t & get_message_type_support_handle();
|
||||
|
||||
#else
|
||||
|
||||
template<typename MessageT>
|
||||
constexpr
|
||||
typename std::enable_if_t<
|
||||
rosidl_generator_traits::is_message<MessageT>::value,
|
||||
const rosidl_message_type_support_t &
|
||||
>
|
||||
get_message_type_support_handle()
|
||||
{
|
||||
auto handle = rosidl_typesupport_cpp::get_message_type_support_handle<MessageT>();
|
||||
if (!handle) {
|
||||
throw std::runtime_error("Type support handle unexpectedly nullptr");
|
||||
}
|
||||
return *handle;
|
||||
}
|
||||
|
||||
template<typename AdaptedType>
|
||||
constexpr
|
||||
typename std::enable_if_t<
|
||||
!rosidl_generator_traits::is_message<AdaptedType>::value &&
|
||||
rclcpp::TypeAdapter<AdaptedType>::is_specialized::value,
|
||||
const rosidl_message_type_support_t &
|
||||
>
|
||||
get_message_type_support_handle()
|
||||
{
|
||||
auto handle = rosidl_typesupport_cpp::get_message_type_support_handle<
|
||||
typename TypeAdapter<AdaptedType>::ros_message_type
|
||||
>();
|
||||
if (!handle) {
|
||||
throw std::runtime_error("Type support handle unexpectedly nullptr");
|
||||
}
|
||||
return *handle;
|
||||
}
|
||||
|
||||
// This specialization is a pass through runtime check, which allows a better
|
||||
// static_assert to catch this issue further down the line.
|
||||
// This should never get to be called in practice, and is purely defensive.
|
||||
template<
|
||||
typename AdaptedType
|
||||
>
|
||||
constexpr
|
||||
typename std::enable_if_t<
|
||||
!rosidl_generator_traits::is_message<AdaptedType>::value &&
|
||||
!TypeAdapter<AdaptedType>::is_specialized::value,
|
||||
const rosidl_message_type_support_t &
|
||||
>
|
||||
get_message_type_support_handle()
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"this specialization of rclcpp::get_message_type_support_handle() "
|
||||
"should never be called");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__GET_MESSAGE_TYPE_SUPPORT_HANDLE_HPP_
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "rcl/guard_condition.h"
|
||||
#include "rcl/wait.h"
|
||||
#include "rclcpp/context.hpp"
|
||||
#include "rclcpp/guard_condition.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/node_graph_interface.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
@@ -127,6 +128,11 @@ public:
|
||||
* If start_if_not_started() was never called, this function still succeeds,
|
||||
* but start_if_not_started() still cannot be called after this function.
|
||||
*
|
||||
* Note that if you override this method, but leave shutdown to be called in
|
||||
* the destruction of this base class, it will not call the overridden
|
||||
* version from your base class.
|
||||
* So you need to ensure you call your class's shutdown() in its destructor.
|
||||
*
|
||||
* \throws rclcpp::execptions::RCLError from rcl_guard_condition_fini()
|
||||
* \throws rclcpp::execptions::RCLError from rcl_wait_set_fini()
|
||||
* \throws std::system_error anything std::mutex::lock() throws
|
||||
@@ -187,7 +193,7 @@ private:
|
||||
mutable std::mutex node_graph_interfaces_mutex_;
|
||||
std::vector<rclcpp::node_interfaces::NodeGraphInterface *> node_graph_interfaces_;
|
||||
|
||||
rcl_guard_condition_t interrupt_guard_condition_ = rcl_get_zero_initialized_guard_condition();
|
||||
rclcpp::GuardCondition interrupt_guard_condition_;
|
||||
rcl_wait_set_t wait_set_ = rcl_get_zero_initialized_wait_set();
|
||||
};
|
||||
|
||||
|
||||
@@ -40,6 +40,8 @@ public:
|
||||
* Defaults to using the global default context singleton.
|
||||
* Shared ownership of the context is held with the guard condition until
|
||||
* destruction.
|
||||
* \param[in] guard_condition_options Optional guard condition options to be used.
|
||||
* Defaults to using the default guard condition options.
|
||||
* \throws std::invalid_argument if the context is nullptr.
|
||||
* \throws rclcpp::exceptions::RCLError based exceptions when underlying
|
||||
* rcl functions fail.
|
||||
@@ -47,7 +49,9 @@ public:
|
||||
RCLCPP_PUBLIC
|
||||
explicit GuardCondition(
|
||||
rclcpp::Context::SharedPtr context =
|
||||
rclcpp::contexts::get_global_default_context());
|
||||
rclcpp::contexts::get_global_default_context(),
|
||||
rcl_guard_condition_options_t guard_condition_options =
|
||||
rcl_guard_condition_get_default_options());
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
@@ -58,12 +62,17 @@ public:
|
||||
rclcpp::Context::SharedPtr
|
||||
get_context() const;
|
||||
|
||||
/// Return the underlying rcl guard condition structure.
|
||||
RCLCPP_PUBLIC
|
||||
rcl_guard_condition_t &
|
||||
get_rcl_guard_condition();
|
||||
|
||||
/// Return the underlying rcl guard condition structure.
|
||||
RCLCPP_PUBLIC
|
||||
const rcl_guard_condition_t &
|
||||
get_rcl_guard_condition() const;
|
||||
|
||||
/// Notify the wait set waiting on this condition, if any, that the condition had been met.
|
||||
/// Signal that the condition has been met, notifying both the wait set and listeners, if any.
|
||||
/**
|
||||
* This function is thread-safe, and may be called concurrently with waiting
|
||||
* on this guard condition in a wait set.
|
||||
@@ -89,10 +98,43 @@ public:
|
||||
bool
|
||||
exchange_in_use_by_wait_set_state(bool in_use_state);
|
||||
|
||||
/// Adds the guard condition to a waitset
|
||||
/**
|
||||
* This function is thread-safe.
|
||||
* \param[in] wait_set pointer to a wait set where to add the guard condition
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_to_wait_set(rcl_wait_set_t * wait_set);
|
||||
|
||||
/// Set a callback to be called whenever the guard condition is triggered.
|
||||
/**
|
||||
* The callback receives a size_t which is the number of times the guard condition was triggered
|
||||
* since the last time this callback was called.
|
||||
* Normally this is 1, but can be > 1 if the guard condition was triggered before any
|
||||
* callback was set.
|
||||
*
|
||||
* Calling it again will clear any previously set callback.
|
||||
*
|
||||
* This function is thread-safe.
|
||||
*
|
||||
* If you want more information available in the callback, like the guard condition
|
||||
* or other information, you may use a lambda with captures or std::bind.
|
||||
*
|
||||
* \param[in] callback functor to be called when the guard condition is triggered
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
set_on_trigger_callback(std::function<void(size_t)> callback);
|
||||
|
||||
protected:
|
||||
rclcpp::Context::SharedPtr context_;
|
||||
rcl_guard_condition_t rcl_guard_condition_;
|
||||
std::atomic<bool> in_use_by_wait_set_{false};
|
||||
std::recursive_mutex reentrant_mutex_;
|
||||
std::function<void(size_t)> on_trigger_callback_{nullptr};
|
||||
size_t unread_count_{0};
|
||||
rcl_wait_set_t * wait_set_{nullptr};
|
||||
};
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
@@ -29,7 +29,7 @@ class InitOptions
|
||||
{
|
||||
public:
|
||||
/// If true, the context will be shutdown on SIGINT by the signal handler (if it was installed).
|
||||
bool shutdown_on_sigint = true;
|
||||
bool shutdown_on_signal = true;
|
||||
|
||||
/// Constructor
|
||||
/**
|
||||
|
||||
35
rclcpp/include/rclcpp/is_ros_compatible_type.hpp
Normal file
35
rclcpp/include/rclcpp/is_ros_compatible_type.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright 2021 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__IS_ROS_COMPATIBLE_TYPE_HPP_
|
||||
#define RCLCPP__IS_ROS_COMPATIBLE_TYPE_HPP_
|
||||
|
||||
#include "rosidl_runtime_cpp/traits.hpp"
|
||||
|
||||
#include "rclcpp/type_adapter.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
struct is_ros_compatible_type
|
||||
{
|
||||
static constexpr bool value =
|
||||
rosidl_generator_traits::is_message<T>::value ||
|
||||
rclcpp::TypeAdapter<T>::is_specialized::value;
|
||||
};
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__IS_ROS_COMPATIBLE_TYPE_HPP_
|
||||
@@ -103,6 +103,9 @@ public:
|
||||
* \param[in] allocator Allocator instance in case middleware can not allocate messages
|
||||
* \throws anything rclcpp::exceptions::throw_from_rcl_error can throw.
|
||||
*/
|
||||
[[
|
||||
deprecated("used the LoanedMessage constructor that does not use a shared_ptr to the allocator")
|
||||
]]
|
||||
LoanedMessage(
|
||||
const rclcpp::PublisherBase * pub,
|
||||
std::shared_ptr<std::allocator<MessageT>> allocator)
|
||||
@@ -114,7 +117,9 @@ public:
|
||||
: pub_(std::move(other.pub_)),
|
||||
message_(std::move(other.message_)),
|
||||
message_allocator_(std::move(other.message_allocator_))
|
||||
{}
|
||||
{
|
||||
other.message_ = nullptr;
|
||||
}
|
||||
|
||||
/// Destructor of the LoanedMessage class.
|
||||
/**
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
@@ -79,7 +80,7 @@ get_node_logger(const rcl_node_t * node);
|
||||
/// Get the current logging directory.
|
||||
/**
|
||||
* For more details of how the logging directory is determined,
|
||||
* see \ref rcl_logging_get_logging_directory.
|
||||
* see rcl_logging_get_logging_directory().
|
||||
*
|
||||
* \returns the logging directory being used.
|
||||
* \throws rclcpp::exceptions::RCLError if an unexpected error occurs.
|
||||
@@ -122,6 +123,7 @@ private:
|
||||
: name_(new std::string(name)) {}
|
||||
|
||||
std::shared_ptr<const std::string> name_;
|
||||
std::shared_ptr<std::pair<std::string, std::string>> logger_sublogger_pairname_ = nullptr;
|
||||
|
||||
public:
|
||||
RCLCPP_PUBLIC
|
||||
@@ -157,13 +159,7 @@ public:
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
Logger
|
||||
get_child(const std::string & suffix)
|
||||
{
|
||||
if (!name_) {
|
||||
return Logger();
|
||||
}
|
||||
return Logger(*name_ + "." + suffix);
|
||||
}
|
||||
get_child(const std::string & suffix);
|
||||
|
||||
/// Set level for current logger.
|
||||
/**
|
||||
@@ -174,6 +170,24 @@ public:
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
set_level(Level level);
|
||||
|
||||
/// Get effective level for current logger.
|
||||
/**
|
||||
* The effective level is determined as the severity level of
|
||||
* the logger if it is set, otherwise it is the first specified severity
|
||||
* level of the logger's ancestors, starting with its closest ancestor.
|
||||
* The ancestor hierarchy is signified by logger names being separated by dots:
|
||||
* a logger named `x` is an ancestor of `x.y`, and both `x` and `x.y` are
|
||||
* ancestors of `x.y.z`, etc.
|
||||
* If the level has not been set for the logger nor any of its
|
||||
* ancestors, the default level is used.
|
||||
*
|
||||
* \throws rclcpp::exceptions::RCLError if any error happens.
|
||||
* \return Level for the current logger.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
Level
|
||||
get_effective_level() const;
|
||||
};
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
@@ -64,9 +64,11 @@ public:
|
||||
virtual void clear_handles() = 0;
|
||||
virtual void remove_null_handles(rcl_wait_set_t * wait_set) = 0;
|
||||
|
||||
virtual void add_guard_condition(const rcl_guard_condition_t * guard_condition) = 0;
|
||||
virtual void
|
||||
add_guard_condition(const rclcpp::GuardCondition & guard_condition) = 0;
|
||||
|
||||
virtual void remove_guard_condition(const rcl_guard_condition_t * guard_condition) = 0;
|
||||
virtual void
|
||||
remove_guard_condition(const rclcpp::GuardCondition * guard_condition) = 0;
|
||||
|
||||
virtual void
|
||||
get_next_subscription(
|
||||
@@ -98,52 +100,52 @@ public:
|
||||
|
||||
static rclcpp::SubscriptionBase::SharedPtr
|
||||
get_subscription_by_handle(
|
||||
std::shared_ptr<const rcl_subscription_t> subscriber_handle,
|
||||
const std::shared_ptr<const rcl_subscription_t> & subscriber_handle,
|
||||
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes);
|
||||
|
||||
static rclcpp::ServiceBase::SharedPtr
|
||||
get_service_by_handle(
|
||||
std::shared_ptr<const rcl_service_t> service_handle,
|
||||
const std::shared_ptr<const rcl_service_t> & service_handle,
|
||||
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes);
|
||||
|
||||
static rclcpp::ClientBase::SharedPtr
|
||||
get_client_by_handle(
|
||||
std::shared_ptr<const rcl_client_t> client_handle,
|
||||
const std::shared_ptr<const rcl_client_t> & client_handle,
|
||||
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes);
|
||||
|
||||
static rclcpp::TimerBase::SharedPtr
|
||||
get_timer_by_handle(
|
||||
std::shared_ptr<const rcl_timer_t> timer_handle,
|
||||
const std::shared_ptr<const rcl_timer_t> & timer_handle,
|
||||
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes);
|
||||
|
||||
static rclcpp::node_interfaces::NodeBaseInterface::SharedPtr
|
||||
get_node_by_group(
|
||||
rclcpp::CallbackGroup::SharedPtr group,
|
||||
const rclcpp::CallbackGroup::SharedPtr & group,
|
||||
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes);
|
||||
|
||||
static rclcpp::CallbackGroup::SharedPtr
|
||||
get_group_by_subscription(
|
||||
rclcpp::SubscriptionBase::SharedPtr subscription,
|
||||
const rclcpp::SubscriptionBase::SharedPtr & subscription,
|
||||
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes);
|
||||
|
||||
static rclcpp::CallbackGroup::SharedPtr
|
||||
get_group_by_service(
|
||||
rclcpp::ServiceBase::SharedPtr service,
|
||||
const rclcpp::ServiceBase::SharedPtr & service,
|
||||
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes);
|
||||
|
||||
static rclcpp::CallbackGroup::SharedPtr
|
||||
get_group_by_client(
|
||||
rclcpp::ClientBase::SharedPtr client,
|
||||
const rclcpp::ClientBase::SharedPtr & client,
|
||||
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes);
|
||||
|
||||
static rclcpp::CallbackGroup::SharedPtr
|
||||
get_group_by_timer(
|
||||
rclcpp::TimerBase::SharedPtr timer,
|
||||
const rclcpp::TimerBase::SharedPtr & timer,
|
||||
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes);
|
||||
|
||||
static rclcpp::CallbackGroup::SharedPtr
|
||||
get_group_by_waitable(
|
||||
rclcpp::Waitable::SharedPtr waitable,
|
||||
const rclcpp::Waitable::SharedPtr & waitable,
|
||||
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes);
|
||||
};
|
||||
|
||||
|
||||
115
rclcpp/include/rclcpp/network_flow_endpoint.hpp
Normal file
115
rclcpp/include/rclcpp/network_flow_endpoint.hpp
Normal file
@@ -0,0 +1,115 @@
|
||||
// Copyright 2020 Ericsson AB
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__NETWORK_FLOW_ENDPOINT_HPP_
|
||||
#define RCLCPP__NETWORK_FLOW_ENDPOINT_HPP_
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#include "rcl/network_flow_endpoints.h"
|
||||
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
/// Forward declaration
|
||||
class NetworkFlowEndpoint;
|
||||
|
||||
/// Check if two NetworkFlowEndpoint instances are equal
|
||||
RCLCPP_PUBLIC
|
||||
bool operator==(const NetworkFlowEndpoint & left, const NetworkFlowEndpoint & right);
|
||||
|
||||
/// Check if two NetworkFlowEndpoint instances are not equal
|
||||
RCLCPP_PUBLIC
|
||||
bool operator!=(const NetworkFlowEndpoint & left, const NetworkFlowEndpoint & right);
|
||||
|
||||
/// Streaming helper for NetworkFlowEndpoint
|
||||
RCLCPP_PUBLIC
|
||||
std::ostream & operator<<(std::ostream & os, const NetworkFlowEndpoint & network_flow_endpoint);
|
||||
|
||||
/**
|
||||
* Class describes a network flow endpoint based on the counterpart definition
|
||||
* in the RMW layer.
|
||||
*/
|
||||
class NetworkFlowEndpoint
|
||||
{
|
||||
public:
|
||||
/// Construct from rcl_network_flow_endpoint_t
|
||||
RCLCPP_PUBLIC
|
||||
explicit NetworkFlowEndpoint(const rcl_network_flow_endpoint_t & network_flow_endpoint)
|
||||
: transport_protocol_(
|
||||
rcl_network_flow_endpoint_get_transport_protocol_string(network_flow_endpoint.
|
||||
transport_protocol)),
|
||||
internet_protocol_(
|
||||
rcl_network_flow_endpoint_get_internet_protocol_string(
|
||||
network_flow_endpoint.internet_protocol)),
|
||||
transport_port_(network_flow_endpoint.transport_port),
|
||||
flow_label_(network_flow_endpoint.flow_label),
|
||||
dscp_(network_flow_endpoint.dscp),
|
||||
internet_address_(network_flow_endpoint.internet_address)
|
||||
{
|
||||
}
|
||||
|
||||
/// Get transport protocol
|
||||
RCLCPP_PUBLIC
|
||||
const std::string & transport_protocol() const;
|
||||
|
||||
/// Get internet protocol
|
||||
RCLCPP_PUBLIC
|
||||
const std::string & internet_protocol() const;
|
||||
|
||||
/// Get transport port
|
||||
RCLCPP_PUBLIC
|
||||
uint16_t transport_port() const;
|
||||
|
||||
/// Get flow label
|
||||
RCLCPP_PUBLIC
|
||||
uint32_t flow_label() const;
|
||||
|
||||
/// Get DSCP
|
||||
RCLCPP_PUBLIC
|
||||
uint8_t dscp() const;
|
||||
|
||||
/// Get internet address
|
||||
RCLCPP_PUBLIC
|
||||
const std::string & internet_address() const;
|
||||
|
||||
/// Compare two NetworkFlowEndpoint instances
|
||||
friend bool rclcpp::operator==(
|
||||
const NetworkFlowEndpoint & left,
|
||||
const NetworkFlowEndpoint & right);
|
||||
friend bool rclcpp::operator!=(
|
||||
const NetworkFlowEndpoint & left,
|
||||
const NetworkFlowEndpoint & right);
|
||||
|
||||
/// Streaming helper
|
||||
friend std::ostream & rclcpp::operator<<(
|
||||
std::ostream & os,
|
||||
const NetworkFlowEndpoint & network_flow_endpoint);
|
||||
|
||||
private:
|
||||
std::string transport_protocol_;
|
||||
std::string internet_protocol_;
|
||||
uint16_t transport_port_;
|
||||
uint32_t flow_label_;
|
||||
uint8_t dscp_;
|
||||
std::string internet_address_;
|
||||
};
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__NETWORK_FLOW_ENDPOINT_HPP_
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
@@ -41,6 +42,8 @@
|
||||
#include "rclcpp/clock.hpp"
|
||||
#include "rclcpp/context.hpp"
|
||||
#include "rclcpp/event.hpp"
|
||||
#include "rclcpp/generic_publisher.hpp"
|
||||
#include "rclcpp/generic_subscription.hpp"
|
||||
#include "rclcpp/logger.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/message_memory_strategy.hpp"
|
||||
@@ -145,10 +148,16 @@ public:
|
||||
rclcpp::CallbackGroupType group_type,
|
||||
bool automatically_add_to_executor_with_node = true);
|
||||
|
||||
/// Return the list of callback groups in the node.
|
||||
/// Iterate over the callback groups in the node, calling the given function on each valid one.
|
||||
/**
|
||||
* This method is called in a thread-safe way, and also makes sure to only call the given
|
||||
* function on those items that are still valid.
|
||||
*
|
||||
* \param[in] func The callback function to call on each valid callback group.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
const std::vector<rclcpp::CallbackGroup::WeakPtr> &
|
||||
get_callback_groups() const;
|
||||
void
|
||||
for_each_callback_group(const node_interfaces::NodeBaseInterface::CallbackGroupFunction & func);
|
||||
|
||||
/// Create and return a Publisher.
|
||||
/**
|
||||
@@ -203,13 +212,8 @@ public:
|
||||
typename MessageT,
|
||||
typename CallbackT,
|
||||
typename AllocatorT = std::allocator<void>,
|
||||
typename CallbackMessageT =
|
||||
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type,
|
||||
typename SubscriptionT = rclcpp::Subscription<CallbackMessageT, AllocatorT>,
|
||||
typename MessageMemoryStrategyT = rclcpp::message_memory_strategy::MessageMemoryStrategy<
|
||||
CallbackMessageT,
|
||||
AllocatorT
|
||||
>
|
||||
typename SubscriptionT = rclcpp::Subscription<MessageT, AllocatorT>,
|
||||
typename MessageMemoryStrategyT = typename SubscriptionT::MessageMemoryStrategyType
|
||||
>
|
||||
std::shared_ptr<SubscriptionT>
|
||||
create_subscription(
|
||||
@@ -223,7 +227,7 @@ public:
|
||||
)
|
||||
);
|
||||
|
||||
/// Create a timer.
|
||||
/// Create a wall timer that uses the wall clock to drive the callback.
|
||||
/**
|
||||
* \param[in] period Time interval between triggers of the callback.
|
||||
* \param[in] callback User-defined callback function.
|
||||
@@ -236,18 +240,47 @@ public:
|
||||
CallbackT callback,
|
||||
rclcpp::CallbackGroup::SharedPtr group = nullptr);
|
||||
|
||||
/// Create a timer that uses the node clock to drive the callback.
|
||||
/**
|
||||
* \param[in] period Time interval between triggers of the callback.
|
||||
* \param[in] callback User-defined callback function.
|
||||
* \param[in] group Callback group to execute this timer's callback in.
|
||||
*/
|
||||
template<typename DurationRepT = int64_t, typename DurationT = std::milli, typename CallbackT>
|
||||
typename rclcpp::GenericTimer<CallbackT>::SharedPtr
|
||||
create_timer(
|
||||
std::chrono::duration<DurationRepT, DurationT> period,
|
||||
CallbackT callback,
|
||||
rclcpp::CallbackGroup::SharedPtr group = nullptr);
|
||||
|
||||
/// Create and return a Client.
|
||||
/**
|
||||
* \param[in] service_name The topic to service on.
|
||||
* \param[in] qos_profile rmw_qos_profile_t Quality of service profile for client.
|
||||
* \param[in] group Callback group to call the service.
|
||||
* \return Shared pointer to the created client.
|
||||
* \deprecated use rclcpp::QoS instead of rmw_qos_profile_t
|
||||
*/
|
||||
template<typename ServiceT>
|
||||
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
|
||||
typename rclcpp::Client<ServiceT>::SharedPtr
|
||||
create_client(
|
||||
const std::string & service_name,
|
||||
const rmw_qos_profile_t & qos_profile,
|
||||
rclcpp::CallbackGroup::SharedPtr group = nullptr);
|
||||
|
||||
/// Create and return a Client.
|
||||
/**
|
||||
* \param[in] service_name The name on which the service is accessible.
|
||||
* \param[in] qos Quality of service profile for client.
|
||||
* \param[in] group Callback group to handle the reply to service calls.
|
||||
* \return Shared pointer to the created client.
|
||||
*/
|
||||
template<typename ServiceT>
|
||||
typename rclcpp::Client<ServiceT>::SharedPtr
|
||||
create_client(
|
||||
const std::string & service_name,
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_services_default,
|
||||
const rclcpp::QoS & qos = rclcpp::ServicesQoS(),
|
||||
rclcpp::CallbackGroup::SharedPtr group = nullptr);
|
||||
|
||||
/// Create and return a Service.
|
||||
@@ -257,15 +290,82 @@ public:
|
||||
* \param[in] qos_profile rmw_qos_profile_t Quality of service profile for client.
|
||||
* \param[in] group Callback group to call the service.
|
||||
* \return Shared pointer to the created service.
|
||||
* \deprecated use rclcpp::QoS instead of rmw_qos_profile_t
|
||||
*/
|
||||
template<typename ServiceT, typename CallbackT>
|
||||
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
|
||||
typename rclcpp::Service<ServiceT>::SharedPtr
|
||||
create_service(
|
||||
const std::string & service_name,
|
||||
CallbackT && callback,
|
||||
const rmw_qos_profile_t & qos_profile,
|
||||
rclcpp::CallbackGroup::SharedPtr group = nullptr);
|
||||
|
||||
/// Create and return a Service.
|
||||
/**
|
||||
* \param[in] service_name The topic to service on.
|
||||
* \param[in] callback User-defined callback function.
|
||||
* \param[in] qos Quality of service profile for the service.
|
||||
* \param[in] group Callback group to call the service.
|
||||
* \return Shared pointer to the created service.
|
||||
*/
|
||||
template<typename ServiceT, typename CallbackT>
|
||||
typename rclcpp::Service<ServiceT>::SharedPtr
|
||||
create_service(
|
||||
const std::string & service_name,
|
||||
CallbackT && callback,
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_services_default,
|
||||
const rclcpp::QoS & qos = rclcpp::ServicesQoS(),
|
||||
rclcpp::CallbackGroup::SharedPtr group = nullptr);
|
||||
|
||||
/// Create and return a GenericPublisher.
|
||||
/**
|
||||
* The returned pointer will never be empty, but this function can throw various exceptions, for
|
||||
* instance when the message's package can not be found on the AMENT_PREFIX_PATH.
|
||||
*
|
||||
* \param[in] topic_name Topic name
|
||||
* \param[in] topic_type Topic type
|
||||
* \param[in] qos %QoS settings
|
||||
* \param options %Publisher options.
|
||||
* Not all publisher options are currently respected, the only relevant options for this
|
||||
* publisher are `event_callbacks`, `use_default_callbacks`, and `%callback_group`.
|
||||
* \return Shared pointer to the created generic publisher.
|
||||
*/
|
||||
template<typename AllocatorT = std::allocator<void>>
|
||||
std::shared_ptr<rclcpp::GenericPublisher> create_generic_publisher(
|
||||
const std::string & topic_name,
|
||||
const std::string & topic_type,
|
||||
const rclcpp::QoS & qos,
|
||||
const rclcpp::PublisherOptionsWithAllocator<AllocatorT> & options = (
|
||||
rclcpp::PublisherOptionsWithAllocator<AllocatorT>()
|
||||
)
|
||||
);
|
||||
|
||||
/// Create and return a GenericSubscription.
|
||||
/**
|
||||
* The returned pointer will never be empty, but this function can throw various exceptions, for
|
||||
* instance when the message's package can not be found on the AMENT_PREFIX_PATH.
|
||||
*
|
||||
* \param[in] topic_name Topic name
|
||||
* \param[in] topic_type Topic type
|
||||
* \param[in] qos %QoS settings
|
||||
* \param[in] callback Callback for new messages of serialized form
|
||||
* \param[in] options %Subscription options.
|
||||
* Not all subscription options are currently respected, the only relevant options for this
|
||||
* subscription are `event_callbacks`, `use_default_callbacks`, `ignore_local_publications`, and
|
||||
* `%callback_group`.
|
||||
* \return Shared pointer to the created generic subscription.
|
||||
*/
|
||||
template<typename AllocatorT = std::allocator<void>>
|
||||
std::shared_ptr<rclcpp::GenericSubscription> create_generic_subscription(
|
||||
const std::string & topic_name,
|
||||
const std::string & topic_type,
|
||||
const rclcpp::QoS & qos,
|
||||
std::function<void(std::shared_ptr<rclcpp::SerializedMessage>)> callback,
|
||||
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options = (
|
||||
rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>()
|
||||
)
|
||||
);
|
||||
|
||||
/// Declare and initialize a parameter, return the effective value.
|
||||
/**
|
||||
* This method is used to declare that a parameter exists on this node.
|
||||
@@ -283,11 +383,21 @@ public:
|
||||
*
|
||||
* If `ignore_override` is `true`, the parameter override will be ignored.
|
||||
*
|
||||
* This method, if successful, will result in any callback registered with
|
||||
* add_on_set_parameters_callback to be called.
|
||||
* This method will result in any callback registered with
|
||||
* `add_on_set_parameters_callback` and `add_post_set_parameters_callback`
|
||||
* to be called for the parameter being set.
|
||||
*
|
||||
* If a callback was registered previously with `add_on_set_parameters_callback`,
|
||||
* it will be called prior to setting the parameter for the node.
|
||||
* If that callback prevents the initial value for the parameter from being
|
||||
* set then rclcpp::exceptions::InvalidParameterValueException is thrown.
|
||||
*
|
||||
* If a callback was registered previously with `add_post_set_parameters_callback`,
|
||||
* it will be called after setting the parameter successfully for the node.
|
||||
*
|
||||
* This method will _not_ result in any callbacks registered with
|
||||
* `add_pre_set_parameters_callback` to be called.
|
||||
*
|
||||
* The returned reference will remain valid until the parameter is
|
||||
* undeclared.
|
||||
*
|
||||
@@ -342,22 +452,6 @@ public:
|
||||
rcl_interfaces::msg::ParameterDescriptor{},
|
||||
bool ignore_override = false);
|
||||
|
||||
/// Declare a parameter
|
||||
[[deprecated(
|
||||
"declare_parameter() with only a name is deprecated and will be deleted in the future.\n" \
|
||||
"If you want to declare a parameter that won't change type without a default value use:\n" \
|
||||
"`node->declare_parameter<ParameterT>(name)`, where e.g. ParameterT=int64_t.\n\n" \
|
||||
"If you want to declare a parameter that can dynamically change type use:\n" \
|
||||
"```\n" \
|
||||
"rcl_interfaces::msg::ParameterDescriptor descriptor;\n" \
|
||||
"descriptor.dynamic_typing = true;\n" \
|
||||
"node->declare_parameter(name, rclcpp::ParameterValue{}, descriptor);\n" \
|
||||
"```"
|
||||
)]]
|
||||
RCLCPP_PUBLIC
|
||||
const rclcpp::ParameterValue &
|
||||
declare_parameter(const std::string & name);
|
||||
|
||||
/// Declare and initialize a parameter with a type.
|
||||
/**
|
||||
* See the non-templated declare_parameter() on this class for details.
|
||||
@@ -420,11 +514,22 @@ public:
|
||||
* If `ignore_overrides` is `true`, all the overrides of the parameters declared
|
||||
* by the function call will be ignored.
|
||||
*
|
||||
* This method will result in any callback registered with
|
||||
* `add_on_set_parameters_callback` and `add_post_set_parameters_callback`
|
||||
* to be called once for each parameter.
|
||||
*
|
||||
* This method, if successful, will result in any callback registered with
|
||||
* add_on_set_parameters_callback to be called, once for each parameter.
|
||||
* `add_on_set_parameters_callback` to be called, once for each parameter.
|
||||
* If that callback prevents the initial value for any parameter from being
|
||||
* set then rclcpp::exceptions::InvalidParameterValueException is thrown.
|
||||
*
|
||||
* If a callback was registered previously with `add_post_set_parameters_callback`,
|
||||
* it will be called after setting the parameters successfully for the node,
|
||||
* once for each parameter.
|
||||
*
|
||||
* This method will _not_ result in any callbacks registered with
|
||||
* `add_pre_set_parameters_callback` to be called.
|
||||
*
|
||||
* \param[in] namespace_ The namespace in which to declare the parameters.
|
||||
* \param[in] parameters The parameters to set in the given namespace.
|
||||
* \param[in] ignore_overrides When `true`, the parameters overrides are ignored.
|
||||
@@ -462,8 +567,9 @@ public:
|
||||
|
||||
/// Undeclare a previously declared parameter.
|
||||
/**
|
||||
* This method will not cause a callback registered with
|
||||
* add_on_set_parameters_callback to be called.
|
||||
* This method will _not_ cause a callback registered with any of the
|
||||
* `add_pre_set_parameters_callback`, `add_on_set_parameters_callback` and
|
||||
* `add_post_set_parameters_callback` to be called.
|
||||
*
|
||||
* \param[in] name The name of the parameter to be undeclared.
|
||||
* \throws rclcpp::exceptions::ParameterNotDeclaredException if the parameter
|
||||
@@ -497,11 +603,24 @@ public:
|
||||
* Parameter overrides are ignored by set_parameter.
|
||||
*
|
||||
* This method will result in any callback registered with
|
||||
* add_on_set_parameters_callback to be called.
|
||||
* `add_pre_set_parameters_callback`, add_on_set_parameters_callback` and
|
||||
* `add_post_set_parameters_callback` to be called once for the parameter
|
||||
* being set.
|
||||
*
|
||||
* This method will result in any callback registered with
|
||||
* `add_on_set_parameters_callback` to be called.
|
||||
* If the callback prevents the parameter from being set, then it will be
|
||||
* reflected in the SetParametersResult that is returned, but no exception
|
||||
* will be thrown.
|
||||
*
|
||||
* If a callback was registered previously with `add_pre_set_parameters_callback`,
|
||||
* it will be called once prior to the validation of the parameter for the node.
|
||||
* If this callback makes modified parameter list empty, then it will be reflected
|
||||
* in the returned result; no exceptions will be raised in this case.
|
||||
*
|
||||
* If a callback was registered previously with `add_post_set_parameters_callback`,
|
||||
* it will be called once after setting the parameter successfully for the node.
|
||||
*
|
||||
* If the value type of the parameter is rclcpp::PARAMETER_NOT_SET, and the
|
||||
* existing parameter type is something else, then the parameter will be
|
||||
* implicitly undeclared.
|
||||
@@ -538,11 +657,25 @@ public:
|
||||
* corresponding SetParametersResult in the vector returned by this function.
|
||||
*
|
||||
* This method will result in any callback registered with
|
||||
* add_on_set_parameters_callback to be called, once for each parameter.
|
||||
* `add_pre_set_parameters_callback`, `add_on_set_parameters_callback` and
|
||||
* `add_post_set_parameters_callback` to be called once for each parameter.
|
||||
|
||||
* If a callback was registered previously with `add_pre_set_parameters_callback`,
|
||||
* it will be called prior to the validation of parameters for the node,
|
||||
* once for each parameter.
|
||||
* If this callback makes modified parameter list empty, then it will be reflected
|
||||
* in the returned result; no exceptions will be raised in this case.
|
||||
*
|
||||
* This method will result in any callback registered with
|
||||
* `add_on_set_parameters_callback` to be called, once for each parameter.
|
||||
* If the callback prevents the parameter from being set, then, as mentioned
|
||||
* before, it will be reflected in the corresponding SetParametersResult
|
||||
* that is returned, but no exception will be thrown.
|
||||
*
|
||||
* If a callback was registered previously with `add_post_set_parameters_callback`,
|
||||
* it will be called after setting the parameters successfully for the node,
|
||||
* once for each parameter.
|
||||
*
|
||||
* Like set_parameter() this method will implicitly undeclare parameters
|
||||
* with the type rclcpp::PARAMETER_NOT_SET.
|
||||
*
|
||||
@@ -569,11 +702,25 @@ public:
|
||||
* If the exception is thrown then none of the parameters will have been set.
|
||||
*
|
||||
* This method will result in any callback registered with
|
||||
* add_on_set_parameters_callback to be called, just one time.
|
||||
* `add_pre_set_parameters_callback`, `add_on_set_parameters_callback` and
|
||||
* `add_post_set_parameters_callback` to be called only 'once' for all parameters.
|
||||
*
|
||||
* If a callback was registered previously with `add_pre_set_parameters_callback`,
|
||||
* it will be called prior to the validation of node parameters, just one time
|
||||
* for all parameters.
|
||||
* If this callback makes modified parameter list empty, then it will be reflected
|
||||
* in the returned result; no exceptions will be raised in this case.
|
||||
*
|
||||
* This method will result in any callback registered with
|
||||
* 'add_on_set_parameters_callback' to be called, just one time.
|
||||
* If the callback prevents the parameters from being set, then it will be
|
||||
* reflected in the SetParametersResult which is returned, but no exception
|
||||
* will be thrown.
|
||||
*
|
||||
* If a callback was registered previously with `add_post_set_parameters_callback`,
|
||||
* it will be called after setting the node parameters successfully, just one time
|
||||
* for all parameters.
|
||||
*
|
||||
* If you pass multiple rclcpp::Parameter instances with the same name, then
|
||||
* only the last one in the vector (forward iteration) will be set.
|
||||
*
|
||||
@@ -593,17 +740,21 @@ public:
|
||||
/**
|
||||
* If the parameter has not been declared, then this method may throw the
|
||||
* rclcpp::exceptions::ParameterNotDeclaredException exception.
|
||||
* If the parameter has not been initialized, then this method may throw the
|
||||
* rclcpp::exceptions::ParameterUninitializedException exception.
|
||||
*
|
||||
* If undeclared parameters are allowed, see the node option
|
||||
* rclcpp::NodeOptions::allow_undeclared_parameters, then this method will
|
||||
* not throw an exception, and instead return a default initialized
|
||||
* rclcpp::Parameter, which has a type of
|
||||
* not throw the rclcpp::exceptions::ParameterNotDeclaredException exception,
|
||||
* and instead return a default initialized rclcpp::Parameter, which has a type of
|
||||
* rclcpp::ParameterType::PARAMETER_NOT_SET.
|
||||
*
|
||||
* \param[in] name The name of the parameter to get.
|
||||
* \return The requested parameter inside of a rclcpp parameter object.
|
||||
* \throws rclcpp::exceptions::ParameterNotDeclaredException if the parameter
|
||||
* has not been declared and undeclared parameters are not allowed.
|
||||
* \throws rclcpp::exceptions::ParameterUninitializedException if the parameter
|
||||
* has not been initialized.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::Parameter
|
||||
@@ -667,14 +818,32 @@ public:
|
||||
ParameterT & parameter,
|
||||
const ParameterT & alternative_value) const;
|
||||
|
||||
/// Return the parameter value, or the "alternative_value" if not set.
|
||||
/**
|
||||
* If the parameter was not set, then the "alternative_value" argument is returned.
|
||||
*
|
||||
* This method will not throw the rclcpp::exceptions::ParameterNotDeclaredException exception.
|
||||
*
|
||||
* In all cases, the parameter is never set or declared within the node.
|
||||
*
|
||||
* \param[in] name The name of the parameter to get.
|
||||
* \param[in] alternative_value Value to be stored in output if the parameter was not set.
|
||||
* \returns The value of the parameter.
|
||||
*/
|
||||
template<typename ParameterT>
|
||||
ParameterT
|
||||
get_parameter_or(
|
||||
const std::string & name,
|
||||
const ParameterT & alternative_value) const;
|
||||
|
||||
/// Return the parameters by the given parameter names.
|
||||
/**
|
||||
* Like get_parameters(), this method may throw the
|
||||
* Like get_parameter(const std::string &), this method may throw the
|
||||
* rclcpp::exceptions::ParameterNotDeclaredException exception if the
|
||||
* requested parameter has not been declared and undeclared parameters are
|
||||
* not allowed.
|
||||
* not allowed, and may throw the rclcpp::exceptions::ParameterUninitializedException exception.
|
||||
*
|
||||
* Also like get_parameters(), if undeclared parameters are allowed and the
|
||||
* Also like get_parameter(const std::string &), if undeclared parameters are allowed and the
|
||||
* parameter has not been declared, then the corresponding rclcpp::Parameter
|
||||
* will be default initialized and therefore have the type
|
||||
* rclcpp::ParameterType::PARAMETER_NOT_SET.
|
||||
@@ -684,6 +853,8 @@ public:
|
||||
* \throws rclcpp::exceptions::ParameterNotDeclaredException if any of the
|
||||
* parameters have not been declared and undeclared parameters are not
|
||||
* allowed.
|
||||
* \throws rclcpp::exceptions::ParameterUninitializedException if any of the
|
||||
* parameters have not been initialized.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<rclcpp::Parameter>
|
||||
@@ -804,12 +975,85 @@ public:
|
||||
rcl_interfaces::msg::ListParametersResult
|
||||
list_parameters(const std::vector<std::string> & prefixes, uint64_t depth) const;
|
||||
|
||||
using PreSetParametersCallbackHandle =
|
||||
rclcpp::node_interfaces::PreSetParametersCallbackHandle;
|
||||
using PreSetParametersCallbackType =
|
||||
rclcpp::node_interfaces::NodeParametersInterface::PreSetParametersCallbackType;
|
||||
|
||||
using OnSetParametersCallbackHandle =
|
||||
rclcpp::node_interfaces::OnSetParametersCallbackHandle;
|
||||
using OnParametersSetCallbackType =
|
||||
rclcpp::node_interfaces::NodeParametersInterface::OnParametersSetCallbackType;
|
||||
using OnSetParametersCallbackType =
|
||||
rclcpp::node_interfaces::NodeParametersInterface::OnSetParametersCallbackType;
|
||||
using OnParametersSetCallbackType [[deprecated("use OnSetParametersCallbackType instead")]] =
|
||||
OnSetParametersCallbackType;
|
||||
|
||||
/// Add a callback for when parameters are being set.
|
||||
using PostSetParametersCallbackHandle =
|
||||
rclcpp::node_interfaces::PostSetParametersCallbackHandle;
|
||||
using PostSetParametersCallbackType =
|
||||
rclcpp::node_interfaces::NodeParametersInterface::PostSetParametersCallbackType;
|
||||
|
||||
/// Add a callback that gets triggered before parameters are validated.
|
||||
/**
|
||||
* This callback can be used to modify the original list of parameters being
|
||||
* set by the user.
|
||||
*
|
||||
* The modified list of parameters is then forwarded to the "on set parameter"
|
||||
* callback for validation.
|
||||
*
|
||||
* The callback is called whenever any of the `set_parameter*` methods are called
|
||||
* or when a set parameter service request is received.
|
||||
*
|
||||
* The callback takes a reference to the vector of parameters to be set.
|
||||
*
|
||||
* The vector of parameters may be modified by the callback.
|
||||
*
|
||||
* One of the use case of "pre set callback" can be updating additional parameters
|
||||
* conditioned on changes to a parameter.
|
||||
*
|
||||
* Users should retain a copy of the returned shared pointer, as the callback
|
||||
* is valid only as long as the smart pointer is alive.
|
||||
*
|
||||
* For an example callback:
|
||||
*
|
||||
*```cpp
|
||||
* void
|
||||
* preSetParameterCallback(std::vector<rclcpp::Parameter> & parameters)
|
||||
* {
|
||||
* for (auto & param : parameters) {
|
||||
* if (param.get_name() == "param1") {
|
||||
* parameters.push_back(rclcpp::Parameter("param2", 4.0));
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
* The above callback appends 'param2' to the list of parameters to be set if
|
||||
* 'param1' is being set by the user.
|
||||
*
|
||||
* All parameters in the vector will be set atomically.
|
||||
*
|
||||
* Note that the callback is only called while setting parameters with `set_parameter`,
|
||||
* `set_parameters`, `set_parameters_atomically`, or externally with a parameters service.
|
||||
*
|
||||
* The callback is not called when parameters are declared with `declare_parameter`
|
||||
* or `declare_parameters`.
|
||||
*
|
||||
* The callback is not called when parameters are undeclared with `undeclare_parameter`.
|
||||
*
|
||||
* An empty modified parameter list from the callback will result in "set_parameter*"
|
||||
* returning an unsuccessful result.
|
||||
*
|
||||
* The `remove_pre_set_parameters_callback` can be used to deregister the callback.
|
||||
*
|
||||
* \param callback The callback to register.
|
||||
* \returns A shared pointer. The callback is valid as long as the smart pointer is alive.
|
||||
* \throws std::bad_alloc if the allocation of the PreSetParametersCallbackHandle fails.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
RCUTILS_WARN_UNUSED
|
||||
PreSetParametersCallbackHandle::SharedPtr
|
||||
add_pre_set_parameters_callback(PreSetParametersCallbackType callback);
|
||||
|
||||
/// Add a callback to validate parameters before they are set.
|
||||
/**
|
||||
* The callback signature is designed to allow handling of any of the above
|
||||
* `set_parameter*` or `declare_parameter*` methods, and so it takes a const
|
||||
@@ -817,6 +1061,9 @@ public:
|
||||
* rcl_interfaces::msg::SetParametersResult to indicate whether or not the
|
||||
* parameter should be set or not, and if not why.
|
||||
*
|
||||
* Users should retain a copy of the returned shared pointer, as the callback
|
||||
* is valid only as long as the smart pointer is alive.
|
||||
*
|
||||
* For an example callback:
|
||||
*
|
||||
* ```cpp
|
||||
@@ -848,6 +1095,8 @@ public:
|
||||
* this callback, so when checking a new value against the existing one, you
|
||||
* must account for the case where the parameter is not yet set.
|
||||
*
|
||||
* The callback is not called when parameters are undeclared with `undeclare_parameter`.
|
||||
*
|
||||
* Some constraints like read_only are enforced before the callback is called.
|
||||
*
|
||||
* The callback may introspect other already set parameters (by calling any
|
||||
@@ -876,7 +1125,80 @@ public:
|
||||
RCLCPP_PUBLIC
|
||||
RCUTILS_WARN_UNUSED
|
||||
OnSetParametersCallbackHandle::SharedPtr
|
||||
add_on_set_parameters_callback(OnParametersSetCallbackType callback);
|
||||
add_on_set_parameters_callback(OnSetParametersCallbackType callback);
|
||||
|
||||
/// Add a callback that gets triggered after parameters are set successfully.
|
||||
/**
|
||||
* The callback is called when any of the `set_parameter*` or `declare_parameter*`
|
||||
* methods are successful.
|
||||
*
|
||||
* Users should retain a copy of the returned shared pointer, as the callback
|
||||
* is valid only as long as the smart pointer is alive.
|
||||
*
|
||||
* The callback takes a reference to a const vector of parameters that have been
|
||||
* set successfully.
|
||||
*
|
||||
* The post callback can be valuable as a place to cause side-effects based on
|
||||
* parameter changes.
|
||||
* For instance updating internally tracked class attributes once parameters
|
||||
* have been changed successfully.
|
||||
*
|
||||
* For an example callback:
|
||||
*
|
||||
* ```cpp
|
||||
* void
|
||||
* postSetParameterCallback(const std::vector<rclcpp::Parameter> & parameters)
|
||||
* {
|
||||
* for(const auto & param:parameters) {
|
||||
* // the internal class member can be changed after
|
||||
* // successful change to param1 or param2
|
||||
* if(param.get_name() == "param1") {
|
||||
* internal_tracked_class_parameter_1_ = param.get_value<double>();
|
||||
* }
|
||||
* else if(param.get_name() == "param2") {
|
||||
* internal_tracked_class_parameter_2_ = param.get_value<double>();
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* The above callback takes a const reference to list of parameters that have been
|
||||
* set successfully and as a result of this updates the internally tracked class attributes
|
||||
* `internal_tracked_class_parameter_1_` and `internal_tracked_class_parameter_2_`
|
||||
* respectively.
|
||||
*
|
||||
* This callback should not modify parameters.
|
||||
*
|
||||
* The callback is called when parameters are declared with `declare_parameter`
|
||||
* or `declare_parameters`. See `declare_parameter` or `declare_parameters` above.
|
||||
*
|
||||
* The callback is not called when parameters are undeclared with `undeclare_parameter`.
|
||||
*
|
||||
* If you want to make changes to parameters based on changes to another, use
|
||||
* `add_pre_set_parameters_callback`.
|
||||
*
|
||||
* The `remove_post_set_parameters_callback` can be used to deregister the callback.
|
||||
*
|
||||
* \param callback The callback to register.
|
||||
* \returns A shared pointer. The callback is valid as long as the smart pointer is alive.
|
||||
* \throws std::bad_alloc if the allocation of the OnSetParametersCallbackHandle fails.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
RCUTILS_WARN_UNUSED
|
||||
PostSetParametersCallbackHandle::SharedPtr
|
||||
add_post_set_parameters_callback(PostSetParametersCallbackType callback);
|
||||
|
||||
/// Remove a callback registered with `add_pre_set_parameters_callback`.
|
||||
/**
|
||||
* Delete a handler returned by `add_pre_set_parameters_callback`.
|
||||
*
|
||||
* \param handler The callback handler to remove.
|
||||
* \throws std::runtime_error if the handler was not created with `add_pre_set_parameters_callback`,
|
||||
* or if it has been removed before.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
remove_pre_set_parameters_callback(const PreSetParametersCallbackHandle * const handler);
|
||||
|
||||
/// Remove a callback registered with `add_on_set_parameters_callback`.
|
||||
/**
|
||||
@@ -905,6 +1227,18 @@ public:
|
||||
void
|
||||
remove_on_set_parameters_callback(const OnSetParametersCallbackHandle * const handler);
|
||||
|
||||
/// Remove a callback registered with `add_post_set_parameters_callback`.
|
||||
/**
|
||||
* Delete a handler returned by `add_post_set_parameters_callback`.
|
||||
*
|
||||
* \param handler The callback handler to remove.
|
||||
* \throws std::runtime_error if the handler was not created with `add_post_set_parameters_callback`,
|
||||
* or if it has been removed before.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
remove_post_set_parameters_callback(const PostSetParametersCallbackHandle * const handler);
|
||||
|
||||
/// Get the fully-qualified names of all available nodes.
|
||||
/**
|
||||
* The fully-qualified name includes the local namespace and name of the node.
|
||||
@@ -932,12 +1266,15 @@ public:
|
||||
std::map<std::string, std::vector<std::string>>
|
||||
get_service_names_and_types() const;
|
||||
|
||||
/// Return the number of publishers that are advertised on a given topic.
|
||||
/// Return a map of existing service names to list of service types for a specific node.
|
||||
/**
|
||||
* \param[in] node_name the node_name on which to count the publishers.
|
||||
* \param[in] namespace_ the namespace of the node associated with the name
|
||||
* \return number of publishers that are advertised on a given topic.
|
||||
* \throws std::runtime_error if publishers could not be counted
|
||||
* This function only considers services - not clients.
|
||||
* The returned names are the actual names used and do not have remap rules applied.
|
||||
*
|
||||
* \param[in] node_name name of the node.
|
||||
* \param[in] namespace_ namespace of the node.
|
||||
* \return a map of existing service names to list of service types.
|
||||
* \throws std::runtime_error anything that rcl_error can throw.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
std::map<std::string, std::vector<std::string>>
|
||||
|
||||
@@ -36,10 +36,12 @@
|
||||
|
||||
#include "rclcpp/contexts/default_context.hpp"
|
||||
#include "rclcpp/create_client.hpp"
|
||||
#include "rclcpp/create_generic_publisher.hpp"
|
||||
#include "rclcpp/create_generic_subscription.hpp"
|
||||
#include "rclcpp/create_publisher.hpp"
|
||||
#include "rclcpp/create_service.hpp"
|
||||
#include "rclcpp/create_timer.hpp"
|
||||
#include "rclcpp/create_subscription.hpp"
|
||||
#include "rclcpp/create_timer.hpp"
|
||||
#include "rclcpp/detail/resolve_enable_topic_statistics.hpp"
|
||||
#include "rclcpp/parameter.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
@@ -84,7 +86,6 @@ template<
|
||||
typename MessageT,
|
||||
typename CallbackT,
|
||||
typename AllocatorT,
|
||||
typename CallbackMessageT,
|
||||
typename SubscriptionT,
|
||||
typename MessageMemoryStrategyT>
|
||||
std::shared_ptr<SubscriptionT>
|
||||
@@ -119,6 +120,38 @@ Node::create_wall_timer(
|
||||
this->node_timers_.get());
|
||||
}
|
||||
|
||||
template<typename DurationRepT, typename DurationT, typename CallbackT>
|
||||
typename rclcpp::GenericTimer<CallbackT>::SharedPtr
|
||||
Node::create_timer(
|
||||
std::chrono::duration<DurationRepT, DurationT> period,
|
||||
CallbackT callback,
|
||||
rclcpp::CallbackGroup::SharedPtr group)
|
||||
{
|
||||
return rclcpp::create_timer(
|
||||
this->get_clock(),
|
||||
period,
|
||||
std::move(callback),
|
||||
group,
|
||||
this->node_base_.get(),
|
||||
this->node_timers_.get());
|
||||
}
|
||||
|
||||
template<typename ServiceT>
|
||||
typename Client<ServiceT>::SharedPtr
|
||||
Node::create_client(
|
||||
const std::string & service_name,
|
||||
const rclcpp::QoS & qos,
|
||||
rclcpp::CallbackGroup::SharedPtr group)
|
||||
{
|
||||
return rclcpp::create_client<ServiceT>(
|
||||
node_base_,
|
||||
node_graph_,
|
||||
node_services_,
|
||||
extend_name_with_sub_namespace(service_name, this->get_sub_namespace()),
|
||||
qos,
|
||||
group);
|
||||
}
|
||||
|
||||
template<typename ServiceT>
|
||||
typename Client<ServiceT>::SharedPtr
|
||||
Node::create_client(
|
||||
@@ -135,6 +168,23 @@ Node::create_client(
|
||||
group);
|
||||
}
|
||||
|
||||
template<typename ServiceT, typename CallbackT>
|
||||
typename rclcpp::Service<ServiceT>::SharedPtr
|
||||
Node::create_service(
|
||||
const std::string & service_name,
|
||||
CallbackT && callback,
|
||||
const rclcpp::QoS & qos,
|
||||
rclcpp::CallbackGroup::SharedPtr group)
|
||||
{
|
||||
return rclcpp::create_service<ServiceT, CallbackT>(
|
||||
node_base_,
|
||||
node_services_,
|
||||
extend_name_with_sub_namespace(service_name, this->get_sub_namespace()),
|
||||
std::forward<CallbackT>(callback),
|
||||
qos,
|
||||
group);
|
||||
}
|
||||
|
||||
template<typename ServiceT, typename CallbackT>
|
||||
typename rclcpp::Service<ServiceT>::SharedPtr
|
||||
Node::create_service(
|
||||
@@ -152,6 +202,43 @@ Node::create_service(
|
||||
group);
|
||||
}
|
||||
|
||||
template<typename AllocatorT>
|
||||
std::shared_ptr<rclcpp::GenericPublisher>
|
||||
Node::create_generic_publisher(
|
||||
const std::string & topic_name,
|
||||
const std::string & topic_type,
|
||||
const rclcpp::QoS & qos,
|
||||
const rclcpp::PublisherOptionsWithAllocator<AllocatorT> & options)
|
||||
{
|
||||
return rclcpp::create_generic_publisher(
|
||||
node_topics_,
|
||||
extend_name_with_sub_namespace(topic_name, this->get_sub_namespace()),
|
||||
topic_type,
|
||||
qos,
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
template<typename AllocatorT>
|
||||
std::shared_ptr<rclcpp::GenericSubscription>
|
||||
Node::create_generic_subscription(
|
||||
const std::string & topic_name,
|
||||
const std::string & topic_type,
|
||||
const rclcpp::QoS & qos,
|
||||
std::function<void(std::shared_ptr<rclcpp::SerializedMessage>)> callback,
|
||||
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options)
|
||||
{
|
||||
return rclcpp::create_generic_subscription(
|
||||
node_topics_,
|
||||
extend_name_with_sub_namespace(topic_name, this->get_sub_namespace()),
|
||||
topic_type,
|
||||
qos,
|
||||
std::move(callback),
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
template<typename ParameterT>
|
||||
auto
|
||||
Node::declare_parameter(
|
||||
@@ -182,12 +269,16 @@ Node::declare_parameter(
|
||||
// get advantage of parameter value template magic to get
|
||||
// the correct rclcpp::ParameterType from ParameterT
|
||||
rclcpp::ParameterValue value{ParameterT{}};
|
||||
return this->declare_parameter(
|
||||
name,
|
||||
value.get_type(),
|
||||
parameter_descriptor,
|
||||
ignore_override
|
||||
).get<ParameterT>();
|
||||
try {
|
||||
return this->declare_parameter(
|
||||
name,
|
||||
value.get_type(),
|
||||
parameter_descriptor,
|
||||
ignore_override
|
||||
).get<ParameterT>();
|
||||
} catch (const ParameterTypeException &) {
|
||||
throw exceptions::UninitializedStaticallyTypedParameterException(name);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename ParameterT>
|
||||
@@ -271,6 +362,17 @@ Node::get_parameter_or(
|
||||
return got_parameter;
|
||||
}
|
||||
|
||||
template<typename ParameterT>
|
||||
ParameterT
|
||||
Node::get_parameter_or(
|
||||
const std::string & name,
|
||||
const ParameterT & alternative_value) const
|
||||
{
|
||||
ParameterT parameter;
|
||||
get_parameter_or(name, parameter, alternative_value);
|
||||
return parameter;
|
||||
}
|
||||
|
||||
// this is a partially-specialized version of get_parameter above,
|
||||
// where our concrete type for ParameterT is std::map, but the to-be-determined
|
||||
// type is the value in the map.
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
// Copyright 2022 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__NODE_INTERFACES__DETAIL__NODE_INTERFACES_HELPERS_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__DETAIL__NODE_INTERFACES_HELPERS_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace node_interfaces
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
// Support and Helper template classes for the NodeInterfaces class.
|
||||
|
||||
template<typename NodeT, typename ... Ts>
|
||||
std::tuple<std::shared_ptr<Ts>...>
|
||||
init_tuple(NodeT & n);
|
||||
|
||||
/// Stores the interfaces in a tuple, provides constructors, and getters.
|
||||
template<typename ... InterfaceTs>
|
||||
struct NodeInterfacesStorage
|
||||
{
|
||||
template<typename NodeT>
|
||||
NodeInterfacesStorage(NodeT & node) // NOLINT(runtime/explicit)
|
||||
: interfaces_(init_tuple<decltype(node), InterfaceTs ...>(node))
|
||||
{}
|
||||
|
||||
NodeInterfacesStorage()
|
||||
: interfaces_()
|
||||
{}
|
||||
|
||||
explicit NodeInterfacesStorage(std::shared_ptr<InterfaceTs>... args)
|
||||
: interfaces_(args ...)
|
||||
{}
|
||||
|
||||
/// Individual Node Interface non-const getter.
|
||||
template<typename NodeInterfaceT>
|
||||
std::shared_ptr<NodeInterfaceT>
|
||||
get()
|
||||
{
|
||||
static_assert(
|
||||
(std::is_same_v<NodeInterfaceT, InterfaceTs>|| ...),
|
||||
"NodeInterfaces class does not contain given NodeInterfaceT");
|
||||
return std::get<std::shared_ptr<NodeInterfaceT>>(interfaces_);
|
||||
}
|
||||
|
||||
/// Individual Node Interface const getter.
|
||||
template<typename NodeInterfaceT>
|
||||
std::shared_ptr<const NodeInterfaceT>
|
||||
get() const
|
||||
{
|
||||
static_assert(
|
||||
(std::is_same_v<NodeInterfaceT, InterfaceTs>|| ...),
|
||||
"NodeInterfaces class does not contain given NodeInterfaceT");
|
||||
return std::get<std::shared_ptr<NodeInterfaceT>>(interfaces_);
|
||||
}
|
||||
|
||||
protected:
|
||||
std::tuple<std::shared_ptr<InterfaceTs>...> interfaces_;
|
||||
};
|
||||
|
||||
/// Prototype of NodeInterfacesSupports.
|
||||
/**
|
||||
* Should read NodeInterfacesSupports<..., T, ...> as "NodeInterfaces supports T", and
|
||||
* if NodeInterfacesSupport is specialized for T, the is_supported should be
|
||||
* set to std::true_type, but by default it is std::false_type, which will
|
||||
* lead to a compiler error when trying to use T with NodeInterfaces.
|
||||
*/
|
||||
template<typename StorageClassT, typename ... Ts>
|
||||
struct NodeInterfacesSupports;
|
||||
|
||||
/// Prototype of NodeInterfacesSupportCheck template meta-function.
|
||||
/**
|
||||
* This meta-function checks that all the types given are supported,
|
||||
* throwing a more human-readable error if an unsupported type is used.
|
||||
*/
|
||||
template<typename StorageClassT, typename ... InterfaceTs>
|
||||
struct NodeInterfacesSupportCheck;
|
||||
|
||||
/// Iterating specialization that ensures classes are supported and inherited.
|
||||
template<typename StorageClassT, typename NextInterfaceT, typename ... RemainingInterfaceTs>
|
||||
struct NodeInterfacesSupportCheck<StorageClassT, NextInterfaceT, RemainingInterfaceTs ...>
|
||||
: public NodeInterfacesSupportCheck<StorageClassT, RemainingInterfaceTs ...>
|
||||
{
|
||||
static_assert(
|
||||
NodeInterfacesSupports<StorageClassT, NextInterfaceT>::is_supported::value,
|
||||
"given NodeInterfaceT is not supported by rclcpp::node_interfaces::NodeInterfaces");
|
||||
};
|
||||
|
||||
/// Terminating case when there are no more "RemainingInterfaceTs".
|
||||
template<typename StorageClassT>
|
||||
struct NodeInterfacesSupportCheck<StorageClassT>
|
||||
{};
|
||||
|
||||
/// Default specialization, needs to be specialized for each supported interface.
|
||||
template<typename StorageClassT, typename ... RemainingInterfaceTs>
|
||||
struct NodeInterfacesSupports
|
||||
{
|
||||
// Specializations need to set this to std::true_type in addition to other interfaces.
|
||||
using is_supported = std::false_type;
|
||||
};
|
||||
|
||||
/// Terminating specialization of NodeInterfacesSupports.
|
||||
template<typename StorageClassT>
|
||||
struct NodeInterfacesSupports<StorageClassT>
|
||||
: public StorageClassT
|
||||
{
|
||||
/// Perfect forwarding constructor to get arguments down to StorageClassT.
|
||||
template<typename ... ArgsT>
|
||||
explicit NodeInterfacesSupports(ArgsT && ... args)
|
||||
: StorageClassT(std::forward<ArgsT>(args) ...)
|
||||
{}
|
||||
};
|
||||
|
||||
// Helper functions to initialize the tuple in NodeInterfaces.
|
||||
|
||||
template<typename StorageClassT, typename ElementT, typename TupleT, typename NodeT>
|
||||
void
|
||||
init_element(TupleT & t, NodeT & n)
|
||||
{
|
||||
std::get<std::shared_ptr<ElementT>>(t) =
|
||||
NodeInterfacesSupports<StorageClassT, ElementT>::get_from_node_like(n);
|
||||
}
|
||||
|
||||
template<typename NodeT, typename ... Ts>
|
||||
std::tuple<std::shared_ptr<Ts>...>
|
||||
init_tuple(NodeT & n)
|
||||
{
|
||||
using StorageClassT = NodeInterfacesStorage<Ts ...>;
|
||||
std::tuple<std::shared_ptr<Ts>...> t;
|
||||
(init_element<StorageClassT, Ts>(t, n), ...);
|
||||
return t;
|
||||
}
|
||||
|
||||
/// Macro for creating specializations with less boilerplate.
|
||||
/**
|
||||
* You can use this macro to add support for your interface class if:
|
||||
*
|
||||
* - The standard getter is get_node_{NodeInterfaceName}_interface(), and
|
||||
* - the getter returns a non-const shared_ptr<{NodeInterfaceType}>
|
||||
*
|
||||
* Examples of using this can be seen in the standard node interface headers
|
||||
* in rclcpp, e.g. rclcpp/node_interfaces/node_base_interface.hpp has:
|
||||
*
|
||||
* RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeBaseInterface, base)
|
||||
*
|
||||
* If your interface has a non-standard getter, or you want to instrument it or
|
||||
* something like that, then you'll need to create your own specialization of
|
||||
* the NodeInterfacesSupports struct without this macro.
|
||||
*/
|
||||
#define RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(NodeInterfaceType, NodeInterfaceName) \
|
||||
namespace rclcpp::node_interfaces::detail { \
|
||||
template<typename StorageClassT, typename ... RemainingInterfaceTs> \
|
||||
struct NodeInterfacesSupports< \
|
||||
StorageClassT, \
|
||||
NodeInterfaceType, \
|
||||
RemainingInterfaceTs ...> \
|
||||
: public NodeInterfacesSupports<StorageClassT, RemainingInterfaceTs ...> \
|
||||
{ \
|
||||
using is_supported = std::true_type; \
|
||||
\
|
||||
template<typename NodeT> \
|
||||
static \
|
||||
std::shared_ptr<NodeInterfaceType> \
|
||||
get_from_node_like(NodeT & node_like) \
|
||||
{ \
|
||||
return node_like.get_node_ ## NodeInterfaceName ## _interface(); \
|
||||
} \
|
||||
\
|
||||
/* Perfect forwarding constructor to get arguments down to StorageClassT (eventually). */ \
|
||||
template<typename ... ArgsT> \
|
||||
explicit NodeInterfacesSupports(ArgsT && ... args) \
|
||||
: NodeInterfacesSupports<StorageClassT, RemainingInterfaceTs ...>( \
|
||||
std::forward<ArgsT>(args) ...) \
|
||||
{} \
|
||||
\
|
||||
std::shared_ptr<NodeInterfaceType> \
|
||||
get_node_ ## NodeInterfaceName ## _interface() \
|
||||
{ \
|
||||
return StorageClassT::template get<NodeInterfaceType>(); \
|
||||
} \
|
||||
}; \
|
||||
} // namespace rclcpp::node_interfaces::detail
|
||||
|
||||
} // namespace detail
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__DETAIL__NODE_INTERFACES_HELPERS_HPP_
|
||||
@@ -15,11 +15,14 @@
|
||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_BASE_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__NODE_BASE_HPP_
|
||||
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "rcl/node.h"
|
||||
#include "rclcpp/callback_group.hpp"
|
||||
#include "rclcpp/context.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
@@ -31,11 +34,18 @@ namespace node_interfaces
|
||||
{
|
||||
|
||||
/// Implementation of the NodeBase part of the Node API.
|
||||
class NodeBase : public NodeBaseInterface
|
||||
class NodeBase : public NodeBaseInterface, public std::enable_shared_from_this<NodeBase>
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeBase)
|
||||
|
||||
/// Constructor.
|
||||
/**
|
||||
* If nullptr (default) is given for the default_callback_group, one will
|
||||
* be created by the constructor using the create_callback_group() method,
|
||||
* but virtual dispatch will not occur so overrides of that method will not
|
||||
* be used.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
NodeBase(
|
||||
const std::string & node_name,
|
||||
@@ -43,7 +53,8 @@ public:
|
||||
rclcpp::Context::SharedPtr context,
|
||||
const rcl_node_options_t & rcl_node_options,
|
||||
bool use_intra_process_default,
|
||||
bool enable_topic_statistics_default);
|
||||
bool enable_topic_statistics_default,
|
||||
rclcpp::CallbackGroup::SharedPtr default_callback_group = nullptr);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
@@ -95,22 +106,25 @@ public:
|
||||
bool
|
||||
callback_group_in_node(rclcpp::CallbackGroup::SharedPtr group) override;
|
||||
|
||||
/// Iterate over the stored callback groups, calling the given function on each valid one.
|
||||
/**
|
||||
* This method is called in a thread-safe way, and also makes sure to only call the given
|
||||
* function on those items that are still valid.
|
||||
*
|
||||
* \param[in] func The callback function to call on each valid callback group.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
const std::vector<rclcpp::CallbackGroup::WeakPtr> &
|
||||
get_callback_groups() const override;
|
||||
void
|
||||
for_each_callback_group(const CallbackGroupFunction & func) override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
std::atomic_bool &
|
||||
get_associated_with_executor_atomic() override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
rcl_guard_condition_t *
|
||||
rclcpp::GuardCondition &
|
||||
get_notify_guard_condition() override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
std::unique_lock<std::recursive_mutex>
|
||||
acquire_notify_guard_condition_lock() const override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
get_use_intra_process_default() const override;
|
||||
@@ -132,13 +146,14 @@ private:
|
||||
std::shared_ptr<rcl_node_t> node_handle_;
|
||||
|
||||
rclcpp::CallbackGroup::SharedPtr default_callback_group_;
|
||||
std::mutex callback_groups_mutex_;
|
||||
std::vector<rclcpp::CallbackGroup::WeakPtr> callback_groups_;
|
||||
|
||||
std::atomic_bool associated_with_executor_;
|
||||
|
||||
/// Guard condition for notifying the Executor of changes to this node.
|
||||
mutable std::recursive_mutex notify_guard_condition_mutex_;
|
||||
rcl_guard_condition_t notify_guard_condition_ = rcl_get_zero_initialized_guard_condition();
|
||||
rclcpp::GuardCondition notify_guard_condition_;
|
||||
bool notify_guard_condition_is_valid_;
|
||||
};
|
||||
|
||||
|
||||
@@ -15,16 +15,18 @@
|
||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_BASE_INTERFACE_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__NODE_BASE_INTERFACE_HPP_
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "rcl/node.h"
|
||||
|
||||
#include "rclcpp/callback_group.hpp"
|
||||
#include "rclcpp/context.hpp"
|
||||
#include "rclcpp/guard_condition.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
@@ -122,11 +124,19 @@ public:
|
||||
bool
|
||||
callback_group_in_node(rclcpp::CallbackGroup::SharedPtr group) = 0;
|
||||
|
||||
/// Return list of callback groups associated with this node.
|
||||
using CallbackGroupFunction = std::function<void (rclcpp::CallbackGroup::SharedPtr)>;
|
||||
|
||||
/// Iterate over the stored callback groups, calling the given function on each valid one.
|
||||
/**
|
||||
* This method is called in a thread-safe way, and also makes sure to only call the given
|
||||
* function on those items that are still valid.
|
||||
*
|
||||
* \param[in] func The callback function to call on each valid callback group.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
const std::vector<rclcpp::CallbackGroup::WeakPtr> &
|
||||
get_callback_groups() const = 0;
|
||||
void
|
||||
for_each_callback_group(const CallbackGroupFunction & func) = 0;
|
||||
|
||||
/// Return the atomic bool which is used to ensure only one executor is used.
|
||||
RCLCPP_PUBLIC
|
||||
@@ -134,24 +144,17 @@ public:
|
||||
std::atomic_bool &
|
||||
get_associated_with_executor_atomic() = 0;
|
||||
|
||||
/// Return guard condition that should be notified when the internal node state changes.
|
||||
/// Return a guard condition that should be notified when the internal node state changes.
|
||||
/**
|
||||
* For example, this should be notified when a publisher is added or removed.
|
||||
*
|
||||
* \return the rcl_guard_condition_t if it is valid, else nullptr
|
||||
* \return the GuardCondition if it is valid, else thow runtime error
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
rcl_guard_condition_t *
|
||||
rclcpp::GuardCondition &
|
||||
get_notify_guard_condition() = 0;
|
||||
|
||||
/// Acquire and return a scoped lock that protects the notify guard condition.
|
||||
/** This should be used when triggering the notify guard condition. */
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
std::unique_lock<std::recursive_mutex>
|
||||
acquire_notify_guard_condition_lock() const = 0;
|
||||
|
||||
/// Return the default preference for using intra process communication.
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
@@ -175,4 +178,6 @@ public:
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeBaseInterface, base)
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_BASE_INTERFACE_HPP_
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_CLOCK_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__NODE_CLOCK_HPP_
|
||||
|
||||
#include "rcl/time.h"
|
||||
#include "rclcpp/clock.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
@@ -42,7 +43,8 @@ public:
|
||||
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics,
|
||||
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph,
|
||||
rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services,
|
||||
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging);
|
||||
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging,
|
||||
rcl_clock_type_t clock_type);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
@@ -67,7 +69,7 @@ private:
|
||||
rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services_;
|
||||
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging_;
|
||||
|
||||
rclcpp::Clock::SharedPtr ros_clock_;
|
||||
rclcpp::Clock::SharedPtr clock_;
|
||||
};
|
||||
|
||||
} // namespace node_interfaces
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include "rclcpp/clock.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
@@ -50,4 +51,6 @@ public:
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeClockInterface, clock)
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_CLOCK_INTERFACE_HPP_
|
||||
|
||||
@@ -15,11 +15,14 @@
|
||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_GRAPH_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__NODE_GRAPH_HPP_
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@@ -70,10 +73,34 @@ public:
|
||||
const std::string & node_name,
|
||||
const std::string & namespace_) const override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
std::map<std::string, std::vector<std::string>>
|
||||
get_client_names_and_types_by_node(
|
||||
const std::string & node_name,
|
||||
const std::string & namespace_) const override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
std::map<std::string, std::vector<std::string>>
|
||||
get_publisher_names_and_types_by_node(
|
||||
const std::string & node_name,
|
||||
const std::string & namespace_,
|
||||
bool no_demangle = false) const override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
std::map<std::string, std::vector<std::string>>
|
||||
get_subscriber_names_and_types_by_node(
|
||||
const std::string & node_name,
|
||||
const std::string & namespace_,
|
||||
bool no_demangle = false) const override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<std::string>
|
||||
get_node_names() const override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<std::tuple<std::string, std::string, std::string>>
|
||||
get_node_names_with_enclaves() const override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<std::pair<std::string, std::string>>
|
||||
get_node_names_and_namespaces() const override;
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <chrono>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
@@ -28,6 +29,7 @@
|
||||
|
||||
#include "rclcpp/event.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
@@ -146,7 +148,9 @@ public:
|
||||
/**
|
||||
* A topic is considered to exist when at least one publisher or subscriber
|
||||
* exists for it, whether they be local or remote to this process.
|
||||
* The returned names are the actual names used and do not have remap rules applied.
|
||||
* The returned names are the actual names of the topics, either announced by another nodes or by this one.
|
||||
* Attempting to create publishers or subscribers using names returned by this function may not
|
||||
* result in the desired topic name being used depending on the remap rules in use.
|
||||
*
|
||||
* \param[in] no_demangle if true, topic names and types are not demangled
|
||||
*/
|
||||
@@ -160,7 +164,9 @@ public:
|
||||
* A service is considered to exist when at least one service server or
|
||||
* service client exists for it, whether they be local or remote to this
|
||||
* process.
|
||||
* The returned names are the actual names used and do not have remap rules applied.
|
||||
* The returned names are the actual names of the services, either announced by another nodes or by this one.
|
||||
* Attempting to create clients or services using names returned by this function may not result in
|
||||
* the desired service name being used depending on the remap rules in use.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
@@ -170,7 +176,9 @@ public:
|
||||
/// Return a map of existing service names to list of service types for a specific node.
|
||||
/**
|
||||
* This function only considers services - not clients.
|
||||
* The returned names are the actual names used and do not have remap rules applied.
|
||||
* The returned names are the actual names after remap rules applied.
|
||||
* Attempting to create service clients using names returned by this function may not
|
||||
* result in the desired service name being used depending on the remap rules in use.
|
||||
*
|
||||
* \param[in] node_name name of the node
|
||||
* \param[in] namespace_ namespace of the node
|
||||
@@ -182,18 +190,85 @@ public:
|
||||
const std::string & node_name,
|
||||
const std::string & namespace_) const = 0;
|
||||
|
||||
/// Return a map of existing service names and types with a specific node.
|
||||
/**
|
||||
* This function only considers clients - not service servers.
|
||||
* The returned names are the actual names after remap rules applied.
|
||||
* Attempting to create service servers using names returned by this function may not
|
||||
* result in the desired service name being used depending on the remap rules in use.
|
||||
*
|
||||
* \param[in] node_name name of the node
|
||||
* \param[in] namespace_ namespace of the node
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
std::map<std::string, std::vector<std::string>>
|
||||
get_client_names_and_types_by_node(
|
||||
const std::string & node_name,
|
||||
const std::string & namespace_) const = 0;
|
||||
|
||||
/// Return a map of existing topic names to list of topic types for a specific node.
|
||||
/**
|
||||
* This function only considers publishers - not subscribers.
|
||||
* The returned names are the actual names after remap rules applied.
|
||||
* Attempting to create publishers or subscribers using names returned by this function may not
|
||||
* result in the desired topic name being used depending on the remap rules in use.
|
||||
*
|
||||
* \param[in] node_name name of the node
|
||||
* \param[in] namespace_ namespace of the node
|
||||
* \param[in] no_demangle if true, topic names and types are not demangled
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
std::map<std::string, std::vector<std::string>>
|
||||
get_publisher_names_and_types_by_node(
|
||||
const std::string & node_name,
|
||||
const std::string & namespace_,
|
||||
bool no_demangle = false) const = 0;
|
||||
|
||||
/// Return a map of existing topic names to list of topic types for a specific node.
|
||||
/**
|
||||
* This function only considers subscribers - not publishers.
|
||||
* The returned names are the actual names after remap rules applied.
|
||||
* Attempting to create publishers or subscribers using names returned by this function may not
|
||||
* result in the desired topic name being used depending on the remap rules in use.
|
||||
*
|
||||
* \param[in] node_name name of the node
|
||||
* \param[in] namespace_ namespace of the node
|
||||
* \param[in] no_demangle if true, topic names and types are not demangled
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
std::map<std::string, std::vector<std::string>>
|
||||
get_subscriber_names_and_types_by_node(
|
||||
const std::string & node_name,
|
||||
const std::string & namespace_,
|
||||
bool no_demangle = false) const = 0;
|
||||
|
||||
/// Return a vector of existing node names (string).
|
||||
/*
|
||||
* The returned names are the actual names used and do not have remap rules applied.
|
||||
* The returned names are the actual names after remap rules applied.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
std::vector<std::string>
|
||||
get_node_names() const = 0;
|
||||
|
||||
/// Return a vector of existing node names, namespaces and enclaves (tuple of string).
|
||||
/*
|
||||
* The returned names are the actual names after remap rules applied.
|
||||
* The enclaves contain the runtime security artifacts, those can be
|
||||
* used to establish secured network.
|
||||
* See https://design.ros2.org/articles/ros2_security_enclaves.html
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
std::vector<std::tuple<std::string, std::string, std::string>>
|
||||
get_node_names_with_enclaves() const = 0;
|
||||
|
||||
/// Return a vector of existing node names and namespaces (pair of string).
|
||||
/*
|
||||
* The returned names are the actual names used and do not have remap rules applied.
|
||||
* The returned names are the actual names after remap rules applied.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
@@ -283,6 +358,8 @@ public:
|
||||
/// Return the topic endpoint information about publishers on a given topic.
|
||||
/**
|
||||
* \param[in] topic_name the actual topic name used; it will not be automatically remapped.
|
||||
* \param[in] no_mangle if `true`, `topic_name` needs to be a valid middleware topic name,
|
||||
* otherwise it should be a valid ROS topic name.
|
||||
* \sa rclcpp::Node::get_publishers_info_by_topic
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
@@ -293,6 +370,8 @@ public:
|
||||
/// Return the topic endpoint information about subscriptions on a given topic.
|
||||
/**
|
||||
* \param[in] topic_name the actual topic name used; it will not be automatically remapped.
|
||||
* \param[in] no_mangle if `true`, `topic_name` needs to be a valid middleware topic name,
|
||||
* otherwise it should be a valid ROS topic name.
|
||||
* \sa rclcpp::Node::get_subscriptions_info_by_topic
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
@@ -304,4 +383,6 @@ public:
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeGraphInterface, graph)
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_GRAPH_INTERFACE_HPP_
|
||||
|
||||
164
rclcpp/include/rclcpp/node_interfaces/node_interfaces.hpp
Normal file
164
rclcpp/include/rclcpp/node_interfaces/node_interfaces.hpp
Normal file
@@ -0,0 +1,164 @@
|
||||
// Copyright 2022 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_INTERFACES_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__NODE_INTERFACES_HPP_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "rclcpp/detail/template_unique.hpp"
|
||||
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||
|
||||
#define ALL_RCLCPP_NODE_INTERFACES \
|
||||
rclcpp::node_interfaces::NodeBaseInterface, \
|
||||
rclcpp::node_interfaces::NodeClockInterface, \
|
||||
rclcpp::node_interfaces::NodeGraphInterface, \
|
||||
rclcpp::node_interfaces::NodeLoggingInterface, \
|
||||
rclcpp::node_interfaces::NodeParametersInterface, \
|
||||
rclcpp::node_interfaces::NodeServicesInterface, \
|
||||
rclcpp::node_interfaces::NodeTimeSourceInterface, \
|
||||
rclcpp::node_interfaces::NodeTimersInterface, \
|
||||
rclcpp::node_interfaces::NodeTopicsInterface, \
|
||||
rclcpp::node_interfaces::NodeWaitablesInterface
|
||||
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace node_interfaces
|
||||
{
|
||||
|
||||
|
||||
/// A helper class for aggregating node interfaces.
|
||||
template<typename ... InterfaceTs>
|
||||
class NodeInterfaces
|
||||
: public detail::NodeInterfacesSupportCheck<
|
||||
detail::NodeInterfacesStorage<InterfaceTs ...>,
|
||||
InterfaceTs ...
|
||||
>,
|
||||
public detail::NodeInterfacesSupports<
|
||||
detail::NodeInterfacesStorage<InterfaceTs ...>,
|
||||
InterfaceTs ...
|
||||
>
|
||||
{
|
||||
static_assert(
|
||||
0 != sizeof ...(InterfaceTs),
|
||||
"must provide at least one interface as a template argument");
|
||||
static_assert(
|
||||
rclcpp::detail::template_unique_v<InterfaceTs ...>,
|
||||
"must provide unique template parameters");
|
||||
|
||||
using NodeInterfacesSupportsT = detail::NodeInterfacesSupports<
|
||||
detail::NodeInterfacesStorage<InterfaceTs ...>,
|
||||
InterfaceTs ...
|
||||
>;
|
||||
|
||||
public:
|
||||
/// Create a new NodeInterfaces object using the given node-like object's interfaces.
|
||||
/**
|
||||
* Specify which interfaces you need by passing them as template parameters.
|
||||
*
|
||||
* This allows you to aggregate interfaces from different sources together to pass as a single
|
||||
* aggregate object to any functions that take node interfaces or node-likes, without needing to
|
||||
* templatize that function.
|
||||
*
|
||||
* You may also use this constructor to create a NodeInterfaces that contains a subset of
|
||||
* another NodeInterfaces' interfaces.
|
||||
*
|
||||
* Finally, this class supports implicit conversion from node-like objects, allowing you to
|
||||
* directly pass a node-like to a function that takes a NodeInterfaces object.
|
||||
*
|
||||
* Usage examples:
|
||||
* ```cpp
|
||||
* // Suppose we have some function:
|
||||
* void fn(NodeInterfaces<NodeBaseInterface, NodeClockInterface> interfaces);
|
||||
*
|
||||
* // Then we can, explicitly:
|
||||
* rclcpp::Node node("some_node");
|
||||
* auto ni = NodeInterfaces<NodeBaseInterface, NodeClockInterface>(node);
|
||||
* fn(ni);
|
||||
*
|
||||
* // But also:
|
||||
* fn(node);
|
||||
*
|
||||
* // Subsetting a NodeInterfaces object also works!
|
||||
* auto ni_base = NodeInterfaces<NodeBaseInterface>(ni);
|
||||
*
|
||||
* // Or aggregate them (you could aggregate interfaces from disparate node-likes)
|
||||
* auto ni_aggregated = NodeInterfaces<NodeBaseInterface, NodeClockInterface>(
|
||||
* node->get_node_base_interface(),
|
||||
* node->get_node_clock_interface()
|
||||
* )
|
||||
*
|
||||
* // And then to access the interfaces:
|
||||
* // Get with get<>
|
||||
* auto base = ni.get<NodeBaseInterface>();
|
||||
*
|
||||
* // Or the appropriate getter
|
||||
* auto clock = ni.get_clock_interface();
|
||||
* ```
|
||||
*
|
||||
* You may use any of the standard node interfaces that come with rclcpp:
|
||||
* - rclcpp::node_interfaces::NodeBaseInterface
|
||||
* - rclcpp::node_interfaces::NodeClockInterface
|
||||
* - rclcpp::node_interfaces::NodeGraphInterface
|
||||
* - rclcpp::node_interfaces::NodeLoggingInterface
|
||||
* - rclcpp::node_interfaces::NodeParametersInterface
|
||||
* - rclcpp::node_interfaces::NodeServicesInterface
|
||||
* - rclcpp::node_interfaces::NodeTimeSourceInterface
|
||||
* - rclcpp::node_interfaces::NodeTimersInterface
|
||||
* - rclcpp::node_interfaces::NodeTopicsInterface
|
||||
* - rclcpp::node_interfaces::NodeWaitablesInterface
|
||||
*
|
||||
* Or you use custom interfaces as long as you make a template specialization
|
||||
* of the rclcpp::node_interfaces::detail::NodeInterfacesSupport struct using
|
||||
* the RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT macro.
|
||||
*
|
||||
* Usage example:
|
||||
* ```RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeBaseInterface, base)```
|
||||
*
|
||||
* If you choose not to use the helper macro, then you can specialize the
|
||||
* template yourself, but you must:
|
||||
*
|
||||
* - Provide a template specialization of the get_from_node_like method that gets the interface
|
||||
* from any node-like that stores the interface, using the node-like's getter
|
||||
* - Designate the is_supported type as std::true_type using a using directive
|
||||
* - Provide any number of getter methods to be used to obtain the interface with the
|
||||
* NodeInterface object, noting that the getters of the storage class will apply to all
|
||||
* supported interfaces.
|
||||
* - The getter method names should not clash in name with any other interface getter
|
||||
* specializations if those other interfaces are meant to be aggregated in the same
|
||||
* NodeInterfaces object.
|
||||
*
|
||||
* \param[in] node Node-like object from which to get the node interfaces
|
||||
*/
|
||||
template<typename NodeT>
|
||||
NodeInterfaces(NodeT & node) // NOLINT(runtime/explicit)
|
||||
: NodeInterfacesSupportsT(node)
|
||||
{}
|
||||
|
||||
// Create a NodeInterfaces object with no bound interfaces
|
||||
NodeInterfaces()
|
||||
: NodeInterfacesSupportsT()
|
||||
{}
|
||||
|
||||
explicit NodeInterfaces(std::shared_ptr<InterfaceTs>... args)
|
||||
: NodeInterfacesSupportsT(args ...)
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_INTERFACES_HPP_
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "rclcpp/logger.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
@@ -37,14 +38,18 @@ public:
|
||||
~NodeLoggingInterface() = default;
|
||||
|
||||
/// Return the logger of the node.
|
||||
/** \return The logger of the node. */
|
||||
/**
|
||||
* \return The logger of the node.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
rclcpp::Logger
|
||||
get_logger() const = 0;
|
||||
|
||||
/// Return the logger name associated with the node.
|
||||
/** \return The logger name associated with the node. */
|
||||
/**
|
||||
* \return The logger name associated with the node.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
const char *
|
||||
@@ -54,4 +59,6 @@ public:
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeLoggingInterface, logging)
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_LOGGING_INTERFACE_HPP_
|
||||
|
||||
@@ -15,9 +15,10 @@
|
||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_HPP_
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -84,6 +85,16 @@ class NodeParameters : public NodeParametersInterface
|
||||
public:
|
||||
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeParameters)
|
||||
|
||||
/// Constructor.
|
||||
/**
|
||||
* If using automatically_declare_parameters_from_overrides, overrides of
|
||||
* get_parameter_overrides(), has_parameter(), declare_parameter() will not
|
||||
* be respected.
|
||||
* If this is an issue, pass false for
|
||||
* automatically_declare_parameters_from_overrides and invoke
|
||||
* perform_automatically_declare_parameters_from_overrides() manually after
|
||||
* construction.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
NodeParameters(
|
||||
const node_interfaces::NodeBaseInterface::SharedPtr node_base,
|
||||
@@ -103,25 +114,6 @@ public:
|
||||
virtual
|
||||
~NodeParameters();
|
||||
|
||||
// This is overriding a deprecated method, so we need to ignore the deprecation warning here.
|
||||
// Users of the method will still get a warning!
|
||||
#ifndef _WIN32
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#else
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4996)
|
||||
#endif
|
||||
[[deprecated(RCLCPP_INTERNAL_NODE_PARAMETERS_INTERFACE_DEPRECATE_DECLARE)]]
|
||||
RCLCPP_PUBLIC
|
||||
const rclcpp::ParameterValue &
|
||||
declare_parameter(const std::string & name) override;
|
||||
#ifndef _WIN32
|
||||
# pragma GCC diagnostic pop
|
||||
#else
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
const rclcpp::ParameterValue &
|
||||
declare_parameter(
|
||||
@@ -190,20 +182,48 @@ public:
|
||||
rcl_interfaces::msg::ListParametersResult
|
||||
list_parameters(const std::vector<std::string> & prefixes, uint64_t depth) const override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
RCUTILS_WARN_UNUSED
|
||||
PreSetParametersCallbackHandle::SharedPtr
|
||||
add_pre_set_parameters_callback(PreSetParametersCallbackType callback) override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
RCUTILS_WARN_UNUSED
|
||||
OnSetParametersCallbackHandle::SharedPtr
|
||||
add_on_set_parameters_callback(OnParametersSetCallbackType callback) override;
|
||||
add_on_set_parameters_callback(OnSetParametersCallbackType callback) override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
RCUTILS_WARN_UNUSED
|
||||
PostSetParametersCallbackHandle::SharedPtr
|
||||
add_post_set_parameters_callback(PostSetParametersCallbackType callback) override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
remove_on_set_parameters_callback(const OnSetParametersCallbackHandle * const handler) override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
remove_post_set_parameters_callback(const PostSetParametersCallbackHandle * const handler)
|
||||
override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
remove_pre_set_parameters_callback(const PreSetParametersCallbackHandle * const handler) override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
const std::map<std::string, rclcpp::ParameterValue> &
|
||||
get_parameter_overrides() const override;
|
||||
|
||||
using CallbacksContainerType = std::list<OnSetParametersCallbackHandle::WeakPtr>;
|
||||
using PreSetCallbacksHandleContainer = std::list<PreSetParametersCallbackHandle::WeakPtr>;
|
||||
using OnSetCallbacksHandleContainer = std::list<OnSetParametersCallbackHandle::WeakPtr>;
|
||||
using PostSetCallbacksHandleContainer = std::list<PostSetParametersCallbackHandle::WeakPtr>;
|
||||
using CallbacksContainerType [[deprecated("use OnSetCallbacksHandleContainer instead")]] =
|
||||
OnSetCallbacksHandleContainer;
|
||||
|
||||
protected:
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
perform_automatically_declare_parameters_from_overrides();
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(NodeParameters)
|
||||
@@ -215,9 +235,11 @@ private:
|
||||
// declare_parameter, etc). In those cases, this will be set to false.
|
||||
bool parameter_modification_enabled_{true};
|
||||
|
||||
OnParametersSetCallbackType on_parameters_set_callback_ = nullptr;
|
||||
PreSetCallbacksHandleContainer pre_set_parameters_callback_container_;
|
||||
|
||||
CallbacksContainerType on_parameters_set_callback_container_;
|
||||
OnSetCallbacksHandleContainer on_set_parameters_callback_container_;
|
||||
|
||||
PostSetCallbacksHandleContainer post_set_parameters_callback_container_;
|
||||
|
||||
std::map<std::string, ParameterInfo> parameters_;
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_INTERFACE_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_INTERFACE_HPP_
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include "rcl_interfaces/msg/set_parameters_result.hpp"
|
||||
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||
#include "rclcpp/parameter.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
@@ -33,28 +34,39 @@ namespace rclcpp
|
||||
namespace node_interfaces
|
||||
{
|
||||
|
||||
struct PreSetParametersCallbackHandle
|
||||
{
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(PreSetParametersCallbackHandle)
|
||||
|
||||
using PreSetParametersCallbackType =
|
||||
std::function<void (std::vector<rclcpp::Parameter> &)>;
|
||||
|
||||
PreSetParametersCallbackType callback;
|
||||
};
|
||||
|
||||
struct OnSetParametersCallbackHandle
|
||||
{
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(OnSetParametersCallbackHandle)
|
||||
|
||||
using OnParametersSetCallbackType =
|
||||
using OnSetParametersCallbackType =
|
||||
std::function<
|
||||
rcl_interfaces::msg::SetParametersResult(
|
||||
const std::vector<rclcpp::Parameter> &)>;
|
||||
using OnParametersSetCallbackType [[deprecated("use OnSetParametersCallbackType instead")]] =
|
||||
OnSetParametersCallbackType;
|
||||
|
||||
OnParametersSetCallbackType callback;
|
||||
OnSetParametersCallbackType callback;
|
||||
};
|
||||
|
||||
#define RCLCPP_INTERNAL_NODE_PARAMETERS_INTERFACE_DEPRECATE_DECLARE \
|
||||
"declare_parameter() with only a name is deprecated and will be deleted in the future.\n" \
|
||||
"If you want to declare a parameter that won't change type without a default value use:\n" \
|
||||
"`node_params->declare_parameter(name, type)`, with e.g. type=rclcpp::PARAMETER_INTEGER.\n\n" \
|
||||
"If you want to declare a parameter that can dynamically change type use:\n" \
|
||||
"```\n" \
|
||||
"rcl_interfaces::msg::ParameterDescriptor descriptor;\n" \
|
||||
"descriptor.dynamic_typing = true;\n" \
|
||||
"node_params->declare_parameter(name, rclcpp::ParameterValue{}, descriptor);\n" \
|
||||
"```"
|
||||
struct PostSetParametersCallbackHandle
|
||||
{
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(PostSetParametersCallbackHandle)
|
||||
|
||||
using PostSetParametersCallbackType =
|
||||
std::function<void (const std::vector<rclcpp::Parameter> &)>;
|
||||
|
||||
PostSetParametersCallbackType callback;
|
||||
};
|
||||
|
||||
/// Pure virtual interface class for the NodeParameters part of the Node API.
|
||||
class NodeParametersInterface
|
||||
@@ -66,15 +78,6 @@ public:
|
||||
virtual
|
||||
~NodeParametersInterface() = default;
|
||||
|
||||
/// Declare a parameter.
|
||||
/**
|
||||
* \sa rclcpp::Node::declare_parameter
|
||||
*/
|
||||
[[deprecated(RCLCPP_INTERNAL_NODE_PARAMETERS_INTERFACE_DEPRECATE_DECLARE)]]
|
||||
virtual
|
||||
const rclcpp::ParameterValue &
|
||||
declare_parameter(const std::string & name) = 0;
|
||||
|
||||
/// Declare and initialize a parameter.
|
||||
/**
|
||||
* \sa rclcpp::Node::declare_parameter
|
||||
@@ -130,7 +133,7 @@ public:
|
||||
std::vector<rcl_interfaces::msg::SetParametersResult>
|
||||
set_parameters(const std::vector<rclcpp::Parameter> & parameters) = 0;
|
||||
|
||||
/// Set and initialize a parameter, all at once.
|
||||
/// Set one or more parameters, all at once.
|
||||
/**
|
||||
* \sa rclcpp::Node::set_parameters_atomically
|
||||
*/
|
||||
@@ -205,16 +208,46 @@ public:
|
||||
rcl_interfaces::msg::ListParametersResult
|
||||
list_parameters(const std::vector<std::string> & prefixes, uint64_t depth) const = 0;
|
||||
|
||||
using OnParametersSetCallbackType = OnSetParametersCallbackHandle::OnParametersSetCallbackType;
|
||||
using OnSetParametersCallbackType = OnSetParametersCallbackHandle::OnSetParametersCallbackType;
|
||||
using PostSetParametersCallbackType =
|
||||
PostSetParametersCallbackHandle::PostSetParametersCallbackType;
|
||||
using PreSetParametersCallbackType = PreSetParametersCallbackHandle::PreSetParametersCallbackType;
|
||||
|
||||
/// Add a callback for when parameters are being set.
|
||||
/// Add a callback that gets triggered before parameters are validated.
|
||||
/**
|
||||
* \sa rclcpp::Node::add_pre_set_parameters_callback
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
PreSetParametersCallbackHandle::SharedPtr
|
||||
add_pre_set_parameters_callback(PreSetParametersCallbackType callback) = 0;
|
||||
|
||||
/// Add a callback to validate parameters before they are set.
|
||||
/**
|
||||
* \sa rclcpp::Node::add_on_set_parameters_callback
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
OnSetParametersCallbackHandle::SharedPtr
|
||||
add_on_set_parameters_callback(OnParametersSetCallbackType callback) = 0;
|
||||
add_on_set_parameters_callback(OnSetParametersCallbackType callback) = 0;
|
||||
|
||||
/// Add a callback that gets triggered after parameters are set successfully.
|
||||
/**
|
||||
* \sa rclcpp::Node::add_post_set_parameters_callback
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
PostSetParametersCallbackHandle::SharedPtr
|
||||
add_post_set_parameters_callback(PostSetParametersCallbackType callback) = 0;
|
||||
|
||||
/// Remove a callback registered with `add_pre_set_parameters_callback`.
|
||||
/**
|
||||
* \sa rclcpp::Node::remove_pre_set_parameters_callback
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
remove_pre_set_parameters_callback(const PreSetParametersCallbackHandle * const handler) = 0;
|
||||
|
||||
/// Remove a callback registered with `add_on_set_parameters_callback`.
|
||||
/**
|
||||
@@ -225,6 +258,15 @@ public:
|
||||
void
|
||||
remove_on_set_parameters_callback(const OnSetParametersCallbackHandle * const handler) = 0;
|
||||
|
||||
/// Remove a callback registered with `add_post_set_parameters_callback`.
|
||||
/**
|
||||
* \sa rclcpp::Node::remove_post_set_parameters_callback
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
remove_post_set_parameters_callback(const PostSetParametersCallbackHandle * const handler) = 0;
|
||||
|
||||
/// Return the initial parameter values used by the NodeParameters to override default values.
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
@@ -235,4 +277,6 @@ public:
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeParametersInterface, parameters)
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_INTERFACE_HPP_
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "rclcpp/callback_group.hpp"
|
||||
#include "rclcpp/client.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||
#include "rclcpp/service.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
@@ -62,4 +63,6 @@ public:
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeServicesInterface, services)
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_SERVICES_INTERFACE_HPP_
|
||||
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging,
|
||||
rclcpp::node_interfaces::NodeClockInterface::SharedPtr node_clock,
|
||||
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr node_parameters,
|
||||
const rclcpp::QoS & qos = rclcpp::RosoutQoS(),
|
||||
const rclcpp::QoS & qos = rclcpp::ClockQoS(),
|
||||
bool use_clock_thread = true
|
||||
);
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#define RCLCPP__NODE_INTERFACES__NODE_TIME_SOURCE_INTERFACE_HPP_
|
||||
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
@@ -37,4 +38,6 @@ public:
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeTimeSourceInterface, time_source)
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_TIME_SOURCE_INTERFACE_HPP_
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include "rclcpp/callback_group.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||
#include "rclcpp/timer.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
@@ -47,4 +48,6 @@ public:
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeTimersInterface, timers)
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_TIMERS_INTERFACE_HPP_
|
||||
|
||||
@@ -20,12 +20,16 @@
|
||||
#include "rcl/publisher.h"
|
||||
#include "rcl/subscription.h"
|
||||
|
||||
#include "rclcpp/callback_group.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_timers_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
|
||||
#include "rclcpp/publisher.hpp"
|
||||
#include "rclcpp/publisher_base.hpp"
|
||||
#include "rclcpp/publisher_factory.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
#include "rclcpp/subscription_base.hpp"
|
||||
#include "rclcpp/subscription_factory.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_TOPICS_INTERFACE_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__NODE_TOPICS_INTERFACE_HPP_
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "rcl/publisher.h"
|
||||
@@ -24,6 +22,7 @@
|
||||
|
||||
#include "rclcpp/callback_group.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_timers_interface.hpp"
|
||||
#include "rclcpp/publisher.hpp"
|
||||
@@ -97,4 +96,6 @@ public:
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeTopicsInterface, topics)
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_TOPICS_INTERFACE_HPP_
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include "rclcpp/callback_group.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
#include "rclcpp/waitable.hpp"
|
||||
|
||||
@@ -54,4 +55,6 @@ public:
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeWaitablesInterface, waitables)
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_WAITABLES_INTERFACE_HPP_
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "rcl/time.h"
|
||||
#include "rcl/node_options.h"
|
||||
#include "rclcpp/context.hpp"
|
||||
#include "rclcpp/contexts/default_context.hpp"
|
||||
@@ -46,6 +47,7 @@ public:
|
||||
* - enable_topic_statistics = false
|
||||
* - start_parameter_services = true
|
||||
* - start_parameter_event_publisher = true
|
||||
* - clock_type = RCL_ROS_TIME
|
||||
* - clock_qos = rclcpp::ClockQoS()
|
||||
* - use_clock_thread = true
|
||||
* - rosout_qos = rclcpp::RosoutQoS()
|
||||
@@ -246,6 +248,19 @@ public:
|
||||
NodeOptions &
|
||||
start_parameter_event_publisher(bool start_parameter_event_publisher);
|
||||
|
||||
/// Return a reference to the clock type.
|
||||
RCLCPP_PUBLIC
|
||||
const rcl_clock_type_t &
|
||||
clock_type() const;
|
||||
|
||||
/// Set the clock type.
|
||||
/**
|
||||
* The clock type to be used by the node.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
NodeOptions &
|
||||
clock_type(const rcl_clock_type_t & clock_type);
|
||||
|
||||
/// Return a reference to the clock QoS.
|
||||
RCLCPP_PUBLIC
|
||||
const rclcpp::QoS &
|
||||
@@ -349,6 +364,9 @@ public:
|
||||
* global arguments (e.g. parameter overrides from a YAML file), which are
|
||||
* not explicitly declared will not appear on the node at all, even if
|
||||
* `allow_undeclared_parameters` is true.
|
||||
* Parameter declaration from overrides is done in the node's base constructor,
|
||||
* so the user must take care to check if the parameter is already (e.g.
|
||||
* automatically) declared before declaring it themselves.
|
||||
* Already declared parameters will not be re-declared, and parameters
|
||||
* declared in this way will use the default constructed ParameterDescriptor.
|
||||
*/
|
||||
@@ -397,6 +415,8 @@ private:
|
||||
|
||||
bool start_parameter_event_publisher_ {true};
|
||||
|
||||
rcl_clock_type_t clock_type_ {RCL_ROS_TIME};
|
||||
|
||||
rclcpp::QoS clock_qos_ = rclcpp::ClockQoS();
|
||||
|
||||
bool use_clock_thread_ {true};
|
||||
|
||||
@@ -264,6 +264,7 @@ get_value_helper<rclcpp::Parameter>(const rclcpp::Parameter * parameter)
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// \cond
|
||||
template<typename T>
|
||||
decltype(auto)
|
||||
Parameter::get_value() const
|
||||
@@ -275,6 +276,7 @@ Parameter::get_value() const
|
||||
throw exceptions::InvalidParameterTypeException(this->name_, ex.what());
|
||||
}
|
||||
}
|
||||
/// \endcond
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
|
||||
@@ -31,11 +31,15 @@
|
||||
#include "rcl_interfaces/srv/list_parameters.hpp"
|
||||
#include "rcl_interfaces/srv/set_parameters.hpp"
|
||||
#include "rcl_interfaces/srv/set_parameters_atomically.hpp"
|
||||
#include "rcl_yaml_param_parser/parser.h"
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
#include "rclcpp/executors.hpp"
|
||||
#include "rclcpp/create_subscription.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node.hpp"
|
||||
#include "rclcpp/parameter.hpp"
|
||||
#include "rclcpp/parameter_map.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
#include "rclcpp/type_support_decl.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
#include "rmw/rmw.h"
|
||||
@@ -48,6 +52,37 @@ class AsyncParametersClient
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(AsyncParametersClient)
|
||||
|
||||
/// Create an async parameters client.
|
||||
/**
|
||||
* \param[in] node_base_interface The node base interface of the corresponding node.
|
||||
* \param[in] node_topics_interface Node topic base interface.
|
||||
* \param[in] node_graph_interface The node graph interface of the corresponding node.
|
||||
* \param[in] node_services_interface Node service interface.
|
||||
* \param[in] remote_node_name Name of the remote node
|
||||
* \param[in] qos_profile The rmw qos profile to use to subscribe
|
||||
* \param[in] group (optional) The async parameter client will be added to this callback group.
|
||||
* \deprecated use rclcpp::QoS instead of rmw_qos_profile_t
|
||||
*/
|
||||
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
|
||||
RCLCPP_PUBLIC
|
||||
AsyncParametersClient(
|
||||
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_interface,
|
||||
const rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics_interface,
|
||||
const rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph_interface,
|
||||
const rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services_interface,
|
||||
const std::string & remote_node_name,
|
||||
const rmw_qos_profile_t & qos_profile,
|
||||
rclcpp::CallbackGroup::SharedPtr group = nullptr)
|
||||
: AsyncParametersClient(
|
||||
node_base_interface,
|
||||
node_topics_interface,
|
||||
node_graph_interface,
|
||||
node_services_interface,
|
||||
remote_node_name,
|
||||
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)),
|
||||
group)
|
||||
{}
|
||||
|
||||
/// Create an async parameters client.
|
||||
/**
|
||||
* \param[in] node_base_interface The node base interface of the corresponding node.
|
||||
@@ -55,7 +90,7 @@ public:
|
||||
* \param[in] node_graph_interface The node graph interface of the corresponding node.
|
||||
* \param[in] node_services_interface Node service interface.
|
||||
* \param[in] remote_node_name (optional) name of the remote node
|
||||
* \param[in] qos_profile (optional) The rmw qos profile to use to subscribe
|
||||
* \param[in] qos_profile (optional) The qos profile to use to subscribe
|
||||
* \param[in] group (optional) The async parameter client will be added to this callback group.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
@@ -65,21 +100,45 @@ public:
|
||||
const rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph_interface,
|
||||
const rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services_interface,
|
||||
const std::string & remote_node_name = "",
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters,
|
||||
const rclcpp::QoS & qos_profile = rclcpp::ParametersQoS(),
|
||||
rclcpp::CallbackGroup::SharedPtr group = nullptr);
|
||||
|
||||
/// Constructor
|
||||
/**
|
||||
* \param[in] node The async paramters client will be added to this node.
|
||||
* \param[in] node The async parameters client will be added to this node.
|
||||
* \param[in] remote_node_name name of the remote node
|
||||
* \param[in] qos_profile The rmw qos profile to use to subscribe
|
||||
* \param[in] group (optional) The async parameter client will be added to this callback group.
|
||||
* \deprecated use rclcpp::QoS instead of rmw_qos_profile_t
|
||||
*/
|
||||
template<typename NodeT>
|
||||
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
|
||||
AsyncParametersClient(
|
||||
const std::shared_ptr<NodeT> node,
|
||||
const std::string & remote_node_name,
|
||||
const rmw_qos_profile_t & qos_profile,
|
||||
rclcpp::CallbackGroup::SharedPtr group = nullptr)
|
||||
: AsyncParametersClient(
|
||||
node->get_node_base_interface(),
|
||||
node->get_node_topics_interface(),
|
||||
node->get_node_graph_interface(),
|
||||
node->get_node_services_interface(),
|
||||
remote_node_name,
|
||||
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)),
|
||||
group)
|
||||
{}
|
||||
|
||||
/**
|
||||
* \param[in] node The async parameters client will be added to this node.
|
||||
* \param[in] remote_node_name (optional) name of the remote node
|
||||
* \param[in] qos_profile (optional) The rmw qos profile to use to subscribe
|
||||
* \param[in] qos_profile (optional) The qos profile to use to subscribe
|
||||
* \param[in] group (optional) The async parameter client will be added to this callback group.
|
||||
*/
|
||||
template<typename NodeT>
|
||||
AsyncParametersClient(
|
||||
explicit AsyncParametersClient(
|
||||
const std::shared_ptr<NodeT> node,
|
||||
const std::string & remote_node_name = "",
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters,
|
||||
const rclcpp::QoS & qos_profile = rclcpp::ParametersQoS(),
|
||||
rclcpp::CallbackGroup::SharedPtr group = nullptr)
|
||||
: AsyncParametersClient(
|
||||
node->get_node_base_interface(),
|
||||
@@ -93,16 +152,40 @@ public:
|
||||
|
||||
/// Constructor
|
||||
/**
|
||||
* \param[in] node The async paramters client will be added to this node.
|
||||
* \param[in] node The async parameters client will be added to this node.
|
||||
* \param[in] remote_node_name Name of the remote node
|
||||
* \param[in] qos_profile The rmw qos profile to use to subscribe
|
||||
* \param[in] group (optional) The async parameter client will be added to this callback group.
|
||||
* \deprecated use rclcpp::QoS instead of rmw_qos_profile_t
|
||||
*/
|
||||
template<typename NodeT>
|
||||
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
|
||||
AsyncParametersClient(
|
||||
NodeT * node,
|
||||
const std::string & remote_node_name,
|
||||
const rmw_qos_profile_t & qos_profile,
|
||||
rclcpp::CallbackGroup::SharedPtr group = nullptr)
|
||||
: AsyncParametersClient(
|
||||
node->get_node_base_interface(),
|
||||
node->get_node_topics_interface(),
|
||||
node->get_node_graph_interface(),
|
||||
node->get_node_services_interface(),
|
||||
remote_node_name,
|
||||
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)),
|
||||
group)
|
||||
{}
|
||||
|
||||
/**
|
||||
* \param[in] node The async parameters client will be added to this node.
|
||||
* \param[in] remote_node_name (optional) name of the remote node
|
||||
* \param[in] qos_profile (optional) The rmw qos profile to use to subscribe
|
||||
* \param[in] qos_profile (optional) The qos profile to use to subscribe
|
||||
* \param[in] group (optional) The async parameter client will be added to this callback group.
|
||||
*/
|
||||
template<typename NodeT>
|
||||
AsyncParametersClient(
|
||||
explicit AsyncParametersClient(
|
||||
NodeT * node,
|
||||
const std::string & remote_node_name = "",
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters,
|
||||
const rclcpp::QoS & qos_profile = rclcpp::ParametersQoS(),
|
||||
rclcpp::CallbackGroup::SharedPtr group = nullptr)
|
||||
: AsyncParametersClient(
|
||||
node->get_node_base_interface(),
|
||||
@@ -154,6 +237,45 @@ public:
|
||||
void(std::shared_future<rcl_interfaces::msg::SetParametersResult>)
|
||||
> callback = nullptr);
|
||||
|
||||
/// Delete several parameters at once.
|
||||
/**
|
||||
* This function behaves like command-line tool `ros2 param delete` would.
|
||||
*
|
||||
* \param parameters_names vector of parameters names
|
||||
* \return the future of the set_parameter service used to delete the parameters
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
std::shared_future<std::vector<rcl_interfaces::msg::SetParametersResult>>
|
||||
delete_parameters(
|
||||
const std::vector<std::string> & parameters_names);
|
||||
|
||||
/// Load parameters from yaml file.
|
||||
/**
|
||||
* This function behaves like command-line tool `ros2 param load` would.
|
||||
*
|
||||
* \param yaml_filename the full name of the yaml file
|
||||
* \return the future of the set_parameter service used to load the parameters
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
std::shared_future<std::vector<rcl_interfaces::msg::SetParametersResult>>
|
||||
load_parameters(
|
||||
const std::string & yaml_filename);
|
||||
|
||||
/// Load parameters from parameter map.
|
||||
/**
|
||||
* This function filters the parameters to be set based on the node name.
|
||||
*
|
||||
* If two duplicate keys exist in node names belongs to one FQN, there is no guarantee
|
||||
* which one could be set.
|
||||
*
|
||||
* \param parameter_map named parameters to be loaded
|
||||
* \return the future of the set_parameter service used to load the parameters
|
||||
* \throw InvalidParametersException if there is no parameter to set
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
std::shared_future<std::vector<rcl_interfaces::msg::SetParametersResult>>
|
||||
load_parameters(const rclcpp::ParameterMap & parameter_map);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
std::shared_future<rcl_interfaces::msg::ListParametersResult>
|
||||
list_parameters(
|
||||
@@ -169,9 +291,7 @@ public:
|
||||
typename rclcpp::Subscription<rcl_interfaces::msg::ParameterEvent>::SharedPtr
|
||||
on_parameter_event(
|
||||
CallbackT && callback,
|
||||
const rclcpp::QoS & qos = (
|
||||
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(rmw_qos_profile_parameter_events))
|
||||
),
|
||||
const rclcpp::QoS & qos = rclcpp::ParameterEventsQoS(),
|
||||
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options = (
|
||||
rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>()
|
||||
))
|
||||
@@ -196,9 +316,7 @@ public:
|
||||
on_parameter_event(
|
||||
NodeT && node,
|
||||
CallbackT && callback,
|
||||
const rclcpp::QoS & qos = (
|
||||
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(rmw_qos_profile_parameter_events))
|
||||
),
|
||||
const rclcpp::QoS & qos = rclcpp::ParameterEventsQoS(),
|
||||
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options = (
|
||||
rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>()
|
||||
))
|
||||
@@ -265,11 +383,24 @@ class SyncParametersClient
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(SyncParametersClient)
|
||||
|
||||
template<typename NodeT>
|
||||
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
|
||||
SyncParametersClient(
|
||||
std::shared_ptr<NodeT> node,
|
||||
const std::string & remote_node_name,
|
||||
const rmw_qos_profile_t & qos_profile)
|
||||
: SyncParametersClient(
|
||||
std::make_shared<rclcpp::executors::SingleThreadedExecutor>(),
|
||||
node,
|
||||
remote_node_name,
|
||||
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)))
|
||||
{}
|
||||
|
||||
template<typename NodeT>
|
||||
explicit SyncParametersClient(
|
||||
std::shared_ptr<NodeT> node,
|
||||
const std::string & remote_node_name = "",
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters)
|
||||
const rclcpp::QoS & qos_profile = rclcpp::ParametersQoS())
|
||||
: SyncParametersClient(
|
||||
std::make_shared<rclcpp::executors::SingleThreadedExecutor>(),
|
||||
node,
|
||||
@@ -277,12 +408,29 @@ public:
|
||||
qos_profile)
|
||||
{}
|
||||
|
||||
template<typename NodeT>
|
||||
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
|
||||
SyncParametersClient(
|
||||
rclcpp::Executor::SharedPtr executor,
|
||||
std::shared_ptr<NodeT> node,
|
||||
const std::string & remote_node_name,
|
||||
const rmw_qos_profile_t & qos_profile)
|
||||
: SyncParametersClient(
|
||||
executor,
|
||||
node->get_node_base_interface(),
|
||||
node->get_node_topics_interface(),
|
||||
node->get_node_graph_interface(),
|
||||
node->get_node_services_interface(),
|
||||
remote_node_name,
|
||||
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)))
|
||||
{}
|
||||
|
||||
template<typename NodeT>
|
||||
SyncParametersClient(
|
||||
rclcpp::Executor::SharedPtr executor,
|
||||
std::shared_ptr<NodeT> node,
|
||||
const std::string & remote_node_name = "",
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters)
|
||||
const rclcpp::QoS & qos_profile = rclcpp::ParametersQoS())
|
||||
: SyncParametersClient(
|
||||
executor,
|
||||
node->get_node_base_interface(),
|
||||
@@ -294,10 +442,23 @@ public:
|
||||
{}
|
||||
|
||||
template<typename NodeT>
|
||||
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
|
||||
SyncParametersClient(
|
||||
NodeT * node,
|
||||
const std::string & remote_node_name,
|
||||
const rmw_qos_profile_t & qos_profile)
|
||||
: SyncParametersClient(
|
||||
std::make_shared<rclcpp::executors::SingleThreadedExecutor>(),
|
||||
node,
|
||||
remote_node_name,
|
||||
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)))
|
||||
{}
|
||||
|
||||
template<typename NodeT>
|
||||
explicit SyncParametersClient(
|
||||
NodeT * node,
|
||||
const std::string & remote_node_name = "",
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters)
|
||||
const rclcpp::QoS & qos_profile = rclcpp::ParametersQoS())
|
||||
: SyncParametersClient(
|
||||
std::make_shared<rclcpp::executors::SingleThreadedExecutor>(),
|
||||
node,
|
||||
@@ -305,12 +466,29 @@ public:
|
||||
qos_profile)
|
||||
{}
|
||||
|
||||
template<typename NodeT>
|
||||
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
|
||||
SyncParametersClient(
|
||||
rclcpp::Executor::SharedPtr executor,
|
||||
NodeT * node,
|
||||
const std::string & remote_node_name,
|
||||
const rmw_qos_profile_t & qos_profile)
|
||||
: SyncParametersClient(
|
||||
executor,
|
||||
node->get_node_base_interface(),
|
||||
node->get_node_topics_interface(),
|
||||
node->get_node_graph_interface(),
|
||||
node->get_node_services_interface(),
|
||||
remote_node_name,
|
||||
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)))
|
||||
{}
|
||||
|
||||
template<typename NodeT>
|
||||
SyncParametersClient(
|
||||
rclcpp::Executor::SharedPtr executor,
|
||||
NodeT * node,
|
||||
const std::string & remote_node_name = "",
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters)
|
||||
const rclcpp::QoS & qos_profile = rclcpp::ParametersQoS())
|
||||
: SyncParametersClient(
|
||||
executor,
|
||||
node->get_node_base_interface(),
|
||||
@@ -321,6 +499,28 @@ public:
|
||||
qos_profile)
|
||||
{}
|
||||
|
||||
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
|
||||
RCLCPP_PUBLIC
|
||||
SyncParametersClient(
|
||||
rclcpp::Executor::SharedPtr executor,
|
||||
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_interface,
|
||||
const rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics_interface,
|
||||
const rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph_interface,
|
||||
const rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services_interface,
|
||||
const std::string & remote_node_name,
|
||||
const rmw_qos_profile_t & qos_profile)
|
||||
: executor_(executor), node_base_interface_(node_base_interface)
|
||||
{
|
||||
async_parameters_client_ =
|
||||
std::make_shared<AsyncParametersClient>(
|
||||
node_base_interface,
|
||||
node_topics_interface,
|
||||
node_graph_interface,
|
||||
node_services_interface,
|
||||
remote_node_name,
|
||||
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)));
|
||||
}
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
SyncParametersClient(
|
||||
rclcpp::Executor::SharedPtr executor,
|
||||
@@ -329,7 +529,7 @@ public:
|
||||
const rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph_interface,
|
||||
const rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services_interface,
|
||||
const std::string & remote_node_name = "",
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters)
|
||||
const rclcpp::QoS & qos_profile = rclcpp::ParametersQoS())
|
||||
: executor_(executor), node_base_interface_(node_base_interface)
|
||||
{
|
||||
async_parameters_client_ =
|
||||
@@ -444,6 +644,46 @@ public:
|
||||
);
|
||||
}
|
||||
|
||||
/// Delete several parameters at once.
|
||||
/**
|
||||
* This function behaves like command-line tool `ros2 param delete` would.
|
||||
*
|
||||
* \param parameters_names vector of parameters names
|
||||
* \param timeout for the spin used to make it synchronous
|
||||
* \return the future of the set_parameter service used to delete the parameters
|
||||
*/
|
||||
template<typename RepT = int64_t, typename RatioT = std::milli>
|
||||
std::vector<rcl_interfaces::msg::SetParametersResult>
|
||||
delete_parameters(
|
||||
const std::vector<std::string> & parameters_names,
|
||||
std::chrono::duration<RepT, RatioT> timeout = std::chrono::duration<RepT, RatioT>(-1))
|
||||
{
|
||||
return delete_parameters(
|
||||
parameters_names,
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
|
||||
);
|
||||
}
|
||||
|
||||
/// Load parameters from yaml file.
|
||||
/**
|
||||
* This function behaves like command-line tool `ros2 param load` would.
|
||||
*
|
||||
* \param yaml_filename the full name of the yaml file
|
||||
* \param timeout for the spin used to make it synchronous
|
||||
* \return the future of the set_parameter service used to load the parameters
|
||||
*/
|
||||
template<typename RepT = int64_t, typename RatioT = std::milli>
|
||||
std::vector<rcl_interfaces::msg::SetParametersResult>
|
||||
load_parameters(
|
||||
const std::string & yaml_filename,
|
||||
std::chrono::duration<RepT, RatioT> timeout = std::chrono::duration<RepT, RatioT>(-1))
|
||||
{
|
||||
return load_parameters(
|
||||
yaml_filename,
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
|
||||
);
|
||||
}
|
||||
|
||||
template<typename RepT = int64_t, typename RatioT = std::milli>
|
||||
rcl_interfaces::msg::ListParametersResult
|
||||
list_parameters(
|
||||
@@ -524,6 +764,18 @@ protected:
|
||||
const std::vector<rclcpp::Parameter> & parameters,
|
||||
std::chrono::nanoseconds timeout);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<rcl_interfaces::msg::SetParametersResult>
|
||||
delete_parameters(
|
||||
const std::vector<std::string> & parameters_names,
|
||||
std::chrono::nanoseconds timeout);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<rcl_interfaces::msg::SetParametersResult>
|
||||
load_parameters(
|
||||
const std::string & yaml_filename,
|
||||
std::chrono::nanoseconds timeout);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
rcl_interfaces::msg::SetParametersResult
|
||||
set_parameters_atomically(
|
||||
|
||||
@@ -52,7 +52,7 @@ struct ParameterEventCallbackHandle
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(ParameterEventCallbackHandle)
|
||||
|
||||
using ParameterEventCallbackType =
|
||||
std::function<void (const rcl_interfaces::msg::ParameterEvent::SharedPtr &)>;
|
||||
std::function<void (const rcl_interfaces::msg::ParameterEvent &)>;
|
||||
|
||||
ParameterEventCallbackType callback;
|
||||
};
|
||||
@@ -86,6 +86,9 @@ struct ParameterEventCallbackHandle
|
||||
* the ROS node supplied in the ParameterEventHandler constructor.
|
||||
* The callback, a lambda function in this case, simply prints out the value of the parameter.
|
||||
*
|
||||
* Note: the object returned from add_parameter_callback must be captured or the callback will
|
||||
* be immediately unregistered.
|
||||
*
|
||||
* You may also monitor for changes to parameters in other nodes by supplying the node
|
||||
* name to add_parameter_callback:
|
||||
*
|
||||
@@ -103,8 +106,8 @@ struct ParameterEventCallbackHandle
|
||||
* In this case, the callback will be invoked whenever "some_remote_param_name" changes
|
||||
* on remote node "some_remote_node_name".
|
||||
*
|
||||
* To remove a parameter callback, call remove_parameter_callback, passing the handle returned
|
||||
* from add_parameter_callback:
|
||||
* To remove a parameter callback, reset the callback handle smart pointer or call
|
||||
* remove_parameter_callback, passing the handle returned from add_parameter_callback:
|
||||
*
|
||||
* param_handler->remove_parameter_callback(handle2);
|
||||
*
|
||||
@@ -115,16 +118,16 @@ struct ParameterEventCallbackHandle
|
||||
* For example:
|
||||
*
|
||||
* auto cb3 =
|
||||
* [fqn, remote_param_name, &node](const rcl_interfaces::msg::ParameterEvent::SharedPtr & event) {
|
||||
* [fqn, remote_param_name, &node](const rcl_interfaces::msg::ParameterEvent & event) {
|
||||
* // Look for any updates to parameters in "/a_namespace" as well as any parameter changes
|
||||
* // to our own node ("this_node")
|
||||
* std::regex re("(/a_namespace/.*)|(/this_node)");
|
||||
* if (regex_match(event->node, re)) {
|
||||
* if (regex_match(event.node, re)) {
|
||||
* // Now that we know the event matches the regular expression we scanned for, we can
|
||||
* // use 'get_parameter_from_event' to get a specific parameter name that we're looking for
|
||||
* rclcpp::Parameter p;
|
||||
* if (rclcpp::ParameterEventsSubscriber::get_parameter_from_event(
|
||||
* *event, p, remote_param_name, fqn))
|
||||
* event, p, remote_param_name, fqn))
|
||||
* {
|
||||
* RCLCPP_INFO(
|
||||
* node->get_logger(),
|
||||
@@ -136,7 +139,7 @@ struct ParameterEventCallbackHandle
|
||||
*
|
||||
* // You can also use 'get_parameter*s*_from_event' to enumerate all changes that came
|
||||
* // in on this event
|
||||
* auto params = rclcpp::ParameterEventsSubscriber::get_parameters_from_event(*event);
|
||||
* auto params = rclcpp::ParameterEventsSubscriber::get_parameters_from_event(event);
|
||||
* for (auto & p : params) {
|
||||
* RCLCPP_INFO(
|
||||
* node->get_logger(),
|
||||
@@ -152,9 +155,12 @@ struct ParameterEventCallbackHandle
|
||||
* For both parameter callbacks and parameter event callbacks, when multiple callbacks are added,
|
||||
* the callbacks are invoked last-in, first-called order (LIFO).
|
||||
*
|
||||
* To remove a parameter event callback, use:
|
||||
* Note: the callback handle returned from add_parameter_event_callback must be captured or
|
||||
* the callback will immediately be unregistered.
|
||||
*
|
||||
* param_handler->remove_event_parameter_callback(handle);
|
||||
* To remove a parameter event callback, reset the callback smart pointer or use:
|
||||
*
|
||||
* param_handler->remove_event_parameter_callback(handle3);
|
||||
*/
|
||||
class ParameterEventHandler
|
||||
{
|
||||
@@ -165,17 +171,21 @@ public:
|
||||
* \param[in] qos The QoS settings to use for any subscriptions.
|
||||
*/
|
||||
template<typename NodeT>
|
||||
ParameterEventHandler(
|
||||
explicit ParameterEventHandler(
|
||||
NodeT node,
|
||||
const rclcpp::QoS & qos =
|
||||
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(rmw_qos_profile_parameter_events)))
|
||||
: node_base_(rclcpp::node_interfaces::get_node_base_interface(node))
|
||||
{
|
||||
node_base_ = rclcpp::node_interfaces::get_node_base_interface(node);
|
||||
auto node_topics = rclcpp::node_interfaces::get_node_topics_interface(node);
|
||||
|
||||
callbacks_ = std::make_shared<Callbacks>();
|
||||
|
||||
event_subscription_ = rclcpp::create_subscription<rcl_interfaces::msg::ParameterEvent>(
|
||||
node_topics, "/parameter_events", qos,
|
||||
std::bind(&ParameterEventHandler::event_callback, this, std::placeholders::_1));
|
||||
[callbacks = callbacks_](const rcl_interfaces::msg::ParameterEvent & event) {
|
||||
callbacks->event_callback(event);
|
||||
});
|
||||
}
|
||||
|
||||
using ParameterEventCallbackType =
|
||||
@@ -185,10 +195,14 @@ public:
|
||||
/**
|
||||
* This function may be called multiple times to set multiple parameter event callbacks.
|
||||
*
|
||||
* Note: if the returned callback handle smart pointer is not captured, the callback is
|
||||
* immediatedly unregistered. A compiler warning should be generated to warn of this.
|
||||
*
|
||||
* \param[in] callback Function callback to be invoked on parameter updates.
|
||||
* \returns A handle used to refer to the callback.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
RCUTILS_WARN_UNUSED
|
||||
ParameterEventCallbackHandle::SharedPtr
|
||||
add_parameter_event_callback(
|
||||
ParameterEventCallbackType callback);
|
||||
@@ -208,12 +222,17 @@ public:
|
||||
/**
|
||||
* If a node_name is not provided, defaults to the current node.
|
||||
*
|
||||
* Note: if the returned callback handle smart pointer is not captured, the callback
|
||||
* is immediately unregistered. A compiler warning should be generated to warn
|
||||
* of this.
|
||||
*
|
||||
* \param[in] parameter_name Name of parameter to monitor.
|
||||
* \param[in] callback Function callback to be invoked upon parameter update.
|
||||
* \param[in] node_name Name of node which hosts the parameter.
|
||||
* \returns A handle used to refer to the callback.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
RCUTILS_WARN_UNUSED
|
||||
ParameterCallbackHandle::SharedPtr
|
||||
add_parameter_callback(
|
||||
const std::string & parameter_name,
|
||||
@@ -249,8 +268,8 @@ public:
|
||||
get_parameter_from_event(
|
||||
const rcl_interfaces::msg::ParameterEvent & event,
|
||||
rclcpp::Parameter & parameter,
|
||||
const std::string parameter_name,
|
||||
const std::string node_name = "");
|
||||
const std::string & parameter_name,
|
||||
const std::string & node_name = "");
|
||||
|
||||
/// Get an rclcpp::Parameter from parameter event
|
||||
/**
|
||||
@@ -264,13 +283,14 @@ public:
|
||||
* \param[in] parameter_name Name of parameter.
|
||||
* \param[in] node_name Name of node which hosts the parameter.
|
||||
* \returns The resultant rclcpp::Parameter from the event.
|
||||
* \throws std::runtime_error if input node name doesn't match the node name in parameter event.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
static rclcpp::Parameter
|
||||
get_parameter_from_event(
|
||||
const rcl_interfaces::msg::ParameterEvent & event,
|
||||
const std::string parameter_name,
|
||||
const std::string node_name = "");
|
||||
const std::string & parameter_name,
|
||||
const std::string & node_name = "");
|
||||
|
||||
/// Get all rclcpp::Parameter values from a parameter event
|
||||
/**
|
||||
@@ -285,17 +305,6 @@ public:
|
||||
using CallbacksContainerType = std::list<ParameterCallbackHandle::WeakPtr>;
|
||||
|
||||
protected:
|
||||
/// Callback for parameter events subscriptions.
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
event_callback(const rcl_interfaces::msg::ParameterEvent::SharedPtr event);
|
||||
|
||||
// Utility function for resolving node path.
|
||||
std::string resolve_path(const std::string & path);
|
||||
|
||||
// Node interface used for base functionality
|
||||
std::shared_ptr<rclcpp::node_interfaces::NodeBaseInterface> node_base_;
|
||||
|
||||
// *INDENT-OFF* Uncrustify doesn't handle indented public/private labels
|
||||
// Hash function for string pair required in std::unordered_map
|
||||
// See: https://stackoverflow.com/questions/35985960/c-why-is-boosthash-combine-the-best-way-to-combine-hash-values
|
||||
@@ -319,18 +328,34 @@ protected:
|
||||
};
|
||||
// *INDENT-ON*
|
||||
|
||||
// Map container for registered parameters
|
||||
std::unordered_map<
|
||||
std::pair<std::string, std::string>,
|
||||
CallbacksContainerType,
|
||||
StringPairHash
|
||||
> parameter_callbacks_;
|
||||
struct Callbacks
|
||||
{
|
||||
std::recursive_mutex mutex_;
|
||||
|
||||
// Map container for registered parameters
|
||||
std::unordered_map<
|
||||
std::pair<std::string, std::string>,
|
||||
CallbacksContainerType,
|
||||
StringPairHash
|
||||
> parameter_callbacks_;
|
||||
|
||||
std::list<ParameterEventCallbackHandle::WeakPtr> event_callbacks_;
|
||||
|
||||
/// Callback for parameter events subscriptions.
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
event_callback(const rcl_interfaces::msg::ParameterEvent & event);
|
||||
};
|
||||
|
||||
std::shared_ptr<Callbacks> callbacks_;
|
||||
|
||||
// Utility function for resolving node path.
|
||||
std::string resolve_path(const std::string & path);
|
||||
|
||||
// Node interface used for base functionality
|
||||
std::shared_ptr<rclcpp::node_interfaces::NodeBaseInterface> node_base_;
|
||||
|
||||
rclcpp::Subscription<rcl_interfaces::msg::ParameterEvent>::SharedPtr event_subscription_;
|
||||
|
||||
std::list<ParameterEventCallbackHandle::WeakPtr> event_callbacks_;
|
||||
|
||||
std::recursive_mutex mutex_;
|
||||
};
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
@@ -37,7 +37,7 @@ public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(ParameterEventsFilter)
|
||||
enum class EventType {NEW, DELETED, CHANGED}; ///< An enum for the type of event.
|
||||
/// Used for the listed results
|
||||
using EventPair = std::pair<EventType, rcl_interfaces::msg::Parameter *>;
|
||||
using EventPair = std::pair<EventType, const rcl_interfaces::msg::Parameter *>;
|
||||
|
||||
/// Construct a filtered view of a parameter event.
|
||||
/**
|
||||
@@ -60,7 +60,7 @@ public:
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
ParameterEventsFilter(
|
||||
rcl_interfaces::msg::ParameterEvent::SharedPtr event,
|
||||
std::shared_ptr<const rcl_interfaces::msg::ParameterEvent> event,
|
||||
const std::vector<std::string> & names,
|
||||
const std::vector<EventType> & types);
|
||||
|
||||
@@ -74,7 +74,7 @@ public:
|
||||
private:
|
||||
// access only allowed via const accessor.
|
||||
std::vector<EventPair> result_; ///< Storage of the resultant vector
|
||||
rcl_interfaces::msg::ParameterEvent::SharedPtr event_; ///< Keep event in scope
|
||||
std::shared_ptr<const rcl_interfaces::msg::ParameterEvent> event_; ///< Keep event in scope
|
||||
};
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#ifndef RCLCPP__PARAMETER_MAP_HPP_
|
||||
#define RCLCPP__PARAMETER_MAP_HPP_
|
||||
|
||||
#include <rcl_yaml_param_parser/parser.h>
|
||||
#include <rcl_yaml_param_parser/types.h>
|
||||
|
||||
#include <string>
|
||||
@@ -34,11 +35,13 @@ using ParameterMap = std::unordered_map<std::string, std::vector<Parameter>>;
|
||||
|
||||
/// Convert parameters from rcl_yaml_param_parser into C++ class instances.
|
||||
/// \param[in] c_params C structures containing parameters for multiple nodes.
|
||||
/// \param[in] node_fqn a Fully Qualified Name of node, default value is nullptr.
|
||||
/// If it's not nullptr, return the relative node parameters belonging to this node_fqn.
|
||||
/// \returns a map where the keys are fully qualified node names and values a list of parameters.
|
||||
/// \throws InvalidParametersException if the `rcl_params_t` is inconsistent or invalid.
|
||||
RCLCPP_PUBLIC
|
||||
ParameterMap
|
||||
parameter_map_from(const rcl_params_t * const c_params);
|
||||
parameter_map_from(const rcl_params_t * const c_params, const char * node_fqn = nullptr);
|
||||
|
||||
/// Convert parameter value from rcl_yaml_param_parser into a C++ class instance.
|
||||
/// \param[in] c_value C structure containing a value of a parameter.
|
||||
@@ -48,6 +51,23 @@ RCLCPP_PUBLIC
|
||||
ParameterValue
|
||||
parameter_value_from(const rcl_variant_t * const c_value);
|
||||
|
||||
/// Get the ParameterMap from a yaml file.
|
||||
/// \param[in] yaml_filename full name of the yaml file.
|
||||
/// \param[in] node_fqn a Fully Qualified Name of node, default value is nullptr.
|
||||
/// \returns an instance of a parameter map
|
||||
/// \throws from rcl error of rcl_parse_yaml_file()
|
||||
RCLCPP_PUBLIC
|
||||
ParameterMap
|
||||
parameter_map_from_yaml_file(const std::string & yaml_filename, const char * node_fqn = nullptr);
|
||||
|
||||
/// Get the Parameters from ParameterMap.
|
||||
/// \param[in] parameter_map a parameter map.
|
||||
/// \param[in] node_fqn a Fully Qualified Name of node, default value is nullptr.
|
||||
/// \returns a list of a parameter
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<Parameter>
|
||||
parameters_from_map(const ParameterMap & parameter_map, const char * node_fqn = nullptr);
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__PARAMETER_MAP_HPP_
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node.hpp"
|
||||
#include "rclcpp/parameter.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
#include "rmw/rmw.h"
|
||||
|
||||
@@ -39,12 +40,26 @@ class ParameterService
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(ParameterService)
|
||||
|
||||
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
|
||||
RCLCPP_PUBLIC
|
||||
explicit ParameterService(
|
||||
ParameterService(
|
||||
const std::shared_ptr<node_interfaces::NodeBaseInterface> node_base,
|
||||
const std::shared_ptr<node_interfaces::NodeServicesInterface> node_services,
|
||||
rclcpp::node_interfaces::NodeParametersInterface * node_params,
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters);
|
||||
const rmw_qos_profile_t & qos_profile)
|
||||
: ParameterService(
|
||||
node_base,
|
||||
node_services,
|
||||
node_params,
|
||||
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)))
|
||||
{}
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
ParameterService(
|
||||
const std::shared_ptr<node_interfaces::NodeBaseInterface> node_base,
|
||||
const std::shared_ptr<node_interfaces::NodeServicesInterface> node_services,
|
||||
rclcpp::node_interfaces::NodeParametersInterface * node_params,
|
||||
const rclcpp::QoS & qos_profile = rclcpp::ParametersQoS());
|
||||
|
||||
private:
|
||||
rclcpp::Service<rcl_interfaces::srv::GetParameters>::SharedPtr get_parameters_service_;
|
||||
|
||||
@@ -301,6 +301,16 @@ public:
|
||||
return get<ParameterType::PARAMETER_BOOL_ARRAY>();
|
||||
}
|
||||
|
||||
template<typename type>
|
||||
constexpr
|
||||
typename std::enable_if<
|
||||
std::is_convertible<
|
||||
type, const std::vector<int> &>::value, const std::vector<int64_t> &>::type
|
||||
get() const
|
||||
{
|
||||
return get<ParameterType::PARAMETER_INTEGER_ARRAY>();
|
||||
}
|
||||
|
||||
template<typename type>
|
||||
constexpr
|
||||
typename std::enable_if<
|
||||
@@ -311,6 +321,16 @@ public:
|
||||
return get<ParameterType::PARAMETER_INTEGER_ARRAY>();
|
||||
}
|
||||
|
||||
template<typename type>
|
||||
constexpr
|
||||
typename std::enable_if<
|
||||
std::is_convertible<
|
||||
type, const std::vector<float> &>::value, const std::vector<double> &>::type
|
||||
get() const
|
||||
{
|
||||
return get<ParameterType::PARAMETER_DOUBLE_ARRAY>();
|
||||
}
|
||||
|
||||
template<typename type>
|
||||
constexpr
|
||||
typename std::enable_if<
|
||||
|
||||
@@ -15,31 +15,37 @@
|
||||
#ifndef RCLCPP__PUBLISHER_HPP_
|
||||
#define RCLCPP__PUBLISHER_HPP_
|
||||
|
||||
#include <rmw/error_handling.h>
|
||||
#include <rmw/rmw.h>
|
||||
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "rcl/error_handling.h"
|
||||
#include "rcl/publisher.h"
|
||||
#include "rmw/error_handling.h"
|
||||
#include "rmw/rmw.h"
|
||||
#include "rosidl_runtime_cpp/traits.hpp"
|
||||
|
||||
#include "rclcpp/allocator/allocator_common.hpp"
|
||||
#include "rclcpp/allocator/allocator_deleter.hpp"
|
||||
#include "rclcpp/detail/resolve_use_intra_process.hpp"
|
||||
#include "rclcpp/experimental/intra_process_manager.hpp"
|
||||
#include "rclcpp/get_message_type_support_handle.hpp"
|
||||
#include "rclcpp/is_ros_compatible_type.hpp"
|
||||
#include "rclcpp/loaned_message.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/publisher_base.hpp"
|
||||
#include "rclcpp/publisher_options.hpp"
|
||||
#include "rclcpp/type_adapter.hpp"
|
||||
#include "rclcpp/type_support_decl.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
#include "tracetools/tracetools.h"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
@@ -47,15 +53,61 @@ template<typename MessageT, typename AllocatorT>
|
||||
class LoanedMessage;
|
||||
|
||||
/// A publisher publishes messages of any type to a topic.
|
||||
/**
|
||||
* MessageT must be a:
|
||||
*
|
||||
* - ROS message type with its own type support (e.g. std_msgs::msgs::String), or a
|
||||
* - rclcpp::TypeAdapter<CustomType, ROSMessageType>
|
||||
* (e.g. rclcpp::TypeAdapter<std::string, std_msgs::msg::String), or a
|
||||
* - custom type that has been setup as the implicit type for a ROS type using
|
||||
* RCLCPP_USING_CUSTOM_TYPE_AS_ROS_MESSAGE_TYPE(custom_type, ros_message_type)
|
||||
*
|
||||
* In the case that MessageT is ROS message type (e.g. std_msgs::msg::String),
|
||||
* both PublishedType and ROSMessageType will be that type.
|
||||
* In the case that MessageT is a TypeAdapter<CustomType, ROSMessageType> type
|
||||
* (e.g. TypeAdapter<std::string, std_msgs::msg::String>), PublishedType will
|
||||
* be the custom type, and ROSMessageType will be the ros message type.
|
||||
*
|
||||
* This is achieved because of the "identity specialization" for TypeAdapter,
|
||||
* which returns itself if it is already a TypeAdapter, and the default
|
||||
* specialization which allows ROSMessageType to be void.
|
||||
* \sa rclcpp::TypeAdapter for more details.
|
||||
*/
|
||||
template<typename MessageT, typename AllocatorT = std::allocator<void>>
|
||||
class Publisher : public PublisherBase
|
||||
{
|
||||
public:
|
||||
using MessageAllocatorTraits = allocator::AllocRebind<MessageT, AllocatorT>;
|
||||
using MessageAllocator = typename MessageAllocatorTraits::allocator_type;
|
||||
using MessageDeleter = allocator::Deleter<MessageAllocator, MessageT>;
|
||||
using MessageUniquePtr = std::unique_ptr<MessageT, MessageDeleter>;
|
||||
using MessageSharedPtr = std::shared_ptr<const MessageT>;
|
||||
static_assert(
|
||||
rclcpp::is_ros_compatible_type<MessageT>::value,
|
||||
"given message type is not compatible with ROS and cannot be used with a Publisher");
|
||||
|
||||
/// MessageT::custom_type if MessageT is a TypeAdapter, otherwise just MessageT.
|
||||
using PublishedType = typename rclcpp::TypeAdapter<MessageT>::custom_type;
|
||||
using ROSMessageType = typename rclcpp::TypeAdapter<MessageT>::ros_message_type;
|
||||
|
||||
using PublishedTypeAllocatorTraits = allocator::AllocRebind<PublishedType, AllocatorT>;
|
||||
using PublishedTypeAllocator = typename PublishedTypeAllocatorTraits::allocator_type;
|
||||
using PublishedTypeDeleter = allocator::Deleter<PublishedTypeAllocator, PublishedType>;
|
||||
|
||||
using ROSMessageTypeAllocatorTraits = allocator::AllocRebind<ROSMessageType, AllocatorT>;
|
||||
using ROSMessageTypeAllocator = typename ROSMessageTypeAllocatorTraits::allocator_type;
|
||||
using ROSMessageTypeDeleter = allocator::Deleter<ROSMessageTypeAllocator, ROSMessageType>;
|
||||
|
||||
using MessageAllocatorTraits
|
||||
[[deprecated("use PublishedTypeAllocatorTraits")]] =
|
||||
PublishedTypeAllocatorTraits;
|
||||
using MessageAllocator
|
||||
[[deprecated("use PublishedTypeAllocator")]] =
|
||||
PublishedTypeAllocator;
|
||||
using MessageDeleter
|
||||
[[deprecated("use PublishedTypeDeleter")]] =
|
||||
PublishedTypeDeleter;
|
||||
using MessageUniquePtr
|
||||
[[deprecated("use std::unique_ptr<PublishedType, PublishedTypeDeleter>")]] =
|
||||
std::unique_ptr<PublishedType, PublishedTypeDeleter>;
|
||||
using MessageSharedPtr
|
||||
[[deprecated("use std::shared_ptr<const PublishedType>")]] =
|
||||
std::shared_ptr<const PublishedType>;
|
||||
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(Publisher<MessageT, AllocatorT>)
|
||||
|
||||
@@ -78,39 +130,17 @@ public:
|
||||
: PublisherBase(
|
||||
node_base,
|
||||
topic,
|
||||
*rosidl_typesupport_cpp::get_message_type_support_handle<MessageT>(),
|
||||
options.template to_rcl_publisher_options<MessageT>(qos)),
|
||||
rclcpp::get_message_type_support_handle<MessageT>(),
|
||||
options.template to_rcl_publisher_options<MessageT>(qos),
|
||||
// NOTE(methylDragon): Passing these args separately is necessary for event binding
|
||||
options.event_callbacks,
|
||||
options.use_default_callbacks),
|
||||
options_(options),
|
||||
message_allocator_(new MessageAllocator(*options.get_allocator().get()))
|
||||
published_type_allocator_(*options.get_allocator()),
|
||||
ros_message_type_allocator_(*options.get_allocator())
|
||||
{
|
||||
allocator::set_allocator_for_deleter(&message_deleter_, message_allocator_.get());
|
||||
|
||||
if (options_.event_callbacks.deadline_callback) {
|
||||
this->add_event_handler(
|
||||
options_.event_callbacks.deadline_callback,
|
||||
RCL_PUBLISHER_OFFERED_DEADLINE_MISSED);
|
||||
}
|
||||
if (options_.event_callbacks.liveliness_callback) {
|
||||
this->add_event_handler(
|
||||
options_.event_callbacks.liveliness_callback,
|
||||
RCL_PUBLISHER_LIVELINESS_LOST);
|
||||
}
|
||||
if (options_.event_callbacks.incompatible_qos_callback) {
|
||||
this->add_event_handler(
|
||||
options_.event_callbacks.incompatible_qos_callback,
|
||||
RCL_PUBLISHER_OFFERED_INCOMPATIBLE_QOS);
|
||||
} else if (options_.use_default_callbacks) {
|
||||
// Register default callback when not specified
|
||||
try {
|
||||
this->add_event_handler(
|
||||
[this](QOSOfferedIncompatibleQoSInfo & info) {
|
||||
this->default_incompatible_qos_callback(info);
|
||||
},
|
||||
RCL_PUBLISHER_OFFERED_INCOMPATIBLE_QOS);
|
||||
} catch (UnsupportedEventTypeException & /*exc*/) {
|
||||
// pass
|
||||
}
|
||||
}
|
||||
allocator::set_allocator_for_deleter(&published_type_deleter_, &published_type_allocator_);
|
||||
allocator::set_allocator_for_deleter(&ros_message_type_deleter_, &ros_message_type_allocator_);
|
||||
// Setup continues in the post construction method, post_init_setup().
|
||||
}
|
||||
|
||||
@@ -133,15 +163,15 @@ public:
|
||||
// Get the intra process manager instance for this context.
|
||||
auto ipm = context->get_sub_context<rclcpp::experimental::IntraProcessManager>();
|
||||
// Register the publisher with the intra process manager.
|
||||
if (qos.get_rmw_qos_profile().history == RMW_QOS_POLICY_HISTORY_KEEP_ALL) {
|
||||
if (qos.history() != rclcpp::HistoryPolicy::KeepLast) {
|
||||
throw std::invalid_argument(
|
||||
"intraprocess communication is not allowed with keep all history qos policy");
|
||||
"intraprocess communication allowed only with keep last history qos policy");
|
||||
}
|
||||
if (qos.get_rmw_qos_profile().depth == 0) {
|
||||
if (qos.depth() == 0) {
|
||||
throw std::invalid_argument(
|
||||
"intraprocess communication is not allowed with a zero qos history depth value");
|
||||
}
|
||||
if (qos.get_rmw_qos_profile().durability != RMW_QOS_POLICY_DURABILITY_VOLATILE) {
|
||||
if (qos.durability() != rclcpp::DurabilityPolicy::Volatile) {
|
||||
throw std::invalid_argument(
|
||||
"intraprocess communication allowed only with volatile durability");
|
||||
}
|
||||
@@ -168,21 +198,33 @@ public:
|
||||
* allocator.
|
||||
* \sa rclcpp::LoanedMessage for details of the LoanedMessage class.
|
||||
*
|
||||
* \return LoanedMessage containing memory for a ROS message of type MessageT
|
||||
* \return LoanedMessage containing memory for a ROS message of type ROSMessageType
|
||||
*/
|
||||
rclcpp::LoanedMessage<MessageT, AllocatorT>
|
||||
rclcpp::LoanedMessage<ROSMessageType, AllocatorT>
|
||||
borrow_loaned_message()
|
||||
{
|
||||
return rclcpp::LoanedMessage<MessageT, AllocatorT>(this, this->get_allocator());
|
||||
return rclcpp::LoanedMessage<ROSMessageType, AllocatorT>(
|
||||
*this,
|
||||
this->get_ros_message_type_allocator());
|
||||
}
|
||||
|
||||
/// Send a message to the topic for this publisher.
|
||||
/// Publish a message on the topic.
|
||||
/**
|
||||
* This function is templated on the input message type, MessageT.
|
||||
* \param[in] msg A shared pointer to the message to send.
|
||||
* This signature is enabled if the element_type of the std::unique_ptr is
|
||||
* a ROS message type, as opposed to the custom_type of a TypeAdapter, and
|
||||
* that type matches the type given when creating the publisher.
|
||||
*
|
||||
* This signature allows the user to give ownership of the message to rclcpp,
|
||||
* allowing for more efficient intra-process communication optimizations.
|
||||
*
|
||||
* \param[in] msg A unique pointer to the message to send.
|
||||
*/
|
||||
virtual void
|
||||
publish(std::unique_ptr<MessageT, MessageDeleter> msg)
|
||||
template<typename T>
|
||||
typename std::enable_if_t<
|
||||
rosidl_generator_traits::is_message<T>::value &&
|
||||
std::is_same<T, ROSMessageType>::value
|
||||
>
|
||||
publish(std::unique_ptr<T, ROSMessageTypeDeleter> msg)
|
||||
{
|
||||
if (!intra_process_is_enabled_) {
|
||||
this->do_inter_process_publish(*msg);
|
||||
@@ -198,15 +240,32 @@ public:
|
||||
get_subscription_count() > get_intra_process_subscription_count();
|
||||
|
||||
if (inter_process_publish_needed) {
|
||||
auto shared_msg = this->do_intra_process_publish_and_return_shared(std::move(msg));
|
||||
auto shared_msg =
|
||||
this->do_intra_process_ros_message_publish_and_return_shared(std::move(msg));
|
||||
this->do_inter_process_publish(*shared_msg);
|
||||
} else {
|
||||
this->do_intra_process_publish(std::move(msg));
|
||||
this->do_intra_process_ros_message_publish(std::move(msg));
|
||||
}
|
||||
}
|
||||
|
||||
virtual void
|
||||
publish(const MessageT & msg)
|
||||
/// Publish a message on the topic.
|
||||
/**
|
||||
* This signature is enabled if the object being published is
|
||||
* a ROS message type, as opposed to the custom_type of a TypeAdapter, and
|
||||
* that type matches the type given when creating the publisher.
|
||||
*
|
||||
* This signature allows the user to give a reference to a message, which is
|
||||
* copied onto the heap without modification so that a copy can be owned by
|
||||
* rclcpp and ownership of the copy can be moved later if needed.
|
||||
*
|
||||
* \param[in] msg A const reference to the message to send.
|
||||
*/
|
||||
template<typename T>
|
||||
typename std::enable_if_t<
|
||||
rosidl_generator_traits::is_message<T>::value &&
|
||||
std::is_same<T, ROSMessageType>::value
|
||||
>
|
||||
publish(const T & msg)
|
||||
{
|
||||
// Avoid allocating when not using intra process.
|
||||
if (!intra_process_is_enabled_) {
|
||||
@@ -216,9 +275,83 @@ public:
|
||||
// Otherwise we have to allocate memory in a unique_ptr and pass it along.
|
||||
// As the message is not const, a copy should be made.
|
||||
// A shared_ptr<const MessageT> could also be constructed here.
|
||||
auto ptr = MessageAllocatorTraits::allocate(*message_allocator_.get(), 1);
|
||||
MessageAllocatorTraits::construct(*message_allocator_.get(), ptr, msg);
|
||||
MessageUniquePtr unique_msg(ptr, message_deleter_);
|
||||
auto unique_msg = this->duplicate_ros_message_as_unique_ptr(msg);
|
||||
this->publish(std::move(unique_msg));
|
||||
}
|
||||
|
||||
/// Publish a message on the topic.
|
||||
/**
|
||||
* This signature is enabled if this class was created with a TypeAdapter and
|
||||
* the element_type of the std::unique_ptr matches the custom_type for the
|
||||
* TypeAdapter used with this class.
|
||||
*
|
||||
* This signature allows the user to give ownership of the message to rclcpp,
|
||||
* allowing for more efficient intra-process communication optimizations.
|
||||
*
|
||||
* \param[in] msg A unique pointer to the message to send.
|
||||
*/
|
||||
template<typename T>
|
||||
typename std::enable_if_t<
|
||||
rclcpp::TypeAdapter<MessageT>::is_specialized::value &&
|
||||
std::is_same<T, PublishedType>::value
|
||||
>
|
||||
publish(std::unique_ptr<T, PublishedTypeDeleter> msg)
|
||||
{
|
||||
// Avoid allocating when not using intra process.
|
||||
if (!intra_process_is_enabled_) {
|
||||
// In this case we're not using intra process.
|
||||
ROSMessageType ros_msg;
|
||||
rclcpp::TypeAdapter<MessageT>::convert_to_ros_message(*msg, ros_msg);
|
||||
return this->do_inter_process_publish(ros_msg);
|
||||
}
|
||||
|
||||
bool inter_process_publish_needed =
|
||||
get_subscription_count() > get_intra_process_subscription_count();
|
||||
|
||||
if (inter_process_publish_needed) {
|
||||
ROSMessageType ros_msg;
|
||||
// TODO(clalancette): This is unnecessarily doing an additional conversion
|
||||
// that may have already been done in do_intra_process_publish_and_return_shared().
|
||||
// We should just reuse that effort.
|
||||
rclcpp::TypeAdapter<MessageT>::convert_to_ros_message(*msg, ros_msg);
|
||||
this->do_intra_process_publish(std::move(msg));
|
||||
this->do_inter_process_publish(ros_msg);
|
||||
} else {
|
||||
this->do_intra_process_publish(std::move(msg));
|
||||
}
|
||||
}
|
||||
|
||||
/// Publish a message on the topic.
|
||||
/**
|
||||
* This signature is enabled if this class was created with a TypeAdapter and
|
||||
* the given type matches the custom_type of the TypeAdapter.
|
||||
*
|
||||
* This signature allows the user to give a reference to a message, which is
|
||||
* copied onto the heap without modification so that a copy can be owned by
|
||||
* rclcpp and ownership of the copy can be moved later if needed.
|
||||
*
|
||||
* \param[in] msg A const reference to the message to send.
|
||||
*/
|
||||
template<typename T>
|
||||
typename std::enable_if_t<
|
||||
rclcpp::TypeAdapter<MessageT>::is_specialized::value &&
|
||||
std::is_same<T, PublishedType>::value
|
||||
>
|
||||
publish(const T & msg)
|
||||
{
|
||||
// Avoid double allocating when not using intra process.
|
||||
if (!intra_process_is_enabled_) {
|
||||
// Convert to the ROS message equivalent and publish it.
|
||||
ROSMessageType ros_msg;
|
||||
rclcpp::TypeAdapter<MessageT>::convert_to_ros_message(msg, ros_msg);
|
||||
// In this case we're not using intra process.
|
||||
return this->do_inter_process_publish(ros_msg);
|
||||
}
|
||||
|
||||
// Otherwise we have to allocate memory in a unique_ptr and pass it along.
|
||||
// As the message is not const, a copy should be made.
|
||||
// A shared_ptr<const MessageT> could also be constructed here.
|
||||
auto unique_msg = this->duplicate_type_adapt_message_as_unique_ptr(msg);
|
||||
this->publish(std::move(unique_msg));
|
||||
}
|
||||
|
||||
@@ -243,15 +376,11 @@ public:
|
||||
* \param loaned_msg The LoanedMessage instance to be published.
|
||||
*/
|
||||
void
|
||||
publish(rclcpp::LoanedMessage<MessageT, AllocatorT> && loaned_msg)
|
||||
publish(rclcpp::LoanedMessage<ROSMessageType, AllocatorT> && loaned_msg)
|
||||
{
|
||||
if (!loaned_msg.is_valid()) {
|
||||
throw std::runtime_error("loaned message is not valid");
|
||||
}
|
||||
if (intra_process_is_enabled_) {
|
||||
// TODO(Karsten1987): support loaned message passed by intraprocess
|
||||
throw std::runtime_error("storing loaned messages in intra process is not supported yet");
|
||||
}
|
||||
|
||||
// verify that publisher supports loaned messages
|
||||
// TODO(Karsten1987): This case separation has to be done in rclcpp
|
||||
@@ -265,20 +394,34 @@ public:
|
||||
} else {
|
||||
// we don't release the ownership, let the middleware copy the ros message
|
||||
// and thus the destructor of rclcpp::LoanedMessage cleans up the memory.
|
||||
this->do_inter_process_publish(loaned_msg.get());
|
||||
this->publish(loaned_msg.get());
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<MessageAllocator>
|
||||
[[deprecated("use get_published_type_allocator() or get_ros_message_type_allocator() instead")]]
|
||||
std::shared_ptr<PublishedTypeAllocator>
|
||||
get_allocator() const
|
||||
{
|
||||
return message_allocator_;
|
||||
return std::make_shared<PublishedTypeAllocator>(published_type_allocator_);
|
||||
}
|
||||
|
||||
PublishedTypeAllocator
|
||||
get_published_type_allocator() const
|
||||
{
|
||||
return published_type_allocator_;
|
||||
}
|
||||
|
||||
ROSMessageTypeAllocator
|
||||
get_ros_message_type_allocator() const
|
||||
{
|
||||
return ros_message_type_allocator_;
|
||||
}
|
||||
|
||||
protected:
|
||||
void
|
||||
do_inter_process_publish(const MessageT & msg)
|
||||
do_inter_process_publish(const ROSMessageType & msg)
|
||||
{
|
||||
TRACEPOINT(rclcpp_publish, nullptr, static_cast<const void *>(&msg));
|
||||
auto status = rcl_publish(publisher_handle_.get(), &msg, nullptr);
|
||||
|
||||
if (RCL_RET_PUBLISHER_INVALID == status) {
|
||||
@@ -310,7 +453,8 @@ protected:
|
||||
}
|
||||
|
||||
void
|
||||
do_loaned_message_publish(std::unique_ptr<MessageT, std::function<void(MessageT *)>> msg)
|
||||
do_loaned_message_publish(
|
||||
std::unique_ptr<ROSMessageType, std::function<void(ROSMessageType *)>> msg)
|
||||
{
|
||||
auto status = rcl_publish_loaned_message(publisher_handle_.get(), msg.get(), nullptr);
|
||||
|
||||
@@ -330,7 +474,7 @@ protected:
|
||||
}
|
||||
|
||||
void
|
||||
do_intra_process_publish(std::unique_ptr<MessageT, MessageDeleter> msg)
|
||||
do_intra_process_publish(std::unique_ptr<PublishedType, PublishedTypeDeleter> msg)
|
||||
{
|
||||
auto ipm = weak_ipm_.lock();
|
||||
if (!ipm) {
|
||||
@@ -341,14 +485,14 @@ protected:
|
||||
throw std::runtime_error("cannot publish msg which is a null pointer");
|
||||
}
|
||||
|
||||
ipm->template do_intra_process_publish<MessageT, AllocatorT>(
|
||||
ipm->template do_intra_process_publish<PublishedType, ROSMessageType, AllocatorT>(
|
||||
intra_process_publisher_id_,
|
||||
std::move(msg),
|
||||
message_allocator_);
|
||||
published_type_allocator_);
|
||||
}
|
||||
|
||||
std::shared_ptr<const MessageT>
|
||||
do_intra_process_publish_and_return_shared(std::unique_ptr<MessageT, MessageDeleter> msg)
|
||||
void
|
||||
do_intra_process_ros_message_publish(std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter> msg)
|
||||
{
|
||||
auto ipm = weak_ipm_.lock();
|
||||
if (!ipm) {
|
||||
@@ -359,10 +503,58 @@ protected:
|
||||
throw std::runtime_error("cannot publish msg which is a null pointer");
|
||||
}
|
||||
|
||||
return ipm->template do_intra_process_publish_and_return_shared<MessageT, AllocatorT>(
|
||||
ipm->template do_intra_process_publish<ROSMessageType, ROSMessageType, AllocatorT>(
|
||||
intra_process_publisher_id_,
|
||||
std::move(msg),
|
||||
message_allocator_);
|
||||
ros_message_type_allocator_);
|
||||
}
|
||||
|
||||
std::shared_ptr<const ROSMessageType>
|
||||
do_intra_process_ros_message_publish_and_return_shared(
|
||||
std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter> msg)
|
||||
{
|
||||
auto ipm = weak_ipm_.lock();
|
||||
if (!ipm) {
|
||||
throw std::runtime_error(
|
||||
"intra process publish called after destruction of intra process manager");
|
||||
}
|
||||
if (!msg) {
|
||||
throw std::runtime_error("cannot publish msg which is a null pointer");
|
||||
}
|
||||
|
||||
return ipm->template do_intra_process_publish_and_return_shared<ROSMessageType, ROSMessageType,
|
||||
AllocatorT>(
|
||||
intra_process_publisher_id_,
|
||||
std::move(msg),
|
||||
ros_message_type_allocator_);
|
||||
}
|
||||
|
||||
|
||||
/// Return a new unique_ptr using the ROSMessageType of the publisher.
|
||||
std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>
|
||||
create_ros_message_unique_ptr()
|
||||
{
|
||||
auto ptr = ROSMessageTypeAllocatorTraits::allocate(ros_message_type_allocator_, 1);
|
||||
ROSMessageTypeAllocatorTraits::construct(ros_message_type_allocator_, ptr);
|
||||
return std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>(ptr, ros_message_type_deleter_);
|
||||
}
|
||||
|
||||
/// Duplicate a given ros message as a unique_ptr.
|
||||
std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>
|
||||
duplicate_ros_message_as_unique_ptr(const ROSMessageType & msg)
|
||||
{
|
||||
auto ptr = ROSMessageTypeAllocatorTraits::allocate(ros_message_type_allocator_, 1);
|
||||
ROSMessageTypeAllocatorTraits::construct(ros_message_type_allocator_, ptr, msg);
|
||||
return std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>(ptr, ros_message_type_deleter_);
|
||||
}
|
||||
|
||||
/// Duplicate a given type adapted message as a unique_ptr.
|
||||
std::unique_ptr<PublishedType, PublishedTypeDeleter>
|
||||
duplicate_type_adapt_message_as_unique_ptr(const PublishedType & msg)
|
||||
{
|
||||
auto ptr = PublishedTypeAllocatorTraits::allocate(published_type_allocator_, 1);
|
||||
PublishedTypeAllocatorTraits::construct(published_type_allocator_, ptr, msg);
|
||||
return std::unique_ptr<PublishedType, PublishedTypeDeleter>(ptr, published_type_deleter_);
|
||||
}
|
||||
|
||||
/// Copy of original options passed during construction.
|
||||
@@ -372,9 +564,10 @@ protected:
|
||||
*/
|
||||
const rclcpp::PublisherOptionsWithAllocator<AllocatorT> options_;
|
||||
|
||||
std::shared_ptr<MessageAllocator> message_allocator_;
|
||||
|
||||
MessageDeleter message_deleter_;
|
||||
PublishedTypeAllocator published_type_allocator_;
|
||||
PublishedTypeDeleter published_type_deleter_;
|
||||
ROSMessageTypeAllocator ros_message_type_allocator_;
|
||||
ROSMessageTypeDeleter ros_message_type_deleter_;
|
||||
};
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
@@ -18,20 +18,25 @@
|
||||
#include <rmw/error_handling.h>
|
||||
#include <rmw/rmw.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "rcl/publisher.h"
|
||||
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/network_flow_endpoint.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
#include "rclcpp/qos_event.hpp"
|
||||
#include "rclcpp/event_handler.hpp"
|
||||
#include "rclcpp/type_support_decl.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
#include "rcpputils/time.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
@@ -73,11 +78,18 @@ public:
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||
const std::string & topic,
|
||||
const rosidl_message_type_support_t & type_support,
|
||||
const rcl_publisher_options_t & publisher_options);
|
||||
const rcl_publisher_options_t & publisher_options,
|
||||
const PublisherEventCallbacks & event_callbacks,
|
||||
bool use_default_callbacks);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual ~PublisherBase();
|
||||
|
||||
/// Add event handlers for passed in event_callbacks.
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
bind_event_callbacks(const PublisherEventCallbacks & event_callbacks, bool use_default_callbacks);
|
||||
|
||||
/// Get the topic that this publisher publishes on.
|
||||
/** \return The topic name. */
|
||||
RCLCPP_PUBLIC
|
||||
@@ -109,9 +121,10 @@ public:
|
||||
get_publisher_handle() const;
|
||||
|
||||
/// Get all the QoS event handlers associated with this publisher.
|
||||
/** \return The vector of QoS event handlers. */
|
||||
/** \return The map of QoS event handlers. */
|
||||
RCLCPP_PUBLIC
|
||||
const std::vector<std::shared_ptr<rclcpp::QOSEventHandlerBase>> &
|
||||
const
|
||||
std::unordered_map<rcl_publisher_event_type_t, std::shared_ptr<rclcpp::EventHandlerBase>> &
|
||||
get_event_handlers() const;
|
||||
|
||||
/// Get subscription count
|
||||
@@ -193,6 +206,120 @@ public:
|
||||
uint64_t intra_process_publisher_id,
|
||||
IntraProcessManagerSharedPtr ipm);
|
||||
|
||||
/// Get network flow endpoints
|
||||
/**
|
||||
* Describes network flow endpoints that this publisher is sending messages out on
|
||||
* \return vector of NetworkFlowEndpoint
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<rclcpp::NetworkFlowEndpoint>
|
||||
get_network_flow_endpoints() const;
|
||||
|
||||
/// Wait until all published messages are acknowledged or until the specified timeout elapses.
|
||||
/**
|
||||
* This method waits until all published messages are acknowledged by all matching
|
||||
* subscriptions or the given timeout elapses.
|
||||
*
|
||||
* If the timeout is negative then this method will block indefinitely until all published
|
||||
* messages are acknowledged.
|
||||
* If the timeout is zero then this method will not block, it will check if all published
|
||||
* messages are acknowledged and return immediately.
|
||||
* If the timeout is greater than zero, this method will wait until all published messages are
|
||||
* acknowledged or the timeout elapses.
|
||||
*
|
||||
* This method only waits for acknowledgments if the publisher's QoS profile is RELIABLE.
|
||||
* Otherwise this method will immediately return `true`.
|
||||
*
|
||||
* \param[in] timeout the duration to wait for all published messages to be acknowledged.
|
||||
* \return `true` if all published messages were acknowledged before the given timeout
|
||||
* elapsed, otherwise `false`.
|
||||
* \throws rclcpp::exceptions::RCLError if middleware doesn't support or internal error occurs
|
||||
* \throws std::invalid_argument if timeout is greater than std::chrono::nanoseconds::max() or
|
||||
* less than std::chrono::nanoseconds::min()
|
||||
*/
|
||||
template<typename DurationRepT = int64_t, typename DurationT = std::milli>
|
||||
bool
|
||||
wait_for_all_acked(
|
||||
std::chrono::duration<DurationRepT, DurationT> timeout =
|
||||
std::chrono::duration<DurationRepT, DurationT>(-1)) const
|
||||
{
|
||||
rcl_duration_value_t rcl_timeout = rcpputils::convert_to_nanoseconds(timeout).count();
|
||||
|
||||
rcl_ret_t ret = rcl_publisher_wait_for_all_acked(publisher_handle_.get(), rcl_timeout);
|
||||
if (ret == RCL_RET_OK) {
|
||||
return true;
|
||||
} else if (ret == RCL_RET_TIMEOUT) {
|
||||
return false;
|
||||
} else {
|
||||
rclcpp::exceptions::throw_from_rcl_error(ret);
|
||||
}
|
||||
}
|
||||
|
||||
/// Set a callback to be called when each new qos event instance occurs.
|
||||
/**
|
||||
* The callback receives a size_t which is the number of events that occurred
|
||||
* since the last time this callback was called.
|
||||
* Normally this is 1, but can be > 1 if events occurred before any
|
||||
* callback was set.
|
||||
*
|
||||
* Since this callback is called from the middleware, you should aim to make
|
||||
* it fast and not blocking.
|
||||
* If you need to do a lot of work or wait for some other event, you should
|
||||
* spin it off to another thread, otherwise you risk blocking the middleware.
|
||||
*
|
||||
* Calling it again will clear any previously set callback.
|
||||
*
|
||||
* An exception will be thrown if the callback is not callable.
|
||||
*
|
||||
* This function is thread-safe.
|
||||
*
|
||||
* If you want more information available in the callback, like the qos event
|
||||
* or other information, you may use a lambda with captures or std::bind.
|
||||
*
|
||||
* \sa rclcpp::EventHandlerBase::set_on_ready_callback
|
||||
*
|
||||
* \param[in] callback functor to be called when a new event occurs
|
||||
* \param[in] event_type identifier for the qos event we want to attach the callback to
|
||||
*/
|
||||
void
|
||||
set_on_new_qos_event_callback(
|
||||
std::function<void(size_t)> callback,
|
||||
rcl_publisher_event_type_t event_type)
|
||||
{
|
||||
if (event_handlers_.count(event_type) == 0) {
|
||||
RCLCPP_WARN(
|
||||
rclcpp::get_logger("rclcpp"),
|
||||
"Calling set_on_new_qos_event_callback for non registered publisher event_type");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!callback) {
|
||||
throw std::invalid_argument(
|
||||
"The callback passed to set_on_new_qos_event_callback "
|
||||
"is not callable.");
|
||||
}
|
||||
|
||||
// The on_ready_callback signature has an extra `int` argument used to disambiguate between
|
||||
// possible different entities within a generic waitable.
|
||||
// We hide that detail to users of this method.
|
||||
std::function<void(size_t, int)> new_callback = std::bind(callback, std::placeholders::_1);
|
||||
event_handlers_[event_type]->set_on_ready_callback(new_callback);
|
||||
}
|
||||
|
||||
/// Unset the callback registered for new qos events, if any.
|
||||
void
|
||||
clear_on_new_qos_event_callback(rcl_publisher_event_type_t event_type)
|
||||
{
|
||||
if (event_handlers_.count(event_type) == 0) {
|
||||
RCLCPP_WARN(
|
||||
rclcpp::get_logger("rclcpp"),
|
||||
"Calling clear_on_new_qos_event_callback for non registered event_type");
|
||||
return;
|
||||
}
|
||||
|
||||
event_handlers_[event_type]->clear_on_ready_callback();
|
||||
}
|
||||
|
||||
protected:
|
||||
template<typename EventCallbackT>
|
||||
void
|
||||
@@ -200,23 +327,27 @@ protected:
|
||||
const EventCallbackT & callback,
|
||||
const rcl_publisher_event_type_t event_type)
|
||||
{
|
||||
auto handler = std::make_shared<QOSEventHandler<EventCallbackT,
|
||||
auto handler = std::make_shared<EventHandler<EventCallbackT,
|
||||
std::shared_ptr<rcl_publisher_t>>>(
|
||||
callback,
|
||||
rcl_publisher_event_init,
|
||||
publisher_handle_,
|
||||
event_type);
|
||||
event_handlers_.emplace_back(handler);
|
||||
event_handlers_.insert(std::make_pair(event_type, handler));
|
||||
}
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void default_incompatible_qos_callback(QOSOfferedIncompatibleQoSInfo & info) const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void default_incompatible_type_callback(IncompatibleTypeInfo & info) const;
|
||||
|
||||
std::shared_ptr<rcl_node_t> rcl_node_handle_;
|
||||
|
||||
std::shared_ptr<rcl_publisher_t> publisher_handle_;
|
||||
|
||||
std::vector<std::shared_ptr<rclcpp::QOSEventHandlerBase>> event_handlers_;
|
||||
std::unordered_map<rcl_publisher_event_type_t,
|
||||
std::shared_ptr<rclcpp::EventHandlerBase>> event_handlers_;
|
||||
|
||||
using IntraProcessManagerWeakPtr =
|
||||
std::weak_ptr<rclcpp::experimental::IntraProcessManager>;
|
||||
@@ -225,6 +356,10 @@ protected:
|
||||
uint64_t intra_process_publisher_id_;
|
||||
|
||||
rmw_gid_t rmw_gid_;
|
||||
|
||||
const rosidl_message_type_support_t type_support_;
|
||||
|
||||
const PublisherEventCallbacks event_callbacks_;
|
||||
};
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user