Compare commits

...

33 Commits

Author SHA1 Message Date
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
Jacob Perron
491475f232 16.2.0 2022-05-03 12:14:26 -07:00
Barry Xu
b8b64b4c08 Update get_parameter_from_event to follow the function description (#1922)
Signed-off-by: Barry Xu <barry.xu@sony.com>
2022-05-03 11:21:20 -07:00
Jacob Perron
ee67c211c5 Add 'best available' QoS enum values and methods (#1920)
If users set a policy as 'best available', then the middleware will pick a policy
that is most compatible with the current set of discovered endpoints while maintaining
the highest level of service possible.

For details about the expected behavior, see connected changes:

- https://github.com/ros2/rmw/pull/320
- https://github.com/ros2/rmw_dds_common/pull/60

Signed-off-by: Jacob Perron <jacob@openrobotics.org>
2022-05-03 10:35:10 -07:00
Audrow Nash
82ddd44140 16.1.0
Signed-off-by: Audrow Nash <audrow@hey.com>
2022-04-29 17:40:56 -07:00
Tomoya Fujita
a1980678ae use reinterpret_cast for function pointer conversion. (#1919)
Signed-off-by: Tomoya Fujita <Tomoya.Fujita@sony.com>
2022-04-26 13:39:00 -07:00
81 changed files with 3299 additions and 399 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,46 @@
Changelog for package rclcpp
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
17.0.0 (2022-09-13)
-------------------
* Make ParameterService and Sync/AsyncParameterClient accept rclcpp::QoS (`#1978 <https://github.com/ros2/rclcpp/issues/1978>`_)
* support regex match for parameter client (`#1992 <https://github.com/ros2/rclcpp/issues/1992>`_)
* operator+= and operator-= for Duration (`#1988 <https://github.com/ros2/rclcpp/issues/1988>`_)
* Revert "Revert "Add a create_timer method to Node and `LifecycleNode` classes (`#1975 <https://github.com/ros2/rclcpp/issues/1975>`_)" (`#2009 <https://github.com/ros2/rclcpp/issues/2009>`_) (`#2010 <https://github.com/ros2/rclcpp/issues/2010>`_)
* force compiler warning if callback handles not captured (`#2000 <https://github.com/ros2/rclcpp/issues/2000>`_)
* Revert "Add a `create_timer` method to `Node` and `LifecycleNode` classes (`#1975 <https://github.com/ros2/rclcpp/issues/1975>`_)" (`#2009 <https://github.com/ros2/rclcpp/issues/2009>`_)
* Add a `create_timer` method to `Node` and `LifecycleNode` classes (`#1975 <https://github.com/ros2/rclcpp/issues/1975>`_)
* [docs] add note about callback lifetime for {on, post}_set_parameter_callback (`#1981 <https://github.com/ros2/rclcpp/issues/1981>`_)
* fix memory leak (`#1994 <https://github.com/ros2/rclcpp/issues/1994>`_)
* Support pre-set and post-set parameter callbacks in addition to on-set-parameter-callback. (`#1947 <https://github.com/ros2/rclcpp/issues/1947>`_)
* Make create_service accept rclcpp::QoS (`#1969 <https://github.com/ros2/rclcpp/issues/1969>`_)
* Make create_client accept rclcpp::QoS (`#1964 <https://github.com/ros2/rclcpp/issues/1964>`_)
* Fix the documentation for rclcpp::ok to be accurate. (`#1965 <https://github.com/ros2/rclcpp/issues/1965>`_)
* use regex for wildcard matching (`#1839 <https://github.com/ros2/rclcpp/issues/1839>`_)
* Revert "Introduce executors new spin_for method, replace spin_until_future_complete with spin_until_complete. (`#1821 <https://github.com/ros2/rclcpp/issues/1821>`_) (`#1874 <https://github.com/ros2/rclcpp/issues/1874>`_)" (`#1956 <https://github.com/ros2/rclcpp/issues/1956>`_)
* Introduce executors new spin_for method, replace spin_until_future_complete with spin_until_complete. (`#1821 <https://github.com/ros2/rclcpp/issues/1821>`_) (`#1874 <https://github.com/ros2/rclcpp/issues/1874>`_)
* test adjustment for LoanedMessage. (`#1951 <https://github.com/ros2/rclcpp/issues/1951>`_)
* fix virtual dispatch issues identified by clang-tidy (`#1816 <https://github.com/ros2/rclcpp/issues/1816>`_)
* Remove unused on_parameters_set_callback\_ (`#1945 <https://github.com/ros2/rclcpp/issues/1945>`_)
* Fix subscription.is_serialized() for callbacks with message info (`#1950 <https://github.com/ros2/rclcpp/issues/1950>`_)
* wait for subscriptions on another thread. (`#1940 <https://github.com/ros2/rclcpp/issues/1940>`_)
* Fix documentation of `RCLCPP\_[INFO,WARN,...]` (`#1943 <https://github.com/ros2/rclcpp/issues/1943>`_)
* Always trigger guard condition waitset (`#1923 <https://github.com/ros2/rclcpp/issues/1923>`_)
* Add statistics for handle_loaned_message (`#1927 <https://github.com/ros2/rclcpp/issues/1927>`_)
* Drop wrong template specialization (`#1926 <https://github.com/ros2/rclcpp/issues/1926>`_)
* Contributors: Alberto Soragna, Andrew Symington, Barry Xu, Brian, Chen Lihui, Chris Lalancette, Daniel Reuter, Deepanshu Bansal, Hubert Liberacki, Ivan Santiago Paunovic, Jochen Sprickerhof, Nikolai Morin, Shane Loretz, Tomoya Fujita, Tyler Weaver, William Woodall, schrodinbug
16.2.0 (2022-05-03)
-------------------
* Update get_parameter_from_event to follow the function description (`#1922 <https://github.com/ros2/rclcpp/issues/1922>`_)
* Add 'best available' QoS enum values and methods (`#1920 <https://github.com/ros2/rclcpp/issues/1920>`_)
* Contributors: Barry Xu, Jacob Perron
16.1.0 (2022-04-29)
-------------------
* use reinterpret_cast for function pointer conversion. (`#1919 <https://github.com/ros2/rclcpp/issues/1919>`_)
* Contributors: Tomoya Fujita
16.0.1 (2022-04-13)
-------------------
* remove DEFINE_CONTENT_FILTER cmake option (`#1914 <https://github.com/ros2/rclcpp/issues/1914>`_)

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

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

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

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

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

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

@@ -84,6 +84,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 +181,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 +234,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

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

@@ -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,
@@ -268,6 +283,7 @@ public:
* \param[in] parameter_name Name of parameter.
* \param[in] node_name Name of node which hosts the parameter.
* \returns The resultant rclcpp::Parameter from the event.
* \throws std::runtime_error if input node name doesn't match the node name in parameter event.
*/
RCLCPP_PUBLIC
static rclcpp::Parameter

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

@@ -44,6 +44,7 @@ enum class ReliabilityPolicy
BestEffort = RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT,
Reliable = RMW_QOS_POLICY_RELIABILITY_RELIABLE,
SystemDefault = RMW_QOS_POLICY_RELIABILITY_SYSTEM_DEFAULT,
BestAvailable = RMW_QOS_POLICY_RELIABILITY_BEST_AVAILABLE,
Unknown = RMW_QOS_POLICY_RELIABILITY_UNKNOWN,
};
@@ -52,6 +53,7 @@ enum class DurabilityPolicy
Volatile = RMW_QOS_POLICY_DURABILITY_VOLATILE,
TransientLocal = RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL,
SystemDefault = RMW_QOS_POLICY_DURABILITY_SYSTEM_DEFAULT,
BestAvailable = RMW_QOS_POLICY_DURABILITY_BEST_AVAILABLE,
Unknown = RMW_QOS_POLICY_DURABILITY_UNKNOWN,
};
@@ -60,6 +62,7 @@ enum class LivelinessPolicy
Automatic = RMW_QOS_POLICY_LIVELINESS_AUTOMATIC,
ManualByTopic = RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC,
SystemDefault = RMW_QOS_POLICY_LIVELINESS_SYSTEM_DEFAULT,
BestAvailable = RMW_QOS_POLICY_LIVELINESS_BEST_AVAILABLE,
Unknown = RMW_QOS_POLICY_LIVELINESS_UNKNOWN,
};
@@ -180,6 +183,10 @@ public:
QoS &
best_effort();
/// Set the reliability setting to best available.
QoS &
reliability_best_available();
/// Set the durability setting.
QoS &
durability(rmw_qos_durability_policy_t durability);
@@ -199,6 +206,10 @@ public:
QoS &
transient_local();
/// Set the durability setting to best available.
QoS &
durability_best_available();
/// Set the deadline setting.
QoS &
deadline(rmw_time_t deadline);
@@ -488,6 +499,36 @@ public:
));
};
/**
* Best available QoS class
*
* Match majority of endpoints currently available while maintaining the highest level of service.
* Policies are chosen at the time of creating a subscription or publisher.
* The middleware is not expected to update policies after creating a subscription or publisher,
* even if one or more policies are incompatible with newly discovered endpoints.
* Therefore, this profile should be used with care since non-deterministic behavior can occur due
* to races with discovery.
*
* - History: Keep last,
* - Depth: 10,
* - Reliability: Best available,
* - Durability: Best available,
* - Deadline: Best available,
* - Lifespan: Default,
* - Liveliness: Best available,
* - Liveliness lease duration: Best available,
* - avoid ros namespace conventions: false
*/
class RCLCPP_PUBLIC BestAvailableQoS : public QoS
{
public:
explicit
BestAvailableQoS(
const QoSInitialization & qos_initialization = (
QoSInitialization::from_rmw(rmw_qos_profile_best_available)
));
};
} // namespace rclcpp
#endif // RCLCPP__QOS_HPP_

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

@@ -189,10 +189,10 @@ public:
TRACEPOINT(
rclcpp_timer_callback_added,
static_cast<const void *>(get_timer_handle().get()),
static_cast<const void *>(&callback_));
reinterpret_cast<const void *>(&callback_));
TRACEPOINT(
rclcpp_callback_register,
static_cast<const void *>(&callback_),
reinterpret_cast<const void *>(&callback_),
tracetools::get_symbol(callback_));
}
@@ -226,9 +226,9 @@ public:
void
execute_callback() override
{
TRACEPOINT(callback_start, static_cast<const void *>(&callback_), false);
TRACEPOINT(callback_start, reinterpret_cast<const void *>(&callback_), false);
execute_callback_delegate<>();
TRACEPOINT(callback_end, static_cast<const void *>(&callback_));
TRACEPOINT(callback_end, reinterpret_cast<const void *>(&callback_));
}
// void specialization

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.0.1</version>
<version>17.0.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

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

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

@@ -133,9 +133,13 @@ ParameterEventHandler::get_parameter_from_event(
{
rclcpp::Parameter p;
if (!get_parameter_from_event(event, p, parameter_name, node_name)) {
throw std::runtime_error(
"Parameter '" + parameter_name + "' of node '" + node_name +
"' is not part of parameter event");
if (event.node == node_name) {
return rclcpp::Parameter(parameter_name, rclcpp::PARAMETER_NOT_SET);
} else {
throw std::runtime_error(
"The node name '" + node_name + "' of parameter '" + parameter_name +
+"' doesn't match the node name '" + event.node + "' in parameter event");
}
}
return p;
}

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

@@ -150,6 +150,12 @@ QoS::best_effort()
return this->reliability(RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT);
}
QoS &
QoS::reliability_best_available()
{
return this->reliability(RMW_QOS_POLICY_RELIABILITY_BEST_AVAILABLE);
}
QoS &
QoS::durability(rmw_qos_durability_policy_t durability)
{
@@ -176,6 +182,12 @@ QoS::transient_local()
return this->durability(RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL);
}
QoS &
QoS::durability_best_available()
{
return this->durability(RMW_QOS_POLICY_DURABILITY_BEST_AVAILABLE);
}
QoS &
QoS::deadline(rmw_time_t deadline)
{
@@ -380,4 +392,8 @@ SystemDefaultsQoS::SystemDefaultsQoS(const QoSInitialization & qos_initializatio
: QoS(qos_initialization, rmw_qos_profile_system_default)
{}
BestAvailableQoS::BestAvailableQoS(const QoSInitialization & qos_initialization)
: QoS(qos_initialization, rmw_qos_profile_best_available)
{}
} // namespace rclcpp

View File

@@ -299,7 +299,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

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

@@ -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");
@@ -116,3 +116,80 @@ TEST(TestCreateTimer, call_wall_timer_with_bad_arguments)
std::invalid_argument);
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)
{
rclcpp::init(0, nullptr);
auto node = std::make_shared<rclcpp::Node>("timer_function_pointer_node");
// make sure build succeeds with function pointer instead of lambda
auto some_timer = rclcpp::create_timer(
node,
node->get_clock(),
rclcpp::Duration(0ms),
test_timer_callback);
rclcpp::shutdown();
}

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

@@ -202,9 +202,17 @@ TEST_F(TestNode, GetParameterFromEvent)
EXPECT_THROW(
ParameterEventHandler::get_parameter_from_event(*multiple, "my_int", wrong_name),
std::runtime_error);
// Throws if parameter not part of event
// Parameter not part of event
// with correct node
rclcpp::Parameter expect_notset_ret("my_notset", rclcpp::PARAMETER_NOT_SET);
rclcpp::Parameter ret;
EXPECT_NO_THROW(
ret = ParameterEventHandler::get_parameter_from_event(*multiple, "my_notset", node_name););
EXPECT_EQ(ret, expect_notset_ret);
// with incorrect node
EXPECT_THROW(
ParameterEventHandler::get_parameter_from_event(*diff_ns_bool, "my_int", node_name),
ParameterEventHandler::get_parameter_from_event(*multiple, "my_notset", wrong_name),
std::runtime_error);
}

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

@@ -93,6 +93,9 @@ TEST(TestQoS, setters_and_getters) {
qos.reliable();
EXPECT_EQ(rclcpp::ReliabilityPolicy::Reliable, qos.reliability());
qos.reliability_best_available();
EXPECT_EQ(rclcpp::ReliabilityPolicy::BestAvailable, qos.reliability());
qos.reliability(rclcpp::ReliabilityPolicy::BestEffort);
EXPECT_EQ(rclcpp::ReliabilityPolicy::BestEffort, qos.reliability());
@@ -102,6 +105,9 @@ TEST(TestQoS, setters_and_getters) {
qos.transient_local();
EXPECT_EQ(rclcpp::DurabilityPolicy::TransientLocal, qos.durability());
qos.durability_best_available();
EXPECT_EQ(rclcpp::DurabilityPolicy::BestAvailable, qos.durability());
qos.durability(rclcpp::DurabilityPolicy::Volatile);
EXPECT_EQ(rclcpp::DurabilityPolicy::Volatile, qos.durability());
@@ -183,6 +189,9 @@ TEST(TestQoS, DerivedTypes) {
const rclcpp::KeepLast expected_initialization(RMW_QOS_POLICY_DEPTH_SYSTEM_DEFAULT);
const rclcpp::QoS expected_default(expected_initialization);
EXPECT_EQ(expected_default.get_rmw_qos_profile(), system_default_qos.get_rmw_qos_profile());
rclcpp::BestAvailableQoS best_available_qos;
EXPECT_EQ(rmw_qos_profile_best_available, best_available_qos.get_rmw_qos_profile());
}
TEST(TestQoS, policy_name_from_kind) {

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,18 @@ Changelog for package rclcpp_action
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
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)
-------------------
16.1.0 (2022-04-29)
-------------------
16.0.1 (2022-04-13)
-------------------

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.0.1</version>
<version>17.0.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

@@ -2,6 +2,18 @@
Changelog for package rclcpp_components
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
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)
-------------------
16.1.0 (2022-04-29)
-------------------
16.0.1 (2022-04-13)
-------------------

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.0.1</version>
<version>17.0.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

@@ -3,6 +3,22 @@ Changelog for package rclcpp_lifecycle
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
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)
-------------------
16.1.0 (2022-04-29)
-------------------
16.0.1 (2022-04-13)
-------------------

View File

@@ -109,6 +109,22 @@ if(BUILD_TESTING)
)
target_link_libraries(test_lifecycle_service_client ${PROJECT_NAME} mimick)
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

View File

@@ -242,7 +242,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 +255,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 +318,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 +551,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 +586,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 +616,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

View File

@@ -22,6 +22,7 @@
#include <vector>
#include "rclcpp/contexts/default_context.hpp"
#include "rclcpp/create_client.hpp"
#include "rclcpp/create_generic_publisher.hpp"
#include "rclcpp/create_generic_subscription.hpp"
#include "rclcpp/create_publisher.hpp"
@@ -89,11 +90,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 +121,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 +151,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(

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_lifecycle</name>
<version>16.0.1</version>
<version>17.0.0</version>
<description>Package containing a prototype for lifecycle implementation</description>
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
<maintainer email="jacob@openrobotics.org">Jacob Perron</maintainer>

View File

@@ -283,12 +283,31 @@ LifecycleNode::list_parameters(
return node_parameters_->list_parameters(prefixes, depth);
}
rclcpp::Node::PreSetParametersCallbackHandle::SharedPtr
LifecycleNode::add_pre_set_parameters_callback(PreSetParametersCallbackType callback)
{
return node_parameters_->add_pre_set_parameters_callback(callback);
}
rclcpp::Node::OnSetParametersCallbackHandle::SharedPtr
LifecycleNode::add_on_set_parameters_callback(OnParametersSetCallbackType callback)
LifecycleNode::add_on_set_parameters_callback(OnSetParametersCallbackType callback)
{
return node_parameters_->add_on_set_parameters_callback(callback);
}
rclcpp::Node::PostSetParametersCallbackHandle::SharedPtr
LifecycleNode::add_post_set_parameters_callback(PostSetParametersCallbackType callback)
{
return node_parameters_->add_post_set_parameters_callback(callback);
}
void
LifecycleNode::remove_pre_set_parameters_callback(
const PreSetParametersCallbackHandle * const callback)
{
node_parameters_->remove_pre_set_parameters_callback(callback);
}
void
LifecycleNode::remove_on_set_parameters_callback(
const OnSetParametersCallbackHandle * const callback)
@@ -296,6 +315,13 @@ LifecycleNode::remove_on_set_parameters_callback(
node_parameters_->remove_on_set_parameters_callback(callback);
}
void
LifecycleNode::remove_post_set_parameters_callback(
const PostSetParametersCallbackHandle * const callback)
{
node_parameters_->remove_post_set_parameters_callback(callback);
}
std::vector<std::string>
LifecycleNode::get_node_names() const
{

View File

@@ -0,0 +1,143 @@
// Copyright 2022 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <gtest/gtest.h>
#include <string>
#include <memory>
#include <utility>
#include "rclcpp/exceptions.hpp"
#include "rclcpp/rclcpp.hpp"
#include "rclcpp_lifecycle/lifecycle_node.hpp"
#include "rcl_interfaces/srv/list_parameters.hpp"
class TestClient : public ::testing::Test
{
protected:
static void SetUpTestCase()
{
rclcpp::init(0, nullptr);
}
static void TearDownTestCase()
{
rclcpp::shutdown();
}
void SetUp()
{
node_ = std::make_shared<rclcpp_lifecycle::LifecycleNode>("my_lifecycle_node", "/ns");
}
void TearDown()
{
node_.reset();
}
rclcpp_lifecycle::LifecycleNode::SharedPtr node_;
};
/*
Testing client construction and destruction.
*/
TEST_F(TestClient, construction_and_destruction) {
using rcl_interfaces::srv::ListParameters;
{
auto client = node_->create_client<ListParameters>("service");
EXPECT_TRUE(client);
}
{
// 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);
EXPECT_TRUE(client);
// 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());
EXPECT_TRUE(client);
}
{
ASSERT_THROW(
{
auto client = node_->create_client<ListParameters>("invalid_service?");
}, rclcpp::exceptions::InvalidServiceNameError);
}
}
TEST_F(TestClient, construction_with_free_function) {
{
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",
rmw_qos_profile_services_default,
nullptr);
EXPECT_TRUE(client);
}
{
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",
rmw_qos_profile_services_default,
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);
EXPECT_TRUE(client);
}
{
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);
}
}

View File

@@ -42,10 +42,17 @@ protected:
}
};
/// We want to test everything for both the wall and generic timer.
enum class TimerType
{
WALL_TIMER,
GENERIC_TIMER,
};
class EmptyLifecycleNode : public rclcpp_lifecycle::LifecycleNode
{
public:
explicit EmptyLifecycleNode(const std::string & node_name)
explicit EmptyLifecycleNode(const std::string & node_name, const TimerType & timer_type)
: rclcpp_lifecycle::LifecycleNode(node_name)
{
rclcpp::PublisherOptionsWithAllocator<std::allocator<void>> options;
@@ -55,8 +62,20 @@ public:
add_managed_entity(publisher_);
// For coverage this is being added here
auto timer = create_wall_timer(std::chrono::seconds(1), []() {});
add_timer_handle(timer);
switch (timer_type) {
case TimerType::WALL_TIMER:
{
auto timer = create_wall_timer(std::chrono::seconds(1), []() {});
add_timer_handle(timer);
break;
}
case TimerType::GENERIC_TIMER:
{
auto timer = create_timer(std::chrono::seconds(1), []() {});
add_timer_handle(timer);
break;
}
}
}
std::shared_ptr<rclcpp_lifecycle::LifecyclePublisher<test_msgs::msg::Empty>> publisher()
@@ -68,13 +87,13 @@ private:
std::shared_ptr<rclcpp_lifecycle::LifecyclePublisher<test_msgs::msg::Empty>> publisher_;
};
class TestLifecyclePublisher : public ::testing::Test
class TestLifecyclePublisher : public ::testing::TestWithParam<TimerType>
{
public:
void SetUp()
{
rclcpp::init(0, nullptr);
node_ = std::make_shared<EmptyLifecycleNode>("node");
node_ = std::make_shared<EmptyLifecycleNode>("node", GetParam());
}
void TearDown()
@@ -86,7 +105,7 @@ protected:
std::shared_ptr<EmptyLifecycleNode> node_;
};
TEST_F(TestLifecyclePublisher, publish_managed_by_node) {
TEST_P(TestLifecyclePublisher, publish_managed_by_node) {
// transition via LifecycleNode
auto success = rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn::SUCCESS;
auto reset_key = rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn::ERROR;
@@ -125,7 +144,7 @@ TEST_F(TestLifecyclePublisher, publish_managed_by_node) {
}
}
TEST_F(TestLifecyclePublisher, publish) {
TEST_P(TestLifecyclePublisher, publish) {
// transition via LifecyclePublisher
node_->publisher()->on_deactivate();
EXPECT_FALSE(node_->publisher()->is_activated());
@@ -148,3 +167,19 @@ TEST_F(TestLifecyclePublisher, publish) {
EXPECT_NO_THROW(node_->publisher()->publish(std::move(msg_ptr)));
}
}
INSTANTIATE_TEST_SUITE_P(
PerTimerType, TestLifecyclePublisher,
::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,100 @@
// Copyright 2022 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <gtest/gtest.h>
#include <string>
#include <memory>
#include <utility>
#include "rclcpp/exceptions.hpp"
#include "rclcpp/rclcpp.hpp"
#include "rclcpp_lifecycle/lifecycle_node.hpp"
#include "test_msgs/srv/empty.hpp"
using namespace std::chrono_literals;
class TestService : public ::testing::Test
{
protected:
static void SetUpTestCase()
{
rclcpp::init(0, nullptr);
}
static void TearDownTestCase()
{
rclcpp::shutdown();
}
void SetUp()
{
node = std::make_shared<rclcpp_lifecycle::LifecycleNode>("my_lifecycle_node", "/ns");
}
void TearDown()
{
node.reset();
}
rclcpp_lifecycle::LifecycleNode::SharedPtr node;
};
/*
Testing service construction and destruction.
*/
TEST_F(TestService, construction_and_destruction) {
using test_msgs::srv::Empty;
auto callback =
[](const Empty::Request::SharedPtr, Empty::Response::SharedPtr) {
};
{
auto service = node->create_service<Empty>("service", callback);
EXPECT_NE(nullptr, service->get_service_handle());
const rclcpp::ServiceBase * const_service_base = service.get();
EXPECT_NE(nullptr, const_service_base->get_service_handle());
}
{
// 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 service = node->create_service<Empty>(
"service", callback, rmw_qos_profile_services_default);
// remove warning suppression
#if !defined(_WIN32)
# pragma GCC diagnostic pop
#else // !defined(_WIN32)
# pragma warning(pop)
#endif
EXPECT_NE(nullptr, service->get_service_handle());
const rclcpp::ServiceBase * const_service_base = service.get();
EXPECT_NE(nullptr, const_service_base->get_service_handle());
}
{
ASSERT_THROW(
{
auto service = node->create_service<Empty>("invalid_service?", callback);
}, rclcpp::exceptions::InvalidServiceNameError);
}
}