Compare commits

..

317 Commits

Author SHA1 Message Date
Audrow Nash
52327dd3a3 16.0.5
Signed-off-by: Audrow Nash <audrow@intrinsic.ai>
2023-07-17 22:40:27 +00:00
Joseph Schornak
25263e838d Fix thread safety in LifecycleNode::get_current_state() for Humble (#2183)
* add initially-failing test case

* apply changes to LifecycleNodeInterfaceImpl from #1756

* add static member to State for managing state_handle_ access

* allow parallel read access in MutexMap

Signed-off-by: Joe Schornak <joe.schornak@gmail.com>
2023-06-26 20:46:58 -04:00
mergify[bot]
a75baa6b26 warning: comparison of integer expressions of different signedness (#2219) (#2223)
https://github.com/ros2/rclcpp/pull/2167#issuecomment-1597197552

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
(cherry picked from commit fe2e0e4c64)

Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-06-23 13:00:14 -04:00
Tomoya Fujita
5f7485f4fd Trigger the intraprocess guard condition with data (#2164) (#2167)
If the intraprocess buffer still has data after taking, re-trigger the
guard condition to ensure that the executor will continue to service it,
even if incoming publications stop.

Signed-off-by: Michael Carroll <michael@openrobotics.org>
(cherry picked from commit 5f9695afb0)

Co-authored-by: Michael Carroll <michael@openrobotics.org>
2023-06-15 15:19:56 -07:00
mergify[bot]
613d192cd6 Implement validity checks for rclcpp::Clock (#2040) (#2210)
(cherry picked from commit c091fe1a45)

Co-authored-by: methylDragon <methylDragon@gmail.com>
2023-06-14 14:04:50 -07:00
Audrow Nash
00ef09cbf3 16.0.4
Signed-off-by: Audrow Nash <audrow@intrinsic.ai>
2023-04-25 20:55:32 +00:00
Tomoya Fujita
b2b7bdeac1 Revert "Revert "extract the result response before the callback is issued. (#2133)" (#2148)" (#2152)
This reverts commit 19a666f1c9.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-04-02 18:03:05 -07:00
Tomoya Fujita
19a666f1c9 Revert "extract the result response before the callback is issued. (#2133)" (#2148)
This reverts commit c8ac675035.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-03-31 08:45:10 -07:00
Tomoya Fujita
c8ac675035 extract the result response before the callback is issued. (#2133)
backport of https://github.com/ros2/rclcpp/pull/2132

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
Co-authored-by: Chen Lihui <lihui.chen@sony.com>
2023-03-30 08:43:03 -07:00
mergify[bot]
4196a2a8b4 use allocator via init_options argument. (#2129) (#2131)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
(cherry picked from commit 1a796b5515)

Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2023-03-20 13:36:32 -07:00
Audrow Nash
9171122eae 16.0.3
Signed-off-by: Audrow Nash <audrow@openrobotics.org>
2023-01-10 07:58:19 -06:00
mergify[bot]
ce13f1afba Fix SharedFuture from async_send_request never becomes valid (#2044) (#2076)
Signed-off-by: Lei Liu <Lei.Liu.AP@sony.com>
(cherry picked from commit 66b19448b0)

Co-authored-by: Lei Liu <64953129+llapx@users.noreply.github.com>
2023-01-06 10:19:33 -08:00
mergify[bot]
df08474d38 do not throw exception if trying to dequeue an empty intra-process buffer (#2061) (#2070)
Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>
(cherry picked from commit 3fb012e2e9)

Co-authored-by: Alberto Soragna <alberto.soragna@gmail.com>
2022-12-22 14:14:36 -08:00
mergify[bot]
f9050cd666 fix nullptr dereference in prune_requests_older_than (#2008) (#2065)
* fix nullptr dereference in prune_requests_older_than

Signed-off-by: akela1101 <akela1101@gmail.com>

* add tests for prune_requests_older_than

Signed-off-by: akela1101 <akela1101@gmail.com>

* Update rclcpp/test/rclcpp/test_client.cpp

Co-authored-by: Chen Lihui <lihui.chen@sony.com>
Signed-off-by: akela1101 <akela1101@gmail.com>

Signed-off-by: akela1101 <akela1101@gmail.com>
Co-authored-by: Chen Lihui <lihui.chen@sony.com>
(cherry picked from commit 1ac37b692c)

Co-authored-by: andrei <akela1101@gmail.com>
2022-12-13 15:40:16 -03:00
mergify[bot]
33cbd76c07 Fix bug that a callback not reached (#1640) (#2033)
* Add a test case

a subscriber on a new executor with a callback group triggered to receive a message

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* fix flaky and not to use spin_some

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* update comment

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* update for not using anti-pattern source code

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* add a notify guard condition for callback group

Co-authored-by: William Woodall <william@osrfoundation.org>
Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* Notify guard condition of Node not to be used in Executor

it is only for the waitset of GraphListener

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* put code in the try catch

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* defer to create guard condition

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* use context directly for the create function

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* cpplint

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* fix that some case might call add_node after shutdown

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* nitpick and fix some potential bug

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* add sanity check as some case might not create notify guard condition after shutdown

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* Cleanup includes.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>

* remove destroy method

make a callback group can only create one guard condition

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* remove limitation that guard condition can not be re-created in callback group

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

Signed-off-by: Chen Lihui <lihui.chen@sony.com>
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
Co-authored-by: William Woodall <william@osrfoundation.org>
Co-authored-by: Chris Lalancette <clalancette@openrobotics.org>
(cherry picked from commit d119157948)

Co-authored-by: Chen Lihui <lihui.chen@sony.com>
2022-11-09 22:16:14 -08:00
Audrow Nash
ae8b033ae0 16.0.2
Signed-off-by: Audrow Nash <audrow@openrobotics.org>
2022-11-07 09:12:14 -06:00
mergify[bot]
4fa3489cfd fix mismatched issue if using zero_allocate (#1995) (#2026)
* fix mismatched issue if uzing zero_allocated

Signed-off-by: Chen Lihui <lihui.chen@sony.com>
(cherry picked from commit 978439191f)

Co-authored-by: Chen Lihui <lihui.chen@sony.com>
2022-10-17 10:50:44 -07:00
mergify[bot]
7f575103d8 use regex for wildcard matching (backport #1839) (#1986)
* use regex for wildcard matching (#1839)

* use regex for wildcard matching

Co-authored-by: Aaron Lipinski <aaron.lipinski@roboticsplus.co.nz>
Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* use map to process the content of parameter file by order

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* add more test cases

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* try to not decrease the performance and make the param win last

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* update node name

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* update document comment

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* add more test for parameter_map_from

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

Co-authored-by: Aaron Lipinski <aaron.lipinski@roboticsplus.co.nz>
(cherry picked from commit 6dd3a0377b)

* not to break ABI

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

Signed-off-by: Chen Lihui <lihui.chen@sony.com>
Co-authored-by: Chen Lihui <lihui.chen@sony.com>
2022-09-09 11:55:00 -07:00
mergify[bot]
166007dde3 Drop wrong template specialization (#1926) (#1937)
This fails with g++ -std=gnu++20.

Signed-off-by: Jochen Sprickerhof <git@jochen.sprickerhof.de>
(cherry picked from commit 02802bcc38)

Co-authored-by: Jochen Sprickerhof <github@jochen.sprickerhof.de>
2022-06-15 15:02:18 -03:00
mergify[bot]
cf2a27805e Add statistics for handle_loaned_message (#1927) (#1932)
* Add statistics for handle_loaned_message

Signed-off-by: Barry Xu <barry.xu@sony.com>
(cherry picked from commit 5c688303b3)

Co-authored-by: Barry Xu <barry.xu@sony.com>
2022-06-09 08:54:15 -07:00
Audrow Nash
c24e485084 16.0.1
Signed-off-by: Audrow Nash <audrow@hey.com>
2022-04-13 18:17:29 -07:00
Chen Lihui
d99157d731 remove DEFINE_CONTENT_FILTER cmake option (#1914)
* remove DEFINE_CONTENT_FILTER cmake option

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* remove the macro CONTENT_FILTER_ENABLE as well

Signed-off-by: Chen Lihui <lihui.chen@sony.com>
2022-04-11 10:26:09 -03:00
William Woodall
248d911ea5 16.0.0 2022-04-08 16:27:59 -07:00
William Woodall
76aae4f799 changelogs
Signed-off-by: William Woodall <william@osrfoundation.org>
2022-04-08 16:25:08 -07:00
William Woodall
6815022909 remove things that were deprecated during galactic (#1913)
Signed-off-by: William Woodall <william@osrfoundation.org>
2022-04-08 16:23:43 -07:00
Audrow Nash
85a7046ac3 15.4.0
Signed-off-by: Audrow Nash <audrow@hey.com>
2022-04-05 14:17:00 -07:00
Alberto Soragna
6c06a29050 add take_data_by_entity_id API to waitable (#1892)
* add take_data_by_entity_id API to waitable

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* use size_t for entity id

Signed-off-by: William Woodall <william@osrfoundation.org>

Co-authored-by: William Woodall <william@osrfoundation.org>
2022-04-04 22:25:30 -07:00
Chen Lihui
03fa731d23 add content-filtered-topic interfaces (#1561)
* to support a feature of content filtered topic

Signed-off-by: Chen Lihui <Lihui.Chen@sony.com>

* update for checking memory allocated

Signed-off-by: Chen Lihui <Lihui.Chen@sony.com>

* set expression parameter only if filter is valid

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* add test

Signed-off-by: Chen Lihui <Lihui.Chen@sony.com>

* use a default empty value for expresion parameters

Signed-off-by: Chen Lihui <Lihui.Chen@sony.com>

* remove std_msgs dependency

Signed-off-by: Chen Lihui <Lihui.Chen@sony.com>

* use new rcl interface

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* remove unused include header files and fix unscrutify

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* update comment

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* update comment

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* rename

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* refactor test

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* relate to `rcutils_string_array_t expression_parameters` changed in rmw

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* remove the implementation temporary, add them with fallback in the feature

1. add DEFINE_CONTENT_FILTER with default(ON) to build content filter interfaces
2. user need a compile option(CONTENT_FILTER_ENABLE) to turn on the feature
to set the filter or call the interfaces

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* update comments and check the option to build content filter test

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* add DDS content filter implementation

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* address review

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* rcl api changed

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* increase the filter propagation time

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* add rclcpp::ContentFilterOptions and use it as the return type of get_content_filter

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* increase the maximun time to wait message event and content filter propagation

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* cft member should be defined in the structure.

to check the macro for interfaces is enough.

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* set test timeout to 120

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* update doc

Signed-off-by: Chen Lihui <lihui.chen@sony.com>
2022-04-04 11:50:50 +08:00
Chris Lalancette
0699aeb851 15.3.0 2022-03-30 18:54:18 +00:00
Chris Lalancette
06e6da414a Changelog.
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2022-03-30 18:54:09 +00:00
Abrar Rahman Protyasha
12de518956 [NodeParameters] Set name in param info pre-check (#1908)
* [NodeParameters] Set name if user didn't populate

If the user provided parameter descriptor already contains a name, then
we should not override said name, under the good faith assumption that
the user knows what they are doing.

Signed-off-by: Abrar Rahman Protyasha <aprotyas@u.rochester.edu>
2022-03-30 09:57:22 -07:00
Gaël Écorchard
eac0063176 Add test-dep ament_cmake_google_benchmark (#1904)
Signed-off-by: Gaël Écorchard <gael.ecorchard@cvut.cz>
2022-03-28 09:23:11 -04:00
Barry Xu
492770c12f Add publish by loaned message in GenericPublisher (#1856)
* Add publish by loaned message in GenericPublisher

Signed-off-by: Barry Xu <barry.xu@sony.com>
Co-authored-by: Alban Tamisier <alban.tamisier@apex.ai>
2022-03-27 22:06:17 -07:00
Jacob Perron
d302e3c628 15.2.0 2022-03-24 17:37:17 -07:00
Scott K Logan
011ea39e99 Add missing ament dependency on rcl_interfaces (#1903)
This package uses rcl_interfaces directly, and we've been getting away
with the missing dependency because `rcl` has the entirety of
`rcl_interfaces` as part of its link interface even tough it doesn't
need to.

If (when) `rcl` scopes its dependency to only the c generator and drops
the cpp generator from its link interface, this package will fail to
find the cpp symbols at link time. This change remedies that.

Signed-off-by: Scott K Logan <logans@cottsay.net>
2022-03-22 15:53:08 -07:00
Andrea Sorbini
49c2dd4813 Update data callback tests to account for all published samples. (#1900)
* Update data callback tests to account for all published samples.

Signed-off-by: Andrea Sorbini <asorbini@rti.com>
2022-03-21 13:50:04 -07:00
Andrea Sorbini
6afec4805c Increase timeout for acknowledgments to account for slower Connext settings. (#1901)
Signed-off-by: Andrea Sorbini <asorbini@rti.com>
2022-03-21 10:29:08 -04:00
Hirokazu Ishida
9ae35e347e Select executor in node registration (#1898)
* Select executor

Signed-off-by: Hirokazu Ishida <h-ishida@jsk.imi.i.u-tokyo.ac.jp>

* Fix indent

Signed-off-by: Hirokazu Ishida <h-ishida@jsk.imi.i.u-tokyo.ac.jp>
2022-03-18 20:42:06 +00:00
William Woodall
0f58bb8700 clang-tidy: explicit constructors (#1782)
* mark some single-argument constructors explicit that should have been

Signed-off-by: William Woodall <william@osrfoundation.org>

* suppress clang-tidy [google-explicit-constructor] in some cases where it is a false-positive

Signed-off-by: William Woodall <william@osrfoundation.org>

* Revert "suppress clang-tidy [google-explicit-constructor] in some cases where it is a false-positive"

This reverts commit eb6bf7e2df0dd27c945e97584ba9902ef9f61305.

Signed-off-by: William Woodall <william@osrfoundation.org>
2022-03-16 13:58:49 -07:00
mauropasse
8b9cabfb9d Add client/service QoS getters (#1784)
Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

Co-authored-by: Mauro Passerino <mpasserino@irobot.com>
2022-03-16 18:05:58 +00:00
Chris Lalancette
2e39e09803 Fix a bunch more rosdoc2 issues in rclcpp. (#1897)
* Fix a bunch more rosdoc2 issues in rclcpp.

There are a smattering of problems in here:

1.  We weren't properly using PREDEFINE for all of our macros.
2.  The Doxyfiles were referencing tag files that may not exist
(this will be handled by rosdoc2 automatically).
3.  The C++ parser in doxygen can't handle "friend classname",
but can handle "friend class classname"; it shouldn't matter
one way or the other to the compiler.
4.  There were a couple of parameters that were not documented.
5.  The doxygen C++ parser can't handle decltype in all situations.
6.  There was a structure using a C-style declaration.

This patch fixes all of the above issues.  We still aren't totally
clean on a rosdoc2 build, but we are a lot closer.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2022-03-11 14:46:07 -05:00
mauropasse
91f0b64493 time_until_trigger returns max time if timer is cancelled (#1893)
* time_until_trigger returns max time if timer is cancelled

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>
2022-03-10 20:36:16 -08:00
Chris Lalancette
3bd6900f98 Micro-optimizations in rclcpp (#1896)
* Use a single call to collect all CallbackGroup pointers.

Believe it or not, the taking and releasing of mutex_ within
the CallbackGroup class shows up in profiles.  However, when
collecting entities we really don't need to take it and drop
it between each of subscriptions, services, clients, timers,
and waitables.  Just take it once at the beginning, collect
everything, and then return, which removes a lot of unnecessary
work with that mutex.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>

* Pass shared_ptr as constref in the MemoryStrategy class.

That way, in the case that the callee doesn't need to take
a reference, we avoid creating and destroying a shared_ptr
class.  This reduces the overhead in using these functions,
and seems to work fine in the default case.  If a user wants
to subclass the MemoryStrategy class, then they can explicitly
create a shared_ptr copy by using the copy constructor.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>

* Use constref shared_ptr when iterating.

Believe it or not, the creation and destruction of the
shared_ptr class itself shows up in profiles in these loops.
Since we don't need to hold onto a reference while iterating
(the class is already doing that), just use constref wherever
we can which drastically reduces the overhead.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2022-03-09 11:13:36 -08:00
Alberto Soragna
f2f7ffdf53 fix bugprone-exception-escape in node_main.cpp.in (#1895)
Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>
2022-03-08 19:55:06 +00:00
Chris Lalancette
16914e31a1 15.1.0 2022-03-01 19:33:31 +00:00
Chris Lalancette
4e3c6be76a Changelog.
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2022-03-01 19:33:22 +00:00
Tomoya Fujita
79241a3cdc spin_all with a zero timeout. (#1878)
* spin_all with a zero timeout.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2022-02-25 09:20:00 -08:00
Alberto Soragna
9c5ad79b63 Merge pull request #1889 from ros2/asoragna/improve-components-main
small improvements to node_main.cpp.in
2022-02-24 17:30:40 +00:00
iRobot ROS
d8e1aed520 Add RMW listener APIs (#1579)
* Add RMW listener APIs

Signed-off-by: Alberto Soragna <asoragna@irobot.com>

* split long log into two lines

Signed-off-by: Alberto Soragna <asoragna@irobot.com>

* Remove use_previous_event

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* Do not set gc listener callback

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* significant refactor to make callbacks type safe

Signed-off-by: William Woodall <william@osrfoundation.org>

* Add on_ready callback to waitables, add clear_* functions, add unit-tests

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* add mutex to set and clear listener APIs

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* allow to set ipc sub callback from regular subscription

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* fix minor failures

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* fix typos and errors in comments

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* fix comments

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* expose qos listener APIs from pub and sub; add unit-tests

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* add qos event unit-test for invalid callbacks

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* Use QoS depth to limit callbacks count

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* fix ipc-subscription

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* Rename CallbackMessageT -> ROSMessageType

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* Set callbacks to Actions

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* changes from upstream

Signed-off-by: William Woodall <william@osrfoundation.org>

* Unset callback on entities destruction

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* fix rebase errors

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* fix unit-tests

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* Add GuardCondition on trigger callback

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* Add tests for new GuardCondition APIs

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* Fix windows CI

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* Action unset callbacks only if were set

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* add missing include rcl event callback include directive

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* typos

Signed-off-by: William Woodall <william@osrfoundation.org>

* remove listener reference

Signed-off-by: William Woodall <william@osrfoundation.org>

* remove references to listener and move a method closer to impl

Signed-off-by: William Woodall <william@osrfoundation.org>

* cpplint

Signed-off-by: William Woodall <william@osrfoundation.org>

* Fix qos history check in subscription_intra_process.hpp

Co-authored-by: Mauro Passerino <mpasserino@irobot.com>
Co-authored-by: William Woodall <william@osrfoundation.org>
Co-authored-by: Alberto Soragna <alberto.soragna@gmail.com>
2022-02-24 00:32:17 -08:00
Miguel Company
c5a16dce11 Remove fastrtps customization on tests (#1887)
Signed-off-by: Miguel Company <MiguelCompany@eprosima.com>
2022-02-22 08:49:37 -05:00
Alberto Soragna
32c03dde2d small improvements to node_main.cpp.in
Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>
2022-02-19 11:57:10 +00:00
Shane Loretz
4f778199b4 Install headers to include/${PROJECT_NAME} (#1888)
* initial attempt, problems with ament_gen_version_h

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>

* remove blank line

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>
2022-02-16 09:41:21 -08:00
Shane Loretz
025cd5ccc8 Use ament_generate_version_header (#1886)
Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>
2022-02-15 13:02:23 -08:00
Tomoya Fujita
4c8cfa39f8 use universal reference to support rvalue. (#1883)
* use universal reference to support rvalue.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2022-02-10 09:58:36 -08:00
Chen Lihui
891fff0153 fix one subscription can wait_for_message twice (#1870)
Signed-off-by: Chen Lihui <lihui.chen@sony.com>
2022-02-10 08:44:14 -05:00
Alberto Soragna
43db06dad7 Use spin() in component_manager_isolated.hpp (#1881)
* replace spin_until_future_complete with spin in component_manager_isolated.hpp

spin_until_future_complete() is more inefficient as it needs to check the state of the future and the timeout after every work iteration

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* fix uncrustify error

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>
2022-02-09 11:45:39 -03:00
Tomoya Fujita
0d1747e066 LifecycleNode::on_deactivate deactivate all managed entities. (#1885)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2022-02-07 09:32:44 -08:00
Kenji Miyake
2520d398c7 Add return value version of get_parameter_or (#1813)
* Add return value version of get_parameter_or

* Add test case

Signed-off-by: Kenji Miyake <kenji.miyake@tier4.jp>
Co-authored-by: Abrar Rahman Protyasha <aprotyas@u.rochester.edu>
2022-02-04 09:23:17 -05:00
Alberto Soragna
d3c0049b24 Merge pull request #1871 from ros2/asoragna/executor-is-spinning
add is_spinning() method to executor base class
2022-01-21 08:43:04 +00:00
Chris Lalancette
c54a6f1cd2 Cleanup time source object lifetimes (#1867)
* Small cleanups in TimeSource.

Simplify some code, and also make sure to throw an exception
when use_sim_time is not of type bool.  Also add a test for
the latter.

* Remove the sim_time_cb_handler.

It was originally used to make sure that someone didn't change
the 'use_sim_time' type from boolean to something else.  But
since the parameters interface now does that automatically for
us, we don't need the explicit check here.

I can think of one situation that this allows that wasn't allowed
before.  If the user defined 'use_sim_time' as a parameter override
when constructing a node, and the type is bool, and they also
defined the parameters as 'dynamic_typing', then this callback
will still have effect.  But presumably if the user went out of
their way to change the parameter to dynamic_typing, they are
trying to do something esoteric and so we should just let them.

* ClocksState does not need to be a pointer.

Instead, make it a regular member variable.  That lets us get
rid of all of the special handling for when it is a weak_ptr
or not.  It's lifetime is now just that of NodeState.

* Stop using NodeState as a weak_ptr in the captures.

This ended up causing the lifetime of the object to be weird.
Instead, just capture 'this' which is sufficient.

* Make sure destroy_clock_sub is first.

* Switch to using just a regular object.

Windows objects to trying to do "make_shared" in the RCLCPP
macro, so just switch to a normal object here.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2022-01-20 16:30:55 -05:00
Alberto Soragna
9ec0393e63 add is_spinning() method to executor base class
Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>
2022-01-20 12:55:07 +00:00
gezp
bca3fd7da1 add use_global_arguments for node options of component nodes (#1776)
* add use_global_arguments for node options of component nodes

Signed-off-by: zhenpeng ge <zhenpeng.ge@qq.com>

keep use_global_arguments false default

Signed-off-by: zhenpeng ge <zhenpeng.ge@qq.com>

update warning message

Signed-off-by: zhenpeng ge <zhenpeng.ge@qq.com>

update warnning message

Signed-off-by: zhenpeng ge <zhenpeng.ge@qq.com>

add test

Signed-off-by: zhenpeng ge <zhenpeng.ge@qq.com>

* use forward_global_arguments instead of use_global_arguments

Signed-off-by: zhenpeng ge <zhenpeng.ge@qq.com>
2022-01-19 10:29:33 -03:00
Jacob Perron
8afef51cfd 15.0.0 2022-01-14 17:49:37 -08:00
Ivan Santiago Paunovic
3123f5a643 Automatically transition lifecycle entities when node transitions (#1863)
* Automatically transition LifecyclePublisher(s) between activated and inactive

Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>

* Fix: Add created publishers to the managed entities vector

Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>

* enabled_ -> activated_

Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>

* Continue setting should_log_ as before

Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>

* Fix visibility attributes so it works on Windows

Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2022-01-14 18:00:06 -03:00
Chris Lalancette
aa18ef51cc Cleanup the TypeAdapt tests (#1858)
* Cleanup test_publisher_with_type_adapter.

It had a lot of infrastructure that it didn't need, so remove
most of that.  Also move the creation of the node to open-coded,
since we weren't really saving anything.  Finally make sure
to reset the node pointers as appropriate, which cleans up
errant error messages.

* Cleanup test_subscription_with_type_adapter.

It had a lot of infrastructure that it didn't need, so remove
most of that.  Also move the creation of the node to open-coded,
since we weren't really saving anything.  Finally make sure
to reset the node pointers as appropriate, which cleans up
errant error messages.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2022-01-14 14:38:13 -05:00
Chris Lalancette
1688f05aea Cleanup includes. (#1857)
Remove ones that aren't needed, and add in ones that are
actually needed in the respective files.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2022-01-14 08:23:16 -05:00
Jacob Perron
80f93d1dbb Fix include order and relative paths for cpplint (#1859)
* Fix include order and relative paths for cpplint

Relates to https://github.com/ament/ament_lint/pull/324

Signed-off-by: Jacob Perron <jacob@openrobotics.org>

* Use double-quotes for other includes

This is backwards compatible with older versions of cpplint.

Signed-off-by: Jacob Perron <jacob@openrobotics.org>
2022-01-12 14:24:49 -08:00
Doug Smith
5e314c253e Rename stringstream in macros to a more unique name (#1862)
* Rename stringstream in macros to a more unique name

Signed-off-by: Doug Smith <douglas.smith@swri.org>
2022-01-11 17:52:52 -05:00
Gonzo
6b321edb4f Add non transform capabilities for intra-process (#1849)
That is, make it so that if both a publisher and a subscriber using intra-process
and using TypeAdaptation are the same type, we don't need to convert to
a ROS Message type on the publisher and from a ROS Message type before
delivering to the subscriber.  Instead, we store the original message type
in the subscription buffer, and deliver it straight through to the subscriber.

This has two main benefits:
1. It is better for performance; we are eliding unnecessary work.
2. We can use TypeAdaptation to pass custom handles (like hardware accelerator
    handles) between a publisher and subscriber.  That means we can avoid
    unnecessary overhead when using a hardware accelerator, like synchronizing
    between the hardware accelerator and the main CPU.

The main way this is accomplished is by causing the SubscriptionIntraProcessBuffer
to store messages of the Subscribed Type (which in the case of a ROS message type
subscriber is a ROS message type, but in the case of a TypeAdapter type is the
custom type).  When a publish with a Type Adapted type happens, it delays conversion
of the message, and passes the message type from the user down into the IntraProcessManager.

The IntraProcessManager checks to see if it can cast the SubscriptionBuffer
to the custom type being published first.  If it can, then it knows it can deliver the message directly
into the SubscriptionBuffer with no conversion necessary.  If it can't, it then sees if
the SubscriptionBuffer is of a ROS message type.  If it is, then it performs the conversion
as necessary, and then stores it.  In all cases, the Subscription is then triggered underneath
so that the message will eventually be delivered by an executor.

We also add tests to ensure that in the case where the publisher and subscriber
and using the same type adapter, no conversion happens when delivering the
message.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
Signed-off-by: Gonzalo de Pedro <gonzalo@depedro.com.ar>
2022-01-07 14:45:06 -05:00
Michel Hidalgo
8093648ee3 Fix rclcpp documentation build (#1779)
* Update Doxyfile
* Update docblocks with warnings
* Use leading * instead of trailing [] for pointer types
* Help Doxygen parse std::enable_if<> condition
* Add documentation-only SFINAE functions' declarations
* Avoid function pointer type syntax in function arguments.
* Add documentation-only SFINAE function traits.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
2022-01-07 09:36:11 -03:00
Shane Loretz
9583ec7855 Add rclcpp_components::component (#1855)
Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>
2022-01-06 14:31:17 -08:00
Chris Lalancette
2d6e6364cd 14.1.0 2022-01-05 10:40:02 -05:00
Chris Lalancette
5613d613cf Changelog.
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2022-01-05 10:39:54 -05:00
M. Mostafa Farzan
7a2ee23281 Use UninitializedStaticallyTypedParameterException (#1689)
* Use UninitializedStaticallyTypedParameterException

Signed-off-by: Mohammad Farzan <m2_farzan@yahoo.com>
Co-authored-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-12-23 22:28:46 -08:00
Barry Xu
802bfc2c74 Add wait_for_all_acked support (#1662)
* Add wait_for_all_acked support

Signed-off-by: Barry Xu <barry.xu@sony.com>

* Update the description of wait_for_all_acked

Signed-off-by: Barry Xu <barry.xu@sony.com>

* Use rcpputils::convert_to_nanoseconds() for time conversion

Signed-off-by: Barry Xu <barry.xu@sony.com>
2021-12-20 20:36:01 -08:00
Bi0T1N
152dbc6e38 Add tests for function templates of declare_parameter (#1747)
* Add function template tests for all defined types of declare_parameter

Signed-off-by: Nico Neumann <nico.neumann@iosb.fraunhofer.de>
2021-12-20 11:56:46 -08:00
Chris Lalancette
9342c257b8 14.0.0 2021-12-17 19:24:02 +00:00
Chris Lalancette
d2e563afd5 Changelog.
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2021-12-17 19:23:51 +00:00
Chris Lalancette
8ac848bbc2 Fixes for uncrustify 0.72 (#1844)
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2021-12-17 13:23:44 -05:00
Tomoya Fujita
b2b676d317 use private member to keep the all reference underneath. (#1845)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2021-12-14 16:01:34 -08:00
Daisuke Nishimatsu
ee20dd31e6 Add parameter to configure number of thread (#1708)
* Add parameter to configure number of thread

Signed-off-by: wep21 <border_goldenmarket@yahoo.co.jp>
2021-12-13 09:40:16 -08:00
gezp
0775e2f6e7 remove RCLCPP_COMPONENTS_PUBLIC in class ComponentManagerIsolated (#1843)
Signed-off-by: zhenpeng ge <zhenpeng.ge@qq.com>
2021-12-09 09:41:47 -05:00
gezp
321c74c2b3 create component_container_isolated (#1781)
Signed-off-by: zhenpeng ge <zhenpeng.ge@qq.com>
2021-12-07 14:24:53 -03:00
Chen Lihui
536df11ee0 Make node base sharable (#1832)
Signed-off-by: Chen Lihui <lihui.chen@sony.com>
2021-12-06 16:32:08 -03:00
Shane Loretz
6f6e9e8ce9 Add Clock::sleep_for() (#1828)
Signed-off-by: Shane Loretz <sloretz@openrobotics.org>
2021-11-30 14:02:32 -08:00
Shane Loretz
39dad4d9a7 Synchronize rcl and std::chrono steady clocks in Clock::sleep_until (#1830)
* Synchronize RCL and std::chrono steady clocks

Signed-off-by: Shane Loretz <sloretz@openrobotics.org>

* Warn about gcc steady clock bugs

Signed-off-by: Shane Loretz <sloretz@openrobotics.org>

* Try to make warning message clearer

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>
2021-11-30 10:37:52 -08:00
mauropasse
87d754b219 Use rclcpp::guard_condition (#1612)
* Use rclcpp::GuardCondition

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* Pass GuardCondition ptr instead of ref to remove_guard_condition

Before the api was taking a reference to a guard condition,
then getting the address of it. But if a node had expired,
we can't get the orig gc dereferencing a pointer,
nor can we get an address of an out-of-scope guard condition.

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* Address PR comments

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

Co-authored-by: Mauro Passerino <mpasserino@irobot.com>
2021-11-29 12:58:47 -08:00
Abrar Rahman Protyasha
e03e98220d Call CMake function to generate version header (#1805)
Provides compile-time version information for `rclcpp`.

Signed-off-by: Abrar Rahman Protyasha <aprotyas@u.rochester.edu>
2021-11-12 16:53:52 -05:00
Abrar Rahman Protyasha
f7bb88fc8f Use parantheses around logging macro parameter (#1820)
* Use parantheses around logging macro parameter

This allows the macro to expand "correctly", i.e. macro argument
expression is fully evaluated before use.

Signed-off-by: Abrar Rahman Protyasha <aprotyas@u.rochester.edu>

* Remove redundant parantheses around macro param

`decltype(X)` already provides sufficient "scoping" to the macro
parameter `X`.

Signed-off-by: Abrar Rahman Protyasha <aprotyas@u.rochester.edu>

* Add test case for expressions as logging param

Signed-off-by: Abrar Rahman Protyasha <aprotyas@u.rochester.edu>
2021-11-11 02:12:47 -05:00
Jacob Perron
0781ea543c Remove author by request (#1818)
Signed-off-by: Jacob Perron <jacob@openrobotics.org>
2021-11-08 23:51:05 -08:00
Jacob Perron
e0e96681d9 Update maintainers (#1817)
Adding Jacob, removing Mabel.

Signed-off-by: Jacob Perron <jacob@openrobotics.org>
2021-11-05 13:40:08 -07:00
Shane Loretz
b1f31e0eaa min_forward & min_backward thresholds must not be disabled (#1815)
Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>
2021-11-05 08:24:58 -07:00
Shane Loretz
e2aeb1028b Re-add Clock::sleep_until (#1814)
* Revert "Revert "Add Clock::sleep_until method (#1748)" (#1793)"

This reverts commit d04319a438.

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>

* Context, Shutdown Callback, Condition Var per call

The `Clock` doesn't have enough information to know which Context should
wake it on shutdown, so this adds a Context as an argument to
sleep_until().

Since the context is per call, the shutdown callback is also registered
per call and cannot be stored on impl_.

The condition_variable is also unique per call to reduce spurious
wakeups when multiple threads sleep on the same clock.

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>

* Throw if until has wrong clock type

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>

* unnecessary newline

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>

* Shorten line

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>

* Fix time jump thresholds and add ROS time test

Use -1 and 1 thresholds because 0 and 0 is supposed to disable the
callbacks

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>

* Shorten line

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>

* rclcpp::ok() -> context->is_valid()

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>

* No pre-jump handler instead of noop handler

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>

* If ros_time_is_active errors, let it throw

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>

* Get time source change from callback to avoid race if ROS time toggled quickly

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>

* Fix threshold and no  pre-jump callback

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>

* Use RCUTILS_MS_TO_NS macro

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>

* Explicit cast for duration to system time

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>

* Throws at the end of docblock

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>

* Add tests for invalid and non-global contexts

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>
2021-11-05 08:24:30 -07:00
Grey
94264320b4 Fix lifetime of context so it remains alive while its dependent node handles are still in use (#1754)
* Fix lifetime of context so it remains alive while its dependent node handles are still in use

Signed-off-by: Michael X. Grey <grey@openrobotics.org>

* Explicitly delete moving and assigning

Signed-off-by: Michael X. Grey <grey@openrobotics.org>

* Satisfy uncrustify

Signed-off-by: Michael X. Grey <grey@openrobotics.org>

* Fix more spacing complaints

Signed-off-by: Michael X. Grey <grey@openrobotics.org>

* Fixing style

Signed-off-by: Michael X. Grey <grey@openrobotics.org>

* Provide a safe move constructor to avoid double-allocation

Signed-off-by: Michael X. Grey <grey@openrobotics.org>

* Fix uncrustify

Signed-off-by: Michael X. Grey <grey@openrobotics.org>
2021-11-01 12:29:03 -07:00
Barry Xu
b135e89c1e Add the interface for pre-shutdown callback (#1714)
* Add the interface for pre-shutdown callback

Signed-off-by: Barry Xu <barry.xu@sony.com>
2021-10-29 17:11:39 -07:00
Abrar Rahman Protyasha
c59793618a Take message ownership from moved LoanedMessage (#1808)
* Take message ownership from moved LoanedMessage

Otherwise, since the rvalue reference passed into the move
constructor of `LoanedMessage` was not set to `nullptr`, the
underlying message would be double-free'd.

Signed-off-by: Abrar Rahman Protyasha <aprotyas@u.rochester.edu>

* Add unit test for LoanedMessage move construction

Signed-off-by: Abrar Rahman Protyasha <aprotyas@u.rochester.edu>

* Include <utility> header to satisfy cpplint

`std::move` was being used without including said header,
which made cpplint unhappy.

Signed-off-by: Abrar Rahman Protyasha <aprotyas@u.rochester.edu>
2021-10-25 14:27:12 -04:00
Chris Lalancette
5ecc5b6c19 Suppress clang dead-store warnings in the benchmarks. (#1802)
clang static analysis complains that there are dead stores in
most of the benchmark tests, which is technically correct.
We use an idiom like:

for (auto _ : state) {
}

And never access _.  Silence clang here by doing (void)_;
all of the places this is seen.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2021-10-22 11:27:54 -04:00
Jacob Perron
2d7bd9f4cb Wait for publisher and subscription to match (#1777)
Fix #1775

Connext takes significantly longer for discovery to happened compared to the other RMWs.
So, waiting an arbitrary amount of time for a message to be received is brittle.

By instead waiting for the publisher and subscription to match, the tests become more robust.

Signed-off-by: Jacob Perron <jacob@openrobotics.org>
2021-10-20 08:32:43 -07:00
Nikolai Morin
0fd866d201 Fix unused QoS profile for clock subscription and make ClockQoS the default (#1801)
Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>
2021-10-19 08:49:54 -07:00
Ivan Santiago Paunovic
82950f1141 13.1.0 2021-10-18 19:26:36 +00:00
Ivan Santiago Paunovic
4a343a1f23 Changelogs
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-10-18 15:10:16 -03:00
Geoffrey Biggs
a569214273 Fix dangerous std::bind capture in TimeSource implementation (#1768)
* Convert internal state into shareable structs
* Add documentation
* PIMPL the class
* Use a weak_ptr to avoid a potential dangling reference
* Comply with the rule of 5

Signed-off-by: Geoffrey Biggs <gbiggs@killbots.net>
2021-10-15 11:52:41 -04:00
Geoffrey Biggs
942b74c8bd Fix dangerous std::bind capture in ParameterEventHandler implementation (#1770)
Signed-off-by: Geoffrey Biggs <gbiggs@killbots.net>
2021-10-13 11:36:19 -03:00
Ivan Santiago Paunovic
d107a844ea Handle sigterm, in the same way we handle sigint (#1771)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-10-13 10:05:12 -03:00
Tomoya Fujita
301957515a add node_waitables_ to copy constructor. (#1799)
* add node_waitables_ to copy constructor.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* add node_time_source_ to copy constructor.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* add construction_and_destruction_sub_node for action server.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

Co-authored-by: Abrar Rahman Protyasha <abrar@openrobotics.org>
2021-10-12 18:50:00 -07:00
Jorge Perez
d04319a438 Revert "Add Clock::sleep_until method (#1748)" (#1793)
This reverts commit 81df5843f3.

Signed-off-by: Jorge Perez <jjperez@ekumenlabs.com>
2021-10-05 12:14:35 -03:00
Tomoya Fujita
d5ec258080 typo fix. (#1790)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2021-09-29 15:24:19 -04:00
Michel Hidalgo
9e445bdb91 Update forward declarations of rcl_lifecycle types (#1788)
* Include rcl_lifecycle and drop forward declarations

Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
2021-09-29 10:30:51 -04:00
William Woodall
fa3a6fa597 fixup some small things that cppcheck noticed in my editor (#1783)
* fixup some small things that cppcheck noticed in my editor

Signed-off-by: William Woodall <william@osrfoundation.org>

* fix implementation too

Signed-off-by: William Woodall <william@osrfoundation.org>
2021-09-24 15:22:17 -07:00
Emerson Knapp
81df5843f3 Add Clock::sleep_until method (#1748)
* Add Clock::sleep_until method

Handle all 3 clock types, and edge cases for shutdown and enabling/disabling ROS time

Signed-off-by: Emerson Knapp <eknapp@amazon.com>
2021-09-24 15:15:23 -04:00
Tomoya Fujita
f3a5187775 NodeGraph exposure with test cases (#1484)
* add NodeGraph::get_node_names_and_namespaces()

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>

* add test for NodeGraph::get_node_names_and_namespaces

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>

* add NodeGraph::get_client_names_and_types_by_node()

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>

* add test for NodeGraph::get_client_names_and_types_by_node

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>

* add NodeGraph::get_publisher/subscriber_names_and_types_by_node()

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>

* add test for NodeGraph::get_publisher/subscriber_names_and_types_by_node

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>

* fix comments.

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>

* use make_scope_exit and update comments.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* comment fix.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* minor fixes.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* add comments for enclaves.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* add URL about ROS 2 Security Enclaves.

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* Deprecated `shared_ptr<MessageT>` sub callbacks

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2021-09-23 13:45:58 -07:00
livanov93
2801553d61 Improve documentation for auto declaration from overrides (#1751)
* Improve documentation for auto declaration from overrides.

Signed-off-by: voodoo <lovro.ivanov@gmail.com>

* Fix spelling.

Signed-off-by: voodoo <lovro.ivanov@gmail.com>

* Extend description.

Signed-off-by: voodoo <lovro.ivanov@gmail.com>
2021-09-13 17:36:11 -07:00
Yong-Hao Zou
001f0fb620 Replace recursion with do-while (#1765)
to avoid potential stack-overflow.

Signed-off-by: zouyonghao <yonghaoz1994@gmail.com>
2021-09-13 09:25:06 -04:00
Chris Lalancette
665e37784a Make sure to check for empty extension before accessing front. (#1764)
The documentation for std::string::front() says that calling it
on an empty string is undefined behavior.  It actually seems to
work on all platforms except Windows Debug, where it throws an
error.  Make sure to check for empty first.

We also notice that there is no reason to check the
existing_sub_namespace for empty; the rest of the code handles
that fine.  So remove that check.

Finally, we add an anonymous namespace so that these functions do
not pollute the global namespace.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2021-09-03 08:49:57 -04:00
Abrar Rahman Protyasha
ecb81ef2c3 Deprecate the void shared_ptr<MessageT> subscription callback signatures (#1713)
* Deprecated `shared_ptr<MessageT>` sub callbacks

Addresses #1619.

Signed-off-by: Abrar Rahman Protyasha <abrar@openrobotics.org>

* Resolve deprecated subscription callbacks in tests

Specifically, `void shared_ptr<MessageT>` subscription callbacks have
been migrated to `void shared_ptr<const MessageT>` subscription
callbacks.

This change has been performed only on the test files that do
not actually house unit tests for the `AnySubscriptionCallback` class.
For unit tests that actually target the deprecated `set` functions,
the deprecation warnings have to be avoided. This patch will be
introduced in a separate commit.

Signed-off-by: Abrar Rahman Protyasha <abrar@openrobotics.org>

* Suppress deprecation warnings in unit tests

This commit specifically introduces suppression of the deprecation
warnings produced while compiling unit tests for the
`AnySubscriptionCallback` class.

The macro mechanics to conditionally include the `deprecated` attribute
is not ideal, but the diagnostic pragma solution (`# pragma GCC
diagnostic ignored`) did not work for these unit tests, possibly because
of the way gtest is initializing the necessary `InstanceContext`
objects.

A `TODO` directive has been left to figure out a better way to address
this warning suppression.

Signed-off-by: Abrar Rahman Protyasha <abrar@openrobotics.org>

* Fix shared ptr callback in wait_for_message

Moving away from deprecated signatures.

Signed-off-by: Abrar Rahman Protyasha <abrar@openrobotics.org>

* `rclcpp_action`: Fix deprecated subscr. callbacks

Signed-off-by: Abrar Rahman Protyasha <abrar@openrobotics.org>

* `rclcpp_lifecycle`: Fix deprecated sub callbacks

Signed-off-by: Abrar Rahman Protyasha <abrar@openrobotics.org>
2021-08-26 18:33:03 -04:00
Ivan Santiago Paunovic
d0cd6bb0a4 13.0.0 2021-08-23 17:46:42 +00:00
Ivan Santiago Paunovic
fd08f0dbe7 Changelogs
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-08-23 17:45:06 +00:00
Ahmed Sobhy
2dd09ae274 remove can_be_nullptr assignment check for QNX case (#1752)
Signed-off-by: Ahmed Sobhy <asobhy@blackberry.com>
2021-08-23 11:19:05 -03:00
Ivan Santiago Paunovic
679fb2ba33 Update client API to be able to remove pending requests (#1734)
* Revert "Revert "Updating client API to be able to remove pending requests (#1728)" (#1733)"

This reverts commit d5f3d35fbe.

Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>

* Address peer review comments

Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>

* Fix tests in rclcpp_components, rclcpp_lifecycle

Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-08-23 09:57:18 -03:00
Alberto Soragna
4fcd05db72 Change log level for lifecycle_publisher (#1715)
* Change log level for lifecycle_publisher

De-activating a lifecycle publisher while the function that was invoking `publish` is still running floods the log of useless warning messages.
This requires to add a boolean check around the publish call, thus making useless the choice of a lifecycle publisher

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* change lifecycle publisher to log warning only once per transition

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* rework lifecycle publisher log mechanism to use an helper function

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

* change doxygen format to use implicit brief

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>

Co-authored-by: Alberto Soragna <asoragna@irobot.com>
2021-08-19 10:59:57 -07:00
Mauro Passerino
d7764b4322 Fix bug: Add node while spinning
Signed-off-by: Mauro Passerino <mpasserino@irobot.com>
2021-08-18 08:09:58 -07:00
Christophe Bedard
893b9b4f82 Add tracing instrumentation for executor and message taking (#1738)
* Add tracing instrumentation for executor and message taking

Signed-off-by: Christophe Bedard <bedard.christophe@gmail.com>

* Move publisher handle argument to rcl_publish tracepoint

Signed-off-by: Christophe Bedard <bedard.christophe@gmail.com>

* Keep publisher handle arg for rclcpp_publish tracepoint but use nullptr

Signed-off-by: Christophe Bedard <bedard.christophe@gmail.com>
2021-08-12 12:48:35 -07:00
mauropasse
b918bd4c25 Reset timer trigger time before execute. (#1739)
This PR fixes an issue with StaticSingleThreadedExecutor
not reseting the timers, so they were always ready
and executing callbacks continuosly.

https://github.com/ros2/rclcpp/pull/1692

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>
2021-08-09 10:25:04 -03:00
Shane Loretz
3b1144f1e0 Use FindPython3 and make python3 dependency explicit (#1745)
* Use FindPython3 and make python3 dependency explicit

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>

* Need CMake 3.12 for FindPython3

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>
2021-08-06 12:08:50 -07:00
Shane Loretz
6c0a46bcc8 Use rosidl_get_typesupport_target() (#1729)
Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>
2021-08-04 16:08:47 -07:00
M. Hofstätter
3cddb4edab Fix returning invalid namespace if sub_namespace is empty (#1658)
* Create valid effective namespace when sub-namespace is empty

Fix #1656.

Signed-off-by: Markus Hofstaetter <markus.hofstaetter@ait.ac.at>

* Add regression test for effective namespace and empty sub-namespace

Adds regression test for #1656.

Signed-off-by: Markus Hofstaetter <markus.hofstaetter@ait.ac.at>
2021-08-04 08:02:51 -07:00
Ivan Santiago Paunovic
d5f3d35fbe Revert "Updating client API to be able to remove pending requests (#1728)" (#1733)
This reverts commit bf752c75f5.

Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-07-29 11:37:57 -03:00
Ivan Santiago Paunovic
bf752c75f5 Updating client API to be able to remove pending requests (#1728)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-07-29 11:35:06 -03:00
Shane Loretz
01f6ebdd3d RCLCPP_PUBLIC -> RCLCPP_LIFECYCLE_PUBLIC (#1732)
Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>
2021-07-28 15:18:31 -07:00
Karsten Knese
7bf52dd8a6 wait for message (#1705)
* wait for message

Signed-off-by: Karsten Knese <Karsten1987@users.noreply.github.com>

* move to own header file

Signed-off-by: Karsten Knese <Karsten1987@users.noreply.github.com>

* linters

Signed-off-by: Karsten Knese <Karsten1987@users.noreply.github.com>

* add gc for shutdown interrupt

Signed-off-by: Karsten Knese <Karsten1987@users.noreply.github.com>

* mention behavior when shutdown is called

Signed-off-by: Karsten Knese <Karsten1987@users.noreply.github.com>

* check gc

Signed-off-by: Karsten Knese <Karsten1987@users.noreply.github.com>
2021-07-27 23:05:36 -07:00
Christophe Bedard
1b28f389c2 Use rcpputils/scope_exit.hpp and remove rclcpp/scope_exit.hpp (#1727)
* Use rcpputils/scope_exit.hpp and remove rclcpp/scope_exit.hpp

Signed-off-by: Christophe Bedard <bedard.christophe@gmail.com>

* Remove RCLCPP_STRING_JOIN() since it's unused & also provided by rcutils

Signed-off-by: Christophe Bedard <bedard.christophe@gmail.com>

* Revert "Remove RCLCPP_STRING_JOIN() since it's unused & also provided by rcutils"

This reverts commit 072dabd470.

Signed-off-by: Christophe Bedard <bedard.christophe@gmail.com>

* Re-add but deprecate rclcpp/scope_exit.hpp

Signed-off-by: Christophe Bedard <bedard.christophe@gmail.com>
2021-07-26 16:31:42 -07:00
Aditya Pande
e8cbfe6a1b 12.0.0 2021-07-26 14:07:39 -07:00
Aditya Pande
0c01a43a4f Updated CHANGELOG.rst
Signed-off-by: Aditya Pande <aditya050995@gmail.com>
2021-07-26 14:04:29 -07:00
Chris Lalancette
133088e9a3 Remove unsafe get_callback_groups API.
Callers should change to using for_each_callback_group(), or
store the callback groups they need internally.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2021-07-23 16:55:13 -04:00
Chris Lalancette
3d42c9a5df 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().

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2021-07-23 16:55:13 -04:00
Ivan Santiago Paunovic
5c4f809f2a Use a different mechanism to avoid timers being scheduled multiple times by the MultiThreadedExecutor (#1692)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-07-23 10:41:26 -03:00
Ivan Santiago Paunovic
f7a301441a Fix windows CI (#1726)
Fix bug in AnyServiceCallback introduced in #1709.

Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-07-22 18:48:08 -03:00
Ivan Santiago Paunovic
00f2d563be 11.2.0 2021-07-21 16:52:06 +00:00
Ivan Santiago Paunovic
64ee7d6822 Changelogs
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-07-21 13:37:47 -03:00
Ivan Santiago Paunovic
0750dc418a Support to defer to send a response in services (#1709)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-07-21 13:32:38 -03:00
Rebecca Butler
0d6d9e6778 Deprecate method names that use CamelCase in rclcpp_components (#1716)
* Rename methods in ComponentManager to use snake_case

Signed-off-by: Rebecca Butler <rebecca@openrobotics.org>

* Deprecate old method names

Signed-off-by: Rebecca Butler <rebecca@openrobotics.org>
2021-07-19 13:42:12 -04:00
William Woodall
86c079de31 fix documentation bug (#1719)
Signed-off-by: William Woodall <william@osrfoundation.org>
2021-07-16 13:41:34 -07:00
William Woodall
fb8519070c 11.1.0 2021-07-13 14:35:59 -05:00
William Woodall
e1095adeee changelogs
Signed-off-by: William Woodall <william@osrfoundation.org>
2021-07-13 14:35:45 -05:00
William Woodall
4ecb3dd090 remove left over is_initialized() implementation (#1711)
Leftover from https://github.com/ros2/rclcpp/pull/1622

Signed-off-by: William Woodall <william@osrfoundation.org>
2021-07-12 19:19:01 -07:00
Chen Lihui
0034929eef to support declare parameter with int and float vector (#1696)
* to support declare parameter with int vector

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* update for float vector

Signed-off-by: Chen Lihui <lihui.chen@sony.com>
2021-07-07 08:33:56 -07:00
Rebecca Butler
dbb717cd6e Add hook to generate node options in ComponentManager (#1702)
* Add domain bridge container and `domain` argument for components

Signed-off-by: Rebecca Butler <rebecca@openrobotics.org>

* Fix linter errors

Signed-off-by: Rebecca Butler <rebecca@openrobotics.org>

* Move domain_bridge_container to domain_bridge package

Signed-off-by: Rebecca Butler <rebecca@openrobotics.org>

* Remove domain id argument and add getters/setters to ComponentManager

Signed-off-by: Rebecca Butler <rebecca@openrobotics.org>

* Add SetNodeOptions function

Signed-off-by: Rebecca Butler <rebecca@openrobotics.org>

* Rename SetNodeOptions -> CreateNodeOptions and refactor

Signed-off-by: Rebecca Butler <rebecca@openrobotics.org>
2021-07-07 08:46:20 -04:00
Alberto Soragna
e9e398d2d4 cleanup intra-process-manager (#1695)
Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>
2021-06-23 12:21:26 -07:00
Steve Macenski
7d8b2690ff adding node name to the executor runtime_error (#1686)
* adding node name to the executor runtime_error

Signed-off-by: Steve Macenski <stevenmacenski@gmail.com>

* changing get_name() to get_fully_qualified_name() + linting

Signed-off-by: Steve Macenski <stevenmacenski@gmail.com>

* changing print format for tests

Signed-off-by: Steve Macenski <stevenmacenski@gmail.com>
2021-06-06 09:07:10 +09:00
Chris Lalancette
55d2f67b90 Change the word "Attack" -> "Attach". (#1687)
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2021-06-04 09:48:25 -04:00
Petter Nilsson
39bfb30eb0 Remove use of std::allocator<>::rebind (#1678)
rebind is deprecated in c++17 and removed in c++20

Signed-off-by: Petter Nilsson <pettni@umich.edu>
2021-05-26 19:40:45 -07:00
Kaven Yau
1c61751540 Fix occasionally missing goal result caused by race condition (#1677)
* Fix occasionally missing goal result caused by race condition

Signed-off-by: Kaven Yau <kavenyau@foxmail.com>

* Take action_server_reentrant_mutex_ out of the sending result loop

Signed-off-by: Kaven Yau <kavenyau@foxmail.com>

* add note for explaining the current locking order in server.cpp

Signed-off-by: Kaven Yau <kavenyau@foxmail.com>
2021-05-20 17:15:59 -03:00
Jacob Perron
0251f70fe8 11.0.0 2021-05-18 18:00:56 -07:00
Jacob Perron
07b6ea0ff4 Declare parameters uninitialized (#1673)
* Declare parameters uninitialized

Fixes #1649

Allow declaring parameters without an initial value or override.
This was possible prior to Galactic, but was made impossible since we started enforcing the types of parameters in Galactic.

Signed-off-by: Jacob Perron <jacob@openrobotics.org>

* Remove assertion

Signed-off-by: Jacob Perron <jacob@openrobotics.org>

* Throw NoParameterOverrideProvided exception if accessed before initialized

Signed-off-by: Jacob Perron <jacob@openrobotics.org>

* Add test getting static parameter after it is set

Signed-off-by: Jacob Perron <jacob@openrobotics.org>

* Do not throw on access of uninitialized dynamically typed parameter

Signed-off-by: Jacob Perron <jacob@openrobotics.org>

* Rename exception type

Signed-off-by: Jacob Perron <jacob@openrobotics.org>

* Remove unused exception type

Signed-off-by: Jacob Perron <jacob@openrobotics.org>

* Uncrustify

Signed-off-by: Jacob Perron <jacob@openrobotics.org>
2021-05-18 17:55:48 -07:00
Scott K Logan
56f68f9c44 Fix destruction order in lifecycle benchmark (#1675)
Signed-off-by: Scott K Logan <logans@cottsay.net>
2021-05-14 21:28:55 -07:00
William Woodall
18fcd9138b fix syntax issue with gcc (#1674)
* fix syntax issue with gcc

Signed-off-by: William Woodall <william@osrfoundation.org>

* uncrustify

Signed-off-by: William Woodall <william@osrfoundation.org>
2021-05-14 18:33:10 -07:00
Scott K Logan
f245b4cc81 Bump the benchmark timeout for benchmark_action_client (#1671)
Pausing and resuming the measurement inside the timing loop can cause
the initial run duration calculation to underestimate how long the
benchmark is taking to run, which results in the recorded run taking a
lot longer than it should. This is a known issue in libbenchmark.

This test is affected by that behavior, and typically takes a bit longer
than the others. The easiest thing to do right now is to just bump the
timeout. My tests show that 180 seconds is typically sufficient for this
test, so 240 should be a safe point to conclude that the test is
malfunctioning.

Signed-off-by: Scott K Logan <logans@cottsay.net>
2021-05-13 12:10:19 -07:00
Ivan Santiago Paunovic
d488535f36 [service] Don't use a weak_ptr to avoid leaking (#1668)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-05-13 12:13:07 -03:00
Chris Lalancette
72443ff295 10.0.0 2021-05-11 15:12:49 +00:00
Chris Lalancette
a3383c309a Changelog.
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2021-05-11 15:12:40 +00:00
Jacob Perron
5dad229662 Fix doc typo (#1663)
Signed-off-by: Jacob Perron <jacob@openrobotics.org>
2021-05-10 12:45:34 -07:00
William Woodall
2e4c97ac56 [rclcpp] Type Adaptation feature (#1557)
* initial version of type_adaptor.hpp

Signed-off-by: William Woodall <william@osrfoundation.org>

* initial version of rclcpp::get_message_type_support_handle()

Signed-off-by: William Woodall <william@osrfoundation.org>

* initial version of rclcpp::is_ros_compatible_type check

Signed-off-by: William Woodall <william@osrfoundation.org>

* fixup include statement order in publisher.hpp

Signed-off-by: William Woodall <william@osrfoundation.org>

* use new rclcpp::get_message_type_support_handle() and check in Publisher

Signed-off-by: William Woodall <william@osrfoundation.org>

* update adaptor->adapter, update TypeAdapter to use two arguments, add implicit default

Signed-off-by: William Woodall <william@osrfoundation.org>

* move away from shared_ptr<allocator> to just allocator, like the STL

Signed-off-by: William Woodall <william@osrfoundation.org>

* fixes to TypeAdapter and adding new publish function signatures

Signed-off-by: William Woodall <william@osrfoundation.org>

* bugfixes

Signed-off-by: William Woodall <william@osrfoundation.org>

* more bugfixes

Signed-off-by: William Woodall <william@osrfoundation.org>

* Add nullptr check

Signed-off-by: Audrow Nash <audrow@hey.com>

* Remove public from struct inheritance

Signed-off-by: Audrow Nash <audrow@hey.com>

* Add tests for publisher with type adapter

Signed-off-by: Audrow Nash <audrow@hey.com>

* Update packages to C++17

Signed-off-by: Audrow Nash <audrow@hey.com>

* Revert "Update packages to C++17"

This reverts commit 4585605223639bbd9d18053e5ef39725638512b4.

Signed-off-by: William Woodall <william@osrfoundation.org>

* Begin updating AnySubscriptionCallback to use the TypeAdapter

Signed-off-by: Audrow Nash <audrow@hey.com>

* Use type adapter's custom type

Signed-off-by: Audrow Nash <audrow@hey.com>

* Correct which AnySubscriptionCallbackHelper is selected

Signed-off-by: Audrow Nash <audrow@hey.com>

* Setup dispatch function to work with adapted types

Signed-off-by: Audrow Nash <audrow@hey.com>

* Improve template logic on dispatch methods

Signed-off-by: Audrow Nash <audrow@hey.com>

* implement TypeAdapter for Subscription

Signed-off-by: William Woodall <william@osrfoundation.org>

* Add intraprocess tests with all supported message types

Signed-off-by: Audrow Nash <audrow@hey.com>

* Add intra process tests

Signed-off-by: Audrow Nash <audrow@hey.com>

* Add tests for subscription with type adapter

Signed-off-by: Audrow Nash <audrow@hey.com>

* Fix null allocator test

Signed-off-by: Audrow Nash <audrow@hey.com>

* Handle serialized message correctly

Signed-off-by: Audrow Nash <audrow@hey.com>

* Fix generic subscription

Signed-off-by: Audrow Nash <audrow@hey.com>

* Fix trailing space

Signed-off-by: Audrow Nash <audrow@hey.com>

* fix some issues found while testing type_adapter in demos

Signed-off-by: William Woodall <william@osrfoundation.org>

* add more tests, WIP

Signed-off-by: William Woodall <william@osrfoundation.org>

* Improve pub/sub tests

Signed-off-by: Audrow Nash <audrow@hey.com>

* Apply uncrustify formatting

Signed-off-by: Audrow Nash <audrow@hey.com>

* finish new tests for any subscription callback with type adapter

Signed-off-by: William Woodall <william@osrfoundation.org>

* fix adapt_type<...>::as<...> syntax

Signed-off-by: William Woodall <william@osrfoundation.org>

* fix explicit template instantiation of create_subscription() in new test

Signed-off-by: William Woodall <william@osrfoundation.org>

* cpplint fix

Signed-off-by: William Woodall <william@osrfoundation.org>

* Fix bug by aligning allocator types on both sides of ipm

Signed-off-by: Audrow Nash <audrow@hey.com>

* Fix intra process manager tests

Signed-off-by: Audrow Nash <audrow@hey.com>

Co-authored-by: Audrow Nash <audrow@hey.com>
2021-05-06 21:33:06 -07:00
Michel Hidalgo
0659d829ce Do not attempt to use void allocators for memory allocation. (#1657)
Keep a rebound allocator for byte-sized memory blocks around
for publisher and subscription options.

Follow-up after 1fc2d58799

Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
2021-05-05 13:17:42 -07:00
Michel Hidalgo
1fc2d58799 Keep custom allocator in publisher and subscription options alive. (#1647)
* Keep custom allocator in publisher and subscription options alive.

Also, enforce an allocator bound to void is used to avoid surprises.

Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>

* Avoid sizeof(void) in MyAllocator implementation.

Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>

* Address peer review comment

Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>

* Use a lazely initialized private field when 'allocator' is not initialized

Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>

Co-authored-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-05-04 15:45:15 -07:00
Michel Hidalgo
c15eb1eaac Fix get_publishers_subscriptions_info_by_topic test in test_node.cpp (#1648)
* Wait on graph guard condition for graph changes to propagate

Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
2021-05-03 15:46:25 -03:00
Kaven Yau
d051b8aa20 Returns CancelResponse::REJECT while goal handle failed to transit to CANCELING state (#1641)
Signed-off-by: Kaven Yau <kavenyau@foxmail.com>
2021-04-30 17:56:38 -03:00
Barry Xu
6806cdf825 Use OnShutdown callback handle instead of OnShutdown callback (#1639)
1. Add remove_on_shutdown_callback() in rclcpp::Context

Signed-off-by: Barry Xu <barry.xu@sony.com>

2. Add add_on_shutdown_callback(), which returns a handle that can be removed by remove_on_shutdown_callback().

Signed-off-by: Barry Xu <barry.xu@sony.com>
2021-04-30 14:53:19 -03:00
William Woodall
79c2dd8e8b use dynamic_pointer_cast to detect allocator mismatch in intra process manager (#1643)
* use dynamic_pointer_cast to detect allocator mismatch in intra process manager

Signed-off-by: William Woodall <william@osrfoundation.org>

* add test case for mismatched allocators

Signed-off-by: William Woodall <william@osrfoundation.org>

* forward template arguments to avoid mismatched types in intra process manager

Signed-off-by: William Woodall <william@osrfoundation.org>

* style fixes

Signed-off-by: William Woodall <william@osrfoundation.org>

* refactor to test message address and count, more DRY

Signed-off-by: William Woodall <william@osrfoundation.org>

* update copyright

Signed-off-by: William Woodall <william@osrfoundation.org>

* fix typo

Signed-off-by: William Woodall <william@osrfoundation.org>

Co-authored-by: Michel Hidalgo <michel@ekumenlabs.com>

Co-authored-by: Michel Hidalgo <michel@ekumenlabs.com>
2021-04-29 10:56:16 -07:00
Kaven Yau
fba080cf34 Fix action server deadlock issue that caused by other mutexes locked in CancelCallback (#1635)
* Fix deadlock issue that caused by other mutexes locked in CancelCallback

Signed-off-by: Kaven Yau <love29881460@qq.com>

* Add unit test for rclcpp action server deadlock

Signed-off-by: Kaven Yau <love29881460@qq.com>

* Update rclcpp_action/test/test_server.cpp

Co-authored-by: William Woodall <william+github@osrfoundation.org>

Co-authored-by: Kaven Yau <love29881460@qq.com>
Co-authored-by: Jacob Perron <jacob@openrobotics.org>
Co-authored-by: William Woodall <william+github@osrfoundation.org>
2021-04-25 16:32:30 +09:00
Shane Loretz
bff6916e8f Increase cppcheck timeout to 500s (#1634)
Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>
2021-04-21 11:58:05 -07:00
Jacob Perron
b8df9347a1 Clarify node parameters docs (#1631)
Set and initialize seem redundant.
Update the doc brief to match the equivalent in node.hpp.

Signed-off-by: Jacob Perron <jacob@openrobotics.org>
2021-04-15 10:47:13 -07:00
Chris Lalancette
ec70642c55 9.0.2 2021-04-14 20:05:19 +00:00
Chris Lalancette
14aba06922 Changelog.
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2021-04-14 20:05:13 +00:00
Miguel Company
1c2bd84725 Avoid returning loan when none was obtained. (#1629)
Signed-off-by: Miguel Company <MiguelCompany@eprosima.com>
2021-04-13 20:53:02 -04:00
Ivan Santiago Paunovic
c4a68b4199 Use a different implementation of mutex two priorities (#1628)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-04-13 17:36:15 -03:00
Ivan Santiago Paunovic
085f161230 Do not test the value of the history policy when testing the get_publishers/subscriptions_info_by_topic() methods (#1626)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-04-13 11:26:22 -03:00
Ivan Santiago Paunovic
893679e44f Check first parameter type and range before calling the user validation callbacks (#1627)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-04-13 09:32:06 -03:00
Chris Lalancette
a62287bf8d 9.0.1 2021-04-12 18:05:27 +00:00
Chris Lalancette
98ab933a73 Changelog.
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2021-04-12 18:05:17 +00:00
Andrea Sorbini
a9c6521466 Restore test exception for Connext (#1625)
Signed-off-by: Andrea Sorbini <asorbini@rti.com>
2021-04-09 18:01:20 -03:00
Michel Hidalgo
41fedb7beb Fix race condition in TimeSource clock thread setup (#1623)
Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
2021-04-07 12:33:21 -03:00
Chris Lalancette
98fc7fecc2 9.0.0 2021-04-06 13:59:00 +00:00
Chris Lalancette
f9f90e0226 Changelog.
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2021-04-06 13:58:50 +00:00
William Woodall
61fcc766f8 remove deprecated code which was deprecated in foxy and should be removed in galactic (#1622)
Signed-off-by: William Woodall <william@osrfoundation.org>
2021-04-05 22:32:20 -07:00
Chris Lalancette
091a8bcf86 Change index.ros.org -> docs.ros.org. (#1620)
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2021-04-05 14:07:58 -04:00
Ananya Muddukrishna
6af478d0ba Unique network flows (#1496)
* Add option to enable unique network flow

- Option enabled for publishers and subscriptions
- TODO: Discuss error handling if not supported

Signed-off-by: Ananya Muddukrishna <ananya.x.muddukrishna@ericsson.com>

* Get network flows of publishers and subscriptions

Signed-off-by: Ananya Muddukrishna <ananya.x.muddukrishna@ericsson.com>

* Use new unique network flow option

Signed-off-by: Ananya Muddukrishna <ananya.x.muddukrishna@ericsson.com>

* Rename files for clarity

Signed-off-by: Ananya Muddukrishna <ananya.x.muddukrishna@ericsson.com>

* Rename API for clarity and add DSCP option

Signed-off-by: Ananya Muddukrishna <ananya.x.muddukrishna@ericsson.com>

* Convert integer to string prior to streaming

Signed-off-by: Ananya Muddukrishna <ananya.x.muddukrishna@ericsson.com>

* Uncrustify

Signed-off-by: Ananya Muddukrishna <ananya.x.muddukrishna@ericsson.com>

* Fix linkage error thrown by MSVC compiler

Signed-off-by: Ananya Muddukrishna <ananya.x.muddukrishna@ericsson.com>

* Use updated rmw interface

Signed-off-by: Ananya Muddukrishna <ananya.x.muddukrishna@ericsson.com>

* Improve readability

Signed-off-by: Ananya Muddukrishna <ananya.x.muddukrishna@ericsson.com>

* Forward declare friend functions

Signed-off-by: Ananya Muddukrishna <ananya.x.muddukrishna@ericsson.com>

Co-authored-by: Ananya Muddukrishna <ananya.x.muddukrishna@ericsson.com>
2021-04-05 10:16:46 -07:00
mauropasse
06a4ee01d4 Add spin_some support to the StaticSingleThreadedExecutor (#1338)
* spin_some/spin_all/spin_once support: static executor

Signed-off-by: Mauro <mpasserino@irobot.com>

* Use spin_once instead of spin_once_impl

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* Fix memory leak

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* revert spinSome change

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

* Override spin_once_impl only

This way the StaticSingleThreadedExecutor uses spin_once and
spin_until_future_complete APIs from the base executor class,
but uses its own overrided version of spin_once_impl.

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>

Co-authored-by: Mauro <mpasserino@irobot.com>
2021-04-04 18:53:55 -07:00
Christophe Bedard
7b94f288e5 Add publishing instrumentation (#1600)
Signed-off-by: Christophe Bedard <bedard.christophe@gmail.com>
2021-04-04 15:19:34 -07:00
BriceRenaudeau
7226725d2f Create load_parameters and delete_parameters methods (#1596)
* Create delete_parameters method

Signed-off-by: Brice <brice.renaudeau@wyca.fr>

* cleaner way to delete

Signed-off-by: Brice <brice.renaudeau@wyca.fr>

* add delete_parameters TEST

Signed-off-by: Brice <brice.renaudeau@wyca.fr>

* fix uncrustify

Signed-off-by: Brice <brice.renaudeau@wyca.fr>

* create load_parameter method

Signed-off-by: Brice <brice.renaudeau@wyca.fr>

* create load_parameters TEST

Signed-off-by: Brice <brice.renaudeau@wyca.fr>

* add comments

Signed-off-by: Brice <brice.renaudeau@wyca.fr>

* fix exceptions

Signed-off-by: Brice <brice.renaudeau@wyca.fr>

* fix const auto

Signed-off-by: Brice <brice.renaudeau@wyca.fr>

* fix param node check

Signed-off-by: Brice <brice.renaudeau@wyca.fr>

* Change TEST to use remote_node_name_

Signed-off-by: Brice <brice.renaudeau@wyca.fr>

* change comment style

Signed-off-by: Brice <brice.renaudeau@wyca.fr>

* parameter_map_from_yaml_file

Signed-off-by: Brice <brice.renaudeau@wyca.fr>

* Fix comments

Signed-off-by: Brice <brice.renaudeau@wyca.fr>

* fix sign-compare warning

Signed-off-by: Brice <brice.renaudeau@wyca.fr>

* use c style

Signed-off-by: Brice <brice.renaudeau@wyca.fr>
2021-04-03 23:22:01 -07:00
William Woodall
1037822a63 refactor AnySubscriptionCallback and add/deprecate callback signatures (#1598)
* refactor AnySubscriptionCallback to...

use std::variant and make the dispatch functions constexpr,
avoiding runtime dispatching.

Also, deprecate the std::function<void (std::shared_ptr<MessageT>)> signature,
as it is unsafe to share one shared_ptr when multiple subscriptions take it,
because they could mutate MessageT while others are using it. So you'd have to
make a copy for each subscription, which is no different than the
std::unique_ptr<MessageT> signature or the user making their own copy in a
shared_ptr from the const MessageT & signature or the
std::shared_ptr<const MessageT> signature.

Added a std::function<void (const std::shared_ptr<const MessageT> &)> signature
to go along side the existing
std::function<void (std::shared_ptr<const MessageT>)> signature.

Removed redundant 'const' before pass-by-value signatures, e.g.
std::function<void (const shared_ptr<const MessageT>)> became
std::function<void (shared_ptr<const MessageT>)>.
This will not affect API or any users using the old style.

Signed-off-by: William Woodall <william@osrfoundation.org>

* fix use of std::bind, free functions, etc. using new function_traits::as_std_function<>

Signed-off-by: William Woodall <william@osrfoundation.org>

* fix use of const MessageT & callbacks by fixing subscriptin_traits

Signed-off-by: William Woodall <william@osrfoundation.org>

* fix deprecation warnings

Signed-off-by: William Woodall <william@osrfoundation.org>

* use target_compile_features to require c++17 for downstream users of rclcpp

Signed-off-by: William Woodall <william@osrfoundation.org>

* uncrustify

Signed-off-by: William Woodall <william@osrfoundation.org>

* cpplint

Signed-off-by: William Woodall <william@osrfoundation.org>

* use target_compile_features(... cxx_std_17)

Signed-off-by: William Woodall <william@osrfoundation.org>

* Keep both std::shared_ptr<const MessageT> and const std::shared_ptr<const MessageT> & signatures.

The const std::shared_ptr<const MessageT> & signature is being kept because it
can be more flexible and efficient than std::shared_ptr<const MessageT>, but
costs realtively little to support.

The std::shared_ptr<const MessageT> signature is being kept because we want to
avoid deprecating it and causing disruption, and because it is convenient to
write, and in most cases will not materially impact the performance.

Signed-off-by: William Woodall <william@osrfoundation.org>

* defer deprecation of the shared_ptr<MessageT> sub callbacks

Signed-off-by: William Woodall <william@osrfoundation.org>

* fix unused variable warning

Signed-off-by: William Woodall <william@osrfoundation.org>

* small fixups to AnySubscriptionCallback

Signed-off-by: William Woodall <william@osrfoundation.org>

* add check for unset AnySubscriptionCallback in dispatch methods

Signed-off-by: William Woodall <william@osrfoundation.org>

* update dispatch methods to handle all scenarios

Signed-off-by: William Woodall <william@osrfoundation.org>

* updated tests for AnySubscriptionCallback, include full parameterized i/o matrix

Signed-off-by: William Woodall <william@osrfoundation.org>

* fixup test with changed assumption

Signed-off-by: William Woodall <william@osrfoundation.org>

* remove use of std::unary_function, which was removed in c++17

Signed-off-by: William Woodall <william@osrfoundation.org>

* silence c++17 warnings on windows for now

Signed-off-by: William Woodall <william@osrfoundation.org>
2021-04-02 17:30:29 -07:00
Nikolai Morin
95adde2a19 Add generic publisher and generic subscription for serialized messages (#1452)
* Copying files from rosbag2

The generic_* files are from rosbag2_transport
typesupport_helpers incl. test is from rosbag2_cpp
memory_management.hpp is from rosbag2_test_common
test_pubsub.cpp was renamed from test_rosbag2_node.cpp from rosbag2_transport

Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Rebrand into rclcpp_generic

Add package.xml, CMakeLists.txt, Doxyfile, README.md and CHANGELOG.rst
Rename namespaces
Make GenericPublisher and GenericSubscription self-contained by storing shared library
New create() methods that return shared pointers
Add docstrings
Include only what is needed
Make linters & tests pass

Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Review feedback

* Delete CHANGELOG.rst
* Enable cppcheck
* Remove all references to rosbag2/ros2bag

Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Move rclpp_generic into rclcpp

Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Rename namespace rclcpp_generic to rclcpp::generic

Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Free 'create' functions instead of static functions in class

Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Remove 'generic' subdirectory and namespace hierarchy

Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Order includes according to style guide

Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Remove extra README.md

Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Also add brief to class docs

Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Make ament_index_cpp a build_depend

Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Add to rclcpp.hpp

Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Remove memory_management, use rclcpp::SerializedMessage in GenericPublisher::publish

Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Clean up the typesupport_helpers

Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Use make_shared, add UnimplementedError

Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Add more comments, make member variable private, remove unnecessary include

Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Apply suggestions from code review

Co-authored-by: William Woodall <william+github@osrfoundation.org>
Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Rename test

Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Update copyright and remove ament_target_dependencies for test

Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Accept PublisherOptions and SubscriptionOptions

Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Remove target_include_directories

Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Add explanatory comment to SubscriptionBase

Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Use kSolibPrefix and kSolibExtension from rcpputils

Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Fix downstream build failure by making ament_index_cpp a build_export_depend

Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Use path_for_library(), fix documentation nitpicks

Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Improve error handling in get_typesupport_handle

Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Accept SubscriptionOptions in GenericSubscription

Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Make use of PublisherOptions in GenericPublisher

Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Document typesupport_helpers

Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Improve documentation

Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Use std::function instead of function pointer

Co-authored-by: William Woodall <william+github@osrfoundation.org>
Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Minimize vertical whitespace

Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Add TODO for callback with message info

Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Link issue in TODO

Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Add missing include for functional

Signed-off-by: nnmm <nnmmgit@gmail.com>

* Fix compilation

Signed-off-by: Jacob Perron <jacob@openrobotics.org>

* Fix lint

Signed-off-by: Jacob Perron <jacob@openrobotics.org>

* Address review comments (#1)

* fix redefinition of default template arguments

Signed-off-by: Karsten Knese <Karsten1987@users.noreply.github.com>

* address review comments

Signed-off-by: Karsten Knese <Karsten1987@users.noreply.github.com>

* rename test executable

Signed-off-by: Karsten Knese <Karsten1987@users.noreply.github.com>

* add functionality to lifecycle nodes

Signed-off-by: Karsten Knese <Karsten1987@users.noreply.github.com>

* Refactor typesupport helpers

* Make extract_type_identifier function private
* Remove unused extract_type_and_package function
* Update unit tests

Signed-off-by: Jacob Perron <jacob@openrobotics.org>

* Remove note about ament from classes

This comment only applies to the free functions.

Signed-off-by: Jacob Perron <jacob@openrobotics.org>

* Fix formatting

Co-authored-by: Karsten Knese <Karsten1987@users.noreply.github.com>

* Fix warning

Possible loss of data from double to rcutils_duration_value_t

Signed-off-by: Jacob Perron <jacob@openrobotics.org>

* Add missing visibility macros

Signed-off-by: Jacob Perron <jacob@openrobotics.org>

Co-authored-by: William Woodall <william+github@osrfoundation.org>
Co-authored-by: Jacob Perron <jacob@openrobotics.org>
Co-authored-by: Karsten Knese <Karsten1987@users.noreply.github.com>
2021-04-02 17:01:47 -07:00
Tomoya Fujita
cd3fd53c8c use context from node_base_ for clock executor. (#1617)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2021-04-02 15:59:34 -07:00
shonigmann
70dfa2e778 updating quality declaration links (re: ros2/docs.ros2.org#52) (#1615)
Signed-off-by: Simon Honigmann <shonigmann@blueorigin.com>

Co-authored-by: Simon Honigmann <shonigmann@blueorigin.com>
2021-04-02 08:39:08 +02:00
Chris Lalancette
e7e3504fcf 8.2.0 2021-03-31 14:57:27 +00:00
Chris Lalancette
474720511e Changelog.
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2021-03-31 14:57:16 +00:00
Ivan Santiago Paunovic
51a4b2155e Initialize integers in test_parameter_event_handler.cpp to avoid undefined behavior (#1609)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-03-31 10:58:37 -03:00
Christophe Bedard
aa3a65d3ff Namespace tracetools C++ functions (#1608)
Signed-off-by: Christophe Bedard <bedard.christophe@gmail.com>
2021-03-30 21:51:57 -07:00
Jacob Perron
f986ca3edc Fix flaky lifecycle node tests (#1606)
Apparently, the topics and services that LifecycleNode provides are not
available immediately after creating a node.

Fix flaky tests by accounting for some delay between the LifecycleNode
constructor and queries about its topics and services.

Signed-off-by: Jacob Perron <jacob@openrobotics.org>
2021-03-30 14:42:49 -07:00
Chris Lalancette
2562f715ab Revert "Namespace tracetools C++ functions (#1603)" (#1607)
This reverts commit 3ab6571593.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2021-03-30 08:58:32 -04:00
Christophe Bedard
3ab6571593 Namespace tracetools C++ functions (#1603)
Signed-off-by: Christophe Bedard <bedard.christophe@gmail.com>
2021-03-30 12:55:44 +09:00
anaelle-sw
bc8c71b63f Clock subscription callback group spins in its own thread (#1556)
* Clock subscription callback group spins in its own thread

Signed-off-by: anaelle-sw <anaelle.sarazin@wyca.fr>

* fix line length

Signed-off-by: anaelle-sw <anaelle.sarazin@wyca.fr>

* fix code style divergence

Signed-off-by: anaelle-sw <anaelle.sarazin@wyca.fr>

* fix code style divergence

Signed-off-by: anaelle-sw <anaelle.sarazin@wyca.fr>

* Initialize only once clock_callbackgroup

Signed-off-by: anaelle-sw <anaelle.sarazin@wyca.fr>

* Check if thread joinable before start a new thread

Signed-off-by: anaelle-sw <anaelle.sarazin@wyca.fr>

* Cancel executor and join thread in destroy_clock_sub

Signed-off-by: anaelle-sw <anaelle.sarazin@wyca.fr>

* Check if clock_thread_ is joinable before cancel executor and join

Signed-off-by: anaelle-sw <anaelle.sarazin@wyca.fr>

* Add use_clock_thread as an option

Signed-off-by: anaelle-sw <anaelle.sarazin@wyca.fr>

* Fix code style divergence

Signed-off-by: anaelle-sw <anaelle.sarazin@wyca.fr>

* Fix code style divergence

Signed-off-by: anaelle-sw <anaelle.sarazin@wyca.fr>

* Fix code style divergence

Signed-off-by: anaelle-sw <anaelle.sarazin@wyca.fr>

* Add TimeSource tests

Signed-off-by: anaelle-sw <anaelle.sarazin@wyca.fr>

* update use_clock_thread value in function attachNode

Signed-off-by: anaelle <anaelle.sarazin@wyca.fr>

* join clock thread in function detachNode

Signed-off-by: anaelle <anaelle.sarazin@wyca.fr>

* TimeSource tests: fixes + comments + more tested cases

Signed-off-by: anaelle <anaelle.sarazin@wyca.fr>

* clean destroy_clock_sub()

Signed-off-by: anaelle <anaelle.sarazin@wyca.fr>

* flag to ensure clock_executor is cancelled

Signed-off-by: anaelle <anaelle.sarazin@wyca.fr>

* Always re-init clock_callback_group when creating a new clock sub

Signed-off-by: anaelle <anaelle.sarazin@wyca.fr>

* spin_until_future_complete() to cleanly cancel executor

Signed-off-by: anaelle <anaelle.sarazin@wyca.fr>

* fix tests warnings

Signed-off-by: anaelle <anaelle.sarazin@wyca.fr>

* fix test error: cancel clock executor

Signed-off-by: anaelle <anaelle.sarazin@wyca.fr>

* clean comments

Signed-off-by: anaelle <anaelle.sarazin@wyca.fr>

* fix precision loss

Signed-off-by: anaelle <anaelle.sarazin@wyca.fr>
2021-03-30 07:45:19 +09:00
Ivan Santiago Paunovic
63e79223f9 Delete debug messages (#1602)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-03-29 10:58:51 -03:00
BriceRenaudeau
92ece94ca3 add automatically_add_executor_with_node option (#1594)
* add automatically_add_executor_with_node option

Signed-off-by: Brice <brice.renaudeau@wyca.fr>

* Fix typo

Signed-off-by: Brice <brice.renaudeau@wyca.fr>

* add option usage in test

Signed-off-by: Brice <brice.renaudeau@wyca.fr>

* Document parameter

Signed-off-by: Brice <brice.renaudeau@wyca.fr>
2021-03-25 14:10:59 -07:00
Chris Lalancette
a7ec7d9243 8.1.0 2021-03-25 21:06:58 +00:00
Chris Lalancette
06a4a56017 Changelog.
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2021-03-25 21:06:26 +00:00
Chris Lalancette
98a62f6a18 Remove rmw_connext_cpp references. (#1595)
* Remove rmw_connext_cpp references.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
Co-authored-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-03-25 14:49:12 -04:00
Jacob Perron
dbb4c354d6 Add API for checking QoS profile compatibility (#1554)
* Add API for checking QoS profile compatibility

Depends on https://github.com/ros2/rmw/pull/299

Signed-off-by: Jacob Perron <jacob@openrobotics.org>

* Refactor as free function

Returns a struct containing the compatibility enum value and string for the reason.

Updated tests to reflect behavior changes upstream.

Signed-off-by: Jacob Perron <jacob@openrobotics.org>
2021-03-25 08:21:47 -07:00
Jacob Perron
0088e35052 Document misuse of parameters callback (#1590)
* Document misuse of parameters callback

Related to https://github.com/ros2/rclcpp/issues/1587

Signed-off-by: Jacob Perron <jacob@openrobotics.org>

* Remove bad example

Signed-off-by: Jacob Perron <jacob@openrobotics.org>
2021-03-24 08:37:29 -07:00
Karsten Knese
3fa511a8a0 use const auto & to iterate over parameters (#1593)
Clang is complaining about the looping variable being referenced as `const val` but should rather be `const ref`.

```
/Users/karsten/workspace/ros2/ros2_master/src/ros2/rclcpp/rclcpp/src/rclcpp/parameter_service.cpp:46:25: error: loop variable 'param' of type 'const rclcpp::Parameter' creates a copy from type 'const rclcpp::Parameter' [-Werror,-Wrange-loop-construct]
        for (const auto param : parameters) {
                        ^
/Users/karsten/workspace/ros2/ros2_master/src/ros2/rclcpp/rclcpp/src/rclcpp/parameter_service.cpp:46:14: note: use reference type 'const rclcpp::Parameter &' to prevent copying
        for (const auto param : parameters) {
             ^~~~~~~~~~~~~~~~~~
                        &
1 error generated.
```

Signed-off-by: Karsten Knese <Karsten1987@users.noreply.github.com>
2021-03-23 16:31:46 -07:00
Chris Lalancette
763c56481f 8.0.0 2021-03-23 21:16:22 +00:00
Chris Lalancette
63fdf82ebf Changelog.
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2021-03-23 21:16:14 +00:00
Karsten Knese
052596c971 make rcl_lifecyle_com_interface optional in lifecycle nodes (#1507)
* make rcl_com_interface optional

Signed-off-by: Karsten Knese <Karsten1987@users.noreply.github.com>

* Update rclcpp_lifecycle/test/mocking_utils/patch.hpp

Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>

* line break

Signed-off-by: Karsten Knese <Karsten1987@users.noreply.github.com>

* use state_machine_options

Signed-off-by: Karsten Knese <Karsten1987@users.noreply.github.com>

Co-authored-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2021-03-23 11:26:35 -07:00
Jacob Perron
182ad3860e Guard against integer overflow in duration conversion (#1584)
Guard against overflow when converting from rclcpp::Duration to builtin_interfaces::msg::Duration,
which is a unsigned to signed conversion.

Use non-std int types for consistency

Handle large negative values

Signed-off-by: Jacob Perron <jacob@openrobotics.org>
2021-03-22 15:29:38 -07:00
Ivan Santiago Paunovic
59ad83ab5a 7.0.1 2021-03-22 14:20:25 +00:00
Ivan Santiago Paunovic
cae3836ca0 Changelogs
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-03-22 14:20:03 +00:00
Tomoya Fujita
75051616f1 get_parameters_service_ should return empty if allow_undeclared_ is false (#1514)
Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>
2021-03-22 10:54:27 -03:00
suab321321
f5afe380d5 Made 'Context::shutdown_reason' function a const function (#1578)
Signed-off-by: Abhinav Singh <singhabhinav9051571833@gmail.com>
2021-03-19 15:53:01 -07:00
Scott K Logan
7bfda87d32 7.0.0
Signed-off-by: Scott K Logan <logans@cottsay.net>
2021-03-18 15:49:39 -07:00
Ivan Santiago Paunovic
e33105057c Document design decisions that were made for statically typed parameters (#1568)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-03-18 11:13:48 -03:00
Jacob Perron
736550cace Fix doc typo in CallbackGroup constructor (#1582)
Signed-off-by: Jacob Perron <jacob@openrobotics.org>
2021-03-17 17:00:18 -07:00
Ivan Santiago Paunovic
35c89c8afc Enable qos parameter overrides for the /parameter_events topic (#1532)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-03-12 13:07:12 -03:00
Andrea Sorbini
37ee1ff309 Add support for rmw_connextdds (#1574)
* Replace stale reference to Connext

* Restore exceptions for ros2/rmw_connext to ease transition to rticommunity/rmw_connextdds

Signed-off-by: Andrea Sorbini <asorbini@rti.com>
Co-authored-by: Chris Lalancette <clalancette@gmail.com>
2021-03-11 09:17:25 -05:00
Chris Lalancette
d01a577f87 Remove 'struct' from the rcl_time_jump_t. (#1577)
It is redundant.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2021-03-10 15:55:14 -05:00
Steven! Ragnarök
6cc89caa63 Re-apply #829: Add ParameterEventsSubscriber class (#1573)
Also add the following fixes for CI:

* Fix symbol visibility error on Windows
* Remove an unused parameter to quiet a clang-tidy warning on MacOS

Signed-off-by: Michael Jeronimo <michael.jeronimo@openrobotics.org>
2021-03-09 09:05:30 -08:00
Ivan Santiago Paunovic
c767f0b4c4 Add tests for declaring statically typed parameters when undeclared parameters are allowed (#1575)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-03-09 11:57:00 -03:00
Chris Lalancette
13312dc6ed Quiet clang memory leak warning on "DoNotOptimize". (#1571)
When building rclcpp under clang static analysis, it complains
that the "DoNotOptimize" function from Google benchmark can
cause a memory leak.  I can't see how this is possible, so I
can only assume that the inline assembly that is used to implement
"DoNotOptimize" is causing a false positive.  Just quite the
warning here when building under clang static analysis.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2021-03-05 15:20:18 -05:00
Steven! Ragnarök
e11986bbdb Revert "Add ParameterEventsSubscriber class (#829)" (#1572)
This reverts commit c8713edbe4.
2021-03-04 16:15:31 -08:00
bpwilcox
c8713edbe4 Add ParameterEventsSubscriber class (#829)
* add ParameterEventsSubscriber class and tests

Signed-off-by: bpwilcox <bpwilcox@eng.ucsd.edu>

* test improvements, path name fixes, and more documentation

Signed-off-by: bpwilcox <bpwilcox@eng.ucsd.edu>

* fix lint and uncrustify issues

Signed-off-by: bpwilcox <bpwilcox@eng.ucsd.edu>

* add try-catch and warning around getting parameter value

Signed-off-by: bpwilcox <bpwilcox@eng.ucsd.edu>

* pass rclcpp::Parameter object to callback, rename functions, get param from event

Signed-off-by: bpwilcox <bpwilcox@eng.ucsd.edu>

* use unordered map with string pair, add test for different nodes same parameter, address feedback

Signed-off-by: bpwilcox <bpwilcox@eng.ucsd.edu>

* address feedback (wjwwood) part 1

Signed-off-by: bpwilcox <bpwilcox@eng.ucsd.edu>

use const string & for node name

Signed-off-by: bpwilcox <bpwilcox@eng.ucsd.edu>

* add RCLCPP_PUBLIC macro

Signed-off-by: bpwilcox <bpwilcox@eng.ucsd.edu>

* address feedback part 1: static get_parameter method, remove register_parameter_update, mutex for thread-safety

Signed-off-by: bpwilcox <bpwilcox@eng.ucsd.edu>

* map parameters to list of callbacks

functions to remove parameter callbacks

add functions to remove event callbacks, remove subscriptions, allow subscribing event callback to many namespaces, additional test coverage

Signed-off-by: bpwilcox <bpwilcox@eng.ucsd.edu>

* use absolute parameter event topic for parameter event subscriber

Signed-off-by: bpwilcox <bpwilcox@eng.ucsd.edu>

* support multiple parameter event callbacks

Signed-off-by: bpwilcox <bpwilcox@eng.ucsd.edu>

* use get_child for parameter event subscriber logger

Signed-off-by: bpwilcox <bpwilcox@eng.ucsd.edu>

* update utility function description

Signed-off-by: bpwilcox <bpwilcox@eng.ucsd.edu>

* address feedback: move HandleCompare, test exceptions, reference code source

Signed-off-by: bpwilcox <bpwilcox@eng.ucsd.edu>

* address feedback: replace ParameterEventsFilter dependency, fix copyright, add get_node_logging_interface, modify constructor

Signed-off-by: bpwilcox <bpwilcox@eng.ucsd.edu>

* Get rid of a few compiler warnings; add test to build

Signed-off-by: Michael Jeronimo <michael.jeronimo@openrobotics.org>

* Remove some unneeded code

Signed-off-by: Michael Jeronimo <michael.jeronimo@openrobotics.org>

* Remove a stray debug trace

Signed-off-by: Michael Jeronimo <michael.jeronimo@openrobotics.org>

* Add a function to get all parameter values from a parameter event

Signed-off-by: Michael Jeronimo <michael.jeronimo@openrobotics.org>

* Address code review feedback

Signed-off-by: Michael Jeronimo <michael.jeronimo@openrobotics.org>

* Another name change; using Handler instead of the more passive term, Monitor

Signed-off-by: Michael Jeronimo <michael.jeronimo@openrobotics.org>

* Pass SharedPtrs callback remove functions instead of bare pointers

Per William's review feedback.

Signed-off-by: Michael Jeronimo <michael.jeronimo@openrobotics.org>

* Add a comment block describing usage

Signed-off-by: Michael Jeronimo <michael.jeronimo@openrobotics.org>

* Address review feedback

* Remove unused interfaces
* Document LIFO order for invoking callbacks
* Add test cases to verify LIFO order for callbacks

Signed-off-by: Michael Jeronimo <michael.jeronimo@openrobotics.org>

* A couple more doc fixes from review comments

Signed-off-by: Michael Jeronimo <michael.jeronimo@openrobotics.org>

Co-authored-by: Michael Jeronimo <michael.jeronimo@openrobotics.org>
2021-03-04 08:47:51 -08:00
Ivan Santiago Paunovic
5a832e4db0 When a parameter change is rejected, the parameters map shouldn't be updated.
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-03-03 10:56:27 -03:00
Ivan Santiago Paunovic
267786207b * Fix when to throw the NoParameterOverrideProvided exception.
* Throw an exception when declaring a parameter of a specific type and passing a descriptor with dynamic typing enabled.

Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-03-03 10:56:27 -03:00
Colin MacKenzie
b9ffd72f42 Fix SEGV caused by order of destruction of Node sub-interfaces (#1469)
* added tear-down of node sub-interfaces in reverse order of their creation (#1469)

Signed-off-by: Colin MacKenzie <colin@flyingeinstein.com>

* added name of service to log message for leak detection. Previously it gave no indication of what node is causing the memory leak (#1469)

Signed-off-by: Colin MacKenzie <colin@flyingeinstein.com>
2021-03-02 10:27:50 -03:00
Tomoya Fujita
dc7e95aaa5 node_handle must be destroyed after client_handle to prevent memory leak (#1562)
Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>
2021-02-26 08:12:03 +09:00
Ivan Santiago Paunovic
ee7080d95d Fix benchmark test failure introduced in #1522 (#1564)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-02-25 17:28:59 -03:00
Jacob Perron
b9fb9bda3d Fix documented example in create_publisher (#1558)
Signed-off-by: Jacob Perron <jacob@openrobotics.org>
2021-02-24 09:55:33 -08:00
Ivan Santiago Paunovic
24bb65305d Enforce static parameter types (#1522)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-02-23 10:29:30 -03:00
Ivan Santiago Paunovic
ab743392e4 Allow timers to keep up the intended rate in MultiThreadedExecutor (#1516)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-02-17 16:24:18 -03:00
Chris Lalancette
18b112fcce Fix UBSAN warnings in any_subscription_callback. (#1551)
When running the rclcpp tests under UBSAN, it complained that
the AnySubscriptionCallback tests were using an uninitialized
allocator.

Reviewing the code there, it also looks like the AnySubscriptionCallback
constructor wasn't checking for a null allocator.

Fix this by doing 3 things:

1.  Add a check for a null allocator in the AnySubscriptionCallback
constructor.
2.  Add a new test to test_any_subscription_callback that tests the new
nullptr handling.
3.  Fix the test fixture to initialize the allocator before trying to
call the AnySubscriptionCallback constructor.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2021-02-12 12:56:12 -05:00
tomoya
09950ba23f Fix runtime error: reference binding to null pointer of type (#1547)
* Fix runtime error: reference binding to null pointer of type

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>

* delete cppcheck v1.89 workaround

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>
2021-02-10 14:30:53 +09:00
Scott K Logan
377fc4f076 6.3.1 2021-02-08 10:33:36 -08:00
Scott K Logan
c2a75f0b5b Reference test resources directly from source tree (#1543)
The CMake 'install' command should never be used to copy content from
the source tree to the build directory like this. The destination
directory is affected by the 'DESTDIR' variable on UNIX platforms, which
will get prefixed onto the destination directory and we'll end up
installing the test resources into the target install space.

This change will eliminate the excess test collateral present in the
rclcpp deb packages being installed to '/tmp/binarydeb'.

Signed-off-by: Scott K Logan <logans@cottsay.net>
2021-02-08 09:55:55 -08:00
hsgwa
bce19675a2 clear statistics after window reset (#1531) (#1535)
* clear statistics after window reset (#1531)

Signed-off-by: hsgwa <hasegawa@isp.co.jp>

* move ClearCurrentMeasurements just after GetStatisticsResults

Signed-off-by: hsgwa <hasegawa@isp.co.jp>

* refactor publish_message to publish_and_reset_message

Signed-off-by: hsgwa <hasegawa@isp.co.jp>

* rename function name

Signed-off-by: hsgwa <hasegawa@isp.co.jp>

* rename function name

Signed-off-by: hsgwa <hasegawa@isp.co.jp>

* add unit test to check window reset

Signed-off-by: hsgwa <hasegawa@isp.co.jp>

* pass measured == offset case

Signed-off-by: hsgwa <hasegawa@isp.co.jp>

* modify comment

Signed-off-by: hsgwa <hasegawa@isp.co.jp>

* add received message size test

Signed-off-by: hsgwa <hasegawa@isp.co.jp>

* rename test parameter names

Signed-off-by: hsgwa <hasegawa@isp.co.jp>

* set statistics collector's collection period explicitly to defaultStatisticsPublishPeriod

Signed-off-by: Miaofei <miaofei@amazon.com>

Co-authored-by: Miaofei <miaofei@amazon.com>
2021-02-05 12:55:18 -08:00
Chris Lalancette
5d6e48c800 Fix a minor string error in the topic_statistics test. (#1541)
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2021-02-03 21:27:53 -05:00
Chen Lihui
7c984f1a4c Avoid Resource deadlock avoided if use intra_process_comms (#1530)
Co-authored-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-02-03 09:40:32 +08:00
Chris Lalancette
9bf0f8374e Avoid an object copy in parameter_value.cpp. (#1538)
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2021-02-02 15:34:07 -05:00
Chris Lalancette
1c92e6d609 Assert that the publisher_list size is 1. (#1537)
If we just EXPECT it, then we continue running tests below
and eventually dereference an empty list.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2021-02-01 18:24:54 -05:00
Chris Lalancette
490e12ea86 Don't access objects after they have been std::move (#1536)
According to the documentation at
https://en.cppreference.com/w/cpp/utility/move,
the "moved-from" objects are "in a valid but unspecified
state" after the move.  Thus, we shouldn't assume anything
about them, since it could be implementation-defined behavior.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2021-02-01 18:16:38 -05:00
Chen Lihui
900be20a5a Update for checking correct variable (#1534)
Signed-off-by: Chen Lihui <Lihui.Chen@sony.com>
2021-01-29 18:13:46 -03:00
y-okumura-isp
963b5bbea3 Finalize rcl_handle to prevent leak (#1528) (#1529)
Signed-off-by: y-okumura-isp <y-okumura@isp.co.jp>
2021-01-27 13:50:51 -05:00
Chen Lihui
a2fc45f955 Destroy msg extracted from LoanedMessage. (#1305)
* Destroy msg extracted from LoanedMessage.

Signed-off-by: Chen Lihui <Lihui.Chen@sony.com>

* Remove the release method of LoadedMessage and a related test case

Signed-off-by: Chen Lihui <Lihui.Chen@sony.com>

* Revert "Remove the release method of LoadedMessage and a related test case"

This reverts commit b9825251d148198cb63dc841139e88e77ac02aff.

Signed-off-by: Chen Lihui <Lihui.Chen@sony.com>

* Use unique_ptr as return type for release method of LoanedMessage

Signed-off-by: Chen Lihui <Lihui.Chen@sony.com>

* Update based on review.

Co-authored-by: William Woodall <william@osrfoundation.org>
Signed-off-by: Chen Lihui <Lihui.Chen@sony.com>

* Update description for the release method

Signed-off-by: Chen Lihui <Lihui.Chen@sony.com>

* update based on suggestion and revert some changes.

Co-authored-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
Signed-off-by: Chen Lihui <Lihui.Chen@sony.com>

* Use explicit capture

Co-authored-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
Signed-off-by: Chen Lihui <lihui.chen@sony.com>

* Use unique_ptr as argument type and update exist test

Signed-off-by: Chen Lihui <lihui.chen@sony.com>

Co-authored-by: William Woodall <william@osrfoundation.org>
Co-authored-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-01-26 17:40:30 +09:00
y-okumura-isp
4da9a0c2cd Fix #1526. (#1527)
* Fix #1526.

As action_server_ depends on clock_, we declare clock_ first.
Then the order of deletion becomes action_server_, clock_.

Signed-off-by: y-okumura-isp <y-okumura@isp.co.jp>

* Add comments about declaration order (#1526)

Signed-off-by: y-okumura-isp <y-okumura@isp.co.jp>
2021-01-26 11:44:35 +09:00
Chris Lalancette
83af414811 6.3.0 2021-01-25 21:20:57 +00:00
Chris Lalancette
a7500478d8 Changelog.
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2021-01-25 21:20:40 +00:00
Christophe Bedard
b1ff2d5bdc Add instrumentation for linking a timer to a node (#1500)
Signed-off-by: Christophe Bedard <bedard.christophe@gmail.com>
2021-01-20 17:56:13 -03:00
mauropasse
f38cd8a8bb Fix error when using IPC with StaticSingleThreadExecutor (#1520)
Signed-off-by: Mauro Passerino <mpasserino@irobot.com>
2021-01-20 17:24:02 -03:00
Chris Lalancette
064a021c7a Change to using unique_ptrs for DummyExecutor. (#1517)
* Change to using unique_ptrs for DummyExecutor.

clang static analysis suggested that there was a possible memory
leak here, and it is right.  The test is expecting to throw during
the constructor, in which case the memory would be automatically
freed.  However, if the test did *not* throw for some reason,
we would leak the memory.  Switch to using a unique_ptr here
which will free the memory in all cases at the end of the scope.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2021-01-20 10:49:48 -05:00
Ivan Santiago Paunovic
5cb2274e8c Allow reconfiguring 'clock' topic qos (#1512)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-01-18 13:51:51 -03:00
Daisuke Sato
ca3ad7da2f Fix action server deadlock (#1285) (#1313)
* unlock action_server_reentrant_mutex_ before calling user callback functions
add an additional lock to keep previous behavior broken by deadlock fix

Also add a test case to reproduce deadlock situation in rclcpp_action

Signed-off-by: Daisuke Sato <daisukes@cmu.edu>
2021-01-14 17:18:19 -05:00
Ivan Santiago Paunovic
7ccd64c9c1 Allow to add/remove nodes thread safely in rclcpp::Executor (#1505)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-01-14 13:35:34 -03:00
eboasson
8d2c682c09 Call rclcpp::shutdown in test_node for clean shutdown on Windows (#1515)
The graph_listener thread is started in the background in some of the tests and
this thread is killed by Windows prior to executing global destructors if it is
still running when leaving main().  This then corrupts state because the RMW
layer is blocking in a waitset and causes Cyclone to hang trying to destroy the
waitset.

Signed-off-by: Erik Boasson <eb@ilities.com>
2021-01-13 15:02:45 -05:00
Ivan Santiago Paunovic
56a037a3da Reapply "Add get_logging_directory method to rclcpp::Logger (#1509)" (#1513)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-01-13 10:24:09 -03:00
tomoya
8d5af66858 use describe_parameters of parameter client for test (#1499)
* use describe_parameters of parameter client for test

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>
2021-01-12 09:54:36 -05:00
Ivan Santiago Paunovic
438822fe13 Revert "Add get_logging_directory method to rclcpp::Logger (#1509)" (#1511)
This reverts commit 7a31d7c01b.

Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-01-11 10:05:29 -05:00
Ivan Santiago Paunovic
7a31d7c01b Add get_logging_directory method to rclcpp::Logger (#1509)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2021-01-08 16:24:40 -03:00
Chris Lalancette
700e3c47bf 6.2.0 2021-01-08 19:12:56 +00:00
Chris Lalancette
069b20b7af Changelog.
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2021-01-08 19:12:42 +00:00
Nikolai Morin
bcceecb24b Better documentation for the QoS class (#1508)
* Better documentation for the QoS class

Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* PR Review suggestions

Co-authored-by: William Woodall <william+github@osrfoundation.org>
Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>

* Shorter brief

Signed-off-by: nnmm <nnmmgit@gmail.com>

Co-authored-by: William Woodall <william+github@osrfoundation.org>
2021-01-07 15:30:38 -08:00
hsgwa
7ed61e52fe Modify excluding callback duration from topic statistics (#1492)
Signed-off-by: hsgwa <hasegawa@isp.co.jp>
2021-01-07 15:04:18 -03:00
Chris Lalancette
85c32a94a5 Make the test of graph users more robust. (#1504)
In particular, we don't know for sure that the graph will only
have 1 user; we just know that it should have *at least* one
user.  So change that check to be more robust.  This also
lets us get rid of the slightly strange call to 'notify_graph_change'
that was being used to cleanup graph users.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2021-01-06 10:30:24 -05:00
Chris Lalancette
5821361dcb Make sure to wait for graph change events in test_node_graph. (#1503)
* Make sure to wait for graph change events in test_node_graph.

While debugging something else, I came across this fairly rare
flake in the test_node_graph tests.  Essentially, it may take
some time for node changes to propagate into the graph.  If
the NodeGraph client asks for data before the changes are
in the graph, they may get something they don't expect.  The
fix is to wait for an event on the NodeGraph to happen, and
then look for the data you are interested in.

Before this change, I could get the flake to happen on a loaded
aarch64 system fairly regularly.  After this change, I can no
longer make the flake happen on a loaded system.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2021-01-06 08:41:31 -05:00
Josh Langsfeld
b9ef1fedfa Use std compliant non-method std::filesystem::exists function (#1502)
Signed-off-by: Josh Langsfeld <josh.langsfeld@gmail.com>
2021-01-05 11:18:46 -05:00
tomoya
adebda52c5 add timeout to SyncParametersClient methods (#1493)
* add timeout to SyncParametersClient methods

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>

* update parameter client test with timeout.

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>

* use template thin interface to keep the implementations in library.

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>

* test duration should be long enough not to detect unnecessary timeout

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>
2020-12-22 13:13:37 -08:00
Ivan Santiago Paunovic
715b0e9008 Fix wrong test expectations (#1497)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-12-21 19:33:54 -03:00
Ivan Santiago Paunovic
6257103e76 Goal response callback compatibility shim with deprecation of old signature (#1495)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-12-21 14:54:02 -03:00
Audrow Nash
543a3c39c1 [rclcpp_action] Add warnings (#1405)
* Add warnings

Signed-off-by: Audrow Nash <audrow.nash@gmail.com>

* Simplify for loop in test_client.cpp

Signed-off-by: Audrow Nash <audrow.nash@gmail.com>

* Fix conversion warning in test_client static cast to size_t

Signed-off-by: Audrow Nash <audrow.nash@gmail.com>

* Fix new warnings after rebasing on master

Signed-off-by: Audrow Nash <audrow.nash@gmail.com>

* Fix shadowing in the benchmark action server

Signed-off-by: Audrow Nash <audrow.nash@gmail.com>

* Static cast goal order to size_t

Signed-off-by: Audrow Nash <audrow.nash@gmail.com>

* Remove unnecessary include

Signed-off-by: Audrow Nash <audrow.nash@gmail.com>
2020-12-18 21:59:34 -08:00
Ivan Santiago Paunovic
62c958be30 Update create_publisher/subscription documentation, clarifying when a parameters interface is required (#1494)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-12-18 12:05:33 -08:00
Audrow Nash
febe86e6b5 Fix string literal warnings (#1442)
* Add warnings

Signed-off-by: Audrow Nash <audrow.nash@gmail.com>

* Fix nonliteral string warnings

Signed-off-by: Audrow Nash <audrow.nash@gmail.com>

* Fix compile error from new logging functions in rclcpp_components

Signed-off-by: Audrow Nash <audrow.nash@gmail.com>

* Use "%s" to make log string evaluation secure

Signed-off-by: Audrow Nash <audrow.nash@gmail.com>

* Fix logging warnings in rclcpp

Signed-off-by: Audrow Nash <audrow.nash@gmail.com>

* Fix coding style to pass linter

Signed-off-by: Audrow Nash <audrow.nash@gmail.com>

* Get the c_str of streams

Signed-off-by: Audrow Nash <audrow.nash@gmail.com>

* Remove test to check string logging

Signed-off-by: Audrow Nash <audrow.nash@gmail.com>

* Add in stream logging tests

Signed-off-by: Audrow Nash <audrow.nash@gmail.com>
2020-12-18 09:44:59 -08:00
tomoya
504b082d8b support describe_parameters methods to parameter client. (#1453)
* support describe_parameters methods to parameter client.

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>
2020-12-14 12:30:54 -05:00
Chris Lalancette
9c62c1c946 6.1.0 2020-12-10 17:13:45 +00:00
Chris Lalancette
5b6e0af339 Changelog.
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2020-12-10 17:13:33 +00:00
Ivan Santiago Paunovic
c64ba72bbd Add getters to rclcpp::qos and rclcpp::*Policy enum classes (#1467)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-12-10 12:05:07 -03:00
Chris Lalancette
eddb938aec Change nullptr checks to use ASSERT_TRUE. (#1486)
* Change nullptr checks to use ASSERT_TRUE.

clang static analysis gets a bit confused going through the
gtest macros, so switch from ASSERT_NE to ASSERT_TRUE as
we've done elsewhere.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2020-12-08 09:06:16 -05:00
tomoya
0dc782aca8 add LifecycleNode::get_transition_graph to match services. (#1472)
* add LifecycleNode::get_transition_graph along with service.

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>

* add concrete test cases for get_available_transitions with each primary state.

Signed-off-by: Tomoya.Fujita <Tomoya.Fujita@sony.com>
2020-12-02 11:25:01 -08:00
Stephen Brawner
ea0ee50318 Adjust logic around finding and erasing guard_condition (#1474)
Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-11-30 10:30:26 -08:00
Stephen Brawner
35c73aa61e Update QDs to QL 1 (#1477)
Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-11-25 16:34:19 -08:00
Scott K Logan
08963df926 Add benchmarks for components (#1476)
Signed-off-by: Scott K Logan <logans@cottsay.net>
2020-11-25 14:51:59 -08:00
Scott K Logan
f5e35bda86 Add performance tests for parameter transport (#1463)
Note that these tests are written without using
performance_test_fixture. Because the parameter server is running in the
same process, any allocations happening in the spin thread for the
server get picked up by the allocation statistics even though those
functions aren't invoked in the tests.

If we can find a way to turn off the memory tracking on a per-thread
basis, we can enable memory tracking. Until then, leaving the memory
statistics enabled could be misleading.

Signed-off-by: Scott K Logan <logans@cottsay.net>
2020-11-18 20:39:57 -08:00
brawner
a7db1dcca2 Benchmark lifecycle features (#1462)
* Benchmark lifecycle features

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Cleanup

Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-11-18 18:41:29 -08:00
Ivan Santiago Paunovic
ba1056fe63 6.0.0 2020-11-18 21:51:48 +00:00
Ivan Santiago Paunovic
048d9b57c0 Changelogs
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-11-18 18:50:39 -03:00
brawner
de353f9e45 Reserve vector capacities and use emplace_back for constructing vectors (#1464)
* Reserve vector capacities and use emplace_back for constructing vectors

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Use resize instead of reserve

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Remove push_back

Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-11-17 13:06:58 -08:00
brawner
cba6f20988 Move ownership of shutdown_guard_condition to executors/graph_listener (#1404)
Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-11-17 17:40:55 -03:00
Ivan Santiago Paunovic
71a58d40f1 Qos configurability (take 2) (#1465)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-11-17 17:12:30 -03:00
brawner
add6d61231 [rclcpp_lifecycle] Change uint8_t iterator variables to size_t (#1461)
* Change uint8_t iterator variables to size_t

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Change to unsigned int

Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-11-17 11:22:39 -08:00
Audrow Nash
8c8c268aad Add take_data to Waitable and data to AnyExecutable (#1241)
Signed-off-by: Audrow <audrow.nash@gmail.com>
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-11-17 11:42:03 -03:00
Ivan Santiago Paunovic
27d1b11647 Revert "Qos configurability (#1408)" (#1459)
This reverts commit 4c5986aa2d.

Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-11-16 19:59:27 -03:00
Ivan Santiago Paunovic
4c5986aa2d Qos configurability (#1408)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-11-16 13:58:45 -03:00
Scott K Logan
dd0f97f179 Add benchmarks for node parameters interface (#1444)
Signed-off-by: Scott K Logan <logans@cottsay.net>
2020-11-12 14:40:43 -08:00
brawner
7d257177e0 Remove allocation from executor::remove_node() (#1448)
* Remove allocation from remove_node

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Fix uncrustify

Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-11-12 13:21:51 -08:00
Chris Lalancette
a95efa452e Fix test crashes on CentOS 7 (#1449)
* Refactor graph listener tests to work on CentOS.

inject_on_return doesn't work on CentOS.  To fix this, we
do two separate things:

1.  Where applicable, replace calls to inject_on_return with
patch_and_return (which does work).
2.  We were sort of abusing inject_on_return to do partial
initialization for us for some of the tests.  Instead, make
the class under test (GraphListener) have a protected method
that we can call to do initialization.  With this in place,
we can now get rid of the problematic inject_on_return.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2020-11-11 07:54:41 -05:00
Louise Poubel
06465ba827 Bump rclcpp packages to Quality Level 2 (#1445)
Signed-off-by: Louise Poubel <louise@openrobotics.org>
2020-11-09 17:12:24 -08:00
brawner
5fe6840ad1 Add rclcpp_action action_server benchmarks (#1433)
* Add rclcpp_action action_server benchmarks

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Address cancel bug

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Fix errors

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Fix clang error

Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-11-05 12:09:11 -08:00
Alejandro Hernández Cordero
361be5e4c0 Added executor benchmark tests (#1413)
* Added executor benchmark tests

Signed-off-by: ahcorde <ahcorde@gmail.com>

* make linters happy

Signed-off-by: ahcorde <ahcorde@gmail.com>

* initialize callback_count

Signed-off-by: ahcorde <ahcorde@gmail.com>

* Added feddback

Signed-off-by: ahcorde <ahcorde@gmail.com>

* Added feedback

Signed-off-by: ahcorde <ahcorde@gmail.com>

* Added add_node and remove_node benchmark tests

Signed-off-by: ahcorde <ahcorde@gmail.com>

* Add/remove node in static_single_thread_executor

Signed-off-by: ahcorde <ahcorde@gmail.com>

* Make linters happy

Signed-off-by: ahcorde <ahcorde@gmail.com>

* Added StaticSingleThreadedExecutor add/remove node tests

Signed-off-by: ahcorde <ahcorde@gmail.com>

* make linters happy

Signed-off-by: ahcorde <ahcorde@gmail.com>
2020-11-05 13:18:52 +01:00
Chris Lalancette
58bd8d6c21 Add fully-qualified namespace to WeakCallbackGroupsToNodesMap (#1435)
Older versions of MSVC 2019 can't figure out the correct namespace.
Just to keep them happy, add a fully-qualified namespace.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2020-11-03 12:00:07 -05:00
Ivan Santiago Paunovic
3b04b056e3 5.1.0 2020-11-02 20:10:50 +00:00
Ivan Santiago Paunovic
0aa416e17f Changelogs
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-11-02 20:10:28 +00:00
Ivan Santiago Paunovic
79403119e4 rclcpp::Duration constructors might be confusing to users migrating from ROS 1 (#1432)
* Deprecate Duration(rcl_duration_value_t) in favor of static Duration::from_nanoseconds(rcl_duration_value_t)

Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-11-02 16:54:43 -03:00
Chen Lihui
3ae5170b52 Avoid parsing arguments twice (#1415)
Signed-off-by: Chen Lihui <Lihui.Chen@sony.com>
2020-11-02 12:12:07 -03:00
brawner
2309811814 Benchmark rclcpp_action action_client (#1429)
* Benchmark rclcpp_action action_client

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Bump timeout

Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-10-30 10:40:06 -07:00
brawner
aa159a5e8f Add service and client benchmarks (#1425)
* Add service and client benchmarks

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Style

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Uncrustify

Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-10-28 17:53:19 -07:00
brawner
8a8e46d7e9 Set CMakeLists to only use default rmw for benchmarks (#1427)
* Set CMakeLists to only use default rmw for benchmarks

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Add comment

Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-10-28 12:49:53 -07:00
Christophe Bedard
1ddc8c815c Update tracetools' QL in rclcpp's QD (#1428)
Signed-off-by: Christophe Bedard <bedard.christophe@gmail.com>
2020-10-28 11:24:34 -07:00
Chris Lalancette
579e9d01d6 Add missing locking to the rclcpp_action::ServerBase. (#1421)
This patch actually does 4 related things:

1.  Renames the recursive mutex in the ServerBaseImpl class
to action_server_reentrant_mutex_, which makes it a lot
clearer what it is meant to lock.
2.  Adds some additional error checking where checks were missed.
3.  Adds a lock to publish_status so that the action_server
structure is protected.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2020-10-26 20:45:03 -04:00
brawner
371074523a Address #1423 by moving rosidl_generate_interfaces call (#1424)
Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-10-23 11:36:19 -07:00
brawner
eb7c46ea43 Initial benchmark tests for rclcpp::init/shutdown create/destroy node (#1411)
* Initial benchmark tests for rclcpp::init/shutdown create/destroy node

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Pr feedback

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Fixes to cmakelists

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Remove quotes

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Move find_package calls

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Skip create/destroy node for rmw_connext_cpp

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* SKIP TEST in cmakelists

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Add warmup loops

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* remove for loop

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* reset_heap_counters

Signed-off-by: Stephen Brawner <brawner@gmail.com>

* Change to make_shared

Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-10-22 15:04:13 -07:00
brawner
0810140e18 Refactor test CMakeLists in prep for benchmarks (#1422)
Signed-off-by: Stephen Brawner <brawner@gmail.com>
2020-10-22 13:54:12 -07:00
Ivan Santiago Paunovic
5d9db5de74 Add methods in topic and service interface to resolve a name (#1410)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2020-10-21 18:30:55 -03:00
Audrow Nash
8e5ddb1f81 Update deprecated gtest macros (#1370)
Signed-off-by: Audrow Nash <audrow.nash@gmail.com>
2020-10-20 11:26:45 -07:00
305 changed files with 27993 additions and 4690 deletions

View File

@@ -12,6 +12,6 @@ Visit the [rclcpp API documentation](http://docs.ros2.org/latest/api/rclcpp/) fo
### 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.

View File

@@ -2,6 +2,412 @@
Changelog for package rclcpp
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
16.0.5 (2023-07-17)
-------------------
* warning: comparison of integer expressions of different signedness (`#2219 <https://github.com/ros2/rclcpp/issues/2219>`_) (`#2223 <https://github.com/ros2/rclcpp/issues/2223>`_)
* Trigger the intraprocess guard condition with data (`#2164 <https://github.com/ros2/rclcpp/issues/2164>`_) (`#2167 <https://github.com/ros2/rclcpp/issues/2167>`_)
* Implement validity checks for rclcpp::Clock (`#2040 <https://github.com/ros2/rclcpp/issues/2040>`_) (`#2210 <https://github.com/ros2/rclcpp/issues/2210>`_)
* Contributors: Tomoya Fujita, mergify[bot]
16.0.4 (2023-04-25)
-------------------
* use allocator via init_options argument. (`#2129 <https://github.com/ros2/rclcpp/issues/2129>`_) (`#2131 <https://github.com/ros2/rclcpp/issues/2131>`_)
* Contributors: mergify[bot]
16.0.3 (2023-01-10)
-------------------
* Fix SharedFuture from async_send_request never becomes valid (`#2044 <https://github.com/ros2/rclcpp/issues/2044>`_) (`#2076 <https://github.com/ros2/rclcpp/issues/2076>`_)
* do not throw exception if trying to dequeue an empty intra-process buffer (`#2061 <https://github.com/ros2/rclcpp/issues/2061>`_) (`#2070 <https://github.com/ros2/rclcpp/issues/2070>`_)
* fix nullptr dereference in prune_requests_older_than (`#2008 <https://github.com/ros2/rclcpp/issues/2008>`_) (`#2065 <https://github.com/ros2/rclcpp/issues/2065>`_)
* Fix bug that a callback not reached (`#1640 <https://github.com/ros2/rclcpp/issues/1640>`_) (`#2033 <https://github.com/ros2/rclcpp/issues/2033>`_)
* Contributors: mergify[bot]
16.0.2 (2022-11-07)
-------------------
* fix mismatched issue if using zero_allocate (`#1995 <https://github.com/ros2/rclcpp/issues/1995>`_) (`#2026 <https://github.com/ros2/rclcpp/issues/2026>`_)
* use regex for wildcard matching (backport `#1839 <https://github.com/ros2/rclcpp/issues/1839>`_) (`#1986 <https://github.com/ros2/rclcpp/issues/1986>`_)
* Drop wrong template specialization (`#1926 <https://github.com/ros2/rclcpp/issues/1926>`_) (`#1937 <https://github.com/ros2/rclcpp/issues/1937>`_)
* Add statistics for handle_loaned_message (`#1927 <https://github.com/ros2/rclcpp/issues/1927>`_) (`#1932 <https://github.com/ros2/rclcpp/issues/1932>`_)
* Contributors: mergify[bot]
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>`_)
* Namespace tracetools C++ functions (`#1608 <https://github.com/ros2/rclcpp/issues/1608>`_)
* Revert "Namespace tracetools C++ functions (`#1603 <https://github.com/ros2/rclcpp/issues/1603>`_)" (`#1607 <https://github.com/ros2/rclcpp/issues/1607>`_)
* Namespace tracetools C++ functions (`#1603 <https://github.com/ros2/rclcpp/issues/1603>`_)
* Clock subscription callback group spins in its own thread (`#1556 <https://github.com/ros2/rclcpp/issues/1556>`_)
* Contributors: Chris Lalancette, Christophe Bedard, Ivan Santiago Paunovic, anaelle-sw
8.1.0 (2021-03-25)
------------------
* Remove rmw_connext_cpp references. (`#1595 <https://github.com/ros2/rclcpp/issues/1595>`_)
* Add API for checking QoS profile compatibility (`#1554 <https://github.com/ros2/rclcpp/issues/1554>`_)
* Document misuse of parameters callback (`#1590 <https://github.com/ros2/rclcpp/issues/1590>`_)
* use const auto & to iterate over parameters (`#1593 <https://github.com/ros2/rclcpp/issues/1593>`_)
* Contributors: Chris Lalancette, Jacob Perron, Karsten Knese
8.0.0 (2021-03-23)
------------------
* Guard against integer overflow in duration conversion (`#1584 <https://github.com/ros2/rclcpp/issues/1584>`_)
* Contributors: Jacob Perron
7.0.1 (2021-03-22)
------------------
* get_parameters service should return empty if undeclared parameters are allowed (`#1514 <https://github.com/ros2/rclcpp/issues/1514>`_)
* Made 'Context::shutdown_reason' function a const function (`#1578 <https://github.com/ros2/rclcpp/issues/1578>`_)
* Contributors: Tomoya Fujita, suab321321
7.0.0 (2021-03-18)
------------------
* Document design decisions that were made for statically typed parameters (`#1568 <https://github.com/ros2/rclcpp/issues/1568>`_)
* Fix doc typo in CallbackGroup constructor (`#1582 <https://github.com/ros2/rclcpp/issues/1582>`_)
* Enable qos parameter overrides for the /parameter_events topic (`#1532 <https://github.com/ros2/rclcpp/issues/1532>`_)
* Add support for rmw_connextdds (`#1574 <https://github.com/ros2/rclcpp/issues/1574>`_)
* Remove 'struct' from the rcl_time_jump_t. (`#1577 <https://github.com/ros2/rclcpp/issues/1577>`_)
* Add tests for declaring statically typed parameters when undeclared parameters are allowed (`#1575 <https://github.com/ros2/rclcpp/issues/1575>`_)
* Quiet clang memory leak warning on "DoNotOptimize". (`#1571 <https://github.com/ros2/rclcpp/issues/1571>`_)
* Add ParameterEventsSubscriber class (`#829 <https://github.com/ros2/rclcpp/issues/829>`_)
* When a parameter change is rejected, the parameters map shouldn't be updated. (`#1567 <https://github.com/ros2/rclcpp/pull/1567>`_)
* Fix when to throw the NoParameterOverrideProvided exception. (`#1567 <https://github.com/ros2/rclcpp/pull/1567>`_)
* Fix SEGV caused by order of destruction of Node sub-interfaces (`#1469 <https://github.com/ros2/rclcpp/issues/1469>`_)
* Fix benchmark test failure introduced in `#1522 <https://github.com/ros2/rclcpp/issues/1522>`_ (`#1564 <https://github.com/ros2/rclcpp/issues/1564>`_)
* Fix documented example in create_publisher (`#1558 <https://github.com/ros2/rclcpp/issues/1558>`_)
* Enforce static parameter types (`#1522 <https://github.com/ros2/rclcpp/issues/1522>`_)
* Allow timers to keep up the intended rate in MultiThreadedExecutor (`#1516 <https://github.com/ros2/rclcpp/issues/1516>`_)
* Fix UBSAN warnings in any_subscription_callback. (`#1551 <https://github.com/ros2/rclcpp/issues/1551>`_)
* Fix runtime error: reference binding to null pointer of type (`#1547 <https://github.com/ros2/rclcpp/issues/1547>`_)
* Contributors: Andrea Sorbini, Chris Lalancette, Colin MacKenzie, Ivan Santiago Paunovic, Jacob Perron, Steven! Ragnarök, bpwilcox, tomoya
6.3.1 (2021-02-08)
------------------
* Reference test resources directly from source tree (`#1543 <https://github.com/ros2/rclcpp/issues/1543>`_)
* clear statistics after window reset (`#1531 <https://github.com/ros2/rclcpp/issues/1531>`_) (`#1535 <https://github.com/ros2/rclcpp/issues/1535>`_)
* Fix a minor string error in the topic_statistics test. (`#1541 <https://github.com/ros2/rclcpp/issues/1541>`_)
* Avoid `Resource deadlock avoided` if use intra_process_comms (`#1530 <https://github.com/ros2/rclcpp/issues/1530>`_)
* Avoid an object copy in parameter_value.cpp. (`#1538 <https://github.com/ros2/rclcpp/issues/1538>`_)
* Assert that the publisher_list size is 1. (`#1537 <https://github.com/ros2/rclcpp/issues/1537>`_)
* Don't access objects after they have been std::move (`#1536 <https://github.com/ros2/rclcpp/issues/1536>`_)
* Update for checking correct variable (`#1534 <https://github.com/ros2/rclcpp/issues/1534>`_)
* Destroy msg extracted from LoanedMessage. (`#1305 <https://github.com/ros2/rclcpp/issues/1305>`_)
* Contributors: Chen Lihui, Chris Lalancette, Ivan Santiago Paunovic, Miaofei Mei, Scott K Logan, William Woodall, hsgwa
6.3.0 (2021-01-25)
------------------
* Add instrumentation for linking a timer to a node (`#1500 <https://github.com/ros2/rclcpp/issues/1500>`_)
* Fix error when using IPC with StaticSingleThreadExecutor (`#1520 <https://github.com/ros2/rclcpp/issues/1520>`_)
* Change to using unique_ptrs for DummyExecutor. (`#1517 <https://github.com/ros2/rclcpp/issues/1517>`_)
* Allow reconfiguring 'clock' topic qos (`#1512 <https://github.com/ros2/rclcpp/issues/1512>`_)
* Allow to add/remove nodes thread safely in rclcpp::Executor (`#1505 <https://github.com/ros2/rclcpp/issues/1505>`_)
* Call rclcpp::shutdown in test_node for clean shutdown on Windows (`#1515 <https://github.com/ros2/rclcpp/issues/1515>`_)
* Reapply "Add get_logging_directory method to rclcpp::Logger (`#1509 <https://github.com/ros2/rclcpp/issues/1509>`_)" (`#1513 <https://github.com/ros2/rclcpp/issues/1513>`_)
* use describe_parameters of parameter client for test (`#1499 <https://github.com/ros2/rclcpp/issues/1499>`_)
* Revert "Add get_logging_directory method to rclcpp::Logger (`#1509 <https://github.com/ros2/rclcpp/issues/1509>`_)" (`#1511 <https://github.com/ros2/rclcpp/issues/1511>`_)
* Add get_logging_directory method to rclcpp::Logger (`#1509 <https://github.com/ros2/rclcpp/issues/1509>`_)
* Contributors: Chris Lalancette, Christophe Bedard, Ivan Santiago Paunovic, eboasson, mauropasse, tomoya
6.2.0 (2021-01-08)
------------------
* Better documentation for the QoS class (`#1508 <https://github.com/ros2/rclcpp/issues/1508>`_)
* Modify excluding callback duration from topic statistics (`#1492 <https://github.com/ros2/rclcpp/issues/1492>`_)
* Make the test of graph users more robust. (`#1504 <https://github.com/ros2/rclcpp/issues/1504>`_)
* Make sure to wait for graph change events in test_node_graph. (`#1503 <https://github.com/ros2/rclcpp/issues/1503>`_)
* add timeout to SyncParametersClient methods (`#1493 <https://github.com/ros2/rclcpp/issues/1493>`_)
* Fix wrong test expectations (`#1497 <https://github.com/ros2/rclcpp/issues/1497>`_)
* Update create_publisher/subscription documentation, clarifying when a parameters interface is required (`#1494 <https://github.com/ros2/rclcpp/issues/1494>`_)
* Fix string literal warnings (`#1442 <https://github.com/ros2/rclcpp/issues/1442>`_)
* support describe_parameters methods to parameter client. (`#1453 <https://github.com/ros2/rclcpp/issues/1453>`_)
* Contributors: Audrow Nash, Chris Lalancette, Ivan Santiago Paunovic, Nikolai Morin, hsgwa, tomoya
6.1.0 (2020-12-10)
------------------
* Add getters to rclcpp::qos and rclcpp::Policy enum classes (`#1467 <https://github.com/ros2/rclcpp/issues/1467>`_)
* Change nullptr checks to use ASSERT_TRUE. (`#1486 <https://github.com/ros2/rclcpp/issues/1486>`_)
* Adjust logic around finding and erasing guard_condition (`#1474 <https://github.com/ros2/rclcpp/issues/1474>`_)
* Update QDs to QL 1 (`#1477 <https://github.com/ros2/rclcpp/issues/1477>`_)
* Add performance tests for parameter transport (`#1463 <https://github.com/ros2/rclcpp/issues/1463>`_)
* Contributors: Chris Lalancette, Ivan Santiago Paunovic, Scott K Logan, Stephen Brawner
6.0.0 (2020-11-18)
------------------
* Move ownership of shutdown_guard_condition to executors/graph_listener (`#1404 <https://github.com/ros2/rclcpp/issues/1404>`_)
* Add options to automatically declare qos parameters when creating a publisher/subscription (`#1465 <https://github.com/ros2/rclcpp/issues/1465>`_)
* Add `take_data` to `Waitable` and `data` to `AnyExecutable` (`#1241 <https://github.com/ros2/rclcpp/issues/1241>`_)
* Add benchmarks for node parameters interface (`#1444 <https://github.com/ros2/rclcpp/issues/1444>`_)
* Remove allocation from executor::remove_node() (`#1448 <https://github.com/ros2/rclcpp/issues/1448>`_)
* Fix test crashes on CentOS 7 (`#1449 <https://github.com/ros2/rclcpp/issues/1449>`_)
* Bump rclcpp packages to Quality Level 2 (`#1445 <https://github.com/ros2/rclcpp/issues/1445>`_)
* Added executor benchmark tests (`#1413 <https://github.com/ros2/rclcpp/issues/1413>`_)
* Add fully-qualified namespace to WeakCallbackGroupsToNodesMap (`#1435 <https://github.com/ros2/rclcpp/issues/1435>`_)
* Contributors: Alejandro Hernández Cordero, Audrow Nash, Chris Lalancette, Ivan Santiago Paunovic, Louise Poubel, Scott K Logan, brawner
5.1.0 (2020-11-02)
------------------
* Deprecate Duration(rcl_duration_value_t) in favor of static Duration::from_nanoseconds(rcl_duration_value_t) (`#1432 <https://github.com/ros2/rclcpp/issues/1432>`_)
* Avoid parsing arguments twice in `rclcpp::init_and_remove_ros_arguments` (`#1415 <https://github.com/ros2/rclcpp/issues/1415>`_)
* Add service and client benchmarks (`#1425 <https://github.com/ros2/rclcpp/issues/1425>`_)
* Set CMakeLists to only use default rmw for benchmarks (`#1427 <https://github.com/ros2/rclcpp/issues/1427>`_)
* Update tracetools' QL in rclcpp's QD (`#1428 <https://github.com/ros2/rclcpp/issues/1428>`_)
* Add missing locking to the rclcpp_action::ServerBase. (`#1421 <https://github.com/ros2/rclcpp/issues/1421>`_)
* Initial benchmark tests for rclcpp::init/shutdown create/destroy node (`#1411 <https://github.com/ros2/rclcpp/issues/1411>`_)
* Refactor test CMakeLists in prep for benchmarks (`#1422 <https://github.com/ros2/rclcpp/issues/1422>`_)
* Add methods in topic and service interface to resolve a name (`#1410 <https://github.com/ros2/rclcpp/issues/1410>`_)
* Update deprecated gtest macros (`#1370 <https://github.com/ros2/rclcpp/issues/1370>`_)
* Clear members for StaticExecutorEntitiesCollector to avoid shared_ptr dependency (`#1303 <https://github.com/ros2/rclcpp/issues/1303>`_)
* Increase test timeouts of slow running tests with rmw_connext_cpp (`#1400 <https://github.com/ros2/rclcpp/issues/1400>`_)
* Avoid self dependency that not destoryed (`#1301 <https://github.com/ros2/rclcpp/issues/1301>`_)
* Update maintainers (`#1384 <https://github.com/ros2/rclcpp/issues/1384>`_)
* Add clock qos to node options (`#1375 <https://github.com/ros2/rclcpp/issues/1375>`_)
* Fix NodeOptions copy constructor (`#1376 <https://github.com/ros2/rclcpp/issues/1376>`_)
* Make sure to clean the external client/service handle. (`#1296 <https://github.com/ros2/rclcpp/issues/1296>`_)
* Increase coverage of WaitSetTemplate (`#1368 <https://github.com/ros2/rclcpp/issues/1368>`_)
* Increase coverage of guard_condition.cpp to 100% (`#1369 <https://github.com/ros2/rclcpp/issues/1369>`_)
* Add coverage statement (`#1367 <https://github.com/ros2/rclcpp/issues/1367>`_)
* Tests for LoanedMessage with mocked loaned message publisher (`#1366 <https://github.com/ros2/rclcpp/issues/1366>`_)
* Add unit tests for qos and qos_event files (`#1352 <https://github.com/ros2/rclcpp/issues/1352>`_)
* Finish coverage of publisher API (`#1365 <https://github.com/ros2/rclcpp/issues/1365>`_)
* Finish API coverage on executors. (`#1364 <https://github.com/ros2/rclcpp/issues/1364>`_)
* Add test for ParameterService (`#1355 <https://github.com/ros2/rclcpp/issues/1355>`_)
* Add time API coverage tests (`#1347 <https://github.com/ros2/rclcpp/issues/1347>`_)
* Add timer coverage tests (`#1363 <https://github.com/ros2/rclcpp/issues/1363>`_)
* Add in additional tests for parameter_client.cpp coverage.
* Minor fixes to the parameter_service.cpp file.
* reset rcl_context shared_ptr after calling rcl_init sucessfully (`#1357 <https://github.com/ros2/rclcpp/issues/1357>`_)
* Improved test publisher - zero qos history depth value exception (`#1360 <https://github.com/ros2/rclcpp/issues/1360>`_)
* Covered resolve_use_intra_process (`#1359 <https://github.com/ros2/rclcpp/issues/1359>`_)
* Improve test_subscription_options (`#1358 <https://github.com/ros2/rclcpp/issues/1358>`_)
* Add in more tests for init_options coverage. (`#1353 <https://github.com/ros2/rclcpp/issues/1353>`_)
* Test the remaining node public API (`#1342 <https://github.com/ros2/rclcpp/issues/1342>`_)
* Complete coverage of Parameter and ParameterValue API (`#1344 <https://github.com/ros2/rclcpp/issues/1344>`_)
* Add in more tests for the utilities. (`#1349 <https://github.com/ros2/rclcpp/issues/1349>`_)
* Add in two more tests for expand_topic_or_service_name. (`#1350 <https://github.com/ros2/rclcpp/issues/1350>`_)
* Add tests for node_options API (`#1343 <https://github.com/ros2/rclcpp/issues/1343>`_)
* Add in more coverage for expand_topic_or_service_name. (`#1346 <https://github.com/ros2/rclcpp/issues/1346>`_)
* Test exception in spin_until_future_complete. (`#1345 <https://github.com/ros2/rclcpp/issues/1345>`_)
* Add coverage tests graph_listener (`#1330 <https://github.com/ros2/rclcpp/issues/1330>`_)
* Add in unit tests for the Executor class.
* Allow mimick patching of methods with up to 9 arguments.
* Improve the error messages in the Executor class.
* Add coverage for client API (`#1329 <https://github.com/ros2/rclcpp/issues/1329>`_)
* Increase service coverage (`#1332 <https://github.com/ros2/rclcpp/issues/1332>`_)
* Make more of the static entity collector API private.
* Const-ify more of the static executor.
* Add more tests for the static single threaded executor.
* Many more tests for the static_executor_entities_collector.
* Get one more line of code coverage in memory_strategy.cpp
* Bugfix when adding callback group.
* Fix typos in comments.
* Remove deprecated executor::FutureReturnCode APIs. (`#1327 <https://github.com/ros2/rclcpp/issues/1327>`_)
* Increase coverage of publisher/subscription API (`#1325 <https://github.com/ros2/rclcpp/issues/1325>`_)
* Not finalize guard condition while destructing SubscriptionIntraProcess (`#1307 <https://github.com/ros2/rclcpp/issues/1307>`_)
* Expose qos setting for /rosout (`#1247 <https://github.com/ros2/rclcpp/issues/1247>`_)
* Add coverage for missing API (except executors) (`#1326 <https://github.com/ros2/rclcpp/issues/1326>`_)
* Include topic name in QoS mismatch warning messages (`#1286 <https://github.com/ros2/rclcpp/issues/1286>`_)
* Add coverage tests context functions (`#1321 <https://github.com/ros2/rclcpp/issues/1321>`_)
* Increase coverage of node_interfaces, including with mocking rcl errors (`#1322 <https://github.com/ros2/rclcpp/issues/1322>`_)
* Contributors: Ada-King, Alejandro Hernández Cordero, Audrow Nash, Barry Xu, Chen Lihui, Chris Lalancette, Christophe Bedard, Ivan Santiago Paunovic, Jorge Perez, Morgan Quigley, brawner
5.0.0 (2020-09-18)
------------------
* Make node_graph::count_graph_users() const (`#1320 <https://github.com/ros2/rclcpp/issues/1320>`_)

View File

@@ -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,10 @@ 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)
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,6 +41,8 @@ set(${PROJECT_NAME}_SRCS
src/rclcpp/clock.cpp
src/rclcpp/context.cpp
src/rclcpp/contexts/default_context.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
@@ -49,12 +53,14 @@ set(${PROJECT_NAME}_SRCS
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
@@ -64,8 +70,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
@@ -76,15 +82,18 @@ 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/qos_overriding_options.cpp
src/rclcpp/serialization.cpp
src/rclcpp/serialized_message.cpp
src/rclcpp/service.cpp
@@ -95,11 +104,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"
@@ -113,7 +125,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
@@ -137,7 +149,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
@@ -157,7 +169,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
@@ -166,17 +178,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"
@@ -200,11 +218,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)
@@ -222,12 +244,6 @@ if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
ament_lint_auto_find_test_dependencies()
# For benchmark tests. Currently there is a bug where these targets can't be
# found if these calls are added to the CMakeLists.txt in test/rclcpp/benchmark
find_package(benchmark REQUIRED)
find_package(osrf_testing_tools_cpp REQUIRED)
find_package(performance_test_fixture REQUIRED)
add_subdirectory(test)
endif()
@@ -235,5 +251,12 @@ 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()
ament_generate_version_header(${PROJECT_NAME})

View File

@@ -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"

View File

@@ -2,15 +2,15 @@ This document is a declaration of software quality for the `rclcpp` package, bas
# rclcpp Quality Declaration
The package `rclcpp` claims to be in the **Quality Level 3** category.
The package `rclcpp` claims to be in the **Quality Level 1** category when it is used with a **Quality Level 1** middleware.
Below are the rationales, notes, and caveats for this claim, organized by each requirement listed in the [Package Quality Categories in REP-2004](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#package-quality-categories) of the ROS2 developer guide.
Below are the rationales, notes, and caveats for this claim, organized by each requirement listed in the [Package Quality Categories in REP-2004](https://www.ros.org/reps/rep-2004.html) of the ROS2 developer guide.
## Version Policy [1]
### Version Scheme [1.i]
`rclcpp` uses `semver` according to the recommendation for ROS Core packages in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#versioning).
`rclcpp` uses `semver` according to the recommendation for ROS Core packages in the [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#versioning).
### Version Stability [1.ii]
@@ -39,11 +39,11 @@ Headers under the folder `detail` are not considered part of the public API and
## Change Control Process [2]
`rclcpp` follows the recommended guidelines for ROS Core packages in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#change-control-process).
`rclcpp` follows the recommended guidelines for ROS Core packages in the [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#change-control-process).
### Change Requests [2.i]
All changes will occur through a pull request, check [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#change-control-process) for additional information.
All changes will occur through a pull request, check [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#change-control-process) for additional information.
### Contributor Origin [2.ii]
@@ -51,7 +51,7 @@ This package uses DCO as its confirmation of contributor origin policy. More inf
### Peer Review Policy [2.iii]
All pull requests will be peer-reviewed, check [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#change-control-process) for additional information.
All pull requests will be peer-reviewed, check [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#change-control-process) for additional information.
### Continuous Integration [2.iv]
@@ -82,13 +82,13 @@ The API is publicly available in its [ROS 2 API documentation](http://docs.ros2.
The license for `rclcpp` is Apache 2.0, and a summary is in each source file, the type is declared in the [`package.xml`](./package.xml) manifest file, and a full copy of the license is in the [`LICENSE`](../LICENSE) file.
There is an automated test which runs a linter that ensures each file has a license statement. [Here](http://build.ros2.org/view/Fpr/job/Fpr__rclcpp__ubuntu_focal_amd64/lastSuccessfulBuild/testReport/rclcpp/) can be found a list with the latest results of the various linters being run on the package.
There is an automated test which runs a linter that ensures each file has a license statement. [Here](http://build.ros2.org/view/Rpr/job/Rpr__rclcpp__ubuntu_focal_amd64/lastCompletedBuild/testReport/rclcpp/) can be found a list with the latest results of the various linters being run on the package.
### Copyright Statements [3.iv]
The copyright holders each provide a statement of copyright in each source code file in `rclcpp`.
There is an automated test which runs a linter that ensures each file has at least one copyright statement. Latest linter result report can be seen [here](http://build.ros2.org/view/Fpr/job/Fpr__rclcpp__ubuntu_focal_amd64/lastSuccessfulBuild/testReport/rclcpp/copyright/).
There is an automated test which runs a linter that ensures each file has at least one copyright statement. Latest linter result report can be seen [here](http://build.ros2.org/view/Rpr/job/Rpr__rclcpp__ubuntu_focal_amd64/lastCompletedBuild/testReport/rclcpp/copyright/).
## Testing [4]
@@ -111,7 +111,7 @@ The tests aim to cover both typical usage and corner cases, but are quantified b
### Coverage [4.iii]
`rclcpp` follows the recommendations for ROS Core packages in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#code-coverage), and opts to use line coverage instead of branch coverage.
`rclcpp` follows the recommendations for ROS Core packages in the [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#code-coverage), and opts to use line coverage instead of branch coverage.
This includes:
@@ -121,17 +121,25 @@ This includes:
Changes are required to make a best effort to keep or increase coverage before being accepted, but decreases are allowed if properly justified and accepted by reviewers.
Current coverage statistics can be viewed [here](https://ci.ros2.org/job/nightly_linux_coverage/lastSuccessfulBuild/cobertura/src_ros2_rclcpp_rclcpp_src_rclcpp/). A description of how coverage statistics are calculated is summarized in this page ["ROS 2 Onboarding Guide"](https://index.ros.org/doc/ros2/Contributing/ROS-2-On-boarding-Guide/#note-on-coverage-runs).
Current coverage statistics can be viewed [here](https://ci.ros2.org/job/nightly_linux_coverage/lastCompletedBuild/cobertura/src_ros2_rclcpp_rclcpp_src_rclcpp/). A description of how coverage statistics are calculated is summarized in this page ["ROS 2 Onboarding Guide"](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#note-on-coverage-runs).
`rclcpp` has a line coverage `>= 95%`, which is calculated over all directories within `rclcpp` with the exception of the `experimental` directory.
### Performance [4.iv]
It is not yet defined if this package requires performance testing and how addresses this topic.
`rclcpp` follows the recommendations for performance testing of C/C++ code in the [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#performance), and opts to do performance analysis on each release rather than each change.
The performance tests of `rclcpp` are located in the [test/benchmark directory](https://github.com/ros2/rclcpp/tree/master/rclcpp/test/benchmark).
System level performance benchmarks that cover features of `rclcpp` can be found at:
* [Benchmarks](http://build.ros2.org/view/Rci/job/Rci__benchmark_ubuntu_focal_amd64/BenchmarkTable/)
* [Performance](http://build.ros2.org/view/Rci/job/Rci__nightly-performance_ubuntu_focal_amd64/lastCompletedBuild/)
Changes that introduce regressions in performance must be adequately justified in order to be accepted and merged.
### Linters and Static Analysis [4.v]
`rclcpp` uses and passes all the ROS2 standard linters and static analysis tools for a C++ package as described in the [ROS 2 Developer Guide](https://index.ros.org/doc/ros2/Contributing/Developer-Guide/#linters-and-static-analysis). Passing implies there are no linter/static errors when testing against CI of supported platforms.
`rclcpp` uses and passes all the ROS2 standard linters and static analysis tools for a C++ package as described in the [ROS 2 Developer Guide](https://docs.ros.org/en/rolling/Contributing/Developer-Guide.html#linters-and-static-analysis). Passing implies there are no linter/static errors when testing against CI of supported platforms.
Currently nightly test results can be seen here:
* [linux-aarch64_release](https://ci.ros2.org/view/nightly/job/nightly_linux-aarch64_release/lastBuild/testReport/rclcpp/)
@@ -155,49 +163,49 @@ It also has several test dependencies, which do not affect the resulting quality
The `libstatistics_collector` package provides lightweight aggregation utilities to collect statistics and measure message metrics.
It is **Quality Level 3**, see its [Quality Declaration document](https://github.com/ros-tooling/libstatistics_collector/tree/master/QUALITY_DECLARATION.md).
It is **Quality Level 1**, see its [Quality Declaration document](https://github.com/ros-tooling/libstatistics_collector/tree/master/QUALITY_DECLARATION.md).
#### `rcl`
`rcl` a library to support implementation of language specific ROS 2 Client Libraries.
It is **Quality Level 3**, see its [Quality Declaration document](https://github.com/ros2/rcl/blob/master/rcl/QUALITY_DECLARATION.md).
It is **Quality Level 1**, see its [Quality Declaration document](https://github.com/ros2/rcl/blob/master/rcl/QUALITY_DECLARATION.md).
#### `rcl_yaml_param_parser`
The `rcl_yaml_param_parser` package provides an API that is used to parse YAML configuration files which may be used to configure ROS and specific nodes.
It is **Quality Level 3**, see its [Quality Declaration document](https://github.com/ros2/rcl/tree/master/rcl_yaml_param_parser/QUALITY_DECLARATION.md).
It is **Quality Level 1**, see its [Quality Declaration document](https://github.com/ros2/rcl/tree/master/rcl_yaml_param_parser/QUALITY_DECLARATION.md).
#### `rcpputils`
The `rcpputils` package provides an API which contains common utilities and data structures useful when programming in C++.
It is **Quality Level 2**, see its [Quality Declaration document](https://github.com/ros2/rcpputils/blob/master/QUALITY_DECLARATION.md).
It is **Quality Level 1**, see its [Quality Declaration document](https://github.com/ros2/rcpputils/blob/master/QUALITY_DECLARATION.md).
#### `rcutils`
The `rcutils` package provides an API which contains common utilities and data structures useful when programming in C.
It is **Quality Level 2**, see its [Quality Declaration document](https://github.com/ros2/rcutils/blob/master/QUALITY_DECLARATION.md).
It is **Quality Level 1**, see its [Quality Declaration document](https://github.com/ros2/rcutils/blob/master/QUALITY_DECLARATION.md).
#### `rmw`
`rmw` is the ROS 2 middleware library.
It is **Quality Level 2**, see its [Quality Declaration document](https://github.com/ros2/rmw/blob/master/rmw/QUALITY_DECLARATION.md).
It is **Quality Level 1**, see its [Quality Declaration document](https://github.com/ros2/rmw/blob/master/rmw/QUALITY_DECLARATION.md).
#### `statistics_msgs`
The `statistics_msgs` package contains ROS 2 message definitions for reporting statistics for topics and system resources.
It is **Quality Level 3**, see its [Quality Declaration document](https://github.com/ros2/rcl_interfaces/blob/master/statistics_msgs/QUALITY_DECLARATION.md).
It is **Quality Level 1**, see its [Quality Declaration document](https://github.com/ros2/rcl_interfaces/blob/master/statistics_msgs/QUALITY_DECLARATION.md).
#### `tracetools`
The `tracetools` package provides utilities for instrumenting the code in `rclcpp` so that it may be traced for debugging and performance analysis.
It is **Quality Level 2**, see its [Quality Declaration document](https://gitlab.com/micro-ROS/ros_tracing/ros2_tracing/-/blob/master/tracetools/QUALITY_DECLARATION.md).
It is **Quality Level 1**, see its [Quality Declaration document](https://gitlab.com/ros-tracing/ros2_tracing/-/blob/master/tracetools/QUALITY_DECLARATION.md).
### Direct Runtime non-ROS Dependency [5.iii]

View File

@@ -6,4 +6,4 @@ Visit the [rclcpp API documentation](http://docs.ros2.org/latest/api/rclcpp/) fo
## Quality Declaration
This package claims to be in the **Quality Level 3** category, see the [Quality Declaration](QUALITY_DECLARATION.md) for more details.
This package claims to be in the **Quality Level 1** category, see the [Quality Declaration](QUALITY_DECLARATION.md) for more details.

View File

@@ -0,0 +1,141 @@
# Notes on statically typed parameters
## Introduction
Until ROS 2 Foxy, all parameters could change type anytime, except if the user installed a parameter callback to reject a change.
This could generate confusing errors, for example:
```
$ ros2 run demo_nodes_py listener &
$ ros2 param set /listener use_sim_time not_a_boolean
[ERROR] [1614712713.233733147] [listener]: use_sim_time parameter set to something besides a bool
Set parameter successful
$ ros2 param get /listener use_sim_time
String value is: not_a_boolean
```
For most use cases, having static parameter types is enough.
This article documents some of the decisions that were made when implementing static parameter types enforcement in:
* https://github.com/ros2/rclcpp/pull/1522
* https://github.com/ros2/rclpy/pull/683
## Allowing dynamically typed parameters
There might be some scenarios where dynamic typing is desired, so a `dynamic_typing` field was added to the [parameter descriptor](https://github.com/ros2/rcl_interfaces/blob/09b5ed93a733adb9deddc47f9a4a8c6e9f584667/rcl_interfaces/msg/ParameterDescriptor.msg#L25).
It defaults to `false`.
For example:
```cpp
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.dynamic_typing = true;
node->declare_parameter("dynamically_typed_parameter", rclcpp::ParameterValue{}, descriptor);
```
```py
rcl_interfaces.msg.ParameterDescriptor descriptor;
descriptor.dynamic_typing = True;
node.declare_parameter("dynamically_typed_parameter", None, descriptor);
```
## How is the parameter type specified?
The parameter type will be inferred from the default value provided when declaring it.
## Statically typed parameters when allowing undeclared parameters
When undeclared parameters are allowed and a parameter is set without a previous declaration, the parameter will be dynamically typed.
This is consistent with other allowed behaviors when undeclared parameters are allowed, e.g. trying to get an undeclared parameter returns "NOT_SET".
Parameter declarations will remain special and dynamic or static typing will be used based on the parameter descriptor (default to static).
## Declaring a parameter without a default value
There might be cases were a default value does not make sense and the user must always provide an override.
In those cases, the parameter type can be specified explicitly:
```cpp
// method signature
template<typename T>
Node::declare_parameter<T>(std::string name, rcl_interfaces::msg::ParameterDescriptor = rcl_interfaces::msg::ParameterDescriptor{});
// or alternatively
Node::declare_parameter(std::string name, rclcpp::ParameterType type, rcl_interfaces::msg::ParameterDescriptor = rcl_interfaces::msg::ParameterDescriptor{});
// examples
node->declare_parameter<int64_t>("my_integer_parameter"); // declare an integer parameter
node->declare_parameter("another_integer_parameter", rclcpp::ParameterType::PARAMETER_INTEGER); // another way to do the same
```
```py
# method signature
Node.declare_parameter(name: str, param_type: rclpy.Parameter.Type, descriptor: rcl_interfaces.msg.ParameterDescriptor = rcl_interfaces.msg.ParameterDescriptor())
# example
node.declare_parameter('my_integer_parameter', rclpy.Parameter.Type.INTEGER); # declare an integer parameter
```
If the parameter may be unused, but when used requires a parameter override, then you could conditionally declare it:
```cpp
auto mode = node->declare_parameter("mode", "modeA"); // "mode" parameter is an string
if (mode == "modeB") {
node->declare_parameter<int64_t>("param_needed_when_mode_b"); // when "modeB", the user must provide "param_needed_when_mode_b"
}
```
## Other migration notes
Declaring a parameter with only a name is deprecated:
```cpp
node->declare_parameter("my_param"); // this generates a build warning
```
```py
node.declare_parameter("my_param"); # this generates a python user warning
```
Before, you could initialize a parameter with the "NOT SET" value (in cpp `rclcpp::ParameterValue{}`, in python `None`).
Now this will throw an exception in both cases:
```cpp
node->declare_parameter("my_param", rclcpp::ParameterValue{}); // not valid, will throw exception
```
```py
node.declare_parameter("my_param", None); # not valid, will raise error
```
## Possible improvements
### Easier way to declare dynamically typed parameters
Declaring a dynamically typed parameter in `rclcpp` could be considered to be a bit verbose:
```cpp
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.dynamic_typing = true;
node->declare_parameter(name, rclcpp::ParameterValue{}, descriptor);
```
the following ways could be supported to make it simpler:
```cpp
node->declare_parameter(name, rclcpp::PARAMETER_DYNAMIC);
node->declare_parameter(name, default_value, rclcpp::PARAMETER_DYNAMIC);
```
or alternatively:
```cpp
node->declare_parameter(name, default_value, rclcpp::ParameterDescriptor{}.dynamic_typing());
```
For `rclpy`, there's already a short way to do it:
```py
node.declare_parameter(name, default_value, rclpy.ParameterDescriptor(dynamic_typing=true));
```

View File

@@ -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;

View File

@@ -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;

View File

@@ -47,14 +47,9 @@ struct AnyExecutable
// These are used to keep the scope on the containing items
rclcpp::CallbackGroup::SharedPtr callback_group;
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base;
std::shared_ptr<void> data;
};
namespace executor
{
using AnyExecutable [[deprecated("use rclcpp::AnyExecutable instead")]] = AnyExecutable;
} // namespace executor
} // namespace rclcpp
#endif // RCLCPP__ANY_EXECUTABLE_HPP_

View File

@@ -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,204 @@
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),
get_symbol(shared_ptr_callback_));
} else if (shared_ptr_with_request_header_callback_) {
TRACEPOINT(
rclcpp_callback_register,
static_cast<const void *>(this),
get_symbol(shared_ptr_with_request_header_callback_));
}
std::visit(
[this](auto && arg) {
TRACEPOINT(
rclcpp_callback_register,
static_cast<const void *>(this),
tracetools::get_symbol(arg));
}, 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

View File

@@ -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"
@@ -85,8 +88,8 @@ public:
* group, or after, is irrelevant; the callback group will be automatically
* added to the executor in either case.
*
* \param[in] group_type They type of the callback group.
* \param[in] automatically_add_to_executor_with_node a boolean which
* \param[in] group_type The type of the callback group.
* \param[in] automatically_add_to_executor_with_node A boolean that
* determines whether a callback group is automatically added to an executor
* with the node with which it is associated.
*/
@@ -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_

View File

@@ -17,34 +17,103 @@
#include <atomic>
#include <future>
#include <map>
#include <unordered_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 <utility>
#include <variant> // NOLINT
#include <vector>
#include "rcl/client.h"
#include "rcl/error_handling.h"
#include "rcl/event_callback.h"
#include "rcl/wait.h"
#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;
@@ -150,6 +219,122 @@ 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<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<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 +350,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 +383,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 +392,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.
@@ -292,34 +547,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 +639,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,28 +670,165 @@ 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();
}
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_;
};

View File

@@ -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"
@@ -78,6 +79,109 @@ public:
Time
now();
/**
* 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.
*
@@ -136,7 +240,7 @@ private:
RCLCPP_PUBLIC
static void
on_time_jump(
const struct rcl_time_jump_t * time_jump,
const rcl_time_jump_t * time_jump,
bool before_jump,
void * user_data);

View File

@@ -23,6 +23,7 @@
#include <typeindex>
#include <typeinfo>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>
@@ -47,6 +48,20 @@ 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.
@@ -63,7 +78,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 +95,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 +127,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.
@@ -150,7 +165,7 @@ public:
*/
RCLCPP_PUBLIC
std::string
shutdown_reason();
shutdown_reason() const;
/// Shutdown the context, making it uninitialized and therefore invalid for derived entities.
/**
@@ -177,7 +192,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 +200,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 +218,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 +306,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.
@@ -248,67 +322,6 @@ public:
void
interrupt_all_sleep_for();
/// Get a handle to the guard condition which is triggered when interrupted.
/**
* This guard condition is triggered any time interrupt_all_wait_sets() is
* called, which may be called by the user, or shutdown().
* And in turn, shutdown() may be called by the user, the destructor of this
* context, or the signal handler if installed and shutdown_on_sigint is true
* for this context.
*
* The first time that this function is called for a given wait set a new guard
* condition will be created and returned; thereafter the same guard condition
* will be returned for the same wait set.
* This mechanism is designed to ensure that the same guard condition is not
* reused across wait sets (e.g., when using multiple executors in the same
* process).
* This method will throw an exception if initialization of the guard
* condition fails.
*
* The returned guard condition needs to be released with the
* release_interrupt_guard_condition() method in order to reclaim resources.
*
* \param[in] wait_set Pointer to the rcl_wait_set_t that will be using the
* resulting guard condition.
* \return Pointer to the guard condition.
* \throws anything rclcpp::exceptions::throw_from_rcl_error can throw.
*/
RCLCPP_PUBLIC
rcl_guard_condition_t *
get_interrupt_guard_condition(rcl_wait_set_t * wait_set);
/// Release the previously allocated guard condition which is triggered when interrupted.
/**
* If you previously called get_interrupt_guard_condition() for a given wait
* set to get a interrupt guard condition, then you should call
* release_interrupt_guard_condition() when you're done, to free that
* condition.
* Will throw an exception if get_interrupt_guard_condition() wasn't
* previously called for the given wait set.
*
* After calling this, the pointer returned by get_interrupt_guard_condition()
* for the given wait_set is invalid.
*
* \param[in] wait_set Pointer to the rcl_wait_set_t that was using the
* resulting guard condition.
* \throws anything rclcpp::exceptions::throw_from_rcl_error can throw.
* \throws std::runtime_error if a nonexistent wait set is trying to release sigint guard condition.
*/
RCLCPP_PUBLIC
void
release_interrupt_guard_condition(rcl_wait_set_t * wait_set);
/// Nothrow version of release_interrupt_guard_condition(), logs to RCLCPP_ERROR instead.
RCLCPP_PUBLIC
void
release_interrupt_guard_condition(rcl_wait_set_t * wait_set, const std::nothrow_t &) noexcept;
/// Interrupt any blocking executors, or wait sets associated with this context.
RCLCPP_PUBLIC
virtual
void
interrupt_all_wait_sets();
/// Return a singleton instance for the SubContext type, constructing one if necessary.
template<typename SubContext, typename ... Args>
std::shared_ptr<SubContext>
@@ -347,7 +360,7 @@ private:
// This mutex is recursive so that the destructor can ensure atomicity
// between is_initialized and shutdown.
std::recursive_mutex init_mutex_;
mutable std::recursive_mutex init_mutex_;
std::shared_ptr<rcl_context_t> rcl_context_;
rclcpp::InitOptions init_options_;
std::string shutdown_reason_;
@@ -360,21 +373,42 @@ 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::unordered_set<std::shared_ptr<OnShutdownCallback>> on_shutdown_callbacks_;
mutable std::mutex on_shutdown_callbacks_mutex_;
std::unordered_set<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_;
/// Mutex for protecting the global condition variable.
std::mutex interrupt_mutex_;
/// Mutex to protect sigint_guard_cond_handles_.
std::mutex interrupt_guard_cond_handles_mutex_;
/// Guard conditions for interrupting of associated wait sets on interrupt_all_wait_sets().
std::unordered_map<rcl_wait_set_t *, rcl_guard_condition_t> interrupt_guard_cond_handles_;
/// 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;
RCLCPP_LOCAL
ShutdownCallbackHandle
add_shutdown_callback(
ShutdownType shutdown_type,
ShutdownCallback callback);
RCLCPP_LOCAL
bool
remove_shutdown_callback(
ShutdownType shutdown_type,
const ShutdownCallbackHandle & callback_handle);
std::vector<rclcpp::Context::ShutdownCallback>
get_shutdown_callback(ShutdownType shutdown_type) const;
};
/// Return a copy of the list of context shared pointers.

View File

@@ -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

View 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_

View 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_

View File

@@ -17,6 +17,7 @@
#include <memory>
#include <string>
#include <utility>
#include "rclcpp/node_interfaces/get_node_topics_interface.hpp"
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
@@ -24,15 +25,65 @@
#include "rclcpp/publisher_factory.hpp"
#include "rclcpp/publisher_options.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/qos_overriding_options.hpp"
#include "rclcpp/detail/qos_parameters.hpp"
#include "rmw/qos_profiles.h"
namespace rclcpp
{
namespace detail
{
/// Create and return a publisher of the given MessageT type.
template<
typename MessageT,
typename AllocatorT = std::allocator<void>,
typename PublisherT = rclcpp::Publisher<MessageT, AllocatorT>,
typename NodeParametersT,
typename NodeTopicsT>
std::shared_ptr<PublisherT>
create_publisher(
NodeParametersT & node_parameters,
NodeTopicsT & node_topics,
const std::string & topic_name,
const rclcpp::QoS & qos,
const rclcpp::PublisherOptionsWithAllocator<AllocatorT> & options = (
rclcpp::PublisherOptionsWithAllocator<AllocatorT>()
)
)
{
auto node_topics_interface = rclcpp::node_interfaces::get_node_topics_interface(node_topics);
const rclcpp::QoS & actual_qos = options.qos_overriding_options.get_policy_kinds().size() ?
rclcpp::detail::declare_qos_parameters(
options.qos_overriding_options, node_parameters,
node_topics_interface->resolve_topic_name(topic_name),
qos, rclcpp::detail::PublisherQosParametersTraits{}) :
qos;
// Create the publisher.
auto pub = node_topics_interface->create_publisher(
topic_name,
rclcpp::create_publisher_factory<MessageT, AllocatorT, PublisherT>(options),
actual_qos
);
// Add the publisher to the node topics interface.
node_topics_interface->add_publisher(pub, options.callback_group);
return std::dynamic_pointer_cast<PublisherT>(pub);
}
} // namespace detail
/// Create and return a publisher of the given MessageT type.
/**
* The NodeT type only needs to have a method called get_node_topics_interface()
* which returns a shared_ptr to a NodeTopicsInterface.
*
* In case `options.qos_overriding_options` is enabling qos parameter overrides,
* NodeT must also have a method called get_node_parameters_interface()
* which returns a shared_ptr to a NodeParametersInterface.
*/
template<
typename MessageT,
@@ -41,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 = (
@@ -49,21 +100,28 @@ create_publisher(
)
)
{
// Extract the NodeTopicsInterface from the NodeT.
using rclcpp::node_interfaces::get_node_topics_interface;
auto node_topics = get_node_topics_interface(node);
return detail::create_publisher<MessageT, AllocatorT, PublisherT>(
node, node, topic_name, qos, options);
}
// Create the publisher.
auto pub = node_topics->create_publisher(
topic_name,
rclcpp::create_publisher_factory<MessageT, AllocatorT, PublisherT>(options),
qos
);
// Add the publisher to the node topics interface.
node_topics->add_publisher(pub, options.callback_group);
return std::dynamic_pointer_cast<PublisherT>(pub);
/// Create and return a publisher of the given MessageT type.
template<
typename MessageT,
typename AllocatorT = std::allocator<void>,
typename PublisherT = rclcpp::Publisher<MessageT, AllocatorT>>
std::shared_ptr<PublisherT>
create_publisher(
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr & node_parameters,
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr & node_topics,
const std::string & topic_name,
const rclcpp::QoS & qos,
const rclcpp::PublisherOptionsWithAllocator<AllocatorT> & options = (
rclcpp::PublisherOptionsWithAllocator<AllocatorT>()
)
)
{
return detail::create_publisher<MessageT, AllocatorT, PublisherT>(
node_parameters, node_topics, topic_name, qos, options);
}
} // namespace rclcpp

View File

@@ -41,16 +41,118 @@
namespace rclcpp
{
namespace detail
{
template<
typename MessageT,
typename CallbackT,
typename AllocatorT,
typename SubscriptionT,
typename MessageMemoryStrategyT,
typename NodeParametersT,
typename NodeTopicsT,
typename ROSMessageType = typename SubscriptionT::ROSMessageType>
typename std::shared_ptr<SubscriptionT>
create_subscription(
NodeParametersT & node_parameters,
NodeTopicsT & node_topics,
const std::string & topic_name,
const rclcpp::QoS & qos,
CallbackT && callback,
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options = (
rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>()
),
typename MessageMemoryStrategyT::SharedPtr msg_mem_strat = (
MessageMemoryStrategyT::create_default()
)
)
{
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<ROSMessageType>>
subscription_topic_stats = nullptr;
if (rclcpp::detail::resolve_enable_topic_statistics(
options,
*node_topics_interface->get_node_base_interface()))
{
if (options.topic_stats_options.publish_period <= std::chrono::milliseconds(0)) {
throw std::invalid_argument(
"topic_stats_options.publish_period must be greater than 0, specified value of " +
std::to_string(options.topic_stats_options.publish_period.count()) +
" ms");
}
std::shared_ptr<Publisher<statistics_msgs::msg::MetricsMessage>>
publisher = rclcpp::detail::create_publisher<statistics_msgs::msg::MetricsMessage>(
node_parameters,
node_topics_interface,
options.topic_stats_options.publish_topic,
qos);
subscription_topic_stats = std::make_shared<
rclcpp::topic_statistics::SubscriptionTopicStatistics<ROSMessageType>
>(node_topics_interface->get_node_base_interface()->get_name(), publisher);
std::weak_ptr<
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();
if (subscription_topic_stats) {
subscription_topic_stats->publish_message_and_reset_measurements();
}
};
auto node_timer_interface = node_topics_interface->get_node_timers_interface();
auto timer = create_wall_timer(
std::chrono::duration_cast<std::chrono::nanoseconds>(
options.topic_stats_options.publish_period),
sub_call_back,
options.callback_group,
node_topics_interface->get_node_base_interface(),
node_timer_interface
);
subscription_topic_stats->set_publisher_timer(timer);
}
auto factory = rclcpp::create_subscription_factory<MessageT>(
std::forward<CallbackT>(callback),
options,
msg_mem_strat,
subscription_topic_stats
);
const rclcpp::QoS & actual_qos = options.qos_overriding_options.get_policy_kinds().size() ?
rclcpp::detail::declare_qos_parameters(
options.qos_overriding_options, node_parameters,
node_topics_interface->resolve_topic_name(topic_name),
qos, rclcpp::detail::SubscriptionQosParametersTraits{}) :
qos;
auto sub = node_topics_interface->create_subscription(topic_name, factory, actual_qos);
node_topics_interface->add_subscription(sub, options.callback_group);
return std::dynamic_pointer_cast<SubscriptionT>(sub);
}
} // namespace detail
/// Create and return a subscription of the given MessageT type.
/**
* The NodeT type only needs to have a method called get_node_topics_interface()
* which returns a shared_ptr to a NodeTopicsInterface, or be a
* NodeTopicsInterface pointer itself.
*
* In case `options.qos_overriding_options` is enabling qos parameter overrides,
* NodeT must also have a method called get_node_parameters_interface()
* which returns a shared_ptr to a NodeParametersInterface.
*
* \tparam MessageT
* \tparam CallbackT
* \tparam AllocatorT
* \tparam CallbackMessageT
* \tparam SubscriptionT
* \tparam MessageMemoryStrategyT
* \tparam NodeT
@@ -68,17 +170,12 @@ 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(
NodeT && node,
NodeT & node,
const std::string & topic_name,
const rclcpp::QoS & qos,
CallbackT && callback,
@@ -90,68 +187,40 @@ create_subscription(
)
)
{
using rclcpp::node_interfaces::get_node_topics_interface;
auto node_topics = get_node_topics_interface(std::forward<NodeT>(node));
return rclcpp::detail::create_subscription<
MessageT, CallbackT, AllocatorT, SubscriptionT, MessageMemoryStrategyT>(
node, node, topic_name, qos, std::forward<CallbackT>(callback), options, msg_mem_strat);
}
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics<CallbackMessageT>>
subscription_topic_stats = nullptr;
if (rclcpp::detail::resolve_enable_topic_statistics(
options,
*node_topics->get_node_base_interface()))
{
if (options.topic_stats_options.publish_period <= std::chrono::milliseconds(0)) {
throw std::invalid_argument(
"topic_stats_options.publish_period must be greater than 0, specified value of " +
std::to_string(options.topic_stats_options.publish_period.count()) +
" ms");
}
std::shared_ptr<Publisher<statistics_msgs::msg::MetricsMessage>> publisher =
create_publisher<statistics_msgs::msg::MetricsMessage>(
node,
options.topic_stats_options.publish_topic,
qos);
subscription_topic_stats = std::make_shared<
rclcpp::topic_statistics::SubscriptionTopicStatistics<CallbackMessageT>
>(node_topics->get_node_base_interface()->get_name(), publisher);
std::weak_ptr<
rclcpp::topic_statistics::SubscriptionTopicStatistics<CallbackMessageT>
> weak_subscription_topic_stats(subscription_topic_stats);
auto sub_call_back = [weak_subscription_topic_stats]() {
auto subscription_topic_stats = weak_subscription_topic_stats.lock();
if (subscription_topic_stats) {
subscription_topic_stats->publish_message();
}
};
auto node_timer_interface = node_topics->get_node_timers_interface();
auto timer = create_wall_timer(
std::chrono::duration_cast<std::chrono::nanoseconds>(
options.topic_stats_options.publish_period),
sub_call_back,
options.callback_group,
node_topics->get_node_base_interface(),
node_timer_interface
);
subscription_topic_stats->set_publisher_timer(timer);
}
auto factory = rclcpp::create_subscription_factory<MessageT>(
std::forward<CallbackT>(callback),
options,
msg_mem_strat,
subscription_topic_stats
);
auto sub = node_topics->create_subscription(topic_name, factory, qos);
node_topics->add_subscription(sub, options.callback_group);
return std::dynamic_pointer_cast<SubscriptionT>(sub);
/// Create and return a subscription of the given MessageT type.
/**
* See \ref create_subscription().
*/
template<
typename MessageT,
typename CallbackT,
typename AllocatorT = std::allocator<void>,
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,
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr & node_topics,
const std::string & topic_name,
const rclcpp::QoS & qos,
CallbackT && callback,
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options = (
rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>()
),
typename MessageMemoryStrategyT::SharedPtr msg_mem_strat = (
MessageMemoryStrategyT::create_default()
)
)
{
return rclcpp::detail::create_subscription<
MessageT, CallbackT, AllocatorT, SubscriptionT, MessageMemoryStrategyT>(
node_parameters, node_topics, topic_name, qos,
std::forward<CallbackT>(callback), options, msg_mem_strat);
}
} // namespace rclcpp

View File

@@ -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_

View File

@@ -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__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 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 UserDataT,
typename ... Args,
typename ReturnT = void
>
ReturnT
cpp_callback_trampoline(UserDataT user_data, Args ... args) noexcept
{
auto & actual_callback = *reinterpret_cast<const std::function<ReturnT(Args...)> *>(user_data);
return actual_callback(args ...);
}
} // namespace detail
} // namespace rclcpp
#endif // RCLCPP__DETAIL__CPP_CALLBACK_TRAMPOLINE_HPP_

View File

@@ -0,0 +1,340 @@
// Copyright 2020 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__QOS_PARAMETERS_HPP_
#define RCLCPP__DETAIL__QOS_PARAMETERS_HPP_
#include <algorithm>
#include <array>
#include <functional>
#include <initializer_list>
#include <map>
#include <string>
#include <type_traits>
#include <vector>
#include "rcl_interfaces/msg/parameter_descriptor.hpp"
#include "rcpputils/pointer_traits.hpp"
#include "rmw/qos_string_conversions.h"
#include "rclcpp/duration.hpp"
#include "rclcpp/node_interfaces/get_node_parameters_interface.hpp"
#include "rclcpp/node_interfaces/node_parameters_interface.hpp"
#include "rclcpp/qos_overriding_options.hpp"
namespace rclcpp
{
namespace detail
{
/// \internal Trait used to specialize `declare_qos_parameters()` for publishers.
struct PublisherQosParametersTraits
{
static constexpr const char * entity_type() {return "publisher";}
static constexpr auto allowed_policies()
{
return std::array<::rclcpp::QosPolicyKind, 9> {
QosPolicyKind::AvoidRosNamespaceConventions,
QosPolicyKind::Deadline,
QosPolicyKind::Durability,
QosPolicyKind::History,
QosPolicyKind::Depth,
QosPolicyKind::Lifespan,
QosPolicyKind::Liveliness,
QosPolicyKind::LivelinessLeaseDuration,
QosPolicyKind::Reliability,
};
}
};
/// \internal Trait used to specialize `declare_qos_parameters()` for subscriptions.
struct SubscriptionQosParametersTraits
{
static constexpr const char * entity_type() {return "subscription";}
static constexpr auto allowed_policies()
{
return std::array<::rclcpp::QosPolicyKind, 8> {
QosPolicyKind::AvoidRosNamespaceConventions,
QosPolicyKind::Deadline,
QosPolicyKind::Durability,
QosPolicyKind::History,
QosPolicyKind::Depth,
QosPolicyKind::Liveliness,
QosPolicyKind::LivelinessLeaseDuration,
QosPolicyKind::Reliability,
};
}
};
/// \internal Returns the given `policy` of the profile `qos` converted to a parameter value.
inline
::rclcpp::ParameterValue
get_default_qos_param_value(rclcpp::QosPolicyKind policy, const rclcpp::QoS & qos);
/// \internal Modify the given `policy` in `qos` to be `value`.
inline
void
apply_qos_override(
rclcpp::QosPolicyKind policy, rclcpp::ParameterValue value, rclcpp::QoS & qos);
inline
rclcpp::ParameterValue
declare_parameter_or_get(
rclcpp::node_interfaces::NodeParametersInterface & parameters_interface,
const std::string & param_name,
rclcpp::ParameterValue param_value,
rcl_interfaces::msg::ParameterDescriptor descriptor)
{
try {
return parameters_interface.declare_parameter(
param_name, param_value, descriptor);
} catch (const rclcpp::exceptions::ParameterAlreadyDeclaredException &) {
return parameters_interface.get_parameter(param_name).get_parameter_value();
}
}
#ifdef DOXYGEN_ONLY
/// \internal Declare QoS parameters for the given entity.
/**
* \tparam NodeT Node pointer or reference type.
* \tparam EntityQosParametersTraits A class with two static methods: `entity_type()` and
* `allowed_policies()`. See `PublisherQosParametersTraits` and `SubscriptionQosParametersTraits`.
* \param options User provided options that indicate if QoS parameter overrides should be
* declared or not, which policy can have overrides, and optionally a callback to validate the profile.
* \param node Parameters will be declared using this node.
* \param topic_name Name of the topic of the entity.
* \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<
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::QoS>
declare_qos_parameters(
const ::rclcpp::QosOverridingOptions & options,
NodeT & node,
const std::string & topic_name,
const ::rclcpp::QoS & default_qos,
EntityQosParametersTraits)
{
auto & parameters_interface = *rclcpp::node_interfaces::get_node_parameters_interface(node);
std::string param_prefix;
const auto & id = options.get_id();
{
std::ostringstream oss{"qos_overrides.", std::ios::ate};
oss << topic_name << "." << EntityQosParametersTraits::entity_type();
if (!id.empty()) {
oss << "_" << id;
}
oss << ".";
param_prefix = oss.str();
}
std::string param_description_suffix;
{
std::ostringstream oss{"} for ", std::ios::ate};
oss << EntityQosParametersTraits::entity_type() << " {" << topic_name << "}";
if (!id.empty()) {
oss << " with id {" << id << "}";
}
param_description_suffix = oss.str();
}
rclcpp::QoS qos = default_qos;
for (auto policy : EntityQosParametersTraits::allowed_policies()) {
if (
std::count(options.get_policy_kinds().begin(), options.get_policy_kinds().end(), policy))
{
std::ostringstream param_name{param_prefix, std::ios::ate};
param_name << qos_policy_kind_to_cstr(policy);
std::ostringstream param_desciption{"qos policy {", std::ios::ate};
param_desciption << qos_policy_kind_to_cstr(policy) << param_description_suffix;
rcl_interfaces::msg::ParameterDescriptor descriptor{};
descriptor.description = param_desciption.str();
descriptor.read_only = true;
auto value = declare_parameter_or_get(
parameters_interface, param_name.str(),
get_default_qos_param_value(policy, qos), descriptor);
::rclcpp::detail::apply_qos_override(policy, value, qos);
}
}
const auto & validation_callback = options.get_validation_callback();
if (validation_callback) {
auto result = validation_callback(qos);
if (!result.successful) {
throw rclcpp::exceptions::InvalidQosOverridesException{
"validation callback failed: " + result.reason};
}
}
return qos;
}
// TODO(ivanpauno): This overload cannot declare the QoS parameters, as a node parameters interface
// was not provided.
template<typename NodeT, typename EntityQosParametersTraits>
std::enable_if_t<
!(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::QoS>
declare_qos_parameters(
const ::rclcpp::QosOverridingOptions & options,
NodeT &,
const std::string &,
const ::rclcpp::QoS & default_qos,
EntityQosParametersTraits)
{
if (options.get_policy_kinds().size()) {
std::runtime_error exc{
"passed non-default qos overriding options without providing a parameters interface"};
throw exc;
}
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) \
do { \
auto policy_string = (parameter_value).get<std::string>(); \
auto policy_value = rmw_qos_ ## kind_lower ## _policy_from_str(policy_string.c_str()); \
if (RMW_QOS_POLICY_ ## kind_upper ## _UNKNOWN == policy_value) { \
throw std::invalid_argument{"unknown QoS policy " #kind_lower " value: " + policy_string}; \
} \
((rclcpp_qos).kind_lower)(policy_value); \
} while (0)
inline
void
apply_qos_override(
rclcpp::QosPolicyKind policy, rclcpp::ParameterValue value, rclcpp::QoS & qos)
{
switch (policy) {
case QosPolicyKind::AvoidRosNamespaceConventions:
qos.avoid_ros_namespace_conventions(value.get<bool>());
break;
case QosPolicyKind::Deadline:
qos.deadline(::rclcpp::Duration::from_nanoseconds(value.get<int64_t>()));
break;
case QosPolicyKind::Durability:
RCLCPP_DETAIL_APPLY_QOS_OVERRIDE_FROM_PARAMETER_STRING(
durability, DURABILITY, value, qos);
break;
case QosPolicyKind::History:
RCLCPP_DETAIL_APPLY_QOS_OVERRIDE_FROM_PARAMETER_STRING(
history, HISTORY, value, qos);
break;
case QosPolicyKind::Depth:
qos.get_rmw_qos_profile().depth = static_cast<size_t>(value.get<int64_t>());
break;
case QosPolicyKind::Lifespan:
qos.lifespan(::rclcpp::Duration::from_nanoseconds(value.get<int64_t>()));
break;
case QosPolicyKind::Liveliness:
RCLCPP_DETAIL_APPLY_QOS_OVERRIDE_FROM_PARAMETER_STRING(
liveliness, LIVELINESS, value, qos);
break;
case QosPolicyKind::LivelinessLeaseDuration:
qos.liveliness_lease_duration(::rclcpp::Duration::from_nanoseconds(value.get<int64_t>()));
break;
case QosPolicyKind::Reliability:
RCLCPP_DETAIL_APPLY_QOS_OVERRIDE_FROM_PARAMETER_STRING(
reliability, RELIABILITY, value, qos);
break;
default:
throw std::invalid_argument{"unknown QosPolicyKind"};
}
}
/// Convert `rmw_time_t` to `int64_t` that can be used as a parameter value.
inline
int64_t
rmw_duration_to_int64_t(rmw_time_t rmw_duration)
{
return ::rclcpp::Duration(
static_cast<int32_t>(rmw_duration.sec),
static_cast<uint32_t>(rmw_duration.nsec)
).nanoseconds();
}
/// \internal Throw an exception if `policy_value_stringified` is NULL.
inline
const char *
check_if_stringified_policy_is_null(const char * policy_value_stringified, QosPolicyKind kind)
{
if (!policy_value_stringified) {
std::ostringstream oss{"unknown value for policy kind {", std::ios::ate};
oss << kind << "}";
throw std::invalid_argument{oss.str()};
}
return policy_value_stringified;
}
inline
::rclcpp::ParameterValue
get_default_qos_param_value(rclcpp::QosPolicyKind kind, const rclcpp::QoS & qos)
{
using ParameterValue = ::rclcpp::ParameterValue;
const auto & rmw_qos = qos.get_rmw_qos_profile();
switch (kind) {
case QosPolicyKind::AvoidRosNamespaceConventions:
return ParameterValue(rmw_qos.avoid_ros_namespace_conventions);
case QosPolicyKind::Deadline:
return ParameterValue(rmw_duration_to_int64_t(rmw_qos.deadline));
case QosPolicyKind::Durability:
return ParameterValue(
check_if_stringified_policy_is_null(
rmw_qos_durability_policy_to_str(rmw_qos.durability), kind));
case QosPolicyKind::History:
return ParameterValue(
check_if_stringified_policy_is_null(
rmw_qos_history_policy_to_str(rmw_qos.history), kind));
case QosPolicyKind::Depth:
return ParameterValue(static_cast<int64_t>(rmw_qos.depth));
case QosPolicyKind::Lifespan:
return ParameterValue(rmw_duration_to_int64_t(rmw_qos.lifespan));
case QosPolicyKind::Liveliness:
return ParameterValue(
check_if_stringified_policy_is_null(
rmw_qos_liveliness_policy_to_str(rmw_qos.liveliness), kind));
case QosPolicyKind::LivelinessLeaseDuration:
return ParameterValue(rmw_duration_to_int64_t(rmw_qos.liveliness_lease_duration));
case QosPolicyKind::Reliability:
return ParameterValue(
check_if_stringified_policy_is_null(
rmw_qos_reliability_policy_to_str(rmw_qos.reliability), kind));
default:
throw std::invalid_argument{"unknown QoS policy kind"};
}
}
} // namespace detail
} // namespace rclcpp
#endif // RCLCPP__DETAIL__QOS_PARAMETERS_HPP_

View File

@@ -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_

View File

@@ -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);

View File

@@ -38,10 +38,7 @@ public:
*/
Duration(int32_t seconds, uint32_t nanoseconds);
// This constructor matches any numeric value - ints or floats.
explicit Duration(rcl_duration_value_t nanoseconds);
// This constructor matches std::chrono::nanoseconds.
/// Construct duration from the specified std::chrono::nanoseconds.
explicit Duration(std::chrono::nanoseconds nanoseconds);
// This constructor matches any std::chrono value other than nanoseconds
@@ -129,6 +126,13 @@ public:
static Duration
from_seconds(double seconds);
/// Create a duration object from an integer number representing nanoseconds
static Duration
from_nanoseconds(rcl_duration_value_t nanoseconds);
static Duration
from_rmw_time(rmw_time_t duration);
/// Convert Duration into a std::chrono::Duration.
template<class DurationT>
DurationT
@@ -143,6 +147,8 @@ public:
private:
rcl_duration_t rcl_duration_;
Duration() = default;
};
} // namespace rclcpp

View File

@@ -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,6 +301,33 @@ class ParameterModifiedInCallbackException : public std::runtime_error
using std::runtime_error::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.
*/
explicit ParameterUninitializedException(const std::string & name)
: std::runtime_error("parameter '" + name + "' is not initialized")
{}
};
/// Thrown if the QoS overrides provided aren't valid.
class InvalidQosOverridesException : public std::runtime_error
{
// Inherit constructors from runtime_error.
using std::runtime_error::runtime_error;
};
/// Thrown if a QoS compatibility check fails.
class QoSCheckCompatibleException : public std::runtime_error
{
// Inherit constructors from runtime_error.
using std::runtime_error::runtime_error;
};
} // namespace exceptions
} // namespace rclcpp

View File

@@ -29,8 +29,11 @@
#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"
#include "rclcpp/future_return_code.hpp"
#include "rclcpp/memory_strategies.hpp"
@@ -38,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
{
@@ -303,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.
*/
@@ -352,7 +356,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);
@@ -399,6 +403,15 @@ 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:
RCLCPP_PUBLIC
void
@@ -447,19 +460,20 @@ protected:
RCLCPP_PUBLIC
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr
get_node_by_group(
WeakCallbackGroupsToNodesMap weak_groups_to_nodes,
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes,
rclcpp::CallbackGroup::SharedPtr group);
/// 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
bool
has_node(
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
WeakCallbackGroupsToNodesMap weak_groups_to_nodes) const;
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes) const;
RCLCPP_PUBLIC
rclcpp::CallbackGroup::SharedPtr
@@ -475,7 +489,7 @@ protected:
rclcpp::CallbackGroup::SharedPtr group_ptr,
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
WeakCallbackGroupsToNodesMap & weak_groups_to_nodes,
bool notify = true);
bool notify = true) RCPPUTILS_TSA_REQUIRES(mutex_);
/// Remove a callback group from the executor.
/**
@@ -486,7 +500,7 @@ protected:
remove_callback_group_from_map(
rclcpp::CallbackGroup::SharedPtr group_ptr,
WeakCallbackGroupsToNodesMap & weak_groups_to_nodes,
bool notify = true);
bool notify = true) RCPPUTILS_TSA_REQUIRES(mutex_);
RCLCPP_PUBLIC
bool
@@ -496,7 +510,7 @@ protected:
bool
get_next_ready_executable_from_map(
AnyExecutable & any_executable,
WeakCallbackGroupsToNodesMap weak_groups_to_nodes);
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes);
RCLCPP_PUBLIC
bool
@@ -517,22 +531,25 @@ protected:
*/
RCLCPP_PUBLIC
virtual void
add_callback_groups_from_nodes_associated_to_executor();
add_callback_groups_from_nodes_associated_to_executor() RCPPUTILS_TSA_REQUIRES(mutex_);
/// Spinning state, used to prevent multi threaded calls to spin and to cancel blocking spins.
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_;
/// Wait set for managing entities that the rmw layer waits on.
rcl_wait_set_t wait_set_ = rcl_get_zero_initialized_wait_set();
// Mutex to protect the subsequent memory_strategy_.
std::mutex memory_strategy_mutex_;
mutable std::mutex mutex_;
/// The memory strategy: an interface for handling user-defined memory allocation strategies.
memory_strategy::MemoryStrategy::SharedPtr memory_strategy_;
memory_strategy::MemoryStrategy::SharedPtr
memory_strategy_ RCPPUTILS_TSA_PT_GUARDED_BY(mutex_);
/// The context associated with this executor.
std::shared_ptr<rclcpp::Context> context_;
@@ -540,36 +557,38 @@ 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 *,
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_;
/// 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_;
WeakCallbackGroupsToNodesMap
weak_groups_associated_with_executor_to_nodes_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
/// maps callback groups to nodes associated with executor
WeakCallbackGroupsToNodesMap weak_groups_to_nodes_associated_with_executor_;
WeakCallbackGroupsToNodesMap
weak_groups_to_nodes_associated_with_executor_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
/// maps all callback groups to nodes
WeakCallbackGroupsToNodesMap weak_groups_to_nodes_;
WeakCallbackGroupsToNodesMap
weak_groups_to_nodes_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
/// nodes that are associated with the executor
std::list<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr> weak_nodes_;
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_

View File

@@ -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_

View File

@@ -52,7 +52,7 @@ public:
* \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,
@@ -85,8 +85,6 @@ private:
size_t number_of_threads_;
bool yield_before_execute_;
std::chrono::nanoseconds next_exec_timeout_;
std::set<TimerBase::SharedPtr> scheduled_timers_;
};
} // namespace executors

View File

@@ -57,24 +57,36 @@ 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();
/// Execute the waitable.
RCLCPP_PUBLIC
void
execute() override;
execute(std::shared_ptr<void> & data) override;
/// Take the data so that it can be consumed with `execute`.
/**
* For `StaticExecutorEntitiesCollector`, this always return `nullptr`.
* \sa rclcpp::Waitable::take_data()
*/
RCLCPP_PUBLIC
std::shared_ptr<void>
take_data() override;
/// Function to add_handles_to_wait_set and wait for work and
/**
@@ -90,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
@@ -287,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
@@ -316,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_;
@@ -324,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

View File

@@ -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)

View File

@@ -16,6 +16,7 @@
#define RCLCPP__EXPERIMENTAL__BUFFERS__INTRA_PROCESS_BUFFER_HPP_
#include <memory>
#include <stdexcept>
#include <type_traits>
#include <utility>

View File

@@ -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_]);

View File

@@ -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;

View File

@@ -15,7 +15,6 @@
#ifndef RCLCPP__EXPERIMENTAL__EXECUTABLE_LIST_HPP_
#define RCLCPP__EXPERIMENTAL__EXECUTABLE_LIST_HPP_
#include <memory>
#include <vector>
#include "rclcpp/client.hpp"

View File

@@ -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,12 +205,13 @@ 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)
{
// There is at maximum 1 buffer that does not require ownership.
// So we this case is equivalent to all the buffers requiring ownership
// So this case is equivalent to all the buffers requiring ownership
// Merge the two vector of ids into a unique one
std::vector<uint64_t> concatenated_vector(sub_ids.take_shared_subscriptions);
@@ -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::SharedPtr 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,65 +333,177 @@ 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;
auto subscription_base = subscription_it->second.lock();
if (subscription_base == nullptr) {
subscriptions_.erase(id);
continue;
}
auto subscription = std::static_pointer_cast<
rclcpp::experimental::SubscriptionIntraProcess<MessageT>
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;
}
subscription->provide_intra_process_message(message);
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;
auto subscription_base = subscription_it->second.lock();
if (subscription_base == nullptr) {
subscriptions_.erase(subscription_it);
continue;
}
auto subscription = std::static_pointer_cast<
rclcpp::experimental::SubscriptionIntraProcess<MessageT>
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_data(std::move(message));
} else {
// Copy the message since we have additional subscriptions to serve
Deleter deleter = message.get_deleter();
auto ptr = MessageAllocTraits::allocate(allocator, 1);
MessageAllocTraits::construct(allocator, ptr, *message);
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(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 {
// 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);
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));
} 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);
subscription->provide_intra_process_message(std::move(copy_message));
ros_message_subscription->provide_intra_process_message(
std::move(MessageUniquePtr(ptr, deleter)));
}
}
}
}
}

View File

@@ -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_

View File

@@ -15,21 +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 <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
@@ -39,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),
@@ -102,82 +99,79 @@ public:
#endif
}
~SubscriptionIntraProcess()
virtual ~SubscriptionIntraProcess() = default;
std::shared_ptr<void>
take_data() override
{
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);
ConstMessageSharedPtr shared_msg;
MessageUniquePtr unique_msg;
if (any_callback_.use_take_shared_method()) {
shared_msg = this->buffer_->consume_shared();
if (!shared_msg) {
return nullptr;
}
} else {
unique_msg = this->buffer_->consume_unique();
if (!unique_msg) {
return nullptr;
}
}
if (this->buffer_->has_data()) {
// If there is data still to be processed, indicate to the
// executor or waitset by triggering the guard condition.
this->trigger_guard_condition();
}
return std::static_pointer_cast<void>(
std::make_shared<std::pair<ConstMessageSharedPtr, MessageUniquePtr>>(
std::pair<ConstMessageSharedPtr, MessageUniquePtr>(
shared_msg, std::move(unique_msg)))
);
}
bool
is_ready(rcl_wait_set_t * wait_set)
void execute(std::shared_ptr<void> & data) override
{
(void)wait_set;
return buffer_->has_data();
}
void execute()
{
execute_impl<CallbackMessageT>();
}
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()
execute_impl(std::shared_ptr<void> & data)
{
(void)data;
throw std::runtime_error("Subscription intra-process can't handle serialized messages");
}
template<class T>
typename std::enable_if<!std::is_same<T, rcl_serialized_message_t>::value, void>::type
execute_impl()
execute_impl(std::shared_ptr<void> & data)
{
if (!data) {
return;
}
rmw_message_info_t msg_info;
msg_info.publisher_gid = {0, {0}};
msg_info.from_intra_process = true;
auto shared_ptr = std::static_pointer_cast<std::pair<ConstMessageSharedPtr, MessageUniquePtr>>(
data);
if (any_callback_.use_take_shared_method()) {
ConstMessageSharedPtr msg = buffer_->consume_shared();
any_callback_.dispatch_intra_process(msg, msg_info);
ConstMessageSharedPtr shared_msg = shared_ptr->first;
any_callback_.dispatch_intra_process(shared_msg, msg_info);
} else {
MessageUniquePtr msg = buffer_->consume_unique();
any_callback_.dispatch_intra_process(std::move(msg), msg_info);
MessageUniquePtr unique_msg = std::move(shared_ptr->second);
any_callback_.dispatch_intra_process(std::move(unique_msg), msg_info);
}
shared_ptr.reset();
}
AnySubscriptionCallback<CallbackMessageT, Alloc> any_callback_;
BufferUniquePtr buffer_;
AnySubscriptionCallback<MessageT, Alloc> any_callback_;
};
} // namespace experimental

View File

@@ -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,28 +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)
{}
virtual ~SubscriptionIntraProcessBase() = default;
RCLCPP_PUBLIC
virtual ~SubscriptionIntraProcessBase();
RCLCPP_PUBLIC
size_t
get_number_of_ready_guard_conditions() {return 1;}
get_number_of_ready_guard_conditions() override {return 1;}
RCLCPP_PUBLIC
void
add_to_wait_set(rcl_wait_set_t * wait_set) override;
bool
add_to_wait_set(rcl_wait_set_t * wait_set);
is_ready(rcl_wait_set_t * wait_set) override = 0;
virtual bool
is_ready(rcl_wait_set_t * wait_set) = 0;
std::shared_ptr<void>
take_data() override = 0;
virtual void
execute() = 0;
std::shared_ptr<void>
take_data_by_entity_id(size_t id) override
{
(void)id;
return take_data();
}
virtual bool
void
execute(std::shared_ptr<void> & data) override = 0;
virtual
bool
use_take_shared_method() const = 0;
RCLCPP_PUBLIC
@@ -67,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

View File

@@ -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_

View File

@@ -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

View File

@@ -0,0 +1,143 @@
// 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)),
ts_lib_(ts_lib)
{
// This is unfortunately duplicated with the code in publisher.hpp.
// TODO(nnmm): Deduplicate by moving this into PublisherBase.
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
}
}
}
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_

View File

@@ -0,0 +1,168 @@
// 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.template to_rcl_subscription_options<rclcpp::SerializedMessage>(qos),
true),
callback_(callback),
ts_lib_(ts_lib)
{
// This is unfortunately duplicated with the code in subscription.hpp.
// TODO(nnmm): Deduplicate by moving this into SubscriptionBase.
if (options.event_callbacks.deadline_callback) {
this->add_event_handler(
options.event_callbacks.deadline_callback,
RCL_SUBSCRIPTION_REQUESTED_DEADLINE_MISSED);
}
if (options.event_callbacks.liveliness_callback) {
this->add_event_handler(
options.event_callbacks.liveliness_callback,
RCL_SUBSCRIPTION_LIVELINESS_CHANGED);
}
if (options.event_callbacks.incompatible_qos_callback) {
this->add_event_handler(
options.event_callbacks.incompatible_qos_callback,
RCL_SUBSCRIPTION_REQUESTED_INCOMPATIBLE_QOS);
} else if (options.use_default_callbacks) {
// Register default callback when not specified
try {
this->add_event_handler(
[this](QOSRequestedIncompatibleQoSInfo & info) {
this->default_incompatible_qos_callback(info);
},
RCL_SUBSCRIPTION_REQUESTED_INCOMPATIBLE_QOS);
} catch (UnsupportedEventTypeException & /*exc*/) {
// pass
}
}
if (options.event_callbacks.message_lost_callback) {
this->add_event_handler(
options.event_callbacks.message_lost_callback,
RCL_SUBSCRIPTION_MESSAGE_LOST);
}
}
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;
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_

View 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_

View File

@@ -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"
@@ -63,7 +64,7 @@ class GraphListener : public std::enable_shared_from_this<GraphListener>
{
public:
RCLCPP_PUBLIC
explicit GraphListener(std::shared_ptr<rclcpp::Context> parent_context);
explicit GraphListener(const rclcpp::Context::SharedPtr & parent_context);
RCLCPP_PUBLIC
virtual ~GraphListener();
@@ -160,14 +161,23 @@ protected:
void
run_loop();
RCLCPP_PUBLIC
void
init_wait_set();
RCLCPP_PUBLIC
void
cleanup_wait_set();
private:
RCLCPP_DISABLE_COPY(GraphListener)
/** \internal */
void
__shutdown(bool);
__shutdown();
rclcpp::Context::WeakPtr parent_context_;
std::weak_ptr<rclcpp::Context> weak_parent_context_;
std::shared_ptr<rcl_context_t> rcl_parent_context_;
std::thread listener_thread_;
bool is_started_;
@@ -178,8 +188,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();
rcl_guard_condition_t * shutdown_guard_condition_;
rclcpp::GuardCondition interrupt_guard_condition_;
rcl_wait_set_t wait_set_ = rcl_get_zero_initialized_wait_set();
};

View File

@@ -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,6 +62,11 @@ 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 &
@@ -89,10 +98,27 @@ 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);
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

View File

@@ -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
/**

View 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_

View File

@@ -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.
/**
@@ -183,14 +188,30 @@ public:
/**
* A call to `release()` will unmanage the memory for the ROS message.
* That means that the destructor of this class will not free the memory on scope exit.
* If the message is loaned from the middleware but not be published, the user needs to call
* `rcl_return_loaned_message_from_publisher` manually.
* If the memory is from the local allocator, the memory is freed when the unique pointer
* goes out instead.
*
* \return Raw pointer to the message instance.
* \return std::unique_ptr to the message instance.
*/
MessageT * release()
std::unique_ptr<MessageT, std::function<void(MessageT *)>>
release()
{
auto msg = message_;
message_ = nullptr;
return msg;
if (pub_.can_loan_messages()) {
return std::unique_ptr<MessageT, std::function<void(MessageT *)>>(msg, [](MessageT *) {});
}
return std::unique_ptr<MessageT, std::function<void(MessageT *)>>(
msg,
[allocator = message_allocator_](MessageT * msg_ptr) mutable {
// call destructor before deallocating
msg_ptr->~MessageT();
allocator.deallocate(msg_ptr, 1);
});
}
protected:

View File

@@ -22,6 +22,7 @@
#include "rcl/node.h"
#include "rcutils/logging.h"
#include "rcpputils/filesystem_helper.hpp"
/**
* \def RCLCPP_LOGGING_ENABLED
@@ -75,6 +76,18 @@ RCLCPP_PUBLIC
Logger
get_node_logger(const rcl_node_t * node);
/// Get the current logging directory.
/**
* For more details of how the logging directory is determined,
* see rcl_logging_get_logging_directory().
*
* \returns the logging directory being used.
* \throws rclcpp::exceptions::RCLError if an unexpected error occurs.
*/
RCLCPP_PUBLIC
rcpputils::fs::path
get_logging_directory();
class Logger
{
public:

View File

@@ -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);
};

View 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_

View File

@@ -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.
/**
@@ -163,7 +172,7 @@ public:
* pub = node->create_publisher<MsgT>("chatter", QoS(10)); // implicitly KeepLast
* pub = node->create_publisher<MsgT>("chatter", QoS(KeepLast(10)));
* pub = node->create_publisher<MsgT>("chatter", QoS(KeepAll()));
* pub = node->create_publisher<MsgT>("chatter", QoS(1).best_effort().volatile());
* pub = node->create_publisher<MsgT>("chatter", QoS(1).best_effort().durability_volatile());
* {
* rclcpp::QoS custom_qos(KeepLast(10), rmw_qos_profile_sensor_data);
* pub = node->create_publisher<MsgT>("chatter", custom_qos);
@@ -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(
@@ -266,6 +270,55 @@ public:
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_services_default,
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.
@@ -305,16 +358,43 @@ public:
* name is invalid.
* \throws rclcpp::exceptions::InvalidParameterValueException if initial
* value fails to be set.
* \throws rclcpp::exceptions::InvalidParameterTypeException
* if the type of the default value or override is wrong.
*/
RCLCPP_PUBLIC
const rclcpp::ParameterValue &
declare_parameter(
const std::string & name,
const rclcpp::ParameterValue & default_value = rclcpp::ParameterValue(),
const rclcpp::ParameterValue & default_value,
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor =
rcl_interfaces::msg::ParameterDescriptor(),
bool ignore_override = false);
/// Declare and initialize a parameter, return the effective value.
/**
* Same as the previous one, but a default value is not provided and the user
* must provide a parameter override of the correct type.
*
* \param[in] name The name of the parameter.
* \param[in] type Desired type of the parameter, which will enforced at runtime.
* \param[in] parameter_descriptor An optional, custom description for
* the parameter.
* \param[in] ignore_override When `true`, the parameter override is ignored.
* Default to `false`.
* \return A const reference to the value of the parameter.
* \throws Same as the previous overload taking a default value.
* \throws rclcpp::exceptions::InvalidParameterTypeException
* if an override is not provided or the provided override is of the wrong type.
*/
RCLCPP_PUBLIC
const rclcpp::ParameterValue &
declare_parameter(
const std::string & name,
rclcpp::ParameterType type,
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor =
rcl_interfaces::msg::ParameterDescriptor{},
bool ignore_override = false);
/// Declare and initialize a parameter with a type.
/**
* See the non-templated declare_parameter() on this class for details.
@@ -345,6 +425,18 @@ public:
rcl_interfaces::msg::ParameterDescriptor(),
bool ignore_override = false);
/// Declare and initialize a parameter with a type.
/**
* See the non-templated declare_parameter() on this class for details.
*/
template<typename ParameterT>
auto
declare_parameter(
const std::string & name,
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor =
rcl_interfaces::msg::ParameterDescriptor(),
bool ignore_override = false);
/// Declare and initialize several parameters with the same namespace and type.
/**
* For each key in the map, a parameter with a name of "namespace.key"
@@ -612,6 +704,24 @@ 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
@@ -785,6 +895,9 @@ public:
*
* This allows the node developer to control which parameters may be changed.
*
* It is considered bad practice to reject changes for "unknown" parameters as this prevents
* other parts of the node (that may be aware of these parameters) from handling them.
*
* Note that the callback is called when declare_parameter() and its variants
* are called, and so you cannot assume the parameter has been set before
* this callback, so when checking a new value against the existing one, you
@@ -874,12 +987,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>>

View File

@@ -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>
@@ -152,6 +153,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(
@@ -172,6 +210,28 @@ Node::declare_parameter(
}
}
template<typename ParameterT>
auto
Node::declare_parameter(
const std::string & name,
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor,
bool ignore_override)
{
// get advantage of parameter value template magic to get
// the correct rclcpp::ParameterType from ParameterT
rclcpp::ParameterValue value{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>
std::vector<ParameterT>
Node::declare_parameters(
@@ -253,6 +313,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.

View File

@@ -15,11 +15,14 @@
#ifndef RCLCPP__NODE_INTERFACES__NODE_BASE_HPP_
#define RCLCPP__NODE_INTERFACES__NODE_BASE_HPP_
#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/macros.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
@@ -31,7 +34,7 @@ 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)
@@ -95,22 +98,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;
@@ -118,6 +124,10 @@ public:
bool
get_enable_topic_statistics_default() const override;
std::string
resolve_topic_or_service_name(
const std::string & name, bool is_service, bool only_expand = false) const override;
private:
RCLCPP_DISABLE_COPY(NodeBase)
@@ -128,13 +138,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_;
};

View File

@@ -24,6 +24,7 @@
#include "rclcpp/callback_group.hpp"
#include "rclcpp/context.hpp"
#include "rclcpp/guard_condition.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/visibility_control.hpp"
@@ -122,11 +123,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 +143,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
@@ -163,6 +165,13 @@ public:
virtual
bool
get_enable_topic_statistics_default() const = 0;
/// Expand and remap a given topic or service name.
RCLCPP_PUBLIC
virtual
std::string
resolve_topic_or_service_name(
const std::string & name, bool is_service, bool only_expand = false) const = 0;
};
} // namespace node_interfaces

View File

@@ -20,6 +20,7 @@
#include <memory>
#include <mutex>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
@@ -70,10 +71,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;

View File

@@ -20,6 +20,7 @@
#include <chrono>
#include <map>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
@@ -146,7 +147,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 +163,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 +175,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 +189,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 +357,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 +369,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

View File

@@ -108,8 +108,18 @@ public:
declare_parameter(
const std::string & name,
const rclcpp::ParameterValue & default_value,
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor,
bool ignore_override) override;
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor =
rcl_interfaces::msg::ParameterDescriptor{},
bool ignore_override = false) override;
RCLCPP_PUBLIC
const rclcpp::ParameterValue &
declare_parameter(
const std::string & name,
rclcpp::ParameterType type,
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor =
rcl_interfaces::msg::ParameterDescriptor(),
bool ignore_override = false) override;
RCLCPP_PUBLIC
void

View File

@@ -64,7 +64,21 @@ public:
const rclcpp::ParameterValue &
declare_parameter(
const std::string & name,
const rclcpp::ParameterValue & default_value = rclcpp::ParameterValue(),
const rclcpp::ParameterValue & default_value,
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor =
rcl_interfaces::msg::ParameterDescriptor(),
bool ignore_override = false) = 0;
/// Declare a parameter.
/**
* \sa rclcpp::Node::declare_parameter
*/
RCLCPP_PUBLIC
virtual
const rclcpp::ParameterValue &
declare_parameter(
const std::string & name,
rclcpp::ParameterType type,
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor =
rcl_interfaces::msg::ParameterDescriptor(),
bool ignore_override = false) = 0;
@@ -96,7 +110,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
*/

View File

@@ -15,6 +15,8 @@
#ifndef RCLCPP__NODE_INTERFACES__NODE_SERVICES_HPP_
#define RCLCPP__NODE_INTERFACES__NODE_SERVICES_HPP_
#include <string>
#include "rclcpp/callback_group.hpp"
#include "rclcpp/client.hpp"
#include "rclcpp/macros.hpp"
@@ -53,6 +55,10 @@ public:
rclcpp::ServiceBase::SharedPtr service_base_ptr,
rclcpp::CallbackGroup::SharedPtr group) override;
RCLCPP_PUBLIC
std::string
resolve_service_name(const std::string & name, bool only_expand = false) const override;
private:
RCLCPP_DISABLE_COPY(NodeServices)

View File

@@ -15,6 +15,8 @@
#ifndef RCLCPP__NODE_INTERFACES__NODE_SERVICES_INTERFACE_HPP_
#define RCLCPP__NODE_INTERFACES__NODE_SERVICES_INTERFACE_HPP_
#include <string>
#include "rclcpp/callback_group.hpp"
#include "rclcpp/client.hpp"
#include "rclcpp/macros.hpp"
@@ -49,6 +51,12 @@ public:
add_service(
rclcpp::ServiceBase::SharedPtr service_base_ptr,
rclcpp::CallbackGroup::SharedPtr group) = 0;
/// Get the remapped and expanded service name given a input name.
RCLCPP_PUBLIC
virtual
std::string
resolve_service_name(const std::string & name, bool only_expand = false) const = 0;
};
} // namespace node_interfaces

View File

@@ -48,7 +48,8 @@ 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
);
RCLCPP_PUBLIC

View File

@@ -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
@@ -81,6 +85,10 @@ public:
rclcpp::node_interfaces::NodeTimersInterface *
get_node_timers_interface() const override;
RCLCPP_PUBLIC
std::string
resolve_topic_name(const std::string & name, bool only_expand = false) const override;
private:
RCLCPP_DISABLE_COPY(NodeTopics)

View File

@@ -86,6 +86,12 @@ public:
virtual
rclcpp::node_interfaces::NodeTimersInterface *
get_node_timers_interface() const = 0;
/// Get a remapped and expanded topic name given an input name.
RCLCPP_PUBLIC
virtual
std::string
resolve_topic_name(const std::string & name, bool only_expand = false) const = 0;
};
} // namespace node_interfaces

View File

@@ -47,6 +47,7 @@ public:
* - start_parameter_services = true
* - start_parameter_event_publisher = true
* - clock_qos = rclcpp::ClockQoS()
* - use_clock_thread = true
* - rosout_qos = rclcpp::RosoutQoS()
* - parameter_event_qos = rclcpp::ParameterEventQoS
* - with history setting and depth from rmw_qos_profile_parameter_events
@@ -258,6 +259,20 @@ public:
NodeOptions &
clock_qos(const rclcpp::QoS & clock_qos);
/// Return the use_clock_thread flag.
RCLCPP_PUBLIC
bool
use_clock_thread() const;
/// Set the use_clock_thread flag, return this for parameter idiom.
/**
* If true, a dedicated thread will be used to subscribe to "/clock" topic.
*/
RCLCPP_PUBLIC
NodeOptions &
use_clock_thread(bool use_clock_thread);
/// Return a reference to the parameter_event_qos QoS.
RCLCPP_PUBLIC
const rclcpp::QoS &
@@ -334,6 +349,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.
*/
@@ -384,6 +402,8 @@ private:
rclcpp::QoS clock_qos_ = rclcpp::ClockQoS();
bool use_clock_thread_ {true};
rclcpp::QoS parameter_event_qos_ = rclcpp::ParameterEventsQoS(
rclcpp::QoSInitialization::from_rmw(rmw_qos_profile_parameter_events)
);

View File

@@ -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

View File

@@ -15,6 +15,8 @@
#ifndef RCLCPP__PARAMETER_CLIENT_HPP_
#define RCLCPP__PARAMETER_CLIENT_HPP_
#include <functional>
#include <future>
#include <memory>
#include <string>
#include <utility>
@@ -29,11 +31,14 @@
#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/type_support_decl.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rmw/rmw.h"
@@ -74,7 +79,7 @@ public:
* \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,
@@ -97,7 +102,7 @@ public:
* \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,
@@ -120,6 +125,14 @@ public:
void(std::shared_future<std::vector<rclcpp::Parameter>>)
> callback = nullptr);
RCLCPP_PUBLIC
std::shared_future<std::vector<rcl_interfaces::msg::ParameterDescriptor>>
describe_parameters(
const std::vector<std::string> & names,
std::function<
void(std::shared_future<std::vector<rcl_interfaces::msg::ParameterDescriptor>>)
> callback = nullptr);
RCLCPP_PUBLIC
std::shared_future<std::vector<rclcpp::ParameterType>>
get_parameter_types(
@@ -144,6 +157,42 @@ 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.
*
* \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(
@@ -284,7 +333,7 @@ public:
{}
template<typename NodeT>
SyncParametersClient(
explicit SyncParametersClient(
NodeT * node,
const std::string & remote_node_name = "",
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters)
@@ -332,9 +381,17 @@ public:
qos_profile);
}
RCLCPP_PUBLIC
template<typename RepT = int64_t, typename RatioT = std::milli>
std::vector<rclcpp::Parameter>
get_parameters(const std::vector<std::string> & parameter_names);
get_parameters(
const std::vector<std::string> & parameter_names,
std::chrono::duration<RepT, RatioT> timeout = std::chrono::duration<RepT, RatioT>(-1))
{
return get_parameters(
parameter_names,
std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
);
}
RCLCPP_PUBLIC
bool
@@ -378,23 +435,107 @@ public:
);
}
RCLCPP_PUBLIC
template<typename RepT = int64_t, typename RatioT = std::milli>
std::vector<rcl_interfaces::msg::ParameterDescriptor>
describe_parameters(
const std::vector<std::string> & parameter_names,
std::chrono::duration<RepT, RatioT> timeout = std::chrono::duration<RepT, RatioT>(-1))
{
return describe_parameters(
parameter_names,
std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
);
}
template<typename RepT = int64_t, typename RatioT = std::milli>
std::vector<rclcpp::ParameterType>
get_parameter_types(const std::vector<std::string> & parameter_names);
get_parameter_types(
const std::vector<std::string> & parameter_names,
std::chrono::duration<RepT, RatioT> timeout = std::chrono::duration<RepT, RatioT>(-1))
{
return get_parameter_types(
parameter_names,
std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
);
}
RCLCPP_PUBLIC
template<typename RepT = int64_t, typename RatioT = std::milli>
std::vector<rcl_interfaces::msg::SetParametersResult>
set_parameters(const std::vector<rclcpp::Parameter> & parameters);
set_parameters(
const std::vector<rclcpp::Parameter> & parameters,
std::chrono::duration<RepT, RatioT> timeout = std::chrono::duration<RepT, RatioT>(-1))
{
return set_parameters(
parameters,
std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
);
}
RCLCPP_PUBLIC
template<typename RepT = int64_t, typename RatioT = std::milli>
rcl_interfaces::msg::SetParametersResult
set_parameters_atomically(const std::vector<rclcpp::Parameter> & parameters);
set_parameters_atomically(
const std::vector<rclcpp::Parameter> & parameters,
std::chrono::duration<RepT, RatioT> timeout = std::chrono::duration<RepT, RatioT>(-1))
{
return set_parameters_atomically(
parameters,
std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
);
}
RCLCPP_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(
const std::vector<std::string> & parameter_prefixes,
uint64_t depth);
uint64_t depth,
std::chrono::duration<RepT, RatioT> timeout = std::chrono::duration<RepT, RatioT>(-1))
{
return list_parameters(
parameter_prefixes,
depth,
std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
);
}
template<typename CallbackT>
typename rclcpp::Subscription<rcl_interfaces::msg::ParameterEvent>::SharedPtr
@@ -437,6 +578,56 @@ public:
return async_parameters_client_->wait_for_service(timeout);
}
protected:
RCLCPP_PUBLIC
std::vector<rclcpp::Parameter>
get_parameters(
const std::vector<std::string> & parameter_names,
std::chrono::nanoseconds timeout);
RCLCPP_PUBLIC
std::vector<rcl_interfaces::msg::ParameterDescriptor>
describe_parameters(
const std::vector<std::string> & parameter_names,
std::chrono::nanoseconds timeout);
RCLCPP_PUBLIC
std::vector<rclcpp::ParameterType>
get_parameter_types(
const std::vector<std::string> & parameter_names,
std::chrono::nanoseconds timeout);
RCLCPP_PUBLIC
std::vector<rcl_interfaces::msg::SetParametersResult>
set_parameters(
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(
const std::vector<rclcpp::Parameter> & parameters,
std::chrono::nanoseconds timeout);
RCLCPP_PUBLIC
rcl_interfaces::msg::ListParametersResult
list_parameters(
const std::vector<std::string> & parameter_prefixes,
uint64_t depth,
std::chrono::nanoseconds timeout);
private:
rclcpp::Executor::SharedPtr executor_;
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_interface_;

View File

@@ -0,0 +1,347 @@
// Copyright 2019 Intel Corporation
//
// 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__PARAMETER_EVENT_HANDLER_HPP_
#define RCLCPP__PARAMETER_EVENT_HANDLER_HPP_
#include <list>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include "rclcpp/create_subscription.hpp"
#include "rclcpp/node_interfaces/get_node_base_interface.hpp"
#include "rclcpp/node_interfaces/get_node_topics_interface.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
#include "rclcpp/parameter.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/subscription.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rcl_interfaces/msg/parameter_event.hpp"
namespace rclcpp
{
struct ParameterCallbackHandle
{
RCLCPP_SMART_PTR_DEFINITIONS(ParameterCallbackHandle)
using ParameterCallbackType = std::function<void (const rclcpp::Parameter &)>;
std::string parameter_name;
std::string node_name;
ParameterCallbackType callback;
};
struct ParameterEventCallbackHandle
{
RCLCPP_SMART_PTR_DEFINITIONS(ParameterEventCallbackHandle)
using ParameterEventCallbackType =
std::function<void (const rcl_interfaces::msg::ParameterEvent &)>;
ParameterEventCallbackType callback;
};
/// A class used to "handle" (monitor and respond to) changes to parameters.
/**
* The ParameterEventHandler class allows for the monitoring of changes to node parameters,
* either a node's own parameters or parameters owned by other nodes in the system.
* Multiple parameter callbacks can be set and will be invoked when the specified parameter
* changes.
*
* The first step is to instantiate a ParameterEventHandler, providing a ROS node to use
* to create any required subscriptions:
*
* auto param_handler = std::make_shared<rclcpp::ParameterEventHandler>(node);
*
* Next, you can supply a callback to the add_parameter_callback method, as follows:
*
* auto cb1 = [&node](const rclcpp::Parameter & p) {
* RCLCPP_INFO(
* node->get_logger(),
* "cb1: Received an update to parameter \"%s\" of type %s: \"%ld\"",
* p.get_name().c_str(),
* p.get_type_name().c_str(),
* p.as_int());
* };
* auto handle1 = param_handler->add_parameter_callback("an_int_param", cb1);
*
* In this case, we didn't supply a node name (the third, optional, parameter) so the
* default will be to monitor for changes to the "an_int_param" parameter associated with
* the ROS node supplied in the ParameterEventHandler constructor.
* The callback, a lambda function in this case, simply prints out the value of the parameter.
*
* You may also monitor for changes to parameters in other nodes by supplying the node
* name to add_parameter_callback:
*
* auto cb2 = [&node](const rclcpp::Parameter & p) {
* RCLCPP_INFO(
* node->get_logger(),
* "cb2: Received an update to parameter \"%s\" of type: %s: \"%s\"",
* p.get_name().c_str(),
* p.get_type_name().c_str(),
* p.as_string().c_str());
* };
* auto handle2 = param_handler->add_parameter_callback(
* "some_remote_param_name", cb2, "some_remote_node_name");
*
* 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:
*
* param_handler->remove_parameter_callback(handle2);
*
* You can also monitor for *all* parameter changes, using add_parameter_event_callback.
* In this case, the callback will be invoked whenever any parameter changes in the system.
* You are likely interested in a subset of these parameter changes, so in the callback it
* is convenient to use a regular expression on the node names or namespaces of interest.
* For example:
*
* auto cb3 =
* [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)) {
* // 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))
* {
* RCLCPP_INFO(
* node->get_logger(),
* "cb3: Received an update to parameter \"%s\" of type: %s: \"%s\"",
* p.get_name().c_str(),
* p.get_type_name().c_str(),
* p.as_string().c_str());
* }
*
* // 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);
* for (auto & p : params) {
* RCLCPP_INFO(
* node->get_logger(),
* "cb3: Received an update to parameter \"%s\" of type: %s: \"%s\"",
* p.get_name().c_str(),
* p.get_type_name().c_str(),
* p.value_to_string().c_str());
* }
* }
* };
* auto handle3 = param_handler->add_parameter_event_callback(cb3);
*
* 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:
*
* param_handler->remove_event_parameter_callback(handle);
*/
class ParameterEventHandler
{
public:
/// Construct a parameter events monitor.
/**
* \param[in] node The node to use to create any required subscribers.
* \param[in] qos The QoS settings to use for any subscriptions.
*/
template<typename NodeT>
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))
{
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,
[callbacks = callbacks_](const rcl_interfaces::msg::ParameterEvent & event) {
callbacks->event_callback(event);
});
}
using ParameterEventCallbackType =
ParameterEventCallbackHandle::ParameterEventCallbackType;
/// Set a callback for all parameter events.
/**
* This function may be called multiple times to set multiple parameter event callbacks.
*
* \param[in] callback Function callback to be invoked on parameter updates.
* \returns A handle used to refer to the callback.
*/
RCLCPP_PUBLIC
ParameterEventCallbackHandle::SharedPtr
add_parameter_event_callback(
ParameterEventCallbackType callback);
/// Remove parameter event callback registered with add_parameter_event_callback.
/**
* \param[in] callback_handle Handle of the callback to remove.
*/
RCLCPP_PUBLIC
void
remove_parameter_event_callback(
ParameterEventCallbackHandle::SharedPtr callback_handle);
using ParameterCallbackType = ParameterCallbackHandle::ParameterCallbackType;
/// Add a callback for a specified parameter.
/**
* If a node_name is not provided, defaults to the current node.
*
* \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
ParameterCallbackHandle::SharedPtr
add_parameter_callback(
const std::string & parameter_name,
ParameterCallbackType callback,
const std::string & node_name = "");
/// Remove a parameter callback registered with add_parameter_callback.
/**
* The parameter name and node name are inspected from the callback handle. The callback handle
* is erased from the list of callback handles on the {parameter_name, node_name} in the map.
* An error is thrown if the handle does not exist and/or was already removed.
*
* \param[in] callback_handle Handle of the callback to remove.
*/
RCLCPP_PUBLIC
void
remove_parameter_callback(
ParameterCallbackHandle::SharedPtr callback_handle);
/// Get an rclcpp::Parameter from a parameter event.
/**
* If a node_name is not provided, defaults to the current node.
*
* \param[in] event Event msg to be inspected.
* \param[out] parameter Reference to rclcpp::Parameter to be assigned.
* \param[in] parameter_name Name of parameter.
* \param[in] node_name Name of node which hosts the parameter.
* \returns Output parameter is set with requested parameter info and returns true if
* requested parameter name and node is in event. Otherwise, returns false.
*/
RCLCPP_PUBLIC
static bool
get_parameter_from_event(
const rcl_interfaces::msg::ParameterEvent & event,
rclcpp::Parameter & parameter,
const std::string & parameter_name,
const std::string & node_name = "");
/// Get an rclcpp::Parameter from parameter event
/**
* If a node_name is not provided, defaults to the current node.
*
* The user is responsible to check if the returned parameter has been properly assigned.
* By default, if the requested parameter is not found in the event, the returned parameter
* has parameter value of type rclcpp::PARAMETER_NOT_SET.
*
* \param[in] event Event msg to be inspected.
* \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.
*/
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 = "");
/// Get all rclcpp::Parameter values from a parameter event
/**
* \param[in] event Event msg to be inspected.
* \returns A vector rclcpp::Parameter values from the event.
*/
RCLCPP_PUBLIC
static std::vector<rclcpp::Parameter>
get_parameters_from_event(
const rcl_interfaces::msg::ParameterEvent & event);
using CallbacksContainerType = std::list<ParameterCallbackHandle::WeakPtr>;
protected:
// *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
class StringPairHash
{
public:
template<typename T>
inline void hash_combine(std::size_t & seed, const T & v) const
{
std::hash<T> hasher;
seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
inline size_t operator()(const std::pair<std::string, std::string> & s) const
{
size_t seed = 0;
hash_combine(seed, s.first);
hash_combine(seed, s.second);
return seed;
}
};
// *INDENT-ON*
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_;
};
} // namespace rclcpp
#endif // RCLCPP__PARAMETER_EVENT_HANDLER_HPP_

View File

@@ -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

View File

@@ -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>
@@ -40,6 +41,16 @@ RCLCPP_PUBLIC
ParameterMap
parameter_map_from(const rcl_params_t * const c_params);
/// 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, const char * node_fqn);
/// 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.
/// \returns an instance of a parameter value
@@ -48,6 +59,14 @@ 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.
/// \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);
} // namespace rclcpp
#endif // RCLCPP__PARAMETER_MAP_HPP_

View File

@@ -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<

View File

@@ -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,12 +130,14 @@ public:
: PublisherBase(
node_base,
topic,
*rosidl_typesupport_cpp::get_message_type_support_handle<MessageT>(),
rclcpp::get_message_type_support_handle<MessageT>(),
options.template to_rcl_publisher_options<MessageT>(qos)),
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());
allocator::set_allocator_for_deleter(&published_type_deleter_, &published_type_allocator_);
allocator::set_allocator_for_deleter(&ros_message_type_deleter_, &ros_message_type_allocator_);
if (options_.event_callbacks.deadline_callback) {
this->add_event_handler(
@@ -133,15 +187,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 +222,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 +264,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 +299,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,7 +400,7 @@ 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");
@@ -261,7 +418,7 @@ public:
if (this->can_loan_messages()) {
// we release the ownership from the rclpp::LoanedMessage instance
// and let the middleware clean up the memory.
this->do_loaned_message_publish(loaned_msg.release());
this->do_loaned_message_publish(std::move(loaned_msg.release()));
} 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.
@@ -269,16 +426,30 @@ public:
}
}
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,9 +481,10 @@ protected:
}
void
do_loaned_message_publish(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, nullptr);
auto status = rcl_publish_loaned_message(publisher_handle_.get(), msg.get(), nullptr);
if (RCL_RET_PUBLISHER_INVALID == status) {
rcl_reset_error(); // next call will reset error message if not context
@@ -330,7 +502,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 +513,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 +531,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 +592,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

View File

@@ -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/type_support_decl.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rcpputils/time.hpp"
namespace rclcpp
{
@@ -109,9 +114,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::QOSEventHandlerBase>> &
get_event_handlers() const;
/// Get subscription count
@@ -193,6 +199,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::QOSEventHandlerBase::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
@@ -206,7 +326,7 @@ protected:
rcl_publisher_event_init,
publisher_handle_,
event_type);
event_handlers_.emplace_back(handler);
event_handlers_.insert(std::make_pair(event_type, handler));
}
RCLCPP_PUBLIC
@@ -216,7 +336,8 @@ protected:
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::QOSEventHandlerBase>> event_handlers_;
using IntraProcessManagerWeakPtr =
std::weak_ptr<rclcpp::experimental::IntraProcessManager>;
@@ -225,6 +346,8 @@ protected:
uint64_t intra_process_publisher_id_;
rmw_gid_t rmw_gid_;
const rosidl_message_type_support_t type_support_;
};
} // namespace rclcpp

View File

@@ -17,6 +17,7 @@
#include <memory>
#include <string>
#include <type_traits>
#include <vector>
#include "rcl/publisher.h"
@@ -26,6 +27,7 @@
#include "rclcpp/intra_process_setting.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/qos_event.hpp"
#include "rclcpp/qos_overriding_options.hpp"
namespace rclcpp
{
@@ -44,22 +46,33 @@ struct PublisherOptionsBase
/// Whether or not to use default callbacks when user doesn't supply any in event_callbacks
bool use_default_callbacks = true;
/// Require middleware to generate unique network flow endpoints
/// Disabled by default
rmw_unique_network_flow_endpoints_requirement_t require_unique_network_flow_endpoints =
RMW_UNIQUE_NETWORK_FLOW_ENDPOINTS_NOT_REQUIRED;
/// Callback group in which the waitable items from the publisher should be placed.
std::shared_ptr<rclcpp::CallbackGroup> callback_group;
/// Optional RMW implementation specific payload to be used during creation of the publisher.
std::shared_ptr<rclcpp::detail::RMWImplementationSpecificPublisherPayload>
rmw_implementation_payload = nullptr;
QosOverridingOptions qos_overriding_options;
};
/// Structure containing optional configuration for Publishers.
template<typename Allocator>
struct PublisherOptionsWithAllocator : public PublisherOptionsBase
{
static_assert(
std::is_void_v<typename std::allocator_traits<Allocator>::value_type>,
"Publisher allocator value type must be void");
/// Optional custom allocator.
std::shared_ptr<Allocator> allocator = nullptr;
PublisherOptionsWithAllocator<Allocator>() {}
PublisherOptionsWithAllocator() {}
/// Constructor using base class as input.
explicit PublisherOptionsWithAllocator(const PublisherOptionsBase & publisher_options_base)
@@ -72,11 +85,10 @@ struct PublisherOptionsWithAllocator : public PublisherOptionsBase
to_rcl_publisher_options(const rclcpp::QoS & qos) const
{
rcl_publisher_options_t result = rcl_publisher_get_default_options();
using AllocatorTraits = std::allocator_traits<Allocator>;
using MessageAllocatorT = typename AllocatorTraits::template rebind_alloc<MessageT>;
auto message_alloc = std::make_shared<MessageAllocatorT>(*this->get_allocator().get());
result.allocator = rclcpp::allocator::get_rcl_allocator<MessageT>(*message_alloc);
result.allocator = this->get_rcl_allocator();
result.qos = qos.get_rmw_qos_profile();
result.rmw_publisher_options.require_unique_network_flow_endpoints =
this->require_unique_network_flow_endpoints;
// Apply payload to rcl_publisher_options if necessary.
if (rmw_implementation_payload && rmw_implementation_payload->has_been_customized()) {
@@ -92,15 +104,35 @@ struct PublisherOptionsWithAllocator : public PublisherOptionsBase
get_allocator() const
{
if (!this->allocator) {
// TODO(wjwwood): I would like to use the commented line instead, but
// cppcheck 1.89 fails with:
// Syntax Error: AST broken, binary operator '>' doesn't have two operands.
// return std::make_shared<Allocator>();
std::shared_ptr<Allocator> tmp(new Allocator());
return tmp;
if (!allocator_storage_) {
allocator_storage_ = std::make_shared<Allocator>();
}
return allocator_storage_;
}
return this->allocator;
}
private:
using PlainAllocator =
typename std::allocator_traits<Allocator>::template rebind_alloc<char>;
rcl_allocator_t
get_rcl_allocator() const
{
if (!plain_allocator_storage_) {
plain_allocator_storage_ =
std::make_shared<PlainAllocator>(*this->get_allocator());
}
return rclcpp::allocator::get_rcl_allocator<char>(*plain_allocator_storage_);
}
// This is a temporal workaround, to make sure that get_allocator()
// always returns a copy of the same allocator.
mutable std::shared_ptr<Allocator> allocator_storage_;
// This is a temporal workaround, to keep the plain allocator that backs
// up the rcl allocator returned in rcl_publisher_options_t alive.
mutable std::shared_ptr<PlainAllocator> plain_allocator_storage_;
};
using PublisherOptions = PublisherOptionsWithAllocator<std::allocator<void>>;

View File

@@ -18,6 +18,7 @@
#include <string>
#include "rclcpp/duration.hpp"
#include "rclcpp/exceptions.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rcl/logging_rosout.h"
#include "rmw/incompatible_qos_events_statuses.h"
@@ -30,6 +31,45 @@ namespace rclcpp
RCLCPP_PUBLIC
std::string qos_policy_name_from_kind(rmw_qos_policy_kind_t policy_kind);
enum class HistoryPolicy
{
KeepLast = RMW_QOS_POLICY_HISTORY_KEEP_LAST,
KeepAll = RMW_QOS_POLICY_HISTORY_KEEP_ALL,
SystemDefault = RMW_QOS_POLICY_HISTORY_SYSTEM_DEFAULT,
Unknown = RMW_QOS_POLICY_HISTORY_UNKNOWN,
};
enum class ReliabilityPolicy
{
BestEffort = RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT,
Reliable = RMW_QOS_POLICY_RELIABILITY_RELIABLE,
SystemDefault = RMW_QOS_POLICY_RELIABILITY_SYSTEM_DEFAULT,
Unknown = RMW_QOS_POLICY_RELIABILITY_UNKNOWN,
};
enum class DurabilityPolicy
{
Volatile = RMW_QOS_POLICY_DURABILITY_VOLATILE,
TransientLocal = RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL,
SystemDefault = RMW_QOS_POLICY_DURABILITY_SYSTEM_DEFAULT,
Unknown = RMW_QOS_POLICY_DURABILITY_UNKNOWN,
};
enum class LivelinessPolicy
{
Automatic = RMW_QOS_POLICY_LIVELINESS_AUTOMATIC,
ManualByTopic = RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC,
SystemDefault = RMW_QOS_POLICY_LIVELINESS_SYSTEM_DEFAULT,
Unknown = RMW_QOS_POLICY_LIVELINESS_UNKNOWN,
};
enum class QoSCompatibility
{
Ok = RMW_QOS_COMPATIBILITY_OK,
Warning = RMW_QOS_COMPATIBILITY_WARNING,
Error = RMW_QOS_COMPATIBILITY_ERROR,
};
/// QoS initialization values, cannot be created directly, use KeepAll or KeepLast instead.
struct RCLCPP_PUBLIC QoSInitialization
{
@@ -58,10 +98,32 @@ struct RCLCPP_PUBLIC KeepLast : public rclcpp::QoSInitialization
};
/// Encapsulation of Quality of Service settings.
/**
* Quality of Service settings control the behavior of publishers, subscriptions,
* and other entities, and includes things like how data is sent or resent,
* how data is buffered on the publishing and subscribing side, and other things.
* See:
* <a href="https://docs.ros.org/en/rolling/Concepts/About-Quality-of-Service-Settings.html">
* https://docs.ros.org/en/rolling/Concepts/About-Quality-of-Service-Settings.html
* </a>
*/
class RCLCPP_PUBLIC QoS
{
public:
/// Constructor which allows you to construct a QoS by giving the only required settings.
/// Create a QoS by specifying only the history policy and history depth.
/**
* When using the default initial profile, the defaults will include:
*
* - \link rclcpp::ReliabilityPolicy::Reliable ReliabilityPolicy::Reliable\endlink
* - \link rclcpp::DurabilityPolicy::Volatile DurabilityPolicy::Volatile\endlink
*
* See rmw_qos_profile_default for a full list of default settings.
* If some other rmw_qos_profile_t is passed to initial_profile, then the defaults will derive from
* that profile instead.
*
* \param[in] qos_initialization Specifies history policy and history depth.
* \param[in] initial_profile The rmw_qos_profile_t instance on which to base the default settings.
*/
explicit
QoS(
const QoSInitialization & qos_initialization,
@@ -69,7 +131,11 @@ public:
/// Conversion constructor to ease construction in the common case of just specifying depth.
/**
* Convenience constructor, equivalent to QoS(KeepLast(history_depth)).
* This is a convenience constructor that calls QoS(KeepLast(history_depth)).
*
* \param[in] history_depth How many messages can be queued when publishing
* with a Publisher, or how many messages can be queued before being replaced
* by a Subscription.
*/
// cppcheck-suppress noExplicitConstructor
QoS(size_t history_depth); // NOLINT(runtime/explicit): conversion constructor
@@ -82,6 +148,10 @@ public:
const rmw_qos_profile_t &
get_rmw_qos_profile() const;
/// Set the history policy.
QoS &
history(HistoryPolicy history);
/// Set the history policy.
QoS &
history(rmw_qos_history_policy_t history);
@@ -98,6 +168,10 @@ public:
QoS &
reliability(rmw_qos_reliability_policy_t reliability);
/// Set the reliability setting.
QoS &
reliability(ReliabilityPolicy reliability);
/// Set the reliability setting to reliable.
QoS &
reliable();
@@ -110,6 +184,10 @@ public:
QoS &
durability(rmw_qos_durability_policy_t durability);
/// Set the durability setting.
QoS &
durability(DurabilityPolicy durability);
/// Set the durability setting to volatile.
/**
* Note that this cannot be named `volatile` because it is a C++ keyword.
@@ -141,6 +219,10 @@ public:
QoS &
liveliness(rmw_qos_liveliness_policy_t liveliness);
/// Set the liveliness setting.
QoS &
liveliness(LivelinessPolicy liveliness);
/// Set the liveliness_lease_duration setting.
QoS &
liveliness_lease_duration(rmw_time_t liveliness_lease_duration);
@@ -153,6 +235,42 @@ public:
QoS &
avoid_ros_namespace_conventions(bool avoid_ros_namespace_conventions);
/// Get the history qos policy.
HistoryPolicy
history() const;
/// Get the history depth.
size_t
depth() const;
/// Get the reliability policy.
ReliabilityPolicy
reliability() const;
/// Get the durability policy.
DurabilityPolicy
durability() const;
/// Get the deadline duration setting.
rclcpp::Duration
deadline() const;
/// Get the lifespan duration setting.
rclcpp::Duration
lifespan() const;
/// Get the liveliness policy.
LivelinessPolicy
liveliness() const;
/// Get the liveliness lease duration setting.
rclcpp::Duration
liveliness_lease_duration() const;
/// Get the `avoid ros namespace convention` setting.
bool
avoid_ros_namespace_conventions() const;
private:
rmw_qos_profile_t rmw_qos_profile_;
};
@@ -163,6 +281,61 @@ bool operator==(const QoS & left, const QoS & right);
RCLCPP_PUBLIC
bool operator!=(const QoS & left, const QoS & right);
/// Result type for checking QoS compatibility
/**
* \see rclcpp::qos_check_compatible()
*/
struct QoSCheckCompatibleResult
{
/// Compatibility result.
QoSCompatibility compatibility;
/// Reason for a (possible) incompatibility.
/**
* Set if compatiblity is QoSCompatibility::Warning or QoSCompatiblity::Error.
* Not set if the QoS profiles are compatible.
*/
std::string reason;
};
/// Check if two QoS profiles are compatible.
/**
* Two QoS profiles are compatible if a publisher and subcription
* using the QoS policies can communicate with each other.
*
* If any policies have value "system default" or "unknown" then it is possible that
* compatiblity cannot be determined.
* In this case, the value QoSCompatility::Warning is set as part of
* the returned structure.
*
* Example usage:
*
* ```cpp
* rclcpp::QoSCheckCompatibleResult result = rclcpp::qos_check_compatible(
* publisher_qos, subscription_qos);
* if (rclcpp::QoSCompatibility::Error != result.compatibility) {
* // QoS not compatible ...
* // result.reason contains info about the incompatibility
* } else if (rclcpp::QoSCompatibility::Warning != result.compatibility) {
* // QoS may not be compatible ...
* // result.reason contains info about the possible incompatibility
* }
* ```
*
* \param[in] publisher_qos: The QoS profile for a publisher.
* \param[in] subscription_qos: The QoS profile for a subscription.
* \return Struct with compatiblity set to QoSCompatibility::Ok if the QoS profiles are
* compatible, or
* \return Struct with compatibility set to QoSCompatibility::Warning if there is a chance
* the QoS profiles are not compatible, or
* \return Struct with compatibility set to QoSCompatibility::Error if the QoS profiles are
* not compatible.
* \throws rclcpp::exceptions::QoSCheckCompatibilityException if an unexpected error occurs.
*/
RCLCPP_PUBLIC
QoSCheckCompatibleResult
qos_check_compatible(const QoS & publisher_qos, const QoS & subscription_qos);
/**
* Clock QoS class
* - History: Keep last,

View File

@@ -16,15 +16,22 @@
#define RCLCPP__QOS_EVENT_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 "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
@@ -82,6 +89,11 @@ public:
class QOSEventHandlerBase : public Waitable
{
public:
enum class EntityType : std::size_t
{
Event,
};
RCLCPP_PUBLIC
virtual ~QOSEventHandlerBase();
@@ -92,7 +104,7 @@ public:
/// Add the Waitable to a wait set.
RCLCPP_PUBLIC
bool
void
add_to_wait_set(rcl_wait_set_t * wait_set) override;
/// Check if the Waitable is ready.
@@ -100,9 +112,111 @@ 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::QOSEventHandlerBase@" << 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::QOSEventHandlerBase@" << 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<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<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);
rcl_event_t event_handle_;
size_t wait_set_event_index_;
std::recursive_mutex callback_mutex_;
std::function<void(size_t)> on_new_event_callback_{nullptr};
};
template<typename EventCallbackT, typename ParentHandleT>
@@ -115,9 +229,8 @@ public:
InitFuncT init_func,
ParentHandleT parent_handle,
EventTypeEnum event_type)
: event_callback_(callback)
: parent_handle_(parent_handle), event_callback_(callback)
{
parent_handle_ = parent_handle;
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) {
@@ -131,21 +244,38 @@ public:
}
}
/// Execute any entities of the Waitable that are ready.
void
execute() override
/// 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;
return nullptr;
}
return std::static_pointer_cast<void>(std::make_shared<EventCallbackInfoT>(callback_info));
}
event_callback_(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:

View File

@@ -0,0 +1,154 @@
// Copyright 2020 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__QOS_OVERRIDING_OPTIONS_HPP_
#define RCLCPP__QOS_OVERRIDING_OPTIONS_HPP_
#include <functional>
#include <initializer_list>
#include <ostream>
#include <string>
#include <utility>
#include <vector>
#include "rclcpp/qos.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rcl_interfaces/msg/set_parameters_result.hpp"
#include "rmw/qos_policy_kind.h"
namespace rclcpp
{
enum class RCLCPP_PUBLIC_TYPE QosPolicyKind
{
AvoidRosNamespaceConventions = RMW_QOS_POLICY_AVOID_ROS_NAMESPACE_CONVENTIONS,
Deadline = RMW_QOS_POLICY_DEADLINE,
Depth = RMW_QOS_POLICY_DEPTH,
Durability = RMW_QOS_POLICY_DURABILITY,
History = RMW_QOS_POLICY_HISTORY,
Lifespan = RMW_QOS_POLICY_LIFESPAN,
Liveliness = RMW_QOS_POLICY_LIVELINESS,
LivelinessLeaseDuration = RMW_QOS_POLICY_LIVELINESS_LEASE_DURATION,
Reliability = RMW_QOS_POLICY_RELIABILITY,
Invalid = RMW_QOS_POLICY_INVALID,
};
RCLCPP_PUBLIC
const char *
qos_policy_kind_to_cstr(const QosPolicyKind & qpk);
RCLCPP_PUBLIC
std::ostream &
operator<<(std::ostream & os, const QosPolicyKind & qpk);
using QosCallbackResult = rcl_interfaces::msg::SetParametersResult;
using QosCallback = std::function<QosCallbackResult(const rclcpp::QoS &)>;
namespace detail
{
// forward declare
template<typename T>
class QosParameters;
}
/// Options that are passed in subscription/publisher constructor to specify QoSConfigurability.
/**
* This options struct allows configuring:
* - Which policy kinds will have declared parameters.
* - An optional callback, that will be called to validate the final qos profile.
* - An optional id. In the case that different qos are desired for two publishers/subscriptions in
* the same topic, this id will allow disambiguating them.
*
* Example parameter file:
*
* ```yaml
* my_node_name:
* ros__parameters:
* qos_overrides:
* /my/topic/name:
* publisher: # publisher without provided id
* reliability: reliable
* depth: 100
* publisher_my_id: # publisher with `id="my_id"
* reliability: reliable
* depth: 10
* ```
*/
class QosOverridingOptions
{
public:
/// Default constructor, no overrides allowed.
RCLCPP_PUBLIC
QosOverridingOptions() = default;
/// Construct passing a list of QoS policies and a verification callback.
/**
* This constructor is implicit, e.g.:
* ```cpp
* node->create_publisher(
* "topic_name",
* default_qos_profile,
* {
* {QosPolicyKind::Reliability},
* [] (auto && qos) {return check_qos_validity(qos)},
* "my_id"
* });
* ```
* \param policy_kinds list of policy kinds that will be reconfigurable.
* \param validation_callback callbak that will be called to validate the validity of
* the qos profile set by the user.
* \param id id of the entity.
*/
RCLCPP_PUBLIC
QosOverridingOptions(
std::initializer_list<QosPolicyKind> policy_kinds,
QosCallback validation_callback = nullptr,
std::string id = {});
RCLCPP_PUBLIC
const std::string &
get_id() const;
RCLCPP_PUBLIC
const std::vector<QosPolicyKind> &
get_policy_kinds() const;
RCLCPP_PUBLIC
const QosCallback &
get_validation_callback() const;
/// Construct passing a list of QoS policies and a verification callback.
/**
* Same as `QosOverridingOptions` constructor, but only declares the default policies:
*
* History, Depth, Reliability.
*/
RCLCPP_PUBLIC
static
QosOverridingOptions
with_default_policies(QosCallback validation_callback = nullptr, std::string id = {});
private:
/// \internal Id of the entity requesting to create parameters.
std::string id_;
/// \internal Policy kinds that are allowed to be reconfigured.
std::vector<QosPolicyKind> policy_kinds_;
/// \internal Validation callback that will be called to verify the profile.
QosCallback validation_callback_;
};
} // namespace rclcpp
#endif // RCLCPP__QOS_OVERRIDING_OPTIONS_HPP_

View File

@@ -117,6 +117,15 @@
* - Allocator related items:
* - rclcpp/allocator/allocator_common.hpp
* - rclcpp/allocator/allocator_deleter.hpp
* - Generic publisher
* - rclcpp::Node::create_generic_publisher()
* - rclcpp::GenericPublisher
* - rclcpp::GenericPublisher::publish()
* - rclcpp/generic_publisher.hpp
* - Generic subscription
* - rclcpp::Node::create_generic_subscription()
* - rclcpp::GenericSubscription
* - rclcpp/generic_subscription.hpp
* - Memory management tools:
* - rclcpp/memory_strategies.hpp
* - rclcpp/memory_strategy.hpp
@@ -131,9 +140,9 @@
* - rclcpp/duration.hpp
* - rclcpp/function_traits.hpp
* - rclcpp/macros.hpp
* - rclcpp/scope_exit.hpp
* - rclcpp/time.hpp
* - rclcpp/utilities.hpp
* - rclcpp/typesupport_helpers.hpp
* - rclcpp/visibility_control.hpp
*/
@@ -147,14 +156,15 @@
#include "rclcpp/guard_condition.hpp"
#include "rclcpp/logging.hpp"
#include "rclcpp/node.hpp"
#include "rclcpp/parameter.hpp"
#include "rclcpp/parameter_client.hpp"
#include "rclcpp/parameter_event_handler.hpp"
#include "rclcpp/parameter.hpp"
#include "rclcpp/parameter_service.hpp"
#include "rclcpp/rate.hpp"
#include "rclcpp/time.hpp"
#include "rclcpp/utilities.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rclcpp/wait_set.hpp"
#include "rclcpp/waitable.hpp"
#include "rclcpp/wait_set.hpp"
#endif // RCLCPP__RCLCPP_HPP_

View File

@@ -19,6 +19,10 @@
#ifndef RCLCPP__SCOPE_EXIT_HPP_
#define RCLCPP__SCOPE_EXIT_HPP_
// TODO(christophebedard) remove this header completely in I-turtle
#warning rclcpp/scope_exit.hpp has been deprecated, please use rcpputils/scope_exit.hpp instead
#include <functional>
#include "rclcpp/macros.hpp"

View File

@@ -47,7 +47,7 @@ public:
* \param[in] initial_capacity The amount of memory to be allocated.
* \param[in] allocator The allocator to be used for the initialization.
*/
SerializedMessage(
explicit SerializedMessage(
size_t initial_capacity,
const rcl_allocator_t & allocator = rcl_get_default_allocator());

View File

@@ -19,23 +19,30 @@
#include <functional>
#include <iostream>
#include <memory>
#include <mutex>
#include <sstream>
#include <string>
#include "rcl/error_handling.h"
#include "rcl/event_callback.h"
#include "rcl/service.h"
#include "rclcpp/any_service_callback.hpp"
#include "rclcpp/exceptions.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/type_support_decl.hpp"
#include "rclcpp/expand_topic_or_service_name.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rclcpp/logging.hpp"
#include "rmw/error_handling.h"
#include "rmw/impl/cpp/demangle.hpp"
#include "rmw/rmw.h"
#include "tracetools/tracetools.h"
#include "rclcpp/any_service_callback.hpp"
#include "rclcpp/detail/cpp_callback_trampoline.hpp"
#include "rclcpp/exceptions.hpp"
#include "rclcpp/expand_topic_or_service_name.hpp"
#include "rclcpp/logging.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/type_support_decl.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
@@ -121,6 +128,123 @@ public:
bool
exchange_in_use_by_wait_set_state(bool in_use_state);
/// Get the actual response publisher 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 service, 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 publisher qos settings.
* \throws std::runtime_error if failed to get qos settings
*/
RCLCPP_PUBLIC
rclcpp::QoS
get_response_publisher_actual_qos() const;
/// Get the actual request 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 service, 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 subscription qos settings.
* \throws std::runtime_error if failed to get qos settings
*/
RCLCPP_PUBLIC
rclcpp::QoS
get_request_subscription_actual_qos() const;
/// Set a callback to be called when each new request is received.
/**
* The callback receives a size_t which is the number of requests received
* since the last time this callback was called.
* Normally this is 1, but can be > 1 if requests 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 service
* or other information, you may use a lambda with captures or std::bind.
*
* \sa rmw_service_set_on_new_request_callback
* \sa rcl_service_set_on_new_request_callback
*
* \param[in] callback functor to be called when a new request is received
*/
void
set_on_new_request_callback(std::function<void(size_t)> callback)
{
if (!callback) {
throw std::invalid_argument(
"The callback passed to set_on_new_request_callback "
"is not callable.");
}
auto new_callback =
[callback, this](size_t number_of_requests) {
try {
callback(number_of_requests);
} catch (const std::exception & exception) {
RCLCPP_ERROR_STREAM(
node_logger_,
"rclcpp::ServiceBase@" << this <<
" caught " << rmw::impl::cpp::demangle(exception) <<
" exception in user-provided callback for the 'on new request' callback: " <<
exception.what());
} catch (...) {
RCLCPP_ERROR_STREAM(
node_logger_,
"rclcpp::ServiceBase@" << this <<
" caught unhandled exception in user-provided callback " <<
"for the 'on new request' 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_request_callback(
rclcpp::detail::cpp_callback_trampoline<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_request_callback_ = new_callback;
// Set it again, now using the permanent storage.
set_on_new_request_callback(
rclcpp::detail::cpp_callback_trampoline<const void *, size_t>,
static_cast<const void *>(&on_new_request_callback_));
}
/// Unset the callback registered for new requests, if any.
void
clear_on_new_request_callback()
{
std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
if (on_new_request_callback_) {
set_on_new_request_callback(nullptr, nullptr);
on_new_request_callback_ = nullptr;
}
}
protected:
RCLCPP_DISABLE_COPY(ServiceBase)
@@ -132,16 +256,27 @@ protected:
const rcl_node_t *
get_rcl_node_handle() const;
RCLCPP_PUBLIC
void
set_on_new_request_callback(rcl_event_callback_t callback, const void * user_data);
std::shared_ptr<rcl_node_t> node_handle_;
std::shared_ptr<rcl_service_t> service_handle_;
bool owns_rcl_handle_ = true;
rclcpp::Logger node_logger_;
std::atomic<bool> in_use_by_wait_set_{false};
std::recursive_mutex callback_mutex_;
std::function<void(size_t)> on_new_request_callback_{nullptr};
};
template<typename ServiceT>
class Service : public ServiceBase
class Service
: public ServiceBase,
public std::enable_shared_from_this<Service<ServiceT>>
{
public:
using CallbackType = std::function<
@@ -177,25 +312,16 @@ public:
using rosidl_typesupport_cpp::get_service_type_support_handle;
auto service_type_support_handle = get_service_type_support_handle<ServiceT>();
std::weak_ptr<rcl_node_t> weak_node_handle(node_handle_);
// rcl does the static memory allocation here
service_handle_ = std::shared_ptr<rcl_service_t>(
new rcl_service_t, [weak_node_handle](rcl_service_t * service)
new rcl_service_t, [handle = node_handle_, service_name](rcl_service_t * service)
{
auto handle = weak_node_handle.lock();
if (handle) {
if (rcl_service_fini(service, handle.get()) != RCL_RET_OK) {
RCLCPP_ERROR(
rclcpp::get_node_logger(handle.get()).get_child("rclcpp"),
"Error in destruction of rcl service handle: %s",
rcl_get_error_string().str);
rcl_reset_error();
}
} else {
if (rcl_service_fini(service, handle.get()) != RCL_RET_OK) {
RCLCPP_ERROR(
rclcpp::get_logger("rclcpp"),
"Error in destruction of rcl service handle: "
"the Node Handle was destructed too early. You will leak memory");
rclcpp::get_node_logger(handle.get()).get_child("rclcpp"),
"Error in destruction of rcl service handle: %s",
rcl_get_error_string().str);
rcl_reset_error();
}
delete service;
});
@@ -344,18 +470,10 @@ public:
std::shared_ptr<void> request) override
{
auto typed_request = std::static_pointer_cast<typename ServiceT::Request>(request);
auto response = std::make_shared<typename ServiceT::Response>();
any_callback_.dispatch(request_header, typed_request, response);
send_response(*request_header, *response);
}
[[deprecated("use the send_response() which takes references instead of shared pointers")]]
void
send_response(
std::shared_ptr<rmw_request_id_t> req_id,
std::shared_ptr<typename ServiceT::Response> response)
{
send_response(*req_id, *response);
auto response = any_callback_.dispatch(this->shared_from_this(), request_header, typed_request);
if (response) {
send_response(*request_header, *response);
}
}
void

View File

@@ -21,6 +21,7 @@
#include "rcl/allocator.h"
#include "rclcpp/allocator/allocator_common.hpp"
#include "rclcpp/detail/add_guard_condition_to_rcl_wait_set.hpp"
#include "rclcpp/memory_strategy.hpp"
#include "rclcpp/node.hpp"
#include "rclcpp/visibility_control.hpp"
@@ -61,17 +62,17 @@ public:
allocator_ = std::make_shared<VoidAlloc>();
}
void add_guard_condition(const rcl_guard_condition_t * guard_condition) override
void add_guard_condition(const rclcpp::GuardCondition & guard_condition) override
{
for (const auto & existing_guard_condition : guard_conditions_) {
if (existing_guard_condition == guard_condition) {
if (existing_guard_condition == &guard_condition) {
return;
}
}
guard_conditions_.push_back(guard_condition);
guard_conditions_.push_back(&guard_condition);
}
void remove_guard_condition(const rcl_guard_condition_t * guard_condition) override
void remove_guard_condition(const rclcpp::GuardCondition * guard_condition) override
{
for (auto it = guard_conditions_.begin(); it != guard_conditions_.end(); ++it) {
if (*it == guard_condition) {
@@ -163,30 +164,22 @@ public:
if (!group || !group->can_be_taken_from().load()) {
continue;
}
group->find_subscription_ptrs_if(
group->collect_all_ptrs(
[this](const rclcpp::SubscriptionBase::SharedPtr & subscription) {
subscription_handles_.push_back(subscription->get_subscription_handle());
return false;
});
group->find_service_ptrs_if(
},
[this](const rclcpp::ServiceBase::SharedPtr & service) {
service_handles_.push_back(service->get_service_handle());
return false;
});
group->find_client_ptrs_if(
},
[this](const rclcpp::ClientBase::SharedPtr & client) {
client_handles_.push_back(client->get_client_handle());
return false;
});
group->find_timer_ptrs_if(
},
[this](const rclcpp::TimerBase::SharedPtr & timer) {
timer_handles_.push_back(timer->get_timer_handle());
return false;
});
group->find_waitable_ptrs_if(
},
[this](const rclcpp::Waitable::SharedPtr & waitable) {
waitable_handles_.push_back(waitable);
return false;
});
}
@@ -203,7 +196,7 @@ public:
bool add_handles_to_wait_set(rcl_wait_set_t * wait_set) override
{
for (auto subscription : subscription_handles_) {
for (const std::shared_ptr<const rcl_subscription_t> & subscription : subscription_handles_) {
if (rcl_wait_set_add_subscription(wait_set, subscription.get(), NULL) != RCL_RET_OK) {
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
@@ -212,7 +205,7 @@ public:
}
}
for (auto client : client_handles_) {
for (const std::shared_ptr<const rcl_client_t> & client : client_handles_) {
if (rcl_wait_set_add_client(wait_set, client.get(), NULL) != RCL_RET_OK) {
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
@@ -221,7 +214,7 @@ public:
}
}
for (auto service : service_handles_) {
for (const std::shared_ptr<const rcl_service_t> & service : service_handles_) {
if (rcl_wait_set_add_service(wait_set, service.get(), NULL) != RCL_RET_OK) {
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
@@ -230,7 +223,7 @@ public:
}
}
for (auto timer : timer_handles_) {
for (const std::shared_ptr<const rcl_timer_t> & timer : timer_handles_) {
if (rcl_wait_set_add_timer(wait_set, timer.get(), NULL) != RCL_RET_OK) {
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
@@ -240,22 +233,11 @@ public:
}
for (auto guard_condition : guard_conditions_) {
if (rcl_wait_set_add_guard_condition(wait_set, guard_condition, NULL) != RCL_RET_OK) {
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"Couldn't add guard_condition to wait set: %s",
rcl_get_error_string().str);
return false;
}
detail::add_guard_condition_to_rcl_wait_set(*wait_set, *guard_condition);
}
for (auto waitable : waitable_handles_) {
if (!waitable->add_to_wait_set(wait_set)) {
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"Couldn't add waitable to wait set: %s", rcl_get_error_string().str);
return false;
}
for (const std::shared_ptr<Waitable> & waitable : waitable_handles_) {
waitable->add_to_wait_set(wait_set);
}
return true;
}
@@ -388,6 +370,11 @@ public:
++it;
continue;
}
if (!timer->call()) {
// timer was cancelled, skip it.
++it;
continue;
}
// Otherwise it is safe to set and return the any_exec
any_exec.timer = timer;
any_exec.callback_group = group;
@@ -395,7 +382,7 @@ public:
timer_handles_.erase(it);
return;
}
// Else, the service is no longer valid, remove it and continue
// Else, the timer is no longer valid, remove it and continue
it = timer_handles_.erase(it);
}
}
@@ -407,7 +394,7 @@ public:
{
auto it = waitable_handles_.begin();
while (it != waitable_handles_.end()) {
auto waitable = *it;
std::shared_ptr<Waitable> & waitable = *it;
if (waitable) {
// Find the group for this handle and see if it can be serviced
auto group = get_group_by_waitable(waitable, weak_groups_to_nodes);
@@ -443,7 +430,7 @@ public:
size_t number_of_ready_subscriptions() const override
{
size_t number_of_subscriptions = subscription_handles_.size();
for (auto waitable : waitable_handles_) {
for (const std::shared_ptr<Waitable> & waitable : waitable_handles_) {
number_of_subscriptions += waitable->get_number_of_ready_subscriptions();
}
return number_of_subscriptions;
@@ -452,7 +439,7 @@ public:
size_t number_of_ready_services() const override
{
size_t number_of_services = service_handles_.size();
for (auto waitable : waitable_handles_) {
for (const std::shared_ptr<Waitable> & waitable : waitable_handles_) {
number_of_services += waitable->get_number_of_ready_services();
}
return number_of_services;
@@ -461,7 +448,7 @@ public:
size_t number_of_ready_events() const override
{
size_t number_of_events = 0;
for (auto waitable : waitable_handles_) {
for (const std::shared_ptr<Waitable> & waitable : waitable_handles_) {
number_of_events += waitable->get_number_of_ready_events();
}
return number_of_events;
@@ -470,7 +457,7 @@ public:
size_t number_of_ready_clients() const override
{
size_t number_of_clients = client_handles_.size();
for (auto waitable : waitable_handles_) {
for (const std::shared_ptr<Waitable> & waitable : waitable_handles_) {
number_of_clients += waitable->get_number_of_ready_clients();
}
return number_of_clients;
@@ -479,7 +466,7 @@ public:
size_t number_of_guard_conditions() const override
{
size_t number_of_guard_conditions = guard_conditions_.size();
for (auto waitable : waitable_handles_) {
for (const std::shared_ptr<Waitable> & waitable : waitable_handles_) {
number_of_guard_conditions += waitable->get_number_of_ready_guard_conditions();
}
return number_of_guard_conditions;
@@ -488,7 +475,7 @@ public:
size_t number_of_ready_timers() const override
{
size_t number_of_timers = timer_handles_.size();
for (auto waitable : waitable_handles_) {
for (const std::shared_ptr<Waitable> & waitable : waitable_handles_) {
number_of_timers += waitable->get_number_of_ready_timers();
}
return number_of_timers;
@@ -504,7 +491,7 @@ private:
using VectorRebind =
std::vector<T, typename std::allocator_traits<Alloc>::template rebind_alloc<T>>;
VectorRebind<const rcl_guard_condition_t *> guard_conditions_;
VectorRebind<const rclcpp::GuardCondition *> guard_conditions_;
VectorRebind<std::shared_ptr<const rcl_subscription_t>> subscription_handles_;
VectorRebind<std::shared_ptr<const rcl_service_t>> service_handles_;

View File

@@ -60,10 +60,16 @@ class NodeTopicsInterface;
/// Subscription implementation, templated on the type of message this subscription receives.
template<
typename CallbackMessageT,
typename MessageT,
typename AllocatorT = std::allocator<void>,
/// MessageT::custom_type if MessageT is a TypeAdapter,
/// otherwise just MessageT.
typename SubscribedT = typename rclcpp::TypeAdapter<MessageT>::custom_type,
/// MessageT::ros_message_type if MessageT is a TypeAdapter,
/// otherwise just MessageT.
typename ROSMessageT = typename rclcpp::TypeAdapter<MessageT>::ros_message_type,
typename MessageMemoryStrategyT = rclcpp::message_memory_strategy::MessageMemoryStrategy<
CallbackMessageT,
ROSMessageT,
AllocatorT
>>
class Subscription : public SubscriptionBase
@@ -71,14 +77,36 @@ class Subscription : public SubscriptionBase
friend class rclcpp::node_interfaces::NodeTopicsInterface;
public:
using MessageAllocatorTraits = allocator::AllocRebind<CallbackMessageT, AllocatorT>;
using MessageAllocator = typename MessageAllocatorTraits::allocator_type;
using MessageDeleter = allocator::Deleter<MessageAllocator, CallbackMessageT>;
using ConstMessageSharedPtr = std::shared_ptr<const CallbackMessageT>;
using MessageUniquePtr = std::unique_ptr<CallbackMessageT, MessageDeleter>;
using SubscriptionTopicStatisticsSharedPtr =
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics<CallbackMessageT>>;
// Redeclare these here to use outside of the class.
using SubscribedType = SubscribedT;
using ROSMessageType = ROSMessageT;
using MessageMemoryStrategyType = MessageMemoryStrategyT;
using SubscribedTypeAllocatorTraits = allocator::AllocRebind<SubscribedType, AllocatorT>;
using SubscribedTypeAllocator = typename SubscribedTypeAllocatorTraits::allocator_type;
using SubscribedTypeDeleter = allocator::Deleter<SubscribedTypeAllocator, SubscribedType>;
using ROSMessageTypeAllocatorTraits = allocator::AllocRebind<ROSMessageType, AllocatorT>;
using ROSMessageTypeAllocator = typename ROSMessageTypeAllocatorTraits::allocator_type;
using ROSMessageTypeDeleter = allocator::Deleter<ROSMessageTypeAllocator, ROSMessageType>;
using MessageAllocatorTraits [[deprecated("use ROSMessageTypeAllocatorTraits")]] =
ROSMessageTypeAllocatorTraits;
using MessageAllocator [[deprecated("use ROSMessageTypeAllocator")]] =
ROSMessageTypeAllocator;
using MessageDeleter [[deprecated("use ROSMessageTypeDeleter")]] =
ROSMessageTypeDeleter;
using ConstMessageSharedPtr [[deprecated]] = std::shared_ptr<const ROSMessageType>;
using MessageUniquePtr
[[deprecated("use std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter> instead")]] =
std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>;
private:
using SubscriptionTopicStatisticsSharedPtr =
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics<ROSMessageType>>;
public:
RCLCPP_SMART_PTR_DEFINITIONS(Subscription)
/// Default constructor.
@@ -104,7 +132,7 @@ public:
const rosidl_message_type_support_t & type_support_handle,
const std::string & topic_name,
const rclcpp::QoS & qos,
AnySubscriptionCallback<CallbackMessageT, AllocatorT> callback,
AnySubscriptionCallback<MessageT, AllocatorT> callback,
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options,
typename MessageMemoryStrategyT::SharedPtr message_memory_strategy,
SubscriptionTopicStatisticsSharedPtr subscription_topic_statistics = nullptr)
@@ -112,25 +140,25 @@ public:
node_base,
type_support_handle,
topic_name,
options.template to_rcl_subscription_options<CallbackMessageT>(qos),
rclcpp::subscription_traits::is_serialized_subscription_argument<CallbackMessageT>::value),
options.template to_rcl_subscription_options<ROSMessageType>(qos),
callback.is_serialized_message_callback()),
any_callback_(callback),
options_(options),
message_memory_strategy_(message_memory_strategy)
{
if (options.event_callbacks.deadline_callback) {
if (options_.event_callbacks.deadline_callback) {
this->add_event_handler(
options.event_callbacks.deadline_callback,
options_.event_callbacks.deadline_callback,
RCL_SUBSCRIPTION_REQUESTED_DEADLINE_MISSED);
}
if (options.event_callbacks.liveliness_callback) {
if (options_.event_callbacks.liveliness_callback) {
this->add_event_handler(
options.event_callbacks.liveliness_callback,
options_.event_callbacks.liveliness_callback,
RCL_SUBSCRIPTION_LIVELINESS_CHANGED);
}
if (options.event_callbacks.incompatible_qos_callback) {
if (options_.event_callbacks.incompatible_qos_callback) {
this->add_event_handler(
options.event_callbacks.incompatible_qos_callback,
options_.event_callbacks.incompatible_qos_callback,
RCL_SUBSCRIPTION_REQUESTED_INCOMPATIBLE_QOS);
} else if (options_.use_default_callbacks) {
// Register default callback when not specified
@@ -144,53 +172,57 @@ public:
// pass
}
}
if (options.event_callbacks.message_lost_callback) {
if (options_.event_callbacks.message_lost_callback) {
this->add_event_handler(
options.event_callbacks.message_lost_callback,
options_.event_callbacks.message_lost_callback,
RCL_SUBSCRIPTION_MESSAGE_LOST);
}
// Setup intra process publishing if requested.
if (rclcpp::detail::resolve_use_intra_process(options, *node_base)) {
if (rclcpp::detail::resolve_use_intra_process(options_, *node_base)) {
using rclcpp::detail::resolve_intra_process_buffer_type;
// Check if the QoS is compatible with intra-process.
rmw_qos_profile_t qos_profile = get_actual_qos().get_rmw_qos_profile();
if (qos_profile.history == RMW_QOS_POLICY_HISTORY_KEEP_ALL) {
auto qos_profile = get_actual_qos();
if (qos_profile.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_profile.depth == 0) {
if (qos_profile.depth() == 0) {
throw std::invalid_argument(
"intraprocess communication is not allowed with 0 depth qos policy");
}
if (qos_profile.durability != RMW_QOS_POLICY_DURABILITY_VOLATILE) {
if (qos_profile.durability() != rclcpp::DurabilityPolicy::Volatile) {
throw std::invalid_argument(
"intraprocess communication allowed only with volatile durability");
}
using SubscriptionIntraProcessT = rclcpp::experimental::SubscriptionIntraProcess<
MessageT,
SubscribedType,
SubscribedTypeAllocator,
SubscribedTypeDeleter,
ROSMessageT,
AllocatorT>;
// First create a SubscriptionIntraProcess which will be given to the intra-process manager.
auto context = node_base->get_context();
using SubscriptionIntraProcessT = rclcpp::experimental::SubscriptionIntraProcess<
CallbackMessageT,
AllocatorT,
typename MessageUniquePtr::deleter_type>;
auto subscription_intra_process = std::make_shared<SubscriptionIntraProcessT>(
subscription_intra_process_ = std::make_shared<SubscriptionIntraProcessT>(
callback,
options.get_allocator(),
options_.get_allocator(),
context,
this->get_topic_name(), // important to get like this, as it has the fully-qualified name
qos_profile,
resolve_intra_process_buffer_type(options.intra_process_buffer_type, callback));
resolve_intra_process_buffer_type(options_.intra_process_buffer_type, callback));
TRACEPOINT(
rclcpp_subscription_init,
static_cast<const void *>(get_subscription_handle().get()),
static_cast<const void *>(subscription_intra_process.get()));
static_cast<const void *>(subscription_intra_process_.get()));
// Add it to the intra process manager.
using rclcpp::experimental::IntraProcessManager;
auto ipm = context->get_sub_context<IntraProcessManager>();
uint64_t intra_process_subscription_id = ipm->add_subscription(subscription_intra_process);
uint64_t intra_process_subscription_id = ipm->add_subscription(subscription_intra_process_);
this->setup_intra_process(intra_process_subscription_id, ipm);
}
@@ -245,11 +277,34 @@ public:
* \throws any rcl errors from rcl_take, \sa rclcpp::exceptions::throw_from_rcl_error()
*/
bool
take(CallbackMessageT & message_out, rclcpp::MessageInfo & message_info_out)
take(ROSMessageType & message_out, rclcpp::MessageInfo & message_info_out)
{
return this->take_type_erased(static_cast<void *>(&message_out), message_info_out);
}
/// Take the next message from the inter-process subscription.
/**
* This version takes a SubscribedType which is different from the
* ROSMessageType when a rclcpp::TypeAdapter is in used.
*
* \sa take(ROSMessageType &, rclcpp::MessageInfo &)
*/
template<typename TakeT>
std::enable_if_t<
!rosidl_generator_traits::is_message<TakeT>::value &&
std::is_same_v<TakeT, SubscribedType>,
bool
>
take(TakeT & message_out, rclcpp::MessageInfo & message_info_out)
{
ROSMessageType local_message;
bool taken = this->take_type_erased(static_cast<void *>(&local_message), message_info_out);
if (taken) {
rclcpp::TypeAdapter<MessageT>::convert_to_custom(local_message, message_out);
}
return taken;
}
std::shared_ptr<void>
create_message() override
{
@@ -276,27 +331,63 @@ public:
// we should ignore this copy of the message.
return;
}
auto typed_message = std::static_pointer_cast<CallbackMessageT>(message);
auto typed_message = std::static_pointer_cast<ROSMessageType>(message);
std::chrono::time_point<std::chrono::system_clock> now;
if (subscription_topic_statistics_) {
// get current time before executing callback to
// exclude callback duration from topic statistics result.
now = std::chrono::system_clock::now();
}
any_callback_.dispatch(typed_message, message_info);
if (subscription_topic_statistics_) {
const auto nanos = std::chrono::time_point_cast<std::chrono::nanoseconds>(
std::chrono::system_clock::now());
const auto nanos = std::chrono::time_point_cast<std::chrono::nanoseconds>(now);
const auto time = rclcpp::Time(nanos.time_since_epoch().count());
subscription_topic_statistics_->handle_message(*typed_message, time);
}
}
void
handle_serialized_message(
const std::shared_ptr<rclcpp::SerializedMessage> & serialized_message,
const rclcpp::MessageInfo & message_info) override
{
// TODO(wjwwood): enable topic statistics for serialized messages
any_callback_.dispatch(serialized_message, message_info);
}
void
handle_loaned_message(
void * loaned_message,
const rclcpp::MessageInfo & message_info) override
{
auto typed_message = static_cast<CallbackMessageT *>(loaned_message);
if (matches_any_intra_process_publishers(&message_info.get_rmw_message_info().publisher_gid)) {
// In this case, the message will be delivered via intra process and
// we should ignore this copy of the message.
return;
}
auto typed_message = static_cast<ROSMessageType *>(loaned_message);
// message is loaned, so we have to make sure that the deleter does not deallocate the message
auto sptr = std::shared_ptr<CallbackMessageT>(
typed_message, [](CallbackMessageT * msg) {(void) msg;});
auto sptr = std::shared_ptr<ROSMessageType>(
typed_message, [](ROSMessageType * msg) {(void) msg;});
std::chrono::time_point<std::chrono::system_clock> now;
if (subscription_topic_statistics_) {
// get current time before executing callback to
// exclude callback duration from topic statistics result.
now = std::chrono::system_clock::now();
}
any_callback_.dispatch(sptr, message_info);
if (subscription_topic_statistics_) {
const auto nanos = std::chrono::time_point_cast<std::chrono::nanoseconds>(now);
const auto time = rclcpp::Time(nanos.time_since_epoch().count());
subscription_topic_statistics_->handle_message(*typed_message, time);
}
}
/// Return the borrowed message.
@@ -306,7 +397,7 @@ public:
void
return_message(std::shared_ptr<void> & message) override
{
auto typed_message = std::static_pointer_cast<CallbackMessageT>(message);
auto typed_message = std::static_pointer_cast<ROSMessageType>(message);
message_memory_strategy_->return_message(typed_message);
}
@@ -329,15 +420,16 @@ public:
private:
RCLCPP_DISABLE_COPY(Subscription)
AnySubscriptionCallback<CallbackMessageT, AllocatorT> any_callback_;
AnySubscriptionCallback<MessageT, AllocatorT> any_callback_;
/// Copy of original options passed during construction.
/**
* It is important to save a copy of this so that the rmw payload which it
* may contain is kept alive for the duration of the subscription.
*/
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> options_;
typename message_memory_strategy::MessageMemoryStrategy<CallbackMessageT, AllocatorT>::SharedPtr
typename message_memory_strategy::MessageMemoryStrategy<ROSMessageType, AllocatorT>::SharedPtr
message_memory_strategy_;
/// Component which computes and publishes topic statistics for this subscriber
SubscriptionTopicStatisticsSharedPtr subscription_topic_statistics_{nullptr};
};

View File

@@ -17,23 +17,29 @@
#include <atomic>
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
#include <vector>
#include <utility>
#include "rcl/event_callback.h"
#include "rcl/subscription.h"
#include "rmw/impl/cpp/demangle.hpp"
#include "rmw/rmw.h"
#include "rclcpp/any_subscription_callback.hpp"
#include "rclcpp/detail/cpp_callback_trampoline.hpp"
#include "rclcpp/experimental/intra_process_manager.hpp"
#include "rclcpp/experimental/subscription_intra_process_base.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/message_info.hpp"
#include "rclcpp/network_flow_endpoint.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/qos_event.hpp"
#include "rclcpp/serialized_message.hpp"
#include "rclcpp/subscription_content_filter_options.hpp"
#include "rclcpp/type_support_decl.hpp"
#include "rclcpp/visibility_control.hpp"
@@ -61,8 +67,11 @@ class SubscriptionBase : public std::enable_shared_from_this<SubscriptionBase>
public:
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(SubscriptionBase)
/// Default constructor.
/// Constructor.
/**
* This accepts rcl_subscription_options_t instead of rclcpp::SubscriptionOptions because
* rclcpp::SubscriptionOptions::to_rcl_subscription_options depends on the message type.
*
* \param[in] node_base NodeBaseInterface pointer used in parts of the setup.
* \param[in] type_support_handle rosidl type support struct, for the Message type of the topic.
* \param[in] topic_name Name of the topic to subscribe to.
@@ -77,7 +86,7 @@ public:
const rcl_subscription_options_t & subscription_options,
bool is_serialized = false);
/// Default destructor.
/// Destructor.
RCLCPP_PUBLIC
virtual ~SubscriptionBase();
@@ -95,15 +104,16 @@ public:
get_subscription_handle() const;
/// Get all the QoS event handlers associated with this subscription.
/** \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_subscription_event_type_t, std::shared_ptr<rclcpp::QOSEventHandlerBase>> &
get_event_handlers() const;
/// Get the actual 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 publisher, and it
* can only be resolved after the creation of the subscription, 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.
@@ -179,6 +189,13 @@ public:
void
handle_message(std::shared_ptr<void> & message, const rclcpp::MessageInfo & message_info) = 0;
RCLCPP_PUBLIC
virtual
void
handle_serialized_message(
const std::shared_ptr<rclcpp::SerializedMessage> & serialized_message,
const rclcpp::MessageInfo & message_info) = 0;
RCLCPP_PUBLIC
virtual
void
@@ -263,6 +280,252 @@ public:
bool
exchange_in_use_by_wait_set_state(void * pointer_to_subscription_part, bool in_use_state);
/// Get network flow endpoints
/**
* Describes network flow endpoints that this subscription is receiving messages on
* \return vector of NetworkFlowEndpoint
*/
RCLCPP_PUBLIC
std::vector<rclcpp::NetworkFlowEndpoint>
get_network_flow_endpoints() const;
/// Set a callback to be called when each new message is received.
/**
* 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.
*
* 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.
*
* 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.
*
* \sa rmw_subscription_set_on_new_message_callback
* \sa rcl_subscription_set_on_new_message_callback
*
* \param[in] callback functor to be called when a new message is received
*/
void
set_on_new_message_callback(std::function<void(size_t)> callback)
{
if (!callback) {
throw std::invalid_argument(
"The callback passed to set_on_new_message_callback "
"is not callable.");
}
auto new_callback =
[callback, this](size_t number_of_messages) {
try {
callback(number_of_messages);
} catch (const std::exception & exception) {
RCLCPP_ERROR_STREAM(
node_logger_,
"rclcpp::SubscriptionBase@" << this <<
" caught " << rmw::impl::cpp::demangle(exception) <<
" exception in user-provided callback for the 'on new message' callback: " <<
exception.what());
} catch (...) {
RCLCPP_ERROR_STREAM(
node_logger_,
"rclcpp::SubscriptionBase@" << this <<
" caught unhandled exception in user-provided callback " <<
"for the 'on new message' 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_message_callback(
rclcpp::detail::cpp_callback_trampoline<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_message_callback_ = new_callback;
// Set it again, now using the permanent storage.
set_on_new_message_callback(
rclcpp::detail::cpp_callback_trampoline<const void *, size_t>,
static_cast<const void *>(&on_new_message_callback_));
}
/// Unset the callback registered for new messages, if any.
void
clear_on_new_message_callback()
{
std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
if (on_new_message_callback_) {
set_on_new_message_callback(nullptr, nullptr);
on_new_message_callback_ = nullptr;
}
}
/// Set a callback to be called when each new intra-process message is received.
/**
* 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.
*
* 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 subscription
* or other information, you may use a lambda with captures or std::bind.
*
* \sa rclcpp::SubscriptionIntraProcessBase::set_on_ready_callback
*
* \param[in] callback functor to be called when a new message is received
*/
void
set_on_new_intra_process_message_callback(std::function<void(size_t)> callback)
{
if (!use_intra_process_) {
RCLCPP_WARN(
rclcpp::get_logger("rclcpp"),
"Calling set_on_new_intra_process_message_callback for subscription with IPC disabled");
return;
}
if (!callback) {
throw std::invalid_argument(
"The callback passed to set_on_new_intra_process_message_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);
subscription_intra_process_->set_on_ready_callback(new_callback);
}
/// Unset the callback registered for new intra-process messages, if any.
void
clear_on_new_intra_process_message_callback()
{
if (!use_intra_process_) {
RCLCPP_WARN(
rclcpp::get_logger("rclcpp"),
"Calling clear_on_new_intra_process_message_callback for subscription with IPC disabled");
return;
}
subscription_intra_process_->clear_on_ready_callback();
}
/// 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::QOSEventHandlerBase::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_subscription_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 subscription 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_subscription_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();
}
/// Check if content filtered topic feature of the subscription instance is enabled.
/**
* \return boolean flag indicating if the content filtered topic of this subscription is enabled.
*/
RCLCPP_PUBLIC
bool
is_cft_enabled() const;
/// Set the filter expression and expression parameters for the subscription.
/**
* \param[in] filter_expression A filter expression to set.
* \sa ContentFilterOptions::filter_expression
* An empty string ("") will clear the content filter setting of the subscription.
* \param[in] expression_parameters Array of expression parameters to set.
* \sa ContentFilterOptions::expression_parameters
* \throws RCLBadAlloc if memory cannot be allocated
* \throws RCLError if an unexpect error occurs
*/
RCLCPP_PUBLIC
void
set_content_filter(
const std::string & filter_expression,
const std::vector<std::string> & expression_parameters = {});
/// Get the filter expression and expression parameters for the subscription.
/**
* \return rclcpp::ContentFilterOptions The content filter options to get.
* \throws RCLBadAlloc if memory cannot be allocated
* \throws RCLError if an unexpect error occurs
*/
RCLCPP_PUBLIC
rclcpp::ContentFilterOptions
get_content_filter() const;
protected:
template<typename EventCallbackT>
void
@@ -277,7 +540,7 @@ protected:
get_subscription_handle(),
event_type);
qos_events_in_use_by_wait_set_.insert(std::make_pair(handler.get(), false));
event_handlers_.emplace_back(handler);
event_handlers_.insert(std::make_pair(event_type, handler));
}
RCLCPP_PUBLIC
@@ -287,17 +550,24 @@ protected:
bool
matches_any_intra_process_publishers(const rmw_gid_t * sender_gid) const;
RCLCPP_PUBLIC
void
set_on_new_message_callback(rcl_event_callback_t callback, const void * user_data);
rclcpp::node_interfaces::NodeBaseInterface * const node_base_;
std::shared_ptr<rcl_node_t> node_handle_;
std::shared_ptr<rcl_subscription_t> subscription_handle_;
std::shared_ptr<rcl_subscription_t> intra_process_subscription_handle_;
rclcpp::Logger node_logger_;
std::vector<std::shared_ptr<rclcpp::QOSEventHandlerBase>> event_handlers_;
std::unordered_map<rcl_subscription_event_type_t,
std::shared_ptr<rclcpp::QOSEventHandlerBase>> event_handlers_;
bool use_intra_process_;
IntraProcessManagerWeakPtr weak_ipm_;
uint64_t intra_process_subscription_id_;
std::shared_ptr<rclcpp::experimental::SubscriptionIntraProcessBase> subscription_intra_process_;
private:
RCLCPP_DISABLE_COPY(SubscriptionBase)
@@ -309,6 +579,9 @@ private:
std::atomic<bool> intra_process_subscription_waitable_in_use_by_wait_set_{false};
std::unordered_map<rclcpp::QOSEventHandlerBase *,
std::atomic<bool>> qos_events_in_use_by_wait_set_;
std::recursive_mutex callback_mutex_;
std::function<void(size_t)> on_new_message_callback_{nullptr};
};
} // namespace rclcpp

View File

@@ -0,0 +1,38 @@
// 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__SUBSCRIPTION_CONTENT_FILTER_OPTIONS_HPP_
#define RCLCPP__SUBSCRIPTION_CONTENT_FILTER_OPTIONS_HPP_
#include <string>
#include <vector>
namespace rclcpp
{
/// Options to configure content filtered topic in the subscription.
struct ContentFilterOptions
{
/// Filter expression is similar to the WHERE part of an SQL clause.
std::string filter_expression;
/**
* Expression parameters is the tokens placeholder parameters (i.e., "%n" tokens begin from 0)
* in the filter_expression. The maximum expression_parameters size is 100.
*/
std::vector<std::string> expression_parameters;
};
} // namespace rclcpp
#endif // RCLCPP__SUBSCRIPTION_CONTENT_FILTER_OPTIONS_HPP_

View File

@@ -25,14 +25,14 @@
#include "rosidl_typesupport_cpp/message_type_support.hpp"
#include "rclcpp/any_subscription_callback.hpp"
#include "rclcpp/intra_process_buffer_type.hpp"
#include "rclcpp/get_message_type_support_handle.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/subscription.hpp"
#include "rclcpp/subscription_options.hpp"
#include "rclcpp/subscription_traits.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rclcpp/topic_statistics/subscription_topic_statistics.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
@@ -74,26 +74,23 @@ template<
typename MessageT,
typename CallbackT,
typename AllocatorT,
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 ROSMessageType = typename SubscriptionT::ROSMessageType
>
SubscriptionFactory
create_subscription_factory(
CallbackT && callback,
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options,
typename MessageMemoryStrategyT::SharedPtr msg_mem_strat,
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics<CallbackMessageT>>
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics<ROSMessageType>>
subscription_topic_stats = nullptr
)
{
auto allocator = options.get_allocator();
using rclcpp::AnySubscriptionCallback;
AnySubscriptionCallback<CallbackMessageT, AllocatorT> any_subscription_callback(allocator);
AnySubscriptionCallback<MessageT, AllocatorT> any_subscription_callback(*allocator);
any_subscription_callback.set(std::forward<CallbackT>(callback));
SubscriptionFactory factory {
@@ -107,9 +104,9 @@ create_subscription_factory(
using rclcpp::Subscription;
using rclcpp::SubscriptionBase;
auto sub = Subscription<CallbackMessageT, AllocatorT>::make_shared(
auto sub = Subscription<MessageT, AllocatorT>::make_shared(
node_base,
*rosidl_typesupport_cpp::get_message_type_support_handle<MessageT>(),
rclcpp::get_message_type_support_handle<MessageT>(),
topic_name,
qos,
any_subscription_callback,

View File

@@ -18,6 +18,7 @@
#include <chrono>
#include <memory>
#include <string>
#include <type_traits>
#include <vector>
#include "rclcpp/callback_group.hpp"
@@ -26,6 +27,8 @@
#include "rclcpp/intra_process_setting.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/qos_event.hpp"
#include "rclcpp/qos_overriding_options.hpp"
#include "rclcpp/subscription_content_filter_options.hpp"
#include "rclcpp/topic_statistics_state.hpp"
#include "rclcpp/visibility_control.hpp"
@@ -44,6 +47,11 @@ struct SubscriptionOptionsBase
/// True to ignore local publications.
bool ignore_local_publications = false;
/// Require middleware to generate unique network flow endpoints
/// Disabled by default
rmw_unique_network_flow_endpoints_requirement_t require_unique_network_flow_endpoints =
RMW_UNIQUE_NETWORK_FLOW_ENDPOINTS_NOT_REQUIRED;
/// The callback group for this subscription. NULL to use the default callback group.
rclcpp::CallbackGroup::SharedPtr callback_group = nullptr;
@@ -72,16 +80,24 @@ struct SubscriptionOptionsBase
};
TopicStatisticsOptions topic_stats_options;
QosOverridingOptions qos_overriding_options;
ContentFilterOptions content_filter_options;
};
/// Structure containing optional configuration for Subscriptions.
template<typename Allocator>
struct SubscriptionOptionsWithAllocator : public SubscriptionOptionsBase
{
static_assert(
std::is_void_v<typename std::allocator_traits<Allocator>::value_type>,
"Subscription allocator value type must be void");
/// Optional custom allocator.
std::shared_ptr<Allocator> allocator = nullptr;
SubscriptionOptionsWithAllocator<Allocator>() {}
SubscriptionOptionsWithAllocator() {}
/// Constructor using base class as input.
explicit SubscriptionOptionsWithAllocator(
@@ -99,30 +115,68 @@ struct SubscriptionOptionsWithAllocator : public SubscriptionOptionsBase
to_rcl_subscription_options(const rclcpp::QoS & qos) const
{
rcl_subscription_options_t result = rcl_subscription_get_default_options();
using AllocatorTraits = std::allocator_traits<Allocator>;
using MessageAllocatorT = typename AllocatorTraits::template rebind_alloc<MessageT>;
auto message_alloc = std::make_shared<MessageAllocatorT>(*allocator.get());
result.allocator = allocator::get_rcl_allocator<MessageT>(*message_alloc);
result.allocator = this->get_rcl_allocator();
result.qos = qos.get_rmw_qos_profile();
result.rmw_subscription_options.ignore_local_publications = this->ignore_local_publications;
result.rmw_subscription_options.require_unique_network_flow_endpoints =
this->require_unique_network_flow_endpoints;
// Apply payload to rcl_subscription_options if necessary.
if (rmw_implementation_payload && rmw_implementation_payload->has_been_customized()) {
rmw_implementation_payload->modify_rmw_subscription_options(result.rmw_subscription_options);
}
// Copy content_filter_options into rcl_subscription_options.
if (!content_filter_options.filter_expression.empty()) {
std::vector<const char *> cstrings =
get_c_vector_string(content_filter_options.expression_parameters);
rcl_ret_t ret = rcl_subscription_options_set_content_filter_options(
get_c_string(content_filter_options.filter_expression),
cstrings.size(),
cstrings.data(),
&result);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(
ret, "failed to set content_filter_options");
}
}
return result;
}
/// Get the allocator, creating one if needed.
std::shared_ptr<Allocator>
get_allocator() const
{
if (!this->allocator) {
return std::make_shared<Allocator>();
if (!allocator_storage_) {
allocator_storage_ = std::make_shared<Allocator>();
}
return allocator_storage_;
}
return this->allocator;
}
private:
using PlainAllocator =
typename std::allocator_traits<Allocator>::template rebind_alloc<char>;
rcl_allocator_t
get_rcl_allocator() const
{
if (!plain_allocator_storage_) {
plain_allocator_storage_ =
std::make_shared<PlainAllocator>(*this->get_allocator());
}
return rclcpp::allocator::get_rcl_allocator<char>(*plain_allocator_storage_);
}
// This is a temporal workaround, to make sure that get_allocator()
// always returns a copy of the same allocator.
mutable std::shared_ptr<Allocator> allocator_storage_;
// This is a temporal workaround, to keep the plain allocator that backs
// up the rcl allocator returned in rcl_subscription_options_t alive.
mutable std::shared_ptr<PlainAllocator> plain_allocator_storage_;
};
using SubscriptionOptions = SubscriptionOptionsWithAllocator<std::allocator<void>>;

View File

@@ -64,7 +64,7 @@ struct is_serialized_callback
template<typename MessageT>
struct extract_message_type
{
using type = typename std::remove_cv<MessageT>::type;
using type = typename std::remove_cv_t<std::remove_reference_t<MessageT>>;
};
template<typename MessageT>

View File

@@ -25,6 +25,7 @@
#include "rcl_interfaces/msg/parameter_event.hpp"
#include "rclcpp/node.hpp"
#include "rclcpp/executors.hpp"
#include "rclcpp/node_interfaces/node_parameters_interface.hpp"
@@ -32,6 +33,20 @@ namespace rclcpp
{
class Clock;
/**
* Time source that will drive the attached clocks.
*
* If the attached node `use_sim_time` parameter is `true`, the attached clocks will
* be updated based on messages received.
*
* The subscription to the clock topic created by the time source can have it's qos reconfigured
* using parameter overrides, particularly the following ones are accepted:
*
* - qos_overrides./clock.depth
* - qos_overrides./clock.durability
* - qos_overrides./clock.history
* - qos_overrides./clock.reliability
*/
class TimeSource
{
public:
@@ -41,27 +56,42 @@ public:
*
* \param node std::shared pointer to a initialized node
* \param qos QoS that will be used when creating a `/clock` subscription.
* \param use_clock_thread whether to spin the attached node in a separate thread
*/
RCLCPP_PUBLIC
explicit TimeSource(rclcpp::Node::SharedPtr node, const rclcpp::QoS & qos = rclcpp::ClockQoS());
explicit TimeSource(
rclcpp::Node::SharedPtr node,
const rclcpp::QoS & qos = rclcpp::ClockQoS(),
bool use_clock_thread = true);
/// Empty constructor
/**
* An Empty TimeSource class
*
* \param qos QoS that will be used when creating a `/clock` subscription.
* \param use_clock_thread whether to spin the attached node in a separate thread.
*/
RCLCPP_PUBLIC
explicit TimeSource(const rclcpp::QoS & qos = rclcpp::ClockQoS());
explicit TimeSource(
const rclcpp::QoS & qos = rclcpp::ClockQoS(),
bool use_clock_thread = true);
/// Attack node to the time source.
// The TimeSource is uncopyable
TimeSource(const TimeSource &) = delete;
TimeSource & operator=(const TimeSource &) = delete;
// The TimeSource is moveable
TimeSource(TimeSource &&) = default;
TimeSource & operator=(TimeSource &&) = default;
/// Attach node to the time source.
/**
* \param node std::shared pointer to a initialized node
*/
RCLCPP_PUBLIC
void attachNode(rclcpp::Node::SharedPtr node);
/// Attack node to the time source.
/// Attach node to the time source.
/**
* If the parameter `use_sim_time` is `true` then the source time is the simulation time,
* otherwise the source time is defined by the system.
@@ -96,81 +126,33 @@ public:
RCLCPP_PUBLIC
void attachClock(rclcpp::Clock::SharedPtr clock);
/// Detach a clock to the time source
/// Detach a clock from the time source
RCLCPP_PUBLIC
void detachClock(rclcpp::Clock::SharedPtr clock);
/// Get whether a separate clock thread is used or not
RCLCPP_PUBLIC
bool get_use_clock_thread();
/// Set whether to use a separate clock thread or not
RCLCPP_PUBLIC
void set_use_clock_thread(bool use_clock_thread);
/// Check if the clock thread is joinable
RCLCPP_PUBLIC
bool clock_thread_is_joinable();
/// TimeSource Destructor
RCLCPP_PUBLIC
~TimeSource();
private:
// Preserve the node reference
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_;
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::NodeClockInterface::SharedPtr node_clock_;
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr node_parameters_;
class NodeState;
std::shared_ptr<NodeState> node_state_;
// Store (and update on node attach) logger for logging.
Logger logger_;
// QoS of the clock subscription.
rclcpp::QoS qos_;
// The subscription for the clock callback
using MessageT = rosgraph_msgs::msg::Clock;
using Alloc = std::allocator<void>;
using SubscriptionT = rclcpp::Subscription<MessageT, Alloc>;
std::shared_ptr<SubscriptionT> clock_subscription_{nullptr};
std::mutex clock_sub_lock_;
// The clock callback itself
void clock_cb(const rosgraph_msgs::msg::Clock::SharedPtr msg);
// Create the subscription for the clock topic
void create_clock_sub();
// Destroy the subscription for the clock topic
void destroy_clock_sub();
// Parameter Event subscription
using ParamMessageT = rcl_interfaces::msg::ParameterEvent;
using ParamSubscriptionT = rclcpp::Subscription<ParamMessageT, Alloc>;
std::shared_ptr<ParamSubscriptionT> parameter_subscription_;
// Callback for parameter updates
void on_parameter_event(const rcl_interfaces::msg::ParameterEvent::SharedPtr event);
// An enum to hold the parameter state
enum UseSimTimeParameterState {UNSET, SET_TRUE, SET_FALSE};
UseSimTimeParameterState parameter_state_;
// An internal method to use in the clock callback that iterates and enables all clocks
void enable_ros_time();
// An internal method to use in the clock callback that iterates and disables all clocks
void disable_ros_time();
// Internal helper functions used inside iterators
static void set_clock(
const builtin_interfaces::msg::Time::SharedPtr msg,
bool set_ros_time_enabled,
rclcpp::Clock::SharedPtr clock);
// Local storage of validity of ROS time
// This is needed when new clocks are added.
bool ros_time_active_{false};
// Last set message to be passed to newly registered clocks
rosgraph_msgs::msg::Clock::SharedPtr last_msg_set_;
// A lock to protect iterating the associated_clocks_ field.
std::mutex clock_list_lock_;
// A vector to store references to associated clocks.
std::vector<rclcpp::Clock::SharedPtr> associated_clocks_;
// A handler for the use_sim_time parameter callback.
rclcpp::node_interfaces::OnSetParametersCallbackHandle::SharedPtr sim_time_cb_handler_{nullptr};
// Preserve the arguments received by the constructor for reuse at runtime
bool constructed_use_clock_thread_;
rclcpp::QoS constructed_qos_;
};
} // namespace rclcpp

View File

@@ -91,6 +91,17 @@ public:
void
reset();
/// Indicate that we're about to execute the callback.
/**
* The multithreaded executor takes advantage of this to avoid scheduling
* the callback multiple times.
*
* \return `true` if the callback should be executed, `false` if the timer was canceled.
*/
RCLCPP_PUBLIC
virtual bool
call() = 0;
/// Call the callback function when the timer signal is emitted.
RCLCPP_PUBLIC
virtual void
@@ -102,7 +113,8 @@ public:
/// Check how long the timer has until its next scheduled callback.
/**
* \return A std::chrono::duration representing the relative time until the next callback.
* \return A std::chrono::duration representing the relative time until the next callback
* or std::chrono::nanoseconds::max() if the timer is canceled.
* \throws std::runtime_error if the rcl_timer_get_time_until_next_call returns a failure
*/
RCLCPP_PUBLIC
@@ -181,7 +193,7 @@ public:
TRACEPOINT(
rclcpp_callback_register,
static_cast<const void *>(&callback_),
get_symbol(callback_));
tracetools::get_symbol(callback_));
}
/// Default destructor.
@@ -192,19 +204,28 @@ public:
}
/**
* \sa rclcpp::TimerBase::execute_callback
* \throws std::runtime_error if it failed to notify timer that callback occurred
* \sa rclcpp::TimerBase::call
* \throws std::runtime_error if it failed to notify timer that callback will occurr
*/
void
execute_callback() override
bool
call() override
{
rcl_ret_t ret = rcl_timer_call(timer_handle_.get());
if (ret == RCL_RET_TIMER_CANCELED) {
return;
return false;
}
if (ret != RCL_RET_OK) {
throw std::runtime_error("Failed to notify timer that callback occurred");
}
return true;
}
/**
* \sa rclcpp::TimerBase::execute_callback
*/
void
execute_callback() override
{
TRACEPOINT(callback_start, static_cast<const void *>(&callback_), false);
execute_callback_delegate<>();
TRACEPOINT(callback_end, static_cast<const void *>(&callback_));

View File

@@ -127,7 +127,7 @@ public:
/**
* This method acquires a lock to prevent race conditions to collectors list.
*/
virtual void publish_message()
virtual void publish_message_and_reset_measurements()
{
std::vector<MetricsMessage> msgs;
rclcpp::Time window_end{get_current_nanoseconds_since_epoch()};
@@ -136,6 +136,7 @@ public:
std::lock_guard<std::mutex> lock(mutex_);
for (auto & collector : subscriber_statistics_collectors_) {
const auto collected_stats = collector->GetStatisticsResults();
collector->ClearCurrentMeasurements();
auto message = libstatistics_collector::collector::GenerateStatisticMessage(
node_name_,

View File

@@ -0,0 +1,201 @@
// 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__TYPE_ADAPTER_HPP_
#define RCLCPP__TYPE_ADAPTER_HPP_
#include <type_traits>
namespace rclcpp
{
/// Template structure used to adapt custom, user-defined types to ROS types.
/**
* Adapting a custom, user-defined type to a ROS type allows that custom type
* to be used when publishing and subscribing in ROS.
*
* In order to adapt a custom type to a ROS type, the user must create a
* template specialization of this structure for the custom type.
* In that specialization they must:
*
* - change `is_specialized` to `std::true_type`,
* - specify the custom type with `using custom_type = ...`,
* - specify the ROS type with `using ros_message_type = ...`,
* - provide static convert functions with the signatures:
* - static void convert_to_ros(const custom_type &, ros_message_type &)
* - static void convert_to_custom(const ros_message_type &, custom_type &)
*
* The convert functions must convert from one type to the other.
*
* For example, here is a theoretical example for adapting `std::string` to the
* `std_msgs::msg::String` ROS message type:
*
* template<>
* struct rclcpp::TypeAdapter<std::string, std_msgs::msg::String>
* {
* using is_specialized = std::true_type;
* using custom_type = std::string;
* using ros_message_type = std_msgs::msg::String;
*
* static
* void
* convert_to_ros_message(
* const custom_type & source,
* ros_message_type & destination)
* {
* destination.data = source;
* }
*
* static
* void
* convert_to_custom(
* const ros_message_type & source,
* custom_type & destination)
* {
* destination = source.data;
* }
* };
*
* The adapter can then be used when creating a publisher or subscription,
* e.g.:
*
* using MyAdaptedType = TypeAdapter<std::string, std_msgs::msg::String>;
* auto pub = node->create_publisher<MyAdaptedType>("topic", 10);
* auto sub = node->create_subscription<MyAdaptedType>(
* "topic",
* 10,
* [](const std::string & msg) {...});
*
* You can also be more declarative by using the adapt_type::as metafunctions,
* which are a bit less ambiguous to read:
*
* using AdaptedType = rclcpp::adapt_type<std::string>::as<std_msgs::msg::String>;
* auto pub = node->create_publisher<AdaptedType>(...);
*
* If you wish, you may associate a custom type with a single ROS message type,
* allowing you to be a bit more brief when creating entities, e.g.:
*
* // First you must declare the association, this is similar to how you
* // would avoid using the namespace in C++ by doing `using std::vector;`.
* RCLCPP_USING_CUSTOM_TYPE_AS_ROS_MESSAGE_TYPE(std::string, std_msgs::msg::String);
*
* // Then you can create things with just the custom type, and the ROS
* // message type is implied based on the previous statement.
* auto pub = node->create_publisher<std::string>(...);
*/
template<typename CustomType, typename ROSMessageType = void, class Enable = void>
struct TypeAdapter
{
using is_specialized = std::false_type;
using custom_type = CustomType;
// In this case, the CustomType is the only thing given, or there is no specialization.
// Assign ros_message_type to CustomType for the former case.
using ros_message_type = CustomType;
};
/// Helper template to determine if a type is a TypeAdapter, false specialization.
template<typename T>
struct is_type_adapter : std::false_type {};
/// Helper template to determine if a type is a TypeAdapter, true specialization.
template<typename ... Ts>
struct is_type_adapter<TypeAdapter<Ts...>>: std::true_type {};
/// Identity specialization for TypeAdapter.
template<typename T>
struct TypeAdapter<T, void, std::enable_if_t<is_type_adapter<T>::value>>: T {};
namespace detail
{
template<typename CustomType, typename ROSMessageType>
struct assert_type_pair_is_specialized_type_adapter
{
using type_adapter = TypeAdapter<CustomType, ROSMessageType>;
static_assert(
type_adapter::is_specialized::value,
"No type adapter for this custom type/ros message type pair");
};
} // namespace detail
/// Template metafunction that can make the type being adapted explicit.
template<typename CustomType>
struct adapt_type
{
template<typename ROSMessageType>
using as = typename ::rclcpp::detail::assert_type_pair_is_specialized_type_adapter<
CustomType,
ROSMessageType
>::type_adapter;
};
/// Implicit type adapter used as a short hand way to create something with just the custom type.
/**
* This is used when creating a publisher or subscription using just the custom
* type in conjunction with RCLCPP_USING_CUSTOM_TYPE_AS_ROS_MESSAGE_TYPE().
* For example:
*
* #include "type_adapter_for_std_string_to_std_msgs_String.hpp"
*
* RCLCPP_USING_CUSTOM_TYPE_AS_ROS_MESSAGE_TYPE(std::string, std_msgs::msg::String);
*
* int main(...) {
* // ...
* auto pub = node->create_publisher<std::string>(...);
* }
*
* \sa TypeAdapter for more examples.
*/
template<typename CustomType>
struct ImplicitTypeAdapter
{
using is_specialized = std::false_type;
};
/// Specialization of TypeAdapter for ImplicitTypeAdapter.
/**
* This allows for things like this:
*
* RCLCPP_USING_CUSTOM_TYPE_AS_ROS_MESSAGE_TYPE(std::string, std_msgs::msg::String);
* auto pub = node->create_publisher<std::string>("topic", 10);
*
*/
template<typename T>
struct TypeAdapter<T, void, std::enable_if_t<ImplicitTypeAdapter<T>::is_specialized::value>>
: ImplicitTypeAdapter<T>
{};
/// Assigns the custom type implicitly to the given custom type/ros message type pair.
/**
* Note: this macro needs to be used in the root namespace.
* We cannot use ::rclcpp to protect against this, due to how GCC interprets the
* syntax, see: https://stackoverflow.com/a/2781537
*
* \sa TypeAdapter
* \sa ImplicitTypeAdapter
*/
#define RCLCPP_USING_CUSTOM_TYPE_AS_ROS_MESSAGE_TYPE(CustomType, ROSMessageType) \
template<> \
struct rclcpp::ImplicitTypeAdapter<CustomType> \
: public rclcpp::TypeAdapter<CustomType, ROSMessageType> \
{ \
static_assert( \
is_specialized::value, \
"Cannot use custom type as ros type when there is no TypeAdapter for that pair"); \
}
} // namespace rclcpp
#endif // RCLCPP__TYPE_ADAPTER_HPP_

View File

@@ -0,0 +1,57 @@
// 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__TYPESUPPORT_HELPERS_HPP_
#define RCLCPP__TYPESUPPORT_HELPERS_HPP_
#include <memory>
#include <string>
#include <tuple>
#include "rcpputils/shared_library.hpp"
#include "rosidl_runtime_cpp/message_type_support_decl.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
/// Load the type support library for the given type.
/**
* \param[in] type The topic type, e.g. "std_msgs/msg/String"
* \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
* \return A shared library
*/
RCLCPP_PUBLIC
std::shared_ptr<rcpputils::SharedLibrary>
get_typesupport_library(const std::string & type, const std::string & typesupport_identifier);
/// Extract the type support handle from the library.
/**
* The library needs to match the topic type. The shared library must stay loaded for the lifetime of the result.
* \param[in] type The topic type, e.g. "std_msgs/msg/String"
* \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
* \param[in] library The shared type support library
* \return A type support handle
*/
RCLCPP_PUBLIC
const rosidl_message_type_support_t *
get_typesupport_handle(
const std::string & type,
const std::string & typesupport_identifier,
rcpputils::SharedLibrary & library);
} // namespace rclcpp
#endif // RCLCPP__TYPESUPPORT_HELPERS_HPP_

View File

@@ -42,6 +42,20 @@ std::string to_string(T value)
namespace rclcpp
{
/// Option to indicate which signal handlers rclcpp should install.
enum class SignalHandlerOptions
{
/// Install both sigint and sigterm, this is the default behavior.
All,
/// Install only a sigint handler.
SigInt,
/// Install only a sigterm handler.
SigTerm,
/// Do not install any signal handler.
None,
};
/// Initialize communications via the rmw implementation and set up a global signal handler.
/**
* Initializes the global context which is accessible via the function
@@ -50,10 +64,19 @@ namespace rclcpp
* rclcpp::install_signal_handlers().
*
* \sa rclcpp::Context::init() for more details on arguments and possible exceptions
*
* \param[in] argc number of command-line arguments to parse.
* \param[in] argv array of command-line arguments to parse.
* \param[in] init_options initialization options to apply.
* \param[in] signal_handler_options option to indicate which signal handlers should be installed.
*/
RCLCPP_PUBLIC
void
init(int argc, char const * const argv[], const InitOptions & init_options = InitOptions());
init(
int argc,
char const * const * argv,
const InitOptions & init_options = InitOptions(),
SignalHandlerOptions signal_handler_options = SignalHandlerOptions::All);
/// Install the global signal handler for rclcpp.
/**
@@ -67,17 +90,26 @@ init(int argc, char const * const argv[], const InitOptions & init_options = Ini
*
* This function is thread-safe.
*
* \param[in] signal_handler_options option to indicate which signal handlers should be installed.
* \return true if signal handler was installed by this function, false if already installed.
*/
RCLCPP_PUBLIC
bool
install_signal_handlers();
install_signal_handlers(SignalHandlerOptions signal_handler_options = SignalHandlerOptions::All);
/// Return true if the signal handlers are installed, otherwise false.
RCLCPP_PUBLIC
bool
signal_handlers_installed();
/// Get the current signal handler options.
/**
* If no signal handler is installed, SignalHandlerOptions::None is returned.
*/
RCLCPP_PUBLIC
SignalHandlerOptions
get_current_signal_handler_options();
/// Uninstall the global signal handler for rclcpp.
/**
* This function does not necessarily need to be called, but can be used to
@@ -107,7 +139,7 @@ RCLCPP_PUBLIC
std::vector<std::string>
init_and_remove_ros_arguments(
int argc,
char const * const argv[],
char const * const * argv,
const InitOptions & init_options = InitOptions());
/// Remove ROS-specific arguments from argument vector.
@@ -125,7 +157,7 @@ init_and_remove_ros_arguments(
*/
RCLCPP_PUBLIC
std::vector<std::string>
remove_ros_arguments(int argc, char const * const argv[]);
remove_ros_arguments(int argc, char const * const * argv);
/// Check rclcpp's status.
/**
@@ -143,21 +175,6 @@ RCLCPP_PUBLIC
bool
ok(rclcpp::Context::SharedPtr context = nullptr);
/// Return true if init() has already been called for the given context.
/**
* If nullptr is given for the context, then the global context is used, i.e.
* the context initialized by rclcpp::init().
*
* Deprecated, as it is no longer different from rcl_ok().
*
* \param[in] context Optional check for initialization of this Context.
* \return true if the context is initialized, and false otherwise
*/
[[deprecated("use the function ok() instead, which has the same usage.")]]
RCLCPP_PUBLIC
bool
is_initialized(rclcpp::Context::SharedPtr context = nullptr);
/// Shutdown rclcpp context, invalidating it for derived entities.
/**
* If nullptr is given for the context, then the global context is used, i.e.
@@ -304,6 +321,15 @@ RCLCPP_PUBLIC
const char *
get_c_string(const std::string & string_in);
/// Return the std::vector of C string from the given std::vector<std::string>.
/**
* \param[in] strings_in is a std::vector of std::string
* \return the std::vector of C string from the std::vector<std::string>
*/
RCLCPP_PUBLIC
std::vector<const char *>
get_c_vector_string(const std::vector<std::string> & strings_in);
} // namespace rclcpp
#endif // RCLCPP__UTILITIES_HPP_

View File

@@ -0,0 +1,103 @@
// 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__WAIT_FOR_MESSAGE_HPP_
#define RCLCPP__WAIT_FOR_MESSAGE_HPP_
#include <memory>
#include <string>
#include "rcpputils/scope_exit.hpp"
#include "rclcpp/node.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rclcpp/wait_set.hpp"
namespace rclcpp
{
/// Wait for the next incoming message.
/**
* Given an already initialized subscription,
* wait for the next incoming message to arrive before the specified timeout.
*
* \param[out] out is the message to be filled when a new message is arriving.
* \param[in] subscription shared pointer to a previously initialized subscription.
* \param[in] context shared pointer to a context to watch for SIGINT requests.
* \param[in] time_to_wait parameter specifying the timeout before returning.
* \return true if a message was successfully received, false if message could not
* be obtained or shutdown was triggered asynchronously on the context.
*/
template<class MsgT, class Rep = int64_t, class Period = std::milli>
bool wait_for_message(
MsgT & out,
std::shared_ptr<rclcpp::Subscription<MsgT>> subscription,
std::shared_ptr<rclcpp::Context> context,
std::chrono::duration<Rep, Period> time_to_wait = std::chrono::duration<Rep, Period>(-1))
{
auto gc = std::make_shared<rclcpp::GuardCondition>(context);
auto shutdown_callback_handle = context->add_on_shutdown_callback(
[weak_gc = std::weak_ptr<rclcpp::GuardCondition>{gc}]() {
auto strong_gc = weak_gc.lock();
if (strong_gc) {
strong_gc->trigger();
}
});
rclcpp::WaitSet wait_set;
wait_set.add_subscription(subscription);
RCPPUTILS_SCOPE_EXIT(wait_set.remove_subscription(subscription); );
wait_set.add_guard_condition(gc);
auto ret = wait_set.wait(time_to_wait);
if (ret.kind() != rclcpp::WaitResultKind::Ready) {
return false;
}
if (wait_set.get_rcl_wait_set().guard_conditions[0]) {
return false;
}
rclcpp::MessageInfo info;
if (!subscription->take(out, info)) {
return false;
}
return true;
}
/// Wait for the next incoming message.
/**
* Wait for the next incoming message to arrive on a specified topic before the specified timeout.
*
* \param[out] out is the message to be filled when a new message is arriving.
* \param[in] node the node pointer to initialize the subscription on.
* \param[in] topic the topic to wait for messages.
* \param[in] time_to_wait parameter specifying the timeout before returning.
* \return true if a message was successfully received, false if message could not
* be obtained or shutdown was triggered asynchronously on the context.
*/
template<class MsgT, class Rep = int64_t, class Period = std::milli>
bool wait_for_message(
MsgT & out,
rclcpp::Node::SharedPtr node,
const std::string & topic,
std::chrono::duration<Rep, Period> time_to_wait = std::chrono::duration<Rep, Period>(-1))
{
auto sub = node->create_subscription<MsgT>(topic, 1, [](const std::shared_ptr<const MsgT>) {});
return wait_for_message<MsgT, Rep, Period>(
out, sub, node->get_node_options().context(), time_to_wait);
}
} // namespace rclcpp
#endif // RCLCPP__WAIT_FOR_MESSAGE_HPP_

View File

@@ -383,10 +383,7 @@ protected:
continue;
}
rclcpp::Waitable & waitable = *waitable_ptr_pair.second;
bool successful = waitable.add_to_wait_set(&rcl_wait_set_);
if (!successful) {
throw std::runtime_error("waitable unexpectedly failed to be added to wait set");
}
waitable.add_to_wait_set(&rcl_wait_set_);
}
}

View File

@@ -191,7 +191,7 @@ protected:
WritePreferringReadWriteLock & parent_lock_;
friend WritePreferringReadWriteLock;
friend class WritePreferringReadWriteLock;
};
/// Write mutex for the WritePreferringReadWriteLock.
@@ -212,7 +212,7 @@ protected:
WritePreferringReadWriteLock & parent_lock_;
friend WritePreferringReadWriteLock;
friend class WritePreferringReadWriteLock;
};
/// Return read mutex which can be used with standard constructs like std::lock_guard.

Some files were not shown because too many files have changed in this diff Show More