Compare commits

...

44 Commits

Author SHA1 Message Date
Chris Lalancette
7c6785176a 17.1.0 2022-11-02 18:06:21 +00:00
Chris Lalancette
586932ebf8 Changelog.
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2022-11-02 18:06:12 +00:00
Tomoya Fujita
edbfe1404b LifecycleNode on_configure doc fix. (#2034)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2022-10-28 09:17:47 -07:00
Tomoya Fujita
6f22443513 MultiThreadExecutor number of threads is at least 2+ in default. (#2032)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2022-10-28 09:17:23 -07:00
Tomoya Fujita
e5d13a2478 Bugfix 20210810 get current state (#1756)
* protect state_machine_ with mutex lock.

protect state_handle_ with mutex lock.

reconsider mutex lock scope.

remove mutex lock from constructors.

lock just once during initialization of LifecycleNodeInterfaceImpl.

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

* Move updating of current_state to right after initialization.

This is slightly more correct in the case that registering one
of the services fails.

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

Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
Co-authored-by: Chris Lalancette <clalancette@openrobotics.org>
2022-10-28 09:15:14 -07:00
Chen Lihui
d119157948 Fix bug that a callback not reached (#1640)
* 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>
2022-10-26 14:18:21 -07:00
Alexis Paques
85c0af4fa0 Set the minimum number of threads of the Multithreaded executor to 2 (#2030)
* Set the minimum number of threads of the Multithreaded executor to 2

Signed-off-by: Alexis Paques <paa1ti@bosch.com>
2022-10-25 13:33:14 -04:00
Chris Lalancette
2d32d03ba3 Make lifecycle impl get_current_state() const. (#2031)
We should only need to update the current state when it changes,
so we do that in the change_state method (which is not const).
Then we can just return the current_state_ object in
get_current_state, and then mark it as const.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2022-10-24 17:14:12 -04:00
Chris Lalancette
28890bf126 Cleanup the lifecycle implementation (#2027)
* Split lifecycle_node_interface_impl into header and implementation.

There is no reason it should all be in the header file.  No
functional change.

* Mark LifecycleNodeInterfaceImpl as final.

* Update documentation about return codes.

* Mark a bunch of LifecycleNodeInterfaceImpl methods as const.

* Make most of LifecycleNodeInterfaceImpl private.

* Mark some LifecycleNode methods as const.

* Disable copies on LifecycleNodeInterfaceImpl.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2022-10-24 08:43:17 -04:00
uupks
b9b1468d15 check thread whether joinable before join (#2019)
Signed-off-by: uupks <uupks0325@gmail.com>
2022-10-13 08:30:02 -04:00
Cristóbal Arroyo
3aca271ef5 Set cpplint test timeout to 3 minutes (#2022)
Signed-off-by: Crola1702 <cristobal.arroyo@ekumenlabs.com>
2022-10-10 08:17:24 -05:00
Chris Lalancette
dec766228d Cleanup the rclcpp_lifecycle dependencies. (#2021)
That is, make sure they are all listed in package.xml, found
in the CMakeLists.txt, and properly included where they are
used.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2022-10-04 14:04:12 -04:00
Chris Lalancette
95837d34f1 Make sure to include-what-you-use in the node_interfaces. (#2018)
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2022-09-29 07:54:41 -04:00
mauropasse
145933b037 Do not clear entities callbacks on destruction (#2002)
* Do not clear entities callbacks on destruction

Removing these clearings since they were not necessary,
since the objects are being destroyed anyway.

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

* Fix CI

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

* Restore clear_on_ready_callback on ~QOSEventHandlerBase

Needed since QOSEventHandlerBase does not own
the pub/sub listeners. So the QOSEventHandler
can be destroyed while the corresponding listeners
are still alive, so we need to clear these callbacks.

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

* Add coment on clearing callback for QoS event

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

Signed-off-by: Mauro Passerino <mpasserino@irobot.com>
Co-authored-by: Mauro Passerino <mpasserino@irobot.com>
2022-09-23 00:30:59 +01:00
Chen Lihui
6a8c61c026 use unique ptr and remove unuseful container (#2013)
Signed-off-by: Chen Lihui <lihui.chen@sony.com>

Signed-off-by: Chen Lihui <lihui.chen@sony.com>
2022-09-19 10:08:25 -07:00
Chen Lihui
978439191f fix mismatched issue if using zero_allocate (#1995)
* fix mismatched issue if uzing zero_allocated

Signed-off-by: Chen Lihui <lihui.chen@sony.com>
2022-09-15 08:17:28 -04:00
Chris Lalancette
7bc05da5d1 17.0.0 2022-09-13 20:29:01 +00:00
Chris Lalancette
4744fb6f50 Changelog.
Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2022-09-13 20:28:54 +00:00
Barry Xu
d0e1e837b5 Make ParameterService and Sync/AsyncParameterClient accept rclcpp::QoS (#1978)
* Make ParameterService and Sync/AsyncParameterClient accept rclcpp::QoS

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

* Avoid deprecated function using another deprecated function

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

Signed-off-by: Barry Xu <barry.xu@sony.com>
2022-09-09 15:06:33 -07:00
Chen Lihui
92d4f3e347 support regex match for parameter client (#1992)
* support regex match for parameter client

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

* address review that change behavior of a public method

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

* remove an unnecessary comment

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

* update gmock compilation setting

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

Signed-off-by: Chen Lihui <lihui.chen@sony.com>
2022-09-08 12:55:41 -07:00
Tyler Weaver
ea8daa3784 operator+= and operator-= for Duration (#1988)
* operator+= and operator-= for Duration

Signed-off-by: Tyler Weaver <maybe@tylerjw.dev>
2022-09-02 13:58:56 -04:00
Ivan Santiago Paunovic
df994e435d Revert "Revert "Add a create_timer method to Node and LifecycleNode classes (#1975)" (#2009) (#2010)
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2022-08-31 10:21:13 -03:00
schrodinbug
93222cc2cd force compiler warning if callback handles not captured (#2000)
clarify documentation to show that not capturing returned handles
will result in callbacks immediately being unregistered

Signed-off-by: Jason Beach <jason.m.beach@gmail.com>
2022-08-31 08:40:11 -04:00
Shane Loretz
11b5f8db21 Revert "Add a create_timer method to Node and LifecycleNode classes (#1975)" (#2009)
This reverts commit 6167a575b3.

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

Signed-off-by: Shane Loretz <sloretz@openrobotics.org>
2022-08-30 13:42:14 -07:00
Andrew Symington
6167a575b3 Add a create_timer method to Node and LifecycleNode classes (#1975)
Signed-off-by: Andrew Symington <andrew.c.symington@gmail.com>
2022-08-30 10:10:11 -03:00
Brian
dab9f5e0a3 [docs] add note about callback lifetime for {on, post}_set_parameter_callback (#1981)
[docs] add note about {on, post, pre}_set_parameter_callback lifetime

Signed-off-by: Brian Chen <brian.chen@openrobotics.org>
2022-08-29 15:14:09 -04:00
Chen Lihui
3d69031d2a fix memory leak (#1994)
Signed-off-by: Chen Lihui <lihui.chen@sony.com>
2022-08-17 21:30:51 -07:00
Deepanshu Bansal
b953bdddf8 Support pre-set and post-set parameter callbacks in addition to on-set-parameter-callback. (#1947)
* Support add_pre_set_parameter and add_post_set_parameter callbacks in addition to add_on_set_parameter_callback in Node API

Signed-off-by: deepanshu <deepanshubansal01@gmail.com>
2022-07-14 18:22:48 -04:00
Shane Loretz
64e4c72791 Make create_service accept rclcpp::QoS (#1969)
Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>
2022-07-12 09:41:40 +09:00
Shane Loretz
f6056beaa0 Make create_client accept rclcpp::QoS (#1964)
* Make create_client accept rclcpp::QoS

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

* Deprecate passing rmw_qos_profile_t to create_client

Signed-off-by: Shane Loretz <sloretz@osrfoundation.org>
2022-07-11 10:09:44 -07:00
Chris Lalancette
37b589dc85 Fix the documentation for rclcpp::ok to be accurate. (#1965)
That is, it returns false if shutdown has been called, and
true in all other circumstances.

Signed-off-by: Chris Lalancette <clalancette@openrobotics.org>
2022-07-07 09:07:12 -07:00
Chen Lihui
6dd3a0377b 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>
2022-07-06 09:41:16 -07:00
Audrow Nash
33dae5d679 Mirror rolling to master 2022-06-28 09:20:48 -05:00
William Woodall
f43a9198eb Revert "Introduce executors new spin_for method, replace spin_until_future_complete with spin_until_complete. (#1821) (#1874)" (#1956)
This reverts commit 3c8e89d17c.
2022-06-24 11:21:24 -07:00
Hubert Liberacki
3c8e89d17c Introduce executors new spin_for method, replace spin_until_future_complete with spin_until_complete. (#1821) (#1874) 2022-06-24 00:33:29 -07:00
Tomoya Fujita
546ddf87fe test adjustment for LoanedMessage. (#1951)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2022-06-22 15:01:43 -07:00
William Woodall
dbded5c0d6 fix virtual dispatch issues identified by clang-tidy (#1816)
* fix virtual dispatch issues identified by clang-tidy

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

* fix up to reduce code duplication

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

* uncrustify

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

* avoid returning temporaries

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

* uncrustify

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

* add docs about overriding methods used in constructors

Signed-off-by: William Woodall <william@osrfoundation.org>
2022-06-21 18:59:25 -07:00
Nikolai Morin
86a9d5882e Remove unused on_parameters_set_callback_ (#1945)
Signed-off-by: Nikolai Morin <nikolai.morin@apex.ai>
2022-06-14 13:22:53 -03:00
Ivan Santiago Paunovic
8e6a6fb32d Fix subscription.is_serialized() for callbacks with message info (#1950)
* Fix subscription.is_serialized() for callbacks with message info argument

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

* Add tests + please linters

Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
2022-06-10 17:18:25 -03:00
Tomoya Fujita
b3f57033a9 wait for subscriptions on another thread. (#1940)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2022-06-09 12:14:12 -07:00
Daniel Reuter
38581cc860 Fix documentation of RCLCPP_[INFO,WARN,...] (#1943)
In the pull request https://github.com/ros2/rclcpp/pull/1442 the ability
to use `std::string` as the first argument to the logging functions was
(rightfully) removed.

This commit just corrects the documentation of the macro, since it
confused me a bit ;)

Signed-off-by: Daniel Reuter <daniel.robin.reuter@googlemail.com>
2022-06-07 11:56:57 -04:00
Alberto Soragna
790e529ba3 Always trigger guard condition waitset (#1923)
* trigger guard condition waitset regardless of whether a trigger callback is present

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

* restore mutex in guard_condition.cpp

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

* remove whitespace

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

* add unit-test

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

* add documentation for trigger and set_on_trigger_callback

Signed-off-by: Alberto Soragna <alberto.soragna@gmail.com>
2022-06-02 18:58:19 +01:00
Barry Xu
5c688303b3 Add statistics for handle_loaned_message (#1927)
* Add statistics for handle_loaned_message

Signed-off-by: Barry Xu <barry.xu@sony.com>
2022-05-19 08:10:17 -07:00
Jochen Sprickerhof
02802bcc38 Drop wrong template specialization (#1926)
This fails with g++ -std=gnu++20.

Signed-off-by: Jochen Sprickerhof <git@jochen.sprickerhof.de>
2022-05-12 19:08:34 -07:00
116 changed files with 4246 additions and 1038 deletions

View File

@@ -0,0 +1,13 @@
name: Mirror rolling to master
on:
push:
branches: [ rolling ]
jobs:
mirror-to-master:
runs-on: ubuntu-latest
steps:
- uses: zofrex/mirror-branch@v1
with:
target-branch: master

View File

@@ -2,6 +2,47 @@
Changelog for package rclcpp
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
17.1.0 (2022-11-02)
-------------------
* MultiThreadExecutor number of threads is at least 2+ in default. (`#2032 <https://github.com/ros2/rclcpp/issues/2032>`_)
* Fix bug that a callback not reached (`#1640 <https://github.com/ros2/rclcpp/issues/1640>`_)
* Set the minimum number of threads of the Multithreaded executor to 2 (`#2030 <https://github.com/ros2/rclcpp/issues/2030>`_)
* check thread whether joinable before join (`#2019 <https://github.com/ros2/rclcpp/issues/2019>`_)
* Set cpplint test timeout to 3 minutes (`#2022 <https://github.com/ros2/rclcpp/issues/2022>`_)
* Make sure to include-what-you-use in the node_interfaces. (`#2018 <https://github.com/ros2/rclcpp/issues/2018>`_)
* Do not clear entities callbacks on destruction (`#2002 <https://github.com/ros2/rclcpp/issues/2002>`_)
* fix mismatched issue if using zero_allocate (`#1995 <https://github.com/ros2/rclcpp/issues/1995>`_)
* Contributors: Alexis Paques, Chen Lihui, Chris Lalancette, Cristóbal Arroyo, Tomoya Fujita, mauropasse, uupks
17.0.0 (2022-09-13)
-------------------
* Make ParameterService and Sync/AsyncParameterClient accept rclcpp::QoS (`#1978 <https://github.com/ros2/rclcpp/issues/1978>`_)
* support regex match for parameter client (`#1992 <https://github.com/ros2/rclcpp/issues/1992>`_)
* operator+= and operator-= for Duration (`#1988 <https://github.com/ros2/rclcpp/issues/1988>`_)
* Revert "Revert "Add a create_timer method to Node and `LifecycleNode` classes (`#1975 <https://github.com/ros2/rclcpp/issues/1975>`_)" (`#2009 <https://github.com/ros2/rclcpp/issues/2009>`_) (`#2010 <https://github.com/ros2/rclcpp/issues/2010>`_)
* force compiler warning if callback handles not captured (`#2000 <https://github.com/ros2/rclcpp/issues/2000>`_)
* Revert "Add a `create_timer` method to `Node` and `LifecycleNode` classes (`#1975 <https://github.com/ros2/rclcpp/issues/1975>`_)" (`#2009 <https://github.com/ros2/rclcpp/issues/2009>`_)
* Add a `create_timer` method to `Node` and `LifecycleNode` classes (`#1975 <https://github.com/ros2/rclcpp/issues/1975>`_)
* [docs] add note about callback lifetime for {on, post}_set_parameter_callback (`#1981 <https://github.com/ros2/rclcpp/issues/1981>`_)
* fix memory leak (`#1994 <https://github.com/ros2/rclcpp/issues/1994>`_)
* Support pre-set and post-set parameter callbacks in addition to on-set-parameter-callback. (`#1947 <https://github.com/ros2/rclcpp/issues/1947>`_)
* Make create_service accept rclcpp::QoS (`#1969 <https://github.com/ros2/rclcpp/issues/1969>`_)
* Make create_client accept rclcpp::QoS (`#1964 <https://github.com/ros2/rclcpp/issues/1964>`_)
* Fix the documentation for rclcpp::ok to be accurate. (`#1965 <https://github.com/ros2/rclcpp/issues/1965>`_)
* use regex for wildcard matching (`#1839 <https://github.com/ros2/rclcpp/issues/1839>`_)
* Revert "Introduce executors new spin_for method, replace spin_until_future_complete with spin_until_complete. (`#1821 <https://github.com/ros2/rclcpp/issues/1821>`_) (`#1874 <https://github.com/ros2/rclcpp/issues/1874>`_)" (`#1956 <https://github.com/ros2/rclcpp/issues/1956>`_)
* Introduce executors new spin_for method, replace spin_until_future_complete with spin_until_complete. (`#1821 <https://github.com/ros2/rclcpp/issues/1821>`_) (`#1874 <https://github.com/ros2/rclcpp/issues/1874>`_)
* test adjustment for LoanedMessage. (`#1951 <https://github.com/ros2/rclcpp/issues/1951>`_)
* fix virtual dispatch issues identified by clang-tidy (`#1816 <https://github.com/ros2/rclcpp/issues/1816>`_)
* Remove unused on_parameters_set_callback\_ (`#1945 <https://github.com/ros2/rclcpp/issues/1945>`_)
* Fix subscription.is_serialized() for callbacks with message info (`#1950 <https://github.com/ros2/rclcpp/issues/1950>`_)
* wait for subscriptions on another thread. (`#1940 <https://github.com/ros2/rclcpp/issues/1940>`_)
* Fix documentation of `RCLCPP\_[INFO,WARN,...]` (`#1943 <https://github.com/ros2/rclcpp/issues/1943>`_)
* Always trigger guard condition waitset (`#1923 <https://github.com/ros2/rclcpp/issues/1923>`_)
* Add statistics for handle_loaned_message (`#1927 <https://github.com/ros2/rclcpp/issues/1927>`_)
* Drop wrong template specialization (`#1926 <https://github.com/ros2/rclcpp/issues/1926>`_)
* Contributors: Alberto Soragna, Andrew Symington, Barry Xu, Brian, Chen Lihui, Chris Lalancette, Daniel Reuter, Deepanshu Bansal, Hubert Liberacki, Ivan Santiago Paunovic, Jochen Sprickerhof, Nikolai Morin, Shane Loretz, Tomoya Fujita, Tyler Weaver, William Woodall, schrodinbug
16.2.0 (2022-05-03)
-------------------
* Update get_parameter_from_event to follow the function description (`#1922 <https://github.com/ros2/rclcpp/issues/1922>`_)

View File

@@ -259,4 +259,8 @@ if(TEST cppcheck)
set_tests_properties(cppcheck PROPERTIES TIMEOUT 500)
endif()
if(TEST cpplint)
set_tests_properties(cpplint PROPERTIES TIMEOUT 180)
endif()
ament_generate_version_header(${PROJECT_NAME})

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

View File

@@ -0,0 +1,29 @@
# Proposed node parameters callback Design
## Introduction:
The original requirement came in **gazebo_ros_pkgs** for setting individual wheel slip parameters based on global wheel slip value [link to original issue](https://github.com/ros-simulation/gazebo_ros_pkgs/pull/1365).
The main requirement is to set one or more parameters after another parameter is set successfully.
Additionally, it would be nice if users could be notified locally (via a callback) when parameters have been set successfully (i.e. post validation).
Related discussion can be found in [#609](https://github.com/ros2/rclcpp/issues/609) [#1789](https://github.com/ros2/rclcpp/pull/1789)
With the current parameters API, the `add_on_set_parameters_callback` is intended for validation of parameter values before they are set, it should **not** cause any side-effects.
There is also the `ParameterEventHandler` that publishes changes to node parameters on `/parameter_events` topic for external nodes to see. Though the node could subscribe to the `/parameter_events` topic to be notified of changes to its own parameters, it is less than ideal since there is a delay caused by waiting for an executor to process the callback.
We propose adding a `PostSetParametersCallbackHandle` for successful parameter set similar to `OnSetParametersCallbackHandle` for parameter validation. Also, we propose adding a `PreSetParametersCallbackHandle` useful for modifying list of parameters being set.
The validation callback is often abused to trigger side effects in the code, for instance updating class attributes even before a parameter has been set successfully. Instead of relying on the `/parameter_events` topic to be notified of parameter changes, users can register a callback with a new API, `add_post_set_parameters_callback`.
It is possible to use the proposed `add_post_set_parameters_callback` for setting additional parameters, but this might result in infinite recursion and does not allow those additional parameters to be set atomically with the original parameter(s) changed.
To workaround these issues, we propose adding a "pre set" callback type that can be registered with `add_pre_set_parameters_callback`, which will be triggered before the validation callbacks and can be used to modify the parameter list.
![Desgin API](https://github.com/ros2/rclcpp/blob/deepanshu/local-param-changed-callback-support/rclcpp/doc/param_callback_design.png?raw=true)
## Alternatives
* Users could call `set_parameter` while processing a message from the `/parameter_events` topic, however, there is extra overhead in having to create subscription (as noted earlier).
* Users could call `set_parameter` inside the "on set" parameters callback, however it is not well-defined how side-effects should handle cases where parameter validation fails.

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

@@ -950,7 +950,13 @@ public:
std::holds_alternative<UniquePtrSerializedMessageCallback>(callback_variant_) ||
std::holds_alternative<SharedConstPtrSerializedMessageCallback>(callback_variant_) ||
std::holds_alternative<ConstRefSharedConstPtrSerializedMessageCallback>(callback_variant_) ||
std::holds_alternative<SharedPtrSerializedMessageCallback>(callback_variant_);
std::holds_alternative<SharedPtrSerializedMessageCallback>(callback_variant_) ||
std::holds_alternative<ConstRefSerializedMessageWithInfoCallback>(callback_variant_) ||
std::holds_alternative<UniquePtrSerializedMessageWithInfoCallback>(callback_variant_) ||
std::holds_alternative<SharedConstPtrSerializedMessageWithInfoCallback>(callback_variant_) ||
std::holds_alternative<ConstRefSharedConstPtrSerializedMessageWithInfoCallback>(
callback_variant_) ||
std::holds_alternative<SharedPtrSerializedMessageWithInfoCallback>(callback_variant_);
}
void

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"
@@ -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
@@ -171,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)
@@ -213,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>

View File

@@ -130,7 +130,7 @@ public:
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph);
RCLCPP_PUBLIC
virtual ~ClientBase();
virtual ~ClientBase() = default;
/// Take the next response for this client as a type erased pointer.
/**

View File

@@ -183,6 +183,11 @@ public:
*
* This function is thread-safe.
*
* Note that if you override this method, but leave shutdown to be called in
* the destruction of this base class, it will not call the overridden
* version from your base class.
* So you need to ensure you call your class's shutdown() in its destructor.
*
* \param[in] reason the description of why shutdown happened
* \return true if shutdown was successful, false if context was already shutdown
* \throw various exceptions derived from rclcpp::exceptions::RCLError, if rcl_shutdown fails
@@ -318,7 +323,6 @@ public:
/// Interrupt any blocking sleep_for calls, causing them to return immediately and return true.
RCLCPP_PUBLIC
virtual
void
interrupt_all_sleep_for();
@@ -351,7 +355,6 @@ protected:
// Called by constructor and destructor to clean up by finalizing the
// shutdown rcl context and preparing for a new init cycle.
RCLCPP_PUBLIC
virtual
void
clean_up();

View File

@@ -20,10 +20,40 @@
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/node_interfaces/node_services_interface.hpp"
#include "rclcpp/qos.hpp"
#include "rmw/rmw.h"
namespace rclcpp
{
/// Create a service client with a given type.
/**
* \param[in] node_base NodeBaseInterface implementation of the node on which
* to create the client.
* \param[in] node_graph NodeGraphInterface implementation of the node on which
* to create the client.
* \param[in] node_services NodeServicesInterface implementation of the node on
* which to create the client.
* \param[in] service_name The name on which the service is accessible.
* \param[in] qos Quality of service profile for client.
* \param[in] group Callback group to handle the reply to service calls.
* \return Shared pointer to the created client.
*/
template<typename ServiceT>
typename rclcpp::Client<ServiceT>::SharedPtr
create_client(
std::shared_ptr<node_interfaces::NodeBaseInterface> node_base,
std::shared_ptr<node_interfaces::NodeGraphInterface> node_graph,
std::shared_ptr<node_interfaces::NodeServicesInterface> node_services,
const std::string & service_name,
const rclcpp::QoS & qos = rclcpp::ServicesQoS(),
rclcpp::CallbackGroup::SharedPtr group = nullptr)
{
return create_client<ServiceT>(
node_base, node_graph, node_services,
service_name,
qos.get_rmw_qos_profile(),
group);
}
/// Create a service client with a given type.
/// \internal

View File

@@ -26,6 +26,32 @@
namespace rclcpp
{
/// Create a service with a given type.
/**
* \param[in] node_base NodeBaseInterface implementation of the node on which
* to create the service.
* \param[in] node_services NodeServicesInterface implementation of the node on
* which to create the service.
* \param[in] service_name The name on which the service is accessible.
* \param[in] callback The callback to call when the service gets a request.
* \param[in] qos Quality of service profile for the service.
* \param[in] group Callback group to handle the reply to service calls.
* \return Shared pointer to the created service.
*/
template<typename ServiceT, typename CallbackT>
typename rclcpp::Service<ServiceT>::SharedPtr
create_service(
std::shared_ptr<node_interfaces::NodeBaseInterface> node_base,
std::shared_ptr<node_interfaces::NodeServicesInterface> node_services,
const std::string & service_name,
CallbackT && callback,
const rclcpp::QoS & qos,
rclcpp::CallbackGroup::SharedPtr group)
{
return create_service<ServiceT, CallbackT>(
node_base, node_services, service_name,
std::forward<CallbackT>(callback), qos.get_rmw_qos_profile(), group);
}
/// Create a service with a given type.
/// \internal

View File

@@ -23,85 +23,29 @@
#include "rclcpp/duration.hpp"
#include "rclcpp/node_interfaces/get_node_base_interface.hpp"
#include "rclcpp/node_interfaces/get_node_clock_interface.hpp"
#include "rclcpp/node_interfaces/get_node_timers_interface.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/node_interfaces/node_clock_interface.hpp"
#include "rclcpp/node_interfaces/node_timers_interface.hpp"
namespace rclcpp
{
/// Create a timer with a given clock
/// \internal
template<typename CallbackT>
typename rclcpp::TimerBase::SharedPtr
create_timer(
std::shared_ptr<node_interfaces::NodeBaseInterface> node_base,
std::shared_ptr<node_interfaces::NodeTimersInterface> node_timers,
rclcpp::Clock::SharedPtr clock,
rclcpp::Duration period,
CallbackT && callback,
rclcpp::CallbackGroup::SharedPtr group = nullptr)
namespace detail
{
auto timer = rclcpp::GenericTimer<CallbackT>::make_shared(
clock,
period.to_chrono<std::chrono::nanoseconds>(),
std::forward<CallbackT>(callback),
node_base->get_context());
node_timers->add_timer(timer, group);
return timer;
}
/// Create a timer with a given clock
template<typename NodeT, typename CallbackT>
typename rclcpp::TimerBase::SharedPtr
create_timer(
NodeT node,
rclcpp::Clock::SharedPtr clock,
rclcpp::Duration period,
CallbackT && callback,
rclcpp::CallbackGroup::SharedPtr group = nullptr)
{
return create_timer(
rclcpp::node_interfaces::get_node_base_interface(node),
rclcpp::node_interfaces::get_node_timers_interface(node),
clock,
period,
std::forward<CallbackT>(callback),
group);
}
/// Convenience method to create a timer with node resources.
/// Perform a safe cast to a timer period in nanoseconds
/**
*
* \tparam DurationRepT
* \tparam DurationT
* \tparam CallbackT
* \param period period to execute callback. This duration must be 0 <= period < nanoseconds::max()
* \param callback callback to execute via the timer period
* \param group
* \param node_base
* \param node_timers
* \return
* \throws std::invalid argument if either node_base or node_timers
* are null, or period is negative or too large
* \return period, expressed as chrono::duration::nanoseconds
* \throws std::invalid_argument if period is negative or too large
*/
template<typename DurationRepT, typename DurationT, typename CallbackT>
typename rclcpp::WallTimer<CallbackT>::SharedPtr
create_wall_timer(
std::chrono::duration<DurationRepT, DurationT> period,
CallbackT callback,
rclcpp::CallbackGroup::SharedPtr group,
node_interfaces::NodeBaseInterface * node_base,
node_interfaces::NodeTimersInterface * node_timers)
template<typename DurationRepT, typename DurationT>
std::chrono::nanoseconds
safe_cast_to_period_in_ns(std::chrono::duration<DurationRepT, DurationT> period)
{
if (node_base == nullptr) {
throw std::invalid_argument{"input node_base cannot be null"};
}
if (node_timers == nullptr) {
throw std::invalid_argument{"input node_timers cannot be null"};
}
if (period < std::chrono::duration<DurationRepT, DurationT>::zero()) {
throw std::invalid_argument{"timer period cannot be negative"};
}
@@ -132,12 +76,135 @@ create_wall_timer(
"Casting timer period to nanoseconds resulted in integer overflow."};
}
return period_ns;
}
} // namespace detail
/// Create a timer with a given clock
/// \internal
template<typename CallbackT>
typename rclcpp::TimerBase::SharedPtr
create_timer(
std::shared_ptr<node_interfaces::NodeBaseInterface> node_base,
std::shared_ptr<node_interfaces::NodeTimersInterface> node_timers,
rclcpp::Clock::SharedPtr clock,
rclcpp::Duration period,
CallbackT && callback,
rclcpp::CallbackGroup::SharedPtr group = nullptr)
{
return create_timer(
clock,
period.to_chrono<std::chrono::nanoseconds>(),
std::forward<CallbackT>(callback),
group,
node_base.get(),
node_timers.get());
}
/// Create a timer with a given clock
template<typename NodeT, typename CallbackT>
typename rclcpp::TimerBase::SharedPtr
create_timer(
NodeT node,
rclcpp::Clock::SharedPtr clock,
rclcpp::Duration period,
CallbackT && callback,
rclcpp::CallbackGroup::SharedPtr group = nullptr)
{
return create_timer(
clock,
period.to_chrono<std::chrono::nanoseconds>(),
std::forward<CallbackT>(callback),
group,
rclcpp::node_interfaces::get_node_base_interface(node).get(),
rclcpp::node_interfaces::get_node_timers_interface(node).get());
}
/// Convenience method to create a general timer with node resources.
/**
*
* \tparam DurationRepT
* \tparam DurationT
* \tparam CallbackT
* \param clock clock to be used
* \param period period to execute callback. This duration must be 0 <= period < nanoseconds::max()
* \param callback callback to execute via the timer period
* \param group callback group
* \param node_base node base interface
* \param node_timers node timer interface
* \return shared pointer to a generic timer
* \throws std::invalid_argument if either clock, node_base or node_timers
* are nullptr, or period is negative or too large
*/
template<typename DurationRepT, typename DurationT, typename CallbackT>
typename rclcpp::GenericTimer<CallbackT>::SharedPtr
create_timer(
rclcpp::Clock::SharedPtr clock,
std::chrono::duration<DurationRepT, DurationT> period,
CallbackT callback,
rclcpp::CallbackGroup::SharedPtr group,
node_interfaces::NodeBaseInterface * node_base,
node_interfaces::NodeTimersInterface * node_timers)
{
if (clock == nullptr) {
throw std::invalid_argument{"clock cannot be null"};
}
if (node_base == nullptr) {
throw std::invalid_argument{"input node_base cannot be null"};
}
if (node_timers == nullptr) {
throw std::invalid_argument{"input node_timers cannot be null"};
}
const std::chrono::nanoseconds period_ns = detail::safe_cast_to_period_in_ns(period);
// Add a new generic timer.
auto timer = rclcpp::GenericTimer<CallbackT>::make_shared(
std::move(clock), period_ns, std::move(callback), node_base->get_context());
node_timers->add_timer(timer, group);
return timer;
}
/// Convenience method to create a wall timer with node resources.
/**
*
* \tparam DurationRepT
* \tparam DurationT
* \tparam CallbackT
* \param period period to execute callback. This duration must be 0 <= period < nanoseconds::max()
* \param callback callback to execute via the timer period
* \param group callback group
* \param node_base node base interface
* \param node_timers node timer interface
* \return shared pointer to a wall timer
* \throws std::invalid_argument if either node_base or node_timers
* are null, or period is negative or too large
*/
template<typename DurationRepT, typename DurationT, typename CallbackT>
typename rclcpp::WallTimer<CallbackT>::SharedPtr
create_wall_timer(
std::chrono::duration<DurationRepT, DurationT> period,
CallbackT callback,
rclcpp::CallbackGroup::SharedPtr group,
node_interfaces::NodeBaseInterface * node_base,
node_interfaces::NodeTimersInterface * node_timers)
{
if (node_base == nullptr) {
throw std::invalid_argument{"input node_base cannot be null"};
}
if (node_timers == nullptr) {
throw std::invalid_argument{"input node_timers cannot be null"};
}
const std::chrono::nanoseconds period_ns = detail::safe_cast_to_period_in_ns(period);
// Add a new wall timer.
auto timer = rclcpp::WallTimer<CallbackT>::make_shared(
period_ns, std::move(callback), node_base->get_context());
node_timers->add_timer(timer, group);
return timer;
}
} // namespace rclcpp
#endif // RCLCPP__CREATE_TIMER_HPP_

View File

@@ -92,9 +92,13 @@ public:
Duration
operator+(const rclcpp::Duration & rhs) const;
Duration & operator+=(const rclcpp::Duration & rhs);
Duration
operator-(const rclcpp::Duration & rhs) const;
Duration & operator-=(const rclcpp::Duration & rhs);
/// Get the maximum representable value.
/**
* \return the maximum representable value
@@ -106,6 +110,9 @@ public:
Duration
operator*(double scale) const;
Duration &
operator*=(double scale);
/// Get duration in nanosecods
/**
* \return the duration in nanoseconds as a rcl_duration_value_t.

View File

@@ -560,14 +560,14 @@ protected:
virtual void
spin_once_impl(std::chrono::nanoseconds timeout);
typedef std::map<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr,
typedef std::map<rclcpp::CallbackGroup::WeakPtr,
const rclcpp::GuardCondition *,
std::owner_less<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>>
WeakNodesToGuardConditionsMap;
std::owner_less<rclcpp::CallbackGroup::WeakPtr>>
WeakCallbackGroupsToGuardConditionsMap;
/// maps nodes to guard conditions
WeakNodesToGuardConditionsMap
weak_nodes_to_guard_conditions_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
/// maps callback groups to guard conditions
WeakCallbackGroupsToGuardConditionsMap
weak_groups_to_guard_conditions_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
/// maps callback groups associated to nodes
WeakCallbackGroupsToNodesMap

View File

@@ -47,7 +47,7 @@ public:
*
* \param options common options for all executors
* \param number_of_threads number of threads to have in the thread pool,
* the default 0 will use the number of cpu cores found instead
* the default 0 will use the number of cpu cores found (minimum of 2)
* \param yield_before_execute if true std::this_thread::yield() is called
* \param timeout maximum time to wait
*/

View File

@@ -52,7 +52,7 @@ public:
{}
RCLCPP_PUBLIC
virtual ~SubscriptionIntraProcessBase();
virtual ~SubscriptionIntraProcessBase() = default;
RCLCPP_PUBLIC
size_t

View File

@@ -128,6 +128,11 @@ public:
* If start_if_not_started() was never called, this function still succeeds,
* but start_if_not_started() still cannot be called after this function.
*
* Note that if you override this method, but leave shutdown to be called in
* the destruction of this base class, it will not call the overridden
* version from your base class.
* So you need to ensure you call your class's shutdown() in its destructor.
*
* \throws rclcpp::execptions::RCLError from rcl_guard_condition_fini()
* \throws rclcpp::execptions::RCLError from rcl_wait_set_fini()
* \throws std::system_error anything std::mutex::lock() throws

View File

@@ -72,7 +72,7 @@ public:
const rcl_guard_condition_t &
get_rcl_guard_condition() const;
/// Notify the wait set waiting on this condition, if any, that the condition had been met.
/// Signal that the condition has been met, notifying both the wait set and listeners, if any.
/**
* This function is thread-safe, and may be called concurrently with waiting
* on this guard condition in a wait set.
@@ -107,6 +107,22 @@ public:
void
add_to_wait_set(rcl_wait_set_t * wait_set);
/// Set a callback to be called whenever the guard condition is triggered.
/**
* The callback receives a size_t which is the number of times the guard condition was triggered
* since the last time this callback was called.
* Normally this is 1, but can be > 1 if the guard condition was triggered before any
* callback was set.
*
* Calling it again will clear any previously set callback.
*
* This function is thread-safe.
*
* If you want more information available in the callback, like the guard condition
* or other information, you may use a lambda with captures or std::bind.
*
* \param[in] callback functor to be called when the guard condition is triggered
*/
RCLCPP_PUBLIC
void
set_on_trigger_callback(std::function<void(size_t)> callback);

View File

@@ -227,7 +227,7 @@ public:
)
);
/// Create a timer.
/// Create a wall timer that uses the wall clock to drive the callback.
/**
* \param[in] period Time interval between triggers of the callback.
* \param[in] callback User-defined callback function.
@@ -240,18 +240,47 @@ public:
CallbackT callback,
rclcpp::CallbackGroup::SharedPtr group = nullptr);
/// Create a timer that uses the node clock to drive the callback.
/**
* \param[in] period Time interval between triggers of the callback.
* \param[in] callback User-defined callback function.
* \param[in] group Callback group to execute this timer's callback in.
*/
template<typename DurationRepT = int64_t, typename DurationT = std::milli, typename CallbackT>
typename rclcpp::GenericTimer<CallbackT>::SharedPtr
create_timer(
std::chrono::duration<DurationRepT, DurationT> period,
CallbackT callback,
rclcpp::CallbackGroup::SharedPtr group = nullptr);
/// Create and return a Client.
/**
* \param[in] service_name The topic to service on.
* \param[in] qos_profile rmw_qos_profile_t Quality of service profile for client.
* \param[in] group Callback group to call the service.
* \return Shared pointer to the created client.
* \deprecated use rclcpp::QoS instead of rmw_qos_profile_t
*/
template<typename ServiceT>
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
typename rclcpp::Client<ServiceT>::SharedPtr
create_client(
const std::string & service_name,
const rmw_qos_profile_t & qos_profile,
rclcpp::CallbackGroup::SharedPtr group = nullptr);
/// Create and return a Client.
/**
* \param[in] service_name The name on which the service is accessible.
* \param[in] qos Quality of service profile for client.
* \param[in] group Callback group to handle the reply to service calls.
* \return Shared pointer to the created client.
*/
template<typename ServiceT>
typename rclcpp::Client<ServiceT>::SharedPtr
create_client(
const std::string & service_name,
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_services_default,
const rclcpp::QoS & qos = rclcpp::ServicesQoS(),
rclcpp::CallbackGroup::SharedPtr group = nullptr);
/// Create and return a Service.
@@ -261,13 +290,31 @@ public:
* \param[in] qos_profile rmw_qos_profile_t Quality of service profile for client.
* \param[in] group Callback group to call the service.
* \return Shared pointer to the created service.
* \deprecated use rclcpp::QoS instead of rmw_qos_profile_t
*/
template<typename ServiceT, typename CallbackT>
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
typename rclcpp::Service<ServiceT>::SharedPtr
create_service(
const std::string & service_name,
CallbackT && callback,
const rmw_qos_profile_t & qos_profile,
rclcpp::CallbackGroup::SharedPtr group = nullptr);
/// Create and return a Service.
/**
* \param[in] service_name The topic to service on.
* \param[in] callback User-defined callback function.
* \param[in] qos Quality of service profile for the service.
* \param[in] group Callback group to call the service.
* \return Shared pointer to the created service.
*/
template<typename ServiceT, typename CallbackT>
typename rclcpp::Service<ServiceT>::SharedPtr
create_service(
const std::string & service_name,
CallbackT && callback,
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_services_default,
const rclcpp::QoS & qos = rclcpp::ServicesQoS(),
rclcpp::CallbackGroup::SharedPtr group = nullptr);
/// Create and return a GenericPublisher.
@@ -336,11 +383,21 @@ public:
*
* If `ignore_override` is `true`, the parameter override will be ignored.
*
* This method, if successful, will result in any callback registered with
* add_on_set_parameters_callback to be called.
* This method will result in any callback registered with
* `add_on_set_parameters_callback` and `add_post_set_parameters_callback`
* to be called for the parameter being set.
*
* If a callback was registered previously with `add_on_set_parameters_callback`,
* it will be called prior to setting the parameter for the node.
* If that callback prevents the initial value for the parameter from being
* set then rclcpp::exceptions::InvalidParameterValueException is thrown.
*
* If a callback was registered previously with `add_post_set_parameters_callback`,
* it will be called after setting the parameter successfully for the node.
*
* This method will _not_ result in any callbacks registered with
* `add_pre_set_parameters_callback` to be called.
*
* The returned reference will remain valid until the parameter is
* undeclared.
*
@@ -457,11 +514,22 @@ public:
* If `ignore_overrides` is `true`, all the overrides of the parameters declared
* by the function call will be ignored.
*
* This method will result in any callback registered with
* `add_on_set_parameters_callback` and `add_post_set_parameters_callback`
* to be called once for each parameter.
*
* This method, if successful, will result in any callback registered with
* add_on_set_parameters_callback to be called, once for each parameter.
* `add_on_set_parameters_callback` to be called, once for each parameter.
* If that callback prevents the initial value for any parameter from being
* set then rclcpp::exceptions::InvalidParameterValueException is thrown.
*
* If a callback was registered previously with `add_post_set_parameters_callback`,
* it will be called after setting the parameters successfully for the node,
* once for each parameter.
*
* This method will _not_ result in any callbacks registered with
* `add_pre_set_parameters_callback` to be called.
*
* \param[in] namespace_ The namespace in which to declare the parameters.
* \param[in] parameters The parameters to set in the given namespace.
* \param[in] ignore_overrides When `true`, the parameters overrides are ignored.
@@ -499,8 +567,9 @@ public:
/// Undeclare a previously declared parameter.
/**
* This method will not cause a callback registered with
* add_on_set_parameters_callback to be called.
* This method will _not_ cause a callback registered with any of the
* `add_pre_set_parameters_callback`, `add_on_set_parameters_callback` and
* `add_post_set_parameters_callback` to be called.
*
* \param[in] name The name of the parameter to be undeclared.
* \throws rclcpp::exceptions::ParameterNotDeclaredException if the parameter
@@ -534,11 +603,24 @@ public:
* Parameter overrides are ignored by set_parameter.
*
* This method will result in any callback registered with
* add_on_set_parameters_callback to be called.
* `add_pre_set_parameters_callback`, add_on_set_parameters_callback` and
* `add_post_set_parameters_callback` to be called once for the parameter
* being set.
*
* This method will result in any callback registered with
* `add_on_set_parameters_callback` to be called.
* If the callback prevents the parameter from being set, then it will be
* reflected in the SetParametersResult that is returned, but no exception
* will be thrown.
*
* If a callback was registered previously with `add_pre_set_parameters_callback`,
* it will be called once prior to the validation of the parameter for the node.
* If this callback makes modified parameter list empty, then it will be reflected
* in the returned result; no exceptions will be raised in this case.
*
* If a callback was registered previously with `add_post_set_parameters_callback`,
* it will be called once after setting the parameter successfully for the node.
*
* If the value type of the parameter is rclcpp::PARAMETER_NOT_SET, and the
* existing parameter type is something else, then the parameter will be
* implicitly undeclared.
@@ -575,11 +657,25 @@ public:
* corresponding SetParametersResult in the vector returned by this function.
*
* This method will result in any callback registered with
* add_on_set_parameters_callback to be called, once for each parameter.
* `add_pre_set_parameters_callback`, `add_on_set_parameters_callback` and
* `add_post_set_parameters_callback` to be called once for each parameter.
* If a callback was registered previously with `add_pre_set_parameters_callback`,
* it will be called prior to the validation of parameters for the node,
* once for each parameter.
* If this callback makes modified parameter list empty, then it will be reflected
* in the returned result; no exceptions will be raised in this case.
*
* This method will result in any callback registered with
* `add_on_set_parameters_callback` to be called, once for each parameter.
* If the callback prevents the parameter from being set, then, as mentioned
* before, it will be reflected in the corresponding SetParametersResult
* that is returned, but no exception will be thrown.
*
* If a callback was registered previously with `add_post_set_parameters_callback`,
* it will be called after setting the parameters successfully for the node,
* once for each parameter.
*
* Like set_parameter() this method will implicitly undeclare parameters
* with the type rclcpp::PARAMETER_NOT_SET.
*
@@ -606,11 +702,25 @@ public:
* If the exception is thrown then none of the parameters will have been set.
*
* This method will result in any callback registered with
* add_on_set_parameters_callback to be called, just one time.
* `add_pre_set_parameters_callback`, `add_on_set_parameters_callback` and
* `add_post_set_parameters_callback` to be called only 'once' for all parameters.
*
* If a callback was registered previously with `add_pre_set_parameters_callback`,
* it will be called prior to the validation of node parameters, just one time
* for all parameters.
* If this callback makes modified parameter list empty, then it will be reflected
* in the returned result; no exceptions will be raised in this case.
*
* This method will result in any callback registered with
* 'add_on_set_parameters_callback' to be called, just one time.
* If the callback prevents the parameters from being set, then it will be
* reflected in the SetParametersResult which is returned, but no exception
* will be thrown.
*
* If a callback was registered previously with `add_post_set_parameters_callback`,
* it will be called after setting the node parameters successfully, just one time
* for all parameters.
*
* If you pass multiple rclcpp::Parameter instances with the same name, then
* only the last one in the vector (forward iteration) will be set.
*
@@ -859,12 +969,85 @@ public:
rcl_interfaces::msg::ListParametersResult
list_parameters(const std::vector<std::string> & prefixes, uint64_t depth) const;
using PreSetParametersCallbackHandle =
rclcpp::node_interfaces::PreSetParametersCallbackHandle;
using PreSetParametersCallbackType =
rclcpp::node_interfaces::NodeParametersInterface::PreSetParametersCallbackType;
using OnSetParametersCallbackHandle =
rclcpp::node_interfaces::OnSetParametersCallbackHandle;
using OnParametersSetCallbackType =
rclcpp::node_interfaces::NodeParametersInterface::OnParametersSetCallbackType;
using OnSetParametersCallbackType =
rclcpp::node_interfaces::NodeParametersInterface::OnSetParametersCallbackType;
using OnParametersSetCallbackType [[deprecated("use OnSetParametersCallbackType instead")]] =
OnSetParametersCallbackType;
/// Add a callback for when parameters are being set.
using PostSetParametersCallbackHandle =
rclcpp::node_interfaces::PostSetParametersCallbackHandle;
using PostSetParametersCallbackType =
rclcpp::node_interfaces::NodeParametersInterface::PostSetParametersCallbackType;
/// Add a callback that gets triggered before parameters are validated.
/**
* This callback can be used to modify the original list of parameters being
* set by the user.
*
* The modified list of parameters is then forwarded to the "on set parameter"
* callback for validation.
*
* The callback is called whenever any of the `set_parameter*` methods are called
* or when a set parameter service request is received.
*
* The callback takes a reference to the vector of parameters to be set.
*
* The vector of parameters may be modified by the callback.
*
* One of the use case of "pre set callback" can be updating additional parameters
* conditioned on changes to a parameter.
*
* Users should retain a copy of the returned shared pointer, as the callback
* is valid only as long as the smart pointer is alive.
*
* For an example callback:
*
*```cpp
* void
* preSetParameterCallback(std::vector<rclcpp::Parameter> & parameters)
* {
* for (auto & param : parameters) {
* if (param.get_name() == "param1") {
* parameters.push_back(rclcpp::Parameter("param2", 4.0));
* }
* }
* }
* ```
* The above callback appends 'param2' to the list of parameters to be set if
* 'param1' is being set by the user.
*
* All parameters in the vector will be set atomically.
*
* Note that the callback is only called while setting parameters with `set_parameter`,
* `set_parameters`, `set_parameters_atomically`, or externally with a parameters service.
*
* The callback is not called when parameters are declared with `declare_parameter`
* or `declare_parameters`.
*
* The callback is not called when parameters are undeclared with `undeclare_parameter`.
*
* An empty modified parameter list from the callback will result in "set_parameter*"
* returning an unsuccessful result.
*
* The `remove_pre_set_parameters_callback` can be used to deregister the callback.
*
* \param callback The callback to register.
* \returns A shared pointer. The callback is valid as long as the smart pointer is alive.
* \throws std::bad_alloc if the allocation of the PreSetParametersCallbackHandle fails.
*/
RCLCPP_PUBLIC
RCUTILS_WARN_UNUSED
PreSetParametersCallbackHandle::SharedPtr
add_pre_set_parameters_callback(PreSetParametersCallbackType callback);
/// Add a callback to validate parameters before they are set.
/**
* The callback signature is designed to allow handling of any of the above
* `set_parameter*` or `declare_parameter*` methods, and so it takes a const
@@ -872,6 +1055,9 @@ public:
* rcl_interfaces::msg::SetParametersResult to indicate whether or not the
* parameter should be set or not, and if not why.
*
* Users should retain a copy of the returned shared pointer, as the callback
* is valid only as long as the smart pointer is alive.
*
* For an example callback:
*
* ```cpp
@@ -903,6 +1089,8 @@ public:
* this callback, so when checking a new value against the existing one, you
* must account for the case where the parameter is not yet set.
*
* The callback is not called when parameters are undeclared with `undeclare_parameter`.
*
* Some constraints like read_only are enforced before the callback is called.
*
* The callback may introspect other already set parameters (by calling any
@@ -931,7 +1119,80 @@ public:
RCLCPP_PUBLIC
RCUTILS_WARN_UNUSED
OnSetParametersCallbackHandle::SharedPtr
add_on_set_parameters_callback(OnParametersSetCallbackType callback);
add_on_set_parameters_callback(OnSetParametersCallbackType callback);
/// Add a callback that gets triggered after parameters are set successfully.
/**
* The callback is called when any of the `set_parameter*` or `declare_parameter*`
* methods are successful.
*
* Users should retain a copy of the returned shared pointer, as the callback
* is valid only as long as the smart pointer is alive.
*
* The callback takes a reference to a const vector of parameters that have been
* set successfully.
*
* The post callback can be valuable as a place to cause side-effects based on
* parameter changes.
* For instance updating internally tracked class attributes once parameters
* have been changed successfully.
*
* For an example callback:
*
* ```cpp
* void
* postSetParameterCallback(const std::vector<rclcpp::Parameter> & parameters)
* {
* for(const auto & param:parameters) {
* // the internal class member can be changed after
* // successful change to param1 or param2
* if(param.get_name() == "param1") {
* internal_tracked_class_parameter_1_ = param.get_value<double>();
* }
* else if(param.get_name() == "param2") {
* internal_tracked_class_parameter_2_ = param.get_value<double>();
* }
* }
* }
* ```
*
* The above callback takes a const reference to list of parameters that have been
* set successfully and as a result of this updates the internally tracked class attributes
* `internal_tracked_class_parameter_1_` and `internal_tracked_class_parameter_2_`
* respectively.
*
* This callback should not modify parameters.
*
* The callback is called when parameters are declared with `declare_parameter`
* or `declare_parameters`. See `declare_parameter` or `declare_parameters` above.
*
* The callback is not called when parameters are undeclared with `undeclare_parameter`.
*
* If you want to make changes to parameters based on changes to another, use
* `add_pre_set_parameters_callback`.
*
* The `remove_post_set_parameters_callback` can be used to deregister the callback.
*
* \param callback The callback to register.
* \returns A shared pointer. The callback is valid as long as the smart pointer is alive.
* \throws std::bad_alloc if the allocation of the OnSetParametersCallbackHandle fails.
*/
RCLCPP_PUBLIC
RCUTILS_WARN_UNUSED
PostSetParametersCallbackHandle::SharedPtr
add_post_set_parameters_callback(PostSetParametersCallbackType callback);
/// Remove a callback registered with `add_pre_set_parameters_callback`.
/**
* Delete a handler returned by `add_pre_set_parameters_callback`.
*
* \param handler The callback handler to remove.
* \throws std::runtime_error if the handler was not created with `add_pre_set_parameters_callback`,
* or if it has been removed before.
*/
RCLCPP_PUBLIC
void
remove_pre_set_parameters_callback(const PreSetParametersCallbackHandle * const handler);
/// Remove a callback registered with `add_on_set_parameters_callback`.
/**
@@ -960,6 +1221,18 @@ public:
void
remove_on_set_parameters_callback(const OnSetParametersCallbackHandle * const handler);
/// Remove a callback registered with `add_post_set_parameters_callback`.
/**
* Delete a handler returned by `add_post_set_parameters_callback`.
*
* \param handler The callback handler to remove.
* \throws std::runtime_error if the handler was not created with `add_post_set_parameters_callback`,
* or if it has been removed before.
*/
RCLCPP_PUBLIC
void
remove_post_set_parameters_callback(const PostSetParametersCallbackHandle * const handler);
/// Get the fully-qualified names of all available nodes.
/**
* The fully-qualified name includes the local namespace and name of the node.

View File

@@ -120,6 +120,38 @@ Node::create_wall_timer(
this->node_timers_.get());
}
template<typename DurationRepT, typename DurationT, typename CallbackT>
typename rclcpp::GenericTimer<CallbackT>::SharedPtr
Node::create_timer(
std::chrono::duration<DurationRepT, DurationT> period,
CallbackT callback,
rclcpp::CallbackGroup::SharedPtr group)
{
return rclcpp::create_timer(
this->get_clock(),
period,
std::move(callback),
group,
this->node_base_.get(),
this->node_timers_.get());
}
template<typename ServiceT>
typename Client<ServiceT>::SharedPtr
Node::create_client(
const std::string & service_name,
const rclcpp::QoS & qos,
rclcpp::CallbackGroup::SharedPtr group)
{
return rclcpp::create_client<ServiceT>(
node_base_,
node_graph_,
node_services_,
extend_name_with_sub_namespace(service_name, this->get_sub_namespace()),
qos,
group);
}
template<typename ServiceT>
typename Client<ServiceT>::SharedPtr
Node::create_client(
@@ -136,6 +168,23 @@ Node::create_client(
group);
}
template<typename ServiceT, typename CallbackT>
typename rclcpp::Service<ServiceT>::SharedPtr
Node::create_service(
const std::string & service_name,
CallbackT && callback,
const rclcpp::QoS & qos,
rclcpp::CallbackGroup::SharedPtr group)
{
return rclcpp::create_service<ServiceT, CallbackT>(
node_base_,
node_services_,
extend_name_with_sub_namespace(service_name, this->get_sub_namespace()),
std::forward<CallbackT>(callback),
qos,
group);
}
template<typename ServiceT, typename CallbackT>
typename rclcpp::Service<ServiceT>::SharedPtr
Node::create_service(

View File

@@ -15,7 +15,7 @@
#ifndef RCLCPP__NODE_INTERFACES__NODE_BASE_HPP_
#define RCLCPP__NODE_INTERFACES__NODE_BASE_HPP_
#include <functional>
#include <atomic>
#include <memory>
#include <mutex>
#include <string>
@@ -39,6 +39,13 @@ class NodeBase : public NodeBaseInterface, public std::enable_shared_from_this<N
public:
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeBase)
/// Constructor.
/**
* If nullptr (default) is given for the default_callback_group, one will
* be created by the constructor using the create_callback_group() method,
* but virtual dispatch will not occur so overrides of that method will not
* be used.
*/
RCLCPP_PUBLIC
NodeBase(
const std::string & node_name,
@@ -46,7 +53,8 @@ public:
rclcpp::Context::SharedPtr context,
const rcl_node_options_t & rcl_node_options,
bool use_intra_process_default,
bool enable_topic_statistics_default);
bool enable_topic_statistics_default,
rclcpp::CallbackGroup::SharedPtr default_callback_group = nullptr);
RCLCPP_PUBLIC
virtual

View File

@@ -15,10 +15,10 @@
#ifndef RCLCPP__NODE_INTERFACES__NODE_BASE_INTERFACE_HPP_
#define RCLCPP__NODE_INTERFACES__NODE_BASE_INTERFACE_HPP_
#include <atomic>
#include <functional>
#include <memory>
#include <mutex>
#include <string>
#include <vector>
#include "rcl/node.h"

View File

@@ -15,7 +15,9 @@
#ifndef RCLCPP__NODE_INTERFACES__NODE_GRAPH_HPP_
#define RCLCPP__NODE_INTERFACES__NODE_GRAPH_HPP_
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <map>
#include <memory>
#include <mutex>

View File

@@ -37,14 +37,18 @@ public:
~NodeLoggingInterface() = default;
/// Return the logger of the node.
/** \return The logger of the node. */
/**
* \return The logger of the node.
*/
RCLCPP_PUBLIC
virtual
rclcpp::Logger
get_logger() const = 0;
/// Return the logger name associated with the node.
/** \return The logger name associated with the node. */
/**
* \return The logger name associated with the node.
*/
RCLCPP_PUBLIC
virtual
const char *

View File

@@ -15,9 +15,10 @@
#ifndef RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_HPP_
#define RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_HPP_
#include <list>
#include <map>
#include <memory>
#include <list>
#include <mutex>
#include <string>
#include <vector>
@@ -84,6 +85,16 @@ class NodeParameters : public NodeParametersInterface
public:
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeParameters)
/// Constructor.
/**
* If using automatically_declare_parameters_from_overrides, overrides of
* get_parameter_overrides(), has_parameter(), declare_parameter() will not
* be respected.
* If this is an issue, pass false for
* automatically_declare_parameters_from_overrides and invoke
* perform_automatically_declare_parameters_from_overrides() manually after
* construction.
*/
RCLCPP_PUBLIC
NodeParameters(
const node_interfaces::NodeBaseInterface::SharedPtr node_base,
@@ -171,20 +182,48 @@ public:
rcl_interfaces::msg::ListParametersResult
list_parameters(const std::vector<std::string> & prefixes, uint64_t depth) const override;
RCLCPP_PUBLIC
RCUTILS_WARN_UNUSED
PreSetParametersCallbackHandle::SharedPtr
add_pre_set_parameters_callback(PreSetParametersCallbackType callback) override;
RCLCPP_PUBLIC
RCUTILS_WARN_UNUSED
OnSetParametersCallbackHandle::SharedPtr
add_on_set_parameters_callback(OnParametersSetCallbackType callback) override;
add_on_set_parameters_callback(OnSetParametersCallbackType callback) override;
RCLCPP_PUBLIC
RCUTILS_WARN_UNUSED
PostSetParametersCallbackHandle::SharedPtr
add_post_set_parameters_callback(PostSetParametersCallbackType callback) override;
RCLCPP_PUBLIC
void
remove_on_set_parameters_callback(const OnSetParametersCallbackHandle * const handler) override;
RCLCPP_PUBLIC
void
remove_post_set_parameters_callback(const PostSetParametersCallbackHandle * const handler)
override;
RCLCPP_PUBLIC
void
remove_pre_set_parameters_callback(const PreSetParametersCallbackHandle * const handler) override;
RCLCPP_PUBLIC
const std::map<std::string, rclcpp::ParameterValue> &
get_parameter_overrides() const override;
using CallbacksContainerType = std::list<OnSetParametersCallbackHandle::WeakPtr>;
using PreSetCallbacksHandleContainer = std::list<PreSetParametersCallbackHandle::WeakPtr>;
using OnSetCallbacksHandleContainer = std::list<OnSetParametersCallbackHandle::WeakPtr>;
using PostSetCallbacksHandleContainer = std::list<PostSetParametersCallbackHandle::WeakPtr>;
using CallbacksContainerType [[deprecated("use OnSetCallbacksHandleContainer instead")]] =
OnSetCallbacksHandleContainer;
protected:
RCLCPP_PUBLIC
void
perform_automatically_declare_parameters_from_overrides();
private:
RCLCPP_DISABLE_COPY(NodeParameters)
@@ -196,9 +235,11 @@ private:
// declare_parameter, etc). In those cases, this will be set to false.
bool parameter_modification_enabled_{true};
OnParametersSetCallbackType on_parameters_set_callback_ = nullptr;
PreSetCallbacksHandleContainer pre_set_parameters_callback_container_;
CallbacksContainerType on_parameters_set_callback_container_;
OnSetCallbacksHandleContainer on_set_parameters_callback_container_;
PostSetCallbacksHandleContainer post_set_parameters_callback_container_;
std::map<std::string, ParameterInfo> parameters_;

View File

@@ -15,8 +15,8 @@
#ifndef RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_INTERFACE_HPP_
#define RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_INTERFACE_HPP_
#include <functional>
#include <map>
#include <memory>
#include <string>
#include <vector>
@@ -33,16 +33,38 @@ namespace rclcpp
namespace node_interfaces
{
struct PreSetParametersCallbackHandle
{
RCLCPP_SMART_PTR_DEFINITIONS(PreSetParametersCallbackHandle)
using PreSetParametersCallbackType =
std::function<void (std::vector<rclcpp::Parameter> &)>;
PreSetParametersCallbackType callback;
};
struct OnSetParametersCallbackHandle
{
RCLCPP_SMART_PTR_DEFINITIONS(OnSetParametersCallbackHandle)
using OnParametersSetCallbackType =
using OnSetParametersCallbackType =
std::function<
rcl_interfaces::msg::SetParametersResult(
const std::vector<rclcpp::Parameter> &)>;
using OnParametersSetCallbackType [[deprecated("use OnSetParametersCallbackType instead")]] =
OnSetParametersCallbackType;
OnParametersSetCallbackType callback;
OnSetParametersCallbackType callback;
};
struct PostSetParametersCallbackHandle
{
RCLCPP_SMART_PTR_DEFINITIONS(PostSetParametersCallbackHandle)
using PostSetParametersCallbackType =
std::function<void (const std::vector<rclcpp::Parameter> &)>;
PostSetParametersCallbackType callback;
};
/// Pure virtual interface class for the NodeParameters part of the Node API.
@@ -185,16 +207,46 @@ public:
rcl_interfaces::msg::ListParametersResult
list_parameters(const std::vector<std::string> & prefixes, uint64_t depth) const = 0;
using OnParametersSetCallbackType = OnSetParametersCallbackHandle::OnParametersSetCallbackType;
using OnSetParametersCallbackType = OnSetParametersCallbackHandle::OnSetParametersCallbackType;
using PostSetParametersCallbackType =
PostSetParametersCallbackHandle::PostSetParametersCallbackType;
using PreSetParametersCallbackType = PreSetParametersCallbackHandle::PreSetParametersCallbackType;
/// Add a callback for when parameters are being set.
/// Add a callback that gets triggered before parameters are validated.
/**
* \sa rclcpp::Node::add_pre_set_parameters_callback
*/
RCLCPP_PUBLIC
virtual
PreSetParametersCallbackHandle::SharedPtr
add_pre_set_parameters_callback(PreSetParametersCallbackType callback) = 0;
/// Add a callback to validate parameters before they are set.
/**
* \sa rclcpp::Node::add_on_set_parameters_callback
*/
RCLCPP_PUBLIC
virtual
OnSetParametersCallbackHandle::SharedPtr
add_on_set_parameters_callback(OnParametersSetCallbackType callback) = 0;
add_on_set_parameters_callback(OnSetParametersCallbackType callback) = 0;
/// Add a callback that gets triggered after parameters are set successfully.
/**
* \sa rclcpp::Node::add_post_set_parameters_callback
*/
RCLCPP_PUBLIC
virtual
PostSetParametersCallbackHandle::SharedPtr
add_post_set_parameters_callback(PostSetParametersCallbackType callback) = 0;
/// Remove a callback registered with `add_pre_set_parameters_callback`.
/**
* \sa rclcpp::Node::remove_pre_set_parameters_callback
*/
RCLCPP_PUBLIC
virtual
void
remove_pre_set_parameters_callback(const PreSetParametersCallbackHandle * const handler) = 0;
/// Remove a callback registered with `add_on_set_parameters_callback`.
/**
@@ -205,6 +257,15 @@ public:
void
remove_on_set_parameters_callback(const OnSetParametersCallbackHandle * const handler) = 0;
/// Remove a callback registered with `add_post_set_parameters_callback`.
/**
* \sa rclcpp::Node::remove_post_set_parameters_callback
*/
RCLCPP_PUBLIC
virtual
void
remove_post_set_parameters_callback(const PostSetParametersCallbackHandle * const handler) = 0;
/// Return the initial parameter values used by the NodeParameters to override default values.
RCLCPP_PUBLIC
virtual

View File

@@ -15,8 +15,6 @@
#ifndef RCLCPP__NODE_INTERFACES__NODE_TOPICS_INTERFACE_HPP_
#define RCLCPP__NODE_INTERFACES__NODE_TOPICS_INTERFACE_HPP_
#include <functional>
#include <memory>
#include <string>
#include "rcl/publisher.h"

View File

@@ -39,6 +39,7 @@
#include "rclcpp/node.hpp"
#include "rclcpp/parameter.hpp"
#include "rclcpp/parameter_map.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/type_support_decl.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rmw/rmw.h"
@@ -51,6 +52,37 @@ class AsyncParametersClient
public:
RCLCPP_SMART_PTR_DEFINITIONS(AsyncParametersClient)
/// Create an async parameters client.
/**
* \param[in] node_base_interface The node base interface of the corresponding node.
* \param[in] node_topics_interface Node topic base interface.
* \param[in] node_graph_interface The node graph interface of the corresponding node.
* \param[in] node_services_interface Node service interface.
* \param[in] remote_node_name Name of the remote node
* \param[in] qos_profile The rmw qos profile to use to subscribe
* \param[in] group (optional) The async parameter client will be added to this callback group.
* \deprecated use rclcpp::QoS instead of rmw_qos_profile_t
*/
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
RCLCPP_PUBLIC
AsyncParametersClient(
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_interface,
const rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics_interface,
const rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph_interface,
const rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services_interface,
const std::string & remote_node_name,
const rmw_qos_profile_t & qos_profile,
rclcpp::CallbackGroup::SharedPtr group = nullptr)
: AsyncParametersClient(
node_base_interface,
node_topics_interface,
node_graph_interface,
node_services_interface,
remote_node_name,
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)),
group)
{}
/// Create an async parameters client.
/**
* \param[in] node_base_interface The node base interface of the corresponding node.
@@ -58,7 +90,7 @@ public:
* \param[in] node_graph_interface The node graph interface of the corresponding node.
* \param[in] node_services_interface Node service interface.
* \param[in] remote_node_name (optional) name of the remote node
* \param[in] qos_profile (optional) The rmw qos profile to use to subscribe
* \param[in] qos_profile (optional) The qos profile to use to subscribe
* \param[in] group (optional) The async parameter client will be added to this callback group.
*/
RCLCPP_PUBLIC
@@ -68,21 +100,45 @@ public:
const rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph_interface,
const rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services_interface,
const std::string & remote_node_name = "",
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters,
const rclcpp::QoS & qos_profile = rclcpp::ParametersQoS(),
rclcpp::CallbackGroup::SharedPtr group = nullptr);
/// Constructor
/**
* \param[in] node The async paramters client will be added to this node.
* \param[in] node The async parameters client will be added to this node.
* \param[in] remote_node_name name of the remote node
* \param[in] qos_profile The rmw qos profile to use to subscribe
* \param[in] group (optional) The async parameter client will be added to this callback group.
* \deprecated use rclcpp::QoS instead of rmw_qos_profile_t
*/
template<typename NodeT>
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
AsyncParametersClient(
const std::shared_ptr<NodeT> node,
const std::string & remote_node_name,
const rmw_qos_profile_t & qos_profile,
rclcpp::CallbackGroup::SharedPtr group = nullptr)
: AsyncParametersClient(
node->get_node_base_interface(),
node->get_node_topics_interface(),
node->get_node_graph_interface(),
node->get_node_services_interface(),
remote_node_name,
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)),
group)
{}
/**
* \param[in] node The async parameters client will be added to this node.
* \param[in] remote_node_name (optional) name of the remote node
* \param[in] qos_profile (optional) The rmw qos profile to use to subscribe
* \param[in] qos_profile (optional) The qos profile to use to subscribe
* \param[in] group (optional) The async parameter client will be added to this callback group.
*/
template<typename NodeT>
explicit AsyncParametersClient(
const std::shared_ptr<NodeT> node,
const std::string & remote_node_name = "",
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters,
const rclcpp::QoS & qos_profile = rclcpp::ParametersQoS(),
rclcpp::CallbackGroup::SharedPtr group = nullptr)
: AsyncParametersClient(
node->get_node_base_interface(),
@@ -96,16 +152,40 @@ public:
/// Constructor
/**
* \param[in] node The async paramters client will be added to this node.
* \param[in] node The async parameters client will be added to this node.
* \param[in] remote_node_name Name of the remote node
* \param[in] qos_profile The rmw qos profile to use to subscribe
* \param[in] group (optional) The async parameter client will be added to this callback group.
* \deprecated use rclcpp::QoS instead of rmw_qos_profile_t
*/
template<typename NodeT>
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
AsyncParametersClient(
NodeT * node,
const std::string & remote_node_name,
const rmw_qos_profile_t & qos_profile,
rclcpp::CallbackGroup::SharedPtr group = nullptr)
: AsyncParametersClient(
node->get_node_base_interface(),
node->get_node_topics_interface(),
node->get_node_graph_interface(),
node->get_node_services_interface(),
remote_node_name,
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)),
group)
{}
/**
* \param[in] node The async parameters client will be added to this node.
* \param[in] remote_node_name (optional) name of the remote node
* \param[in] qos_profile (optional) The rmw qos profile to use to subscribe
* \param[in] qos_profile (optional) The qos profile to use to subscribe
* \param[in] group (optional) The async parameter client will be added to this callback group.
*/
template<typename NodeT>
explicit AsyncParametersClient(
NodeT * node,
const std::string & remote_node_name = "",
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters,
const rclcpp::QoS & qos_profile = rclcpp::ParametersQoS(),
rclcpp::CallbackGroup::SharedPtr group = nullptr)
: AsyncParametersClient(
node->get_node_base_interface(),
@@ -185,6 +265,9 @@ public:
/**
* This function filters the parameters to be set based on the node name.
*
* If two duplicate keys exist in node names belongs to one FQN, there is no guarantee
* which one could be set.
*
* \param parameter_map named parameters to be loaded
* \return the future of the set_parameter service used to load the parameters
* \throw InvalidParametersException if there is no parameter to set
@@ -208,9 +291,7 @@ public:
typename rclcpp::Subscription<rcl_interfaces::msg::ParameterEvent>::SharedPtr
on_parameter_event(
CallbackT && callback,
const rclcpp::QoS & qos = (
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(rmw_qos_profile_parameter_events))
),
const rclcpp::QoS & qos = rclcpp::ParameterEventsQoS(),
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options = (
rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>()
))
@@ -235,9 +316,7 @@ public:
on_parameter_event(
NodeT && node,
CallbackT && callback,
const rclcpp::QoS & qos = (
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(rmw_qos_profile_parameter_events))
),
const rclcpp::QoS & qos = rclcpp::ParameterEventsQoS(),
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options = (
rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>()
))
@@ -304,11 +383,24 @@ class SyncParametersClient
public:
RCLCPP_SMART_PTR_DEFINITIONS(SyncParametersClient)
template<typename NodeT>
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
SyncParametersClient(
std::shared_ptr<NodeT> node,
const std::string & remote_node_name,
const rmw_qos_profile_t & qos_profile)
: SyncParametersClient(
std::make_shared<rclcpp::executors::SingleThreadedExecutor>(),
node,
remote_node_name,
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)))
{}
template<typename NodeT>
explicit SyncParametersClient(
std::shared_ptr<NodeT> node,
const std::string & remote_node_name = "",
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters)
const rclcpp::QoS & qos_profile = rclcpp::ParametersQoS())
: SyncParametersClient(
std::make_shared<rclcpp::executors::SingleThreadedExecutor>(),
node,
@@ -316,12 +408,29 @@ public:
qos_profile)
{}
template<typename NodeT>
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
SyncParametersClient(
rclcpp::Executor::SharedPtr executor,
std::shared_ptr<NodeT> node,
const std::string & remote_node_name,
const rmw_qos_profile_t & qos_profile)
: SyncParametersClient(
executor,
node->get_node_base_interface(),
node->get_node_topics_interface(),
node->get_node_graph_interface(),
node->get_node_services_interface(),
remote_node_name,
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)))
{}
template<typename NodeT>
SyncParametersClient(
rclcpp::Executor::SharedPtr executor,
std::shared_ptr<NodeT> node,
const std::string & remote_node_name = "",
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters)
const rclcpp::QoS & qos_profile = rclcpp::ParametersQoS())
: SyncParametersClient(
executor,
node->get_node_base_interface(),
@@ -332,11 +441,24 @@ public:
qos_profile)
{}
template<typename NodeT>
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
SyncParametersClient(
NodeT * node,
const std::string & remote_node_name,
const rmw_qos_profile_t & qos_profile)
: SyncParametersClient(
std::make_shared<rclcpp::executors::SingleThreadedExecutor>(),
node,
remote_node_name,
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)))
{}
template<typename NodeT>
explicit SyncParametersClient(
NodeT * node,
const std::string & remote_node_name = "",
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters)
const rclcpp::QoS & qos_profile = rclcpp::ParametersQoS())
: SyncParametersClient(
std::make_shared<rclcpp::executors::SingleThreadedExecutor>(),
node,
@@ -344,12 +466,29 @@ public:
qos_profile)
{}
template<typename NodeT>
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
SyncParametersClient(
rclcpp::Executor::SharedPtr executor,
NodeT * node,
const std::string & remote_node_name,
const rmw_qos_profile_t & qos_profile)
: SyncParametersClient(
executor,
node->get_node_base_interface(),
node->get_node_topics_interface(),
node->get_node_graph_interface(),
node->get_node_services_interface(),
remote_node_name,
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)))
{}
template<typename NodeT>
SyncParametersClient(
rclcpp::Executor::SharedPtr executor,
NodeT * node,
const std::string & remote_node_name = "",
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters)
const rclcpp::QoS & qos_profile = rclcpp::ParametersQoS())
: SyncParametersClient(
executor,
node->get_node_base_interface(),
@@ -360,6 +499,28 @@ public:
qos_profile)
{}
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
RCLCPP_PUBLIC
SyncParametersClient(
rclcpp::Executor::SharedPtr executor,
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_interface,
const rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics_interface,
const rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph_interface,
const rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services_interface,
const std::string & remote_node_name,
const rmw_qos_profile_t & qos_profile)
: executor_(executor), node_base_interface_(node_base_interface)
{
async_parameters_client_ =
std::make_shared<AsyncParametersClient>(
node_base_interface,
node_topics_interface,
node_graph_interface,
node_services_interface,
remote_node_name,
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)));
}
RCLCPP_PUBLIC
SyncParametersClient(
rclcpp::Executor::SharedPtr executor,
@@ -368,7 +529,7 @@ public:
const rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph_interface,
const rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services_interface,
const std::string & remote_node_name = "",
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters)
const rclcpp::QoS & qos_profile = rclcpp::ParametersQoS())
: executor_(executor), node_base_interface_(node_base_interface)
{
async_parameters_client_ =

View File

@@ -86,6 +86,9 @@ struct ParameterEventCallbackHandle
* the ROS node supplied in the ParameterEventHandler constructor.
* The callback, a lambda function in this case, simply prints out the value of the parameter.
*
* Note: the object returned from add_parameter_callback must be captured or the callback will
* be immediately unregistered.
*
* You may also monitor for changes to parameters in other nodes by supplying the node
* name to add_parameter_callback:
*
@@ -103,8 +106,8 @@ struct ParameterEventCallbackHandle
* In this case, the callback will be invoked whenever "some_remote_param_name" changes
* on remote node "some_remote_node_name".
*
* To remove a parameter callback, call remove_parameter_callback, passing the handle returned
* from add_parameter_callback:
* To remove a parameter callback, reset the callback handle smart pointer or call
* remove_parameter_callback, passing the handle returned from add_parameter_callback:
*
* param_handler->remove_parameter_callback(handle2);
*
@@ -152,9 +155,12 @@ struct ParameterEventCallbackHandle
* For both parameter callbacks and parameter event callbacks, when multiple callbacks are added,
* the callbacks are invoked last-in, first-called order (LIFO).
*
* To remove a parameter event callback, use:
* Note: the callback handle returned from add_parameter_event_callback must be captured or
* the callback will immediately be unregistered.
*
* param_handler->remove_event_parameter_callback(handle);
* To remove a parameter event callback, reset the callback smart pointer or use:
*
* param_handler->remove_event_parameter_callback(handle3);
*/
class ParameterEventHandler
{
@@ -189,10 +195,14 @@ public:
/**
* This function may be called multiple times to set multiple parameter event callbacks.
*
* Note: if the returned callback handle smart pointer is not captured, the callback is
* immediatedly unregistered. A compiler warning should be generated to warn of this.
*
* \param[in] callback Function callback to be invoked on parameter updates.
* \returns A handle used to refer to the callback.
*/
RCLCPP_PUBLIC
RCUTILS_WARN_UNUSED
ParameterEventCallbackHandle::SharedPtr
add_parameter_event_callback(
ParameterEventCallbackType callback);
@@ -212,12 +222,17 @@ public:
/**
* If a node_name is not provided, defaults to the current node.
*
* Note: if the returned callback handle smart pointer is not captured, the callback
* is immediately unregistered. A compiler warning should be generated to warn
* of this.
*
* \param[in] parameter_name Name of parameter to monitor.
* \param[in] callback Function callback to be invoked upon parameter update.
* \param[in] node_name Name of node which hosts the parameter.
* \returns A handle used to refer to the callback.
*/
RCLCPP_PUBLIC
RCUTILS_WARN_UNUSED
ParameterCallbackHandle::SharedPtr
add_parameter_callback(
const std::string & parameter_name,

View File

@@ -35,11 +35,13 @@ using ParameterMap = std::unordered_map<std::string, std::vector<Parameter>>;
/// Convert parameters from rcl_yaml_param_parser into C++ class instances.
/// \param[in] c_params C structures containing parameters for multiple nodes.
/// \param[in] node_fqn a Fully Qualified Name of node, default value is nullptr.
/// If it's not nullptr, return the relative node parameters belonging to this node_fqn.
/// \returns a map where the keys are fully qualified node names and values a list of parameters.
/// \throws InvalidParametersException if the `rcl_params_t` is inconsistent or invalid.
RCLCPP_PUBLIC
ParameterMap
parameter_map_from(const rcl_params_t * const c_params);
parameter_map_from(const rcl_params_t * const c_params, const char * node_fqn = nullptr);
/// Convert parameter value from rcl_yaml_param_parser into a C++ class instance.
/// \param[in] c_value C structure containing a value of a parameter.
@@ -51,11 +53,20 @@ parameter_value_from(const rcl_variant_t * const c_value);
/// Get the ParameterMap from a yaml file.
/// \param[in] yaml_filename full name of the yaml file.
/// \param[in] node_fqn a Fully Qualified Name of node, default value is nullptr.
/// \returns an instance of a parameter map
/// \throws from rcl error of rcl_parse_yaml_file()
RCLCPP_PUBLIC
ParameterMap
parameter_map_from_yaml_file(const std::string & yaml_filename);
parameter_map_from_yaml_file(const std::string & yaml_filename, const char * node_fqn = nullptr);
/// Get the Parameters from ParameterMap.
/// \param[in] parameter_map a parameter map.
/// \param[in] node_fqn a Fully Qualified Name of node, default value is nullptr.
/// \returns a list of a parameter
RCLCPP_PUBLIC
std::vector<Parameter>
parameters_from_map(const ParameterMap & parameter_map, const char * node_fqn = nullptr);
} // namespace rclcpp

View File

@@ -28,6 +28,7 @@
#include "rclcpp/macros.hpp"
#include "rclcpp/node.hpp"
#include "rclcpp/parameter.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rmw/rmw.h"
@@ -39,12 +40,26 @@ class ParameterService
public:
RCLCPP_SMART_PTR_DEFINITIONS(ParameterService)
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
RCLCPP_PUBLIC
explicit ParameterService(
ParameterService(
const std::shared_ptr<node_interfaces::NodeBaseInterface> node_base,
const std::shared_ptr<node_interfaces::NodeServicesInterface> node_services,
rclcpp::node_interfaces::NodeParametersInterface * node_params,
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters);
const rmw_qos_profile_t & qos_profile)
: ParameterService(
node_base,
node_services,
node_params,
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile)))
{}
RCLCPP_PUBLIC
ParameterService(
const std::shared_ptr<node_interfaces::NodeBaseInterface> node_base,
const std::shared_ptr<node_interfaces::NodeServicesInterface> node_services,
rclcpp::node_interfaces::NodeParametersInterface * node_params,
const rclcpp::QoS & qos_profile = rclcpp::ParametersQoS());
private:
rclcpp::Service<rcl_interfaces::srv::GetParameters>::SharedPtr get_parameters_service_;

View File

@@ -72,7 +72,7 @@ struct PublisherOptionsWithAllocator : public PublisherOptionsBase
/// 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)

View File

@@ -55,7 +55,7 @@ public:
explicit ServiceBase(std::shared_ptr<rcl_node_t> node_handle);
RCLCPP_PUBLIC
virtual ~ServiceBase();
virtual ~ServiceBase() = default;
/// Return the name of the service.
/** \return The name of the service. */

View File

@@ -363,11 +363,31 @@ public:
void * loaned_message,
const rclcpp::MessageInfo & message_info) override
{
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<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.

View File

@@ -97,7 +97,7 @@ struct SubscriptionOptionsWithAllocator : public SubscriptionOptionsBase
/// Optional custom allocator.
std::shared_ptr<Allocator> allocator = nullptr;
SubscriptionOptionsWithAllocator<Allocator>() {}
SubscriptionOptionsWithAllocator() {}
/// Constructor using base class as input.
explicit SubscriptionOptionsWithAllocator(

View File

@@ -169,7 +169,7 @@ remove_ros_arguments(int argc, char const * const * argv);
* the context initialized by rclcpp::init().
*
* \param[in] context Optional check for shutdown of this Context.
* \return true if shutdown has been called, false otherwise
* \return false if shutdown has been called, true otherwise
*/
RCLCPP_PUBLIC
bool

View File

@@ -2,7 +2,7 @@
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
<name>rclcpp</name>
<version>16.2.0</version>
<version>17.1.0</version>
<description>The ROS client library in C++.</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
<maintainer email="jacob@openrobotics.org">Jacob Perron</maintainer>

View File

@@ -114,7 +114,6 @@ def get_rclcpp_suffix_from_features(features):
@[ end for]@
@[ if 'stream' not in feature_combination]@
* \param ... The format string, followed by the variable arguments for the format string.
* It also accepts a single argument of type std::string.
@[ end if]@
*/
@{params = rclcpp_feature_combinations[feature_combination].params.keys()}@

View File

@@ -12,9 +12,19 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include "rclcpp/callback_group.hpp"
#include <algorithm>
#include <atomic>
#include <functional>
#include <memory>
#include <mutex>
#include <stdexcept>
#include <vector>
#include "rclcpp/callback_group.hpp"
#include "rclcpp/client.hpp"
#include "rclcpp/service.hpp"
#include "rclcpp/subscription_base.hpp"
#include "rclcpp/timer.hpp"
#include "rclcpp/waitable.hpp"
using rclcpp::CallbackGroup;
using rclcpp::CallbackGroupType;
@@ -27,6 +37,10 @@ CallbackGroup::CallbackGroup(
automatically_add_to_executor_with_node_(automatically_add_to_executor_with_node)
{}
CallbackGroup::~CallbackGroup()
{
trigger_notify_guard_condition();
}
std::atomic_bool &
CallbackGroup::can_be_taken_from()
@@ -97,6 +111,33 @@ CallbackGroup::automatically_add_to_executor_with_node() const
return automatically_add_to_executor_with_node_;
}
rclcpp::GuardCondition::SharedPtr
CallbackGroup::get_notify_guard_condition(const rclcpp::Context::SharedPtr context_ptr)
{
std::lock_guard<std::recursive_mutex> lock(notify_guard_condition_mutex_);
if (notify_guard_condition_ && context_ptr != notify_guard_condition_->get_context()) {
if (associated_with_executor_) {
trigger_notify_guard_condition();
}
notify_guard_condition_ = nullptr;
}
if (!notify_guard_condition_) {
notify_guard_condition_ = std::make_shared<rclcpp::GuardCondition>(context_ptr);
}
return notify_guard_condition_;
}
void
CallbackGroup::trigger_notify_guard_condition()
{
std::lock_guard<std::recursive_mutex> lock(notify_guard_condition_mutex_);
if (notify_guard_condition_) {
notify_guard_condition_->trigger();
}
}
void
CallbackGroup::add_subscription(
const rclcpp::SubscriptionBase::SharedPtr subscription_ptr)

View File

@@ -65,13 +65,6 @@ ClientBase::ClientBase(
});
}
ClientBase::~ClientBase()
{
clear_on_new_response_callback();
// Make sure the client handle is destructed as early as possible and before the node handle
client_handle_.reset();
}
bool
ClientBase::take_type_erased_response(void * response_out, rmw_request_id_t & request_header_out)
{

View File

@@ -154,7 +154,9 @@ Context::~Context()
// this will not prevent errors, but will maybe make them easier to reproduce
std::lock_guard<std::recursive_mutex> lock(init_mutex_);
try {
this->shutdown("context destructor was called while still not shutdown");
// Cannot rely on virtual dispatch in a destructor, so explicitly use the
// shutdown() provided by this base class.
Context::shutdown("context destructor was called while still not shutdown");
// at this point it is shutdown and cannot reinit
// clean_up will finalize the rcl context
this->clean_up();

View File

@@ -51,18 +51,13 @@ rclcpp::detail::resolve_parameter_overrides(
[params]() {
rcl_yaml_node_struct_fini(params);
});
rclcpp::ParameterMap initial_map = rclcpp::parameter_map_from(params);
rclcpp::ParameterMap initial_map = rclcpp::parameter_map_from(params, node_fqn.c_str());
// Enforce wildcard matching precedence
// TODO(cottsay) implement further wildcard matching
const std::array<std::string, 2> node_matching_names{"/**", node_fqn};
for (const auto & node_name : node_matching_names) {
if (initial_map.count(node_name) > 0) {
// Combine parameter yaml files, overwriting values in older ones
for (const rclcpp::Parameter & param : initial_map.at(node_name)) {
result[param.get_name()] =
rclcpp::ParameterValue(param.get_value_message());
}
if (initial_map.count(node_fqn) > 0) {
// Combine parameter yaml files, overwriting values in older ones
for (const rclcpp::Parameter & param : initial_map.at(node_fqn)) {
result[param.get_name()] =
rclcpp::ParameterValue(param.get_value_message());
}
}
}

View File

@@ -161,6 +161,13 @@ Duration::operator+(const rclcpp::Duration & rhs) const
rcl_duration_.nanoseconds + rhs.rcl_duration_.nanoseconds);
}
Duration &
Duration::operator+=(const rclcpp::Duration & rhs)
{
*this = *this + rhs;
return *this;
}
void
bounds_check_duration_difference(int64_t lhsns, int64_t rhsns, uint64_t max)
{
@@ -190,6 +197,13 @@ Duration::operator-(const rclcpp::Duration & rhs) const
rcl_duration_.nanoseconds - rhs.rcl_duration_.nanoseconds);
}
Duration &
Duration::operator-=(const rclcpp::Duration & rhs)
{
*this = *this - rhs;
return *this;
}
void
bounds_check_duration_scale(int64_t dns, double scale, uint64_t max)
{
@@ -222,6 +236,13 @@ Duration::operator*(double scale) const
static_cast<long double>(rcl_duration_.nanoseconds) * scale_ld));
}
Duration &
Duration::operator*=(double scale)
{
*this = *this * scale;
return *this;
}
rcl_duration_value_t
Duration::nanoseconds() const
{

View File

@@ -106,11 +106,11 @@ Executor::~Executor()
weak_groups_associated_with_executor_to_nodes_.clear();
weak_groups_to_nodes_associated_with_executor_.clear();
weak_groups_to_nodes_.clear();
for (const auto & pair : weak_nodes_to_guard_conditions_) {
for (const auto & pair : weak_groups_to_guard_conditions_) {
auto guard_condition = pair.second;
memory_strategy_->remove_guard_condition(guard_condition);
}
weak_nodes_to_guard_conditions_.clear();
weak_groups_to_guard_conditions_.clear();
// Finalize the wait set.
if (rcl_wait_set_fini(&wait_set_) != RCL_RET_OK) {
@@ -204,8 +204,7 @@ Executor::add_callback_group_to_map(
if (has_executor.exchange(true)) {
throw std::runtime_error("Callback group has already been added to an executor.");
}
bool is_new_node = !has_node(node_ptr, weak_groups_to_nodes_associated_with_executor_) &&
!has_node(node_ptr, weak_groups_associated_with_executor_to_nodes_);
rclcpp::CallbackGroup::WeakPtr weak_group_ptr = group_ptr;
auto insert_info =
weak_groups_to_nodes.insert(std::make_pair(weak_group_ptr, node_ptr));
@@ -215,21 +214,24 @@ Executor::add_callback_group_to_map(
}
// Also add to the map that contains all callback groups
weak_groups_to_nodes_.insert(std::make_pair(weak_group_ptr, node_ptr));
if (is_new_node) {
const auto & gc = node_ptr->get_notify_guard_condition();
weak_nodes_to_guard_conditions_[node_ptr] = &gc;
if (notify) {
// Interrupt waiting to handle new node
try {
interrupt_guard_condition_.trigger();
} catch (const rclcpp::exceptions::RCLError & ex) {
throw std::runtime_error(
std::string(
"Failed to trigger guard condition on callback group add: ") + ex.what());
}
if (node_ptr->get_context()->is_valid()) {
auto callback_group_guard_condition =
group_ptr->get_notify_guard_condition(node_ptr->get_context());
weak_groups_to_guard_conditions_[weak_group_ptr] = callback_group_guard_condition.get();
// Add the callback_group's notify condition to the guard condition handles
memory_strategy_->add_guard_condition(*callback_group_guard_condition);
}
if (notify) {
// Interrupt waiting to handle new node
try {
interrupt_guard_condition_.trigger();
} catch (const rclcpp::exceptions::RCLError & ex) {
throw std::runtime_error(
std::string(
"Failed to trigger guard condition on callback group add: ") + ex.what());
}
// Add the node's notify condition to the guard condition handles
memory_strategy_->add_guard_condition(gc);
}
}
@@ -300,7 +302,12 @@ Executor::remove_callback_group_from_map(
if (!has_node(node_ptr, weak_groups_to_nodes_associated_with_executor_) &&
!has_node(node_ptr, weak_groups_associated_with_executor_to_nodes_))
{
weak_nodes_to_guard_conditions_.erase(node_ptr);
auto iter = weak_groups_to_guard_conditions_.find(weak_group_ptr);
if (iter != weak_groups_to_guard_conditions_.end()) {
memory_strategy_->remove_guard_condition(iter->second);
}
weak_groups_to_guard_conditions_.erase(weak_group_ptr);
if (notify) {
try {
interrupt_guard_condition_.trigger();
@@ -310,7 +317,6 @@ Executor::remove_callback_group_from_map(
"Failed to trigger guard condition on callback group remove: ") + ex.what());
}
}
memory_strategy_->remove_guard_condition(&node_ptr->get_notify_guard_condition());
}
}
@@ -700,12 +706,6 @@ Executor::wait_for_work(std::chrono::nanoseconds timeout)
auto weak_node_ptr = pair.second;
if (weak_group_ptr.expired() || weak_node_ptr.expired()) {
invalid_group_ptrs.push_back(weak_group_ptr);
auto node_guard_pair = weak_nodes_to_guard_conditions_.find(weak_node_ptr);
if (node_guard_pair != weak_nodes_to_guard_conditions_.end()) {
auto guard_condition = node_guard_pair->second;
weak_nodes_to_guard_conditions_.erase(weak_node_ptr);
memory_strategy_->remove_guard_condition(guard_condition);
}
}
}
std::for_each(
@@ -721,6 +721,12 @@ Executor::wait_for_work(std::chrono::nanoseconds timeout)
{
weak_groups_associated_with_executor_to_nodes_.erase(group_ptr);
}
auto callback_guard_pair = weak_groups_to_guard_conditions_.find(group_ptr);
if (callback_guard_pair != weak_groups_to_guard_conditions_.end()) {
auto guard_condition = callback_guard_pair->second;
weak_groups_to_guard_conditions_.erase(group_ptr);
memory_strategy_->remove_guard_condition(guard_condition);
}
weak_groups_to_nodes_.erase(group_ptr);
});
}

View File

@@ -21,6 +21,7 @@
#include "rcpputils/scope_exit.hpp"
#include "rclcpp/logging.hpp"
#include "rclcpp/utilities.hpp"
using rclcpp::executors::MultiThreadedExecutor;
@@ -34,9 +35,15 @@ MultiThreadedExecutor::MultiThreadedExecutor(
yield_before_execute_(yield_before_execute),
next_exec_timeout_(next_exec_timeout)
{
number_of_threads_ = number_of_threads ? number_of_threads : std::thread::hardware_concurrency();
if (number_of_threads_ == 0) {
number_of_threads_ = 1;
number_of_threads_ = number_of_threads > 0 ?
number_of_threads :
std::max(std::thread::hardware_concurrency(), 2U);
if (number_of_threads_ == 1) {
RCLCPP_WARN(
rclcpp::get_logger("rclcpp"),
"MultiThreadedExecutor is used with a single thread.\n"
"Use the SingleThreadedExecutor instead.");
}
}

View File

@@ -48,7 +48,7 @@ GraphListener::GraphListener(const std::shared_ptr<Context> & parent_context)
GraphListener::~GraphListener()
{
this->shutdown(std::nothrow);
GraphListener::shutdown(std::nothrow);
}
void GraphListener::init_wait_set()

View File

@@ -74,16 +74,19 @@ GuardCondition::get_rcl_guard_condition() const
void
GuardCondition::trigger()
{
std::lock_guard<std::recursive_mutex> lock(reentrant_mutex_);
rcl_ret_t ret = rcl_trigger_guard_condition(&rcl_guard_condition_);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);
}
if (on_trigger_callback_) {
on_trigger_callback_(1);
} else {
rcl_ret_t ret = rcl_trigger_guard_condition(&rcl_guard_condition_);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);
{
std::lock_guard<std::recursive_mutex> lock(reentrant_mutex_);
if (on_trigger_callback_) {
on_trigger_callback_(1);
} else {
unread_count_++;
}
unread_count_++;
}
}
@@ -125,10 +128,9 @@ GuardCondition::set_on_trigger_callback(std::function<void(size_t)> callback)
callback(unread_count_);
unread_count_ = 0;
}
return;
} else {
on_trigger_callback_ = nullptr;
}
on_trigger_callback_ = nullptr;
}
} // namespace rclcpp

View File

@@ -353,7 +353,7 @@ Node::has_parameter(const std::string & name) const
rcl_interfaces::msg::SetParametersResult
Node::set_parameter(const rclcpp::Parameter & parameter)
{
return this->set_parameters_atomically({parameter});
return node_parameters_->set_parameters_atomically({parameter});
}
std::vector<rcl_interfaces::msg::SetParametersResult>
@@ -418,16 +418,40 @@ Node::list_parameters(const std::vector<std::string> & prefixes, uint64_t depth)
return node_parameters_->list_parameters(prefixes, depth);
}
rclcpp::Node::PreSetParametersCallbackHandle::SharedPtr
Node::add_pre_set_parameters_callback(PreSetParametersCallbackType callback)
{
return node_parameters_->add_pre_set_parameters_callback(callback);
}
rclcpp::Node::OnSetParametersCallbackHandle::SharedPtr
Node::add_on_set_parameters_callback(OnParametersSetCallbackType callback)
Node::add_on_set_parameters_callback(OnSetParametersCallbackType callback)
{
return node_parameters_->add_on_set_parameters_callback(callback);
}
void
Node::remove_on_set_parameters_callback(const OnSetParametersCallbackHandle * const callback)
rclcpp::Node::PostSetParametersCallbackHandle::SharedPtr
Node::add_post_set_parameters_callback(PostSetParametersCallbackType callback)
{
return node_parameters_->remove_on_set_parameters_callback(callback);
return node_parameters_->add_post_set_parameters_callback(callback);
}
void
Node::remove_pre_set_parameters_callback(const PreSetParametersCallbackHandle * const handler)
{
node_parameters_->remove_pre_set_parameters_callback(handler);
}
void
Node::remove_on_set_parameters_callback(const OnSetParametersCallbackHandle * const handler)
{
node_parameters_->remove_on_set_parameters_callback(handler);
}
void
Node::remove_post_set_parameters_callback(const PostSetParametersCallbackHandle * const handler)
{
node_parameters_->remove_post_set_parameters_callback(handler);
}
std::vector<std::string>

View File

@@ -37,12 +37,13 @@ NodeBase::NodeBase(
rclcpp::Context::SharedPtr context,
const rcl_node_options_t & rcl_node_options,
bool use_intra_process_default,
bool enable_topic_statistics_default)
bool enable_topic_statistics_default,
rclcpp::CallbackGroup::SharedPtr default_callback_group)
: context_(context),
use_intra_process_default_(use_intra_process_default),
enable_topic_statistics_default_(enable_topic_statistics_default),
node_handle_(nullptr),
default_callback_group_(nullptr),
default_callback_group_(default_callback_group),
associated_with_executor_(false),
notify_guard_condition_(context),
notify_guard_condition_is_valid_(false)
@@ -128,9 +129,12 @@ NodeBase::NodeBase(
delete node;
});
// Create the default callback group.
using rclcpp::CallbackGroupType;
default_callback_group_ = create_callback_group(CallbackGroupType::MutuallyExclusive);
// Create the default callback group, if needed.
if (nullptr == default_callback_group_) {
using rclcpp::CallbackGroupType;
default_callback_group_ =
NodeBase::create_callback_group(CallbackGroupType::MutuallyExclusive);
}
// Indicate the notify_guard_condition is now valid.
notify_guard_condition_is_valid_ = true;

View File

@@ -19,7 +19,7 @@ using rclcpp::node_interfaces::NodeLogging;
NodeLogging::NodeLogging(rclcpp::node_interfaces::NodeBaseInterface * node_base)
: node_base_(node_base)
{
logger_ = rclcpp::get_logger(this->get_logger_name());
logger_ = rclcpp::get_logger(NodeLogging::get_logger_name());
}
NodeLogging::~NodeLogging()

View File

@@ -39,6 +39,31 @@
using rclcpp::node_interfaces::NodeParameters;
RCLCPP_LOCAL
void
local_perform_automatically_declare_parameters_from_overrides(
const std::map<std::string, rclcpp::ParameterValue> & parameter_overrides,
std::function<bool(const std::string &)> has_parameter,
std::function<void(
const std::string &,
const rclcpp::ParameterValue &,
const rcl_interfaces::msg::ParameterDescriptor &,
bool)>
declare_parameter)
{
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.dynamic_typing = true;
for (const auto & pair : parameter_overrides) {
if (!has_parameter(pair.first)) {
declare_parameter(
pair.first,
pair.second,
descriptor,
true);
}
}
}
NodeParameters::NodeParameters(
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base,
const rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging,
@@ -101,20 +126,43 @@ NodeParameters::NodeParameters(
// If asked, initialize any parameters that ended up in the initial parameter values,
// but did not get declared explcitily by this point.
if (automatically_declare_parameters_from_overrides) {
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.dynamic_typing = true;
for (const auto & pair : this->get_parameter_overrides()) {
if (!this->has_parameter(pair.first)) {
this->declare_parameter(
pair.first,
pair.second,
descriptor,
true);
using namespace std::placeholders;
local_perform_automatically_declare_parameters_from_overrides(
this->get_parameter_overrides(),
std::bind(&NodeParameters::has_parameter, this, _1),
[this](
const std::string & name,
const rclcpp::ParameterValue & default_value,
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor,
bool ignore_override)
{
NodeParameters::declare_parameter(
name, default_value, parameter_descriptor, ignore_override);
}
}
);
}
}
void
NodeParameters::perform_automatically_declare_parameters_from_overrides()
{
local_perform_automatically_declare_parameters_from_overrides(
this->get_parameter_overrides(),
[this](const std::string & name) {
return this->has_parameter(name);
},
[this](
const std::string & name,
const rclcpp::ParameterValue & default_value,
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor,
bool ignore_override)
{
this->declare_parameter(
name, default_value, parameter_descriptor, ignore_override);
}
);
}
NodeParameters::~NodeParameters()
{}
@@ -257,19 +305,54 @@ __check_parameters(
return result;
}
using OnParametersSetCallbackType =
rclcpp::node_interfaces::NodeParametersInterface::OnParametersSetCallbackType;
using CallbacksContainerType =
rclcpp::node_interfaces::NodeParameters::CallbacksContainerType;
using PreSetParametersCallbackType =
rclcpp::node_interfaces::NodeParametersInterface::PreSetParametersCallbackType;
using PreSetParametersCallbackHandle =
rclcpp::node_interfaces::PreSetParametersCallbackHandle;
using PreSetCallbacksHandleContainer =
rclcpp::node_interfaces::NodeParameters::PreSetCallbacksHandleContainer;
using OnSetParametersCallbackType =
rclcpp::node_interfaces::NodeParametersInterface::OnSetParametersCallbackType;
using OnSetParametersCallbackHandle =
rclcpp::node_interfaces::OnSetParametersCallbackHandle;
using OnSetCallbacksHandleContainer =
rclcpp::node_interfaces::NodeParameters::OnSetCallbacksHandleContainer;
using PostSetParametersCallbackType =
rclcpp::node_interfaces::NodeParametersInterface::PostSetParametersCallbackType;
using PostSetParametersCallbackHandle =
rclcpp::node_interfaces::PostSetParametersCallbackHandle;
using PostSetCallbacksHandleContainer =
rclcpp::node_interfaces::NodeParameters::PostSetCallbacksHandleContainer;
RCLCPP_LOCAL
void
__call_pre_set_parameters_callbacks(
std::vector<rclcpp::Parameter> & parameters,
PreSetCallbacksHandleContainer & callback_container)
{
if (callback_container.empty()) {
return;
}
auto it = callback_container.begin();
while (it != callback_container.end()) {
auto shared_handle = it->lock();
if (nullptr != shared_handle) {
shared_handle->callback(parameters);
it++;
} else {
it = callback_container.erase(it);
}
}
}
RCLCPP_LOCAL
rcl_interfaces::msg::SetParametersResult
__call_on_parameters_set_callbacks(
__call_on_set_parameters_callbacks(
const std::vector<rclcpp::Parameter> & parameters,
CallbacksContainerType & callback_container,
const OnParametersSetCallbackType & callback)
OnSetCallbacksHandleContainer & callback_container)
{
rcl_interfaces::msg::SetParametersResult result;
result.successful = true;
@@ -286,19 +369,37 @@ __call_on_parameters_set_callbacks(
it = callback_container.erase(it);
}
}
if (callback) {
result = callback(parameters);
}
return result;
}
RCLCPP_LOCAL
void __call_post_set_parameters_callbacks(
const std::vector<rclcpp::Parameter> & parameters,
PostSetCallbacksHandleContainer & callback_container)
{
if (callback_container.empty()) {
return;
}
auto it = callback_container.begin();
while (it != callback_container.end()) {
auto shared_handle = it->lock();
if (nullptr != shared_handle) {
shared_handle->callback(parameters);
it++;
} else {
it = callback_container.erase(it);
}
}
}
RCLCPP_LOCAL
rcl_interfaces::msg::SetParametersResult
__set_parameters_atomically_common(
const std::vector<rclcpp::Parameter> & parameters,
std::map<std::string, rclcpp::node_interfaces::ParameterInfo> & parameter_infos,
CallbacksContainerType & callback_container,
const OnParametersSetCallbackType & callback,
OnSetCallbacksHandleContainer & on_set_callback_container,
PostSetCallbacksHandleContainer & post_set_callback_container,
bool allow_undeclared = false)
{
// Check if the value being set complies with the descriptor.
@@ -307,9 +408,9 @@ __set_parameters_atomically_common(
if (!result.successful) {
return result;
}
// Call the user callback to see if the new value(s) are allowed.
// Call the user callbacks to see if the new value(s) are allowed.
result =
__call_on_parameters_set_callbacks(parameters, callback_container, callback);
__call_on_set_parameters_callbacks(parameters, on_set_callback_container);
if (!result.successful) {
return result;
}
@@ -321,6 +422,8 @@ __set_parameters_atomically_common(
parameter_infos[name].descriptor.type = parameters[i].get_type();
parameter_infos[name].value = parameters[i].get_parameter_value();
}
// Call the user post set parameter callback
__call_post_set_parameters_callbacks(parameters, post_set_callback_container);
}
// Either way, return the result.
@@ -335,8 +438,8 @@ __declare_parameter_common(
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor,
std::map<std::string, rclcpp::node_interfaces::ParameterInfo> & parameters_out,
const std::map<std::string, rclcpp::ParameterValue> & overrides,
CallbacksContainerType & callback_container,
const OnParametersSetCallbackType & callback,
OnSetCallbacksHandleContainer & on_set_callback_container,
PostSetCallbacksHandleContainer & post_set_callback_container,
rcl_interfaces::msg::ParameterEvent * parameter_event_out,
bool ignore_override = false)
{
@@ -366,14 +469,15 @@ __declare_parameter_common(
return result;
}
// Check with the user's callback to see if the initial value can be set.
// Check with the user's callbacks to see if the initial value can be set.
std::vector<rclcpp::Parameter> parameter_wrappers {rclcpp::Parameter(name, *initial_value)};
// This function also takes care of default vs initial value.
auto result = __set_parameters_atomically_common(
parameter_wrappers,
parameter_infos,
callback_container,
callback);
on_set_callback_container,
post_set_callback_container
);
if (!result.successful) {
return result;
@@ -400,8 +504,8 @@ declare_parameter_helper(
bool ignore_override,
std::map<std::string, rclcpp::node_interfaces::ParameterInfo> & parameters,
const std::map<std::string, rclcpp::ParameterValue> & overrides,
CallbacksContainerType & callback_container,
const OnParametersSetCallbackType & callback,
OnSetCallbacksHandleContainer & on_set_callback_container,
PostSetCallbacksHandleContainer & post_set_callback_container,
rclcpp::Publisher<rcl_interfaces::msg::ParameterEvent> * events_publisher,
const std::string & combined_name,
rclcpp::node_interfaces::NodeClockInterface & node_clock)
@@ -437,8 +541,8 @@ declare_parameter_helper(
parameter_descriptor,
parameters,
overrides,
callback_container,
callback,
on_set_callback_container,
post_set_callback_container,
&parameter_event,
ignore_override);
@@ -485,8 +589,8 @@ NodeParameters::declare_parameter(
ignore_override,
parameters_,
parameter_overrides_,
on_parameters_set_callback_container_,
on_parameters_set_callback_,
on_set_parameters_callback_container_,
post_set_parameters_callback_container_,
events_publisher_.get(),
combined_name_,
*node_clock_);
@@ -521,8 +625,8 @@ NodeParameters::declare_parameter(
ignore_override,
parameters_,
parameter_overrides_,
on_parameters_set_callback_container_,
on_parameters_set_callback_,
on_set_parameters_callback_container_,
post_set_parameters_callback_container_,
events_publisher_.get(),
combined_name_,
*node_clock_);
@@ -596,12 +700,27 @@ NodeParameters::set_parameters_atomically(const std::vector<rclcpp::Parameter> &
rcl_interfaces::msg::SetParametersResult result;
// call any user registered pre set parameter callbacks
// this callback can make changes to the original parameters list
// also check if the changed parameter list is empty or not, if empty return
std::vector<rclcpp::Parameter> parameters_after_pre_set_callback(parameters);
__call_pre_set_parameters_callbacks(
parameters_after_pre_set_callback,
pre_set_parameters_callback_container_);
if (parameters_after_pre_set_callback.empty()) {
result.successful = false;
result.reason = "parameter list cannot be empty, this might be due to "
"pre_set_parameters_callback modifying the original parameters list.";
return result;
}
// Check if any of the parameters are read-only, or if any parameters are not
// declared.
// If not declared, keep track of them in order to declare them later, when
// undeclared parameters are allowed, and if they're not allowed, fail.
std::vector<const rclcpp::Parameter *> parameters_to_be_declared;
for (const auto & parameter : parameters) {
for (const auto & parameter : parameters_after_pre_set_callback) {
const std::string & name = parameter.get_name();
// Check to make sure the parameter name is valid.
@@ -636,12 +755,13 @@ NodeParameters::set_parameters_atomically(const std::vector<rclcpp::Parameter> &
// Declare parameters into a temporary "staging area", incase one of the declares fail.
// We will use the staged changes as input to the "set atomically" action.
// We explicitly avoid calling the user callback here, so that it may be called once, with
// We explicitly avoid calling the user callbacks here, so that it may be called once, with
// all the other parameters to be set (already declared parameters).
std::map<std::string, rclcpp::node_interfaces::ParameterInfo> staged_parameter_changes;
rcl_interfaces::msg::ParameterEvent parameter_event_msg;
parameter_event_msg.node = combined_name_;
CallbacksContainerType empty_callback_container;
OnSetCallbacksHandleContainer empty_on_set_callback_container;
PostSetCallbacksHandleContainer empty_post_set_callback_container;
// Implicit declare uses dynamic type descriptor.
rcl_interfaces::msg::ParameterDescriptor descriptor;
@@ -656,8 +776,8 @@ NodeParameters::set_parameters_atomically(const std::vector<rclcpp::Parameter> &
staged_parameter_changes,
parameter_overrides_,
// Only call callbacks once below
empty_callback_container, // callback_container is explicitly empty
nullptr, // callback is explicitly null.
empty_on_set_callback_container, // callback_container is explicitly empty
empty_post_set_callback_container, // callback_container is explicitly empty
&parameter_event_msg,
true);
if (!result.successful) {
@@ -670,12 +790,14 @@ NodeParameters::set_parameters_atomically(const std::vector<rclcpp::Parameter> &
// If there were implicitly declared parameters, then we may need to copy the input parameters
// and then assign the value that was selected after the declare (could be affected by the
// initial parameter values).
const std::vector<rclcpp::Parameter> * parameters_to_be_set = &parameters;
const std::vector<rclcpp::Parameter> * parameters_to_be_set = &parameters_after_pre_set_callback;
std::vector<rclcpp::Parameter> parameters_copy;
if (0 != staged_parameter_changes.size()) { // If there were any implicitly declared parameters.
bool any_initial_values_used = false;
for (const auto & staged_parameter_change : staged_parameter_changes) {
auto it = __find_parameter_by_name(parameters, staged_parameter_change.first);
auto it = __find_parameter_by_name(
parameters_after_pre_set_callback,
staged_parameter_change.first);
if (it->get_parameter_value() != staged_parameter_change.second.value) {
// In this case, the value of the staged parameter differs from the
// input from the user, and therefore we need to update things before setting.
@@ -685,7 +807,7 @@ NodeParameters::set_parameters_atomically(const std::vector<rclcpp::Parameter> &
}
}
if (any_initial_values_used) {
parameters_copy = parameters;
parameters_copy = parameters_after_pre_set_callback;
for (const auto & staged_parameter_change : staged_parameter_changes) {
auto it = __find_parameter_by_name(parameters_copy, staged_parameter_change.first);
*it = Parameter(staged_parameter_change.first, staged_parameter_change.second.value);
@@ -717,11 +839,10 @@ NodeParameters::set_parameters_atomically(const std::vector<rclcpp::Parameter> &
*parameters_to_be_set,
// they are actually set on the official parameter storage
parameters_,
// this will get called once, with all the parameters to be set
on_parameters_set_callback_container_,
// These callbacks are called once. When a callback returns an unsuccessful result,
// the remaining aren't called.
on_parameters_set_callback_,
// the remaining aren't called
on_set_parameters_callback_container_,
post_set_parameters_callback_container_,
allow_undeclared_); // allow undeclared
// If not successful, then stop here.
@@ -777,7 +898,6 @@ NodeParameters::set_parameters_atomically(const std::vector<rclcpp::Parameter> &
parameter_event_msg.stamp = node_clock_->get_clock()->now();
events_publisher_->publish(parameter_event_msg);
}
return result;
}
@@ -963,6 +1083,26 @@ NodeParameters::list_parameters(const std::vector<std::string> & prefixes, uint6
return result;
}
void
NodeParameters::remove_pre_set_parameters_callback(
const PreSetParametersCallbackHandle * const handle)
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
auto it = std::find_if(
pre_set_parameters_callback_container_.begin(),
pre_set_parameters_callback_container_.end(),
[handle](const auto & weak_handle) {
return handle == weak_handle.lock().get();
});
if (it != pre_set_parameters_callback_container_.end()) {
pre_set_parameters_callback_container_.erase(it);
} else {
throw std::runtime_error("Pre set parameter callback doesn't exist");
}
}
void
NodeParameters::remove_on_set_parameters_callback(
const OnSetParametersCallbackHandle * const handle)
@@ -971,20 +1111,53 @@ NodeParameters::remove_on_set_parameters_callback(
ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
auto it = std::find_if(
on_parameters_set_callback_container_.begin(),
on_parameters_set_callback_container_.end(),
on_set_parameters_callback_container_.begin(),
on_set_parameters_callback_container_.end(),
[handle](const auto & weak_handle) {
return handle == weak_handle.lock().get();
});
if (it != on_parameters_set_callback_container_.end()) {
on_parameters_set_callback_container_.erase(it);
if (it != on_set_parameters_callback_container_.end()) {
on_set_parameters_callback_container_.erase(it);
} else {
throw std::runtime_error("Callback doesn't exist");
throw std::runtime_error("On set parameter callback doesn't exist");
}
}
void
NodeParameters::remove_post_set_parameters_callback(
const PostSetParametersCallbackHandle * const handle)
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
auto it = std::find_if(
post_set_parameters_callback_container_.begin(),
post_set_parameters_callback_container_.end(),
[handle](const auto & weak_handle) {
return handle == weak_handle.lock().get();
});
if (it != post_set_parameters_callback_container_.end()) {
post_set_parameters_callback_container_.erase(it);
} else {
throw std::runtime_error("Post set parameter callback doesn't exist");
}
}
PreSetParametersCallbackHandle::SharedPtr
NodeParameters::add_pre_set_parameters_callback(PreSetParametersCallbackType callback)
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
auto handle = std::make_shared<PreSetParametersCallbackHandle>();
handle->callback = callback;
// the last callback registered is executed first.
pre_set_parameters_callback_container_.emplace_front(handle);
return handle;
}
OnSetParametersCallbackHandle::SharedPtr
NodeParameters::add_on_set_parameters_callback(OnParametersSetCallbackType callback)
NodeParameters::add_on_set_parameters_callback(OnSetParametersCallbackType callback)
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
@@ -992,7 +1165,21 @@ NodeParameters::add_on_set_parameters_callback(OnParametersSetCallbackType callb
auto handle = std::make_shared<OnSetParametersCallbackHandle>();
handle->callback = callback;
// the last callback registered is executed first.
on_parameters_set_callback_container_.emplace_front(handle);
on_set_parameters_callback_container_.emplace_front(handle);
return handle;
}
PostSetParametersCallbackHandle::SharedPtr
NodeParameters::add_post_set_parameters_callback(
PostSetParametersCallbackType callback)
{
std::lock_guard<std::recursive_mutex> lock(mutex_);
ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
auto handle = std::make_shared<PostSetParametersCallbackHandle>();
handle->callback = callback;
// the last callback registered is executed first.
post_set_parameters_callback_container_.emplace_front(handle);
return handle;
}

View File

@@ -35,15 +35,17 @@ NodeServices::add_service(
// TODO(jacquelinekay): use custom exception
throw std::runtime_error("Cannot create service, group not in node.");
}
group->add_service(service_base_ptr);
} else {
node_base_->get_default_callback_group()->add_service(service_base_ptr);
group = node_base_->get_default_callback_group();
}
group->add_service(service_base_ptr);
// Notify the executor that a new service was created using the parent Node.
auto & node_gc = node_base_->get_notify_guard_condition();
try {
node_gc.trigger();
group->trigger_notify_guard_condition();
} catch (const rclcpp::exceptions::RCLError & ex) {
throw std::runtime_error(
std::string("failed to notify wait set on service creation: ") + ex.what());
@@ -60,15 +62,17 @@ NodeServices::add_client(
// TODO(jacquelinekay): use custom exception
throw std::runtime_error("Cannot create client, group not in node.");
}
group->add_client(client_base_ptr);
} else {
node_base_->get_default_callback_group()->add_client(client_base_ptr);
group = node_base_->get_default_callback_group();
}
group->add_client(client_base_ptr);
// Notify the executor that a new client was created using the parent Node.
auto & node_gc = node_base_->get_notify_guard_condition();
try {
node_gc.trigger();
group->trigger_notify_guard_condition();
} catch (const rclcpp::exceptions::RCLError & ex) {
throw std::runtime_error(
std::string("failed to notify wait set on client creation: ") + ex.what());

View File

@@ -37,14 +37,15 @@ NodeTimers::add_timer(
// TODO(jacquelinekay): use custom exception
throw std::runtime_error("Cannot create timer, group not in node.");
}
callback_group->add_timer(timer);
} else {
node_base_->get_default_callback_group()->add_timer(timer);
callback_group = node_base_->get_default_callback_group();
}
callback_group->add_timer(timer);
auto & node_gc = node_base_->get_notify_guard_condition();
try {
node_gc.trigger();
callback_group->trigger_notify_guard_condition();
} catch (const rclcpp::exceptions::RCLError & ex) {
throw std::runtime_error(
std::string("failed to notify wait set on timer creation: ") + ex.what());

View File

@@ -73,6 +73,7 @@ NodeTopics::add_publisher(
auto & node_gc = node_base_->get_notify_guard_condition();
try {
node_gc.trigger();
callback_group->trigger_notify_guard_condition();
} catch (const rclcpp::exceptions::RCLError & ex) {
throw std::runtime_error(
std::string("failed to notify wait set on publisher creation: ") + ex.what());
@@ -121,6 +122,7 @@ NodeTopics::add_subscription(
auto & node_gc = node_base_->get_notify_guard_condition();
try {
node_gc.trigger();
callback_group->trigger_notify_guard_condition();
} catch (const rclcpp::exceptions::RCLError & ex) {
throw std::runtime_error(
std::string("failed to notify wait set on subscription creation: ") + ex.what());

View File

@@ -35,15 +35,17 @@ NodeWaitables::add_waitable(
// TODO(jacobperron): use custom exception
throw std::runtime_error("Cannot create waitable, group not in node.");
}
group->add_waitable(waitable_ptr);
} else {
node_base_->get_default_callback_group()->add_waitable(waitable_ptr);
group = node_base_->get_default_callback_group();
}
group->add_waitable(waitable_ptr);
// Notify the executor that a new waitable was created using the parent Node.
auto & node_gc = node_base_->get_notify_guard_condition();
try {
node_gc.trigger();
group->trigger_notify_guard_condition();
} catch (const rclcpp::exceptions::RCLError & ex) {
throw std::runtime_error(
std::string("failed to notify wait set on waitable creation: ") + ex.what());

View File

@@ -35,7 +35,7 @@ AsyncParametersClient::AsyncParametersClient(
const rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph_interface,
const rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services_interface,
const std::string & remote_node_name,
const rmw_qos_profile_t & qos_profile,
const rclcpp::QoS & qos_profile,
rclcpp::CallbackGroup::SharedPtr group)
: node_topics_interface_(node_topics_interface)
{
@@ -46,7 +46,7 @@ AsyncParametersClient::AsyncParametersClient(
}
rcl_client_options_t options = rcl_client_get_default_options();
options.qos = qos_profile;
options.qos = qos_profile.get_rmw_qos_profile();
using rclcpp::Client;
using rclcpp::ClientBase;
@@ -290,28 +290,24 @@ std::shared_future<std::vector<rcl_interfaces::msg::SetParametersResult>>
AsyncParametersClient::load_parameters(
const std::string & yaml_filename)
{
rclcpp::ParameterMap parameter_map = rclcpp::parameter_map_from_yaml_file(yaml_filename);
return this->load_parameters(parameter_map);
rclcpp::ParameterMap parameter_map =
rclcpp::parameter_map_from_yaml_file(yaml_filename, remote_node_name_.c_str());
auto iter = parameter_map.find(remote_node_name_);
if (iter == parameter_map.end() || iter->second.size() == 0) {
throw rclcpp::exceptions::InvalidParametersException("No valid parameter");
}
auto future_result = set_parameters(iter->second);
return future_result;
}
std::shared_future<std::vector<rcl_interfaces::msg::SetParametersResult>>
AsyncParametersClient::load_parameters(
const rclcpp::ParameterMap & parameter_map)
{
std::vector<rclcpp::Parameter> parameters;
std::string remote_name = remote_node_name_.substr(remote_node_name_.substr(1).find("/") + 2);
for (const auto & params : parameter_map) {
std::string node_full_name = params.first;
std::string node_name = node_full_name.substr(node_full_name.find("/*/") + 3);
if (node_full_name == remote_node_name_ ||
node_full_name == "/**" ||
(node_name == remote_name))
{
for (const auto & param : params.second) {
parameters.push_back(param);
}
}
}
std::vector<rclcpp::Parameter> parameters =
rclcpp::parameters_from_map(parameter_map, remote_node_name_.c_str());
if (parameters.size() == 0) {
throw rclcpp::exceptions::InvalidParametersException("No valid parameter");

View File

@@ -13,8 +13,11 @@
// limitations under the License.
#include <string>
#include <regex>
#include <vector>
#include "rcpputils/find_and_replace.hpp"
#include "rcpputils/scope_exit.hpp"
#include "rclcpp/parameter_map.hpp"
using rclcpp::exceptions::InvalidParametersException;
@@ -22,8 +25,15 @@ using rclcpp::exceptions::InvalidParameterValueException;
using rclcpp::ParameterMap;
using rclcpp::ParameterValue;
static bool is_node_name_matched(const std::string & node_name, const char * node_fqn)
{
// Update the regular expression ["/*" -> "(/\\w+)" and "/**" -> "(/\\w+)*"]
std::string regex = rcpputils::find_and_replace(node_name, "/*", "(/\\w+)");
return std::regex_match(node_fqn, std::regex(regex));
}
ParameterMap
rclcpp::parameter_map_from(const rcl_params_t * const c_params)
rclcpp::parameter_map_from(const rcl_params_t * const c_params, const char * node_fqn)
{
if (NULL == c_params) {
throw InvalidParametersException("parameters struct is NULL");
@@ -49,6 +59,15 @@ rclcpp::parameter_map_from(const rcl_params_t * const c_params)
node_name = c_node_name;
}
if (node_fqn) {
if (!is_node_name_matched(node_name, node_fqn)) {
// No need to parse the items because the user just care about node_fqn
continue;
}
node_name = node_fqn;
}
const rcl_node_params_t * const c_params_node = &(c_params->params[n]);
std::vector<Parameter> & params_node = parameters[node_name];
@@ -65,6 +84,7 @@ rclcpp::parameter_map_from(const rcl_params_t * const c_params)
params_node.emplace_back(c_param_name, parameter_value_from(c_param_value));
}
}
return parameters;
}
@@ -128,13 +148,31 @@ rclcpp::parameter_value_from(const rcl_variant_t * const c_param_value)
}
ParameterMap
rclcpp::parameter_map_from_yaml_file(const std::string & yaml_filename)
rclcpp::parameter_map_from_yaml_file(const std::string & yaml_filename, const char * node_fqn)
{
rcutils_allocator_t allocator = rcutils_get_default_allocator();
rcl_params_t * rcl_parameters = rcl_yaml_node_struct_init(allocator);
RCPPUTILS_SCOPE_EXIT(rcl_yaml_node_struct_fini(rcl_parameters); );
const char * path = yaml_filename.c_str();
if (!rcl_parse_yaml_file(path, rcl_parameters)) {
rclcpp::exceptions::throw_from_rcl_error(RCL_RET_ERROR);
}
return rclcpp::parameter_map_from(rcl_parameters);
return rclcpp::parameter_map_from(rcl_parameters, node_fqn);
}
std::vector<rclcpp::Parameter>
rclcpp::parameters_from_map(const ParameterMap & parameter_map, const char * node_fqn)
{
std::vector<rclcpp::Parameter> parameters;
std::string node_name_old;
for (auto & [node_name, node_parameters] : parameter_map) {
if (node_fqn && !is_node_name_matched(node_name, node_fqn)) {
// No need to parse the items because the user just care about node_fqn
continue;
}
parameters.insert(parameters.end(), node_parameters.begin(), node_parameters.end());
}
return parameters;
}

View File

@@ -29,7 +29,7 @@ ParameterService::ParameterService(
const std::shared_ptr<rclcpp::node_interfaces::NodeBaseInterface> node_base,
const std::shared_ptr<rclcpp::node_interfaces::NodeServicesInterface> node_services,
rclcpp::node_interfaces::NodeParametersInterface * node_params,
const rmw_qos_profile_t & qos_profile)
const rclcpp::QoS & qos_profile)
{
const std::string node_name = node_base->get_name();

View File

@@ -102,11 +102,6 @@ PublisherBase::PublisherBase(
PublisherBase::~PublisherBase()
{
for (const auto & pair : event_handlers_) {
rcl_publisher_event_type_t event_type = pair.first;
clear_on_new_qos_event_callback(event_type);
}
// must fini the events before fini-ing the publisher
event_handlers_.clear();

View File

@@ -35,6 +35,11 @@ UnsupportedEventTypeException::UnsupportedEventTypeException(
QOSEventHandlerBase::~QOSEventHandlerBase()
{
// Since the rmw event listener holds a reference to
// this callback, we need to clear it on destruction of this class.
// This clearing is not needed for other rclcpp entities like pub/subs, since
// they do own the underlying rmw entities, which are destroyed
// on their rclcpp destructors, thus no risk of dangling pointers.
if (on_new_event_callback_) {
clear_on_ready_callback();
}

View File

@@ -32,10 +32,6 @@ ServiceBase::ServiceBase(std::shared_ptr<rcl_node_t> node_handle)
node_logger_(rclcpp::get_node_logger(node_handle_.get()))
{}
ServiceBase::~ServiceBase()
{
clear_on_new_request_callback();
}
bool
ServiceBase::take_type_erased_request(void * request_out, rmw_request_id_t & request_id_out)

View File

@@ -191,7 +191,9 @@ SignalHandler::uninstall()
signal_handlers_options_ = SignalHandlerOptions::None;
RCLCPP_DEBUG(get_logger(), "SignalHandler::uninstall(): notifying deferred signal handler");
notify_signal_handler();
signal_handler_thread_.join();
if (signal_handler_thread_.joinable()) {
signal_handler_thread_.join();
}
teardown_wait_for_signal();
} catch (...) {
installed_.exchange(true);

View File

@@ -87,13 +87,6 @@ SubscriptionBase::SubscriptionBase(
SubscriptionBase::~SubscriptionBase()
{
clear_on_new_message_callback();
for (const auto & pair : event_handlers_) {
rcl_subscription_event_type_t event_type = pair.first;
clear_on_new_qos_event_callback(event_type);
}
if (!use_intra_process_) {
return;
}

View File

@@ -17,11 +17,6 @@
using rclcpp::experimental::SubscriptionIntraProcessBase;
SubscriptionIntraProcessBase::~SubscriptionIntraProcessBase()
{
clear_on_ready_callback();
}
void
SubscriptionIntraProcessBase::add_to_wait_set(rcl_wait_set_t * wait_set)
{

View File

@@ -100,15 +100,20 @@ if(TARGET test_create_subscription)
"test_msgs"
)
endif()
ament_add_gtest(test_add_callback_groups_to_executor
test_add_callback_groups_to_executor.cpp
TIMEOUT 120)
if(TARGET test_add_callback_groups_to_executor)
target_link_libraries(test_add_callback_groups_to_executor ${PROJECT_NAME})
ament_target_dependencies(test_add_callback_groups_to_executor
"test_msgs"
function(test_add_callback_groups_to_executor_for_rmw_implementation)
set(rmw_implementation_env_var RMW_IMPLEMENTATION=${rmw_implementation})
ament_add_gmock(test_add_callback_groups_to_executor${target_suffix} test_add_callback_groups_to_executor.cpp
ENV ${rmw_implementation_env_var}
TIMEOUT 120
)
endif()
if(TARGET test_add_callback_groups_to_executor${target_suffix})
target_link_libraries(test_add_callback_groups_to_executor${target_suffix} ${PROJECT_NAME})
ament_target_dependencies(test_add_callback_groups_to_executor${target_suffix}
"test_msgs"
)
endif()
endfunction()
call_for_each_rmw_implementation(test_add_callback_groups_to_executor_for_rmw_implementation)
ament_add_gtest(test_expand_topic_or_service_name test_expand_topic_or_service_name.cpp)
if(TARGET test_expand_topic_or_service_name)
ament_target_dependencies(test_expand_topic_or_service_name
@@ -299,7 +304,7 @@ if(TARGET test_init_options)
ament_target_dependencies(test_init_options "rcl")
target_link_libraries(test_init_options ${PROJECT_NAME} mimick)
endif()
ament_add_gtest(test_parameter_client test_parameter_client.cpp)
ament_add_gmock(test_parameter_client test_parameter_client.cpp)
if(TARGET test_parameter_client)
ament_target_dependencies(test_parameter_client
"rcl_interfaces"

View File

@@ -51,6 +51,53 @@ TEST(TestAllocatorCommon, retyped_allocate) {
EXPECT_NO_THROW(code2());
}
TEST(TestAllocatorCommon, retyped_zero_allocate_basic) {
std::allocator<int> allocator;
void * untyped_allocator = &allocator;
void * allocated_mem =
rclcpp::allocator::retyped_zero_allocate<std::allocator<char>>(20u, 1u, untyped_allocator);
ASSERT_TRUE(nullptr != allocated_mem);
auto code = [&untyped_allocator, allocated_mem]() {
rclcpp::allocator::retyped_deallocate<char, std::allocator<char>>(
allocated_mem, untyped_allocator);
};
EXPECT_NO_THROW(code());
}
TEST(TestAllocatorCommon, retyped_zero_allocate) {
std::allocator<int> allocator;
void * untyped_allocator = &allocator;
void * allocated_mem =
rclcpp::allocator::retyped_zero_allocate<std::allocator<char>>(20u, 1u, untyped_allocator);
// The more natural check here is ASSERT_NE(nullptr, ptr), but clang static
// analysis throws a false-positive memory leak warning. Use ASSERT_TRUE instead.
ASSERT_TRUE(nullptr != allocated_mem);
auto code = [&untyped_allocator, allocated_mem]() {
rclcpp::allocator::retyped_deallocate<int, std::allocator<int>>(
allocated_mem, untyped_allocator);
};
EXPECT_NO_THROW(code());
allocated_mem = allocator.allocate(1);
// The more natural check here is ASSERT_NE(nullptr, ptr), but clang static
// analysis throws a false-positive memory leak warning. Use ASSERT_TRUE instead.
ASSERT_TRUE(nullptr != allocated_mem);
void * reallocated_mem =
rclcpp::allocator::retyped_reallocate<int, std::allocator<int>>(
allocated_mem, 2u, untyped_allocator);
// The more natural check here is ASSERT_NE(nullptr, ptr), but clang static
// analysis throws a false-positive memory leak warning. Use ASSERT_TRUE instead.
ASSERT_TRUE(nullptr != reallocated_mem);
auto code2 = [&untyped_allocator, reallocated_mem]() {
rclcpp::allocator::retyped_deallocate<int, std::allocator<int>>(
reallocated_mem, untyped_allocator);
};
EXPECT_NO_THROW(code2());
}
TEST(TestAllocatorCommon, get_rcl_allocator) {
std::allocator<int> allocator;
auto rcl_allocator = rclcpp::allocator::get_rcl_allocator<int>(allocator);

View File

@@ -31,6 +31,8 @@
#include "../../mocking_utils/patch.hpp"
#include "../../utils/rclcpp_gtest_macros.hpp"
#include "rcpputils/filesystem_helper.hpp"
class TestNodeParameters : public ::testing::Test
{
public:
@@ -47,6 +49,7 @@ public:
dynamic_cast<rclcpp::node_interfaces::NodeParameters *>(
node->get_node_parameters_interface().get());
ASSERT_NE(nullptr, node_parameters);
test_resources_path /= "test_node_parameters";
}
void TearDown()
@@ -57,6 +60,8 @@ public:
protected:
std::shared_ptr<rclcpp::Node> node;
rclcpp::node_interfaces::NodeParameters * node_parameters;
rcpputils::fs::path test_resources_path{TEST_RESOURCES_DIRECTORY};
};
TEST_F(TestNodeParameters, construct_destruct_rcl_errors) {
@@ -170,7 +175,7 @@ TEST_F(TestNodeParameters, set_parameters) {
EXPECT_TRUE(result[0].successful);
}
TEST_F(TestNodeParameters, add_remove_parameters_callback) {
TEST_F(TestNodeParameters, add_remove_on_set_parameters_callback) {
rcl_interfaces::msg::ParameterDescriptor bool_descriptor;
bool_descriptor.name = "bool_parameter";
bool_descriptor.type = rcl_interfaces::msg::ParameterType::PARAMETER_BOOL;
@@ -197,5 +202,248 @@ TEST_F(TestNodeParameters, add_remove_parameters_callback) {
RCLCPP_EXPECT_THROW_EQ(
node_parameters->remove_on_set_parameters_callback(handle.get()),
std::runtime_error("Callback doesn't exist"));
std::runtime_error("On set parameter callback doesn't exist"));
}
TEST_F(TestNodeParameters, add_remove_pre_set_parameters_callback) {
// `add_pre_set_parameters_callback` used to modify parameters list.
auto modify_parameter_list_callback = [](std::vector<rclcpp::Parameter> & parameters) {
for (const auto & param : parameters) {
if (param.get_name() == "param1") {
parameters.emplace_back("param2", 2.0);
}
}
};
// `add_pre_set_parameters_callback` used to make the parameters list empty.
auto empty_parameter_list_callback = [](std::vector<rclcpp::Parameter> & parameters) {
parameters = {};
};
auto handle1 =
node_parameters->add_pre_set_parameters_callback(modify_parameter_list_callback);
double default_value = 0.0;
node_parameters->declare_parameter(
"param1", rclcpp::ParameterValue(default_value));
node_parameters->declare_parameter(
"param2", rclcpp::ParameterValue(default_value));
// verify that `declare_parameter` does not call any of the callbacks registered with
// `add_pre_set_parameters_callback`
EXPECT_TRUE(node_parameters->has_parameter("param1"));
EXPECT_EQ(node_parameters->get_parameter("param1").get_value<double>(), default_value);
EXPECT_TRUE(node_parameters->has_parameter("param2"));
EXPECT_EQ(node_parameters->get_parameter("param2").get_value<double>(), default_value);
// verify that the `param2` was set successfully conditioned on setting of
// `param1`
const std::vector<rclcpp::Parameter> parameters_to_be_set = {
rclcpp::Parameter("param1", 1.0)};
auto result = node_parameters->set_parameters(parameters_to_be_set);
// we expect the result size to be same as the original "parameters_to_be_set"
// since the pre set parameter callback will set the modified param list atomically.
ASSERT_EQ(1u, result.size());
EXPECT_TRUE(result[0].successful);
EXPECT_TRUE(node_parameters->has_parameter("param1"));
EXPECT_EQ(node_parameters->get_parameter("param1").get_value<double>(), 1.0);
EXPECT_TRUE(node_parameters->has_parameter("param2"));
EXPECT_EQ(node_parameters->get_parameter("param2").get_value<double>(), 2.0);
EXPECT_NO_THROW(node_parameters->remove_pre_set_parameters_callback(handle1.get()));
RCLCPP_EXPECT_THROW_EQ(
node_parameters->remove_pre_set_parameters_callback(handle1.get()),
std::runtime_error("Pre set parameter callback doesn't exist"));
// verify that the result should be unsuccessful if the pre set callback makes
// parameter list empty
auto handle2 =
node_parameters->add_pre_set_parameters_callback(empty_parameter_list_callback);
auto results = node_parameters->set_parameters(parameters_to_be_set);
std::string reason = "parameter list cannot be empty, this might be due to "
"pre_set_parameters_callback modifying the original parameters list.";
EXPECT_FALSE(results[0].successful);
EXPECT_EQ(results[0].reason, reason);
EXPECT_NO_THROW(node_parameters->remove_pre_set_parameters_callback(handle2.get()));
RCLCPP_EXPECT_THROW_EQ(
node_parameters->remove_pre_set_parameters_callback(handle2.get()),
std::runtime_error("Pre set parameter callback doesn't exist"));
}
TEST_F(TestNodeParameters, add_remove_post_set_parameters_callback) {
rcl_interfaces::msg::ParameterDescriptor param1_descriptor;
param1_descriptor.name = "double_parameter1";
param1_descriptor.type = rcl_interfaces::msg::ParameterType::PARAMETER_DOUBLE;
param1_descriptor.read_only = false;
rcl_interfaces::msg::ParameterDescriptor param2_descriptor;
param2_descriptor.name = "double_parameter2";
param2_descriptor.type = rcl_interfaces::msg::ParameterType::PARAMETER_DOUBLE;
param2_descriptor.read_only = false;
double variable_tracking_param1_internally = node_parameters->declare_parameter(
"param1", rclcpp::ParameterValue(0.0), param1_descriptor, false).get<double>();
double variable_tracking_param2_internally = node_parameters->declare_parameter(
"param2", rclcpp::ParameterValue(0.0), param2_descriptor, false).get<double>();
EXPECT_EQ(variable_tracking_param1_internally, 0.0);
EXPECT_EQ(variable_tracking_param2_internally, 0.0);
const std::vector<rclcpp::Parameter> parameters_to_be_set = {
rclcpp::Parameter("param1", 1.0),
rclcpp::Parameter("param2", 2.0)};
// register a callback for successful set parameter and change the internally tracked variables.
auto callback = [&](const std::vector<rclcpp::Parameter> & parameters) {
for (const auto & param : parameters) {
if (param.get_name() == "param1") {
variable_tracking_param1_internally = param.get_value<double>();
} else if (param.get_name() == "param2") {
variable_tracking_param2_internally = param.get_value<double>();
}
}
};
auto handle = node_parameters->add_post_set_parameters_callback(callback);
auto result = node_parameters->set_parameters(parameters_to_be_set);
ASSERT_EQ(2u, result.size());
EXPECT_TRUE(result[0].successful);
EXPECT_TRUE(result[1].successful);
EXPECT_TRUE(node_parameters->has_parameter("param1"));
EXPECT_TRUE(node_parameters->has_parameter("param2"));
EXPECT_EQ(variable_tracking_param1_internally, 1.0);
EXPECT_EQ(variable_tracking_param2_internally, 2.0);
EXPECT_NO_THROW(node_parameters->remove_post_set_parameters_callback(handle.get()));
RCLCPP_EXPECT_THROW_EQ(
node_parameters->remove_post_set_parameters_callback(handle.get()),
std::runtime_error("Post set parameter callback doesn't exist"));
}
TEST_F(TestNodeParameters, wildcard_with_namespace)
{
rclcpp::NodeOptions opts;
opts.arguments(
{
"--ros-args",
"--params-file", (test_resources_path / "wildcards.yaml").string()
});
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node2", "ns", opts);
auto * node_parameters =
dynamic_cast<rclcpp::node_interfaces::NodeParameters *>(
node->get_node_parameters_interface().get());
ASSERT_NE(nullptr, node_parameters);
const auto & parameter_overrides = node_parameters->get_parameter_overrides();
EXPECT_EQ(7u, parameter_overrides.size());
EXPECT_EQ(parameter_overrides.at("full_wild").get<std::string>(), "full_wild");
EXPECT_EQ(parameter_overrides.at("namespace_wild").get<std::string>(), "namespace_wild");
EXPECT_EQ(
parameter_overrides.at("namespace_wild_another").get<std::string>(),
"namespace_wild_another");
EXPECT_EQ(
parameter_overrides.at("namespace_wild_one_star").get<std::string>(),
"namespace_wild_one_star");
EXPECT_EQ(parameter_overrides.at("node_wild_in_ns").get<std::string>(), "node_wild_in_ns");
EXPECT_EQ(
parameter_overrides.at("node_wild_in_ns_another").get<std::string>(),
"node_wild_in_ns_another");
EXPECT_EQ(parameter_overrides.at("explicit_in_ns").get<std::string>(), "explicit_in_ns");
EXPECT_EQ(parameter_overrides.count("should_not_appear"), 0u);
}
TEST_F(TestNodeParameters, wildcard_no_namespace)
{
rclcpp::NodeOptions opts;
opts.arguments(
{
"--ros-args",
"--params-file", (test_resources_path / "wildcards.yaml").string()
});
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node2", opts);
auto * node_parameters =
dynamic_cast<rclcpp::node_interfaces::NodeParameters *>(
node->get_node_parameters_interface().get());
ASSERT_NE(nullptr, node_parameters);
const auto & parameter_overrides = node_parameters->get_parameter_overrides();
EXPECT_EQ(5u, parameter_overrides.size());
EXPECT_EQ(parameter_overrides.at("full_wild").get<std::string>(), "full_wild");
EXPECT_EQ(parameter_overrides.at("namespace_wild").get<std::string>(), "namespace_wild");
EXPECT_EQ(
parameter_overrides.at("namespace_wild_another").get<std::string>(),
"namespace_wild_another");
EXPECT_EQ(parameter_overrides.at("node_wild_no_ns").get<std::string>(), "node_wild_no_ns");
EXPECT_EQ(parameter_overrides.at("explicit_no_ns").get<std::string>(), "explicit_no_ns");
EXPECT_EQ(parameter_overrides.count("should_not_appear"), 0u);
// "/*" match exactly one token, not expect to get `namespace_wild_one_star`
EXPECT_EQ(parameter_overrides.count("namespace_wild_one_star"), 0u);
}
TEST_F(TestNodeParameters, params_by_order)
{
rclcpp::NodeOptions opts;
opts.arguments(
{
"--ros-args",
"--params-file", (test_resources_path / "params_by_order.yaml").string()
});
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node2", "ns", opts);
auto * node_parameters =
dynamic_cast<rclcpp::node_interfaces::NodeParameters *>(
node->get_node_parameters_interface().get());
ASSERT_NE(nullptr, node_parameters);
const auto & parameter_overrides = node_parameters->get_parameter_overrides();
EXPECT_EQ(3u, parameter_overrides.size());
EXPECT_EQ(parameter_overrides.at("a_value").get<std::string>(), "last_one_win");
EXPECT_EQ(parameter_overrides.at("foo").get<std::string>(), "foo");
EXPECT_EQ(parameter_overrides.at("bar").get<std::string>(), "bar");
}
TEST_F(TestNodeParameters, complicated_wildcards)
{
rclcpp::NodeOptions opts;
opts.arguments(
{
"--ros-args",
"--params-file", (test_resources_path / "complicated_wildcards.yaml").string()
});
{
// regex matched: /**/foo/*/bar
std::shared_ptr<rclcpp::Node> node =
std::make_shared<rclcpp::Node>("node2", "/a/b/c/foo/d/bar", opts);
auto * node_parameters =
dynamic_cast<rclcpp::node_interfaces::NodeParameters *>(
node->get_node_parameters_interface().get());
ASSERT_NE(nullptr, node_parameters);
const auto & parameter_overrides = node_parameters->get_parameter_overrides();
EXPECT_EQ(2u, parameter_overrides.size());
EXPECT_EQ(parameter_overrides.at("foo").get<std::string>(), "foo");
EXPECT_EQ(parameter_overrides.at("bar").get<std::string>(), "bar");
}
{
// regex not matched: /**/foo/*/bar
std::shared_ptr<rclcpp::Node> node =
std::make_shared<rclcpp::Node>("node2", "/a/b/c/foo/bar", opts);
auto * node_parameters =
dynamic_cast<rclcpp::node_interfaces::NodeParameters *>(
node->get_node_parameters_interface().get());
ASSERT_NE(nullptr, node_parameters);
const auto & parameter_overrides = node_parameters->get_parameter_overrides();
EXPECT_EQ(0u, parameter_overrides.size());
}
}

View File

@@ -162,7 +162,7 @@ protected:
services_.push_back(
node_with_service->create_service<test_msgs::srv::Empty>(
"service", std::move(service_callback), rmw_qos_profile_services_default, callback_group));
"service", std::move(service_callback), rclcpp::ServicesQoS(), callback_group));
return node_with_service;
}
@@ -177,7 +177,7 @@ protected:
clients_.push_back(
node_with_client->create_client<test_msgs::srv::Empty>(
"service", rmw_qos_profile_services_default, callback_group));
"service", rclcpp::ServicesQoS(), callback_group));
return node_with_client;
}
@@ -793,7 +793,7 @@ TEST_F(TestAllocatorMemoryStrategy, get_next_service_out_of_scope) {
[](const test_msgs::srv::Empty::Request::SharedPtr,
test_msgs::srv::Empty::Response::SharedPtr) {};
auto service = node->create_service<test_msgs::srv::Empty>(
"service", std::move(service_callback), rmw_qos_profile_services_default, callback_group);
"service", std::move(service_callback), rclcpp::ServicesQoS(), callback_group);
node->for_each_callback_group(
[node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
@@ -831,7 +831,7 @@ TEST_F(TestAllocatorMemoryStrategy, get_next_client_out_of_scope) {
node->create_callback_group(
rclcpp::CallbackGroupType::MutuallyExclusive);
auto client = node->create_client<test_msgs::srv::Empty>(
"service", rmw_qos_profile_services_default, callback_group);
"service", rclcpp::ServicesQoS(), callback_group);
weak_groups_to_nodes.insert(
std::pair<rclcpp::CallbackGroup::WeakPtr,

View File

@@ -276,6 +276,70 @@ TYPED_TEST(TestAddCallbackGroupsToExecutor, one_node_many_callback_groups_many_e
ASSERT_EQ(timer_executor.get_all_callback_groups().size(), 2u);
}
/*
* Test callback groups from one node to many executors.
* A subscriber on a new executor with a callback group not received a message
* because the executor can't be triggered while a subscriber created, see
* https://github.com/ros2/rclcpp/issues/1611
*/
TYPED_TEST(TestAddCallbackGroupsToExecutor, subscriber_triggered_to_receive_message)
{
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
// create a thread running an executor with a new callback group for a coming subscriber
rclcpp::CallbackGroup::SharedPtr cb_grp = node->create_callback_group(
rclcpp::CallbackGroupType::MutuallyExclusive, false);
rclcpp::executors::SingleThreadedExecutor cb_grp_executor;
std::promise<bool> received_message_promise;
auto received_message_future = received_message_promise.get_future();
rclcpp::FutureReturnCode return_code = rclcpp::FutureReturnCode::TIMEOUT;
std::thread cb_grp_thread = std::thread(
[&cb_grp, &node, &cb_grp_executor, &received_message_future, &return_code]() {
cb_grp_executor.add_callback_group(cb_grp, node->get_node_base_interface());
return_code = cb_grp_executor.spin_until_future_complete(received_message_future, 10s);
});
// expect the subscriber to receive a message
auto sub_callback = [&received_message_promise](test_msgs::msg::Empty::ConstSharedPtr) {
received_message_promise.set_value(true);
};
rclcpp::Subscription<test_msgs::msg::Empty>::SharedPtr subscription;
rclcpp::Publisher<test_msgs::msg::Empty>::SharedPtr publisher;
// to create a timer with a callback run on another executor
rclcpp::TimerBase::SharedPtr timer = nullptr;
std::promise<void> timer_promise;
auto timer_callback =
[&subscription, &publisher, &timer, &cb_grp, &node, &sub_callback, &timer_promise]() {
if (timer) {
timer.reset();
}
// create a subscription using the `cb_grp` callback group
rclcpp::QoS qos = rclcpp::QoS(1).reliable();
auto options = rclcpp::SubscriptionOptions();
options.callback_group = cb_grp;
subscription =
node->create_subscription<test_msgs::msg::Empty>("topic_name", qos, sub_callback, options);
// create a publisher to send data
publisher =
node->create_publisher<test_msgs::msg::Empty>("topic_name", qos);
publisher->publish(test_msgs::msg::Empty());
timer_promise.set_value();
};
rclcpp::executors::SingleThreadedExecutor timer_executor;
timer = node->create_wall_timer(100ms, timer_callback);
timer_executor.add_node(node);
auto future = timer_promise.get_future();
timer_executor.spin_until_future_complete(future);
cb_grp_thread.join();
ASSERT_EQ(rclcpp::FutureReturnCode::SUCCESS, return_code);
EXPECT_TRUE(received_message_future.get());
}
/*
* Test removing callback group from executor that its not associated with.
*/

View File

@@ -93,6 +93,111 @@ TEST_F(TestAnySubscriptionCallback, construct_destruct) {
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty> asc2(allocator);
}
TEST_F(TestAnySubscriptionCallback, is_serialized_message_callback) {
{
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty> asc;
asc.set([](const rclcpp::SerializedMessage &) {});
EXPECT_TRUE(asc.is_serialized_message_callback());
EXPECT_NO_THROW(
asc.dispatch(
std::make_shared<rclcpp::SerializedMessage>(),
rclcpp::MessageInfo{}));
}
{
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty> asc;
asc.set([](const rclcpp::SerializedMessage &, const rclcpp::MessageInfo &) {});
EXPECT_TRUE(asc.is_serialized_message_callback());
EXPECT_NO_THROW(
asc.dispatch(
std::make_shared<rclcpp::SerializedMessage>(),
rclcpp::MessageInfo{}));
}
{
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty> asc;
asc.set([](const rclcpp::SerializedMessage &, const rclcpp::MessageInfo &) {});
EXPECT_TRUE(asc.is_serialized_message_callback());
EXPECT_NO_THROW(
asc.dispatch(
std::make_shared<rclcpp::SerializedMessage>(),
rclcpp::MessageInfo{}));
}
{
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty> asc;
asc.set([](std::unique_ptr<rclcpp::SerializedMessage>) {});
EXPECT_TRUE(asc.is_serialized_message_callback());
EXPECT_NO_THROW(
asc.dispatch(
std::make_shared<rclcpp::SerializedMessage>(),
rclcpp::MessageInfo{}));
}
{
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty> asc;
asc.set([](std::unique_ptr<rclcpp::SerializedMessage>, const rclcpp::MessageInfo &) {});
EXPECT_TRUE(asc.is_serialized_message_callback());
EXPECT_NO_THROW(
asc.dispatch(
std::make_shared<rclcpp::SerializedMessage>(),
rclcpp::MessageInfo{}));
}
{
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty> asc;
asc.set([](std::shared_ptr<const rclcpp::SerializedMessage>) {});
EXPECT_TRUE(asc.is_serialized_message_callback());
EXPECT_NO_THROW(
asc.dispatch(
std::make_shared<rclcpp::SerializedMessage>(),
rclcpp::MessageInfo{}));
}
{
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty> asc;
asc.set([](std::shared_ptr<const rclcpp::SerializedMessage>, const rclcpp::MessageInfo &) {});
EXPECT_TRUE(asc.is_serialized_message_callback());
EXPECT_NO_THROW(
asc.dispatch(
std::make_shared<rclcpp::SerializedMessage>(),
rclcpp::MessageInfo{}));
}
{
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty> asc;
asc.set([](const std::shared_ptr<const rclcpp::SerializedMessage> &) {});
EXPECT_TRUE(asc.is_serialized_message_callback());
EXPECT_NO_THROW(
asc.dispatch(
std::make_shared<rclcpp::SerializedMessage>(),
rclcpp::MessageInfo{}));
}
{
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty> asc;
asc.set(
[](
const std::shared_ptr<const rclcpp::SerializedMessage> &,
const rclcpp::MessageInfo &) {});
EXPECT_TRUE(asc.is_serialized_message_callback());
EXPECT_NO_THROW(
asc.dispatch(
std::make_shared<rclcpp::SerializedMessage>(),
rclcpp::MessageInfo{}));
}
{
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty> asc;
asc.set([](std::shared_ptr<rclcpp::SerializedMessage>) {});
EXPECT_TRUE(asc.is_serialized_message_callback());
EXPECT_NO_THROW(
asc.dispatch(
std::make_shared<rclcpp::SerializedMessage>(),
rclcpp::MessageInfo{}));
}
{
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty> asc;
asc.set([](std::shared_ptr<rclcpp::SerializedMessage>, const rclcpp::MessageInfo &) {});
EXPECT_TRUE(asc.is_serialized_message_callback());
EXPECT_NO_THROW(
asc.dispatch(
std::make_shared<rclcpp::SerializedMessage>(),
rclcpp::MessageInfo{}));
}
}
TEST_F(TestAnySubscriptionCallback, unset_dispatch_throw) {
EXPECT_THROW(
any_subscription_callback_.dispatch(msg_shared_ptr_, message_info_),

View File

@@ -92,6 +92,30 @@ TEST_F(TestClient, construction_and_destruction) {
{
auto client = node->create_client<ListParameters>("service");
}
{
// suppress deprecated function warning
#if !defined(_WIN32)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#else // !defined(_WIN32)
# pragma warning(push)
# pragma warning(disable: 4996)
#endif
auto client = node->create_client<ListParameters>(
"service", rmw_qos_profile_services_default);
// remove warning suppression
#if !defined(_WIN32)
# pragma GCC diagnostic pop
#else // !defined(_WIN32)
# pragma warning(pop)
#endif
}
{
auto client = node->create_client<ListParameters>(
"service", rclcpp::ServicesQoS());
}
{
ASSERT_THROW(
@@ -123,6 +147,27 @@ TEST_F(TestClient, construction_with_free_function) {
nullptr);
}, rclcpp::exceptions::InvalidServiceNameError);
}
{
auto client = rclcpp::create_client<rcl_interfaces::srv::ListParameters>(
node->get_node_base_interface(),
node->get_node_graph_interface(),
node->get_node_services_interface(),
"service",
rclcpp::ServicesQoS(),
nullptr);
}
{
ASSERT_THROW(
{
auto client = rclcpp::create_client<rcl_interfaces::srv::ListParameters>(
node->get_node_base_interface(),
node->get_node_graph_interface(),
node->get_node_services_interface(),
"invalid_?service",
rclcpp::ServicesQoS(),
nullptr);
}, rclcpp::exceptions::InvalidServiceNameError);
}
}
TEST_F(TestClient, construct_with_rcl_error) {
@@ -351,8 +396,8 @@ TEST_F(TestClient, on_new_response_callback) {
auto client_node = std::make_shared<rclcpp::Node>("client_node", "ns");
auto server_node = std::make_shared<rclcpp::Node>("server_node", "ns");
rmw_qos_profile_t client_qos = rmw_qos_profile_services_default;
client_qos.depth = 3;
rclcpp::ServicesQoS client_qos;
client_qos.keep_last(3);
auto client = client_node->create_client<test_msgs::srv::Empty>("test_service", client_qos);
std::atomic<size_t> server_requests_count {0};
auto server_callback = [&server_requests_count](
@@ -455,32 +500,30 @@ TEST_F(TestClient, rcl_client_response_subscription_get_actual_qos_error) {
}
TEST_F(TestClient, client_qos) {
rmw_qos_profile_t qos_profile = rmw_qos_profile_services_default;
qos_profile.liveliness = RMW_QOS_POLICY_LIVELINESS_AUTOMATIC;
uint64_t duration = 1;
qos_profile.deadline = {duration, duration};
qos_profile.lifespan = {duration, duration};
qos_profile.liveliness_lease_duration = {duration, duration};
rclcpp::ServicesQoS qos_profile;
qos_profile.liveliness(rclcpp::LivelinessPolicy::Automatic);
rclcpp::Duration duration(std::chrono::nanoseconds(1));
qos_profile.deadline(duration);
qos_profile.lifespan(duration);
qos_profile.liveliness_lease_duration(duration);
auto client =
node->create_client<test_msgs::srv::Empty>("client", qos_profile);
auto init_qos =
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile), qos_profile);
auto rp_qos = client->get_request_publisher_actual_qos();
auto rs_qos = client->get_response_subscription_actual_qos();
EXPECT_EQ(init_qos, rp_qos);
EXPECT_EQ(qos_profile, rp_qos);
// Lifespan has no meaning for subscription/readers
rs_qos.lifespan(qos_profile.lifespan);
EXPECT_EQ(init_qos, rs_qos);
rs_qos.lifespan(qos_profile.lifespan());
EXPECT_EQ(qos_profile, rs_qos);
}
TEST_F(TestClient, client_qos_depth) {
using namespace std::literals::chrono_literals;
rmw_qos_profile_t client_qos_profile = rmw_qos_profile_default;
client_qos_profile.depth = 2;
rclcpp::ServicesQoS client_qos_profile;
client_qos_profile.keep_last(2);
auto client = node->create_client<test_msgs::srv::Empty>("test_qos_depth", client_qos_profile);
@@ -491,10 +534,10 @@ TEST_F(TestClient, client_qos_depth) {
auto server_node = std::make_shared<rclcpp::Node>("server_node", "/ns");
rmw_qos_profile_t server_qos_profile = rmw_qos_profile_default;
rclcpp::QoS server_qos(rclcpp::QoSInitialization::from_rmw(rmw_qos_profile_default));
auto server = server_node->create_service<test_msgs::srv::Empty>(
"test_qos_depth", std::move(server_callback), server_qos_profile);
"test_qos_depth", std::move(server_callback), server_qos);
auto request = std::make_shared<test_msgs::srv::Empty::Request>();
::testing::AssertionResult request_result = ::testing::AssertionSuccess();
@@ -522,10 +565,10 @@ TEST_F(TestClient, client_qos_depth) {
std::this_thread::sleep_for(2ms);
}
EXPECT_GT(server_cb_count_, client_qos_profile.depth);
EXPECT_GT(server_cb_count_, client_qos_profile.depth());
start = std::chrono::steady_clock::now();
while ((client_cb_count_ < client_qos_profile.depth) &&
while ((client_cb_count_ < client_qos_profile.depth()) &&
(std::chrono::steady_clock::now() - start) < 1s)
{
rclcpp::spin_some(node);
@@ -535,5 +578,5 @@ TEST_F(TestClient, client_qos_depth) {
// so more client callbacks might be called than expected.
rclcpp::spin_some(node);
EXPECT_EQ(client_cb_count_, client_qos_profile.depth);
EXPECT_EQ(client_cb_count_, client_qos_profile.depth());
}

View File

@@ -62,7 +62,7 @@ TEST(TestCreateTimer, call_with_node_wrapper_compiles)
rclcpp::shutdown();
}
TEST(TestCreateTimer, call_wall_timer_with_bad_arguments)
TEST(TestCreateWallTimer, call_wall_timer_with_bad_arguments)
{
rclcpp::init(0, nullptr);
NodeWrapper node("test_create_wall_timers_with_bad_arguments");
@@ -117,6 +117,66 @@ TEST(TestCreateTimer, call_wall_timer_with_bad_arguments)
rclcpp::shutdown();
}
TEST(TestCreateTimer, call_timer_with_bad_arguments)
{
rclcpp::init(0, nullptr);
NodeWrapper node("test_create_timers_with_bad_arguments");
auto callback = []() {};
rclcpp::CallbackGroup::SharedPtr group = nullptr;
auto node_interface =
rclcpp::node_interfaces::get_node_base_interface(node).get();
auto timers_interface =
rclcpp::node_interfaces::get_node_timers_interface(node).get();
auto clock = node.get_node_clock_interface()->get_clock();
// Negative period
EXPECT_THROW(
rclcpp::create_timer(
clock, -1ms, callback, group, node_interface, timers_interface),
std::invalid_argument);
// Very negative period
constexpr auto nanoseconds_min = std::chrono::nanoseconds::min();
EXPECT_THROW(
rclcpp::create_timer(
clock, nanoseconds_min, callback, group, node_interface, timers_interface),
std::invalid_argument);
// Period must be less than nanoseconds::max()
constexpr auto nanoseconds_max = std::chrono::nanoseconds::min();
EXPECT_THROW(
rclcpp::create_timer(
clock, nanoseconds_max, callback, group, node_interface, timers_interface),
std::invalid_argument);
EXPECT_NO_THROW(
rclcpp::create_timer(
clock, nanoseconds_max - 1us, callback, group, node_interface, timers_interface));
EXPECT_NO_THROW(
rclcpp::create_timer(clock, 0ms, callback, group, node_interface, timers_interface));
// Period must be less than nanoseconds::max()
constexpr auto hours_max = std::chrono::hours::max();
EXPECT_THROW(
rclcpp::create_timer(
clock, hours_max, callback, group, node_interface, timers_interface),
std::invalid_argument);
// node_interface is null
EXPECT_THROW(
rclcpp::create_timer(clock, 1ms, callback, group, nullptr, timers_interface),
std::invalid_argument);
// timers_interface is null
EXPECT_THROW(
rclcpp::create_timer(clock, 1ms, callback, group, node_interface, nullptr),
std::invalid_argument);
rclcpp::shutdown();
}
static void test_timer_callback(void) {}
TEST(TestCreateTimer, timer_function_pointer)

View File

@@ -52,9 +52,23 @@ TEST_F(TestDuration, operators) {
EXPECT_EQ(sub.nanoseconds(), young.nanoseconds() - old.nanoseconds());
EXPECT_EQ(sub, young - old);
rclcpp::Duration addequal = old;
addequal += young;
EXPECT_EQ(addequal.nanoseconds(), old.nanoseconds() + young.nanoseconds());
EXPECT_EQ(addequal, old + young);
rclcpp::Duration subequal = young;
subequal -= old;
EXPECT_EQ(subequal.nanoseconds(), young.nanoseconds() - old.nanoseconds());
EXPECT_EQ(subequal, young - old);
rclcpp::Duration scale = old * 3;
EXPECT_EQ(scale.nanoseconds(), old.nanoseconds() * 3);
rclcpp::Duration scaleequal = old;
scaleequal *= 3;
EXPECT_EQ(scaleequal.nanoseconds(), old.nanoseconds() * 3);
rclcpp::Duration time = rclcpp::Duration(0, 0);
rclcpp::Duration copy_constructor_duration(time);
rclcpp::Duration assignment_op_duration = rclcpp::Duration(1, 0);

View File

@@ -190,7 +190,7 @@ TEST_F(RclcppGenericNodeFixture, publish_loaned_msg_work)
if (publisher->can_loan_messages()) {
auto subscriber_future_ = std::async(
std::launch::deferred, [this, topic_name, type] {
std::launch::async, [this, topic_name, type] {
return subscribe_raw_messages<int64_t, test_msgs::msg::BasicTypes>(
1, topic_name, type);
});

View File

@@ -164,3 +164,21 @@ TEST_F(TestGuardCondition, set_on_trigger_callback) {
EXPECT_EQ(c1.load(), 2u);
}
}
/*
* Testing that callback and waitset are both notified by triggering gc
*/
TEST_F(TestGuardCondition, callback_and_waitset) {
auto gc = std::make_shared<rclcpp::GuardCondition>();
std::atomic<size_t> c1 {0};
auto increase_c1_cb = [&c1](size_t count_msgs) {c1 += count_msgs;};
gc->set_on_trigger_callback(increase_c1_cb);
rclcpp::WaitSet wait_set;
wait_set.add_guard_condition(gc);
gc->trigger();
EXPECT_EQ(rclcpp::WaitResultKind::Ready, wait_set.wait(std::chrono::seconds(1)).kind());
EXPECT_EQ(c1.load(), 1u);
}

View File

@@ -155,7 +155,7 @@ TEST_F(TestMemoryStrategy, get_service_by_handle) {
{
auto service = node->create_service<test_msgs::srv::Empty>(
"service", std::move(service_callback),
rmw_qos_profile_services_default, callback_group);
rclcpp::ServicesQoS(), callback_group);
service_handle = service->get_service_handle();
@@ -197,7 +197,7 @@ TEST_F(TestMemoryStrategy, get_client_by_handle) {
node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
{
auto client = node->create_client<test_msgs::srv::Empty>(
"service", rmw_qos_profile_services_default, callback_group);
"service", rclcpp::ServicesQoS(), callback_group);
client_handle = client->get_client_handle();
weak_groups_to_nodes.insert(
@@ -396,7 +396,7 @@ TEST_F(TestMemoryStrategy, get_group_by_service) {
service = node->create_service<test_msgs::srv::Empty>(
"service", std::move(service_callback),
rmw_qos_profile_services_default, callback_group);
rclcpp::ServicesQoS(), callback_group);
weak_groups_to_nodes.insert(
std::pair<rclcpp::CallbackGroup::WeakPtr,
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
@@ -435,7 +435,7 @@ TEST_F(TestMemoryStrategy, get_group_by_client) {
node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
client = node->create_client<test_msgs::srv::Empty>(
"service", rmw_qos_profile_services_default, callback_group);
"service", rclcpp::ServicesQoS(), callback_group);
weak_groups_to_nodes.insert(
std::pair<rclcpp::CallbackGroup::WeakPtr,
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(

View File

@@ -1444,6 +1444,36 @@ TEST_F(TestNode, set_parameter_undeclared_parameters_not_allowed) {
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_STRING);
EXPECT_EQ(value.get_value<std::string>(), "asd");
}
{
// adding a parameter in "pre set parameter" callback, when that
// parameter has not been declared before will throw
auto name1 = "parameter"_unq;
auto name2 = "parameter"_unq;
auto default_value = 0; // default value of name1 param
// declare name1 parameter only
node->declare_parameter(name1, default_value);
// add undeclared parameter with name2 to modified list of parameters
auto pre_set_parameters =
[&](std::vector<rclcpp::Parameter> & parameters) {
for (const auto & param : parameters) {
if (param.get_name() == name1) {
parameters.emplace_back(rclcpp::Parameter(name2, 2));
}
}
};
auto handler = node->add_pre_set_parameters_callback(pre_set_parameters);
EXPECT_THROW(
node->set_parameter(rclcpp::Parameter(name1, 4)),
rclcpp::exceptions::ParameterNotDeclaredException);
EXPECT_TRUE(node->has_parameter(name1));
EXPECT_EQ(node->get_parameter(name1).get_value<int>(), default_value);
EXPECT_FALSE(node->has_parameter(name2));
RCPPUTILS_SCOPE_EXIT(
{node->remove_pre_set_parameters_callback(handler.get());}); // always reset
}
}
TEST_F(TestNode, set_parameter_undeclared_parameters_allowed) {
@@ -1481,6 +1511,36 @@ TEST_F(TestNode, set_parameter_undeclared_parameters_allowed) {
EXPECT_TRUE(node->has_parameter(name));
EXPECT_EQ(node->get_parameter(name).get_value<int>(), 43);
}
{
// adding a parameter in "pre set parameter" callback, when that
// parameter has not been declared will not throw if undeclared
// parameters are allowed
auto name1 = "parameter"_unq;
auto name2 = "parameter"_unq;
// declare name1 parameter only
node->declare_parameter(name1, 0);
// add undeclared parameter with name2 to modified list of parameters
auto pre_set_parameters =
[&](std::vector<rclcpp::Parameter> & parameters) {
for (const auto & param : parameters) {
if (param.get_name() == name1) {
parameters.emplace_back(rclcpp::Parameter(name2, 2));
}
}
};
auto handler = node->add_pre_set_parameters_callback(pre_set_parameters);
auto result = node->set_parameter(rclcpp::Parameter(name1, 1));
EXPECT_TRUE(result.successful);
EXPECT_TRUE(node->has_parameter(name1));
EXPECT_TRUE(node->has_parameter(name2));
EXPECT_EQ(node->get_parameter(name1).get_value<int>(), 1);
EXPECT_EQ(node->get_parameter(name2).get_value<int>(), 2);
RCPPUTILS_SCOPE_EXIT(
{node->remove_pre_set_parameters_callback(handler.get());}); // always reset
}
}
TEST_F(TestNode, set_parameters_undeclared_parameters_not_allowed) {
@@ -1625,6 +1685,51 @@ TEST_F(TestNode, set_parameters_undeclared_parameters_not_allowed) {
EXPECT_FALSE(node->has_parameter(name));
}
{
// adding a parameter in "pre set parameter" callback when that
// parameter has not been declared before will throw. However, when
// multiple params are being set using "set_parameters", the params
// which are not conditioned on each other in "pre set callback" will
// still be set successfully. This is the desired behaviour since
// "set_parameters" sets params non atomically.
auto name1 = "parameter"_unq;
auto name2 = "parameter"_unq;
auto name3 = "parameter"_unq;
auto default_value = 0;
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.type = rclcpp::PARAMETER_INTEGER;
// declare name1 and name2 parameter only
node->declare_parameter(name1, default_value, descriptor);
node->declare_parameter(name2, default_value, descriptor);
// add undeclared parameter with name3 to modified list of parameters
// conditioned of name2 param
auto pre_set_parameters =
[&](std::vector<rclcpp::Parameter> & parameters) {
for (const auto & param : parameters) {
if (param.get_name() == name2) {
parameters.emplace_back(rclcpp::Parameter(name3, 3));
}
}
};
auto handler = node->add_pre_set_parameters_callback(pre_set_parameters);
EXPECT_THROW(
node->set_parameters({rclcpp::Parameter(name1, 1), rclcpp::Parameter(name2, 2)}),
rclcpp::exceptions::ParameterNotDeclaredException);
EXPECT_TRUE(node->has_parameter(name1));
EXPECT_TRUE(node->has_parameter(name2));
EXPECT_FALSE(node->has_parameter(name3));
// we still expect the value of name1 param to be set successfully, since
// the setting of name2 param is only conditioned on setting of name3 param
EXPECT_EQ(node->get_parameter(name1).get_value<int>(), 1);
EXPECT_EQ(node->get_parameter(name2).get_value<int>(), default_value);
RCPPUTILS_SCOPE_EXIT(
{node->remove_pre_set_parameters_callback(handler.get());}); // always reset
}
}
// test set_parameters with undeclared allowed
@@ -1673,6 +1778,48 @@ TEST_F(TestNode, set_parameters_undeclared_parameters_allowed) {
EXPECT_EQ(node->get_parameter(name1).get_value<int>(), 42);
EXPECT_EQ(node->get_parameter(name2).get_value<std::string>(), "test");
}
{
// adding a parameter in "pre set parameter" callback when that
// parameter has not been declared before will not throw when
// undeclared parameters are allowed.
auto name1 = "parameter"_unq;
auto name2 = "parameter"_unq;
auto name3 = "parameter"_unq;
auto default_value = 0;
rcl_interfaces::msg::ParameterDescriptor descriptor;
descriptor.type = rclcpp::PARAMETER_INTEGER;
// declare name1 and name2 parameter only
node->declare_parameter(name1, default_value, descriptor);
node->declare_parameter(name2, default_value, descriptor);
// add undeclared parameter with name3 to modified list of parameters
// conditioned of name2 param
auto pre_set_parameters =
[&](std::vector<rclcpp::Parameter> & parameters) {
for (const auto & param : parameters) {
if (param.get_name() == name2) {
parameters.emplace_back(rclcpp::Parameter(name3, 3));
}
}
};
auto handler = node->add_pre_set_parameters_callback(pre_set_parameters);
auto results = node->set_parameters({rclcpp::Parameter(name1, 1), rclcpp::Parameter(name2, 2)});
EXPECT_EQ(2u, results.size());
EXPECT_TRUE(results[0].successful);
EXPECT_TRUE(results[1].successful);
EXPECT_TRUE(node->has_parameter(name1));
EXPECT_TRUE(node->has_parameter(name2));
EXPECT_TRUE(node->has_parameter(name3));
EXPECT_EQ(node->get_parameter(name1).get_value<int>(), 1);
EXPECT_EQ(node->get_parameter(name2).get_value<int>(), 2);
EXPECT_EQ(node->get_parameter(name3).get_value<int>(), 3);
RCPPUTILS_SCOPE_EXIT(
{node->remove_pre_set_parameters_callback(handler.get());}); // always reset
}
}
TEST_F(TestNode, set_parameters_atomically_undeclared_parameters_not_allowed) {
@@ -1815,6 +1962,48 @@ TEST_F(TestNode, set_parameters_atomically_undeclared_parameters_not_allowed) {
EXPECT_FALSE(node->has_parameter(name));
}
{
// adding a parameter in "pre set parameter" callback when that
// parameter has not been declared before will throw and since
// multiple params are being set using "set_parameters_atomically",
// a failure in set of one param will result in all params being
// set unsuccessfully.
auto name1 = "parameter"_unq;
auto name2 = "parameter"_unq;
auto name3 = "parameter"_unq;
auto default_value = 0;
// declare name1 and name2 parameter only
node->declare_parameter(name1, default_value);
node->declare_parameter(name2, default_value);
// add undeclared parameter with name3 to modified list of parameters
// conditioned of name2 param
auto pre_set_parameters =
[&](std::vector<rclcpp::Parameter> & parameters) {
for (const auto & param : parameters) {
if (param.get_name() == name2) {
parameters.emplace_back(rclcpp::Parameter(name3, 3));
}
}
};
auto handler = node->add_pre_set_parameters_callback(pre_set_parameters);
EXPECT_THROW(
node->set_parameters_atomically(
{rclcpp::Parameter(name1, 1),
rclcpp::Parameter(name2, 2)}),
rclcpp::exceptions::ParameterNotDeclaredException);
EXPECT_TRUE(node->has_parameter(name1));
EXPECT_TRUE(node->has_parameter(name2));
EXPECT_FALSE(node->has_parameter(name3));
// the values of all the params is still default.
EXPECT_EQ(node->get_parameter(name1).get_value<int>(), default_value);
EXPECT_EQ(node->get_parameter(name2).get_value<int>(), default_value);
RCPPUTILS_SCOPE_EXIT(
{node->remove_pre_set_parameters_callback(handler.get());}); // always reset
}
}
// test set_parameters with undeclared allowed
@@ -1903,6 +2092,45 @@ TEST_F(TestNode, set_parameters_atomically_undeclared_parameters_allowed) {
EXPECT_FALSE(node->has_parameter(name2)); // important! name2 remains undeclared
EXPECT_EQ(node->get_parameter(name3).get_value<std::string>(), "test");
}
{
// adding a parameter in "pre set parameter" callback when that
// parameter has not been declared before will not throw when
// undeclared parameters are allowed.
auto name1 = "parameter"_unq;
auto name2 = "parameter"_unq;
auto name3 = "parameter"_unq;
auto default_value = 0;
// declare name1 and name2 parameter only
node->declare_parameter(name1, default_value);
node->declare_parameter(name2, default_value);
// add undeclared parameter with name3 to modified list of parameters
// conditioned of name2 param
auto pre_set_parameters =
[&](std::vector<rclcpp::Parameter> & parameters) {
for (const auto & param : parameters) {
if (param.get_name() == name2) {
parameters.emplace_back(rclcpp::Parameter(name3, 3));
}
}
};
auto handler = node->add_pre_set_parameters_callback(pre_set_parameters);
auto result = node->set_parameters_atomically(
{rclcpp::Parameter(name1, 1),
rclcpp::Parameter(name2, 2)});
EXPECT_TRUE(result.successful);
EXPECT_TRUE(node->has_parameter(name1));
EXPECT_TRUE(node->has_parameter(name2));
EXPECT_TRUE(node->has_parameter(name3));
EXPECT_EQ(node->get_parameter(name1).get_value<int>(), 1);
EXPECT_EQ(node->get_parameter(name2).get_value<int>(), 2);
EXPECT_EQ(node->get_parameter(name3).get_value<int>(), 3);
RCPPUTILS_SCOPE_EXIT(
{node->remove_pre_set_parameters_callback(handler.get());}); // always reset
}
}
// test get_parameter with undeclared not allowed

View File

@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <chrono>
#include <functional>
@@ -948,3 +948,138 @@ TEST_F(TestParameterClient, sync_parameter_load_parameters) {
auto list_parameters = synchronous_client->list_parameters({}, 3);
ASSERT_EQ(list_parameters.names.size(), static_cast<uint64_t>(5));
}
/*
Coverage for async load_parameters with complicated regex expression
*/
TEST_F(TestParameterClient, async_parameter_load_parameters_complicated_regex) {
auto load_node = std::make_shared<rclcpp::Node>(
"load_node",
"namespace",
rclcpp::NodeOptions().allow_undeclared_parameters(true));
auto asynchronous_client =
std::make_shared<rclcpp::AsyncParametersClient>(load_node, "/namespace/load_node");
// load parameters
rcpputils::fs::path test_resources_path{TEST_RESOURCES_DIRECTORY};
const std::string parameters_filepath = (
test_resources_path / "test_node" / "load_complicated_parameters.yaml").string();
auto load_future = asynchronous_client->load_parameters(parameters_filepath);
auto result_code = rclcpp::spin_until_future_complete(
load_node, load_future, std::chrono::milliseconds(100));
ASSERT_EQ(result_code, rclcpp::FutureReturnCode::SUCCESS);
ASSERT_EQ(load_future.get()[0].successful, true);
// list parameters
auto list_parameters = asynchronous_client->list_parameters({}, 3);
rclcpp::spin_until_future_complete(
load_node, list_parameters, std::chrono::milliseconds(100));
ASSERT_EQ(list_parameters.get().names.size(), static_cast<uint64_t>(6));
// to check the parameter "a_value"
std::string param_name = "a_value";
auto param = load_node->get_parameter(param_name);
ASSERT_EQ(param.get_value<std::string>(), "last_one_win");
}
/*
Coverage for async load_parameters to load file without valid parameters
*/
TEST_F(TestParameterClient, async_parameter_load_no_valid_parameter) {
auto load_node = std::make_shared<rclcpp::Node>(
"load_node",
"namespace",
rclcpp::NodeOptions().allow_undeclared_parameters(true));
auto asynchronous_client =
std::make_shared<rclcpp::AsyncParametersClient>(load_node, "/namespace/load_node");
// load parameters
rcpputils::fs::path test_resources_path{TEST_RESOURCES_DIRECTORY};
const std::string parameters_filepath = (
test_resources_path / "test_node" / "no_valid_parameters.yaml").string();
EXPECT_THROW(
asynchronous_client->load_parameters(parameters_filepath),
rclcpp::exceptions::InvalidParametersException);
}
/*
Coverage for async load_parameters from maps with complicated regex expression
*/
TEST_F(TestParameterClient, async_parameter_load_parameters_from_map) {
auto load_node = std::make_shared<rclcpp::Node>(
"load_node",
"namespace",
rclcpp::NodeOptions().allow_undeclared_parameters(true));
auto asynchronous_client =
std::make_shared<rclcpp::AsyncParametersClient>(load_node, "/namespace/load_node");
// load parameters
rclcpp::ParameterMap parameter_map = {
{"/**",
{
{"bar", 5},
{"foo", 3.5},
{"a_value", "first"}
}
},
{"/*/load_node",
{
{"bar_foo", "ok"},
{"a_value", "second"}
}
},
{"/namespace/load_node",
{
{"foo_bar", true},
{"a_value", "third"}
}
},
{"/bar",
{
{"fatal", 10}
}
},
{"/**/namespace/*",
{
{"a_value", "not_win"}
}
}
};
auto load_future = asynchronous_client->load_parameters(parameter_map);
auto result_code = rclcpp::spin_until_future_complete(
load_node, load_future, std::chrono::milliseconds(100));
ASSERT_EQ(result_code, rclcpp::FutureReturnCode::SUCCESS);
ASSERT_EQ(load_future.get()[0].successful, true);
// list parameters
auto list_parameters = asynchronous_client->list_parameters({}, 3);
rclcpp::spin_until_future_complete(
load_node, list_parameters, std::chrono::milliseconds(100));
ASSERT_EQ(list_parameters.get().names.size(), static_cast<uint64_t>(6));
// to check the parameter "a_value"
std::string param_name = "a_value";
auto param = load_node->get_parameter(param_name);
// rclcpp::ParameterMap is an unordered map, no guarantee which value will be set for `a_value`.
EXPECT_THAT(
(std::array{"first", "second", "third", "not_win"}),
testing::Contains(param.get_value<std::string>()));
}
/*
Coverage for async load_parameters from maps without valid parameters
*/
TEST_F(TestParameterClient, async_parameter_load_from_map_no_valid_parameter) {
auto load_node = std::make_shared<rclcpp::Node>(
"load_node",
"namespace",
rclcpp::NodeOptions().allow_undeclared_parameters(true));
auto asynchronous_client =
std::make_shared<rclcpp::AsyncParametersClient>(load_node, "/namespace/load_node");
// load parameters
rclcpp::ParameterMap parameter_map = {
{"/no/valid/parameters/node",
{
{"bar", 5},
{"bar", 3.5}
}
}
};
EXPECT_THROW(
asynchronous_client->load_parameters(parameter_map),
rclcpp::exceptions::InvalidParametersException);
}

View File

@@ -19,6 +19,7 @@
#include <cstdio>
#include <string>
#include <unordered_map>
#include <vector>
#include "rclcpp/parameter_map.hpp"
@@ -353,3 +354,132 @@ TEST(Test_parameter_map_from, string_array_param_value)
c_params->params[0].parameter_values[0].string_array_value = NULL;
rcl_yaml_node_struct_fini(c_params);
}
TEST(Test_parameter_map_from, one_node_one_param_by_node_fqn)
{
rcl_params_t * c_params = make_params({"foo"});
make_node_params(c_params, 0, {"string_param"});
std::string hello_world = "hello world";
char * c_hello_world = new char[hello_world.length() + 1];
std::snprintf(c_hello_world, hello_world.size() + 1, "%s", hello_world.c_str());
c_params->params[0].parameter_values[0].string_value = c_hello_world;
rclcpp::ParameterMap map = rclcpp::parameter_map_from(c_params, "/foo");
const std::vector<rclcpp::Parameter> & params = map.at("/foo");
EXPECT_STREQ("string_param", params.at(0).get_name().c_str());
EXPECT_STREQ(hello_world.c_str(), params.at(0).get_value<std::string>().c_str());
c_params->params[0].parameter_values[0].string_value = NULL;
delete[] c_hello_world;
rcl_yaml_node_struct_fini(c_params);
}
TEST(Test_parameter_map_from, multi_nodes_same_param_name_by_node_fqn)
{
std::vector<std::string> node_names_keys = {
"/**", // index: 0
"/*", // index: 1
"/**/node", // index: 2
"/*/node", // index: 3
"/ns/node" // index: 4
};
rcl_params_t * c_params = make_params(node_names_keys);
std::vector<char *> param_values;
for (size_t i = 0; i < node_names_keys.size(); ++i) {
make_node_params(c_params, i, {"string_param"});
std::string hello_world = "hello world" + std::to_string(i);
char * c_hello_world = new char[hello_world.length() + 1];
std::snprintf(c_hello_world, hello_world.size() + 1, "%s", hello_world.c_str());
c_params->params[i].parameter_values[0].string_value = c_hello_world;
param_values.push_back(c_hello_world);
}
std::unordered_map<std::string, std::vector<size_t>> node_fqn_expected = {
{"/ns/foo/another_node", {0}},
{"/another", {0, 1}},
{"/node", {0, 1, 2}},
{"/another_ns/node", {0, 2, 3}},
{"/ns/node", {0, 2, 3, 4}},
};
for (auto & kv : node_fqn_expected) {
rclcpp::ParameterMap map = rclcpp::parameter_map_from(c_params, kv.first.c_str());
const std::vector<rclcpp::Parameter> & params = map.at(kv.first);
EXPECT_EQ(kv.second.size(), params.size());
for (size_t i = 0; i < params.size(); ++i) {
std::string param_value = "hello world" + std::to_string(kv.second[i]);
EXPECT_STREQ("string_param", params.at(i).get_name().c_str());
EXPECT_STREQ(param_value.c_str(), params.at(i).get_value<std::string>().c_str());
}
}
for (size_t i = 0; i < node_names_keys.size(); ++i) {
c_params->params[i].parameter_values[0].string_value = NULL;
}
for (auto c_hello_world : param_values) {
delete[] c_hello_world;
}
rcl_yaml_node_struct_fini(c_params);
}
TEST(Test_parameter_map_from, multi_nodes_diff_param_name_by_node_fqn)
{
std::vector<std::string> node_names_keys = {
"/**", // index: 0
"/*", // index: 1
"/**/node", // index: 2
"/*/node", // index: 3
"/ns/**", // index: 4
"/ns/*", // index: 5
"/ns/**/node", // index: 6
"/ns/*/node", // index: 7
"/ns/**/a/*/node", // index: 8
"/ns/node" // index: 9
};
rcl_params_t * c_params = make_params(node_names_keys);
for (size_t i = 0; i < node_names_keys.size(); ++i) {
std::string param_name = "string_param" + std::to_string(i);
make_node_params(c_params, i, {param_name});
}
std::string hello_world = "hello world";
char * c_hello_world = new char[hello_world.length() + 1];
std::snprintf(c_hello_world, hello_world.size() + 1, "%s", hello_world.c_str());
for (size_t i = 0; i < node_names_keys.size(); ++i) {
c_params->params[i].parameter_values[0].string_value = c_hello_world;
}
std::unordered_map<std::string, std::vector<size_t>> node_fqn_expected = {
{"/ns/node", {0, 2, 3, 4, 5, 6, 9}},
{"/node", {0, 1, 2}},
{"/ns/foo/node", {0, 2, 4, 6, 7}},
{"/ns/foo/a/node", {0, 2, 4, 6}},
{"/ns/foo/a/bar/node", {0, 2, 4, 6, 8}},
{"/ns/a/bar/node", {0, 2, 4, 6, 8}},
{"/ns/foo/zoo/a/bar/node", {0, 2, 4, 6, 8}},
};
for (auto & kv : node_fqn_expected) {
rclcpp::ParameterMap map = rclcpp::parameter_map_from(c_params, kv.first.c_str());
const std::vector<rclcpp::Parameter> & params = map.at(kv.first);
EXPECT_EQ(kv.second.size(), params.size());
for (size_t i = 0; i < params.size(); ++i) {
std::string param_name = "string_param" + std::to_string(kv.second[i]);
EXPECT_STREQ(param_name.c_str(), params.at(i).get_name().c_str());
EXPECT_STREQ(hello_world.c_str(), params.at(i).get_value<std::string>().c_str());
}
}
for (size_t i = 0; i < node_names_keys.size(); ++i) {
c_params->params[i].parameter_values[0].string_value = NULL;
}
delete[] c_hello_world;
rcl_yaml_node_struct_fini(c_params);
}

View File

@@ -25,6 +25,8 @@
#include "rclcpp/exceptions.hpp"
#include "rclcpp/rclcpp.hpp"
#include "rcutils/env.h"
#include "../mocking_utils/patch.hpp"
#include "../utils/rclcpp_gtest_macros.hpp"
@@ -413,10 +415,18 @@ TEST_F(TestPublisher, intra_process_publish_failures) {
{
rclcpp::LoanedMessage<test_msgs::msg::Empty> loaned_msg(*publisher, allocator);
loaned_msg.release();
auto msg = loaned_msg.release(); // this will unmanage the ownership of the message
RCLCPP_EXPECT_THROW_EQ(
publisher->publish(std::move(loaned_msg)),
std::runtime_error("loaned message is not valid"));
// if the message is actually loaned from the middleware but not be published,
// it is user responsibility to return the message to the middleware manually
if (publisher->can_loan_messages()) {
ASSERT_EQ(
RCL_RET_OK,
rcl_return_loaned_message_from_publisher(
publisher->get_publisher_handle().get(), msg.get()));
}
}
RCLCPP_EXPECT_THROW_EQ(
node->create_publisher<test_msgs::msg::Empty>(
@@ -485,6 +495,11 @@ public:
TEST_F(TestPublisher, do_loaned_message_publish_error) {
initialize();
using PublisherT = TestPublisherProtectedMethods<test_msgs::msg::Empty, std::allocator<void>>;
// This test only passes when message is allocated on heap, not middleware.
// Since `do_loaned_message_publish()` will fail, there is no way to return the message
// to the middleware.
// This eventually fails to destroy publisher handle in the implementation.
ASSERT_TRUE(rcutils_set_env("ROS_DISABLE_LOANED_MESSAGES", "1"));
auto publisher =
node->create_publisher<test_msgs::msg::Empty, std::allocator<void>, PublisherT>("topic", 10);

View File

@@ -246,8 +246,8 @@ TEST_F(TestService, on_new_request_callback) {
auto server_callback =
[](const test_msgs::srv::Empty::Request::SharedPtr,
test_msgs::srv::Empty::Response::SharedPtr) {FAIL();};
rmw_qos_profile_t service_qos = rmw_qos_profile_services_default;
service_qos.depth = 3;
rclcpp::ServicesQoS service_qos;
service_qos.keep_last(3);
auto server = node->create_service<test_msgs::srv::Empty>(
"~/test_service", server_callback, service_qos);
@@ -338,28 +338,25 @@ TEST_F(TestService, rcl_service_request_subscription_get_actual_qos_error) {
TEST_F(TestService, server_qos) {
rmw_qos_profile_t qos_profile = rmw_qos_profile_services_default;
qos_profile.liveliness = RMW_QOS_POLICY_LIVELINESS_AUTOMATIC;
uint64_t duration = 1;
qos_profile.deadline = {duration, duration};
qos_profile.lifespan = {duration, duration};
qos_profile.liveliness_lease_duration = {duration, duration};
rclcpp::ServicesQoS qos_profile;
qos_profile.liveliness(rclcpp::LivelinessPolicy::Automatic);
rclcpp::Duration duration(std::chrono::nanoseconds(1));
qos_profile.deadline(duration);
qos_profile.lifespan(duration);
qos_profile.liveliness_lease_duration(duration);
auto callback = [](const test_msgs::srv::Empty::Request::SharedPtr,
test_msgs::srv::Empty::Response::SharedPtr) {};
auto server = node->create_service<test_msgs::srv::Empty>(
"service", callback,
qos_profile);
auto init_qos =
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(qos_profile), qos_profile);
"service", callback, qos_profile);
auto rs_qos = server->get_request_subscription_actual_qos();
auto rp_qos = server->get_response_publisher_actual_qos();
EXPECT_EQ(init_qos, rp_qos);
EXPECT_EQ(qos_profile, rp_qos);
// Lifespan has no meaning for subscription/readers
rs_qos.lifespan(qos_profile.lifespan);
EXPECT_EQ(init_qos, rs_qos);
rs_qos.lifespan(qos_profile.lifespan());
EXPECT_EQ(qos_profile, rs_qos);
}
TEST_F(TestService, server_qos_depth) {
@@ -372,13 +369,12 @@ TEST_F(TestService, server_qos_depth) {
auto server_node = std::make_shared<rclcpp::Node>("server_node", "/ns");
rmw_qos_profile_t server_qos_profile = rmw_qos_profile_default;
server_qos_profile.depth = 2;
rclcpp::QoS server_qos_profile(2);
auto server = server_node->create_service<test_msgs::srv::Empty>(
"test_qos_depth", std::move(server_callback), server_qos_profile);
rmw_qos_profile_t client_qos_profile = rmw_qos_profile_default;
rclcpp::QoS client_qos_profile(rclcpp::QoSInitialization::from_rmw(rmw_qos_profile_default));
auto client = node->create_client<test_msgs::srv::Empty>("test_qos_depth", client_qos_profile);
::testing::AssertionResult request_result = ::testing::AssertionSuccess();
@@ -398,7 +394,7 @@ TEST_F(TestService, server_qos_depth) {
}
auto start = std::chrono::steady_clock::now();
while ((server_cb_count_ < server_qos_profile.depth) &&
while ((server_cb_count_ < server_qos_profile.depth()) &&
(std::chrono::steady_clock::now() - start) < 1s)
{
rclcpp::spin_some(server_node);
@@ -409,5 +405,5 @@ TEST_F(TestService, server_qos_depth) {
// so more server responses might be processed than expected.
rclcpp::spin_some(server_node);
EXPECT_EQ(server_cb_count_, server_qos_profile.depth);
EXPECT_EQ(server_cb_count_, server_qos_profile.depth());
}

View File

@@ -81,7 +81,7 @@ void spin_until_time(
executor.spin_once(10ms);
if (clock->now().nanoseconds() == end_time.count()) {
if (clock->now().nanoseconds() >= end_time.count()) {
return;
}
}
@@ -108,7 +108,7 @@ void spin_until_ros_time_updated(
executor.add_node(node);
auto start = std::chrono::system_clock::now();
while (std::chrono::system_clock::now() < (start + 1s)) {
while (std::chrono::system_clock::now() < (start + 2s)) {
if (!rclcpp::ok()) {
break; // Break for ctrl-c
}
@@ -630,7 +630,8 @@ class SimClockPublisherNode : public rclcpp::Node
{
public:
SimClockPublisherNode()
: rclcpp::Node("sim_clock_publisher_node")
: rclcpp::Node("sim_clock_publisher_node"),
pub_time_(0, 0)
{
// Create a clock publisher
clock_pub_ = this->create_publisher<rosgraph_msgs::msg::Clock>(
@@ -645,10 +646,6 @@ public:
&SimClockPublisherNode::timer_callback,
this)
);
// Init clock msg to zero
clock_msg_.clock.sec = 0;
clock_msg_.clock.nanosec = 0;
}
~SimClockPublisherNode()
@@ -671,13 +668,15 @@ public:
private:
void timer_callback()
{
// Increment clock msg and publish it
clock_msg_.clock.nanosec += 1000000;
// Increment the time, update the clock msg and publish it
pub_time_ += rclcpp::Duration(0, 1000000);
clock_msg_.clock = pub_time_;
clock_pub_->publish(clock_msg_);
}
rclcpp::Publisher<rosgraph_msgs::msg::Clock>::SharedPtr clock_pub_;
rclcpp::TimerBase::SharedPtr pub_timer_;
rclcpp::Time pub_time_;
rosgraph_msgs::msg::Clock clock_msg_;
std::thread node_thread_;
rclcpp::executors::SingleThreadedExecutor node_executor;
@@ -695,7 +694,7 @@ public:
this->set_parameter(rclcpp::Parameter("use_sim_time", true));
// Create a 100ms timer
timer_ = this->create_wall_timer(
timer_ = this->create_timer(
std::chrono::milliseconds(100),
std::bind(
&ClockThreadTestingNode::timer_callback,
@@ -735,29 +734,33 @@ private:
bool is_callback_frozen_ = true;
};
TEST_F(TestTimeSource, check_sim_time_updated_in_callback_if_use_clock_thread) {
// Test if clock time of a node with
// parameter use_sim_time = true and option use_clock_thread = true
// is updated while node is not spinning
// (in a timer callback)
// TODO(ivanpauno): This test was using a wall timer, when it was supposed to use sim time.
// It was also using `use_clock_tread = false`, when it was supposed to be `true`.
// Fixing the test to work as originally intended makes it super flaky.
// Disabling it until the test is fixed.
// TEST_F(TestTimeSource, check_sim_time_updated_in_callback_if_use_clock_thread) {
// // Test if clock time of a node with
// // parameter use_sim_time = true and option use_clock_thread = true
// // is updated while node is not spinning
// // (in a timer callback)
// Create a "sim time" publisher and spin it
SimClockPublisherNode pub_node;
pub_node.SpinNode();
// // Create a "sim time" publisher and spin it
// SimClockPublisherNode pub_node;
// pub_node.SpinNode();
// Spin node for 2 seconds
ClockThreadTestingNode clock_thread_testing_node;
auto steady_clock = rclcpp::Clock(RCL_STEADY_TIME);
auto start_time = steady_clock.now();
while (rclcpp::ok() &&
(steady_clock.now() - start_time).seconds() < 2.0)
{
rclcpp::spin_some(clock_thread_testing_node.get_node_base_interface());
}
// // Spin node for 2 seconds
// ClockThreadTestingNode clock_thread_testing_node;
// auto steady_clock = rclcpp::Clock(RCL_STEADY_TIME);
// auto start_time = steady_clock.now();
// while (rclcpp::ok() &&
// (steady_clock.now() - start_time).seconds() < 2.0)
// {
// rclcpp::spin_some(clock_thread_testing_node.get_node_base_interface());
// }
// Node should have get out of timer callback
ASSERT_FALSE(clock_thread_testing_node.GetIsCallbackFrozen());
}
// // Node should have get out of timer callback
// ASSERT_FALSE(clock_thread_testing_node.GetIsCallbackFrozen());
// }
TEST_F(TestTimeSource, clock_sleep_until_with_ros_time_basic) {
SimClockPublisherNode pub_node;

View File

@@ -30,8 +30,15 @@
using namespace std::chrono_literals;
/// We want to test everything for both the wall and generic timer.
enum class TimerType
{
WALL_TIMER,
GENERIC_TIMER,
};
/// Timer testing bring up and teardown
class TestTimer : public ::testing::Test
class TestTimer : public ::testing::TestWithParam<TimerType>
{
protected:
void SetUp() override
@@ -44,10 +51,7 @@ protected:
test_node = std::make_shared<rclcpp::Node>("test_timer_node");
timer = test_node->create_wall_timer(
100ms,
[this]() -> void
{
auto timer_callback = [this]() -> void {
this->has_timer_run.store(true);
if (this->cancel_timer.load()) {
@@ -55,10 +59,20 @@ protected:
}
// prevent any tests running timer from blocking
this->executor->cancel();
}
);
EXPECT_TRUE(timer->is_steady());
};
// Store the timer type for use in TEST_P declarations.
timer_type = GetParam();
switch (timer_type) {
case TimerType::WALL_TIMER:
timer = test_node->create_wall_timer(100ms, timer_callback);
EXPECT_TRUE(timer->is_steady());
break;
case TimerType::GENERIC_TIMER:
timer = test_node->create_timer(100ms, timer_callback);
EXPECT_FALSE(timer->is_steady());
break;
}
executor->add_node(test_node);
// don't start spinning, let the test dictate when
}
@@ -72,6 +86,7 @@ protected:
}
// set to true if the timer callback executed, false otherwise
TimerType timer_type;
std::atomic<bool> has_timer_run;
// flag used to cancel the timer in the timer callback. If true cancel the timer, otherwise
// cancel the executor (preventing any tests from blocking)
@@ -91,7 +106,7 @@ void test_initial_conditions(
}
/// Simple test
TEST_F(TestTimer, test_simple_cancel)
TEST_P(TestTimer, test_simple_cancel)
{
// expect clean state, don't run otherwise
test_initial_conditions(timer, has_timer_run);
@@ -104,7 +119,7 @@ TEST_F(TestTimer, test_simple_cancel)
}
/// Test state when using reset
TEST_F(TestTimer, test_is_canceled_reset)
TEST_P(TestTimer, test_is_canceled_reset)
{
// expect clean state, don't run otherwise
test_initial_conditions(timer, has_timer_run);
@@ -129,7 +144,7 @@ TEST_F(TestTimer, test_is_canceled_reset)
}
/// Run and check state, cancel the executor
TEST_F(TestTimer, test_run_cancel_executor)
TEST_P(TestTimer, test_run_cancel_executor)
{
// expect clean state, don't run otherwise
test_initial_conditions(timer, has_timer_run);
@@ -146,7 +161,7 @@ TEST_F(TestTimer, test_run_cancel_executor)
}
/// Run and check state, cancel the timer
TEST_F(TestTimer, test_run_cancel_timer)
TEST_P(TestTimer, test_run_cancel_timer)
{
// expect clean state, don't run otherwise
test_initial_conditions(timer, has_timer_run);
@@ -159,7 +174,7 @@ TEST_F(TestTimer, test_run_cancel_timer)
EXPECT_TRUE(timer->is_canceled());
}
TEST_F(TestTimer, test_bad_arguments) {
TEST_P(TestTimer, test_bad_arguments) {
auto node_base = rclcpp::node_interfaces::get_node_base_interface(test_node);
auto context = node_base->get_context();
@@ -198,13 +213,19 @@ TEST_F(TestTimer, test_bad_arguments) {
rclcpp::exceptions::RCLError);
}
TEST_F(TestTimer, callback_with_timer) {
TEST_P(TestTimer, callback_with_timer) {
rclcpp::TimerBase * timer_ptr = nullptr;
timer = test_node->create_wall_timer(
std::chrono::milliseconds(1),
[&timer_ptr](rclcpp::TimerBase & timer) {
auto timer_callback = [&timer_ptr](rclcpp::TimerBase & timer) {
timer_ptr = &timer;
});
};
switch (timer_type) {
case TimerType::WALL_TIMER:
timer = test_node->create_wall_timer(1ms, timer_callback);
break;
case TimerType::GENERIC_TIMER:
timer = test_node->create_timer(1ms, timer_callback);
break;
}
auto start = std::chrono::steady_clock::now();
while (nullptr == timer_ptr &&
(std::chrono::steady_clock::now() - start) < std::chrono::milliseconds(100))
@@ -216,13 +237,19 @@ TEST_F(TestTimer, callback_with_timer) {
EXPECT_FALSE(timer_ptr->is_ready());
}
TEST_F(TestTimer, callback_with_period_zero) {
TEST_P(TestTimer, callback_with_period_zero) {
rclcpp::TimerBase * timer_ptr = nullptr;
timer = test_node->create_wall_timer(
std::chrono::milliseconds(0),
[&timer_ptr](rclcpp::TimerBase & timer) {
auto timer_callback = [&timer_ptr](rclcpp::TimerBase & timer) {
timer_ptr = &timer;
});
};
switch (timer_type) {
case TimerType::WALL_TIMER:
timer = test_node->create_wall_timer(0ms, timer_callback);
break;
case TimerType::GENERIC_TIMER:
timer = test_node->create_timer(0ms, timer_callback);
break;
}
auto start = std::chrono::steady_clock::now();
while (nullptr == timer_ptr &&
(std::chrono::steady_clock::now() - start) < std::chrono::milliseconds(100))
@@ -235,7 +262,7 @@ TEST_F(TestTimer, callback_with_period_zero) {
}
/// Test internal failures using mocks
TEST_F(TestTimer, test_failures_with_exceptions)
TEST_P(TestTimer, test_failures_with_exceptions)
{
// expect clean state, don't run otherwise
test_initial_conditions(timer, has_timer_run);
@@ -245,8 +272,16 @@ TEST_F(TestTimer, test_failures_with_exceptions)
auto mock = mocking_utils::inject_on_return("lib:rclcpp", rcl_timer_fini, RCL_RET_ERROR);
EXPECT_NO_THROW(
{
timer_to_test_destructor =
test_node->create_wall_timer(std::chrono::milliseconds(0), [](void) {});
switch (timer_type) {
case TimerType::WALL_TIMER:
timer_to_test_destructor =
test_node->create_wall_timer(std::chrono::milliseconds(0), [](void) {});
break;
case TimerType::GENERIC_TIMER:
timer_to_test_destructor =
test_node->create_timer(std::chrono::milliseconds(0), [](void) {});
break;
}
timer_to_test_destructor.reset();
});
}
@@ -283,3 +318,19 @@ TEST_F(TestTimer, test_failures_with_exceptions)
std::runtime_error("Timer could not get time until next call: error not set"));
}
}
INSTANTIATE_TEST_SUITE_P(
PerTimerType, TestTimer,
::testing::Values(TimerType::WALL_TIMER, TimerType::GENERIC_TIMER),
[](const ::testing::TestParamInfo<TimerType> & info) -> std::string {
switch (info.param) {
case TimerType::WALL_TIMER:
return std::string("wall_timer");
case TimerType::GENERIC_TIMER:
return std::string("generic_timer");
default:
break;
}
return std::string("unknown");
}
);

View File

@@ -0,0 +1,25 @@
/**:
ros__parameters:
bar: 5
foo: 3.5
a_value: "first"
/*:
load_node:
ros__parameters:
bar_foo: "ok"
a_value: "second"
namespace:
load_node:
ros__parameters:
foo_bar: true
a_value: "third"
bar:
ros__parameters:
fatal: 10
/**/namespace/*:
ros__parameters:
a_value: "last_one_win"

View File

@@ -0,0 +1,4 @@
/no/valid/parameters/node:
ros__parameters:
bar: 5
foo: 3.5

View File

@@ -0,0 +1,5 @@
/**/foo/*/bar:
node2:
ros__parameters:
foo: "foo"
bar: "bar"

View File

@@ -0,0 +1,16 @@
/**:
node2:
ros__parameters:
a_value: "first"
foo: "foo"
/ns:
node2:
ros__parameters:
a_value: "second"
bar: "bar"
/*:
node2:
ros__parameters:
a_value: "last_one_win"

View File

@@ -0,0 +1,57 @@
/**:
ros__parameters:
full_wild: "full_wild"
/**:
node2:
ros__parameters:
namespace_wild: "namespace_wild"
/**/node2:
ros__parameters:
namespace_wild_another: "namespace_wild_another"
/*:
node2:
ros__parameters:
namespace_wild_one_star: "namespace_wild_one_star"
ns:
"*":
ros__parameters:
node_wild_in_ns: "node_wild_in_ns"
/ns/*:
ros__parameters:
node_wild_in_ns_another: "node_wild_in_ns_another"
ns:
node2:
ros__parameters:
explicit_in_ns: "explicit_in_ns"
"*":
ros__parameters:
node_wild_no_ns: "node_wild_no_ns"
node2:
ros__parameters:
explicit_no_ns: "explicit_no_ns"
ns:
nodeX:
ros__parameters:
should_not_appear: "incorrect_node_name"
/**/nodeX:
ros__parameters:
should_not_appear: "incorrect_node_name"
nsX:
node2:
ros__parameters:
should_not_appear: "incorrect_namespace"
/nsX/*:
ros__parameters:
should_not_appear: "incorrect_namespace"

View File

@@ -3,6 +3,17 @@ Changelog for package rclcpp_action
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
17.1.0 (2022-11-02)
-------------------
* Do not clear entities callbacks on destruction (`#2002 <https://github.com/ros2/rclcpp/issues/2002>`_)
* Contributors: mauropasse
17.0.0 (2022-09-13)
-------------------
* Revert "Introduce executors new spin_for method, replace spin_until_future_complete with spin_until_complete. (`#1821 <https://github.com/ros2/rclcpp/issues/1821>`_) (`#1874 <https://github.com/ros2/rclcpp/issues/1874>`_)" (`#1956 <https://github.com/ros2/rclcpp/issues/1956>`_)
* Introduce executors new spin_for method, replace spin_until_future_complete with spin_until_complete. (`#1821 <https://github.com/ros2/rclcpp/issues/1821>`_) (`#1874 <https://github.com/ros2/rclcpp/issues/1874>`_)
* Contributors: Hubert Liberacki, William Woodall
16.2.0 (2022-05-03)
-------------------

View File

@@ -2,7 +2,7 @@
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
<name>rclcpp_action</name>
<version>16.2.0</version>
<version>17.1.0</version>
<description>Adds action APIs for C++.</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
<maintainer email="jacob@openrobotics.org">Jacob Perron</maintainer>

View File

@@ -136,7 +136,6 @@ ClientBase::ClientBase(
ClientBase::~ClientBase()
{
clear_on_ready_callback();
}
bool

View File

@@ -132,7 +132,6 @@ ServerBase::ServerBase(
ServerBase::~ServerBase()
{
clear_on_ready_callback();
}
size_t

View File

@@ -2,6 +2,17 @@
Changelog for package rclcpp_components
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
17.1.0 (2022-11-02)
-------------------
* use unique ptr and remove unuseful container (`#2013 <https://github.com/ros2/rclcpp/issues/2013>`_)
* Contributors: Chen Lihui
17.0.0 (2022-09-13)
-------------------
* Revert "Introduce executors new spin_for method, replace spin_until_future_complete with spin_until_complete. (`#1821 <https://github.com/ros2/rclcpp/issues/1821>`_) (`#1874 <https://github.com/ros2/rclcpp/issues/1874>`_)" (`#1956 <https://github.com/ros2/rclcpp/issues/1956>`_)
* Introduce executors new spin_for method, replace spin_until_future_complete with spin_until_complete. (`#1821 <https://github.com/ros2/rclcpp/issues/1821>`_) (`#1874 <https://github.com/ros2/rclcpp/issues/1874>`_)
* Contributors: Hubert Liberacki, William Woodall
16.2.0 (2022-05-03)
-------------------

View File

@@ -2,7 +2,7 @@
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
<package format="2">
<name>rclcpp_components</name>
<version>16.2.0</version>
<version>17.1.0</version>
<description>Package containing tools for dynamically loadable components</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
<maintainer email="jacob@openrobotics.org">Jacob Perron</maintainer>

View File

@@ -30,14 +30,13 @@ int main(int argc, char * argv[])
rclcpp::executors::@executor@ exec;
rclcpp::NodeOptions options;
options.arguments(args);
std::vector<class_loader::ClassLoader * > loaders;
std::vector<rclcpp_components::NodeInstanceWrapper> node_wrappers;
std::string library_name = "@library_name@";
std::string class_name = "rclcpp_components::NodeFactoryTemplate<@component@>";
RCLCPP_DEBUG(logger, "Load library %s", library_name.c_str());
auto loader = new class_loader::ClassLoader(library_name);
auto loader = std::make_unique<class_loader::ClassLoader>(library_name);
auto classes = loader->getAvailableClasses<rclcpp_components::NodeFactory>();
for (const auto & clazz : classes) {
std::string name = clazz.c_str();
@@ -59,8 +58,6 @@ int main(int argc, char * argv[])
exec.add_node(node);
}
}
loaders.push_back(loader);
exec.spin();

View File

@@ -3,6 +3,25 @@ Changelog for package rclcpp_lifecycle
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
17.1.0 (2022-11-02)
-------------------
* LifecycleNode on_configure doc fix. (`#2034 <https://github.com/ros2/rclcpp/issues/2034>`_)
* Bugfix 20210810 get current state (`#1756 <https://github.com/ros2/rclcpp/issues/1756>`_)
* Make lifecycle impl get_current_state() const. (`#2031 <https://github.com/ros2/rclcpp/issues/2031>`_)
* Cleanup the lifecycle implementation (`#2027 <https://github.com/ros2/rclcpp/issues/2027>`_)
* Cleanup the rclcpp_lifecycle dependencies. (`#2021 <https://github.com/ros2/rclcpp/issues/2021>`_)
* Contributors: Chris Lalancette, Tomoya Fujita
17.0.0 (2022-09-13)
-------------------
* Revert "Revert "Add a create_timer method to Node and `LifecycleNode` classes (`#1975 <https://github.com/ros2/rclcpp/issues/1975>`_)" (`#2009 <https://github.com/ros2/rclcpp/issues/2009>`_) (`#2010 <https://github.com/ros2/rclcpp/issues/2010>`_)
* Revert "Add a `create_timer` method to `Node` and `LifecycleNode` classes (`#1975 <https://github.com/ros2/rclcpp/issues/1975>`_)" (`#2009 <https://github.com/ros2/rclcpp/issues/2009>`_)
* Add a `create_timer` method to `Node` and `LifecycleNode` classes (`#1975 <https://github.com/ros2/rclcpp/issues/1975>`_)
* Support pre-set and post-set parameter callbacks in addition to on-set-parameter-callback. (`#1947 <https://github.com/ros2/rclcpp/issues/1947>`_)
* Make create_service accept rclcpp::QoS (`#1969 <https://github.com/ros2/rclcpp/issues/1969>`_)
* Make create_client accept rclcpp::QoS (`#1964 <https://github.com/ros2/rclcpp/issues/1964>`_)
* Contributors: Andrew Symington, Deepanshu Bansal, Ivan Santiago Paunovic, Shane Loretz
16.2.0 (2022-05-03)
-------------------

View File

@@ -11,14 +11,18 @@ if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
endif()
find_package(ament_cmake_ros REQUIRED)
find_package(rclcpp REQUIRED)
find_package(rcl_lifecycle REQUIRED)
find_package(rosidl_typesupport_cpp REQUIRED)
find_package(lifecycle_msgs REQUIRED)
find_package(rcl REQUIRED)
find_package(rclcpp REQUIRED)
find_package(rcl_interfaces REQUIRED)
find_package(rcl_lifecycle REQUIRED)
find_package(rcutils REQUIRED)
find_package(rosidl_typesupport_cpp REQUIRED)
### CPP High level library
add_library(rclcpp_lifecycle
src/lifecycle_node.cpp
src/lifecycle_node_interface_impl.cpp
src/managed_entity.cpp
src/node_interfaces/lifecycle_node_interface.cpp
src/state.cpp
@@ -28,12 +32,14 @@ target_include_directories(${PROJECT_NAME}
PUBLIC
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
"$<INSTALL_INTERFACE:include/${PROJECT_NAME}>")
# specific order: dependents before dependencies
ament_target_dependencies(rclcpp_lifecycle
"rclcpp"
"rcl_lifecycle"
"lifecycle_msgs"
"rosidl_typesupport_cpp"
target_link_libraries(${PROJECT_NAME}
${lifecycle_msgs_TARGETS}
rcl::rcl
rclcpp::rclcpp
${rcl_interfaces_TARGETS}
rcl_lifecycle::rcl_lifecycle
rcutils::rcutils
rosidl_typesupport_cpp::rosidl_typesupport_cpp
)
# Causes the visibility macros to use dllexport rather than dllimport,
@@ -46,6 +52,9 @@ install(TARGETS
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin)
install(DIRECTORY include/
DESTINATION include/${PROJECT_NAME})
if(BUILD_TESTING)
find_package(ament_lint_auto REQUIRED)
# Give cppcheck hints about macro definitions coming from outside this package
@@ -58,15 +67,13 @@ if(BUILD_TESTING)
benchmark_lifecycle_client
test/benchmark/benchmark_lifecycle_client.cpp)
if(TARGET benchmark_lifecycle_client)
target_link_libraries(benchmark_lifecycle_client ${PROJECT_NAME})
ament_target_dependencies(benchmark_lifecycle_client rclcpp)
target_link_libraries(benchmark_lifecycle_client ${PROJECT_NAME} rclcpp::rclcpp)
endif()
add_performance_test(
benchmark_lifecycle_node
test/benchmark/benchmark_lifecycle_node.cpp)
if(TARGET benchmark_lifecycle_node)
target_link_libraries(benchmark_lifecycle_node ${PROJECT_NAME})
ament_target_dependencies(benchmark_lifecycle_node rclcpp)
target_link_libraries(benchmark_lifecycle_node ${PROJECT_NAME} rclcpp::rclcpp)
endif()
add_performance_test(
benchmark_state
@@ -83,72 +90,57 @@ if(BUILD_TESTING)
ament_add_gtest(test_lifecycle_node test/test_lifecycle_node.cpp TIMEOUT 120)
if(TARGET test_lifecycle_node)
ament_target_dependencies(test_lifecycle_node
"rcl_lifecycle"
"rclcpp"
"rcutils"
)
target_link_libraries(test_lifecycle_node ${PROJECT_NAME} mimick)
target_link_libraries(test_lifecycle_node ${PROJECT_NAME} mimick rcl_lifecycle::rcl_lifecycle rclcpp::rclcpp rcutils::rcutils)
endif()
ament_add_gtest(test_lifecycle_publisher test/test_lifecycle_publisher.cpp)
if(TARGET test_lifecycle_publisher)
ament_target_dependencies(test_lifecycle_publisher
"rcl_lifecycle"
"rclcpp"
"test_msgs"
)
target_link_libraries(test_lifecycle_publisher ${PROJECT_NAME})
target_link_libraries(test_lifecycle_publisher ${PROJECT_NAME} rcl_lifecycle::rcl_lifecycle rclcpp::rclcpp ${test_msgs_TARGETS})
endif()
ament_add_gtest(test_lifecycle_service_client test/test_lifecycle_service_client.cpp TIMEOUT 120)
if(TARGET test_lifecycle_service_client)
ament_target_dependencies(test_lifecycle_service_client
"rcl_lifecycle"
"rclcpp"
"rcpputils"
"rcutils"
)
target_link_libraries(test_lifecycle_service_client ${PROJECT_NAME} mimick)
target_link_libraries(test_lifecycle_service_client
${PROJECT_NAME}
mimick
rcl_lifecycle::rcl_lifecycle
rclcpp::rclcpp
rcpputils::rcpputils
rcutils::rcutils)
endif()
ament_add_gtest(test_client test/test_client.cpp TIMEOUT 120)
if(TARGET test_client)
target_link_libraries(test_client
${PROJECT_NAME}
mimick
${rcl_interfaces_TARGETS}
rclcpp::rclcpp)
endif()
ament_add_gtest(test_service test/test_service.cpp TIMEOUT 120)
if(TARGET test_service)
target_link_libraries(test_service
${PROJECT_NAME}
mimick
${test_msgs_TARGETS}
rclcpp::rclcpp)
endif()
ament_add_gtest(test_state_machine_info test/test_state_machine_info.cpp)
if(TARGET test_state_machine_info)
ament_target_dependencies(test_state_machine_info
"rcl_lifecycle"
"rclcpp"
)
target_link_libraries(test_state_machine_info ${PROJECT_NAME})
target_link_libraries(test_state_machine_info ${PROJECT_NAME} rcl_lifecycle::rcl_lifecycle rclcpp::rclcpp)
endif()
ament_add_gtest(test_register_custom_callbacks test/test_register_custom_callbacks.cpp)
if(TARGET test_register_custom_callbacks)
ament_target_dependencies(test_register_custom_callbacks
"rcl_lifecycle"
"rclcpp"
)
target_link_libraries(test_register_custom_callbacks ${PROJECT_NAME})
target_link_libraries(test_register_custom_callbacks ${PROJECT_NAME} rcl_lifecycle::rcl_lifecycle rclcpp::rclcpp)
endif()
ament_add_gtest(test_callback_exceptions test/test_callback_exceptions.cpp)
if(TARGET test_callback_exceptions)
ament_target_dependencies(test_callback_exceptions
"rcl_lifecycle"
"rclcpp"
)
target_link_libraries(test_callback_exceptions ${PROJECT_NAME})
target_link_libraries(test_callback_exceptions ${PROJECT_NAME} rcl_lifecycle::rcl_lifecycle rclcpp::rclcpp)
endif()
ament_add_gtest(test_state_wrapper test/test_state_wrapper.cpp)
if(TARGET test_state_wrapper)
ament_target_dependencies(test_state_wrapper
"rcl_lifecycle"
"rclcpp"
)
target_link_libraries(test_state_wrapper ${PROJECT_NAME})
target_link_libraries(test_state_wrapper ${PROJECT_NAME} rcl_lifecycle::rcl_lifecycle rclcpp::rclcpp)
endif()
ament_add_gtest(test_transition_wrapper test/test_transition_wrapper.cpp)
if(TARGET test_transition_wrapper)
ament_target_dependencies(test_transition_wrapper
"rcl_lifecycle"
"rclcpp"
"rcutils"
)
target_link_libraries(test_transition_wrapper ${PROJECT_NAME} mimick)
target_link_libraries(test_transition_wrapper ${PROJECT_NAME} mimick rcl_lifecycle::rcl_lifecycle rclcpp::rclcpp rcutils::rcutils)
target_compile_definitions(test_transition_wrapper
PUBLIC RCUTILS_ENABLE_FAULT_INJECTION
)
@@ -162,11 +154,7 @@ ament_export_libraries(${PROJECT_NAME})
# Export modern CMake targets
ament_export_targets(${PROJECT_NAME})
# specific order: dependents before dependencies
ament_export_dependencies(rclcpp)
ament_export_dependencies(rcl_lifecycle)
ament_export_dependencies(lifecycle_msgs)
ament_package()
# Export dependencies
ament_export_dependencies(lifecycle_msgs rcl rclcpp rcl_interfaces rcl_lifecycle rcutils rosidl_typesupport_cpp)
install(DIRECTORY include/
DESTINATION include/${PROJECT_NAME})
ament_package()

View File

@@ -36,6 +36,8 @@
#ifndef RCLCPP_LIFECYCLE__LIFECYCLE_NODE_HPP_
#define RCLCPP_LIFECYCLE__LIFECYCLE_NODE_HPP_
#include <chrono>
#include <functional>
#include <map>
#include <memory>
#include <string>
@@ -49,13 +51,11 @@
#include "rcl_interfaces/msg/list_parameters_result.hpp"
#include "rcl_interfaces/msg/parameter_descriptor.hpp"
#include "rcl_interfaces/msg/parameter_event.hpp"
#include "rcl_interfaces/msg/set_parameters_result.hpp"
#include "rclcpp/callback_group.hpp"
#include "rclcpp/client.hpp"
#include "rclcpp/clock.hpp"
#include "rclcpp/context.hpp"
#include "rclcpp/event.hpp"
#include "rclcpp/generic_publisher.hpp"
#include "rclcpp/generic_subscription.hpp"
@@ -83,6 +83,8 @@
#include "rclcpp/time.hpp"
#include "rclcpp/timer.hpp"
#include "rmw/types.h"
#include "rclcpp_lifecycle/node_interfaces/lifecycle_node_interface.hpp"
#include "rclcpp_lifecycle/lifecycle_publisher.hpp"
#include "rclcpp_lifecycle/state.hpp"
@@ -137,7 +139,7 @@ public:
const rclcpp::NodeOptions & options = rclcpp::NodeOptions(),
bool enable_communication_interface = true);
/// Create a node based on the node name and a rclcpp::Context.
/// Create a node based on the node name
/**
* \param[in] node_name Name of the node.
* \param[in] namespace_ Namespace of the node.
@@ -242,7 +244,7 @@ public:
)
);
/// Create a timer.
/// Create a timer that uses the wall clock to drive the callback.
/**
* \param[in] period Time interval between triggers of the callback.
* \param[in] callback User-defined callback function.
@@ -255,15 +257,58 @@ public:
CallbackT callback,
rclcpp::CallbackGroup::SharedPtr group = nullptr);
/// Create a timer that uses the node clock to drive the callback.
/**
* \param[in] period Time interval between triggers of the callback.
* \param[in] callback User-defined callback function.
* \param[in] group Callback group to execute this timer's callback in.
*/
template<typename DurationRepT = int64_t, typename DurationT = std::milli, typename CallbackT>
typename rclcpp::GenericTimer<CallbackT>::SharedPtr
create_timer(
std::chrono::duration<DurationRepT, DurationT> period,
CallbackT callback,
rclcpp::CallbackGroup::SharedPtr group = nullptr);
/// Create and return a Client.
/**
* \sa rclcpp::Node::create_client
* \deprecated use rclcpp::QoS instead of rmw_qos_profile_t
*/
template<typename ServiceT>
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
typename rclcpp::Client<ServiceT>::SharedPtr
create_client(
const std::string & service_name,
const rmw_qos_profile_t & qos_profile,
rclcpp::CallbackGroup::SharedPtr group = nullptr);
/// Create and return a Client.
/**
* \param[in] service_name The name on which the service is accessible.
* \param[in] qos Quality of service profile for client.
* \param[in] group Callback group to handle the reply to service calls.
* \return Shared pointer to the created client.
*/
template<typename ServiceT>
typename rclcpp::Client<ServiceT>::SharedPtr
create_client(
const std::string & service_name,
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_services_default,
const rclcpp::QoS & qos = rclcpp::ServicesQoS(),
rclcpp::CallbackGroup::SharedPtr group = nullptr);
/// Create and return a Service.
/**
* \sa rclcpp::Node::create_service
* \deprecated use rclcpp::QoS instead of rmw_qos_profile_t
*/
template<typename ServiceT, typename CallbackT>
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
typename rclcpp::Service<ServiceT>::SharedPtr
create_service(
const std::string & service_name,
CallbackT && callback,
const rmw_qos_profile_t & qos_profile,
rclcpp::CallbackGroup::SharedPtr group = nullptr);
/// Create and return a Service.
@@ -275,7 +320,7 @@ public:
create_service(
const std::string & service_name,
CallbackT && callback,
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_services_default,
const rclcpp::QoS & qos = rclcpp::ServicesQoS(),
rclcpp::CallbackGroup::SharedPtr group = nullptr);
/// Create and return a GenericPublisher.
@@ -508,10 +553,32 @@ public:
rcl_interfaces::msg::ListParametersResult
list_parameters(const std::vector<std::string> & prefixes, uint64_t depth) const;
using PreSetParametersCallbackHandle =
rclcpp::node_interfaces::PreSetParametersCallbackHandle;
using PreSetParametersCallbackType =
rclcpp::node_interfaces::NodeParametersInterface::PreSetParametersCallbackType;
using OnSetParametersCallbackHandle =
rclcpp::node_interfaces::OnSetParametersCallbackHandle;
using OnParametersSetCallbackType =
rclcpp::node_interfaces::NodeParametersInterface::OnParametersSetCallbackType;
using OnSetParametersCallbackType =
rclcpp::node_interfaces::NodeParametersInterface::OnSetParametersCallbackType;
using OnParametersSetCallbackType [[deprecated("use OnSetParametersCallbackType instead")]] =
OnSetParametersCallbackType;
using PostSetParametersCallbackHandle =
rclcpp::node_interfaces::PostSetParametersCallbackHandle;
using PostSetParametersCallbackType =
rclcpp::node_interfaces::NodeParametersInterface::PostSetParametersCallbackType;
/// Add a callback that gets triggered before parameters are validated.
/**
* \sa rclcpp::Node::add_pre_set_parameters_callback
*/
RCLCPP_LIFECYCLE_PUBLIC
RCUTILS_WARN_UNUSED
rclcpp_lifecycle::LifecycleNode::PreSetParametersCallbackHandle::SharedPtr
add_pre_set_parameters_callback(
rclcpp_lifecycle::LifecycleNode::PreSetParametersCallbackType callback);
/// Add a callback for when parameters are being set.
/**
@@ -521,7 +588,26 @@ public:
RCUTILS_WARN_UNUSED
rclcpp_lifecycle::LifecycleNode::OnSetParametersCallbackHandle::SharedPtr
add_on_set_parameters_callback(
rclcpp_lifecycle::LifecycleNode::OnParametersSetCallbackType callback);
rclcpp_lifecycle::LifecycleNode::OnSetParametersCallbackType callback);
/// Add a callback that gets triggered after parameters are set successfully.
/**
* \sa rclcpp::Node::add_post_set_parameters_callback
*/
RCLCPP_LIFECYCLE_PUBLIC
RCUTILS_WARN_UNUSED
rclcpp_lifecycle::LifecycleNode::PostSetParametersCallbackHandle::SharedPtr
add_post_set_parameters_callback(
rclcpp_lifecycle::LifecycleNode::PostSetParametersCallbackType callback);
/// Remove a callback registered with `add_pre_set_parameters_callback`.
/**
* \sa rclcpp::Node::remove_pre_set_parameters_callback
*/
RCLCPP_LIFECYCLE_PUBLIC
void
remove_pre_set_parameters_callback(
const rclcpp_lifecycle::LifecycleNode::PreSetParametersCallbackHandle * const handler);
/// Remove a callback registered with `add_on_set_parameters_callback`.
/**
@@ -532,6 +618,15 @@ public:
remove_on_set_parameters_callback(
const rclcpp_lifecycle::LifecycleNode::OnSetParametersCallbackHandle * const handler);
/// Remove a callback registered with `add_post_set_parameters_callback`.
/**
* \sa rclcpp::Node::remove_post_set_parameters_callback
*/
RCLCPP_LIFECYCLE_PUBLIC
void
remove_post_set_parameters_callback(
const rclcpp_lifecycle::LifecycleNode::PostSetParametersCallbackHandle * const handler);
/// Return a vector of existing node names (string).
/**
* \sa rclcpp::Node::get_node_names
@@ -744,7 +839,7 @@ public:
*/
RCLCPP_LIFECYCLE_PUBLIC
const State &
get_current_state();
get_current_state() const;
/// Return a list with the available states.
/**
@@ -752,7 +847,7 @@ public:
*/
RCLCPP_LIFECYCLE_PUBLIC
std::vector<State>
get_available_states();
get_available_states() const;
/// Return a list with the current available transitions.
/**
@@ -760,7 +855,7 @@ public:
*/
RCLCPP_LIFECYCLE_PUBLIC
std::vector<Transition>
get_available_transitions();
get_available_transitions() const;
/// Return a list with all the transitions.
/**
@@ -768,7 +863,7 @@ public:
*/
RCLCPP_LIFECYCLE_PUBLIC
std::vector<Transition>
get_transition_graph();
get_transition_graph() const;
/// Trigger the specified transition.
/*

View File

@@ -15,28 +15,35 @@
#ifndef RCLCPP_LIFECYCLE__LIFECYCLE_NODE_IMPL_HPP_
#define RCLCPP_LIFECYCLE__LIFECYCLE_NODE_IMPL_HPP_
#include <algorithm>
#include <chrono>
#include <functional>
#include <map>
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "rclcpp/contexts/default_context.hpp"
#include "rcl_interfaces/msg/parameter_descriptor.hpp"
#include "rclcpp/callback_group.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_subscription.hpp"
#include "rclcpp/event.hpp"
#include "rclcpp/experimental/intra_process_manager.hpp"
#include "rclcpp/parameter.hpp"
#include "rclcpp/publisher_options.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/subscription_options.hpp"
#include "rclcpp/type_support_decl.hpp"
#include "lifecycle_publisher.hpp"
#include "rclcpp_lifecycle/visibility_control.h"
#include "rmw/types.h"
#include "rclcpp_lifecycle/lifecycle_node.hpp"
#include "rclcpp_lifecycle/lifecycle_publisher.hpp"
#include "rclcpp_lifecycle/visibility_control.h"
namespace rclcpp_lifecycle
{
@@ -89,11 +96,28 @@ LifecycleNode::create_wall_timer(
CallbackT callback,
rclcpp::CallbackGroup::SharedPtr group)
{
auto timer = rclcpp::WallTimer<CallbackT>::make_shared(
std::chrono::duration_cast<std::chrono::nanoseconds>(period),
std::move(callback), this->node_base_->get_context());
node_timers_->add_timer(timer, group);
return timer;
return rclcpp::create_wall_timer(
period,
std::move(callback),
group,
this->node_base_.get(),
this->node_timers_.get());
}
template<typename DurationRepT, typename DurationT, typename CallbackT>
typename rclcpp::GenericTimer<CallbackT>::SharedPtr
LifecycleNode::create_timer(
std::chrono::duration<DurationRepT, DurationT> period,
CallbackT callback,
rclcpp::CallbackGroup::SharedPtr group)
{
return rclcpp::create_timer(
this->get_clock(),
period,
std::move(callback),
group,
this->node_base_.get(),
this->node_timers_.get());
}
template<typename ServiceT>
@@ -103,21 +127,21 @@ LifecycleNode::create_client(
const rmw_qos_profile_t & qos_profile,
rclcpp::CallbackGroup::SharedPtr group)
{
rcl_client_options_t options = rcl_client_get_default_options();
options.qos = qos_profile;
return rclcpp::create_client<ServiceT>(
node_base_, node_graph_, node_services_,
service_name, qos_profile, group);
}
using rclcpp::Client;
using rclcpp::ClientBase;
auto cli = Client<ServiceT>::make_shared(
node_base_.get(),
node_graph_,
service_name,
options);
auto cli_base_ptr = std::dynamic_pointer_cast<ClientBase>(cli);
node_services_->add_client(cli_base_ptr, group);
return cli;
template<typename ServiceT>
typename rclcpp::Client<ServiceT>::SharedPtr
LifecycleNode::create_client(
const std::string & service_name,
const rclcpp::QoS & qos,
rclcpp::CallbackGroup::SharedPtr group)
{
return rclcpp::create_client<ServiceT>(
node_base_, node_graph_, node_services_,
service_name, qos, group);
}
template<typename ServiceT, typename CallbackT>
@@ -133,6 +157,19 @@ LifecycleNode::create_service(
service_name, std::forward<CallbackT>(callback), qos_profile, group);
}
template<typename ServiceT, typename CallbackT>
typename rclcpp::Service<ServiceT>::SharedPtr
LifecycleNode::create_service(
const std::string & service_name,
CallbackT && callback,
const rclcpp::QoS & qos,
rclcpp::CallbackGroup::SharedPtr group)
{
return rclcpp::create_service<ServiceT, CallbackT>(
node_base_, node_services_,
service_name, std::forward<CallbackT>(callback), qos, group);
}
template<typename AllocatorT>
std::shared_ptr<rclcpp::GenericPublisher>
LifecycleNode::create_generic_publisher(

Some files were not shown because too many files have changed in this diff Show More