Compare commits
5 Commits
irobot/eve
...
16.0.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ae8b033ae0 | ||
|
|
4fa3489cfd | ||
|
|
7f575103d8 | ||
|
|
166007dde3 | ||
|
|
cf2a27805e |
13
.github/workflows/mirror-rolling-to-master.yaml
vendored
13
.github/workflows/mirror-rolling-to-master.yaml
vendored
@@ -1,13 +0,0 @@
|
||||
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
|
||||
@@ -1,2 +0,0 @@
|
||||
# This file was generated by https://github.com/audrow/update-ros2-repos
|
||||
* @ivanpauno @hidmic @wjwwood
|
||||
@@ -8,8 +8,7 @@ rclcpp provides the standard C++ API for interacting with ROS 2.
|
||||
|
||||
`#include "rclcpp/rclcpp.hpp"` allows use of the most common elements of the ROS 2 system.
|
||||
|
||||
The link to the latest API documentation can be found on the rclcpp package info page, at the [ROS Index](https://index.ros.org/p/rclcpp/).
|
||||
|
||||
Visit the [rclcpp API documentation](http://docs.ros2.org/latest/api/rclcpp/) for a complete list of its main components.
|
||||
|
||||
### Examples
|
||||
|
||||
|
||||
@@ -2,106 +2,13 @@
|
||||
Changelog for package rclcpp
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
19.3.0 (2023-03-01)
|
||||
16.0.2 (2022-11-07)
|
||||
-------------------
|
||||
* Fix memory leak in tracetools::get_symbol() (`#2104 <https://github.com/ros2/rclcpp/issues/2104>`_)
|
||||
* Service introspection (`#1985 <https://github.com/ros2/rclcpp/issues/1985>`_)
|
||||
* Allow publishing borrowed messages with intra-process enabled (`#2108 <https://github.com/ros2/rclcpp/issues/2108>`_)
|
||||
* to fix flaky test about TestTimeSource.callbacks (`#2111 <https://github.com/ros2/rclcpp/issues/2111>`_)
|
||||
* Contributors: Brian, Chen Lihui, Christophe Bedard, Miguel Company
|
||||
|
||||
19.2.0 (2023-02-24)
|
||||
-------------------
|
||||
* to create a sublogger while getting child of Logger (`#1717 <https://github.com/ros2/rclcpp/issues/1717>`_)
|
||||
* Fix documentation of Context class (`#2107 <https://github.com/ros2/rclcpp/issues/2107>`_)
|
||||
* fixes for rmw callbacks in qos_event class (`#2102 <https://github.com/ros2/rclcpp/issues/2102>`_)
|
||||
* Contributors: Alberto Soragna, Chen Lihui, Silvio Traversaro
|
||||
|
||||
19.1.0 (2023-02-14)
|
||||
-------------------
|
||||
* Add support for timers on reset callback (`#1979 <https://github.com/ros2/rclcpp/issues/1979>`_)
|
||||
* Topic node guard condition in executor (`#2074 <https://github.com/ros2/rclcpp/issues/2074>`_)
|
||||
* Fix bug on the disorder of calling shutdown callback (`#2097 <https://github.com/ros2/rclcpp/issues/2097>`_)
|
||||
* Contributors: Barry Xu, Chen Lihui, mauropasse
|
||||
|
||||
19.0.0 (2023-01-30)
|
||||
-------------------
|
||||
* Add default constructor to NodeInterfaces (`#2094 <https://github.com/ros2/rclcpp/issues/2094>`_)
|
||||
* Fix clock state cached time to be a copy, not a reference. (`#2092 <https://github.com/ros2/rclcpp/issues/2092>`_)
|
||||
* Fix -Wmaybe-uninitialized warning (`#2081 <https://github.com/ros2/rclcpp/issues/2081>`_)
|
||||
* Fix the keep_last warning when using system defaults. (`#2082 <https://github.com/ros2/rclcpp/issues/2082>`_)
|
||||
* Add in a fix for older compilers. (`#2075 <https://github.com/ros2/rclcpp/issues/2075>`_)
|
||||
* Contributors: Alexander Hans, Chris Lalancette, Shane Loretz
|
||||
|
||||
18.0.0 (2022-12-29)
|
||||
-------------------
|
||||
* Implement Unified Node Interface (NodeInterfaces class) (`#2041 <https://github.com/ros2/rclcpp/issues/2041>`_)
|
||||
* Do not throw exception if trying to dequeue an empty intra-process buffer (`#2061 <https://github.com/ros2/rclcpp/issues/2061>`_)
|
||||
* Move event callback binding to PublisherBase and SubscriptionBase (`#2066 <https://github.com/ros2/rclcpp/issues/2066>`_)
|
||||
* Implement validity checks for rclcpp::Clock (`#2040 <https://github.com/ros2/rclcpp/issues/2040>`_)
|
||||
* Explicitly set callback type (`#2059 <https://github.com/ros2/rclcpp/issues/2059>`_)
|
||||
* Fix logging macros to build with msvc and cpp20 (`#2063 <https://github.com/ros2/rclcpp/issues/2063>`_)
|
||||
* Add clock type to node_options (`#1982 <https://github.com/ros2/rclcpp/issues/1982>`_)
|
||||
* Fix nullptr dereference in prune_requests_older_than (`#2008 <https://github.com/ros2/rclcpp/issues/2008>`_)
|
||||
* Remove templating on to_rcl_subscription_options (`#2056 <https://github.com/ros2/rclcpp/issues/2056>`_)
|
||||
* Fix SharedFuture from async_send_request never becoming valid (`#2044 <https://github.com/ros2/rclcpp/issues/2044>`_)
|
||||
* Add in a warning for a KeepLast depth of 0. (`#2048 <https://github.com/ros2/rclcpp/issues/2048>`_)
|
||||
* Mark rclcpp::Clock::now() as const (`#2050 <https://github.com/ros2/rclcpp/issues/2050>`_)
|
||||
* Fix a case that did not throw ParameterUninitializedException (`#2036 <https://github.com/ros2/rclcpp/issues/2036>`_)
|
||||
* Update maintainers (`#2043 <https://github.com/ros2/rclcpp/issues/2043>`_)
|
||||
* Contributors: Alberto Soragna, Audrow Nash, Chen Lihui, Chris Lalancette, Jeffery Hsu, Lei Liu, Mateusz Szczygielski, Shane Loretz, andrei, mauropasse, methylDragon
|
||||
|
||||
17.1.0 (2022-11-02)
|
||||
-------------------
|
||||
* MultiThreadExecutor number of threads is at least 2+ in default. (`#2032 <https://github.com/ros2/rclcpp/issues/2032>`_)
|
||||
* Fix bug that a callback not reached (`#1640 <https://github.com/ros2/rclcpp/issues/1640>`_)
|
||||
* Set the minimum number of threads of the Multithreaded executor to 2 (`#2030 <https://github.com/ros2/rclcpp/issues/2030>`_)
|
||||
* check thread whether joinable before join (`#2019 <https://github.com/ros2/rclcpp/issues/2019>`_)
|
||||
* Set cpplint test timeout to 3 minutes (`#2022 <https://github.com/ros2/rclcpp/issues/2022>`_)
|
||||
* Make sure to include-what-you-use in the node_interfaces. (`#2018 <https://github.com/ros2/rclcpp/issues/2018>`_)
|
||||
* Do not clear entities callbacks on destruction (`#2002 <https://github.com/ros2/rclcpp/issues/2002>`_)
|
||||
* fix mismatched issue if using zero_allocate (`#1995 <https://github.com/ros2/rclcpp/issues/1995>`_)
|
||||
* Contributors: Alexis Paques, Chen Lihui, Chris Lalancette, Cristóbal Arroyo, Tomoya Fujita, mauropasse, uupks
|
||||
|
||||
17.0.0 (2022-09-13)
|
||||
-------------------
|
||||
* Make ParameterService and Sync/AsyncParameterClient accept rclcpp::QoS (`#1978 <https://github.com/ros2/rclcpp/issues/1978>`_)
|
||||
* support regex match for parameter client (`#1992 <https://github.com/ros2/rclcpp/issues/1992>`_)
|
||||
* operator+= and operator-= for Duration (`#1988 <https://github.com/ros2/rclcpp/issues/1988>`_)
|
||||
* Revert "Revert "Add a create_timer method to Node and `LifecycleNode` classes (`#1975 <https://github.com/ros2/rclcpp/issues/1975>`_)" (`#2009 <https://github.com/ros2/rclcpp/issues/2009>`_) (`#2010 <https://github.com/ros2/rclcpp/issues/2010>`_)
|
||||
* force compiler warning if callback handles not captured (`#2000 <https://github.com/ros2/rclcpp/issues/2000>`_)
|
||||
* Revert "Add a `create_timer` method to `Node` and `LifecycleNode` classes (`#1975 <https://github.com/ros2/rclcpp/issues/1975>`_)" (`#2009 <https://github.com/ros2/rclcpp/issues/2009>`_)
|
||||
* Add a `create_timer` method to `Node` and `LifecycleNode` classes (`#1975 <https://github.com/ros2/rclcpp/issues/1975>`_)
|
||||
* [docs] add note about callback lifetime for {on, post}_set_parameter_callback (`#1981 <https://github.com/ros2/rclcpp/issues/1981>`_)
|
||||
* fix memory leak (`#1994 <https://github.com/ros2/rclcpp/issues/1994>`_)
|
||||
* Support pre-set and post-set parameter callbacks in addition to on-set-parameter-callback. (`#1947 <https://github.com/ros2/rclcpp/issues/1947>`_)
|
||||
* Make create_service accept rclcpp::QoS (`#1969 <https://github.com/ros2/rclcpp/issues/1969>`_)
|
||||
* Make create_client accept rclcpp::QoS (`#1964 <https://github.com/ros2/rclcpp/issues/1964>`_)
|
||||
* Fix the documentation for rclcpp::ok to be accurate. (`#1965 <https://github.com/ros2/rclcpp/issues/1965>`_)
|
||||
* use regex for wildcard matching (`#1839 <https://github.com/ros2/rclcpp/issues/1839>`_)
|
||||
* Revert "Introduce executors new spin_for method, replace spin_until_future_complete with spin_until_complete. (`#1821 <https://github.com/ros2/rclcpp/issues/1821>`_) (`#1874 <https://github.com/ros2/rclcpp/issues/1874>`_)" (`#1956 <https://github.com/ros2/rclcpp/issues/1956>`_)
|
||||
* Introduce executors new spin_for method, replace spin_until_future_complete with spin_until_complete. (`#1821 <https://github.com/ros2/rclcpp/issues/1821>`_) (`#1874 <https://github.com/ros2/rclcpp/issues/1874>`_)
|
||||
* test adjustment for LoanedMessage. (`#1951 <https://github.com/ros2/rclcpp/issues/1951>`_)
|
||||
* fix virtual dispatch issues identified by clang-tidy (`#1816 <https://github.com/ros2/rclcpp/issues/1816>`_)
|
||||
* Remove unused on_parameters_set_callback\_ (`#1945 <https://github.com/ros2/rclcpp/issues/1945>`_)
|
||||
* Fix subscription.is_serialized() for callbacks with message info (`#1950 <https://github.com/ros2/rclcpp/issues/1950>`_)
|
||||
* wait for subscriptions on another thread. (`#1940 <https://github.com/ros2/rclcpp/issues/1940>`_)
|
||||
* Fix documentation of `RCLCPP\_[INFO,WARN,...]` (`#1943 <https://github.com/ros2/rclcpp/issues/1943>`_)
|
||||
* Always trigger guard condition waitset (`#1923 <https://github.com/ros2/rclcpp/issues/1923>`_)
|
||||
* Add statistics for handle_loaned_message (`#1927 <https://github.com/ros2/rclcpp/issues/1927>`_)
|
||||
* Drop wrong template specialization (`#1926 <https://github.com/ros2/rclcpp/issues/1926>`_)
|
||||
* Contributors: Alberto Soragna, Andrew Symington, Barry Xu, Brian, Chen Lihui, Chris Lalancette, Daniel Reuter, Deepanshu Bansal, Hubert Liberacki, Ivan Santiago Paunovic, Jochen Sprickerhof, Nikolai Morin, Shane Loretz, Tomoya Fujita, Tyler Weaver, William Woodall, schrodinbug
|
||||
|
||||
16.2.0 (2022-05-03)
|
||||
-------------------
|
||||
* Update get_parameter_from_event to follow the function description (`#1922 <https://github.com/ros2/rclcpp/issues/1922>`_)
|
||||
* Add 'best available' QoS enum values and methods (`#1920 <https://github.com/ros2/rclcpp/issues/1920>`_)
|
||||
* Contributors: Barry Xu, Jacob Perron
|
||||
|
||||
16.1.0 (2022-04-29)
|
||||
-------------------
|
||||
* use reinterpret_cast for function pointer conversion. (`#1919 <https://github.com/ros2/rclcpp/issues/1919>`_)
|
||||
* Contributors: Tomoya Fujita
|
||||
* fix mismatched issue if using zero_allocate (`#1995 <https://github.com/ros2/rclcpp/issues/1995>`_) (`#2026 <https://github.com/ros2/rclcpp/issues/2026>`_)
|
||||
* use regex for wildcard matching (backport `#1839 <https://github.com/ros2/rclcpp/issues/1839>`_) (`#1986 <https://github.com/ros2/rclcpp/issues/1986>`_)
|
||||
* Drop wrong template specialization (`#1926 <https://github.com/ros2/rclcpp/issues/1926>`_) (`#1937 <https://github.com/ros2/rclcpp/issues/1937>`_)
|
||||
* Add statistics for handle_loaned_message (`#1927 <https://github.com/ros2/rclcpp/issues/1927>`_) (`#1932 <https://github.com/ros2/rclcpp/issues/1932>`_)
|
||||
* Contributors: mergify[bot]
|
||||
|
||||
16.0.1 (2022-04-13)
|
||||
-------------------
|
||||
|
||||
@@ -25,7 +25,6 @@ find_package(tracetools REQUIRED)
|
||||
# Default to C++17
|
||||
if(NOT CMAKE_CXX_STANDARD)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
endif()
|
||||
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
# About -Wno-sign-conversion: With Clang, -Wconversion implies -Wsign-conversion. There are a number of
|
||||
@@ -51,9 +50,6 @@ set(${PROJECT_NAME}_SRCS
|
||||
src/rclcpp/duration.cpp
|
||||
src/rclcpp/event.cpp
|
||||
src/rclcpp/exceptions/exceptions.cpp
|
||||
src/rclcpp/experimental/executors/events_executor/events_executor_entities_collector.cpp
|
||||
src/rclcpp/experimental/executors/events_executor/events_executor.cpp
|
||||
src/rclcpp/experimental/timers_manager.cpp
|
||||
src/rclcpp/executable_list.cpp
|
||||
src/rclcpp/executor.cpp
|
||||
src/rclcpp/executors.cpp
|
||||
@@ -96,7 +92,7 @@ set(${PROJECT_NAME}_SRCS
|
||||
src/rclcpp/parameter_value.cpp
|
||||
src/rclcpp/publisher_base.cpp
|
||||
src/rclcpp/qos.cpp
|
||||
src/rclcpp/event_handler.cpp
|
||||
src/rclcpp/qos_event.cpp
|
||||
src/rclcpp/qos_overriding_options.cpp
|
||||
src/rclcpp/serialization.cpp
|
||||
src/rclcpp/serialized_message.cpp
|
||||
@@ -263,8 +259,4 @@ if(TEST cppcheck)
|
||||
set_tests_properties(cppcheck PROPERTIES TIMEOUT 500)
|
||||
endif()
|
||||
|
||||
if(TEST cpplint)
|
||||
set_tests_properties(cpplint PROPERTIES TIMEOUT 180)
|
||||
endif()
|
||||
|
||||
ament_generate_version_header(${PROJECT_NAME})
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 164 KiB |
@@ -1,29 +0,0 @@
|
||||
# Proposed node parameters callback Design
|
||||
|
||||
## Introduction:
|
||||
|
||||
The original requirement came in **gazebo_ros_pkgs** for setting individual wheel slip parameters based on global wheel slip value [link to original issue](https://github.com/ros-simulation/gazebo_ros_pkgs/pull/1365).
|
||||
|
||||
The main requirement is to set one or more parameters after another parameter is set successfully.
|
||||
|
||||
Additionally, it would be nice if users could be notified locally (via a callback) when parameters have been set successfully (i.e. post validation).
|
||||
|
||||
Related discussion can be found in [#609](https://github.com/ros2/rclcpp/issues/609) [#1789](https://github.com/ros2/rclcpp/pull/1789)
|
||||
|
||||
With the current parameters API, the `add_on_set_parameters_callback` is intended for validation of parameter values before they are set, it should **not** cause any side-effects.
|
||||
|
||||
There is also the `ParameterEventHandler` that publishes changes to node parameters on `/parameter_events` topic for external nodes to see. Though the node could subscribe to the `/parameter_events` topic to be notified of changes to its own parameters, it is less than ideal since there is a delay caused by waiting for an executor to process the callback.
|
||||
|
||||
We propose adding a `PostSetParametersCallbackHandle` for successful parameter set similar to `OnSetParametersCallbackHandle` for parameter validation. Also, we propose adding a `PreSetParametersCallbackHandle` useful for modifying list of parameters being set.
|
||||
|
||||
The validation callback is often abused to trigger side effects in the code, for instance updating class attributes even before a parameter has been set successfully. Instead of relying on the `/parameter_events` topic to be notified of parameter changes, users can register a callback with a new API, `add_post_set_parameters_callback`.
|
||||
|
||||
It is possible to use the proposed `add_post_set_parameters_callback` for setting additional parameters, but this might result in infinite recursion and does not allow those additional parameters to be set atomically with the original parameter(s) changed.
|
||||
To workaround these issues, we propose adding a "pre set" callback type that can be registered with `add_pre_set_parameters_callback`, which will be triggered before the validation callbacks and can be used to modify the parameter list.
|
||||
|
||||

|
||||
|
||||
## Alternatives
|
||||
|
||||
* Users could call `set_parameter` while processing a message from the `/parameter_events` topic, however, there is extra overhead in having to create subscription (as noted earlier).
|
||||
* Users could call `set_parameter` inside the "on set" parameters callback, however it is not well-defined how side-effects should handle cases where parameter validation fails.
|
||||
@@ -191,14 +191,10 @@ public:
|
||||
#ifndef TRACETOOLS_DISABLED
|
||||
std::visit(
|
||||
[this](auto && arg) {
|
||||
if (TRACEPOINT_ENABLED(rclcpp_callback_register)) {
|
||||
char * symbol = tracetools::get_symbol(arg);
|
||||
DO_TRACEPOINT(
|
||||
rclcpp_callback_register,
|
||||
static_cast<const void *>(this),
|
||||
symbol);
|
||||
std::free(symbol);
|
||||
}
|
||||
TRACEPOINT(
|
||||
rclcpp_callback_register,
|
||||
static_cast<const void *>(this),
|
||||
tracetools::get_symbol(arg));
|
||||
}, callback_);
|
||||
#endif // TRACETOOLS_DISABLED
|
||||
}
|
||||
|
||||
@@ -950,13 +950,7 @@ 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<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_);
|
||||
std::holds_alternative<SharedPtrSerializedMessageCallback>(callback_variant_);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -965,14 +959,10 @@ public:
|
||||
#ifndef TRACETOOLS_DISABLED
|
||||
std::visit(
|
||||
[this](auto && callback) {
|
||||
if (TRACEPOINT_ENABLED(rclcpp_callback_register)) {
|
||||
char * symbol = tracetools::get_symbol(callback);
|
||||
DO_TRACEPOINT(
|
||||
rclcpp_callback_register,
|
||||
static_cast<const void *>(this),
|
||||
symbol);
|
||||
std::free(symbol);
|
||||
}
|
||||
TRACEPOINT(
|
||||
rclcpp_callback_register,
|
||||
static_cast<const void *>(this),
|
||||
tracetools::get_symbol(callback));
|
||||
}, callback_variant_);
|
||||
#endif // TRACETOOLS_DISABLED
|
||||
}
|
||||
|
||||
@@ -16,14 +16,11 @@
|
||||
#define RCLCPP__CALLBACK_GROUP_HPP_
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "rclcpp/client.hpp"
|
||||
#include "rclcpp/context.hpp"
|
||||
#include "rclcpp/guard_condition.hpp"
|
||||
#include "rclcpp/publisher_base.hpp"
|
||||
#include "rclcpp/service.hpp"
|
||||
#include "rclcpp/subscription_base.hpp"
|
||||
@@ -98,10 +95,6 @@ public:
|
||||
CallbackGroupType group_type,
|
||||
bool automatically_add_to_executor_with_node = true);
|
||||
|
||||
/// Default destructor.
|
||||
RCLCPP_PUBLIC
|
||||
~CallbackGroup();
|
||||
|
||||
template<typename Function>
|
||||
rclcpp::SubscriptionBase::SharedPtr
|
||||
find_subscription_ptrs_if(Function func) const
|
||||
@@ -178,16 +171,6 @@ public:
|
||||
bool
|
||||
automatically_add_to_executor_with_node() const;
|
||||
|
||||
/// Defer creating the notify guard condition and return it.
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::GuardCondition::SharedPtr
|
||||
get_notify_guard_condition(const rclcpp::Context::SharedPtr context_ptr);
|
||||
|
||||
/// Trigger the notify guard condition.
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
trigger_notify_guard_condition();
|
||||
|
||||
protected:
|
||||
RCLCPP_DISABLE_COPY(CallbackGroup)
|
||||
|
||||
@@ -230,9 +213,6 @@ protected:
|
||||
std::vector<rclcpp::Waitable::WeakPtr> waitable_ptrs_;
|
||||
std::atomic_bool can_be_taken_from_;
|
||||
const bool automatically_add_to_executor_with_node_;
|
||||
// defer the creation of the guard condition
|
||||
std::shared_ptr<rclcpp::GuardCondition> notify_guard_condition_ = nullptr;
|
||||
std::recursive_mutex notify_guard_condition_mutex_;
|
||||
|
||||
private:
|
||||
template<typename TypeT, typename Function>
|
||||
|
||||
@@ -16,15 +16,14 @@
|
||||
#define RCLCPP__CLIENT_HPP_
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <future>
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional> // NOLINT, cpplint doesn't think this is a cpp std header
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <variant> // NOLINT
|
||||
#include <vector>
|
||||
@@ -32,10 +31,8 @@
|
||||
#include "rcl/client.h"
|
||||
#include "rcl/error_handling.h"
|
||||
#include "rcl/event_callback.h"
|
||||
#include "rcl/service_introspection.h"
|
||||
#include "rcl/wait.h"
|
||||
|
||||
#include "rclcpp/clock.hpp"
|
||||
#include "rclcpp/detail/cpp_callback_trampoline.hpp"
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
#include "rclcpp/expand_topic_or_service_name.hpp"
|
||||
@@ -133,7 +130,7 @@ public:
|
||||
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual ~ClientBase() = default;
|
||||
virtual ~ClientBase();
|
||||
|
||||
/// Take the next response for this client as a type erased pointer.
|
||||
/**
|
||||
@@ -315,7 +312,7 @@ public:
|
||||
// This two-step setting, prevents a gap where the old std::function has
|
||||
// been replaced but the middleware hasn't been told about the new one yet.
|
||||
set_on_new_response_callback(
|
||||
rclcpp::detail::cpp_callback_trampoline<decltype(new_callback), const void *, size_t>,
|
||||
rclcpp::detail::cpp_callback_trampoline<const void *, size_t>,
|
||||
static_cast<const void *>(&new_callback));
|
||||
|
||||
// Store the std::function to keep it in scope, also overwrites the existing one.
|
||||
@@ -323,8 +320,7 @@ public:
|
||||
|
||||
// Set it again, now using the permanent storage.
|
||||
set_on_new_response_callback(
|
||||
rclcpp::detail::cpp_callback_trampoline<
|
||||
decltype(on_new_response_callback_), const void *, size_t>,
|
||||
rclcpp::detail::cpp_callback_trampoline<const void *, size_t>,
|
||||
static_cast<const void *>(&on_new_response_callback_));
|
||||
}
|
||||
|
||||
@@ -470,13 +466,15 @@ public:
|
||||
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph,
|
||||
const std::string & service_name,
|
||||
rcl_client_options_t & client_options)
|
||||
: ClientBase(node_base, node_graph),
|
||||
srv_type_support_handle_(rosidl_typesupport_cpp::get_service_type_support_handle<ServiceT>())
|
||||
: ClientBase(node_base, node_graph)
|
||||
{
|
||||
using rosidl_typesupport_cpp::get_service_type_support_handle;
|
||||
auto service_type_support_handle =
|
||||
get_service_type_support_handle<ServiceT>();
|
||||
rcl_ret_t ret = rcl_client_init(
|
||||
this->get_client_handle().get(),
|
||||
this->get_rcl_node_handle(),
|
||||
srv_type_support_handle_,
|
||||
service_type_support_handle,
|
||||
service_name.c_str(),
|
||||
&client_options);
|
||||
if (ret != RCL_RET_OK) {
|
||||
@@ -771,9 +769,7 @@ public:
|
||||
auto old_size = pending_requests_.size();
|
||||
for (auto it = pending_requests_.begin(), last = pending_requests_.end(); it != last; ) {
|
||||
if (it->second.first < time_point) {
|
||||
if (pruned_requests) {
|
||||
pruned_requests->push_back(it->first);
|
||||
}
|
||||
pruned_requests->push_back(it->first);
|
||||
it = pending_requests_.erase(it);
|
||||
} else {
|
||||
++it;
|
||||
@@ -782,33 +778,6 @@ public:
|
||||
return old_size - pending_requests_.size();
|
||||
}
|
||||
|
||||
/// Configure client introspection.
|
||||
/**
|
||||
* \param[in] clock clock to use to generate introspection timestamps
|
||||
* \param[in] qos_service_event_pub QoS settings to use when creating the introspection publisher
|
||||
* \param[in] introspection_state the state to set introspection to
|
||||
*/
|
||||
void
|
||||
configure_introspection(
|
||||
Clock::SharedPtr clock, const QoS & qos_service_event_pub,
|
||||
rcl_service_introspection_state_t introspection_state)
|
||||
{
|
||||
rcl_publisher_options_t pub_opts = rcl_publisher_get_default_options();
|
||||
pub_opts.qos = qos_service_event_pub.get_rmw_qos_profile();
|
||||
|
||||
rcl_ret_t ret = rcl_client_configure_service_introspection(
|
||||
client_handle_.get(),
|
||||
node_handle_.get(),
|
||||
clock->get_clock_handle(),
|
||||
srv_type_support_handle_,
|
||||
pub_opts,
|
||||
introspection_state);
|
||||
|
||||
if (RCL_RET_OK != ret) {
|
||||
rclcpp::exceptions::throw_from_rcl_error(ret, "failed to configure client introspection");
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
using CallbackTypeValueVariant = std::tuple<CallbackType, SharedFuture, Promise>;
|
||||
using CallbackWithRequestTypeValueVariant = std::tuple<
|
||||
@@ -823,14 +792,16 @@ protected:
|
||||
async_send_request_impl(const Request & request, CallbackInfoVariant value)
|
||||
{
|
||||
int64_t sequence_number;
|
||||
std::lock_guard<std::mutex> lock(pending_requests_mutex_);
|
||||
rcl_ret_t ret = rcl_send_request(get_client_handle().get(), &request, &sequence_number);
|
||||
if (RCL_RET_OK != ret) {
|
||||
rclcpp::exceptions::throw_from_rcl_error(ret, "failed to send request");
|
||||
}
|
||||
pending_requests_.try_emplace(
|
||||
sequence_number,
|
||||
std::make_pair(std::chrono::system_clock::now(), std::move(value)));
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(pending_requests_mutex_);
|
||||
pending_requests_.try_emplace(
|
||||
sequence_number,
|
||||
std::make_pair(std::chrono::system_clock::now(), std::move(value)));
|
||||
}
|
||||
return sequence_number;
|
||||
}
|
||||
|
||||
@@ -859,9 +830,6 @@ protected:
|
||||
CallbackInfoVariant>>
|
||||
pending_requests_;
|
||||
std::mutex pending_requests_mutex_;
|
||||
|
||||
private:
|
||||
const rosidl_service_type_support_t * srv_type_support_handle_;
|
||||
};
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
@@ -77,7 +77,7 @@ public:
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
Time
|
||||
now() const;
|
||||
now();
|
||||
|
||||
/**
|
||||
* Sleep until a specified Time, according to clock type.
|
||||
@@ -137,51 +137,6 @@ public:
|
||||
Duration rel_time,
|
||||
Context::SharedPtr context = contexts::get_global_default_context());
|
||||
|
||||
/**
|
||||
* Check if the clock is started.
|
||||
*
|
||||
* A started clock is a clock that reflects non-zero time.
|
||||
* Typically a clock will be unstarted if it is using RCL_ROS_TIME with ROS time and
|
||||
* nothing has been published on the clock topic yet.
|
||||
*
|
||||
* \return true if clock is started
|
||||
* \throws std::runtime_error if the clock is not rcl_clock_valid
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
started();
|
||||
|
||||
/**
|
||||
* Wait until clock to start.
|
||||
*
|
||||
* \rclcpp::Clock::started
|
||||
* \param context the context to wait in
|
||||
* \return true if clock was already started or became started
|
||||
* \throws std::runtime_error if the context is invalid or clock is not rcl_clock_valid
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
wait_until_started(Context::SharedPtr context = contexts::get_global_default_context());
|
||||
|
||||
/**
|
||||
* Wait for clock to start, with timeout.
|
||||
*
|
||||
* The timeout is waited in steady time.
|
||||
*
|
||||
* \rclcpp::Clock::started
|
||||
* \param timeout the maximum time to wait for.
|
||||
* \param context the context to wait in.
|
||||
* \param wait_tick_ns the time to wait between each iteration of the wait loop (in nanoseconds).
|
||||
* \return true if clock was or became valid
|
||||
* \throws std::runtime_error if the context is invalid or clock is not rcl_clock_valid
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
wait_until_started(
|
||||
const rclcpp::Duration & timeout,
|
||||
Context::SharedPtr context = contexts::get_global_default_context(),
|
||||
const rclcpp::Duration & wait_tick_ns = rclcpp::Duration(0, static_cast<uint32_t>(1e7)));
|
||||
|
||||
/**
|
||||
* Returns the clock of the type `RCL_ROS_TIME` is active.
|
||||
*
|
||||
|
||||
@@ -65,11 +65,8 @@ using PreShutdownCallbackHandle = ShutdownCallbackHandle;
|
||||
/// Context which encapsulates shared state between nodes and other similar entities.
|
||||
/**
|
||||
* A context also represents the lifecycle between init and shutdown of rclcpp.
|
||||
* Nodes may be attached to a particular context by passing to the rclcpp::Node
|
||||
* constructor a rclcpp::NodeOptions instance in which the Context is set via
|
||||
* rclcpp::NodeOptions::context.
|
||||
* Nodes will be automatically removed from the context when destructed.
|
||||
* Contexts may be shutdown by calling rclcpp::shutdown.
|
||||
* It is often used in conjunction with rclcpp::init, or rclcpp::init_local,
|
||||
* and rclcpp::shutdown.
|
||||
*/
|
||||
class Context : public std::enable_shared_from_this<Context>
|
||||
{
|
||||
@@ -186,11 +183,6 @@ 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
|
||||
@@ -326,6 +318,7 @@ public:
|
||||
|
||||
/// Interrupt any blocking sleep_for calls, causing them to return immediately and return true.
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
interrupt_all_sleep_for();
|
||||
|
||||
@@ -358,6 +351,7 @@ 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();
|
||||
|
||||
@@ -379,10 +373,10 @@ private:
|
||||
// attempt to acquire another sub context.
|
||||
std::recursive_mutex sub_contexts_mutex_;
|
||||
|
||||
std::vector<std::shared_ptr<OnShutdownCallback>> on_shutdown_callbacks_;
|
||||
std::unordered_set<std::shared_ptr<OnShutdownCallback>> on_shutdown_callbacks_;
|
||||
mutable std::mutex on_shutdown_callbacks_mutex_;
|
||||
|
||||
std::vector<std::shared_ptr<PreShutdownCallback>> pre_shutdown_callbacks_;
|
||||
std::unordered_set<std::shared_ptr<PreShutdownCallback>> pre_shutdown_callbacks_;
|
||||
mutable std::mutex pre_shutdown_callbacks_mutex_;
|
||||
|
||||
/// Condition variable for timed sleep (see sleep_for).
|
||||
@@ -401,22 +395,20 @@ private:
|
||||
|
||||
using ShutdownCallback = ShutdownCallbackHandle::ShutdownCallbackType;
|
||||
|
||||
template<ShutdownType shutdown_type>
|
||||
RCLCPP_LOCAL
|
||||
ShutdownCallbackHandle
|
||||
add_shutdown_callback(
|
||||
ShutdownType shutdown_type,
|
||||
ShutdownCallback callback);
|
||||
|
||||
template<ShutdownType shutdown_type>
|
||||
RCLCPP_LOCAL
|
||||
bool
|
||||
remove_shutdown_callback(
|
||||
ShutdownType shutdown_type,
|
||||
const ShutdownCallbackHandle & callback_handle);
|
||||
|
||||
template<ShutdownType shutdown_type>
|
||||
RCLCPP_LOCAL
|
||||
std::vector<rclcpp::Context::ShutdownCallback>
|
||||
get_shutdown_callback() const;
|
||||
get_shutdown_callback(ShutdownType shutdown_type) const;
|
||||
};
|
||||
|
||||
/// Return a copy of the list of context shared pointers.
|
||||
|
||||
@@ -20,40 +20,10 @@
|
||||
|
||||
#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
|
||||
|
||||
@@ -26,32 +26,6 @@
|
||||
|
||||
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
|
||||
|
||||
@@ -23,29 +23,85 @@
|
||||
|
||||
#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
|
||||
{
|
||||
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)
|
||||
{
|
||||
/// Perform a safe cast to a timer period in nanoseconds
|
||||
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.
|
||||
/**
|
||||
*
|
||||
* \tparam DurationRepT
|
||||
* \tparam DurationT
|
||||
* \tparam CallbackT
|
||||
* \param period period to execute callback. This duration must be 0 <= period < nanoseconds::max()
|
||||
* \return period, expressed as chrono::duration::nanoseconds
|
||||
* \throws std::invalid_argument if period is negative or too large
|
||||
* \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
|
||||
*/
|
||||
template<typename DurationRepT, typename DurationT>
|
||||
std::chrono::nanoseconds
|
||||
safe_cast_to_period_in_ns(std::chrono::duration<DurationRepT, DurationT> period)
|
||||
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"};
|
||||
}
|
||||
|
||||
if (period < std::chrono::duration<DurationRepT, DurationT>::zero()) {
|
||||
throw std::invalid_argument{"timer period cannot be negative"};
|
||||
}
|
||||
@@ -76,135 +132,12 @@ safe_cast_to_period_in_ns(std::chrono::duration<DurationRepT, DurationT> period)
|
||||
"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_
|
||||
|
||||
@@ -41,7 +41,6 @@ namespace detail
|
||||
* so no exceptions should be thrown at this point, and doing so results in
|
||||
* undefined behavior.
|
||||
*
|
||||
* \tparam UserDataRealT Declared type of the passed function
|
||||
* \tparam UserDataT Deduced type based on what is passed for user data,
|
||||
* usually this type is either `void *` or `const void *`.
|
||||
* \tparam Args the arguments being passed to the callback
|
||||
@@ -51,7 +50,6 @@ namespace detail
|
||||
* \returns whatever the callback returns, if anything
|
||||
*/
|
||||
template<
|
||||
typename UserDataRealT,
|
||||
typename UserDataT,
|
||||
typename ... Args,
|
||||
typename ReturnT = void
|
||||
@@ -59,7 +57,7 @@ template<
|
||||
ReturnT
|
||||
cpp_callback_trampoline(UserDataT user_data, Args ... args) noexcept
|
||||
{
|
||||
auto & actual_callback = *static_cast<const UserDataRealT *>(user_data);
|
||||
auto & actual_callback = *reinterpret_cast<const std::function<ReturnT(Args...)> *>(user_data);
|
||||
return actual_callback(args ...);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
// Copyright 2022 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__DETAIL__TEMPLATE_CONTAINS_HPP_
|
||||
#define RCLCPP__DETAIL__TEMPLATE_CONTAINS_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
/// Template meta-function that checks if a given T is contained in the list Us.
|
||||
template<typename T, typename ... Us>
|
||||
struct template_contains;
|
||||
|
||||
template<typename ... Args>
|
||||
inline constexpr bool template_contains_v = template_contains<Args ...>::value;
|
||||
|
||||
template<typename T, typename NextT, typename ... Us>
|
||||
struct template_contains<T, NextT, Us ...>
|
||||
{
|
||||
enum { value = (std::is_same_v<T, NextT>|| template_contains_v<T, Us ...>)};
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct template_contains<T>
|
||||
{
|
||||
enum { value = false };
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__DETAIL__TEMPLATE_CONTAINS_HPP_
|
||||
@@ -1,49 +0,0 @@
|
||||
// Copyright 2022 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__DETAIL__TEMPLATE_UNIQUE_HPP_
|
||||
#define RCLCPP__DETAIL__TEMPLATE_UNIQUE_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "rclcpp/detail/template_contains.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
/// Template meta-function that checks if a given list Ts contains unique types.
|
||||
template<typename ... Ts>
|
||||
struct template_unique;
|
||||
|
||||
template<typename ... Args>
|
||||
inline constexpr bool template_unique_v = template_unique<Args ...>::value;
|
||||
|
||||
template<typename NextT, typename ... Ts>
|
||||
struct template_unique<NextT, Ts ...>
|
||||
{
|
||||
enum { value = !template_contains_v<NextT, Ts ...>&& template_unique_v<Ts ...>};
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct template_unique<T>
|
||||
{
|
||||
enum { value = true };
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__DETAIL__TEMPLATE_UNIQUE_HPP_
|
||||
@@ -92,13 +92,9 @@ 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
|
||||
@@ -110,9 +106,6 @@ 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.
|
||||
|
||||
@@ -1,311 +0,0 @@
|
||||
// Copyright 2019 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__EVENT_HANDLER_HPP_
|
||||
#define RCLCPP__EVENT_HANDLER_HPP_
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include "rcl/error_handling.h"
|
||||
#include "rcl/event_callback.h"
|
||||
#include "rmw/impl/cpp/demangle.hpp"
|
||||
#include "rmw/incompatible_qos_events_statuses.h"
|
||||
#include "rmw/events_statuses/incompatible_type.h"
|
||||
|
||||
#include "rcutils/logging_macros.h"
|
||||
|
||||
#include "rclcpp/detail/cpp_callback_trampoline.hpp"
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
#include "rclcpp/function_traits.hpp"
|
||||
#include "rclcpp/logging.hpp"
|
||||
#include "rclcpp/waitable.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
using QOSDeadlineRequestedInfo = rmw_requested_deadline_missed_status_t;
|
||||
using QOSDeadlineOfferedInfo = rmw_offered_deadline_missed_status_t;
|
||||
using QOSLivelinessChangedInfo = rmw_liveliness_changed_status_t;
|
||||
using QOSLivelinessLostInfo = rmw_liveliness_lost_status_t;
|
||||
using QOSMessageLostInfo = rmw_message_lost_status_t;
|
||||
using QOSOfferedIncompatibleQoSInfo = rmw_offered_qos_incompatible_event_status_t;
|
||||
using QOSRequestedIncompatibleQoSInfo = rmw_requested_qos_incompatible_event_status_t;
|
||||
|
||||
using IncompatibleTypeInfo = rmw_incompatible_type_status_t;
|
||||
using MatchedInfo = rmw_matched_status_t;
|
||||
|
||||
using QOSDeadlineRequestedCallbackType = std::function<void (QOSDeadlineRequestedInfo &)>;
|
||||
using QOSDeadlineOfferedCallbackType = std::function<void (QOSDeadlineOfferedInfo &)>;
|
||||
using QOSLivelinessChangedCallbackType = std::function<void (QOSLivelinessChangedInfo &)>;
|
||||
using QOSLivelinessLostCallbackType = std::function<void (QOSLivelinessLostInfo &)>;
|
||||
using QOSMessageLostCallbackType = std::function<void (QOSMessageLostInfo &)>;
|
||||
using QOSOfferedIncompatibleQoSCallbackType = std::function<void (QOSOfferedIncompatibleQoSInfo &)>;
|
||||
using QOSRequestedIncompatibleQoSCallbackType =
|
||||
std::function<void (QOSRequestedIncompatibleQoSInfo &)>;
|
||||
|
||||
using IncompatibleTypeCallbackType = std::function<void (IncompatibleTypeInfo &)>;
|
||||
using PublisherMatchedCallbackType = std::function<void (MatchedInfo &)>;
|
||||
using SubscriptionMatchedCallbackType = std::function<void (MatchedInfo &)>;
|
||||
|
||||
/// Contains callbacks for various types of events a Publisher can receive from the middleware.
|
||||
struct PublisherEventCallbacks
|
||||
{
|
||||
QOSDeadlineOfferedCallbackType deadline_callback;
|
||||
QOSLivelinessLostCallbackType liveliness_callback;
|
||||
QOSOfferedIncompatibleQoSCallbackType incompatible_qos_callback;
|
||||
IncompatibleTypeCallbackType incompatible_type_callback;
|
||||
PublisherMatchedCallbackType matched_callback;
|
||||
};
|
||||
|
||||
/// Contains callbacks for non-message events that a Subscription can receive from the middleware.
|
||||
struct SubscriptionEventCallbacks
|
||||
{
|
||||
QOSDeadlineRequestedCallbackType deadline_callback;
|
||||
QOSLivelinessChangedCallbackType liveliness_callback;
|
||||
QOSRequestedIncompatibleQoSCallbackType incompatible_qos_callback;
|
||||
QOSMessageLostCallbackType message_lost_callback;
|
||||
IncompatibleTypeCallbackType incompatible_type_callback;
|
||||
SubscriptionMatchedCallbackType matched_callback;
|
||||
};
|
||||
|
||||
class UnsupportedEventTypeException : public exceptions::RCLErrorBase, public std::runtime_error
|
||||
{
|
||||
public:
|
||||
RCLCPP_PUBLIC
|
||||
UnsupportedEventTypeException(
|
||||
rcl_ret_t ret,
|
||||
const rcl_error_state_t * error_state,
|
||||
const std::string & prefix);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
UnsupportedEventTypeException(
|
||||
const exceptions::RCLErrorBase & base_exc,
|
||||
const std::string & prefix);
|
||||
};
|
||||
|
||||
class EventHandlerBase : public Waitable
|
||||
{
|
||||
public:
|
||||
enum class EntityType : std::size_t
|
||||
{
|
||||
Event,
|
||||
};
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual ~EventHandlerBase();
|
||||
|
||||
/// Get the number of ready events
|
||||
RCLCPP_PUBLIC
|
||||
size_t
|
||||
get_number_of_ready_events() override;
|
||||
|
||||
/// Add the Waitable to a wait set.
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_to_wait_set(rcl_wait_set_t * wait_set) override;
|
||||
|
||||
/// Check if the Waitable is ready.
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
is_ready(rcl_wait_set_t * wait_set) override;
|
||||
|
||||
/// Set a callback to be called when each new event instance occurs.
|
||||
/**
|
||||
* The callback receives a size_t which is the number of events that occurred
|
||||
* since the last time this callback was called.
|
||||
* Normally this is 1, but can be > 1 if events occurred before any
|
||||
* callback was set.
|
||||
*
|
||||
* The callback also receives an int identifier argument.
|
||||
* This is needed because a Waitable may be composed of several distinct entities,
|
||||
* such as subscriptions, services, etc.
|
||||
* The application should provide a generic callback function that will be then
|
||||
* forwarded by the waitable to all of its entities.
|
||||
* Before forwarding, a different value for the identifier argument will be
|
||||
* bond to the function.
|
||||
* This implies that the provided callback can use the identifier to behave
|
||||
* differently depending on which entity triggered the waitable to become ready.
|
||||
*
|
||||
* Since this callback is called from the middleware, you should aim to make
|
||||
* it fast and not blocking.
|
||||
* If you need to do a lot of work or wait for some other event, you should
|
||||
* spin it off to another thread, otherwise you risk blocking the middleware.
|
||||
*
|
||||
* Calling it again will clear any previously set callback.
|
||||
*
|
||||
* An exception will be thrown if the callback is not callable.
|
||||
*
|
||||
* This function is thread-safe.
|
||||
*
|
||||
* If you want more information available in the callback, like the qos event
|
||||
* or other information, you may use a lambda with captures or std::bind.
|
||||
*
|
||||
* \sa rmw_event_set_callback
|
||||
* \sa rcl_event_set_callback
|
||||
*
|
||||
* \param[in] callback functor to be called when a new event occurs
|
||||
*/
|
||||
void
|
||||
set_on_ready_callback(std::function<void(size_t, int)> callback) override
|
||||
{
|
||||
if (!callback) {
|
||||
throw std::invalid_argument(
|
||||
"The callback passed to set_on_ready_callback "
|
||||
"is not callable.");
|
||||
}
|
||||
|
||||
// Note: we bind the int identifier argument to this waitable's entity types
|
||||
auto new_callback =
|
||||
[callback, this](size_t number_of_events) {
|
||||
try {
|
||||
callback(number_of_events, static_cast<int>(EntityType::Event));
|
||||
} catch (const std::exception & exception) {
|
||||
RCLCPP_ERROR_STREAM(
|
||||
// TODO(wjwwood): get this class access to the node logger it is associated with
|
||||
rclcpp::get_logger("rclcpp"),
|
||||
"rclcpp::EventHandlerBase@" << this <<
|
||||
" caught " << rmw::impl::cpp::demangle(exception) <<
|
||||
" exception in user-provided callback for the 'on ready' callback: " <<
|
||||
exception.what());
|
||||
} catch (...) {
|
||||
RCLCPP_ERROR_STREAM(
|
||||
rclcpp::get_logger("rclcpp"),
|
||||
"rclcpp::EventHandlerBase@" << this <<
|
||||
" caught unhandled exception in user-provided callback " <<
|
||||
"for the 'on ready' callback");
|
||||
}
|
||||
};
|
||||
|
||||
std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
|
||||
|
||||
// Set it temporarily to the new callback, while we replace the old one.
|
||||
// This two-step setting, prevents a gap where the old std::function has
|
||||
// been replaced but the middleware hasn't been told about the new one yet.
|
||||
set_on_new_event_callback(
|
||||
rclcpp::detail::cpp_callback_trampoline<decltype(new_callback), const void *, size_t>,
|
||||
static_cast<const void *>(&new_callback));
|
||||
|
||||
// Store the std::function to keep it in scope, also overwrites the existing one.
|
||||
on_new_event_callback_ = new_callback;
|
||||
|
||||
// Set it again, now using the permanent storage.
|
||||
set_on_new_event_callback(
|
||||
rclcpp::detail::cpp_callback_trampoline<
|
||||
decltype(on_new_event_callback_), const void *, size_t>,
|
||||
static_cast<const void *>(&on_new_event_callback_));
|
||||
}
|
||||
|
||||
/// Unset the callback registered for new events, if any.
|
||||
void
|
||||
clear_on_ready_callback() override
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
|
||||
if (on_new_event_callback_) {
|
||||
set_on_new_event_callback(nullptr, nullptr);
|
||||
on_new_event_callback_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
set_on_new_event_callback(rcl_event_callback_t callback, const void * user_data);
|
||||
|
||||
std::recursive_mutex callback_mutex_;
|
||||
std::function<void(size_t)> on_new_event_callback_{nullptr};
|
||||
|
||||
rcl_event_t event_handle_;
|
||||
size_t wait_set_event_index_;
|
||||
};
|
||||
|
||||
using QOSEventHandlerBase [[deprecated("Use rclcpp::EventHandlerBase")]] = EventHandlerBase;
|
||||
|
||||
template<typename EventCallbackT, typename ParentHandleT>
|
||||
class EventHandler : public EventHandlerBase
|
||||
{
|
||||
public:
|
||||
template<typename InitFuncT, typename EventTypeEnum>
|
||||
EventHandler(
|
||||
const EventCallbackT & callback,
|
||||
InitFuncT init_func,
|
||||
ParentHandleT parent_handle,
|
||||
EventTypeEnum event_type)
|
||||
: parent_handle_(parent_handle), event_callback_(callback)
|
||||
{
|
||||
event_handle_ = rcl_get_zero_initialized_event();
|
||||
rcl_ret_t ret = init_func(&event_handle_, parent_handle.get(), event_type);
|
||||
if (ret != RCL_RET_OK) {
|
||||
if (ret == RCL_RET_UNSUPPORTED) {
|
||||
UnsupportedEventTypeException exc(ret, rcl_get_error_state(), "Failed to initialize event");
|
||||
rcl_reset_error();
|
||||
throw exc;
|
||||
} else {
|
||||
rclcpp::exceptions::throw_from_rcl_error(ret, "Failed to initialize event");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Take data so that the callback cannot be scheduled again
|
||||
std::shared_ptr<void>
|
||||
take_data() override
|
||||
{
|
||||
EventCallbackInfoT callback_info;
|
||||
rcl_ret_t ret = rcl_take_event(&event_handle_, &callback_info);
|
||||
if (ret != RCL_RET_OK) {
|
||||
RCUTILS_LOG_ERROR_NAMED(
|
||||
"rclcpp",
|
||||
"Couldn't take event info: %s", rcl_get_error_string().str);
|
||||
return nullptr;
|
||||
}
|
||||
return std::static_pointer_cast<void>(std::make_shared<EventCallbackInfoT>(callback_info));
|
||||
}
|
||||
|
||||
std::shared_ptr<void>
|
||||
take_data_by_entity_id(size_t id) override
|
||||
{
|
||||
(void)id;
|
||||
return take_data();
|
||||
}
|
||||
|
||||
/// Execute any entities of the Waitable that are ready.
|
||||
void
|
||||
execute(std::shared_ptr<void> & data) override
|
||||
{
|
||||
if (!data) {
|
||||
throw std::runtime_error("'data' is empty");
|
||||
}
|
||||
auto callback_ptr = std::static_pointer_cast<EventCallbackInfoT>(data);
|
||||
event_callback_(*callback_ptr);
|
||||
callback_ptr.reset();
|
||||
}
|
||||
|
||||
private:
|
||||
using EventCallbackInfoT = typename std::remove_reference<typename
|
||||
rclcpp::function_traits::function_traits<EventCallbackT>::template argument_type<0>>::type;
|
||||
|
||||
ParentHandleT parent_handle_;
|
||||
EventCallbackT event_callback_;
|
||||
};
|
||||
|
||||
template<typename EventCallbackT, typename ParentHandleT>
|
||||
using QOSEventHandler [[deprecated("Use rclcpp::EventHandler")]] = EventHandler<EventCallbackT,
|
||||
ParentHandleT>;
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__EVENT_HANDLER_HPP_
|
||||
@@ -315,16 +315,6 @@ public:
|
||||
virtual void
|
||||
spin_all(std::chrono::nanoseconds max_duration);
|
||||
|
||||
|
||||
/// Collect work once and execute the next available work, optionally within a duration.
|
||||
/**
|
||||
* This function can be overridden. The default implementation is suitable for
|
||||
* a single-thread model of execution.
|
||||
* Adding subscriptions, timers, services, etc. with blocking callbacks will cause this function
|
||||
* to block (which may have unintended consequences).
|
||||
* \param[in] timeout The maximum amount of time to spend waiting for work.
|
||||
* `-1` is potentially block forever waiting for work.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual void
|
||||
spin_once(std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));
|
||||
@@ -423,29 +413,12 @@ public:
|
||||
is_spinning();
|
||||
|
||||
protected:
|
||||
/// Add a node to executor, execute the next available unit of work, and remove the node.
|
||||
/**
|
||||
* Implementation of spin_node_once using std::chrono::nanoseconds
|
||||
* \param[in] node Shared pointer to the node to add.
|
||||
* \param[in] timeout How long to wait for work to become available. Negative values cause
|
||||
* spin_node_once to block indefinitely (the default behavior). A timeout of 0 causes this
|
||||
* function to be non-blocking.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
spin_node_once_nanoseconds(
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node,
|
||||
std::chrono::nanoseconds timeout);
|
||||
|
||||
/// Collect work and execute available work, optionally within a duration.
|
||||
/**
|
||||
* Implementation of spin_some and spin_all.
|
||||
* The exhaustive flag controls if the function will re-collect available work within the duration.
|
||||
*
|
||||
* \param[in] max_duration The maximum amount of time to spend executing work, or 0 for no limit.
|
||||
* \param[in] exhaustive when set to true, continue to collect work and execute (spin_all)
|
||||
* when set to false, return when all collected work is executed (spin_some)
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
spin_some_impl(std::chrono::nanoseconds max_duration, bool exhaustive);
|
||||
@@ -460,60 +433,30 @@ protected:
|
||||
void
|
||||
execute_any_executable(AnyExecutable & any_exec);
|
||||
|
||||
/// Run subscription executable.
|
||||
/**
|
||||
* Do necessary setup and tear-down as well as executing the subscription.
|
||||
* \param[in] subscription Subscription to execute
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
static void
|
||||
execute_subscription(
|
||||
rclcpp::SubscriptionBase::SharedPtr subscription);
|
||||
|
||||
/// Run timer executable.
|
||||
/**
|
||||
* Do necessary setup and tear-down as well as executing the timer callback.
|
||||
* \param[in] timer Timer to execute
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
static void
|
||||
execute_timer(rclcpp::TimerBase::SharedPtr timer);
|
||||
|
||||
/// Run service server executable.
|
||||
/**
|
||||
* Do necessary setup and tear-down as well as executing the service server callback.
|
||||
* \param[in] service Service to execute
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
static void
|
||||
execute_service(rclcpp::ServiceBase::SharedPtr service);
|
||||
|
||||
/// Run service client executable.
|
||||
/**
|
||||
* Do necessary setup and tear-down as well as executing the service client callback.
|
||||
* \param[in] service Service to execute
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
static void
|
||||
execute_client(rclcpp::ClientBase::SharedPtr client);
|
||||
|
||||
/// Block until more work becomes avilable or timeout is reached.
|
||||
/**
|
||||
* Builds a set of waitable entities, which are passed to the middleware.
|
||||
* After building wait set, waits on middleware to notify.
|
||||
* \param[in] timeout duration to wait for new work to become available.
|
||||
* \throws std::runtime_error if the wait set can be cleared
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
wait_for_work(std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));
|
||||
|
||||
/// Find node associated with a callback group
|
||||
/**
|
||||
* \param[in] weak_groups_to_nodes map of callback groups to nodes
|
||||
* \param[in] group callback group to find assocatiated node
|
||||
* \return Pointer to associated node if found, else nullptr
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr
|
||||
get_node_by_group(
|
||||
@@ -532,11 +475,6 @@ protected:
|
||||
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
|
||||
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes) const;
|
||||
|
||||
/// Find the callback group associated with a timer
|
||||
/**
|
||||
* \param[in] timer Timer to find associated callback group
|
||||
* \return Pointer to callback group node if found, else nullptr
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::CallbackGroup::SharedPtr
|
||||
get_group_by_timer(rclcpp::TimerBase::SharedPtr timer);
|
||||
@@ -564,54 +502,16 @@ protected:
|
||||
WeakCallbackGroupsToNodesMap & weak_groups_to_nodes,
|
||||
bool notify = true) RCPPUTILS_TSA_REQUIRES(mutex_);
|
||||
|
||||
/// Check for executable in ready state and populate union structure.
|
||||
/**
|
||||
* \param[out] any_executable populated union structure of ready executable
|
||||
* \return true if an executable was ready and any_executable was populated,
|
||||
* otherwise false
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
get_next_ready_executable(AnyExecutable & any_executable);
|
||||
|
||||
/// Check for executable in ready state and populate union structure.
|
||||
/**
|
||||
* This is the implementation of get_next_ready_executable that takes into
|
||||
* account the current state of callback groups' association with nodes and
|
||||
* executors.
|
||||
*
|
||||
* This checks in a particular order for available work:
|
||||
* * Timers
|
||||
* * Subscriptions
|
||||
* * Services
|
||||
* * Clients
|
||||
* * Waitable
|
||||
*
|
||||
* If the next executable is not associated with this executor/node pair,
|
||||
* then this method will return false.
|
||||
*
|
||||
* \param[out] any_executable populated union structure of ready executable
|
||||
* \param[in] weak_groups_to_nodes mapping of callback groups to nodes
|
||||
* \return true if an executable was ready and any_executable was populated,
|
||||
* otherwise false
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
get_next_ready_executable_from_map(
|
||||
AnyExecutable & any_executable,
|
||||
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes);
|
||||
|
||||
/// Wait for executable in ready state and populate union structure.
|
||||
/**
|
||||
* If an executable is ready, it will return immediately, otherwise
|
||||
* block based on the timeout for work to become ready.
|
||||
*
|
||||
* \param[out] any_executable populated union structure of ready executable
|
||||
* \param[in] timeout duration of time to wait for work, a negative value
|
||||
* (the defualt behavior), will make this function block indefinitely
|
||||
* \return true if an executable was ready and any_executable was populated,
|
||||
* otherwise false
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
get_next_executable(
|
||||
@@ -665,19 +565,10 @@ protected:
|
||||
std::owner_less<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>>
|
||||
WeakNodesToGuardConditionsMap;
|
||||
|
||||
typedef std::map<rclcpp::CallbackGroup::WeakPtr,
|
||||
const rclcpp::GuardCondition *,
|
||||
std::owner_less<rclcpp::CallbackGroup::WeakPtr>>
|
||||
WeakCallbackGroupsToGuardConditionsMap;
|
||||
|
||||
/// maps nodes to guard conditions
|
||||
WeakNodesToGuardConditionsMap
|
||||
weak_nodes_to_guard_conditions_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
|
||||
|
||||
/// maps callback groups to guard conditions
|
||||
WeakCallbackGroupsToGuardConditionsMap
|
||||
weak_groups_to_guard_conditions_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
|
||||
|
||||
/// maps callback groups associated to nodes
|
||||
WeakCallbackGroupsToNodesMap
|
||||
weak_groups_associated_with_executor_to_nodes_ RCPPUTILS_TSA_GUARDED_BY(mutex_);
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include "rclcpp/executors/multi_threaded_executor.hpp"
|
||||
#include "rclcpp/executors/single_threaded_executor.hpp"
|
||||
#include "rclcpp/executors/static_single_threaded_executor.hpp"
|
||||
#include "rclcpp/experimental/executors/events_executor/events_executor.hpp"
|
||||
#include "rclcpp/node.hpp"
|
||||
#include "rclcpp/utilities.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
@@ -47,7 +47,7 @@ public:
|
||||
*
|
||||
* \param options common options for all executors
|
||||
* \param number_of_threads number of threads to have in the thread pool,
|
||||
* the default 0 will use the number of cpu cores found (minimum of 2)
|
||||
* the default 0 will use the number of cpu cores found instead
|
||||
* \param yield_before_execute if true std::this_thread::yield() is called
|
||||
* \param timeout maximum time to wait
|
||||
*/
|
||||
|
||||
@@ -86,7 +86,8 @@ public:
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
|
||||
if (!has_data_()) {
|
||||
return BufferT();
|
||||
RCLCPP_ERROR(rclcpp::get_logger("rclcpp"), "Calling dequeue on empty intra-process buffer");
|
||||
throw std::runtime_error("Calling dequeue on empty intra-process buffer");
|
||||
}
|
||||
|
||||
auto request = std::move(ring_buffer_[read_index_]);
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
// Copyright 2023 iRobot Corporation.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__EXPERIMENTAL__EXECUTORS__EVENTS_EXECUTOR__EVENT_WAITABLE_HPP_
|
||||
#define RCLCPP__EXPERIMENTAL__EXECUTORS__EVENTS_EXECUTOR__EVENT_WAITABLE_HPP_
|
||||
|
||||
#include "rclcpp/waitable.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief This class provides a wrapper around the waitable object, that is
|
||||
* meant to be used with the EventsExecutor.
|
||||
* The waitset related methods are stubbed out as they should not be called.
|
||||
* This class is abstract as the execute method of rclcpp::Waitable is not implemented.
|
||||
* Nodes who want to implement a custom EventWaitable, can derive from this class and override
|
||||
* the execute method.
|
||||
*/
|
||||
class EventWaitable : public rclcpp::Waitable
|
||||
{
|
||||
public:
|
||||
// Constructor
|
||||
RCLCPP_PUBLIC
|
||||
EventWaitable() = default;
|
||||
|
||||
// Destructor
|
||||
RCLCPP_PUBLIC
|
||||
virtual ~EventWaitable() = default;
|
||||
|
||||
// Stub API: not used by EventsExecutor
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
is_ready(rcl_wait_set_t * wait_set) final
|
||||
{
|
||||
(void)wait_set;
|
||||
throw std::runtime_error("EventWaitable can't be checked if it's ready");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Stub API: not used by EventsExecutor
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_to_wait_set(rcl_wait_set_t * wait_set) final
|
||||
{
|
||||
(void)wait_set;
|
||||
throw std::runtime_error("EventWaitable can't be added to a wait_set");
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace executors
|
||||
} // namespace experimental
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__EXPERIMENTAL__EXECUTORS__EVENTS_EXECUTOR__EVENT_WAITABLE_HPP_
|
||||
@@ -1,237 +0,0 @@
|
||||
// Copyright 2023 iRobot Corporation.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__EXPERIMENTAL__EXECUTORS__EVENTS_EXECUTOR__EVENTS_EXECUTOR_HPP_
|
||||
#define RCLCPP__EXPERIMENTAL__EXECUTORS__EVENTS_EXECUTOR__EVENTS_EXECUTOR_HPP_
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
|
||||
#include "rclcpp/executor.hpp"
|
||||
#include "rclcpp/experimental/executors/events_executor/events_executor_entities_collector.hpp"
|
||||
#include "rclcpp/experimental/executors/events_executor/events_executor_event_types.hpp"
|
||||
#include "rclcpp/experimental/executors/events_executor/events_executor_notify_waitable.hpp"
|
||||
#include "rclcpp/experimental/executors/events_executor/events_queue.hpp"
|
||||
#include "rclcpp/experimental/executors/events_executor/simple_events_queue.hpp"
|
||||
#include "rclcpp/experimental/timers_manager.hpp"
|
||||
#include "rclcpp/node.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
|
||||
/// Events executor implementation
|
||||
/**
|
||||
* This executor uses an events queue and a timers manager to execute entities from its
|
||||
* associated nodes and callback groups.
|
||||
* The RMW listener APIs are used to collect new events.
|
||||
*
|
||||
* This executor tries to reduce as much as possible the amount of maintenance operations.
|
||||
* This allows to use customized `EventsQueue` classes to achieve different goals such
|
||||
* as very low CPU usage, bounded memory requirement, determinism, etc.
|
||||
*
|
||||
* The executor uses a weak ownership model and it locks entities only while executing
|
||||
* their related events.
|
||||
*
|
||||
* To run this executor:
|
||||
* rclcpp::experimental::executors::EventsExecutor executor;
|
||||
* executor.add_node(node);
|
||||
* executor.spin();
|
||||
* executor.remove_node(node);
|
||||
*/
|
||||
class EventsExecutor : public rclcpp::Executor
|
||||
{
|
||||
friend class EventsExecutorEntitiesCollector;
|
||||
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(EventsExecutor)
|
||||
|
||||
/// Default constructor. See the default constructor for Executor.
|
||||
/**
|
||||
* \param[in] events_queue The queue used to store events.
|
||||
* \param[in] execute_timers_separate_thread If true, timers are executed in a separate
|
||||
* thread. If false, timers are executed in the same thread as all other entities.
|
||||
* \param[in] options Options used to configure the executor.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
explicit EventsExecutor(
|
||||
rclcpp::experimental::executors::EventsQueue::UniquePtr events_queue = std::make_unique<
|
||||
rclcpp::experimental::executors::SimpleEventsQueue>(),
|
||||
bool execute_timers_separate_thread = false,
|
||||
const rclcpp::ExecutorOptions & options = rclcpp::ExecutorOptions());
|
||||
|
||||
/// Default destructor.
|
||||
RCLCPP_PUBLIC
|
||||
virtual ~EventsExecutor();
|
||||
|
||||
/// Events executor implementation of spin.
|
||||
/**
|
||||
* This function will block until work comes in, execute it, and keep blocking.
|
||||
* It will only be interrupted by a CTRL-C (managed by the global signal handler).
|
||||
* \throws std::runtime_error when spin() called while already spinning
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
spin() override;
|
||||
|
||||
/// Events executor implementation of spin some
|
||||
/**
|
||||
* This non-blocking function will execute the timers and events
|
||||
* that were ready when this API was called, until timeout or no
|
||||
* more work available. New ready-timers/events arrived while
|
||||
* executing work, won't be taken into account here.
|
||||
*
|
||||
* Example:
|
||||
* while(condition) {
|
||||
* spin_some();
|
||||
* sleep(); // User should have some sync work or
|
||||
* // sleep to avoid a 100% CPU usage
|
||||
* }
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
spin_some(std::chrono::nanoseconds max_duration = std::chrono::nanoseconds(0)) override;
|
||||
|
||||
/// Events executor implementation of spin all
|
||||
/**
|
||||
* This non-blocking function will execute timers and events
|
||||
* until timeout or no more work available. If new ready-timers/events
|
||||
* arrive while executing work available, they will be executed
|
||||
* as long as the timeout hasn't expired.
|
||||
*
|
||||
* Example:
|
||||
* while(condition) {
|
||||
* spin_all();
|
||||
* sleep(); // User should have some sync work or
|
||||
* // sleep to avoid a 100% CPU usage
|
||||
* }
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
spin_all(std::chrono::nanoseconds max_duration) override;
|
||||
|
||||
/// Add a node to the executor.
|
||||
/**
|
||||
* \sa rclcpp::Executor::add_node
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_node(
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
|
||||
bool notify = true) override;
|
||||
|
||||
/// Convenience function which takes Node and forwards NodeBaseInterface.
|
||||
/**
|
||||
* \sa rclcpp::EventsExecutor::add_node
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_node(std::shared_ptr<rclcpp::Node> node_ptr, bool notify = true) override;
|
||||
|
||||
/// Remove a node from the executor.
|
||||
/**
|
||||
* \sa rclcpp::Executor::remove_node
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
remove_node(
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
|
||||
bool notify = true) override;
|
||||
|
||||
/// Convenience function which takes Node and forwards NodeBaseInterface.
|
||||
/**
|
||||
* \sa rclcpp::Executor::remove_node
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
remove_node(std::shared_ptr<rclcpp::Node> node_ptr, bool notify = true) override;
|
||||
|
||||
/// Add a callback group to an executor.
|
||||
/**
|
||||
* \sa rclcpp::Executor::add_callback_group
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_callback_group(
|
||||
rclcpp::CallbackGroup::SharedPtr group_ptr,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
|
||||
bool notify = true) override;
|
||||
|
||||
/// Remove callback group from the executor
|
||||
/**
|
||||
* \sa rclcpp::Executor::remove_callback_group
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
remove_callback_group(
|
||||
rclcpp::CallbackGroup::SharedPtr group_ptr,
|
||||
bool notify = true) override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<rclcpp::CallbackGroup::WeakPtr>
|
||||
get_all_callback_groups() override;
|
||||
|
||||
/// Get callback groups that belong to executor.
|
||||
/**
|
||||
* \sa rclcpp::Executor::get_manually_added_callback_groups()
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<rclcpp::CallbackGroup::WeakPtr>
|
||||
get_manually_added_callback_groups() override;
|
||||
|
||||
/// Get callback groups that belong to executor.
|
||||
/**
|
||||
* \sa rclcpp::Executor::get_automatically_added_callback_groups_from_nodes()
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<rclcpp::CallbackGroup::WeakPtr>
|
||||
get_automatically_added_callback_groups_from_nodes() override;
|
||||
|
||||
protected:
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
spin_once_impl(std::chrono::nanoseconds timeout) override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
spin_some_impl(std::chrono::nanoseconds max_duration, bool exhaustive);
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(EventsExecutor)
|
||||
|
||||
// Execute a single event
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
execute_event(const ExecutorEvent & event);
|
||||
|
||||
// Queue where entities can push events
|
||||
rclcpp::experimental::executors::EventsQueue::UniquePtr events_queue_;
|
||||
|
||||
EventsExecutorEntitiesCollector::SharedPtr entities_collector_;
|
||||
EventsExecutorNotifyWaitable::SharedPtr executor_notifier_;
|
||||
|
||||
// Timers manager
|
||||
std::shared_ptr<rclcpp::experimental::TimersManager> timers_manager_;
|
||||
};
|
||||
|
||||
} // namespace executors
|
||||
} // namespace experimental
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__EXPERIMENTAL__EXECUTORS__EVENTS_EXECUTOR__EVENTS_EXECUTOR_HPP_
|
||||
@@ -1,348 +0,0 @@
|
||||
// Copyright 2023 iRobot Corporation.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__EXPERIMENTAL__EXECUTORS__EVENTS_EXECUTOR__EVENTS_EXECUTOR_ENTITIES_COLLECTOR_HPP_
|
||||
#define RCLCPP__EXPERIMENTAL__EXECUTORS__EVENTS_EXECUTOR__EVENTS_EXECUTOR_ENTITIES_COLLECTOR_HPP_
|
||||
|
||||
#include <chrono>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "rcl/guard_condition.h"
|
||||
#include "rcl/wait.h"
|
||||
|
||||
#include "rclcpp/callback_group.hpp"
|
||||
#include "rclcpp/experimental/executors/events_executor/events_executor_event_types.hpp"
|
||||
#include "rclcpp/experimental/timers_manager.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
#include "rclcpp/waitable.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
// forward declaration of EventsExecutor to avoid circular dependency
|
||||
class EventsExecutor;
|
||||
|
||||
typedef std::map<rclcpp::CallbackGroup::WeakPtr,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr,
|
||||
std::owner_less<rclcpp::CallbackGroup::WeakPtr>> WeakCallbackGroupsToNodesMap;
|
||||
|
||||
/**
|
||||
* @brief This class provides a waitable object that is used for managing the
|
||||
* entities (i.e. nodes and their subscriptions, timers, services, etc)
|
||||
* added to an EventsExecutor.
|
||||
* The add/remove node APIs are used when a node is added/removed from
|
||||
* the associated EventsExecutor and result in setting/unsetting the
|
||||
* events callbacks and adding timers to the timers manager.
|
||||
*
|
||||
* Being this class derived from Waitable, it can be used to wake up an
|
||||
* executor thread while it's spinning.
|
||||
* When this occurs, the execute API takes care of handling changes
|
||||
* in the entities currently used by the executor.
|
||||
*/
|
||||
class EventsExecutorEntitiesCollector final
|
||||
: public rclcpp::Waitable,
|
||||
public std::enable_shared_from_this<EventsExecutorEntitiesCollector>
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(EventsExecutorEntitiesCollector)
|
||||
|
||||
// Constructor
|
||||
RCLCPP_PUBLIC
|
||||
EventsExecutorEntitiesCollector(
|
||||
EventsExecutor * executor);
|
||||
|
||||
// Destructor
|
||||
RCLCPP_PUBLIC
|
||||
~EventsExecutorEntitiesCollector() override;
|
||||
|
||||
// Initialize entities collector
|
||||
RCLCPP_PUBLIC
|
||||
void init();
|
||||
|
||||
/// Execute the waitable.
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
execute(std::shared_ptr<void> & data) override;
|
||||
|
||||
/// Function to add_handles_to_wait_set and wait for work and
|
||||
/**
|
||||
* block until the wait set is ready or until the timeout has been exceeded.
|
||||
* \throws std::runtime_error if wait set couldn't be cleared or filled.
|
||||
* \throws any rcl errors from rcl_wait, \see rclcpp::exceptions::throw_from_rcl_error()
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
refresh_wait_set(std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));
|
||||
|
||||
/**
|
||||
* \throws std::runtime_error if it couldn't add guard condition to wait set
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_to_wait_set(rcl_wait_set_t * wait_set) override;
|
||||
|
||||
/// Complete all available queued work without blocking.
|
||||
/**
|
||||
* This function checks if after the guard condition was triggered
|
||||
* (or a spurious wakeup happened) we are really ready to execute
|
||||
* i.e. re-collect entities
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
is_ready(rcl_wait_set_t * wait_set) override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
std::shared_ptr<void>
|
||||
take_data() override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
std::shared_ptr<void>
|
||||
take_data_by_entity_id(size_t id) override;
|
||||
|
||||
/// Add a callback group to an executor.
|
||||
/**
|
||||
* \see rclcpp::Executor::add_callback_group
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
add_callback_group(
|
||||
rclcpp::CallbackGroup::SharedPtr group_ptr,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr);
|
||||
|
||||
/// Add a callback group to an executor.
|
||||
/**
|
||||
* \see rclcpp::Executor::add_callback_group
|
||||
* \return boolean whether the node from the callback group is new
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
add_callback_group(
|
||||
rclcpp::CallbackGroup::SharedPtr group_ptr,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
|
||||
WeakCallbackGroupsToNodesMap & weak_groups_to_nodes);
|
||||
|
||||
/// Remove a callback group from the executor.
|
||||
/**
|
||||
* \see rclcpp::Executor::remove_callback_group
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
remove_callback_group(
|
||||
rclcpp::CallbackGroup::SharedPtr group_ptr);
|
||||
|
||||
/// Remove a callback group from the executor.
|
||||
/**
|
||||
* \see rclcpp::Executor::remove_callback_group_from_map
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
remove_callback_group_from_map(
|
||||
rclcpp::CallbackGroup::SharedPtr group_ptr,
|
||||
WeakCallbackGroupsToNodesMap & weak_groups_to_nodes);
|
||||
|
||||
/**
|
||||
* \see rclcpp::Executor::add_node()
|
||||
* \throw std::runtime_error if node was already added
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
add_node(
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr);
|
||||
|
||||
/**
|
||||
* \see rclcpp::Executor::remove_node()
|
||||
* \throw std::runtime_error if no guard condition is associated with node.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
remove_node(
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<rclcpp::CallbackGroup::WeakPtr>
|
||||
get_all_callback_groups();
|
||||
|
||||
/// Get callback groups that belong to executor.
|
||||
/**
|
||||
* \see rclcpp::Executor::get_manually_added_callback_groups()
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<rclcpp::CallbackGroup::WeakPtr>
|
||||
get_manually_added_callback_groups();
|
||||
|
||||
/// Get callback groups that belong to executor.
|
||||
/**
|
||||
* \see rclcpp::Executor::get_automatically_added_callback_groups_from_nodes()
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<rclcpp::CallbackGroup::WeakPtr>
|
||||
get_automatically_added_callback_groups_from_nodes();
|
||||
|
||||
///
|
||||
/**
|
||||
* Get the subscription shared pointer corresponding
|
||||
* to a subscription identifier
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::SubscriptionBase::SharedPtr
|
||||
get_subscription(const void * subscription_id);
|
||||
|
||||
///
|
||||
/**
|
||||
* Get the client shared pointer corresponding
|
||||
* to a client identifier
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::ClientBase::SharedPtr
|
||||
get_client(const void * client_id);
|
||||
|
||||
///
|
||||
/**
|
||||
* Get the service shared pointer corresponding
|
||||
* to a service identifier
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::ServiceBase::SharedPtr
|
||||
get_service(const void * service_id);
|
||||
|
||||
///
|
||||
/**
|
||||
* Get the waitable shared pointer corresponding
|
||||
* to a waitable identifier
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::Waitable::SharedPtr
|
||||
get_waitable(const void * waitable_id);
|
||||
|
||||
///
|
||||
/**
|
||||
* Add a weak pointer to a waitable
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_waitable(rclcpp::Waitable::SharedPtr waitable);
|
||||
|
||||
private:
|
||||
/// Return true if the node belongs to the collector
|
||||
/**
|
||||
* \param[in] node_ptr a node base interface shared pointer
|
||||
* \param[in] weak_groups_to_nodes map to nodes to lookup
|
||||
* \return boolean whether a node belongs the collector
|
||||
*/
|
||||
bool
|
||||
has_node(
|
||||
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
|
||||
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes) const;
|
||||
|
||||
/// Add all callback groups that can be automatically added by any executor
|
||||
/// and is not already associated with an executor from nodes
|
||||
/// that are associated with executor
|
||||
/**
|
||||
* \see rclcpp::Executor::add_callback_groups_from_nodes_associated_to_executor()
|
||||
*/
|
||||
void
|
||||
add_callback_groups_from_nodes_associated_to_executor();
|
||||
|
||||
void
|
||||
callback_group_added_impl(
|
||||
rclcpp::CallbackGroup::SharedPtr group);
|
||||
|
||||
void
|
||||
node_added_impl(
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node);
|
||||
|
||||
void
|
||||
callback_group_removed_impl(
|
||||
rclcpp::CallbackGroup::SharedPtr group);
|
||||
|
||||
void
|
||||
node_removed_impl(
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node);
|
||||
|
||||
void
|
||||
set_entities_event_callbacks_from_map(
|
||||
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes);
|
||||
|
||||
void
|
||||
set_callback_group_entities_callbacks(rclcpp::CallbackGroup::SharedPtr group);
|
||||
|
||||
void
|
||||
unset_callback_group_entities_callbacks(rclcpp::CallbackGroup::SharedPtr group);
|
||||
|
||||
void
|
||||
set_guard_condition_callback(rclcpp::GuardCondition * guard_condition);
|
||||
|
||||
void
|
||||
unset_guard_condition_callback(rclcpp::GuardCondition * guard_condition);
|
||||
|
||||
std::function<void(size_t)>
|
||||
create_entity_callback(void * exec_entity_id, ExecutorEventType type);
|
||||
|
||||
std::function<void(size_t, int)>
|
||||
create_waitable_callback(void * waitable_id);
|
||||
|
||||
typedef std::map<rclcpp::CallbackGroup::WeakPtr,
|
||||
rclcpp::GuardCondition *,
|
||||
std::owner_less<rclcpp::CallbackGroup::WeakPtr>>
|
||||
WeakCallbackGroupsToGuardConditionsMap;
|
||||
|
||||
typedef std::map<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr,
|
||||
const rclcpp::GuardCondition *,
|
||||
std::owner_less<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>>
|
||||
WeakNodesToGuardConditionsMap;
|
||||
|
||||
/// maps callback groups to guard conditions
|
||||
WeakCallbackGroupsToGuardConditionsMap weak_groups_to_guard_conditions_;
|
||||
|
||||
WeakNodesToGuardConditionsMap weak_nodes_to_guard_conditions_;
|
||||
|
||||
// maps callback groups to nodes.
|
||||
WeakCallbackGroupsToNodesMap weak_groups_associated_with_executor_to_nodes_;
|
||||
// maps callback groups to nodes.
|
||||
WeakCallbackGroupsToNodesMap weak_groups_to_nodes_associated_with_executor_;
|
||||
|
||||
/// List of weak nodes registered in the static executor
|
||||
std::list<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr> weak_nodes_;
|
||||
|
||||
// Maps: entity identifiers to weak pointers from the entities registered in the executor
|
||||
// so in the case of an event providing and ID, we can retrieve and own the corresponding
|
||||
// entity while it performs work
|
||||
std::unordered_map<const void *, rclcpp::SubscriptionBase::WeakPtr> weak_subscriptions_map_;
|
||||
std::unordered_map<const void *, rclcpp::ServiceBase::WeakPtr> weak_services_map_;
|
||||
std::unordered_map<const void *, rclcpp::ClientBase::WeakPtr> weak_clients_map_;
|
||||
std::unordered_map<const void *, rclcpp::Waitable::WeakPtr> weak_waitables_map_;
|
||||
|
||||
/// Executor using this entities collector object
|
||||
EventsExecutor * associated_executor_ = nullptr;
|
||||
/// Instance of the timers manager used by the associated executor
|
||||
rclcpp::experimental::TimersManager::SharedPtr timers_manager_;
|
||||
|
||||
// Mutex to protect vector of new nodes.
|
||||
std::recursive_mutex reentrant_mutex_;
|
||||
};
|
||||
|
||||
} // namespace executors
|
||||
} // namespace experimental
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__EXPERIMENTAL__EXECUTORS__EVENTS_EXECUTOR__EVENTS_EXECUTOR_ENTITIES_COLLECTOR_HPP_
|
||||
@@ -1,46 +0,0 @@
|
||||
// Copyright 2023 iRobot Corporation.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__EXPERIMENTAL__EXECUTORS__EVENTS_EXECUTOR__EVENTS_EXECUTOR_EVENT_TYPES_HPP_
|
||||
#define RCLCPP__EXPERIMENTAL__EXECUTORS__EVENTS_EXECUTOR__EVENTS_EXECUTOR_EVENT_TYPES_HPP_
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
|
||||
enum ExecutorEventType
|
||||
{
|
||||
CLIENT_EVENT,
|
||||
SUBSCRIPTION_EVENT,
|
||||
SERVICE_EVENT,
|
||||
TIMER_EVENT,
|
||||
WAITABLE_EVENT
|
||||
};
|
||||
|
||||
struct ExecutorEvent
|
||||
{
|
||||
const void * exec_entity_id;
|
||||
int gen_entity_id;
|
||||
ExecutorEventType type;
|
||||
size_t num_events;
|
||||
};
|
||||
|
||||
} // namespace executors
|
||||
} // namespace experimental
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__EXPERIMENTAL__EXECUTORS__EVENTS_EXECUTOR__EVENTS_EXECUTOR_EVENT_TYPES_HPP_
|
||||
@@ -1,103 +0,0 @@
|
||||
// Copyright 2023 iRobot Corporation.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__EXPERIMENTAL__EXECUTORS__EVENTS_EXECUTOR__EVENTS_EXECUTOR_NOTIFY_WAITABLE_HPP_
|
||||
#define RCLCPP__EXPERIMENTAL__EXECUTORS__EVENTS_EXECUTOR__EVENTS_EXECUTOR_NOTIFY_WAITABLE_HPP_
|
||||
|
||||
#include <list>
|
||||
#include <memory>
|
||||
|
||||
#include "rcl/guard_condition.h"
|
||||
#include "rclcpp/experimental/executors/events_executor/event_waitable.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief This class provides an EventWaitable that allows to
|
||||
* wake up an EventsExecutor when a guard condition is notified.
|
||||
*/
|
||||
class EventsExecutorNotifyWaitable final : public EventWaitable
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(EventsExecutorNotifyWaitable)
|
||||
|
||||
// Constructor
|
||||
RCLCPP_PUBLIC
|
||||
EventsExecutorNotifyWaitable() = default;
|
||||
|
||||
// Destructor
|
||||
RCLCPP_PUBLIC
|
||||
virtual ~EventsExecutorNotifyWaitable() = default;
|
||||
|
||||
// The function is a no-op, since we only care of waking up the executor
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
execute(std::shared_ptr<void> & data) override
|
||||
{
|
||||
(void)data;
|
||||
}
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_guard_condition(rclcpp::GuardCondition * guard_condition)
|
||||
{
|
||||
notify_guard_conditions_.push_back(guard_condition);
|
||||
}
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
set_on_ready_callback(std::function<void(size_t, int)> callback) override
|
||||
{
|
||||
// The second argument of the callback should identify which guard condition
|
||||
// triggered the event. However it's not relevant here as we only
|
||||
// care about waking up the executor, so we pass a 0.
|
||||
auto gc_callback = [callback](size_t count) {
|
||||
callback(count, 0);
|
||||
};
|
||||
|
||||
for (auto gc : notify_guard_conditions_) {
|
||||
gc->set_on_trigger_callback(gc_callback);
|
||||
}
|
||||
}
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
std::shared_ptr<void>
|
||||
take_data() override
|
||||
{
|
||||
// This waitable doesn't handle any data
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
std::shared_ptr<void>
|
||||
take_data_by_entity_id(size_t id) override
|
||||
{
|
||||
(void) id;
|
||||
return take_data();
|
||||
}
|
||||
|
||||
private:
|
||||
std::list<rclcpp::GuardCondition *> notify_guard_conditions_;
|
||||
};
|
||||
|
||||
} // namespace executors
|
||||
} // namespace experimental
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__EXPERIMENTAL__EXECUTORS__EVENTS_EXECUTOR__EVENTS_EXECUTOR_NOTIFY_WAITABLE_HPP_
|
||||
@@ -1,100 +0,0 @@
|
||||
// Copyright 2023 iRobot Corporation.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__EXPERIMENTAL__EXECUTORS__EVENTS_EXECUTOR__EVENTS_QUEUE_HPP_
|
||||
#define RCLCPP__EXPERIMENTAL__EXECUTORS__EVENTS_EXECUTOR__EVENTS_QUEUE_HPP_
|
||||
|
||||
#include <queue>
|
||||
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
#include "rclcpp/experimental/executors/events_executor/events_executor_event_types.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief This abstract class can be used to implement different types of queues
|
||||
* where `ExecutorEvent` can be stored.
|
||||
* The derived classes should choose which underlying container to use and
|
||||
* the strategy for pushing and popping events.
|
||||
* For example a queue implementation may be bounded or unbounded and have
|
||||
* different pruning strategies.
|
||||
* Implementations may or may not check the validity of events and decide how to handle
|
||||
* the situation where an event is not valid anymore (e.g. a subscription history cache overruns)
|
||||
*/
|
||||
class EventsQueue
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_ALIASES_ONLY(EventsQueue)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
EventsQueue() = default;
|
||||
|
||||
/**
|
||||
* @brief Destruct the object.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual ~EventsQueue() = default;
|
||||
|
||||
/**
|
||||
* @brief push event into the queue
|
||||
* @param event The event to push into the queue
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
enqueue(const rclcpp::experimental::executors::ExecutorEvent & event) = 0;
|
||||
|
||||
/**
|
||||
* @brief Extracts an event from the queue, eventually waiting until timeout
|
||||
* if none is available.
|
||||
* @return true if event has been found, false if timeout
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
bool
|
||||
dequeue(
|
||||
rclcpp::experimental::executors::ExecutorEvent & event,
|
||||
std::chrono::nanoseconds timeout = std::chrono::nanoseconds::max()) = 0;
|
||||
|
||||
/**
|
||||
* @brief Test whether queue is empty
|
||||
* @return true if the queue's size is 0, false otherwise.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
bool
|
||||
empty() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Returns the number of elements in the queue.
|
||||
* @return the number of elements in the queue.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
size_t
|
||||
size() const = 0;
|
||||
};
|
||||
|
||||
} // namespace executors
|
||||
} // namespace experimental
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__EXPERIMENTAL__EXECUTORS__EVENTS_EXECUTOR__EVENTS_QUEUE_HPP_
|
||||
@@ -1,134 +0,0 @@
|
||||
// Copyright 2023 iRobot Corporation.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__EXPERIMENTAL__EXECUTORS__EVENTS_EXECUTOR__SIMPLE_EVENTS_QUEUE_HPP_
|
||||
#define RCLCPP__EXPERIMENTAL__EXECUTORS__EVENTS_EXECUTOR__SIMPLE_EVENTS_QUEUE_HPP_
|
||||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
#include <utility>
|
||||
|
||||
#include "rclcpp/experimental/executors/events_executor/events_queue.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief This class implements an EventsQueue as a simple wrapper around a std::queue.
|
||||
* It does not perform any checks about the size of queue, which can grow
|
||||
* unbounded without being pruned.
|
||||
* The simplicity of this implementation makes it suitable for optimizing CPU usage.
|
||||
*/
|
||||
class SimpleEventsQueue : public EventsQueue
|
||||
{
|
||||
public:
|
||||
RCLCPP_PUBLIC
|
||||
~SimpleEventsQueue() override = default;
|
||||
|
||||
/**
|
||||
* @brief enqueue event into the queue
|
||||
* Thread safe
|
||||
* @param event The event to enqueue into the queue
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
enqueue(const rclcpp::experimental::executors::ExecutorEvent & event) override
|
||||
{
|
||||
rclcpp::experimental::executors::ExecutorEvent single_event = event;
|
||||
single_event.num_events = 1;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
for (size_t ev = 0; ev < event.num_events; ev++) {
|
||||
event_queue_.push(single_event);
|
||||
}
|
||||
}
|
||||
events_queue_cv_.notify_one();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief waits for an event until timeout, gets a single event
|
||||
* Thread safe
|
||||
* @return true if event, false if timeout
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
dequeue(
|
||||
rclcpp::experimental::executors::ExecutorEvent & event,
|
||||
std::chrono::nanoseconds timeout = std::chrono::nanoseconds::max()) override
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
|
||||
// Initialize to true because it's only needed if we have a valid timeout
|
||||
bool has_data = true;
|
||||
if (timeout != std::chrono::nanoseconds::max()) {
|
||||
has_data =
|
||||
events_queue_cv_.wait_for(lock, timeout, [this]() {return !event_queue_.empty();});
|
||||
} else {
|
||||
events_queue_cv_.wait(lock, [this]() {return !event_queue_.empty();});
|
||||
}
|
||||
|
||||
if (has_data) {
|
||||
event = event_queue_.front();
|
||||
event_queue_.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Test whether queue is empty
|
||||
* Thread safe
|
||||
* @return true if the queue's size is 0, false otherwise.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
empty() const override
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
return event_queue_.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the number of elements in the queue.
|
||||
* Thread safe
|
||||
* @return the number of elements in the queue.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
size_t
|
||||
size() const override
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mutex_);
|
||||
return event_queue_.size();
|
||||
}
|
||||
|
||||
private:
|
||||
// The underlying queue implementation
|
||||
std::queue<rclcpp::experimental::executors::ExecutorEvent> event_queue_;
|
||||
// Mutex to protect the insertion/extraction of events in the queue
|
||||
mutable std::mutex mutex_;
|
||||
// Variable used to notify when an event is added to the queue
|
||||
std::condition_variable events_queue_cv_;
|
||||
};
|
||||
|
||||
} // namespace executors
|
||||
} // namespace experimental
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__EXPERIMENTAL__EXECUTORS__EVENTS_EXECUTOR__SIMPLE_EVENTS_QUEUE_HPP_
|
||||
@@ -454,8 +454,6 @@ private:
|
||||
if (std::next(it) == subscription_ids.end()) {
|
||||
// If this is the last subscription, give up ownership
|
||||
subscription->provide_intra_process_data(std::move(message));
|
||||
// Last message delivered, break from for loop
|
||||
break;
|
||||
} else {
|
||||
// Copy the message since we have additional subscriptions to serve
|
||||
Deleter deleter = message.get_deleter();
|
||||
@@ -495,8 +493,6 @@ private:
|
||||
if (std::next(it) == subscription_ids.end()) {
|
||||
// If this is the last subscription, give up ownership
|
||||
ros_message_subscription->provide_intra_process_message(std::move(message));
|
||||
// Last message delivered, break from for loop
|
||||
break;
|
||||
} else {
|
||||
// Copy the message since we have additional subscriptions to serve
|
||||
Deleter deleter = message.get_deleter();
|
||||
|
||||
@@ -109,14 +109,8 @@ public:
|
||||
|
||||
if (any_callback_.use_take_shared_method()) {
|
||||
shared_msg = this->buffer_->consume_shared();
|
||||
if (!shared_msg) {
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
unique_msg = this->buffer_->consume_unique();
|
||||
if (!unique_msg) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return std::static_pointer_cast<void>(
|
||||
std::make_shared<std::pair<ConstMessageSharedPtr, MessageUniquePtr>>(
|
||||
@@ -144,7 +138,7 @@ protected:
|
||||
execute_impl(std::shared_ptr<void> & data)
|
||||
{
|
||||
if (!data) {
|
||||
return;
|
||||
throw std::runtime_error("'data' is empty");
|
||||
}
|
||||
|
||||
rmw_message_info_t msg_info;
|
||||
|
||||
@@ -52,7 +52,7 @@ public:
|
||||
{}
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual ~SubscriptionIntraProcessBase() = default;
|
||||
virtual ~SubscriptionIntraProcessBase();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
size_t
|
||||
|
||||
@@ -1,539 +0,0 @@
|
||||
// Copyright 2023 iRobot Corporation.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__EXPERIMENTAL__TIMERS_MANAGER_HPP_
|
||||
#define RCLCPP__EXPERIMENTAL__TIMERS_MANAGER_HPP_
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "rclcpp/context.hpp"
|
||||
#include "rclcpp/timer.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief This class provides a way for storing and executing timer objects.
|
||||
* It provides APIs to suit the needs of different applications and execution models.
|
||||
* All public APIs provided by this class are thread-safe.
|
||||
*
|
||||
* Timers management
|
||||
* This class provides APIs to add/remove timers to/from an internal storage.
|
||||
* It keeps a list of weak pointers from added timers, and locks them only when
|
||||
* they need to be executed or modified.
|
||||
* Timers are kept ordered in a binary-heap priority queue.
|
||||
* Calls to add/remove APIs will temporarily block the execution of the timers and
|
||||
* will require to reorder the internal priority queue.
|
||||
* Because of this, they have a not-negligible impact on the performance.
|
||||
*
|
||||
* Timers execution
|
||||
* The most efficient implementation consists in letting a TimersManager object
|
||||
* to spawn a thread where timers are monitored and periodically executed.
|
||||
* Besides this, other APIs allow to either execute a single timer or all the
|
||||
* currently ready ones.
|
||||
* This class assumes that the `execute_callback()` API of the stored timers is never
|
||||
* called by other entities, but it can only be called from here.
|
||||
* If this assumption is not respected, the heap property may be invalidated,
|
||||
* so timers may be executed out of order, without this object noticing it.
|
||||
*
|
||||
*/
|
||||
class TimersManager
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(TimersManager)
|
||||
|
||||
/**
|
||||
* @brief Construct a new TimersManager object
|
||||
*
|
||||
* @param context custom context to be used.
|
||||
* Shared ownership of the context is held until destruction.
|
||||
* @param on_ready_callback The timers on ready callback. if not callable,
|
||||
* this object will directly execute timers when they are ready.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
TimersManager(
|
||||
std::shared_ptr<rclcpp::Context> context,
|
||||
std::function<void(void *)> on_ready_callback = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Destruct the TimersManager object making sure to stop thread and release memory.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
~TimersManager();
|
||||
|
||||
/**
|
||||
* @brief Adds a new timer to the storage, maintaining weak ownership of it.
|
||||
* Function is thread safe and it can be called regardless of the state of the timers thread.
|
||||
*
|
||||
* @param timer the timer to add.
|
||||
* @throws std::invalid_argument if timer is a nullptr.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void add_timer(rclcpp::TimerBase::SharedPtr timer);
|
||||
|
||||
/**
|
||||
* @brief Remove a single timer from the object storage.
|
||||
* Will do nothing if the timer was not being stored here.
|
||||
* Function is thread safe and it can be called regardless of the state of the timers thread.
|
||||
*
|
||||
* @param timer the timer to remove.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void remove_timer(rclcpp::TimerBase::SharedPtr timer);
|
||||
|
||||
/**
|
||||
* @brief Remove all the timers stored in the object.
|
||||
* Function is thread safe and it can be called regardless of the state of the timers thread.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void clear();
|
||||
|
||||
/**
|
||||
* @brief Starts a thread that takes care of executing the timers stored in this object.
|
||||
* Function will throw an error if the timers thread was already running.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void start();
|
||||
|
||||
/**
|
||||
* @brief Stops the timers thread.
|
||||
* Will do nothing if the timer thread was not running.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void stop();
|
||||
|
||||
/**
|
||||
* @brief Executes all the timers currently ready when the function was invoked.
|
||||
* This function will lock all the stored timers throughout its duration.
|
||||
* This function is thread safe.
|
||||
* @throws std::runtime_error if the timers thread was already running.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void execute_ready_timers();
|
||||
|
||||
/**
|
||||
* @brief Get the number of timers that are currently ready.
|
||||
* This function is thread safe.
|
||||
*
|
||||
* @return size_t number of ready timers.
|
||||
* @throws std::runtime_error if the timers thread was already running.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
size_t get_number_ready_timers();
|
||||
|
||||
/**
|
||||
* @brief Executes head timer if ready.
|
||||
* This function is thread safe.
|
||||
*
|
||||
* @return true if head timer was ready.
|
||||
* @throws std::runtime_error if the timers thread was already running.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
bool execute_head_timer();
|
||||
|
||||
/**
|
||||
* @brief Executes timer identified by its ID.
|
||||
* This function is thread safe.
|
||||
*
|
||||
* @param timer_id the timer ID of the timer to execute
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void execute_ready_timer(const void * timer_id);
|
||||
|
||||
/**
|
||||
* @brief Get the amount of time before the next timer triggers.
|
||||
* This function is thread safe.
|
||||
*
|
||||
* @return std::chrono::nanoseconds to wait,
|
||||
* the returned value could be negative if the timer is already expired
|
||||
* or std::chrono::nanoseconds::max() if there are no timers stored in the object.
|
||||
* @throws std::runtime_error if the timers thread was already running.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
std::chrono::nanoseconds get_head_timeout();
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(TimersManager)
|
||||
|
||||
using TimerPtr = rclcpp::TimerBase::SharedPtr;
|
||||
using WeakTimerPtr = rclcpp::TimerBase::WeakPtr;
|
||||
|
||||
// Forward declaration
|
||||
class TimersHeap;
|
||||
|
||||
/**
|
||||
* @brief This class allows to store weak pointers to timers in a heap-like data structure.
|
||||
* The root of the heap is the timer that triggers first.
|
||||
* Since this class uses weak ownership, it is not guaranteed that it represents a valid heap
|
||||
* at any point in time as timers could go out of scope, thus invalidating it.
|
||||
* The "validate_and_lock" API allows to restore the heap property and also returns a locked version
|
||||
* of the timers heap.
|
||||
* This class is not thread safe and requires external mutexes to protect its usage.
|
||||
*/
|
||||
class WeakTimersHeap
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Add a new timer to the heap. After the addition, the heap property is enforced.
|
||||
*
|
||||
* @param timer new timer to add.
|
||||
* @return true if timer has been added, false if it was already there.
|
||||
*/
|
||||
bool add_timer(TimerPtr timer)
|
||||
{
|
||||
TimersHeap locked_heap = this->validate_and_lock();
|
||||
bool added = locked_heap.add_timer(std::move(timer));
|
||||
|
||||
if (added) {
|
||||
// Re-create the weak heap with the new timer added
|
||||
this->store(locked_heap);
|
||||
}
|
||||
|
||||
return added;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Remove a timer from the heap. After the removal, the heap property is enforced.
|
||||
*
|
||||
* @param timer timer to remove.
|
||||
* @return true if timer has been removed, false if it was not there.
|
||||
*/
|
||||
bool remove_timer(TimerPtr timer)
|
||||
{
|
||||
TimersHeap locked_heap = this->validate_and_lock();
|
||||
bool removed = locked_heap.remove_timer(std::move(timer));
|
||||
|
||||
if (removed) {
|
||||
// Re-create the weak heap with the timer removed
|
||||
this->store(locked_heap);
|
||||
}
|
||||
|
||||
return removed;
|
||||
}
|
||||
|
||||
TimerPtr get_timer(const void * timer_id)
|
||||
{
|
||||
for (auto & weak_timer : weak_heap_) {
|
||||
auto timer = weak_timer.lock();
|
||||
if (timer.get() == timer_id) {
|
||||
return timer;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a const reference to the front element.
|
||||
*/
|
||||
const WeakTimerPtr & front() const
|
||||
{
|
||||
return weak_heap_.front();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns whether the heap is empty or not.
|
||||
*/
|
||||
bool empty() const
|
||||
{
|
||||
return weak_heap_.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function restores the current object as a valid heap
|
||||
* and it returns a locked version of it.
|
||||
* Timers that went out of scope are removed from the container.
|
||||
* It is the only public API to access and manipulate the stored timers.
|
||||
*
|
||||
* @return TimersHeap owned timers corresponding to the current object
|
||||
*/
|
||||
TimersHeap validate_and_lock()
|
||||
{
|
||||
TimersHeap locked_heap;
|
||||
bool any_timer_destroyed = false;
|
||||
|
||||
for (auto weak_timer : weak_heap_) {
|
||||
auto timer = weak_timer.lock();
|
||||
if (timer) {
|
||||
// This timer is valid, so add it to the locked heap
|
||||
// Note: we access friend private `owned_heap_` member field.
|
||||
locked_heap.owned_heap_.push_back(std::move(timer));
|
||||
} else {
|
||||
// This timer went out of scope, so we don't add it to locked heap
|
||||
// and we mark the corresponding flag.
|
||||
// It's not needed to erase it from weak heap, as we are going to re-heapify.
|
||||
// Note: we can't exit from the loop here, as we need to find all valid timers.
|
||||
any_timer_destroyed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If a timer has gone out of scope, then the remaining elements do not represent
|
||||
// a valid heap anymore. We need to re-heapify the timers heap.
|
||||
if (any_timer_destroyed) {
|
||||
locked_heap.heapify();
|
||||
// Re-create the weak heap now that elements have been heapified again
|
||||
this->store(locked_heap);
|
||||
}
|
||||
|
||||
return locked_heap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function allows to recreate the heap of weak pointers
|
||||
* from an heap of owned pointers.
|
||||
* It is required to be called after a locked TimersHeap generated from this object
|
||||
* has been modified in any way (e.g. timers triggered, added, removed).
|
||||
*
|
||||
* @param heap timers heap to store as weak pointers
|
||||
*/
|
||||
void store(const TimersHeap & heap)
|
||||
{
|
||||
weak_heap_.clear();
|
||||
// Note: we access friend private `owned_heap_` member field.
|
||||
for (auto t : heap.owned_heap_) {
|
||||
weak_heap_.push_back(t);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Remove all timers from the heap.
|
||||
*/
|
||||
void clear()
|
||||
{
|
||||
weak_heap_.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<WeakTimerPtr> weak_heap_;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief This class is the equivalent of WeakTimersHeap but with ownership of the timers.
|
||||
* It can be generated by locking the weak version.
|
||||
* It provides operations to manipulate the heap.
|
||||
* This class is not thread safe and requires external mutexes to protect its usage.
|
||||
*/
|
||||
class TimersHeap
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Try to add a new timer to the heap.
|
||||
* After the addition, the heap property is preserved.
|
||||
* @param timer new timer to add.
|
||||
* @return true if timer has been added, false if it was already there.
|
||||
*/
|
||||
bool add_timer(TimerPtr timer)
|
||||
{
|
||||
// Nothing to do if the timer is already stored here
|
||||
auto it = std::find(owned_heap_.begin(), owned_heap_.end(), timer);
|
||||
if (it != owned_heap_.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
owned_heap_.push_back(std::move(timer));
|
||||
std::push_heap(owned_heap_.begin(), owned_heap_.end(), timer_greater);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Try to remove a timer from the heap.
|
||||
* After the removal, the heap property is preserved.
|
||||
* @param timer timer to remove.
|
||||
* @return true if timer has been removed, false if it was not there.
|
||||
*/
|
||||
bool remove_timer(TimerPtr timer)
|
||||
{
|
||||
// Nothing to do if the timer is not stored here
|
||||
auto it = std::find(owned_heap_.begin(), owned_heap_.end(), timer);
|
||||
if (it == owned_heap_.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
owned_heap_.erase(it);
|
||||
this->heapify();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a reference to the front element.
|
||||
* @return reference to front element.
|
||||
*/
|
||||
TimerPtr & front()
|
||||
{
|
||||
return owned_heap_.front();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns a const reference to the front element.
|
||||
* @return const reference to front element.
|
||||
*/
|
||||
const TimerPtr & front() const
|
||||
{
|
||||
return owned_heap_.front();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns whether the heap is empty or not.
|
||||
* @return true if the heap is empty.
|
||||
*/
|
||||
bool empty() const
|
||||
{
|
||||
return owned_heap_.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the size of the heap.
|
||||
* @return the number of valid timers in the heap.
|
||||
*/
|
||||
size_t size() const
|
||||
{
|
||||
return owned_heap_.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the number of timers that are currently ready.
|
||||
* @return size_t number of ready timers.
|
||||
*/
|
||||
size_t get_number_ready_timers() const
|
||||
{
|
||||
size_t ready_timers = 0;
|
||||
|
||||
for (TimerPtr t : owned_heap_) {
|
||||
if (t->is_ready()) {
|
||||
ready_timers++;
|
||||
}
|
||||
}
|
||||
|
||||
return ready_timers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Restore a valid heap after the root value has been replaced (e.g. timer triggered).
|
||||
*/
|
||||
void heapify_root()
|
||||
{
|
||||
// The following code is a more efficient version than doing
|
||||
// pop_heap, pop_back, push_back, push_heap
|
||||
// as it removes the need for the last push_heap
|
||||
|
||||
// Push the modified element (i.e. the current root) at the bottom of the heap
|
||||
owned_heap_.push_back(owned_heap_[0]);
|
||||
// Exchange first and last-1 elements and reheapify
|
||||
std::pop_heap(owned_heap_.begin(), owned_heap_.end(), timer_greater);
|
||||
// Remove last element
|
||||
owned_heap_.pop_back();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Completely restores the structure to a valid heap
|
||||
*/
|
||||
void heapify()
|
||||
{
|
||||
std::make_heap(owned_heap_.begin(), owned_heap_.end(), timer_greater);
|
||||
}
|
||||
|
||||
void clear_callbacks()
|
||||
{
|
||||
for (TimerPtr & t : owned_heap_) {
|
||||
t->clear_on_reset_callback();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Friend declaration to allow the `validate_and_lock()` function to access the
|
||||
* underlying heap container
|
||||
*/
|
||||
friend TimersHeap WeakTimersHeap::validate_and_lock();
|
||||
|
||||
/**
|
||||
* @brief Friend declaration to allow the `store()` function to access the
|
||||
* underlying heap container
|
||||
*/
|
||||
friend void WeakTimersHeap::store(const TimersHeap & heap);
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Comparison function between timers.
|
||||
* @return true if `a` triggers after `b`.
|
||||
*/
|
||||
static bool timer_greater(TimerPtr a, TimerPtr b)
|
||||
{
|
||||
// FIXME!
|
||||
return a->time_until_trigger() > b->time_until_trigger();
|
||||
}
|
||||
|
||||
std::vector<TimerPtr> owned_heap_;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Implements a loop that keeps executing ready timers.
|
||||
* This function is executed in the timers thread.
|
||||
*/
|
||||
void run_timers();
|
||||
|
||||
/**
|
||||
* @brief Get the amount of time before the next timer triggers.
|
||||
* This function is not thread safe, acquire a mutex before calling it.
|
||||
*
|
||||
* @return std::chrono::nanoseconds to wait,
|
||||
* the returned value could be negative if the timer is already expired
|
||||
* or std::chrono::nanoseconds::max() if the heap is empty.
|
||||
* This function is not thread safe, acquire the timers_mutex_ before calling it.
|
||||
*/
|
||||
std::chrono::nanoseconds get_head_timeout_unsafe();
|
||||
|
||||
/**
|
||||
* @brief Executes all the timers currently ready when the function is invoked
|
||||
* while keeping the heap correctly sorted.
|
||||
* This function is not thread safe, acquire the timers_mutex_ before calling it.
|
||||
*/
|
||||
void execute_ready_timers_unsafe();
|
||||
|
||||
// Callback to be called when timer is ready
|
||||
std::function<void(void *)> on_ready_callback_ = nullptr;
|
||||
|
||||
// Thread used to run the timers execution task
|
||||
std::thread timers_thread_;
|
||||
// Protects access to timers
|
||||
std::mutex timers_mutex_;
|
||||
// Protects access to stop()
|
||||
std::mutex stop_mutex_;
|
||||
// Notifies the timers thread whenever timers are added/removed
|
||||
std::condition_variable timers_cv_;
|
||||
// Flag used as predicate by timers_cv_ that denotes one or more timers being added/removed
|
||||
bool timers_updated_ {false};
|
||||
// Indicates whether the timers thread is currently running or not
|
||||
std::atomic<bool> running_ {false};
|
||||
// Parent context used to understand if ROS is still active
|
||||
std::shared_ptr<rclcpp::Context> context_;
|
||||
// Timers heap storage with weak ownership
|
||||
WeakTimersHeap weak_timers_heap_;
|
||||
};
|
||||
|
||||
} // namespace experimental
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__EXPERIMENTAL__TIMERS_MANAGER_HPP_
|
||||
@@ -78,12 +78,38 @@ public:
|
||||
node_base,
|
||||
topic_name,
|
||||
*rclcpp::get_typesupport_handle(topic_type, "rosidl_typesupport_cpp", *ts_lib),
|
||||
options.template to_rcl_publisher_options<rclcpp::SerializedMessage>(qos),
|
||||
// NOTE(methylDragon): Passing these args separately is necessary for event binding
|
||||
options.event_callbacks,
|
||||
options.use_default_callbacks),
|
||||
options.template to_rcl_publisher_options<rclcpp::SerializedMessage>(qos)),
|
||||
ts_lib_(ts_lib)
|
||||
{}
|
||||
{
|
||||
// This is unfortunately duplicated with the code in publisher.hpp.
|
||||
// TODO(nnmm): Deduplicate by moving this into PublisherBase.
|
||||
if (options.event_callbacks.deadline_callback) {
|
||||
this->add_event_handler(
|
||||
options.event_callbacks.deadline_callback,
|
||||
RCL_PUBLISHER_OFFERED_DEADLINE_MISSED);
|
||||
}
|
||||
if (options.event_callbacks.liveliness_callback) {
|
||||
this->add_event_handler(
|
||||
options.event_callbacks.liveliness_callback,
|
||||
RCL_PUBLISHER_LIVELINESS_LOST);
|
||||
}
|
||||
if (options.event_callbacks.incompatible_qos_callback) {
|
||||
this->add_event_handler(
|
||||
options.event_callbacks.incompatible_qos_callback,
|
||||
RCL_PUBLISHER_OFFERED_INCOMPATIBLE_QOS);
|
||||
} else if (options.use_default_callbacks) {
|
||||
// Register default callback when not specified
|
||||
try {
|
||||
this->add_event_handler(
|
||||
[this](QOSOfferedIncompatibleQoSInfo & info) {
|
||||
this->default_incompatible_qos_callback(info);
|
||||
},
|
||||
RCL_PUBLISHER_OFFERED_INCOMPATIBLE_QOS);
|
||||
} catch (UnsupportedEventTypeException & /*exc*/) {
|
||||
// pass
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual ~GenericPublisher() = default;
|
||||
|
||||
@@ -81,13 +81,45 @@ public:
|
||||
node_base,
|
||||
*rclcpp::get_typesupport_handle(topic_type, "rosidl_typesupport_cpp", *ts_lib),
|
||||
topic_name,
|
||||
options.to_rcl_subscription_options(qos),
|
||||
options.event_callbacks,
|
||||
options.use_default_callbacks,
|
||||
options.template to_rcl_subscription_options<rclcpp::SerializedMessage>(qos),
|
||||
true),
|
||||
callback_(callback),
|
||||
ts_lib_(ts_lib)
|
||||
{}
|
||||
{
|
||||
// This is unfortunately duplicated with the code in subscription.hpp.
|
||||
// TODO(nnmm): Deduplicate by moving this into SubscriptionBase.
|
||||
if (options.event_callbacks.deadline_callback) {
|
||||
this->add_event_handler(
|
||||
options.event_callbacks.deadline_callback,
|
||||
RCL_SUBSCRIPTION_REQUESTED_DEADLINE_MISSED);
|
||||
}
|
||||
if (options.event_callbacks.liveliness_callback) {
|
||||
this->add_event_handler(
|
||||
options.event_callbacks.liveliness_callback,
|
||||
RCL_SUBSCRIPTION_LIVELINESS_CHANGED);
|
||||
}
|
||||
if (options.event_callbacks.incompatible_qos_callback) {
|
||||
this->add_event_handler(
|
||||
options.event_callbacks.incompatible_qos_callback,
|
||||
RCL_SUBSCRIPTION_REQUESTED_INCOMPATIBLE_QOS);
|
||||
} else if (options.use_default_callbacks) {
|
||||
// Register default callback when not specified
|
||||
try {
|
||||
this->add_event_handler(
|
||||
[this](QOSRequestedIncompatibleQoSInfo & info) {
|
||||
this->default_incompatible_qos_callback(info);
|
||||
},
|
||||
RCL_SUBSCRIPTION_REQUESTED_INCOMPATIBLE_QOS);
|
||||
} catch (UnsupportedEventTypeException & /*exc*/) {
|
||||
// pass
|
||||
}
|
||||
}
|
||||
if (options.event_callbacks.message_lost_callback) {
|
||||
this->add_event_handler(
|
||||
options.event_callbacks.message_lost_callback,
|
||||
RCL_SUBSCRIPTION_MESSAGE_LOST);
|
||||
}
|
||||
}
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual ~GenericSubscription() = default;
|
||||
|
||||
@@ -128,11 +128,6 @@ 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
|
||||
|
||||
@@ -72,7 +72,7 @@ public:
|
||||
const rcl_guard_condition_t &
|
||||
get_rcl_guard_condition() const;
|
||||
|
||||
/// Signal that the condition has been met, notifying both the wait set and listeners, if any.
|
||||
/// Notify the wait set waiting on this condition, if any, that the condition had been met.
|
||||
/**
|
||||
* This function is thread-safe, and may be called concurrently with waiting
|
||||
* on this guard condition in a wait set.
|
||||
@@ -107,22 +107,6 @@ 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);
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
@@ -123,7 +122,6 @@ private:
|
||||
: name_(new std::string(name)) {}
|
||||
|
||||
std::shared_ptr<const std::string> name_;
|
||||
std::shared_ptr<std::pair<std::string, std::string>> logger_sublogger_pairname_ = nullptr;
|
||||
|
||||
public:
|
||||
RCLCPP_PUBLIC
|
||||
@@ -159,7 +157,13 @@ public:
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
Logger
|
||||
get_child(const std::string & suffix);
|
||||
get_child(const std::string & suffix)
|
||||
{
|
||||
if (!name_) {
|
||||
return Logger();
|
||||
}
|
||||
return Logger(*name_ + "." + suffix);
|
||||
}
|
||||
|
||||
/// Set level for current logger.
|
||||
/**
|
||||
|
||||
@@ -227,7 +227,7 @@ public:
|
||||
)
|
||||
);
|
||||
|
||||
/// Create a wall timer that uses the wall clock to drive the callback.
|
||||
/// Create a timer.
|
||||
/**
|
||||
* \param[in] period Time interval between triggers of the callback.
|
||||
* \param[in] callback User-defined callback function.
|
||||
@@ -240,47 +240,18 @@ 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 rclcpp::QoS & qos = rclcpp::ServicesQoS(),
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_services_default,
|
||||
rclcpp::CallbackGroup::SharedPtr group = nullptr);
|
||||
|
||||
/// Create and return a Service.
|
||||
@@ -290,31 +261,13 @@ 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 rclcpp::QoS & qos = rclcpp::ServicesQoS(),
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_services_default,
|
||||
rclcpp::CallbackGroup::SharedPtr group = nullptr);
|
||||
|
||||
/// Create and return a GenericPublisher.
|
||||
@@ -383,21 +336,11 @@ public:
|
||||
*
|
||||
* If `ignore_override` is `true`, the parameter override 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 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.
|
||||
* This method, if successful, will result in any callback registered with
|
||||
* add_on_set_parameters_callback to be called.
|
||||
* 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.
|
||||
*
|
||||
@@ -514,22 +457,11 @@ 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.
|
||||
@@ -567,9 +499,8 @@ public:
|
||||
|
||||
/// Undeclare a previously declared parameter.
|
||||
/**
|
||||
* 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.
|
||||
* This method will not cause a callback registered with
|
||||
* add_on_set_parameters_callback to be called.
|
||||
*
|
||||
* \param[in] name The name of the parameter to be undeclared.
|
||||
* \throws rclcpp::exceptions::ParameterNotDeclaredException if the parameter
|
||||
@@ -603,24 +534,11 @@ public:
|
||||
* Parameter overrides are ignored by set_parameter.
|
||||
*
|
||||
* This method will result in any callback registered with
|
||||
* `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.
|
||||
* 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.
|
||||
@@ -657,25 +575,11 @@ public:
|
||||
* corresponding SetParametersResult in the vector returned by this function.
|
||||
*
|
||||
* This method will result in any callback registered with
|
||||
* `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.
|
||||
* 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.
|
||||
*
|
||||
@@ -702,25 +606,11 @@ 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_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.
|
||||
* 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.
|
||||
*
|
||||
@@ -740,21 +630,17 @@ public:
|
||||
/**
|
||||
* If the parameter has not been declared, then this method may throw the
|
||||
* rclcpp::exceptions::ParameterNotDeclaredException exception.
|
||||
* If the parameter has not been initialized, then this method may throw the
|
||||
* rclcpp::exceptions::ParameterUninitializedException exception.
|
||||
*
|
||||
* If undeclared parameters are allowed, see the node option
|
||||
* rclcpp::NodeOptions::allow_undeclared_parameters, then this method will
|
||||
* not throw the rclcpp::exceptions::ParameterNotDeclaredException exception,
|
||||
* and instead return a default initialized rclcpp::Parameter, which has a type of
|
||||
* not throw an exception, and instead return a default initialized
|
||||
* rclcpp::Parameter, which has a type of
|
||||
* rclcpp::ParameterType::PARAMETER_NOT_SET.
|
||||
*
|
||||
* \param[in] name The name of the parameter to get.
|
||||
* \return The requested parameter inside of a rclcpp parameter object.
|
||||
* \throws rclcpp::exceptions::ParameterNotDeclaredException if the parameter
|
||||
* has not been declared and undeclared parameters are not allowed.
|
||||
* \throws rclcpp::exceptions::ParameterUninitializedException if the parameter
|
||||
* has not been initialized.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::Parameter
|
||||
@@ -838,12 +724,12 @@ public:
|
||||
|
||||
/// Return the parameters by the given parameter names.
|
||||
/**
|
||||
* Like get_parameter(const std::string &), this method may throw the
|
||||
* Like get_parameters(), this method may throw the
|
||||
* rclcpp::exceptions::ParameterNotDeclaredException exception if the
|
||||
* requested parameter has not been declared and undeclared parameters are
|
||||
* not allowed, and may throw the rclcpp::exceptions::ParameterUninitializedException exception.
|
||||
* not allowed.
|
||||
*
|
||||
* Also like get_parameter(const std::string &), if undeclared parameters are allowed and the
|
||||
* Also like get_parameters(), if undeclared parameters are allowed and the
|
||||
* parameter has not been declared, then the corresponding rclcpp::Parameter
|
||||
* will be default initialized and therefore have the type
|
||||
* rclcpp::ParameterType::PARAMETER_NOT_SET.
|
||||
@@ -853,8 +739,6 @@ public:
|
||||
* \throws rclcpp::exceptions::ParameterNotDeclaredException if any of the
|
||||
* parameters have not been declared and undeclared parameters are not
|
||||
* allowed.
|
||||
* \throws rclcpp::exceptions::ParameterUninitializedException if any of the
|
||||
* parameters have not been initialized.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<rclcpp::Parameter>
|
||||
@@ -975,85 +859,12 @@ 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 OnSetParametersCallbackType =
|
||||
rclcpp::node_interfaces::NodeParametersInterface::OnSetParametersCallbackType;
|
||||
using OnParametersSetCallbackType [[deprecated("use OnSetParametersCallbackType instead")]] =
|
||||
OnSetParametersCallbackType;
|
||||
using OnParametersSetCallbackType =
|
||||
rclcpp::node_interfaces::NodeParametersInterface::OnParametersSetCallbackType;
|
||||
|
||||
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.
|
||||
/// Add a callback for when parameters are being 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
|
||||
@@ -1061,9 +872,6 @@ 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
|
||||
@@ -1095,8 +903,6 @@ 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
|
||||
@@ -1125,80 +931,7 @@ public:
|
||||
RCLCPP_PUBLIC
|
||||
RCUTILS_WARN_UNUSED
|
||||
OnSetParametersCallbackHandle::SharedPtr
|
||||
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);
|
||||
add_on_set_parameters_callback(OnParametersSetCallbackType callback);
|
||||
|
||||
/// Remove a callback registered with `add_on_set_parameters_callback`.
|
||||
/**
|
||||
@@ -1227,18 +960,6 @@ 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.
|
||||
|
||||
@@ -120,38 +120,6 @@ 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(
|
||||
@@ -168,23 +136,6 @@ 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(
|
||||
|
||||
@@ -1,208 +0,0 @@
|
||||
// Copyright 2022 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__NODE_INTERFACES__DETAIL__NODE_INTERFACES_HELPERS_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__DETAIL__NODE_INTERFACES_HELPERS_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace node_interfaces
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
// Support and Helper template classes for the NodeInterfaces class.
|
||||
|
||||
template<typename NodeT, typename ... Ts>
|
||||
std::tuple<std::shared_ptr<Ts>...>
|
||||
init_tuple(NodeT & n);
|
||||
|
||||
/// Stores the interfaces in a tuple, provides constructors, and getters.
|
||||
template<typename ... InterfaceTs>
|
||||
struct NodeInterfacesStorage
|
||||
{
|
||||
template<typename NodeT>
|
||||
NodeInterfacesStorage(NodeT & node) // NOLINT(runtime/explicit)
|
||||
: interfaces_(init_tuple<decltype(node), InterfaceTs ...>(node))
|
||||
{}
|
||||
|
||||
NodeInterfacesStorage()
|
||||
: interfaces_()
|
||||
{}
|
||||
|
||||
explicit NodeInterfacesStorage(std::shared_ptr<InterfaceTs>... args)
|
||||
: interfaces_(args ...)
|
||||
{}
|
||||
|
||||
/// Individual Node Interface non-const getter.
|
||||
template<typename NodeInterfaceT>
|
||||
std::shared_ptr<NodeInterfaceT>
|
||||
get()
|
||||
{
|
||||
static_assert(
|
||||
(std::is_same_v<NodeInterfaceT, InterfaceTs>|| ...),
|
||||
"NodeInterfaces class does not contain given NodeInterfaceT");
|
||||
return std::get<std::shared_ptr<NodeInterfaceT>>(interfaces_);
|
||||
}
|
||||
|
||||
/// Individual Node Interface const getter.
|
||||
template<typename NodeInterfaceT>
|
||||
std::shared_ptr<const NodeInterfaceT>
|
||||
get() const
|
||||
{
|
||||
static_assert(
|
||||
(std::is_same_v<NodeInterfaceT, InterfaceTs>|| ...),
|
||||
"NodeInterfaces class does not contain given NodeInterfaceT");
|
||||
return std::get<std::shared_ptr<NodeInterfaceT>>(interfaces_);
|
||||
}
|
||||
|
||||
protected:
|
||||
std::tuple<std::shared_ptr<InterfaceTs>...> interfaces_;
|
||||
};
|
||||
|
||||
/// Prototype of NodeInterfacesSupports.
|
||||
/**
|
||||
* Should read NodeInterfacesSupports<..., T, ...> as "NodeInterfaces supports T", and
|
||||
* if NodeInterfacesSupport is specialized for T, the is_supported should be
|
||||
* set to std::true_type, but by default it is std::false_type, which will
|
||||
* lead to a compiler error when trying to use T with NodeInterfaces.
|
||||
*/
|
||||
template<typename StorageClassT, typename ... Ts>
|
||||
struct NodeInterfacesSupports;
|
||||
|
||||
/// Prototype of NodeInterfacesSupportCheck template meta-function.
|
||||
/**
|
||||
* This meta-function checks that all the types given are supported,
|
||||
* throwing a more human-readable error if an unsupported type is used.
|
||||
*/
|
||||
template<typename StorageClassT, typename ... InterfaceTs>
|
||||
struct NodeInterfacesSupportCheck;
|
||||
|
||||
/// Iterating specialization that ensures classes are supported and inherited.
|
||||
template<typename StorageClassT, typename NextInterfaceT, typename ... RemainingInterfaceTs>
|
||||
struct NodeInterfacesSupportCheck<StorageClassT, NextInterfaceT, RemainingInterfaceTs ...>
|
||||
: public NodeInterfacesSupportCheck<StorageClassT, RemainingInterfaceTs ...>
|
||||
{
|
||||
static_assert(
|
||||
NodeInterfacesSupports<StorageClassT, NextInterfaceT>::is_supported::value,
|
||||
"given NodeInterfaceT is not supported by rclcpp::node_interfaces::NodeInterfaces");
|
||||
};
|
||||
|
||||
/// Terminating case when there are no more "RemainingInterfaceTs".
|
||||
template<typename StorageClassT>
|
||||
struct NodeInterfacesSupportCheck<StorageClassT>
|
||||
{};
|
||||
|
||||
/// Default specialization, needs to be specialized for each supported interface.
|
||||
template<typename StorageClassT, typename ... RemainingInterfaceTs>
|
||||
struct NodeInterfacesSupports
|
||||
{
|
||||
// Specializations need to set this to std::true_type in addition to other interfaces.
|
||||
using is_supported = std::false_type;
|
||||
};
|
||||
|
||||
/// Terminating specialization of NodeInterfacesSupports.
|
||||
template<typename StorageClassT>
|
||||
struct NodeInterfacesSupports<StorageClassT>
|
||||
: public StorageClassT
|
||||
{
|
||||
/// Perfect forwarding constructor to get arguments down to StorageClassT.
|
||||
template<typename ... ArgsT>
|
||||
explicit NodeInterfacesSupports(ArgsT && ... args)
|
||||
: StorageClassT(std::forward<ArgsT>(args) ...)
|
||||
{}
|
||||
};
|
||||
|
||||
// Helper functions to initialize the tuple in NodeInterfaces.
|
||||
|
||||
template<typename StorageClassT, typename ElementT, typename TupleT, typename NodeT>
|
||||
void
|
||||
init_element(TupleT & t, NodeT & n)
|
||||
{
|
||||
std::get<std::shared_ptr<ElementT>>(t) =
|
||||
NodeInterfacesSupports<StorageClassT, ElementT>::get_from_node_like(n);
|
||||
}
|
||||
|
||||
template<typename NodeT, typename ... Ts>
|
||||
std::tuple<std::shared_ptr<Ts>...>
|
||||
init_tuple(NodeT & n)
|
||||
{
|
||||
using StorageClassT = NodeInterfacesStorage<Ts ...>;
|
||||
std::tuple<std::shared_ptr<Ts>...> t;
|
||||
(init_element<StorageClassT, Ts>(t, n), ...);
|
||||
return t;
|
||||
}
|
||||
|
||||
/// Macro for creating specializations with less boilerplate.
|
||||
/**
|
||||
* You can use this macro to add support for your interface class if:
|
||||
*
|
||||
* - The standard getter is get_node_{NodeInterfaceName}_interface(), and
|
||||
* - the getter returns a non-const shared_ptr<{NodeInterfaceType}>
|
||||
*
|
||||
* Examples of using this can be seen in the standard node interface headers
|
||||
* in rclcpp, e.g. rclcpp/node_interfaces/node_base_interface.hpp has:
|
||||
*
|
||||
* RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeBaseInterface, base)
|
||||
*
|
||||
* If your interface has a non-standard getter, or you want to instrument it or
|
||||
* something like that, then you'll need to create your own specialization of
|
||||
* the NodeInterfacesSupports struct without this macro.
|
||||
*/
|
||||
#define RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(NodeInterfaceType, NodeInterfaceName) \
|
||||
namespace rclcpp::node_interfaces::detail { \
|
||||
template<typename StorageClassT, typename ... RemainingInterfaceTs> \
|
||||
struct NodeInterfacesSupports< \
|
||||
StorageClassT, \
|
||||
NodeInterfaceType, \
|
||||
RemainingInterfaceTs ...> \
|
||||
: public NodeInterfacesSupports<StorageClassT, RemainingInterfaceTs ...> \
|
||||
{ \
|
||||
using is_supported = std::true_type; \
|
||||
\
|
||||
template<typename NodeT> \
|
||||
static \
|
||||
std::shared_ptr<NodeInterfaceType> \
|
||||
get_from_node_like(NodeT & node_like) \
|
||||
{ \
|
||||
return node_like.get_node_ ## NodeInterfaceName ## _interface(); \
|
||||
} \
|
||||
\
|
||||
/* Perfect forwarding constructor to get arguments down to StorageClassT (eventually). */ \
|
||||
template<typename ... ArgsT> \
|
||||
explicit NodeInterfacesSupports(ArgsT && ... args) \
|
||||
: NodeInterfacesSupports<StorageClassT, RemainingInterfaceTs ...>( \
|
||||
std::forward<ArgsT>(args) ...) \
|
||||
{} \
|
||||
\
|
||||
std::shared_ptr<NodeInterfaceType> \
|
||||
get_node_ ## NodeInterfaceName ## _interface() \
|
||||
{ \
|
||||
return StorageClassT::template get<NodeInterfaceType>(); \
|
||||
} \
|
||||
}; \
|
||||
} // namespace rclcpp::node_interfaces::detail
|
||||
|
||||
} // namespace detail
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__DETAIL__NODE_INTERFACES_HELPERS_HPP_
|
||||
@@ -15,7 +15,7 @@
|
||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_BASE_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__NODE_BASE_HPP_
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
@@ -39,13 +39,6 @@ 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,
|
||||
@@ -53,8 +46,7 @@ public:
|
||||
rclcpp::Context::SharedPtr context,
|
||||
const rcl_node_options_t & rcl_node_options,
|
||||
bool use_intra_process_default,
|
||||
bool enable_topic_statistics_default,
|
||||
rclcpp::CallbackGroup::SharedPtr default_callback_group = nullptr);
|
||||
bool enable_topic_statistics_default);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_BASE_INTERFACE_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__NODE_BASE_INTERFACE_HPP_
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "rcl/node.h"
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include "rclcpp/context.hpp"
|
||||
#include "rclcpp/guard_condition.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
@@ -178,6 +177,4 @@ public:
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeBaseInterface, base)
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_BASE_INTERFACE_HPP_
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_CLOCK_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__NODE_CLOCK_HPP_
|
||||
|
||||
#include "rcl/time.h"
|
||||
#include "rclcpp/clock.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
@@ -43,8 +42,7 @@ public:
|
||||
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics,
|
||||
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph,
|
||||
rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services,
|
||||
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging,
|
||||
rcl_clock_type_t clock_type);
|
||||
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
@@ -69,7 +67,7 @@ private:
|
||||
rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services_;
|
||||
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging_;
|
||||
|
||||
rclcpp::Clock::SharedPtr clock_;
|
||||
rclcpp::Clock::SharedPtr ros_clock_;
|
||||
};
|
||||
|
||||
} // namespace node_interfaces
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
#include "rclcpp/clock.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
@@ -51,6 +50,4 @@ public:
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeClockInterface, clock)
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_CLOCK_INTERFACE_HPP_
|
||||
|
||||
@@ -15,9 +15,7 @@
|
||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_GRAPH_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__NODE_GRAPH_HPP_
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
|
||||
#include "rclcpp/event.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
@@ -383,6 +382,4 @@ public:
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeGraphInterface, graph)
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_GRAPH_INTERFACE_HPP_
|
||||
|
||||
@@ -1,164 +0,0 @@
|
||||
// Copyright 2022 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_INTERFACES_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__NODE_INTERFACES_HPP_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "rclcpp/detail/template_unique.hpp"
|
||||
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||
|
||||
#define ALL_RCLCPP_NODE_INTERFACES \
|
||||
rclcpp::node_interfaces::NodeBaseInterface, \
|
||||
rclcpp::node_interfaces::NodeClockInterface, \
|
||||
rclcpp::node_interfaces::NodeGraphInterface, \
|
||||
rclcpp::node_interfaces::NodeLoggingInterface, \
|
||||
rclcpp::node_interfaces::NodeParametersInterface, \
|
||||
rclcpp::node_interfaces::NodeServicesInterface, \
|
||||
rclcpp::node_interfaces::NodeTimeSourceInterface, \
|
||||
rclcpp::node_interfaces::NodeTimersInterface, \
|
||||
rclcpp::node_interfaces::NodeTopicsInterface, \
|
||||
rclcpp::node_interfaces::NodeWaitablesInterface
|
||||
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace node_interfaces
|
||||
{
|
||||
|
||||
|
||||
/// A helper class for aggregating node interfaces.
|
||||
template<typename ... InterfaceTs>
|
||||
class NodeInterfaces
|
||||
: public detail::NodeInterfacesSupportCheck<
|
||||
detail::NodeInterfacesStorage<InterfaceTs ...>,
|
||||
InterfaceTs ...
|
||||
>,
|
||||
public detail::NodeInterfacesSupports<
|
||||
detail::NodeInterfacesStorage<InterfaceTs ...>,
|
||||
InterfaceTs ...
|
||||
>
|
||||
{
|
||||
static_assert(
|
||||
0 != sizeof ...(InterfaceTs),
|
||||
"must provide at least one interface as a template argument");
|
||||
static_assert(
|
||||
rclcpp::detail::template_unique_v<InterfaceTs ...>,
|
||||
"must provide unique template parameters");
|
||||
|
||||
using NodeInterfacesSupportsT = detail::NodeInterfacesSupports<
|
||||
detail::NodeInterfacesStorage<InterfaceTs ...>,
|
||||
InterfaceTs ...
|
||||
>;
|
||||
|
||||
public:
|
||||
/// Create a new NodeInterfaces object using the given node-like object's interfaces.
|
||||
/**
|
||||
* Specify which interfaces you need by passing them as template parameters.
|
||||
*
|
||||
* This allows you to aggregate interfaces from different sources together to pass as a single
|
||||
* aggregate object to any functions that take node interfaces or node-likes, without needing to
|
||||
* templatize that function.
|
||||
*
|
||||
* You may also use this constructor to create a NodeInterfaces that contains a subset of
|
||||
* another NodeInterfaces' interfaces.
|
||||
*
|
||||
* Finally, this class supports implicit conversion from node-like objects, allowing you to
|
||||
* directly pass a node-like to a function that takes a NodeInterfaces object.
|
||||
*
|
||||
* Usage examples:
|
||||
* ```cpp
|
||||
* // Suppose we have some function:
|
||||
* void fn(NodeInterfaces<NodeBaseInterface, NodeClockInterface> interfaces);
|
||||
*
|
||||
* // Then we can, explicitly:
|
||||
* rclcpp::Node node("some_node");
|
||||
* auto ni = NodeInterfaces<NodeBaseInterface, NodeClockInterface>(node);
|
||||
* fn(ni);
|
||||
*
|
||||
* // But also:
|
||||
* fn(node);
|
||||
*
|
||||
* // Subsetting a NodeInterfaces object also works!
|
||||
* auto ni_base = NodeInterfaces<NodeBaseInterface>(ni);
|
||||
*
|
||||
* // Or aggregate them (you could aggregate interfaces from disparate node-likes)
|
||||
* auto ni_aggregated = NodeInterfaces<NodeBaseInterface, NodeClockInterface>(
|
||||
* node->get_node_base_interface(),
|
||||
* node->get_node_clock_interface()
|
||||
* )
|
||||
*
|
||||
* // And then to access the interfaces:
|
||||
* // Get with get<>
|
||||
* auto base = ni.get<NodeBaseInterface>();
|
||||
*
|
||||
* // Or the appropriate getter
|
||||
* auto clock = ni.get_clock_interface();
|
||||
* ```
|
||||
*
|
||||
* You may use any of the standard node interfaces that come with rclcpp:
|
||||
* - rclcpp::node_interfaces::NodeBaseInterface
|
||||
* - rclcpp::node_interfaces::NodeClockInterface
|
||||
* - rclcpp::node_interfaces::NodeGraphInterface
|
||||
* - rclcpp::node_interfaces::NodeLoggingInterface
|
||||
* - rclcpp::node_interfaces::NodeParametersInterface
|
||||
* - rclcpp::node_interfaces::NodeServicesInterface
|
||||
* - rclcpp::node_interfaces::NodeTimeSourceInterface
|
||||
* - rclcpp::node_interfaces::NodeTimersInterface
|
||||
* - rclcpp::node_interfaces::NodeTopicsInterface
|
||||
* - rclcpp::node_interfaces::NodeWaitablesInterface
|
||||
*
|
||||
* Or you use custom interfaces as long as you make a template specialization
|
||||
* of the rclcpp::node_interfaces::detail::NodeInterfacesSupport struct using
|
||||
* the RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT macro.
|
||||
*
|
||||
* Usage example:
|
||||
* ```RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeBaseInterface, base)```
|
||||
*
|
||||
* If you choose not to use the helper macro, then you can specialize the
|
||||
* template yourself, but you must:
|
||||
*
|
||||
* - Provide a template specialization of the get_from_node_like method that gets the interface
|
||||
* from any node-like that stores the interface, using the node-like's getter
|
||||
* - Designate the is_supported type as std::true_type using a using directive
|
||||
* - Provide any number of getter methods to be used to obtain the interface with the
|
||||
* NodeInterface object, noting that the getters of the storage class will apply to all
|
||||
* supported interfaces.
|
||||
* - The getter method names should not clash in name with any other interface getter
|
||||
* specializations if those other interfaces are meant to be aggregated in the same
|
||||
* NodeInterfaces object.
|
||||
*
|
||||
* \param[in] node Node-like object from which to get the node interfaces
|
||||
*/
|
||||
template<typename NodeT>
|
||||
NodeInterfaces(NodeT & node) // NOLINT(runtime/explicit)
|
||||
: NodeInterfacesSupportsT(node)
|
||||
{}
|
||||
|
||||
// Create a NodeInterfaces object with no bound interfaces
|
||||
NodeInterfaces()
|
||||
: NodeInterfacesSupportsT()
|
||||
{}
|
||||
|
||||
explicit NodeInterfaces(std::shared_ptr<InterfaceTs>... args)
|
||||
: NodeInterfacesSupportsT(args ...)
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_INTERFACES_HPP_
|
||||
@@ -19,7 +19,6 @@
|
||||
|
||||
#include "rclcpp/logger.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
@@ -38,18 +37,14 @@ 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 *
|
||||
@@ -59,6 +54,4 @@ public:
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeLoggingInterface, logging)
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_LOGGING_INTERFACE_HPP_
|
||||
|
||||
@@ -15,10 +15,9 @@
|
||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_HPP_
|
||||
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -85,16 +84,6 @@ 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,
|
||||
@@ -182,48 +171,20 @@ 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(OnSetParametersCallbackType callback) override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
RCUTILS_WARN_UNUSED
|
||||
PostSetParametersCallbackHandle::SharedPtr
|
||||
add_post_set_parameters_callback(PostSetParametersCallbackType callback) override;
|
||||
add_on_set_parameters_callback(OnParametersSetCallbackType 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 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();
|
||||
using CallbacksContainerType = std::list<OnSetParametersCallbackHandle::WeakPtr>;
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(NodeParameters)
|
||||
@@ -235,11 +196,9 @@ private:
|
||||
// declare_parameter, etc). In those cases, this will be set to false.
|
||||
bool parameter_modification_enabled_{true};
|
||||
|
||||
PreSetCallbacksHandleContainer pre_set_parameters_callback_container_;
|
||||
OnParametersSetCallbackType on_parameters_set_callback_ = nullptr;
|
||||
|
||||
OnSetCallbacksHandleContainer on_set_parameters_callback_container_;
|
||||
|
||||
PostSetCallbacksHandleContainer post_set_parameters_callback_container_;
|
||||
CallbacksContainerType on_parameters_set_callback_container_;
|
||||
|
||||
std::map<std::string, ParameterInfo> parameters_;
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@
|
||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_INTERFACE_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_INTERFACE_HPP_
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include "rcl_interfaces/msg/set_parameters_result.hpp"
|
||||
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||
#include "rclcpp/parameter.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
@@ -34,38 +33,16 @@ 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 OnSetParametersCallbackType =
|
||||
using OnParametersSetCallbackType =
|
||||
std::function<
|
||||
rcl_interfaces::msg::SetParametersResult(
|
||||
const std::vector<rclcpp::Parameter> &)>;
|
||||
using OnParametersSetCallbackType [[deprecated("use OnSetParametersCallbackType instead")]] =
|
||||
OnSetParametersCallbackType;
|
||||
|
||||
OnSetParametersCallbackType callback;
|
||||
};
|
||||
|
||||
struct PostSetParametersCallbackHandle
|
||||
{
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(PostSetParametersCallbackHandle)
|
||||
|
||||
using PostSetParametersCallbackType =
|
||||
std::function<void (const std::vector<rclcpp::Parameter> &)>;
|
||||
|
||||
PostSetParametersCallbackType callback;
|
||||
OnParametersSetCallbackType callback;
|
||||
};
|
||||
|
||||
/// Pure virtual interface class for the NodeParameters part of the Node API.
|
||||
@@ -208,46 +185,16 @@ public:
|
||||
rcl_interfaces::msg::ListParametersResult
|
||||
list_parameters(const std::vector<std::string> & prefixes, uint64_t depth) const = 0;
|
||||
|
||||
using OnSetParametersCallbackType = OnSetParametersCallbackHandle::OnSetParametersCallbackType;
|
||||
using PostSetParametersCallbackType =
|
||||
PostSetParametersCallbackHandle::PostSetParametersCallbackType;
|
||||
using PreSetParametersCallbackType = PreSetParametersCallbackHandle::PreSetParametersCallbackType;
|
||||
using OnParametersSetCallbackType = OnSetParametersCallbackHandle::OnParametersSetCallbackType;
|
||||
|
||||
/// 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.
|
||||
/// Add a callback for when parameters are being set.
|
||||
/**
|
||||
* \sa rclcpp::Node::add_on_set_parameters_callback
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
OnSetParametersCallbackHandle::SharedPtr
|
||||
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;
|
||||
add_on_set_parameters_callback(OnParametersSetCallbackType callback) = 0;
|
||||
|
||||
/// Remove a callback registered with `add_on_set_parameters_callback`.
|
||||
/**
|
||||
@@ -258,15 +205,6 @@ 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
|
||||
@@ -277,6 +215,4 @@ public:
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeParametersInterface, parameters)
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_INTERFACE_HPP_
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include "rclcpp/callback_group.hpp"
|
||||
#include "rclcpp/client.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||
#include "rclcpp/service.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
@@ -63,6 +62,4 @@ public:
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeServicesInterface, services)
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_SERVICES_INTERFACE_HPP_
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#define RCLCPP__NODE_INTERFACES__NODE_TIME_SOURCE_INTERFACE_HPP_
|
||||
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
@@ -38,6 +37,4 @@ public:
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeTimeSourceInterface, time_source)
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_TIME_SOURCE_INTERFACE_HPP_
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
#include "rclcpp/callback_group.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||
#include "rclcpp/timer.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
@@ -48,6 +47,4 @@ public:
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeTimersInterface, timers)
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_TIMERS_INTERFACE_HPP_
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_TOPICS_INTERFACE_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__NODE_TOPICS_INTERFACE_HPP_
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "rcl/publisher.h"
|
||||
@@ -22,7 +24,6 @@
|
||||
|
||||
#include "rclcpp/callback_group.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_timers_interface.hpp"
|
||||
#include "rclcpp/publisher.hpp"
|
||||
@@ -96,6 +97,4 @@ public:
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeTopicsInterface, topics)
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_TOPICS_INTERFACE_HPP_
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
#include "rclcpp/callback_group.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/detail/node_interfaces_helpers.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
#include "rclcpp/waitable.hpp"
|
||||
|
||||
@@ -55,6 +54,4 @@ public:
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
RCLCPP_NODE_INTERFACE_HELPERS_SUPPORT(rclcpp::node_interfaces::NodeWaitablesInterface, waitables)
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_WAITABLES_INTERFACE_HPP_
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "rcl/time.h"
|
||||
#include "rcl/node_options.h"
|
||||
#include "rclcpp/context.hpp"
|
||||
#include "rclcpp/contexts/default_context.hpp"
|
||||
@@ -47,7 +46,6 @@ public:
|
||||
* - enable_topic_statistics = false
|
||||
* - start_parameter_services = true
|
||||
* - start_parameter_event_publisher = true
|
||||
* - clock_type = RCL_ROS_TIME
|
||||
* - clock_qos = rclcpp::ClockQoS()
|
||||
* - use_clock_thread = true
|
||||
* - rosout_qos = rclcpp::RosoutQoS()
|
||||
@@ -248,19 +246,6 @@ public:
|
||||
NodeOptions &
|
||||
start_parameter_event_publisher(bool start_parameter_event_publisher);
|
||||
|
||||
/// Return a reference to the clock type.
|
||||
RCLCPP_PUBLIC
|
||||
const rcl_clock_type_t &
|
||||
clock_type() const;
|
||||
|
||||
/// Set the clock type.
|
||||
/**
|
||||
* The clock type to be used by the node.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
NodeOptions &
|
||||
clock_type(const rcl_clock_type_t & clock_type);
|
||||
|
||||
/// Return a reference to the clock QoS.
|
||||
RCLCPP_PUBLIC
|
||||
const rclcpp::QoS &
|
||||
@@ -415,8 +400,6 @@ private:
|
||||
|
||||
bool start_parameter_event_publisher_ {true};
|
||||
|
||||
rcl_clock_type_t clock_type_ {RCL_ROS_TIME};
|
||||
|
||||
rclcpp::QoS clock_qos_ = rclcpp::ClockQoS();
|
||||
|
||||
bool use_clock_thread_ {true};
|
||||
|
||||
@@ -39,7 +39,6 @@
|
||||
#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"
|
||||
@@ -52,37 +51,6 @@ 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.
|
||||
@@ -90,7 +58,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 qos profile to use to subscribe
|
||||
* \param[in] qos_profile (optional) The rmw qos profile to use to subscribe
|
||||
* \param[in] group (optional) The async parameter client will be added to this callback group.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
@@ -100,45 +68,21 @@ 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 rclcpp::QoS & qos_profile = rclcpp::ParametersQoS(),
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters,
|
||||
rclcpp::CallbackGroup::SharedPtr group = nullptr);
|
||||
|
||||
/// Constructor
|
||||
/**
|
||||
* \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] node The async paramters client will be added to this node.
|
||||
* \param[in] remote_node_name (optional) name of the remote node
|
||||
* \param[in] qos_profile (optional) The qos profile to use to subscribe
|
||||
* \param[in] qos_profile (optional) The rmw 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 rclcpp::QoS & qos_profile = rclcpp::ParametersQoS(),
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters,
|
||||
rclcpp::CallbackGroup::SharedPtr group = nullptr)
|
||||
: AsyncParametersClient(
|
||||
node->get_node_base_interface(),
|
||||
@@ -152,40 +96,16 @@ public:
|
||||
|
||||
/// Constructor
|
||||
/**
|
||||
* \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] node The async paramters client will be added to this node.
|
||||
* \param[in] remote_node_name (optional) name of the remote node
|
||||
* \param[in] qos_profile (optional) The qos profile to use to subscribe
|
||||
* \param[in] qos_profile (optional) The rmw 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 rclcpp::QoS & qos_profile = rclcpp::ParametersQoS(),
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters,
|
||||
rclcpp::CallbackGroup::SharedPtr group = nullptr)
|
||||
: AsyncParametersClient(
|
||||
node->get_node_base_interface(),
|
||||
@@ -265,9 +185,6 @@ 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
|
||||
@@ -291,7 +208,9 @@ public:
|
||||
typename rclcpp::Subscription<rcl_interfaces::msg::ParameterEvent>::SharedPtr
|
||||
on_parameter_event(
|
||||
CallbackT && callback,
|
||||
const rclcpp::QoS & qos = rclcpp::ParameterEventsQoS(),
|
||||
const rclcpp::QoS & qos = (
|
||||
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(rmw_qos_profile_parameter_events))
|
||||
),
|
||||
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options = (
|
||||
rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>()
|
||||
))
|
||||
@@ -316,7 +235,9 @@ public:
|
||||
on_parameter_event(
|
||||
NodeT && node,
|
||||
CallbackT && callback,
|
||||
const rclcpp::QoS & qos = rclcpp::ParameterEventsQoS(),
|
||||
const rclcpp::QoS & qos = (
|
||||
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(rmw_qos_profile_parameter_events))
|
||||
),
|
||||
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options = (
|
||||
rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>()
|
||||
))
|
||||
@@ -383,24 +304,11 @@ 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 rclcpp::QoS & qos_profile = rclcpp::ParametersQoS())
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters)
|
||||
: SyncParametersClient(
|
||||
std::make_shared<rclcpp::executors::SingleThreadedExecutor>(),
|
||||
node,
|
||||
@@ -408,29 +316,12 @@ 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 rclcpp::QoS & qos_profile = rclcpp::ParametersQoS())
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters)
|
||||
: SyncParametersClient(
|
||||
executor,
|
||||
node->get_node_base_interface(),
|
||||
@@ -441,24 +332,11 @@ 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 rclcpp::QoS & qos_profile = rclcpp::ParametersQoS())
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters)
|
||||
: SyncParametersClient(
|
||||
std::make_shared<rclcpp::executors::SingleThreadedExecutor>(),
|
||||
node,
|
||||
@@ -466,29 +344,12 @@ 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 rclcpp::QoS & qos_profile = rclcpp::ParametersQoS())
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters)
|
||||
: SyncParametersClient(
|
||||
executor,
|
||||
node->get_node_base_interface(),
|
||||
@@ -499,28 +360,6 @@ 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,
|
||||
@@ -529,7 +368,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 rclcpp::QoS & qos_profile = rclcpp::ParametersQoS())
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters)
|
||||
: executor_(executor), node_base_interface_(node_base_interface)
|
||||
{
|
||||
async_parameters_client_ =
|
||||
|
||||
@@ -86,9 +86,6 @@ 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:
|
||||
*
|
||||
@@ -106,8 +103,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, reset the callback handle smart pointer or call
|
||||
* remove_parameter_callback, passing the handle returned from add_parameter_callback:
|
||||
* To remove a parameter callback, call remove_parameter_callback, passing the handle returned
|
||||
* from add_parameter_callback:
|
||||
*
|
||||
* param_handler->remove_parameter_callback(handle2);
|
||||
*
|
||||
@@ -155,12 +152,9 @@ 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).
|
||||
*
|
||||
* Note: the callback handle returned from add_parameter_event_callback must be captured or
|
||||
* the callback will immediately be unregistered.
|
||||
* To remove a parameter event callback, use:
|
||||
*
|
||||
* To remove a parameter event callback, reset the callback smart pointer or use:
|
||||
*
|
||||
* param_handler->remove_event_parameter_callback(handle3);
|
||||
* param_handler->remove_event_parameter_callback(handle);
|
||||
*/
|
||||
class ParameterEventHandler
|
||||
{
|
||||
@@ -195,14 +189,10 @@ 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);
|
||||
@@ -222,17 +212,12 @@ 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,
|
||||
@@ -283,7 +268,6 @@ 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
|
||||
|
||||
@@ -33,6 +33,14 @@ namespace rclcpp
|
||||
/// A map of fully qualified node names to a list of parameters
|
||||
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.
|
||||
/// \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);
|
||||
|
||||
/// 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.
|
||||
@@ -41,7 +49,7 @@ using ParameterMap = std::unordered_map<std::string, std::vector<Parameter>>;
|
||||
/// \throws InvalidParametersException if the `rcl_params_t` is inconsistent or invalid.
|
||||
RCLCPP_PUBLIC
|
||||
ParameterMap
|
||||
parameter_map_from(const rcl_params_t * const c_params, const char * node_fqn = nullptr);
|
||||
parameter_map_from(const rcl_params_t * const c_params, const char * node_fqn);
|
||||
|
||||
/// Convert parameter value from rcl_yaml_param_parser into a C++ class instance.
|
||||
/// \param[in] c_value C structure containing a value of a parameter.
|
||||
@@ -53,20 +61,11 @@ parameter_value_from(const rcl_variant_t * const c_value);
|
||||
|
||||
/// Get the ParameterMap from a yaml file.
|
||||
/// \param[in] yaml_filename full name of the yaml file.
|
||||
/// \param[in] node_fqn a Fully Qualified Name of node, default value is nullptr.
|
||||
/// \returns an instance of a parameter map
|
||||
/// \throws from rcl error of rcl_parse_yaml_file()
|
||||
RCLCPP_PUBLIC
|
||||
ParameterMap
|
||||
parameter_map_from_yaml_file(const std::string & yaml_filename, const char * node_fqn = nullptr);
|
||||
|
||||
/// Get the Parameters from ParameterMap.
|
||||
/// \param[in] parameter_map a parameter map.
|
||||
/// \param[in] node_fqn a Fully Qualified Name of node, default value is nullptr.
|
||||
/// \returns a list of a parameter
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<Parameter>
|
||||
parameters_from_map(const ParameterMap & parameter_map, const char * node_fqn = nullptr);
|
||||
parameter_map_from_yaml_file(const std::string & yaml_filename);
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
#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"
|
||||
|
||||
@@ -40,26 +39,12 @@ class ParameterService
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(ParameterService)
|
||||
|
||||
[[deprecated("use rclcpp::QoS instead of rmw_qos_profile_t")]]
|
||||
RCLCPP_PUBLIC
|
||||
ParameterService(
|
||||
explicit 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)
|
||||
: 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());
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters);
|
||||
|
||||
private:
|
||||
rclcpp::Service<rcl_interfaces::srv::GetParameters>::SharedPtr get_parameters_service_;
|
||||
|
||||
@@ -131,16 +131,40 @@ public:
|
||||
node_base,
|
||||
topic,
|
||||
rclcpp::get_message_type_support_handle<MessageT>(),
|
||||
options.template to_rcl_publisher_options<MessageT>(qos),
|
||||
// NOTE(methylDragon): Passing these args separately is necessary for event binding
|
||||
options.event_callbacks,
|
||||
options.use_default_callbacks),
|
||||
options.template to_rcl_publisher_options<MessageT>(qos)),
|
||||
options_(options),
|
||||
published_type_allocator_(*options.get_allocator()),
|
||||
ros_message_type_allocator_(*options.get_allocator())
|
||||
{
|
||||
allocator::set_allocator_for_deleter(&published_type_deleter_, &published_type_allocator_);
|
||||
allocator::set_allocator_for_deleter(&ros_message_type_deleter_, &ros_message_type_allocator_);
|
||||
|
||||
if (options_.event_callbacks.deadline_callback) {
|
||||
this->add_event_handler(
|
||||
options_.event_callbacks.deadline_callback,
|
||||
RCL_PUBLISHER_OFFERED_DEADLINE_MISSED);
|
||||
}
|
||||
if (options_.event_callbacks.liveliness_callback) {
|
||||
this->add_event_handler(
|
||||
options_.event_callbacks.liveliness_callback,
|
||||
RCL_PUBLISHER_LIVELINESS_LOST);
|
||||
}
|
||||
if (options_.event_callbacks.incompatible_qos_callback) {
|
||||
this->add_event_handler(
|
||||
options_.event_callbacks.incompatible_qos_callback,
|
||||
RCL_PUBLISHER_OFFERED_INCOMPATIBLE_QOS);
|
||||
} else if (options_.use_default_callbacks) {
|
||||
// Register default callback when not specified
|
||||
try {
|
||||
this->add_event_handler(
|
||||
[this](QOSOfferedIncompatibleQoSInfo & info) {
|
||||
this->default_incompatible_qos_callback(info);
|
||||
},
|
||||
RCL_PUBLISHER_OFFERED_INCOMPATIBLE_QOS);
|
||||
} catch (UnsupportedEventTypeException & /*exc*/) {
|
||||
// pass
|
||||
}
|
||||
}
|
||||
// Setup continues in the post construction method, post_init_setup().
|
||||
}
|
||||
|
||||
@@ -381,6 +405,10 @@ public:
|
||||
if (!loaned_msg.is_valid()) {
|
||||
throw std::runtime_error("loaned message is not valid");
|
||||
}
|
||||
if (intra_process_is_enabled_) {
|
||||
// TODO(Karsten1987): support loaned message passed by intraprocess
|
||||
throw std::runtime_error("storing loaned messages in intra process is not supported yet");
|
||||
}
|
||||
|
||||
// verify that publisher supports loaned messages
|
||||
// TODO(Karsten1987): This case separation has to be done in rclcpp
|
||||
@@ -394,7 +422,7 @@ public:
|
||||
} else {
|
||||
// we don't release the ownership, let the middleware copy the ros message
|
||||
// and thus the destructor of rclcpp::LoanedMessage cleans up the memory.
|
||||
this->publish(loaned_msg.get());
|
||||
this->do_inter_process_publish(loaned_msg.get());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/network_flow_endpoint.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
#include "rclcpp/event_handler.hpp"
|
||||
#include "rclcpp/qos_event.hpp"
|
||||
#include "rclcpp/type_support_decl.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
#include "rcpputils/time.hpp"
|
||||
@@ -78,18 +78,11 @@ public:
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||
const std::string & topic,
|
||||
const rosidl_message_type_support_t & type_support,
|
||||
const rcl_publisher_options_t & publisher_options,
|
||||
const PublisherEventCallbacks & event_callbacks,
|
||||
bool use_default_callbacks);
|
||||
const rcl_publisher_options_t & publisher_options);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual ~PublisherBase();
|
||||
|
||||
/// Add event handlers for passed in event_callbacks.
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
bind_event_callbacks(const PublisherEventCallbacks & event_callbacks, bool use_default_callbacks);
|
||||
|
||||
/// Get the topic that this publisher publishes on.
|
||||
/** \return The topic name. */
|
||||
RCLCPP_PUBLIC
|
||||
@@ -124,7 +117,7 @@ public:
|
||||
/** \return The map of QoS event handlers. */
|
||||
RCLCPP_PUBLIC
|
||||
const
|
||||
std::unordered_map<rcl_publisher_event_type_t, std::shared_ptr<rclcpp::EventHandlerBase>> &
|
||||
std::unordered_map<rcl_publisher_event_type_t, std::shared_ptr<rclcpp::QOSEventHandlerBase>> &
|
||||
get_event_handlers() const;
|
||||
|
||||
/// Get subscription count
|
||||
@@ -276,7 +269,7 @@ public:
|
||||
* If you want more information available in the callback, like the qos event
|
||||
* or other information, you may use a lambda with captures or std::bind.
|
||||
*
|
||||
* \sa rclcpp::EventHandlerBase::set_on_ready_callback
|
||||
* \sa rclcpp::QOSEventHandlerBase::set_on_ready_callback
|
||||
*
|
||||
* \param[in] callback functor to be called when a new event occurs
|
||||
* \param[in] event_type identifier for the qos event we want to attach the callback to
|
||||
@@ -327,7 +320,7 @@ protected:
|
||||
const EventCallbackT & callback,
|
||||
const rcl_publisher_event_type_t event_type)
|
||||
{
|
||||
auto handler = std::make_shared<EventHandler<EventCallbackT,
|
||||
auto handler = std::make_shared<QOSEventHandler<EventCallbackT,
|
||||
std::shared_ptr<rcl_publisher_t>>>(
|
||||
callback,
|
||||
rcl_publisher_event_init,
|
||||
@@ -339,15 +332,12 @@ protected:
|
||||
RCLCPP_PUBLIC
|
||||
void default_incompatible_qos_callback(QOSOfferedIncompatibleQoSInfo & info) const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void default_incompatible_type_callback(IncompatibleTypeInfo & info) const;
|
||||
|
||||
std::shared_ptr<rcl_node_t> rcl_node_handle_;
|
||||
|
||||
std::shared_ptr<rcl_publisher_t> publisher_handle_;
|
||||
|
||||
std::unordered_map<rcl_publisher_event_type_t,
|
||||
std::shared_ptr<rclcpp::EventHandlerBase>> event_handlers_;
|
||||
std::shared_ptr<rclcpp::QOSEventHandlerBase>> event_handlers_;
|
||||
|
||||
using IntraProcessManagerWeakPtr =
|
||||
std::weak_ptr<rclcpp::experimental::IntraProcessManager>;
|
||||
@@ -358,8 +348,6 @@ protected:
|
||||
rmw_gid_t rmw_gid_;
|
||||
|
||||
const rosidl_message_type_support_t type_support_;
|
||||
|
||||
const PublisherEventCallbacks event_callbacks_;
|
||||
};
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "rclcpp/detail/rmw_implementation_specific_publisher_payload.hpp"
|
||||
#include "rclcpp/intra_process_setting.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
#include "rclcpp/event_handler.hpp"
|
||||
#include "rclcpp/qos_event.hpp"
|
||||
#include "rclcpp/qos_overriding_options.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
|
||||
@@ -44,7 +44,6 @@ 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,
|
||||
};
|
||||
|
||||
@@ -53,7 +52,6 @@ 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,
|
||||
};
|
||||
|
||||
@@ -62,7 +60,6 @@ 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,
|
||||
};
|
||||
|
||||
@@ -80,9 +77,7 @@ struct RCLCPP_PUBLIC QoSInitialization
|
||||
size_t depth;
|
||||
|
||||
/// Constructor which takes both a history policy and a depth (even if it would be unused).
|
||||
QoSInitialization(
|
||||
rmw_qos_history_policy_t history_policy_arg, size_t depth_arg,
|
||||
bool print_depth_warning = true);
|
||||
QoSInitialization(rmw_qos_history_policy_t history_policy_arg, size_t depth_arg);
|
||||
|
||||
/// Create a QoSInitialization from an existing rmw_qos_profile_t, using its history and depth.
|
||||
static
|
||||
@@ -99,7 +94,7 @@ struct RCLCPP_PUBLIC KeepAll : public rclcpp::QoSInitialization
|
||||
/// Use to initialize the QoS with the keep_last history setting and the given depth.
|
||||
struct RCLCPP_PUBLIC KeepLast : public rclcpp::QoSInitialization
|
||||
{
|
||||
explicit KeepLast(size_t depth, bool print_depth_warning = true);
|
||||
explicit KeepLast(size_t depth);
|
||||
};
|
||||
|
||||
/// Encapsulation of Quality of Service settings.
|
||||
@@ -185,10 +180,6 @@ 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);
|
||||
@@ -208,10 +199,6 @@ 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);
|
||||
@@ -501,36 +488,6 @@ 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_
|
||||
|
||||
@@ -15,8 +15,277 @@
|
||||
#ifndef RCLCPP__QOS_EVENT_HPP_
|
||||
#define RCLCPP__QOS_EVENT_HPP_
|
||||
|
||||
#warning This header is obsolete, please include rclcpp/event_handler.hpp instead
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include "rclcpp/event_handler.hpp"
|
||||
#include "rcl/error_handling.h"
|
||||
#include "rcl/event_callback.h"
|
||||
#include "rmw/impl/cpp/demangle.hpp"
|
||||
#include "rmw/incompatible_qos_events_statuses.h"
|
||||
|
||||
#include "rcutils/logging_macros.h"
|
||||
|
||||
#include "rclcpp/detail/cpp_callback_trampoline.hpp"
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
#include "rclcpp/function_traits.hpp"
|
||||
#include "rclcpp/logging.hpp"
|
||||
#include "rclcpp/waitable.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
using QOSDeadlineRequestedInfo = rmw_requested_deadline_missed_status_t;
|
||||
using QOSDeadlineOfferedInfo = rmw_offered_deadline_missed_status_t;
|
||||
using QOSLivelinessChangedInfo = rmw_liveliness_changed_status_t;
|
||||
using QOSLivelinessLostInfo = rmw_liveliness_lost_status_t;
|
||||
using QOSMessageLostInfo = rmw_message_lost_status_t;
|
||||
using QOSOfferedIncompatibleQoSInfo = rmw_offered_qos_incompatible_event_status_t;
|
||||
using QOSRequestedIncompatibleQoSInfo = rmw_requested_qos_incompatible_event_status_t;
|
||||
|
||||
using QOSDeadlineRequestedCallbackType = std::function<void (QOSDeadlineRequestedInfo &)>;
|
||||
using QOSDeadlineOfferedCallbackType = std::function<void (QOSDeadlineOfferedInfo &)>;
|
||||
using QOSLivelinessChangedCallbackType = std::function<void (QOSLivelinessChangedInfo &)>;
|
||||
using QOSLivelinessLostCallbackType = std::function<void (QOSLivelinessLostInfo &)>;
|
||||
using QOSMessageLostCallbackType = std::function<void (QOSMessageLostInfo &)>;
|
||||
using QOSOfferedIncompatibleQoSCallbackType = std::function<void (QOSOfferedIncompatibleQoSInfo &)>;
|
||||
using QOSRequestedIncompatibleQoSCallbackType =
|
||||
std::function<void (QOSRequestedIncompatibleQoSInfo &)>;
|
||||
|
||||
/// Contains callbacks for various types of events a Publisher can receive from the middleware.
|
||||
struct PublisherEventCallbacks
|
||||
{
|
||||
QOSDeadlineOfferedCallbackType deadline_callback;
|
||||
QOSLivelinessLostCallbackType liveliness_callback;
|
||||
QOSOfferedIncompatibleQoSCallbackType incompatible_qos_callback;
|
||||
};
|
||||
|
||||
/// Contains callbacks for non-message events that a Subscription can receive from the middleware.
|
||||
struct SubscriptionEventCallbacks
|
||||
{
|
||||
QOSDeadlineRequestedCallbackType deadline_callback;
|
||||
QOSLivelinessChangedCallbackType liveliness_callback;
|
||||
QOSRequestedIncompatibleQoSCallbackType incompatible_qos_callback;
|
||||
QOSMessageLostCallbackType message_lost_callback;
|
||||
};
|
||||
|
||||
class UnsupportedEventTypeException : public exceptions::RCLErrorBase, public std::runtime_error
|
||||
{
|
||||
public:
|
||||
RCLCPP_PUBLIC
|
||||
UnsupportedEventTypeException(
|
||||
rcl_ret_t ret,
|
||||
const rcl_error_state_t * error_state,
|
||||
const std::string & prefix);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
UnsupportedEventTypeException(
|
||||
const exceptions::RCLErrorBase & base_exc,
|
||||
const std::string & prefix);
|
||||
};
|
||||
|
||||
class QOSEventHandlerBase : public Waitable
|
||||
{
|
||||
public:
|
||||
enum class EntityType : std::size_t
|
||||
{
|
||||
Event,
|
||||
};
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual ~QOSEventHandlerBase();
|
||||
|
||||
/// Get the number of ready events
|
||||
RCLCPP_PUBLIC
|
||||
size_t
|
||||
get_number_of_ready_events() override;
|
||||
|
||||
/// Add the Waitable to a wait set.
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
add_to_wait_set(rcl_wait_set_t * wait_set) override;
|
||||
|
||||
/// Check if the Waitable is ready.
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
is_ready(rcl_wait_set_t * wait_set) override;
|
||||
|
||||
/// Set a callback to be called when each new event instance occurs.
|
||||
/**
|
||||
* The callback receives a size_t which is the number of events that occurred
|
||||
* since the last time this callback was called.
|
||||
* Normally this is 1, but can be > 1 if events occurred before any
|
||||
* callback was set.
|
||||
*
|
||||
* The callback also receives an int identifier argument.
|
||||
* This is needed because a Waitable may be composed of several distinct entities,
|
||||
* such as subscriptions, services, etc.
|
||||
* The application should provide a generic callback function that will be then
|
||||
* forwarded by the waitable to all of its entities.
|
||||
* Before forwarding, a different value for the identifier argument will be
|
||||
* bond to the function.
|
||||
* This implies that the provided callback can use the identifier to behave
|
||||
* differently depending on which entity triggered the waitable to become ready.
|
||||
*
|
||||
* Since this callback is called from the middleware, you should aim to make
|
||||
* it fast and not blocking.
|
||||
* If you need to do a lot of work or wait for some other event, you should
|
||||
* spin it off to another thread, otherwise you risk blocking the middleware.
|
||||
*
|
||||
* Calling it again will clear any previously set callback.
|
||||
*
|
||||
* An exception will be thrown if the callback is not callable.
|
||||
*
|
||||
* This function is thread-safe.
|
||||
*
|
||||
* If you want more information available in the callback, like the qos event
|
||||
* or other information, you may use a lambda with captures or std::bind.
|
||||
*
|
||||
* \sa rmw_event_set_callback
|
||||
* \sa rcl_event_set_callback
|
||||
*
|
||||
* \param[in] callback functor to be called when a new event occurs
|
||||
*/
|
||||
void
|
||||
set_on_ready_callback(std::function<void(size_t, int)> callback) override
|
||||
{
|
||||
if (!callback) {
|
||||
throw std::invalid_argument(
|
||||
"The callback passed to set_on_ready_callback "
|
||||
"is not callable.");
|
||||
}
|
||||
|
||||
// Note: we bind the int identifier argument to this waitable's entity types
|
||||
auto new_callback =
|
||||
[callback, this](size_t number_of_events) {
|
||||
try {
|
||||
callback(number_of_events, static_cast<int>(EntityType::Event));
|
||||
} catch (const std::exception & exception) {
|
||||
RCLCPP_ERROR_STREAM(
|
||||
// TODO(wjwwood): get this class access to the node logger it is associated with
|
||||
rclcpp::get_logger("rclcpp"),
|
||||
"rclcpp::QOSEventHandlerBase@" << this <<
|
||||
" caught " << rmw::impl::cpp::demangle(exception) <<
|
||||
" exception in user-provided callback for the 'on ready' callback: " <<
|
||||
exception.what());
|
||||
} catch (...) {
|
||||
RCLCPP_ERROR_STREAM(
|
||||
rclcpp::get_logger("rclcpp"),
|
||||
"rclcpp::QOSEventHandlerBase@" << this <<
|
||||
" caught unhandled exception in user-provided callback " <<
|
||||
"for the 'on ready' callback");
|
||||
}
|
||||
};
|
||||
|
||||
std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
|
||||
|
||||
// Set it temporarily to the new callback, while we replace the old one.
|
||||
// This two-step setting, prevents a gap where the old std::function has
|
||||
// been replaced but the middleware hasn't been told about the new one yet.
|
||||
set_on_new_event_callback(
|
||||
rclcpp::detail::cpp_callback_trampoline<const void *, size_t>,
|
||||
static_cast<const void *>(&new_callback));
|
||||
|
||||
// Store the std::function to keep it in scope, also overwrites the existing one.
|
||||
on_new_event_callback_ = new_callback;
|
||||
|
||||
// Set it again, now using the permanent storage.
|
||||
set_on_new_event_callback(
|
||||
rclcpp::detail::cpp_callback_trampoline<const void *, size_t>,
|
||||
static_cast<const void *>(&on_new_event_callback_));
|
||||
}
|
||||
|
||||
/// Unset the callback registered for new events, if any.
|
||||
void
|
||||
clear_on_ready_callback() override
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(callback_mutex_);
|
||||
if (on_new_event_callback_) {
|
||||
set_on_new_event_callback(nullptr, nullptr);
|
||||
on_new_event_callback_ = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
set_on_new_event_callback(rcl_event_callback_t callback, const void * user_data);
|
||||
|
||||
rcl_event_t event_handle_;
|
||||
size_t wait_set_event_index_;
|
||||
std::recursive_mutex callback_mutex_;
|
||||
std::function<void(size_t)> on_new_event_callback_{nullptr};
|
||||
};
|
||||
|
||||
template<typename EventCallbackT, typename ParentHandleT>
|
||||
class QOSEventHandler : public QOSEventHandlerBase
|
||||
{
|
||||
public:
|
||||
template<typename InitFuncT, typename EventTypeEnum>
|
||||
QOSEventHandler(
|
||||
const EventCallbackT & callback,
|
||||
InitFuncT init_func,
|
||||
ParentHandleT parent_handle,
|
||||
EventTypeEnum event_type)
|
||||
: parent_handle_(parent_handle), event_callback_(callback)
|
||||
{
|
||||
event_handle_ = rcl_get_zero_initialized_event();
|
||||
rcl_ret_t ret = init_func(&event_handle_, parent_handle.get(), event_type);
|
||||
if (ret != RCL_RET_OK) {
|
||||
if (ret == RCL_RET_UNSUPPORTED) {
|
||||
UnsupportedEventTypeException exc(ret, rcl_get_error_state(), "Failed to initialize event");
|
||||
rcl_reset_error();
|
||||
throw exc;
|
||||
} else {
|
||||
rclcpp::exceptions::throw_from_rcl_error(ret, "Failed to initialize event");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Take data so that the callback cannot be scheduled again
|
||||
std::shared_ptr<void>
|
||||
take_data() override
|
||||
{
|
||||
EventCallbackInfoT callback_info;
|
||||
rcl_ret_t ret = rcl_take_event(&event_handle_, &callback_info);
|
||||
if (ret != RCL_RET_OK) {
|
||||
RCUTILS_LOG_ERROR_NAMED(
|
||||
"rclcpp",
|
||||
"Couldn't take event info: %s", rcl_get_error_string().str);
|
||||
return nullptr;
|
||||
}
|
||||
return std::static_pointer_cast<void>(std::make_shared<EventCallbackInfoT>(callback_info));
|
||||
}
|
||||
|
||||
std::shared_ptr<void>
|
||||
take_data_by_entity_id(size_t id) override
|
||||
{
|
||||
(void)id;
|
||||
return take_data();
|
||||
}
|
||||
|
||||
/// Execute any entities of the Waitable that are ready.
|
||||
void
|
||||
execute(std::shared_ptr<void> & data) override
|
||||
{
|
||||
if (!data) {
|
||||
throw std::runtime_error("'data' is empty");
|
||||
}
|
||||
auto callback_ptr = std::static_pointer_cast<EventCallbackInfoT>(data);
|
||||
event_callback_(*callback_ptr);
|
||||
callback_ptr.reset();
|
||||
}
|
||||
|
||||
private:
|
||||
using EventCallbackInfoT = typename std::remove_reference<typename
|
||||
rclcpp::function_traits::function_traits<EventCallbackT>::template argument_type<0>>::type;
|
||||
|
||||
ParentHandleT parent_handle_;
|
||||
EventCallbackT event_callback_;
|
||||
};
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__QOS_EVENT_HPP_
|
||||
|
||||
@@ -26,7 +26,6 @@
|
||||
#include "rcl/error_handling.h"
|
||||
#include "rcl/event_callback.h"
|
||||
#include "rcl/service.h"
|
||||
#include "rcl/service_introspection.h"
|
||||
|
||||
#include "rmw/error_handling.h"
|
||||
#include "rmw/impl/cpp/demangle.hpp"
|
||||
@@ -35,7 +34,6 @@
|
||||
#include "tracetools/tracetools.h"
|
||||
|
||||
#include "rclcpp/any_service_callback.hpp"
|
||||
#include "rclcpp/clock.hpp"
|
||||
#include "rclcpp/detail/cpp_callback_trampoline.hpp"
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
#include "rclcpp/expand_topic_or_service_name.hpp"
|
||||
@@ -57,7 +55,7 @@ public:
|
||||
explicit ServiceBase(std::shared_ptr<rcl_node_t> node_handle);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual ~ServiceBase() = default;
|
||||
virtual ~ServiceBase();
|
||||
|
||||
/// Return the name of the service.
|
||||
/** \return The name of the service. */
|
||||
@@ -224,7 +222,7 @@ public:
|
||||
// This two-step setting, prevents a gap where the old std::function has
|
||||
// been replaced but the middleware hasn't been told about the new one yet.
|
||||
set_on_new_request_callback(
|
||||
rclcpp::detail::cpp_callback_trampoline<decltype(new_callback), const void *, size_t>,
|
||||
rclcpp::detail::cpp_callback_trampoline<const void *, size_t>,
|
||||
static_cast<const void *>(&new_callback));
|
||||
|
||||
// Store the std::function to keep it in scope, also overwrites the existing one.
|
||||
@@ -232,8 +230,7 @@ public:
|
||||
|
||||
// Set it again, now using the permanent storage.
|
||||
set_on_new_request_callback(
|
||||
rclcpp::detail::cpp_callback_trampoline<
|
||||
decltype(on_new_request_callback_), const void *, size_t>,
|
||||
rclcpp::detail::cpp_callback_trampoline<const void *, size_t>,
|
||||
static_cast<const void *>(&on_new_request_callback_));
|
||||
}
|
||||
|
||||
@@ -310,9 +307,11 @@ public:
|
||||
const std::string & service_name,
|
||||
AnyServiceCallback<ServiceT> any_callback,
|
||||
rcl_service_options_t & service_options)
|
||||
: ServiceBase(node_handle), any_callback_(any_callback),
|
||||
srv_type_support_handle_(rosidl_typesupport_cpp::get_service_type_support_handle<ServiceT>())
|
||||
: ServiceBase(node_handle), any_callback_(any_callback)
|
||||
{
|
||||
using rosidl_typesupport_cpp::get_service_type_support_handle;
|
||||
auto service_type_support_handle = get_service_type_support_handle<ServiceT>();
|
||||
|
||||
// rcl does the static memory allocation here
|
||||
service_handle_ = std::shared_ptr<rcl_service_t>(
|
||||
new rcl_service_t, [handle = node_handle_, service_name](rcl_service_t * service)
|
||||
@@ -331,7 +330,7 @@ public:
|
||||
rcl_ret_t ret = rcl_service_init(
|
||||
service_handle_.get(),
|
||||
node_handle.get(),
|
||||
srv_type_support_handle_,
|
||||
service_type_support_handle,
|
||||
service_name.c_str(),
|
||||
&service_options);
|
||||
if (ret != RCL_RET_OK) {
|
||||
@@ -371,8 +370,8 @@ public:
|
||||
std::shared_ptr<rcl_node_t> node_handle,
|
||||
std::shared_ptr<rcl_service_t> service_handle,
|
||||
AnyServiceCallback<ServiceT> any_callback)
|
||||
: ServiceBase(node_handle), any_callback_(any_callback),
|
||||
srv_type_support_handle_(rosidl_typesupport_cpp::get_service_type_support_handle<ServiceT>())
|
||||
: ServiceBase(node_handle),
|
||||
any_callback_(any_callback)
|
||||
{
|
||||
// check if service handle was initialized
|
||||
if (!rcl_service_is_valid(service_handle.get())) {
|
||||
@@ -406,8 +405,8 @@ public:
|
||||
std::shared_ptr<rcl_node_t> node_handle,
|
||||
rcl_service_t * service_handle,
|
||||
AnyServiceCallback<ServiceT> any_callback)
|
||||
: ServiceBase(node_handle), any_callback_(any_callback),
|
||||
srv_type_support_handle_(rosidl_typesupport_cpp::get_service_type_support_handle<ServiceT>())
|
||||
: ServiceBase(node_handle),
|
||||
any_callback_(any_callback)
|
||||
{
|
||||
// check if service handle was initialized
|
||||
if (!rcl_service_is_valid(service_handle)) {
|
||||
@@ -487,39 +486,10 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/// Configure client introspection.
|
||||
/**
|
||||
* \param[in] clock clock to use to generate introspection timestamps
|
||||
* \param[in] qos_service_event_pub QoS settings to use when creating the introspection publisher
|
||||
* \param[in] introspection_state the state to set introspection to
|
||||
*/
|
||||
void
|
||||
configure_introspection(
|
||||
Clock::SharedPtr clock, const QoS & qos_service_event_pub,
|
||||
rcl_service_introspection_state_t introspection_state)
|
||||
{
|
||||
rcl_publisher_options_t pub_opts = rcl_publisher_get_default_options();
|
||||
pub_opts.qos = qos_service_event_pub.get_rmw_qos_profile();
|
||||
|
||||
rcl_ret_t ret = rcl_service_configure_service_introspection(
|
||||
service_handle_.get(),
|
||||
node_handle_.get(),
|
||||
clock->get_clock_handle(),
|
||||
srv_type_support_handle_,
|
||||
pub_opts,
|
||||
introspection_state);
|
||||
|
||||
if (RCL_RET_OK != ret) {
|
||||
rclcpp::exceptions::throw_from_rcl_error(ret, "failed to configure service introspection");
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(Service)
|
||||
|
||||
AnyServiceCallback<ServiceT> any_callback_;
|
||||
|
||||
const rosidl_service_type_support_t * srv_type_support_handle_;
|
||||
};
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
#include "rcl/allocator.h"
|
||||
|
||||
@@ -121,8 +120,8 @@ public:
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < waitable_handles_.size(); ++i) {
|
||||
if (waitable_handles_[i]->is_ready(wait_set)) {
|
||||
waitable_triggered_handles_.emplace_back(std::move(waitable_handles_[i]));
|
||||
if (!waitable_handles_[i]->is_ready(wait_set)) {
|
||||
waitable_handles_[i].reset();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,7 +145,10 @@ public:
|
||||
timer_handles_.end()
|
||||
);
|
||||
|
||||
waitable_handles_.clear();
|
||||
waitable_handles_.erase(
|
||||
std::remove(waitable_handles_.begin(), waitable_handles_.end(), nullptr),
|
||||
waitable_handles_.end()
|
||||
);
|
||||
}
|
||||
|
||||
bool collect_entities(const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes) override
|
||||
@@ -390,9 +392,8 @@ public:
|
||||
rclcpp::AnyExecutable & any_exec,
|
||||
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes) override
|
||||
{
|
||||
auto & waitable_handles = waitable_triggered_handles_;
|
||||
auto it = waitable_handles.begin();
|
||||
while (it != waitable_handles.end()) {
|
||||
auto it = waitable_handles_.begin();
|
||||
while (it != waitable_handles_.end()) {
|
||||
std::shared_ptr<Waitable> & waitable = *it;
|
||||
if (waitable) {
|
||||
// Find the group for this handle and see if it can be serviced
|
||||
@@ -400,7 +401,7 @@ public:
|
||||
if (!group) {
|
||||
// Group was not found, meaning the waitable is not valid...
|
||||
// Remove it from the ready list and continue looking
|
||||
it = waitable_handles.erase(it);
|
||||
it = waitable_handles_.erase(it);
|
||||
continue;
|
||||
}
|
||||
if (!group->can_be_taken_from().load()) {
|
||||
@@ -413,11 +414,11 @@ public:
|
||||
any_exec.waitable = waitable;
|
||||
any_exec.callback_group = group;
|
||||
any_exec.node_base = get_node_by_group(group, weak_groups_to_nodes);
|
||||
waitable_handles.erase(it);
|
||||
waitable_handles_.erase(it);
|
||||
return;
|
||||
}
|
||||
// Else, the waitable is no longer valid, remove it and continue
|
||||
it = waitable_handles.erase(it);
|
||||
it = waitable_handles_.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -498,8 +499,6 @@ private:
|
||||
VectorRebind<std::shared_ptr<const rcl_timer_t>> timer_handles_;
|
||||
VectorRebind<std::shared_ptr<Waitable>> waitable_handles_;
|
||||
|
||||
VectorRebind<std::shared_ptr<Waitable>> waitable_triggered_handles_;
|
||||
|
||||
std::shared_ptr<VoidAlloc> allocator_;
|
||||
};
|
||||
|
||||
|
||||
@@ -140,15 +140,44 @@ public:
|
||||
node_base,
|
||||
type_support_handle,
|
||||
topic_name,
|
||||
options.to_rcl_subscription_options(qos),
|
||||
// NOTE(methylDragon): Passing these args separately is necessary for event binding
|
||||
options.event_callbacks,
|
||||
options.use_default_callbacks,
|
||||
options.template to_rcl_subscription_options<ROSMessageType>(qos),
|
||||
callback.is_serialized_message_callback()),
|
||||
any_callback_(callback),
|
||||
options_(options),
|
||||
message_memory_strategy_(message_memory_strategy)
|
||||
{
|
||||
if (options_.event_callbacks.deadline_callback) {
|
||||
this->add_event_handler(
|
||||
options_.event_callbacks.deadline_callback,
|
||||
RCL_SUBSCRIPTION_REQUESTED_DEADLINE_MISSED);
|
||||
}
|
||||
if (options_.event_callbacks.liveliness_callback) {
|
||||
this->add_event_handler(
|
||||
options_.event_callbacks.liveliness_callback,
|
||||
RCL_SUBSCRIPTION_LIVELINESS_CHANGED);
|
||||
}
|
||||
if (options_.event_callbacks.incompatible_qos_callback) {
|
||||
this->add_event_handler(
|
||||
options_.event_callbacks.incompatible_qos_callback,
|
||||
RCL_SUBSCRIPTION_REQUESTED_INCOMPATIBLE_QOS);
|
||||
} else if (options_.use_default_callbacks) {
|
||||
// Register default callback when not specified
|
||||
try {
|
||||
this->add_event_handler(
|
||||
[this](QOSRequestedIncompatibleQoSInfo & info) {
|
||||
this->default_incompatible_qos_callback(info);
|
||||
},
|
||||
RCL_SUBSCRIPTION_REQUESTED_INCOMPATIBLE_QOS);
|
||||
} catch (UnsupportedEventTypeException & /*exc*/) {
|
||||
// pass
|
||||
}
|
||||
}
|
||||
if (options_.event_callbacks.message_lost_callback) {
|
||||
this->add_event_handler(
|
||||
options_.event_callbacks.message_lost_callback,
|
||||
RCL_SUBSCRIPTION_MESSAGE_LOST);
|
||||
}
|
||||
|
||||
// Setup intra process publishing if requested.
|
||||
if (rclcpp::detail::resolve_use_intra_process(options_, *node_base)) {
|
||||
using rclcpp::detail::resolve_intra_process_buffer_type;
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
#include "rclcpp/message_info.hpp"
|
||||
#include "rclcpp/network_flow_endpoint.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
#include "rclcpp/event_handler.hpp"
|
||||
#include "rclcpp/qos_event.hpp"
|
||||
#include "rclcpp/serialized_message.hpp"
|
||||
#include "rclcpp/subscription_content_filter_options.hpp"
|
||||
#include "rclcpp/type_support_decl.hpp"
|
||||
@@ -84,20 +84,12 @@ public:
|
||||
const rosidl_message_type_support_t & type_support_handle,
|
||||
const std::string & topic_name,
|
||||
const rcl_subscription_options_t & subscription_options,
|
||||
const SubscriptionEventCallbacks & event_callbacks,
|
||||
bool use_default_callbacks,
|
||||
bool is_serialized = false);
|
||||
|
||||
/// Destructor.
|
||||
RCLCPP_PUBLIC
|
||||
virtual ~SubscriptionBase();
|
||||
|
||||
/// Add event handlers for passed in event_callbacks.
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
bind_event_callbacks(
|
||||
const SubscriptionEventCallbacks & event_callbacks, bool use_default_callbacks);
|
||||
|
||||
/// Get the topic that this subscription is subscribed on.
|
||||
RCLCPP_PUBLIC
|
||||
const char *
|
||||
@@ -115,7 +107,7 @@ public:
|
||||
/** \return The map of QoS event handlers. */
|
||||
RCLCPP_PUBLIC
|
||||
const
|
||||
std::unordered_map<rcl_subscription_event_type_t, std::shared_ptr<rclcpp::EventHandlerBase>> &
|
||||
std::unordered_map<rcl_subscription_event_type_t, std::shared_ptr<rclcpp::QOSEventHandlerBase>> &
|
||||
get_event_handlers() const;
|
||||
|
||||
/// Get the actual QoS settings, after the defaults have been determined.
|
||||
@@ -356,7 +348,7 @@ public:
|
||||
// This two-step setting, prevents a gap where the old std::function has
|
||||
// been replaced but the middleware hasn't been told about the new one yet.
|
||||
set_on_new_message_callback(
|
||||
rclcpp::detail::cpp_callback_trampoline<decltype(new_callback), const void *, size_t>,
|
||||
rclcpp::detail::cpp_callback_trampoline<const void *, size_t>,
|
||||
static_cast<const void *>(&new_callback));
|
||||
|
||||
// Store the std::function to keep it in scope, also overwrites the existing one.
|
||||
@@ -364,8 +356,7 @@ public:
|
||||
|
||||
// Set it again, now using the permanent storage.
|
||||
set_on_new_message_callback(
|
||||
rclcpp::detail::cpp_callback_trampoline<
|
||||
decltype(on_new_message_callback_), const void *, size_t>,
|
||||
rclcpp::detail::cpp_callback_trampoline<const void *, size_t>,
|
||||
static_cast<const void *>(&on_new_message_callback_));
|
||||
}
|
||||
|
||||
@@ -457,7 +448,7 @@ public:
|
||||
* If you want more information available in the callback, like the qos event
|
||||
* or other information, you may use a lambda with captures or std::bind.
|
||||
*
|
||||
* \sa rclcpp::EventHandlerBase::set_on_ready_callback
|
||||
* \sa rclcpp::QOSEventHandlerBase::set_on_ready_callback
|
||||
*
|
||||
* \param[in] callback functor to be called when a new event occurs
|
||||
* \param[in] event_type identifier for the qos event we want to attach the callback to
|
||||
@@ -542,7 +533,7 @@ protected:
|
||||
const EventCallbackT & callback,
|
||||
const rcl_subscription_event_type_t event_type)
|
||||
{
|
||||
auto handler = std::make_shared<EventHandler<EventCallbackT,
|
||||
auto handler = std::make_shared<QOSEventHandler<EventCallbackT,
|
||||
std::shared_ptr<rcl_subscription_t>>>(
|
||||
callback,
|
||||
rcl_subscription_event_init,
|
||||
@@ -555,9 +546,6 @@ protected:
|
||||
RCLCPP_PUBLIC
|
||||
void default_incompatible_qos_callback(QOSRequestedIncompatibleQoSInfo & info) const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void default_incompatible_type_callback(IncompatibleTypeInfo & info) const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
matches_any_intra_process_publishers(const rmw_gid_t * sender_gid) const;
|
||||
@@ -574,15 +562,13 @@ protected:
|
||||
rclcpp::Logger node_logger_;
|
||||
|
||||
std::unordered_map<rcl_subscription_event_type_t,
|
||||
std::shared_ptr<rclcpp::EventHandlerBase>> event_handlers_;
|
||||
std::shared_ptr<rclcpp::QOSEventHandlerBase>> event_handlers_;
|
||||
|
||||
bool use_intra_process_;
|
||||
IntraProcessManagerWeakPtr weak_ipm_;
|
||||
uint64_t intra_process_subscription_id_;
|
||||
std::shared_ptr<rclcpp::experimental::SubscriptionIntraProcessBase> subscription_intra_process_;
|
||||
|
||||
const SubscriptionEventCallbacks event_callbacks_;
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(SubscriptionBase)
|
||||
|
||||
@@ -591,7 +577,7 @@ private:
|
||||
|
||||
std::atomic<bool> subscription_in_use_by_wait_set_{false};
|
||||
std::atomic<bool> intra_process_subscription_waitable_in_use_by_wait_set_{false};
|
||||
std::unordered_map<rclcpp::EventHandlerBase *,
|
||||
std::unordered_map<rclcpp::QOSEventHandlerBase *,
|
||||
std::atomic<bool>> qos_events_in_use_by_wait_set_;
|
||||
|
||||
std::recursive_mutex callback_mutex_;
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
#include "rclcpp/intra_process_buffer_type.hpp"
|
||||
#include "rclcpp/intra_process_setting.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
#include "rclcpp/event_handler.hpp"
|
||||
#include "rclcpp/qos_event.hpp"
|
||||
#include "rclcpp/qos_overriding_options.hpp"
|
||||
#include "rclcpp/subscription_content_filter_options.hpp"
|
||||
#include "rclcpp/topic_statistics_state.hpp"
|
||||
@@ -110,6 +110,7 @@ struct SubscriptionOptionsWithAllocator : public SubscriptionOptionsBase
|
||||
* \param qos QoS profile for subcription.
|
||||
* \return rcl_subscription_options_t structure based on the rclcpp::QoS
|
||||
*/
|
||||
template<typename MessageT>
|
||||
rcl_subscription_options_t
|
||||
to_rcl_subscription_options(const rclcpp::QoS & qos) const
|
||||
{
|
||||
|
||||
@@ -149,48 +149,11 @@ public:
|
||||
bool
|
||||
exchange_in_use_by_wait_set_state(bool in_use_state);
|
||||
|
||||
/// Set a callback to be called when the timer is reset
|
||||
/**
|
||||
* You should aim to make this callback fast and not blocking.
|
||||
* If you need to do a lot of work or wait for some other event, you should
|
||||
* spin it off to another thread.
|
||||
*
|
||||
* Calling it again will override any previously set callback.
|
||||
* An exception will be thrown if the callback is not callable.
|
||||
*
|
||||
* This function is thread-safe.
|
||||
*
|
||||
* If you want more information available in the callback,
|
||||
* you may use a lambda with captures or std::bind.
|
||||
*
|
||||
* \param[in] callback functor to be called whenever timer is reset
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
set_on_reset_callback(std::function<void(size_t)> callback);
|
||||
|
||||
/// Unset the callback registered for reset timer
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
clear_on_reset_callback();
|
||||
|
||||
protected:
|
||||
std::recursive_mutex callback_mutex_;
|
||||
// Declare callback before timer_handle_, so on destruction
|
||||
// the callback is destroyed last. Otherwise, the rcl timer
|
||||
// callback would point briefly to a destroyed function.
|
||||
// Clearing the callback on timer destructor also makes sure
|
||||
// the rcl callback is cleared before on_reset_callback_.
|
||||
std::function<void(size_t)> on_reset_callback_{nullptr};
|
||||
|
||||
Clock::SharedPtr clock_;
|
||||
std::shared_ptr<rcl_timer_t> timer_handle_;
|
||||
|
||||
std::atomic<bool> in_use_by_wait_set_{false};
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
set_on_reset_callback(rcl_event_callback_t callback, const void * user_data);
|
||||
};
|
||||
|
||||
|
||||
@@ -226,17 +189,11 @@ public:
|
||||
TRACEPOINT(
|
||||
rclcpp_timer_callback_added,
|
||||
static_cast<const void *>(get_timer_handle().get()),
|
||||
reinterpret_cast<const void *>(&callback_));
|
||||
#ifndef TRACETOOLS_DISABLED
|
||||
if (TRACEPOINT_ENABLED(rclcpp_callback_register)) {
|
||||
char * symbol = tracetools::get_symbol(callback_);
|
||||
DO_TRACEPOINT(
|
||||
rclcpp_callback_register,
|
||||
reinterpret_cast<const void *>(&callback_),
|
||||
symbol);
|
||||
std::free(symbol);
|
||||
}
|
||||
#endif
|
||||
static_cast<const void *>(&callback_));
|
||||
TRACEPOINT(
|
||||
rclcpp_callback_register,
|
||||
static_cast<const void *>(&callback_),
|
||||
tracetools::get_symbol(callback_));
|
||||
}
|
||||
|
||||
/// Default destructor.
|
||||
@@ -269,9 +226,9 @@ public:
|
||||
void
|
||||
execute_callback() override
|
||||
{
|
||||
TRACEPOINT(callback_start, reinterpret_cast<const void *>(&callback_), false);
|
||||
TRACEPOINT(callback_start, static_cast<const void *>(&callback_), false);
|
||||
execute_callback_delegate<>();
|
||||
TRACEPOINT(callback_end, reinterpret_cast<const void *>(&callback_));
|
||||
TRACEPOINT(callback_end, static_cast<const void *>(&callback_));
|
||||
}
|
||||
|
||||
// void specialization
|
||||
|
||||
@@ -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 false if shutdown has been called, true otherwise
|
||||
* \return true if shutdown has been called, false otherwise
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
|
||||
@@ -516,7 +516,7 @@ public:
|
||||
* the waitable to be removed, but it will cause the associated entity pointer
|
||||
* to be nullptr when introspecting this waitable after waiting.
|
||||
*
|
||||
* Note that rclcpp::EventHandlerBase is just a special case of
|
||||
* Note that rclcpp::QOSEventHandlerBase are just a special case of
|
||||
* rclcpp::Waitable and can be added with this function.
|
||||
*
|
||||
* \param[in] waitable Waitable to be added.
|
||||
|
||||
@@ -2,17 +2,13 @@
|
||||
<?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>19.3.0</version>
|
||||
<version>16.0.2</version>
|
||||
<description>The ROS client library in C++.</description>
|
||||
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
<maintainer email="michel@ekumenlabs.com">Michel Hidalgo</maintainer>
|
||||
<maintainer email="jacob@openrobotics.org">Jacob Perron</maintainer>
|
||||
<maintainer email="william@openrobotics.org">William Woodall</maintainer>
|
||||
|
||||
<license>Apache License 2.0</license>
|
||||
|
||||
<author email="dthomas@openrobotics.org">Dirk Thomas</author>
|
||||
<author email="jacob@openrobotics.org">Jacob Perron</author>
|
||||
|
||||
<buildtool_depend>ament_cmake_ros</buildtool_depend>
|
||||
<buildtool_depend>ament_cmake_gen_version_h</buildtool_depend>
|
||||
|
||||
@@ -114,6 +114,7 @@ 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()}@
|
||||
@@ -124,7 +125,7 @@ def get_rclcpp_suffix_from_features(features):
|
||||
) \
|
||||
do { \
|
||||
static_assert( \
|
||||
::std::is_same<typename std::remove_cv_t<typename std::remove_reference_t<decltype(logger)>>, \
|
||||
::std::is_same<typename std::remove_cv<typename std::remove_reference<decltype(logger)>::type>::type, \
|
||||
typename ::rclcpp::Logger>::value, \
|
||||
"First argument to logging macros must be an rclcpp::Logger"); \
|
||||
@[ if 'throttle' in feature_combination]@ \
|
||||
|
||||
@@ -12,19 +12,9 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "rclcpp/callback_group.hpp"
|
||||
#include "rclcpp/client.hpp"
|
||||
#include "rclcpp/service.hpp"
|
||||
#include "rclcpp/subscription_base.hpp"
|
||||
#include "rclcpp/timer.hpp"
|
||||
#include "rclcpp/waitable.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
using rclcpp::CallbackGroup;
|
||||
using rclcpp::CallbackGroupType;
|
||||
@@ -37,10 +27,6 @@ CallbackGroup::CallbackGroup(
|
||||
automatically_add_to_executor_with_node_(automatically_add_to_executor_with_node)
|
||||
{}
|
||||
|
||||
CallbackGroup::~CallbackGroup()
|
||||
{
|
||||
trigger_notify_guard_condition();
|
||||
}
|
||||
|
||||
std::atomic_bool &
|
||||
CallbackGroup::can_be_taken_from()
|
||||
@@ -111,33 +97,6 @@ CallbackGroup::automatically_add_to_executor_with_node() const
|
||||
return automatically_add_to_executor_with_node_;
|
||||
}
|
||||
|
||||
rclcpp::GuardCondition::SharedPtr
|
||||
CallbackGroup::get_notify_guard_condition(const rclcpp::Context::SharedPtr context_ptr)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(notify_guard_condition_mutex_);
|
||||
if (notify_guard_condition_ && context_ptr != notify_guard_condition_->get_context()) {
|
||||
if (associated_with_executor_) {
|
||||
trigger_notify_guard_condition();
|
||||
}
|
||||
notify_guard_condition_ = nullptr;
|
||||
}
|
||||
|
||||
if (!notify_guard_condition_) {
|
||||
notify_guard_condition_ = std::make_shared<rclcpp::GuardCondition>(context_ptr);
|
||||
}
|
||||
|
||||
return notify_guard_condition_;
|
||||
}
|
||||
|
||||
void
|
||||
CallbackGroup::trigger_notify_guard_condition()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(notify_guard_condition_mutex_);
|
||||
if (notify_guard_condition_) {
|
||||
notify_guard_condition_->trigger();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CallbackGroup::add_subscription(
|
||||
const rclcpp::SubscriptionBase::SharedPtr subscription_ptr)
|
||||
|
||||
@@ -23,11 +23,9 @@
|
||||
#include "rcl/graph.h"
|
||||
#include "rcl/node.h"
|
||||
#include "rcl/wait.h"
|
||||
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_graph_interface.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
#include "rclcpp/utilities.hpp"
|
||||
#include "rclcpp/logging.hpp"
|
||||
|
||||
@@ -67,6 +65,13 @@ ClientBase::ClientBase(
|
||||
});
|
||||
}
|
||||
|
||||
ClientBase::~ClientBase()
|
||||
{
|
||||
clear_on_new_response_callback();
|
||||
// Make sure the client handle is destructed as early as possible and before the node handle
|
||||
client_handle_.reset();
|
||||
}
|
||||
|
||||
bool
|
||||
ClientBase::take_type_erased_response(void * response_out, rmw_request_id_t & request_header_out)
|
||||
{
|
||||
@@ -243,6 +248,7 @@ ClientBase::set_on_new_response_callback(rcl_event_callback_t callback, const vo
|
||||
user_data);
|
||||
|
||||
if (RCL_RET_OK != ret) {
|
||||
using rclcpp::exceptions::throw_from_rcl_error;
|
||||
throw_from_rcl_error(ret, "failed to set the on new response callback for client");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ Clock::Clock(rcl_clock_type_t clock_type)
|
||||
Clock::~Clock() {}
|
||||
|
||||
Time
|
||||
Clock::now() const
|
||||
Clock::now()
|
||||
{
|
||||
Time now(0, 0, impl_->rcl_clock_.type);
|
||||
|
||||
@@ -182,71 +182,6 @@ Clock::sleep_for(Duration rel_time, Context::SharedPtr context)
|
||||
return sleep_until(now() + rel_time, context);
|
||||
}
|
||||
|
||||
bool
|
||||
Clock::started()
|
||||
{
|
||||
if (!rcl_clock_valid(get_clock_handle())) {
|
||||
throw std::runtime_error("clock is not rcl_clock_valid");
|
||||
}
|
||||
return rcl_clock_time_started(get_clock_handle());
|
||||
}
|
||||
|
||||
bool
|
||||
Clock::wait_until_started(Context::SharedPtr context)
|
||||
{
|
||||
if (!context || !context->is_valid()) {
|
||||
throw std::runtime_error("context cannot be slept with because it's invalid");
|
||||
}
|
||||
if (!rcl_clock_valid(get_clock_handle())) {
|
||||
throw std::runtime_error("clock cannot be waited on as it is not rcl_clock_valid");
|
||||
}
|
||||
|
||||
if (started()) {
|
||||
return true;
|
||||
} else {
|
||||
// Wait until the first non-zero time
|
||||
return sleep_until(rclcpp::Time(0, 1, get_clock_type()), context);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Clock::wait_until_started(
|
||||
const Duration & timeout,
|
||||
Context::SharedPtr context,
|
||||
const Duration & wait_tick_ns)
|
||||
{
|
||||
if (!context || !context->is_valid()) {
|
||||
throw std::runtime_error("context cannot be slept with because it's invalid");
|
||||
}
|
||||
if (!rcl_clock_valid(get_clock_handle())) {
|
||||
throw std::runtime_error("clock cannot be waited on as it is not rcl_clock_valid");
|
||||
}
|
||||
|
||||
Clock timeout_clock = Clock(RCL_STEADY_TIME);
|
||||
Time start = timeout_clock.now();
|
||||
|
||||
// Check if the clock has started every wait_tick_ns nanoseconds
|
||||
// Context check checks for rclcpp::shutdown()
|
||||
while (!started() && context->is_valid()) {
|
||||
if (timeout < wait_tick_ns) {
|
||||
timeout_clock.sleep_for(timeout);
|
||||
} else {
|
||||
Duration time_left = start + timeout - timeout_clock.now();
|
||||
if (time_left > wait_tick_ns) {
|
||||
timeout_clock.sleep_for(Duration(wait_tick_ns));
|
||||
} else {
|
||||
timeout_clock.sleep_for(time_left);
|
||||
}
|
||||
}
|
||||
|
||||
if (timeout_clock.now() - start > timeout) {
|
||||
return started();
|
||||
}
|
||||
}
|
||||
return started();
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
Clock::ros_time_is_active()
|
||||
{
|
||||
|
||||
@@ -154,9 +154,7 @@ 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 {
|
||||
// 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");
|
||||
this->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();
|
||||
@@ -219,7 +217,7 @@ Context::init(
|
||||
if (0u == count) {
|
||||
ret = rcl_logging_configure_with_output_handler(
|
||||
&rcl_context_->global_arguments,
|
||||
rcl_init_options_get_allocator(init_options.get_rcl_init_options()),
|
||||
rcl_init_options_get_allocator(init_options_.get_rcl_init_options()),
|
||||
rclcpp_logging_output_handler);
|
||||
if (RCL_RET_OK != ret) {
|
||||
rcl_context_.reset();
|
||||
@@ -365,45 +363,49 @@ Context::on_shutdown(OnShutdownCallback callback)
|
||||
rclcpp::OnShutdownCallbackHandle
|
||||
Context::add_on_shutdown_callback(OnShutdownCallback callback)
|
||||
{
|
||||
return add_shutdown_callback<ShutdownType::on_shutdown>(callback);
|
||||
return add_shutdown_callback(ShutdownType::on_shutdown, callback);
|
||||
}
|
||||
|
||||
bool
|
||||
Context::remove_on_shutdown_callback(const OnShutdownCallbackHandle & callback_handle)
|
||||
{
|
||||
return remove_shutdown_callback<ShutdownType::on_shutdown>(callback_handle);
|
||||
return remove_shutdown_callback(ShutdownType::on_shutdown, callback_handle);
|
||||
}
|
||||
|
||||
rclcpp::PreShutdownCallbackHandle
|
||||
Context::add_pre_shutdown_callback(PreShutdownCallback callback)
|
||||
{
|
||||
return add_shutdown_callback<ShutdownType::pre_shutdown>(callback);
|
||||
return add_shutdown_callback(ShutdownType::pre_shutdown, callback);
|
||||
}
|
||||
|
||||
bool
|
||||
Context::remove_pre_shutdown_callback(
|
||||
const PreShutdownCallbackHandle & callback_handle)
|
||||
{
|
||||
return remove_shutdown_callback<ShutdownType::pre_shutdown>(callback_handle);
|
||||
return remove_shutdown_callback(ShutdownType::pre_shutdown, callback_handle);
|
||||
}
|
||||
|
||||
template<Context::ShutdownType shutdown_type>
|
||||
rclcpp::ShutdownCallbackHandle
|
||||
Context::add_shutdown_callback(
|
||||
ShutdownType shutdown_type,
|
||||
ShutdownCallback callback)
|
||||
{
|
||||
auto callback_shared_ptr =
|
||||
std::make_shared<ShutdownCallbackHandle::ShutdownCallbackType>(callback);
|
||||
|
||||
static_assert(
|
||||
shutdown_type == ShutdownType::pre_shutdown || shutdown_type == ShutdownType::on_shutdown);
|
||||
|
||||
if constexpr (shutdown_type == ShutdownType::pre_shutdown) {
|
||||
std::lock_guard<std::mutex> lock(pre_shutdown_callbacks_mutex_);
|
||||
pre_shutdown_callbacks_.emplace_back(callback_shared_ptr);
|
||||
} else {
|
||||
std::lock_guard<std::mutex> lock(on_shutdown_callbacks_mutex_);
|
||||
on_shutdown_callbacks_.emplace_back(callback_shared_ptr);
|
||||
switch (shutdown_type) {
|
||||
case ShutdownType::pre_shutdown:
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(pre_shutdown_callbacks_mutex_);
|
||||
pre_shutdown_callbacks_.emplace(callback_shared_ptr);
|
||||
}
|
||||
break;
|
||||
case ShutdownType::on_shutdown:
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(on_shutdown_callbacks_mutex_);
|
||||
on_shutdown_callbacks_.emplace(callback_shared_ptr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ShutdownCallbackHandle callback_handle;
|
||||
@@ -411,74 +413,73 @@ Context::add_shutdown_callback(
|
||||
return callback_handle;
|
||||
}
|
||||
|
||||
template<Context::ShutdownType shutdown_type>
|
||||
bool
|
||||
Context::remove_shutdown_callback(
|
||||
ShutdownType shutdown_type,
|
||||
const ShutdownCallbackHandle & callback_handle)
|
||||
{
|
||||
const auto callback_shared_ptr = callback_handle.callback.lock();
|
||||
std::mutex * mutex_ptr = nullptr;
|
||||
std::unordered_set<
|
||||
std::shared_ptr<ShutdownCallbackHandle::ShutdownCallbackType>> * callback_list_ptr;
|
||||
|
||||
switch (shutdown_type) {
|
||||
case ShutdownType::pre_shutdown:
|
||||
mutex_ptr = &pre_shutdown_callbacks_mutex_;
|
||||
callback_list_ptr = &pre_shutdown_callbacks_;
|
||||
break;
|
||||
case ShutdownType::on_shutdown:
|
||||
mutex_ptr = &on_shutdown_callbacks_mutex_;
|
||||
callback_list_ptr = &on_shutdown_callbacks_;
|
||||
break;
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(*mutex_ptr);
|
||||
auto callback_shared_ptr = callback_handle.callback.lock();
|
||||
if (callback_shared_ptr == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto remove_callback = [&callback_shared_ptr](auto & mutex, auto & callback_vector) {
|
||||
const std::lock_guard<std::mutex> lock(mutex);
|
||||
auto iter = callback_vector.begin();
|
||||
for (; iter != callback_vector.end(); iter++) {
|
||||
if ((*iter).get() == callback_shared_ptr.get()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (iter == callback_vector.end()) {
|
||||
return false;
|
||||
}
|
||||
callback_vector.erase(iter);
|
||||
return true;
|
||||
};
|
||||
|
||||
static_assert(
|
||||
shutdown_type == ShutdownType::pre_shutdown || shutdown_type == ShutdownType::on_shutdown);
|
||||
|
||||
if constexpr (shutdown_type == ShutdownType::pre_shutdown) {
|
||||
return remove_callback(pre_shutdown_callbacks_mutex_, pre_shutdown_callbacks_);
|
||||
} else {
|
||||
return remove_callback(on_shutdown_callbacks_mutex_, on_shutdown_callbacks_);
|
||||
}
|
||||
return callback_list_ptr->erase(callback_shared_ptr) == 1;
|
||||
}
|
||||
|
||||
std::vector<rclcpp::Context::OnShutdownCallback>
|
||||
Context::get_on_shutdown_callbacks() const
|
||||
{
|
||||
return get_shutdown_callback<ShutdownType::on_shutdown>();
|
||||
return get_shutdown_callback(ShutdownType::on_shutdown);
|
||||
}
|
||||
|
||||
std::vector<rclcpp::Context::PreShutdownCallback>
|
||||
Context::get_pre_shutdown_callbacks() const
|
||||
{
|
||||
return get_shutdown_callback<ShutdownType::pre_shutdown>();
|
||||
return get_shutdown_callback(ShutdownType::pre_shutdown);
|
||||
}
|
||||
|
||||
template<Context::ShutdownType shutdown_type>
|
||||
std::vector<rclcpp::Context::ShutdownCallback>
|
||||
Context::get_shutdown_callback() const
|
||||
Context::get_shutdown_callback(ShutdownType shutdown_type) const
|
||||
{
|
||||
const auto get_callback_vector = [this](auto & mutex, auto & callback_set) {
|
||||
const std::lock_guard<std::mutex> lock(mutex);
|
||||
std::vector<rclcpp::Context::ShutdownCallback> callbacks;
|
||||
for (auto & callback : callback_set) {
|
||||
callbacks.push_back(*callback);
|
||||
}
|
||||
return callbacks;
|
||||
};
|
||||
std::mutex * mutex_ptr = nullptr;
|
||||
const std::unordered_set<
|
||||
std::shared_ptr<ShutdownCallbackHandle::ShutdownCallbackType>> * callback_list_ptr;
|
||||
|
||||
static_assert(
|
||||
shutdown_type == ShutdownType::pre_shutdown || shutdown_type == ShutdownType::on_shutdown);
|
||||
|
||||
if constexpr (shutdown_type == ShutdownType::pre_shutdown) {
|
||||
return get_callback_vector(pre_shutdown_callbacks_mutex_, pre_shutdown_callbacks_);
|
||||
} else {
|
||||
return get_callback_vector(on_shutdown_callbacks_mutex_, on_shutdown_callbacks_);
|
||||
switch (shutdown_type) {
|
||||
case ShutdownType::pre_shutdown:
|
||||
mutex_ptr = &pre_shutdown_callbacks_mutex_;
|
||||
callback_list_ptr = &pre_shutdown_callbacks_;
|
||||
break;
|
||||
case ShutdownType::on_shutdown:
|
||||
mutex_ptr = &on_shutdown_callbacks_mutex_;
|
||||
callback_list_ptr = &on_shutdown_callbacks_;
|
||||
break;
|
||||
}
|
||||
|
||||
std::vector<rclcpp::Context::ShutdownCallback> callbacks;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(*mutex_ptr);
|
||||
for (auto & iter : *callback_list_ptr) {
|
||||
callbacks.emplace_back(*iter);
|
||||
}
|
||||
}
|
||||
|
||||
return callbacks;
|
||||
}
|
||||
|
||||
std::shared_ptr<rcl_context_t>
|
||||
|
||||
@@ -161,13 +161,6 @@ 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)
|
||||
{
|
||||
@@ -197,13 +190,6 @@ 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)
|
||||
{
|
||||
@@ -236,13 +222,6 @@ 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
|
||||
{
|
||||
|
||||
@@ -106,12 +106,6 @@ Executor::~Executor()
|
||||
weak_groups_associated_with_executor_to_nodes_.clear();
|
||||
weak_groups_to_nodes_associated_with_executor_.clear();
|
||||
weak_groups_to_nodes_.clear();
|
||||
for (const auto & pair : weak_groups_to_guard_conditions_) {
|
||||
auto guard_condition = pair.second;
|
||||
memory_strategy_->remove_guard_condition(guard_condition);
|
||||
}
|
||||
weak_groups_to_guard_conditions_.clear();
|
||||
|
||||
for (const auto & pair : weak_nodes_to_guard_conditions_) {
|
||||
auto guard_condition = pair.second;
|
||||
memory_strategy_->remove_guard_condition(guard_condition);
|
||||
@@ -210,7 +204,8 @@ Executor::add_callback_group_to_map(
|
||||
if (has_executor.exchange(true)) {
|
||||
throw std::runtime_error("Callback group has already been added to an executor.");
|
||||
}
|
||||
|
||||
bool is_new_node = !has_node(node_ptr, weak_groups_to_nodes_associated_with_executor_) &&
|
||||
!has_node(node_ptr, weak_groups_associated_with_executor_to_nodes_);
|
||||
rclcpp::CallbackGroup::WeakPtr weak_group_ptr = group_ptr;
|
||||
auto insert_info =
|
||||
weak_groups_to_nodes.insert(std::make_pair(weak_group_ptr, node_ptr));
|
||||
@@ -220,24 +215,21 @@ Executor::add_callback_group_to_map(
|
||||
}
|
||||
// Also add to the map that contains all callback groups
|
||||
weak_groups_to_nodes_.insert(std::make_pair(weak_group_ptr, node_ptr));
|
||||
|
||||
if (node_ptr->get_context()->is_valid()) {
|
||||
auto callback_group_guard_condition =
|
||||
group_ptr->get_notify_guard_condition(node_ptr->get_context());
|
||||
weak_groups_to_guard_conditions_[weak_group_ptr] = callback_group_guard_condition.get();
|
||||
// Add the callback_group's notify condition to the guard condition handles
|
||||
memory_strategy_->add_guard_condition(*callback_group_guard_condition);
|
||||
}
|
||||
|
||||
if (notify) {
|
||||
// Interrupt waiting to handle new node
|
||||
try {
|
||||
interrupt_guard_condition_.trigger();
|
||||
} catch (const rclcpp::exceptions::RCLError & ex) {
|
||||
throw std::runtime_error(
|
||||
std::string(
|
||||
"Failed to trigger guard condition on callback group add: ") + ex.what());
|
||||
if (is_new_node) {
|
||||
const auto & gc = node_ptr->get_notify_guard_condition();
|
||||
weak_nodes_to_guard_conditions_[node_ptr] = &gc;
|
||||
if (notify) {
|
||||
// Interrupt waiting to handle new node
|
||||
try {
|
||||
interrupt_guard_condition_.trigger();
|
||||
} catch (const rclcpp::exceptions::RCLError & ex) {
|
||||
throw std::runtime_error(
|
||||
std::string(
|
||||
"Failed to trigger guard condition on callback group add: ") + ex.what());
|
||||
}
|
||||
}
|
||||
// Add the node's notify condition to the guard condition handles
|
||||
memory_strategy_->add_guard_condition(gc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,10 +272,6 @@ Executor::add_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_pt
|
||||
}
|
||||
});
|
||||
|
||||
const auto & gc = node_ptr->get_notify_guard_condition();
|
||||
weak_nodes_to_guard_conditions_[node_ptr] = &gc;
|
||||
// Add the node's notify condition to the guard condition handles
|
||||
memory_strategy_->add_guard_condition(gc);
|
||||
weak_nodes_.push_back(node_ptr);
|
||||
}
|
||||
|
||||
@@ -312,12 +300,7 @@ Executor::remove_callback_group_from_map(
|
||||
if (!has_node(node_ptr, weak_groups_to_nodes_associated_with_executor_) &&
|
||||
!has_node(node_ptr, weak_groups_associated_with_executor_to_nodes_))
|
||||
{
|
||||
auto iter = weak_groups_to_guard_conditions_.find(weak_group_ptr);
|
||||
if (iter != weak_groups_to_guard_conditions_.end()) {
|
||||
memory_strategy_->remove_guard_condition(iter->second);
|
||||
}
|
||||
weak_groups_to_guard_conditions_.erase(weak_group_ptr);
|
||||
|
||||
weak_nodes_to_guard_conditions_.erase(node_ptr);
|
||||
if (notify) {
|
||||
try {
|
||||
interrupt_guard_condition_.trigger();
|
||||
@@ -327,6 +310,7 @@ Executor::remove_callback_group_from_map(
|
||||
"Failed to trigger guard condition on callback group remove: ") + ex.what());
|
||||
}
|
||||
}
|
||||
memory_strategy_->remove_guard_condition(&node_ptr->get_notify_guard_condition());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -388,9 +372,6 @@ Executor::remove_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node
|
||||
}
|
||||
}
|
||||
|
||||
memory_strategy_->remove_guard_condition(&node_ptr->get_notify_guard_condition());
|
||||
weak_nodes_to_guard_conditions_.erase(node_ptr);
|
||||
|
||||
std::atomic_bool & has_executor = node_ptr->get_associated_with_executor_atomic();
|
||||
has_executor.store(false);
|
||||
}
|
||||
@@ -740,12 +721,6 @@ Executor::wait_for_work(std::chrono::nanoseconds timeout)
|
||||
{
|
||||
weak_groups_associated_with_executor_to_nodes_.erase(group_ptr);
|
||||
}
|
||||
auto callback_guard_pair = weak_groups_to_guard_conditions_.find(group_ptr);
|
||||
if (callback_guard_pair != weak_groups_to_guard_conditions_.end()) {
|
||||
auto guard_condition = callback_guard_pair->second;
|
||||
weak_groups_to_guard_conditions_.erase(group_ptr);
|
||||
memory_strategy_->remove_guard_condition(guard_condition);
|
||||
}
|
||||
weak_groups_to_nodes_.erase(group_ptr);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
|
||||
#include "rcpputils/scope_exit.hpp"
|
||||
|
||||
#include "rclcpp/logging.hpp"
|
||||
#include "rclcpp/utilities.hpp"
|
||||
|
||||
using rclcpp::executors::MultiThreadedExecutor;
|
||||
@@ -35,15 +34,9 @@ MultiThreadedExecutor::MultiThreadedExecutor(
|
||||
yield_before_execute_(yield_before_execute),
|
||||
next_exec_timeout_(next_exec_timeout)
|
||||
{
|
||||
number_of_threads_ = number_of_threads > 0 ?
|
||||
number_of_threads :
|
||||
std::max(std::thread::hardware_concurrency(), 2U);
|
||||
|
||||
if (number_of_threads_ == 1) {
|
||||
RCLCPP_WARN(
|
||||
rclcpp::get_logger("rclcpp"),
|
||||
"MultiThreadedExecutor is used with a single thread.\n"
|
||||
"Use the SingleThreadedExecutor instead.");
|
||||
number_of_threads_ = number_of_threads ? number_of_threads : std::thread::hardware_concurrency();
|
||||
if (number_of_threads_ == 0) {
|
||||
number_of_threads_ = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,327 +0,0 @@
|
||||
// Copyright 2023 iRobot Corporation.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "rclcpp/experimental/executors/events_executor/events_executor.hpp"
|
||||
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "rcpputils/scope_exit.hpp"
|
||||
|
||||
#include "rclcpp/exceptions/exceptions.hpp"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
using rclcpp::experimental::executors::EventsExecutor;
|
||||
|
||||
EventsExecutor::EventsExecutor(
|
||||
rclcpp::experimental::executors::EventsQueue::UniquePtr events_queue,
|
||||
bool execute_timers_separate_thread,
|
||||
const rclcpp::ExecutorOptions & options)
|
||||
: rclcpp::Executor(options)
|
||||
{
|
||||
// Get ownership of the queue used to store events.
|
||||
if (!events_queue) {
|
||||
throw std::invalid_argument("events_queue can't be a null pointer");
|
||||
}
|
||||
events_queue_ = std::move(events_queue);
|
||||
|
||||
// Create timers manager
|
||||
std::function<void(void *)> timer_on_ready_cb = nullptr;
|
||||
if (execute_timers_separate_thread) {
|
||||
timer_on_ready_cb = [this](const void * timer_id) {
|
||||
ExecutorEvent event = {timer_id, -1, ExecutorEventType::TIMER_EVENT, 1};
|
||||
this->events_queue_->enqueue(event);
|
||||
};
|
||||
}
|
||||
timers_manager_ =
|
||||
std::make_shared<rclcpp::experimental::TimersManager>(context_, timer_on_ready_cb);
|
||||
|
||||
// Create entities collector
|
||||
entities_collector_ = std::make_shared<EventsExecutorEntitiesCollector>(this);
|
||||
entities_collector_->init();
|
||||
|
||||
// Setup the executor notifier to wake up the executor when some guard conditions are tiggered.
|
||||
// The added guard conditions are guaranteed to not go out of scope before the executor itself.
|
||||
executor_notifier_ = std::make_shared<EventsExecutorNotifyWaitable>();
|
||||
executor_notifier_->add_guard_condition(shutdown_guard_condition_.get());
|
||||
executor_notifier_->add_guard_condition(&interrupt_guard_condition_);
|
||||
|
||||
entities_collector_->add_waitable(executor_notifier_);
|
||||
}
|
||||
|
||||
EventsExecutor::~EventsExecutor()
|
||||
{
|
||||
spinning.store(false);
|
||||
}
|
||||
|
||||
void
|
||||
EventsExecutor::spin()
|
||||
{
|
||||
if (spinning.exchange(true)) {
|
||||
throw std::runtime_error("spin() called while already spinning");
|
||||
}
|
||||
RCPPUTILS_SCOPE_EXIT(this->spinning.store(false); );
|
||||
|
||||
timers_manager_->start();
|
||||
RCPPUTILS_SCOPE_EXIT(timers_manager_->stop(); );
|
||||
|
||||
while (rclcpp::ok(context_) && spinning.load()) {
|
||||
// Wait until we get an event
|
||||
ExecutorEvent event;
|
||||
bool has_event = events_queue_->dequeue(event);
|
||||
if (has_event) {
|
||||
this->execute_event(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EventsExecutor::spin_some(std::chrono::nanoseconds max_duration)
|
||||
{
|
||||
return this->spin_some_impl(max_duration, false);
|
||||
}
|
||||
|
||||
void
|
||||
EventsExecutor::spin_all(std::chrono::nanoseconds max_duration)
|
||||
{
|
||||
if (max_duration <= 0ns) {
|
||||
throw std::invalid_argument("max_duration must be positive");
|
||||
}
|
||||
return this->spin_some_impl(max_duration, true);
|
||||
}
|
||||
|
||||
void
|
||||
EventsExecutor::spin_some_impl(std::chrono::nanoseconds max_duration, bool exhaustive)
|
||||
{
|
||||
if (spinning.exchange(true)) {
|
||||
throw std::runtime_error("spin_some() called while already spinning");
|
||||
}
|
||||
|
||||
RCPPUTILS_SCOPE_EXIT(this->spinning.store(false); );
|
||||
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
|
||||
auto max_duration_not_elapsed = [max_duration, start]() {
|
||||
if (std::chrono::nanoseconds(0) == max_duration) {
|
||||
// told to spin forever if need be
|
||||
return true;
|
||||
} else if (std::chrono::steady_clock::now() - start < max_duration) {
|
||||
// told to spin only for some maximum amount of time
|
||||
return true;
|
||||
}
|
||||
// spun too long
|
||||
return false;
|
||||
};
|
||||
|
||||
// Get the number of events and timers ready at start
|
||||
const size_t ready_events_at_start = events_queue_->size();
|
||||
size_t executed_events = 0;
|
||||
const size_t ready_timers_at_start = timers_manager_->get_number_ready_timers();
|
||||
size_t executed_timers = 0;
|
||||
|
||||
while (rclcpp::ok(context_) && spinning.load() && max_duration_not_elapsed()) {
|
||||
// Execute first ready event from queue if exists
|
||||
if (exhaustive || (executed_events < ready_events_at_start)) {
|
||||
bool has_event = !events_queue_->empty();
|
||||
|
||||
if (has_event) {
|
||||
ExecutorEvent event;
|
||||
bool ret = events_queue_->dequeue(event, std::chrono::nanoseconds(0));
|
||||
if (ret) {
|
||||
this->execute_event(event);
|
||||
executed_events++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Execute first timer if it is ready
|
||||
if (exhaustive || (executed_timers < ready_timers_at_start)) {
|
||||
bool timer_executed = timers_manager_->execute_head_timer();
|
||||
if (timer_executed) {
|
||||
executed_timers++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// If there's no more work available, exit
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EventsExecutor::spin_once_impl(std::chrono::nanoseconds timeout)
|
||||
{
|
||||
// In this context a negative input timeout means no timeout
|
||||
if (timeout < 0ns) {
|
||||
timeout = std::chrono::nanoseconds::max();
|
||||
}
|
||||
|
||||
// Select the smallest between input timeout and timer timeout
|
||||
bool is_timer_timeout = false;
|
||||
auto next_timer_timeout = timers_manager_->get_head_timeout();
|
||||
if (next_timer_timeout < timeout) {
|
||||
timeout = next_timer_timeout;
|
||||
is_timer_timeout = true;
|
||||
}
|
||||
|
||||
ExecutorEvent event;
|
||||
bool has_event = events_queue_->dequeue(event, timeout);
|
||||
|
||||
// If we wake up from the wait with an event, it means that it
|
||||
// arrived before any of the timers expired.
|
||||
if (has_event) {
|
||||
this->execute_event(event);
|
||||
} else if (is_timer_timeout) {
|
||||
timers_manager_->execute_head_timer();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EventsExecutor::add_node(
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr, bool notify)
|
||||
{
|
||||
// This field is unused because we don't have to wake up the executor when a node is added.
|
||||
(void) notify;
|
||||
|
||||
// Add node to entities collector
|
||||
entities_collector_->add_node(node_ptr);
|
||||
}
|
||||
|
||||
void
|
||||
EventsExecutor::add_node(std::shared_ptr<rclcpp::Node> node_ptr, bool notify)
|
||||
{
|
||||
this->add_node(node_ptr->get_node_base_interface(), notify);
|
||||
}
|
||||
|
||||
void
|
||||
EventsExecutor::remove_node(
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr, bool notify)
|
||||
{
|
||||
// This field is unused because we don't have to wake up the executor when a node is removed.
|
||||
(void)notify;
|
||||
|
||||
// Remove node from entities collector.
|
||||
// This will result in un-setting all the event callbacks from its entities.
|
||||
// After this function returns, this executor will not receive any more events associated
|
||||
// to these entities.
|
||||
entities_collector_->remove_node(node_ptr);
|
||||
}
|
||||
|
||||
void
|
||||
EventsExecutor::remove_node(std::shared_ptr<rclcpp::Node> node_ptr, bool notify)
|
||||
{
|
||||
this->remove_node(node_ptr->get_node_base_interface(), notify);
|
||||
}
|
||||
|
||||
void
|
||||
EventsExecutor::execute_event(const ExecutorEvent & event)
|
||||
{
|
||||
switch (event.type) {
|
||||
case ExecutorEventType::CLIENT_EVENT:
|
||||
{
|
||||
auto client = entities_collector_->get_client(event.exec_entity_id);
|
||||
|
||||
if (client) {
|
||||
for (size_t i = 0; i < event.num_events; i++) {
|
||||
execute_client(client);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ExecutorEventType::SUBSCRIPTION_EVENT:
|
||||
{
|
||||
auto subscription = entities_collector_->get_subscription(event.exec_entity_id);
|
||||
|
||||
if (subscription) {
|
||||
for (size_t i = 0; i < event.num_events; i++) {
|
||||
execute_subscription(subscription);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ExecutorEventType::SERVICE_EVENT:
|
||||
{
|
||||
auto service = entities_collector_->get_service(event.exec_entity_id);
|
||||
|
||||
if (service) {
|
||||
for (size_t i = 0; i < event.num_events; i++) {
|
||||
execute_service(service);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ExecutorEventType::TIMER_EVENT:
|
||||
{
|
||||
timers_manager_->execute_ready_timer(event.exec_entity_id);
|
||||
break;
|
||||
}
|
||||
case ExecutorEventType::WAITABLE_EVENT:
|
||||
{
|
||||
auto waitable = entities_collector_->get_waitable(event.exec_entity_id);
|
||||
|
||||
if (waitable) {
|
||||
for (size_t i = 0; i < event.num_events; i++) {
|
||||
auto data = waitable->take_data_by_entity_id(event.gen_entity_id);
|
||||
waitable->execute(data);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EventsExecutor::add_callback_group(
|
||||
rclcpp::CallbackGroup::SharedPtr group_ptr,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
|
||||
bool notify)
|
||||
{
|
||||
// This field is unused because we don't have to wake up
|
||||
// the executor when a callback group is added.
|
||||
(void)notify;
|
||||
entities_collector_->add_callback_group(group_ptr, node_ptr);
|
||||
}
|
||||
|
||||
void
|
||||
EventsExecutor::remove_callback_group(
|
||||
rclcpp::CallbackGroup::SharedPtr group_ptr, bool notify)
|
||||
{
|
||||
// This field is unused because we don't have to wake up
|
||||
// the executor when a callback group is removed.
|
||||
(void)notify;
|
||||
entities_collector_->remove_callback_group(group_ptr);
|
||||
}
|
||||
|
||||
std::vector<rclcpp::CallbackGroup::WeakPtr>
|
||||
EventsExecutor::get_all_callback_groups()
|
||||
{
|
||||
return entities_collector_->get_all_callback_groups();
|
||||
}
|
||||
|
||||
std::vector<rclcpp::CallbackGroup::WeakPtr>
|
||||
EventsExecutor::get_manually_added_callback_groups()
|
||||
{
|
||||
return entities_collector_->get_manually_added_callback_groups();
|
||||
}
|
||||
|
||||
std::vector<rclcpp::CallbackGroup::WeakPtr>
|
||||
EventsExecutor::get_automatically_added_callback_groups_from_nodes()
|
||||
{
|
||||
return entities_collector_->get_automatically_added_callback_groups_from_nodes();
|
||||
}
|
||||
@@ -1,699 +0,0 @@
|
||||
// Copyright 2023 iRobot Corporation.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "rclcpp/experimental/executors/events_executor/events_executor_entities_collector.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "rclcpp/memory_strategy.hpp"
|
||||
#include "rclcpp/detail/add_guard_condition_to_rcl_wait_set.hpp"
|
||||
#include "rclcpp/experimental/executors/events_executor/events_executor.hpp"
|
||||
|
||||
using rclcpp::experimental::executors::ExecutorEvent;
|
||||
using rclcpp::experimental::executors::ExecutorEventType;
|
||||
using rclcpp::experimental::executors::EventsExecutorEntitiesCollector;
|
||||
|
||||
EventsExecutorEntitiesCollector::EventsExecutorEntitiesCollector(
|
||||
rclcpp::experimental::executors::EventsExecutor * executor)
|
||||
{
|
||||
if (executor == nullptr) {
|
||||
throw std::runtime_error("Received nullptr executor in EventsExecutorEntitiesCollector.");
|
||||
}
|
||||
|
||||
associated_executor_ = executor;
|
||||
timers_manager_ = associated_executor_->timers_manager_;
|
||||
}
|
||||
|
||||
void
|
||||
EventsExecutorEntitiesCollector::init()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(reentrant_mutex_);
|
||||
// Add the EventsExecutorEntitiesCollector shared_ptr to waitables map
|
||||
weak_waitables_map_.emplace(this, this->shared_from_this());
|
||||
}
|
||||
|
||||
EventsExecutorEntitiesCollector::~EventsExecutorEntitiesCollector()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(reentrant_mutex_);
|
||||
|
||||
// Disassociate all callback groups and thus nodes.
|
||||
for (const auto & pair : weak_groups_associated_with_executor_to_nodes_) {
|
||||
auto group = pair.first.lock();
|
||||
if (group) {
|
||||
std::atomic_bool & has_executor = group->get_associated_with_executor_atomic();
|
||||
has_executor.store(false);
|
||||
callback_group_removed_impl(group);
|
||||
}
|
||||
}
|
||||
for (const auto & pair : weak_groups_to_nodes_associated_with_executor_) {
|
||||
auto group = pair.first.lock();
|
||||
if (group) {
|
||||
std::atomic_bool & has_executor = group->get_associated_with_executor_atomic();
|
||||
has_executor.store(false);
|
||||
callback_group_removed_impl(group);
|
||||
}
|
||||
}
|
||||
// Disassociate all nodes
|
||||
for (const auto & weak_node : weak_nodes_) {
|
||||
auto node = weak_node.lock();
|
||||
if (node) {
|
||||
std::atomic_bool & has_executor = node->get_associated_with_executor_atomic();
|
||||
has_executor.store(false);
|
||||
node_removed_impl(node);
|
||||
}
|
||||
}
|
||||
|
||||
// Unset callback group notify guard condition executor callback
|
||||
for (const auto & pair : weak_groups_to_guard_conditions_) {
|
||||
auto group = pair.first.lock();
|
||||
if (group) {
|
||||
auto & group_gc = pair.second;
|
||||
unset_guard_condition_callback(group_gc);
|
||||
}
|
||||
}
|
||||
|
||||
weak_clients_map_.clear();
|
||||
weak_services_map_.clear();
|
||||
weak_waitables_map_.clear();
|
||||
weak_subscriptions_map_.clear();
|
||||
weak_nodes_to_guard_conditions_.clear();
|
||||
weak_groups_to_guard_conditions_.clear();
|
||||
|
||||
weak_groups_associated_with_executor_to_nodes_.clear();
|
||||
weak_groups_to_nodes_associated_with_executor_.clear();
|
||||
weak_nodes_.clear();
|
||||
}
|
||||
|
||||
void
|
||||
EventsExecutorEntitiesCollector::execute(std::shared_ptr<void> & data)
|
||||
{
|
||||
// This function is called when the associated executor is notified that something changed.
|
||||
// We do not know if an entity has been added or removed so we have to rebuild everything.
|
||||
(void)data;
|
||||
|
||||
std::lock_guard<std::recursive_mutex> lock(reentrant_mutex_);
|
||||
timers_manager_->clear();
|
||||
|
||||
// If a registered node has a new callback group, register the group.
|
||||
add_callback_groups_from_nodes_associated_to_executor();
|
||||
|
||||
// For all groups registered in the executor, set their event callbacks.
|
||||
set_entities_event_callbacks_from_map(weak_groups_associated_with_executor_to_nodes_);
|
||||
set_entities_event_callbacks_from_map(weak_groups_to_nodes_associated_with_executor_);
|
||||
}
|
||||
|
||||
std::shared_ptr<void>
|
||||
EventsExecutorEntitiesCollector::take_data()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::shared_ptr<void>
|
||||
EventsExecutorEntitiesCollector::take_data_by_entity_id(size_t id)
|
||||
{
|
||||
(void)id;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
EventsExecutorEntitiesCollector::add_to_wait_set(rcl_wait_set_t * wait_set)
|
||||
{
|
||||
(void)wait_set;
|
||||
}
|
||||
|
||||
bool
|
||||
EventsExecutorEntitiesCollector::is_ready(rcl_wait_set_t * p_wait_set)
|
||||
{
|
||||
(void)p_wait_set;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
EventsExecutorEntitiesCollector::add_node(
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr)
|
||||
{
|
||||
bool is_new_node = false;
|
||||
// If the node already has an executor
|
||||
std::atomic_bool & has_executor = node_ptr->get_associated_with_executor_atomic();
|
||||
if (has_executor.exchange(true)) {
|
||||
throw std::runtime_error("Node has already been added to an executor.");
|
||||
}
|
||||
node_ptr->for_each_callback_group(
|
||||
[this, node_ptr, &is_new_node](rclcpp::CallbackGroup::SharedPtr group_ptr)
|
||||
{
|
||||
if (
|
||||
!group_ptr->get_associated_with_executor_atomic().load() &&
|
||||
group_ptr->automatically_add_to_executor_with_node())
|
||||
{
|
||||
is_new_node = (add_callback_group(
|
||||
group_ptr,
|
||||
node_ptr,
|
||||
weak_groups_to_nodes_associated_with_executor_) ||
|
||||
is_new_node);
|
||||
}
|
||||
});
|
||||
weak_nodes_.push_back(node_ptr);
|
||||
return is_new_node;
|
||||
}
|
||||
|
||||
bool
|
||||
EventsExecutorEntitiesCollector::add_callback_group(
|
||||
rclcpp::CallbackGroup::SharedPtr group_ptr,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
|
||||
rclcpp::memory_strategy::MemoryStrategy::WeakCallbackGroupsToNodesMap & weak_groups_to_nodes)
|
||||
{
|
||||
// If the callback_group already has an executor
|
||||
std::atomic_bool & has_executor = group_ptr->get_associated_with_executor_atomic();
|
||||
if (has_executor.exchange(true)) {
|
||||
throw std::runtime_error("Callback group has already been added to an executor.");
|
||||
}
|
||||
bool is_new_node = !has_node(node_ptr, weak_groups_associated_with_executor_to_nodes_) &&
|
||||
!has_node(node_ptr, weak_groups_to_nodes_associated_with_executor_);
|
||||
rclcpp::CallbackGroup::WeakPtr weak_group_ptr = group_ptr;
|
||||
auto insert_info = weak_groups_to_nodes.insert(
|
||||
std::make_pair(weak_group_ptr, node_ptr));
|
||||
bool was_inserted = insert_info.second;
|
||||
if (!was_inserted) {
|
||||
throw std::runtime_error("Callback group was already added to executor.");
|
||||
}
|
||||
|
||||
if (is_new_node) {
|
||||
node_added_impl(node_ptr);
|
||||
}
|
||||
|
||||
if (node_ptr->get_context()->is_valid()) {
|
||||
auto callback_group_guard_condition =
|
||||
group_ptr->get_notify_guard_condition(node_ptr->get_context());
|
||||
|
||||
rclcpp::CallbackGroup::WeakPtr weak_group_ptr = group_ptr;
|
||||
weak_groups_to_guard_conditions_[weak_group_ptr] = callback_group_guard_condition.get();
|
||||
}
|
||||
|
||||
callback_group_added_impl(group_ptr);
|
||||
|
||||
return is_new_node;
|
||||
}
|
||||
|
||||
bool
|
||||
EventsExecutorEntitiesCollector::add_callback_group(
|
||||
rclcpp::CallbackGroup::SharedPtr group_ptr,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr)
|
||||
{
|
||||
return add_callback_group(group_ptr, node_ptr, weak_groups_associated_with_executor_to_nodes_);
|
||||
}
|
||||
|
||||
bool
|
||||
EventsExecutorEntitiesCollector::remove_callback_group(
|
||||
rclcpp::CallbackGroup::SharedPtr group_ptr)
|
||||
{
|
||||
return this->remove_callback_group_from_map(
|
||||
group_ptr,
|
||||
weak_groups_associated_with_executor_to_nodes_);
|
||||
}
|
||||
|
||||
bool
|
||||
EventsExecutorEntitiesCollector::remove_callback_group_from_map(
|
||||
rclcpp::CallbackGroup::SharedPtr group_ptr,
|
||||
rclcpp::memory_strategy::MemoryStrategy::WeakCallbackGroupsToNodesMap & weak_groups_to_nodes)
|
||||
{
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr;
|
||||
rclcpp::CallbackGroup::WeakPtr weak_group_ptr = group_ptr;
|
||||
auto iter = weak_groups_to_nodes.find(weak_group_ptr);
|
||||
if (iter != weak_groups_to_nodes.end()) {
|
||||
node_ptr = iter->second.lock();
|
||||
if (node_ptr == nullptr) {
|
||||
throw std::runtime_error("Node must not be deleted before its callback group(s).");
|
||||
}
|
||||
weak_groups_to_nodes.erase(iter);
|
||||
callback_group_removed_impl(group_ptr);
|
||||
} else {
|
||||
throw std::runtime_error("Callback group needs to be associated with executor.");
|
||||
}
|
||||
// If the node was matched and removed, interrupt waiting.
|
||||
bool node_removed = false;
|
||||
if (!has_node(node_ptr, weak_groups_associated_with_executor_to_nodes_) &&
|
||||
!has_node(node_ptr, weak_groups_to_nodes_associated_with_executor_))
|
||||
{
|
||||
node_removed_impl(node_ptr);
|
||||
node_removed = true;
|
||||
}
|
||||
|
||||
weak_groups_to_guard_conditions_.erase(weak_group_ptr);
|
||||
|
||||
return node_removed;
|
||||
}
|
||||
|
||||
bool
|
||||
EventsExecutorEntitiesCollector::remove_node(
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr)
|
||||
{
|
||||
if (!node_ptr->get_associated_with_executor_atomic().load()) {
|
||||
return false;
|
||||
}
|
||||
bool node_found = false;
|
||||
auto node_it = weak_nodes_.begin();
|
||||
while (node_it != weak_nodes_.end()) {
|
||||
bool matched = (node_it->lock() == node_ptr);
|
||||
if (matched) {
|
||||
weak_nodes_.erase(node_it);
|
||||
node_found = true;
|
||||
break;
|
||||
}
|
||||
++node_it;
|
||||
}
|
||||
if (!node_found) {
|
||||
return false;
|
||||
}
|
||||
std::vector<rclcpp::CallbackGroup::SharedPtr> found_group_ptrs;
|
||||
std::for_each(
|
||||
weak_groups_to_nodes_associated_with_executor_.begin(),
|
||||
weak_groups_to_nodes_associated_with_executor_.end(),
|
||||
[&found_group_ptrs, node_ptr](std::pair<rclcpp::CallbackGroup::WeakPtr,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr> key_value_pair) {
|
||||
auto & weak_node_ptr = key_value_pair.second;
|
||||
auto shared_node_ptr = weak_node_ptr.lock();
|
||||
auto group_ptr = key_value_pair.first.lock();
|
||||
if (shared_node_ptr == node_ptr) {
|
||||
found_group_ptrs.push_back(group_ptr);
|
||||
}
|
||||
});
|
||||
std::for_each(
|
||||
found_group_ptrs.begin(), found_group_ptrs.end(), [this]
|
||||
(rclcpp::CallbackGroup::SharedPtr group_ptr) {
|
||||
this->remove_callback_group_from_map(
|
||||
group_ptr,
|
||||
weak_groups_to_nodes_associated_with_executor_);
|
||||
});
|
||||
std::atomic_bool & has_executor = node_ptr->get_associated_with_executor_atomic();
|
||||
has_executor.store(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns true iff the weak_groups_to_nodes map has node_ptr as the value in any of its entry.
|
||||
bool
|
||||
EventsExecutorEntitiesCollector::has_node(
|
||||
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
|
||||
const rclcpp::memory_strategy::MemoryStrategy::WeakCallbackGroupsToNodesMap &
|
||||
weak_groups_to_nodes) const
|
||||
{
|
||||
return std::find_if(
|
||||
weak_groups_to_nodes.begin(),
|
||||
weak_groups_to_nodes.end(),
|
||||
[&](const WeakCallbackGroupsToNodesMap::value_type & other) -> bool {
|
||||
auto other_ptr = other.second.lock();
|
||||
return other_ptr == node_ptr;
|
||||
}) != weak_groups_to_nodes.end();
|
||||
}
|
||||
|
||||
void
|
||||
EventsExecutorEntitiesCollector::add_callback_groups_from_nodes_associated_to_executor()
|
||||
{
|
||||
for (const auto & weak_node : weak_nodes_) {
|
||||
auto node = weak_node.lock();
|
||||
if (node) {
|
||||
node->for_each_callback_group(
|
||||
[this, node](rclcpp::CallbackGroup::SharedPtr shared_group_ptr)
|
||||
{
|
||||
if (shared_group_ptr->automatically_add_to_executor_with_node() &&
|
||||
!shared_group_ptr->get_associated_with_executor_atomic().load())
|
||||
{
|
||||
add_callback_group(
|
||||
shared_group_ptr,
|
||||
node,
|
||||
weak_groups_to_nodes_associated_with_executor_);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<rclcpp::CallbackGroup::WeakPtr>
|
||||
EventsExecutorEntitiesCollector::get_all_callback_groups()
|
||||
{
|
||||
std::vector<rclcpp::CallbackGroup::WeakPtr> groups;
|
||||
for (const auto & group_node_ptr : weak_groups_associated_with_executor_to_nodes_) {
|
||||
groups.push_back(group_node_ptr.first);
|
||||
}
|
||||
for (const auto & group_node_ptr : weak_groups_to_nodes_associated_with_executor_) {
|
||||
groups.push_back(group_node_ptr.first);
|
||||
}
|
||||
return groups;
|
||||
}
|
||||
|
||||
std::vector<rclcpp::CallbackGroup::WeakPtr>
|
||||
EventsExecutorEntitiesCollector::get_manually_added_callback_groups()
|
||||
{
|
||||
std::vector<rclcpp::CallbackGroup::WeakPtr> groups;
|
||||
for (const auto & group_node_ptr : weak_groups_associated_with_executor_to_nodes_) {
|
||||
groups.push_back(group_node_ptr.first);
|
||||
}
|
||||
return groups;
|
||||
}
|
||||
|
||||
std::vector<rclcpp::CallbackGroup::WeakPtr>
|
||||
EventsExecutorEntitiesCollector::get_automatically_added_callback_groups_from_nodes()
|
||||
{
|
||||
std::vector<rclcpp::CallbackGroup::WeakPtr> groups;
|
||||
for (const auto & group_node_ptr : weak_groups_to_nodes_associated_with_executor_) {
|
||||
groups.push_back(group_node_ptr.first);
|
||||
}
|
||||
return groups;
|
||||
}
|
||||
|
||||
void
|
||||
EventsExecutorEntitiesCollector::callback_group_added_impl(
|
||||
rclcpp::CallbackGroup::SharedPtr group)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(reentrant_mutex_);
|
||||
|
||||
rclcpp::CallbackGroup::WeakPtr weak_group_ptr = group;
|
||||
|
||||
auto iter = weak_groups_to_guard_conditions_.find(weak_group_ptr);
|
||||
if (iter != weak_groups_to_guard_conditions_.end()) {
|
||||
// Set an event callback for the group's notify guard condition, so if new entities are added
|
||||
// or removed to this node we will receive an event.
|
||||
set_guard_condition_callback(iter->second);
|
||||
}
|
||||
// For all entities in the callback group, set their event callback
|
||||
set_callback_group_entities_callbacks(group);
|
||||
}
|
||||
|
||||
void
|
||||
EventsExecutorEntitiesCollector::node_added_impl(
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(reentrant_mutex_);
|
||||
|
||||
auto notify_guard_condition = &(node->get_notify_guard_condition());
|
||||
// Set an event callback for the node's notify guard condition, so if new entities are added
|
||||
// or removed to this node we will receive an event.
|
||||
set_guard_condition_callback(notify_guard_condition);
|
||||
|
||||
// Store node's notify guard condition
|
||||
weak_nodes_to_guard_conditions_[node] = notify_guard_condition;
|
||||
}
|
||||
|
||||
void
|
||||
EventsExecutorEntitiesCollector::callback_group_removed_impl(
|
||||
rclcpp::CallbackGroup::SharedPtr group)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(reentrant_mutex_);
|
||||
// For all the entities in the group, unset their callbacks
|
||||
unset_callback_group_entities_callbacks(group);
|
||||
}
|
||||
|
||||
void
|
||||
EventsExecutorEntitiesCollector::node_removed_impl(
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(reentrant_mutex_);
|
||||
// Node doesn't have more callback groups associated to the executor.
|
||||
// Unset the event callback for the node's notify guard condition, to stop
|
||||
// receiving events if entities are added or removed to this node.
|
||||
unset_guard_condition_callback(&(node->get_notify_guard_condition()));
|
||||
|
||||
// Remove guard condition from list
|
||||
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr weak_node_ptr(node);
|
||||
weak_nodes_to_guard_conditions_.erase(weak_node_ptr);
|
||||
}
|
||||
|
||||
void
|
||||
EventsExecutorEntitiesCollector::set_entities_event_callbacks_from_map(
|
||||
const WeakCallbackGroupsToNodesMap & weak_groups_to_nodes)
|
||||
{
|
||||
for (const auto & pair : weak_groups_to_nodes) {
|
||||
auto group = pair.first.lock();
|
||||
auto node = pair.second.lock();
|
||||
if (!node || !group || !group->can_be_taken_from().load()) {
|
||||
continue;
|
||||
}
|
||||
set_callback_group_entities_callbacks(group);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
EventsExecutorEntitiesCollector::set_callback_group_entities_callbacks(
|
||||
rclcpp::CallbackGroup::SharedPtr group)
|
||||
{
|
||||
// Timers are handled by the timers manager
|
||||
group->find_timer_ptrs_if(
|
||||
[this](const rclcpp::TimerBase::SharedPtr & timer) {
|
||||
if (timer) {
|
||||
timers_manager_->add_timer(timer);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// Set callbacks for all other entity types
|
||||
group->find_subscription_ptrs_if(
|
||||
[this](const rclcpp::SubscriptionBase::SharedPtr & subscription) {
|
||||
if (subscription) {
|
||||
weak_subscriptions_map_.emplace(subscription.get(), subscription);
|
||||
|
||||
subscription->set_on_new_message_callback(
|
||||
create_entity_callback(subscription.get(), ExecutorEventType::SUBSCRIPTION_EVENT));
|
||||
}
|
||||
return false;
|
||||
});
|
||||
group->find_service_ptrs_if(
|
||||
[this](const rclcpp::ServiceBase::SharedPtr & service) {
|
||||
if (service) {
|
||||
weak_services_map_.emplace(service.get(), service);
|
||||
|
||||
service->set_on_new_request_callback(
|
||||
create_entity_callback(service.get(), ExecutorEventType::SERVICE_EVENT));
|
||||
}
|
||||
return false;
|
||||
});
|
||||
group->find_client_ptrs_if(
|
||||
[this](const rclcpp::ClientBase::SharedPtr & client) {
|
||||
if (client) {
|
||||
weak_clients_map_.emplace(client.get(), client);
|
||||
|
||||
client->set_on_new_response_callback(
|
||||
create_entity_callback(client.get(), ExecutorEventType::CLIENT_EVENT));
|
||||
}
|
||||
return false;
|
||||
});
|
||||
group->find_waitable_ptrs_if(
|
||||
[this](const rclcpp::Waitable::SharedPtr & waitable) {
|
||||
if (waitable) {
|
||||
weak_waitables_map_.emplace(waitable.get(), waitable);
|
||||
|
||||
waitable->set_on_ready_callback(
|
||||
create_waitable_callback(waitable.get()));
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
EventsExecutorEntitiesCollector::unset_callback_group_entities_callbacks(
|
||||
rclcpp::CallbackGroup::SharedPtr group)
|
||||
{
|
||||
auto iter = weak_groups_to_guard_conditions_.find(group);
|
||||
|
||||
if (iter != weak_groups_to_guard_conditions_.end()) {
|
||||
unset_guard_condition_callback(iter->second);
|
||||
}
|
||||
|
||||
// Timers are handled by the timers manager
|
||||
group->find_timer_ptrs_if(
|
||||
[this](const rclcpp::TimerBase::SharedPtr & timer) {
|
||||
if (timer) {
|
||||
timers_manager_->remove_timer(timer);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// Unset callbacks for all other entity types
|
||||
group->find_subscription_ptrs_if(
|
||||
[this](const rclcpp::SubscriptionBase::SharedPtr & subscription) {
|
||||
if (subscription) {
|
||||
subscription->clear_on_new_message_callback();
|
||||
weak_subscriptions_map_.erase(subscription.get());
|
||||
}
|
||||
return false;
|
||||
});
|
||||
group->find_service_ptrs_if(
|
||||
[this](const rclcpp::ServiceBase::SharedPtr & service) {
|
||||
if (service) {
|
||||
service->clear_on_new_request_callback();
|
||||
weak_services_map_.erase(service.get());
|
||||
}
|
||||
return false;
|
||||
});
|
||||
group->find_client_ptrs_if(
|
||||
[this](const rclcpp::ClientBase::SharedPtr & client) {
|
||||
if (client) {
|
||||
client->clear_on_new_response_callback();
|
||||
weak_clients_map_.erase(client.get());
|
||||
}
|
||||
return false;
|
||||
});
|
||||
group->find_waitable_ptrs_if(
|
||||
[this](const rclcpp::Waitable::SharedPtr & waitable) {
|
||||
if (waitable) {
|
||||
waitable->clear_on_ready_callback();
|
||||
weak_waitables_map_.erase(waitable.get());
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
void
|
||||
EventsExecutorEntitiesCollector::set_guard_condition_callback(
|
||||
rclcpp::GuardCondition * guard_condition)
|
||||
{
|
||||
auto gc_callback = [this](size_t num_events) {
|
||||
// Override num events (we don't care more than a single event)
|
||||
num_events = 1;
|
||||
int gc_id = -1;
|
||||
ExecutorEvent event = {this, gc_id, ExecutorEventType::WAITABLE_EVENT, num_events};
|
||||
associated_executor_->events_queue_->enqueue(event);
|
||||
};
|
||||
|
||||
guard_condition->set_on_trigger_callback(gc_callback);
|
||||
}
|
||||
|
||||
void
|
||||
EventsExecutorEntitiesCollector::unset_guard_condition_callback(
|
||||
rclcpp::GuardCondition * guard_condition)
|
||||
{
|
||||
guard_condition->set_on_trigger_callback(nullptr);
|
||||
}
|
||||
|
||||
rclcpp::SubscriptionBase::SharedPtr
|
||||
EventsExecutorEntitiesCollector::get_subscription(const void * subscription_id)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(reentrant_mutex_);
|
||||
|
||||
auto it = weak_subscriptions_map_.find(subscription_id);
|
||||
|
||||
if (it != weak_subscriptions_map_.end()) {
|
||||
auto subscription_weak_ptr = it->second;
|
||||
auto subscription_shared_ptr = subscription_weak_ptr.lock();
|
||||
|
||||
if (subscription_shared_ptr) {
|
||||
return subscription_shared_ptr;
|
||||
}
|
||||
|
||||
// The subscription expired, remove from map
|
||||
weak_subscriptions_map_.erase(it);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
rclcpp::ClientBase::SharedPtr
|
||||
EventsExecutorEntitiesCollector::get_client(const void * client_id)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(reentrant_mutex_);
|
||||
|
||||
auto it = weak_clients_map_.find(client_id);
|
||||
|
||||
if (it != weak_clients_map_.end()) {
|
||||
auto client_weak_ptr = it->second;
|
||||
auto client_shared_ptr = client_weak_ptr.lock();
|
||||
|
||||
if (client_shared_ptr) {
|
||||
return client_shared_ptr;
|
||||
}
|
||||
|
||||
// The client expired, remove from map
|
||||
weak_clients_map_.erase(it);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
rclcpp::ServiceBase::SharedPtr
|
||||
EventsExecutorEntitiesCollector::get_service(const void * service_id)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(reentrant_mutex_);
|
||||
|
||||
auto it = weak_services_map_.find(service_id);
|
||||
|
||||
if (it != weak_services_map_.end()) {
|
||||
auto service_weak_ptr = it->second;
|
||||
auto service_shared_ptr = service_weak_ptr.lock();
|
||||
|
||||
if (service_shared_ptr) {
|
||||
return service_shared_ptr;
|
||||
}
|
||||
|
||||
// The service expired, remove from map
|
||||
weak_services_map_.erase(it);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
rclcpp::Waitable::SharedPtr
|
||||
EventsExecutorEntitiesCollector::get_waitable(const void * waitable_id)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(reentrant_mutex_);
|
||||
|
||||
auto it = weak_waitables_map_.find(waitable_id);
|
||||
|
||||
if (it != weak_waitables_map_.end()) {
|
||||
auto waitable_weak_ptr = it->second;
|
||||
auto waitable_shared_ptr = waitable_weak_ptr.lock();
|
||||
|
||||
if (waitable_shared_ptr) {
|
||||
return waitable_shared_ptr;
|
||||
}
|
||||
|
||||
// The waitable expired, remove from map
|
||||
weak_waitables_map_.erase(it);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
EventsExecutorEntitiesCollector::add_waitable(rclcpp::Waitable::SharedPtr waitable)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(reentrant_mutex_);
|
||||
|
||||
weak_waitables_map_.emplace(waitable.get(), waitable);
|
||||
|
||||
waitable->set_on_ready_callback(
|
||||
create_waitable_callback(waitable.get()));
|
||||
}
|
||||
|
||||
std::function<void(size_t)>
|
||||
EventsExecutorEntitiesCollector::create_entity_callback(
|
||||
void * exec_entity_id, ExecutorEventType event_type)
|
||||
{
|
||||
std::function<void(size_t)>
|
||||
callback = [this, exec_entity_id, event_type](size_t num_events) {
|
||||
ExecutorEvent event = {exec_entity_id, -1, event_type, num_events};
|
||||
associated_executor_->events_queue_->enqueue(event);
|
||||
};
|
||||
return callback;
|
||||
}
|
||||
|
||||
std::function<void(size_t, int)>
|
||||
EventsExecutorEntitiesCollector::create_waitable_callback(void * exec_entity_id)
|
||||
{
|
||||
std::function<void(size_t, int)>
|
||||
callback = [this, exec_entity_id](size_t num_events, int gen_entity_id) {
|
||||
ExecutorEvent event =
|
||||
{exec_entity_id, gen_entity_id, ExecutorEventType::WAITABLE_EVENT, num_events};
|
||||
associated_executor_->events_queue_->enqueue(event);
|
||||
};
|
||||
return callback;
|
||||
}
|
||||
@@ -1,311 +0,0 @@
|
||||
// Copyright 2023 iRobot Corporation.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "rclcpp/experimental/timers_manager.hpp"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <ctime>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
|
||||
using rclcpp::experimental::TimersManager;
|
||||
|
||||
TimersManager::TimersManager(
|
||||
std::shared_ptr<rclcpp::Context> context,
|
||||
std::function<void(void *)> on_ready_callback)
|
||||
{
|
||||
context_ = context;
|
||||
on_ready_callback_ = on_ready_callback;
|
||||
}
|
||||
|
||||
TimersManager::~TimersManager()
|
||||
{
|
||||
// Remove all timers
|
||||
this->clear();
|
||||
|
||||
// Make sure timers thread is stopped before destroying this object
|
||||
this->stop();
|
||||
}
|
||||
|
||||
void TimersManager::add_timer(rclcpp::TimerBase::SharedPtr timer)
|
||||
{
|
||||
if (!timer) {
|
||||
throw std::invalid_argument("TimersManager::add_timer() trying to add nullptr timer");
|
||||
}
|
||||
|
||||
bool added = false;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(timers_mutex_);
|
||||
added = weak_timers_heap_.add_timer(timer);
|
||||
timers_updated_ = timers_updated_ || added;
|
||||
}
|
||||
|
||||
timer->set_on_reset_callback(
|
||||
[this](size_t arg) {
|
||||
{
|
||||
(void)arg;
|
||||
std::unique_lock<std::mutex> lock(timers_mutex_);
|
||||
timers_updated_ = true;
|
||||
}
|
||||
timers_cv_.notify_one();
|
||||
});
|
||||
|
||||
if (added) {
|
||||
// Notify that a timer has been added
|
||||
timers_cv_.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
void TimersManager::start()
|
||||
{
|
||||
// Make sure that the thread is not already running
|
||||
if (running_.exchange(true)) {
|
||||
throw std::runtime_error("TimersManager::start() can't start timers thread as already running");
|
||||
}
|
||||
|
||||
timers_thread_ = std::thread(&TimersManager::run_timers, this);
|
||||
}
|
||||
|
||||
void TimersManager::stop()
|
||||
{
|
||||
// Lock stop() function to prevent race condition in destructor
|
||||
std::unique_lock<std::mutex> lock(stop_mutex_);
|
||||
running_ = false;
|
||||
|
||||
// Notify the timers manager thread to wake up
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(timers_mutex_);
|
||||
timers_updated_ = true;
|
||||
}
|
||||
timers_cv_.notify_one();
|
||||
|
||||
// Join timers thread if it's running
|
||||
if (timers_thread_.joinable()) {
|
||||
timers_thread_.join();
|
||||
}
|
||||
}
|
||||
|
||||
std::chrono::nanoseconds TimersManager::get_head_timeout()
|
||||
{
|
||||
// Do not allow to interfere with the thread running
|
||||
if (running_) {
|
||||
throw std::runtime_error(
|
||||
"get_head_timeout() can't be used while timers thread is running");
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> lock(timers_mutex_);
|
||||
return this->get_head_timeout_unsafe();
|
||||
}
|
||||
|
||||
size_t TimersManager::get_number_ready_timers()
|
||||
{
|
||||
// Do not allow to interfere with the thread running
|
||||
if (running_) {
|
||||
throw std::runtime_error(
|
||||
"get_number_ready_timers() can't be used while timers thread is running");
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> lock(timers_mutex_);
|
||||
TimersHeap locked_heap = weak_timers_heap_.validate_and_lock();
|
||||
return locked_heap.get_number_ready_timers();
|
||||
}
|
||||
|
||||
void TimersManager::execute_ready_timers()
|
||||
{
|
||||
// Do not allow to interfere with the thread running
|
||||
if (running_) {
|
||||
throw std::runtime_error(
|
||||
"execute_ready_timers() can't be used while timers thread is running");
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> lock(timers_mutex_);
|
||||
this->execute_ready_timers_unsafe();
|
||||
}
|
||||
|
||||
bool TimersManager::execute_head_timer()
|
||||
{
|
||||
// Do not allow to interfere with the thread running
|
||||
if (running_) {
|
||||
throw std::runtime_error(
|
||||
"execute_head_timer() can't be used while timers thread is running");
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> lock(timers_mutex_);
|
||||
|
||||
TimersHeap timers_heap = weak_timers_heap_.validate_and_lock();
|
||||
|
||||
// Nothing to do if we don't have any timer
|
||||
if (timers_heap.empty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TimerPtr head_timer = timers_heap.front();
|
||||
|
||||
const bool timer_ready = head_timer->is_ready();
|
||||
if (timer_ready) {
|
||||
head_timer->call();
|
||||
if (on_ready_callback_) {
|
||||
on_ready_callback_(head_timer.get());
|
||||
} else {
|
||||
head_timer->execute_callback();
|
||||
}
|
||||
timers_heap.heapify_root();
|
||||
weak_timers_heap_.store(timers_heap);
|
||||
}
|
||||
|
||||
return timer_ready;
|
||||
}
|
||||
|
||||
void TimersManager::execute_ready_timer(const void * timer_id)
|
||||
{
|
||||
TimerPtr ready_timer;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(timers_mutex_);
|
||||
ready_timer = weak_timers_heap_.get_timer(timer_id);
|
||||
}
|
||||
if (ready_timer) {
|
||||
ready_timer->execute_callback();
|
||||
}
|
||||
}
|
||||
|
||||
std::chrono::nanoseconds TimersManager::get_head_timeout_unsafe()
|
||||
{
|
||||
// If we don't have any weak pointer, then we just return maximum timeout
|
||||
if (weak_timers_heap_.empty()) {
|
||||
return std::chrono::nanoseconds::max();
|
||||
}
|
||||
// Weak heap is not empty, so try to lock the first element.
|
||||
// If it is still a valid pointer, it is guaranteed to be the correct head
|
||||
TimerPtr head_timer = weak_timers_heap_.front().lock();
|
||||
|
||||
if (!head_timer) {
|
||||
// The first element has expired, we can't make other assumptions on the heap
|
||||
// and we need to entirely validate it.
|
||||
TimersHeap locked_heap = weak_timers_heap_.validate_and_lock();
|
||||
// NOTE: the following operations will not modify any element in the heap, so we
|
||||
// don't have to call `weak_timers_heap_.store(locked_heap)` at the end.
|
||||
|
||||
if (locked_heap.empty()) {
|
||||
return std::chrono::nanoseconds::max();
|
||||
}
|
||||
head_timer = locked_heap.front();
|
||||
}
|
||||
|
||||
return head_timer->time_until_trigger();
|
||||
}
|
||||
|
||||
void TimersManager::execute_ready_timers_unsafe()
|
||||
{
|
||||
// We start by locking the timers
|
||||
TimersHeap locked_heap = weak_timers_heap_.validate_and_lock();
|
||||
|
||||
// Nothing to do if we don't have any timer
|
||||
if (locked_heap.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Keep executing timers until they are ready and they were already ready when we started.
|
||||
// The two checks prevent this function from blocking indefinitely if the
|
||||
// time required for executing the timers is longer than their period.
|
||||
|
||||
TimerPtr head_timer = locked_heap.front();
|
||||
const size_t number_ready_timers = locked_heap.get_number_ready_timers();
|
||||
size_t executed_timers = 0;
|
||||
while (executed_timers < number_ready_timers && head_timer->is_ready()) {
|
||||
head_timer->call();
|
||||
if (on_ready_callback_) {
|
||||
on_ready_callback_(head_timer.get());
|
||||
} else {
|
||||
head_timer->execute_callback();
|
||||
}
|
||||
|
||||
executed_timers++;
|
||||
// Executing a timer will result in updating its time_until_trigger, so re-heapify
|
||||
locked_heap.heapify_root();
|
||||
// Get new head timer
|
||||
head_timer = locked_heap.front();
|
||||
}
|
||||
|
||||
// After having performed work on the locked heap we reflect the changes to weak one.
|
||||
// Timers will be already sorted the next time we need them if none went out of scope.
|
||||
weak_timers_heap_.store(locked_heap);
|
||||
}
|
||||
|
||||
void TimersManager::run_timers()
|
||||
{
|
||||
while (rclcpp::ok(context_) && running_) {
|
||||
// Lock mutex
|
||||
std::unique_lock<std::mutex> lock(timers_mutex_);
|
||||
|
||||
std::chrono::nanoseconds time_to_sleep = get_head_timeout_unsafe();
|
||||
|
||||
// No need to wait if a timer is already available
|
||||
if (time_to_sleep > std::chrono::nanoseconds::zero()) {
|
||||
if (time_to_sleep != std::chrono::nanoseconds::max()) {
|
||||
// Wait until timeout or notification that timers have been updated
|
||||
timers_cv_.wait_for(lock, time_to_sleep, [this]() {return timers_updated_;});
|
||||
} else {
|
||||
// Wait until notification that timers have been updated
|
||||
timers_cv_.wait(lock, [this]() {return timers_updated_;});
|
||||
}
|
||||
}
|
||||
|
||||
// Reset timers updated flag
|
||||
timers_updated_ = false;
|
||||
|
||||
// Execute timers
|
||||
this->execute_ready_timers_unsafe();
|
||||
}
|
||||
|
||||
// Make sure the running flag is set to false when we exit from this function
|
||||
// to allow restarting the timers thread.
|
||||
running_ = false;
|
||||
}
|
||||
|
||||
void TimersManager::clear()
|
||||
{
|
||||
{
|
||||
// Lock mutex and then clear all data structures
|
||||
std::unique_lock<std::mutex> lock(timers_mutex_);
|
||||
|
||||
TimersHeap locked_heap = weak_timers_heap_.validate_and_lock();
|
||||
locked_heap.clear_callbacks();
|
||||
|
||||
weak_timers_heap_.clear();
|
||||
|
||||
timers_updated_ = true;
|
||||
}
|
||||
|
||||
// Notify timers thread such that it can re-compute its timeout
|
||||
timers_cv_.notify_one();
|
||||
}
|
||||
|
||||
void TimersManager::remove_timer(TimerPtr timer)
|
||||
{
|
||||
bool removed = false;
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(timers_mutex_);
|
||||
removed = weak_timers_heap_.remove_timer(timer);
|
||||
|
||||
timers_updated_ = timers_updated_ || removed;
|
||||
}
|
||||
|
||||
if (removed) {
|
||||
// Notify timers thread such that it can re-compute its timeout
|
||||
timers_cv_.notify_one();
|
||||
timer->clear_on_reset_callback();
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,7 @@ GraphListener::GraphListener(const std::shared_ptr<Context> & parent_context)
|
||||
|
||||
GraphListener::~GraphListener()
|
||||
{
|
||||
GraphListener::shutdown(std::nothrow);
|
||||
this->shutdown(std::nothrow);
|
||||
}
|
||||
|
||||
void GraphListener::init_wait_set()
|
||||
|
||||
@@ -74,19 +74,16 @@ GuardCondition::get_rcl_guard_condition() const
|
||||
void
|
||||
GuardCondition::trigger()
|
||||
{
|
||||
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_);
|
||||
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(reentrant_mutex_);
|
||||
|
||||
if (on_trigger_callback_) {
|
||||
on_trigger_callback_(1);
|
||||
} else {
|
||||
unread_count_++;
|
||||
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);
|
||||
}
|
||||
unread_count_++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,9 +125,10 @@ GuardCondition::set_on_trigger_callback(std::function<void(size_t)> callback)
|
||||
callback(unread_count_);
|
||||
unread_count_ = 0;
|
||||
}
|
||||
} else {
|
||||
on_trigger_callback_ = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
on_trigger_callback_ = nullptr;
|
||||
}
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
@@ -12,19 +12,14 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "rcl_logging_interface/rcl_logging_interface.h"
|
||||
#include "rcl/logging_rosout.h"
|
||||
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
#include "rclcpp/logger.hpp"
|
||||
#include "rclcpp/logging.hpp"
|
||||
|
||||
#include "./logging_mutex.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
@@ -67,46 +62,6 @@ get_logging_directory()
|
||||
return path;
|
||||
}
|
||||
|
||||
Logger
|
||||
Logger::get_child(const std::string & suffix)
|
||||
{
|
||||
if (!name_) {
|
||||
return Logger();
|
||||
}
|
||||
|
||||
rcl_ret_t rcl_ret = RCL_RET_OK;
|
||||
std::shared_ptr<std::recursive_mutex> logging_mutex;
|
||||
logging_mutex = get_global_logging_mutex();
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(*logging_mutex);
|
||||
rcl_ret = rcl_logging_rosout_add_sublogger((*name_).c_str(), suffix.c_str());
|
||||
if (RCL_RET_OK != rcl_ret) {
|
||||
exceptions::throw_from_rcl_error(
|
||||
rcl_ret, "failed to call rcl_logging_rosout_add_sublogger",
|
||||
rcutils_get_error_state(), rcutils_reset_error);
|
||||
}
|
||||
}
|
||||
|
||||
Logger logger(*name_ + RCUTILS_LOGGING_SEPARATOR_STRING + suffix);
|
||||
if (RCL_RET_OK == rcl_ret) {
|
||||
logger.logger_sublogger_pairname_.reset(
|
||||
new std::pair<std::string, std::string>({*name_, suffix}),
|
||||
[logging_mutex](std::pair<std::string, std::string> * logger_sublogger_pairname_ptr) {
|
||||
std::lock_guard<std::recursive_mutex> guard(*logging_mutex);
|
||||
rcl_ret_t rcl_ret = rcl_logging_rosout_remove_sublogger(
|
||||
logger_sublogger_pairname_ptr->first.c_str(),
|
||||
logger_sublogger_pairname_ptr->second.c_str());
|
||||
delete logger_sublogger_pairname_ptr;
|
||||
if (RCL_RET_OK != rcl_ret) {
|
||||
exceptions::throw_from_rcl_error(
|
||||
rcl_ret, "failed to call rcl_logging_rosout_remove_sublogger",
|
||||
rcutils_get_error_state(), rcutils_reset_error);
|
||||
}
|
||||
});
|
||||
}
|
||||
return logger;
|
||||
}
|
||||
|
||||
void
|
||||
Logger::set_level(Level level)
|
||||
{
|
||||
|
||||
@@ -176,8 +176,7 @@ Node::Node(
|
||||
node_topics_,
|
||||
node_graph_,
|
||||
node_services_,
|
||||
node_logging_,
|
||||
options.clock_type()
|
||||
node_logging_
|
||||
)),
|
||||
node_parameters_(new rclcpp::node_interfaces::NodeParameters(
|
||||
node_base_,
|
||||
@@ -354,7 +353,7 @@ Node::has_parameter(const std::string & name) const
|
||||
rcl_interfaces::msg::SetParametersResult
|
||||
Node::set_parameter(const rclcpp::Parameter & parameter)
|
||||
{
|
||||
return node_parameters_->set_parameters_atomically({parameter});
|
||||
return this->set_parameters_atomically({parameter});
|
||||
}
|
||||
|
||||
std::vector<rcl_interfaces::msg::SetParametersResult>
|
||||
@@ -419,40 +418,16 @@ 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(OnSetParametersCallbackType callback)
|
||||
Node::add_on_set_parameters_callback(OnParametersSetCallbackType callback)
|
||||
{
|
||||
return node_parameters_->add_on_set_parameters_callback(callback);
|
||||
}
|
||||
|
||||
rclcpp::Node::PostSetParametersCallbackHandle::SharedPtr
|
||||
Node::add_post_set_parameters_callback(PostSetParametersCallbackType callback)
|
||||
{
|
||||
return node_parameters_->add_post_set_parameters_callback(callback);
|
||||
}
|
||||
|
||||
void
|
||||
Node::remove_pre_set_parameters_callback(const PreSetParametersCallbackHandle * const handler)
|
||||
Node::remove_on_set_parameters_callback(const OnSetParametersCallbackHandle * const callback)
|
||||
{
|
||||
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);
|
||||
return node_parameters_->remove_on_set_parameters_callback(callback);
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
|
||||
@@ -37,13 +37,12 @@ NodeBase::NodeBase(
|
||||
rclcpp::Context::SharedPtr context,
|
||||
const rcl_node_options_t & rcl_node_options,
|
||||
bool use_intra_process_default,
|
||||
bool enable_topic_statistics_default,
|
||||
rclcpp::CallbackGroup::SharedPtr default_callback_group)
|
||||
bool enable_topic_statistics_default)
|
||||
: context_(context),
|
||||
use_intra_process_default_(use_intra_process_default),
|
||||
enable_topic_statistics_default_(enable_topic_statistics_default),
|
||||
node_handle_(nullptr),
|
||||
default_callback_group_(default_callback_group),
|
||||
default_callback_group_(nullptr),
|
||||
associated_with_executor_(false),
|
||||
notify_guard_condition_(context),
|
||||
notify_guard_condition_is_valid_(false)
|
||||
@@ -129,12 +128,9 @@ NodeBase::NodeBase(
|
||||
delete node;
|
||||
});
|
||||
|
||||
// Create the default callback group, if needed.
|
||||
if (nullptr == default_callback_group_) {
|
||||
using rclcpp::CallbackGroupType;
|
||||
default_callback_group_ =
|
||||
NodeBase::create_callback_group(CallbackGroupType::MutuallyExclusive);
|
||||
}
|
||||
// Create the default callback group.
|
||||
using rclcpp::CallbackGroupType;
|
||||
default_callback_group_ = create_callback_group(CallbackGroupType::MutuallyExclusive);
|
||||
|
||||
// Indicate the notify_guard_condition is now valid.
|
||||
notify_guard_condition_is_valid_ = true;
|
||||
|
||||
@@ -24,14 +24,13 @@ NodeClock::NodeClock(
|
||||
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics,
|
||||
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph,
|
||||
rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services,
|
||||
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging,
|
||||
rcl_clock_type_t clock_type)
|
||||
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging)
|
||||
: node_base_(node_base),
|
||||
node_topics_(node_topics),
|
||||
node_graph_(node_graph),
|
||||
node_services_(node_services),
|
||||
node_logging_(node_logging),
|
||||
clock_(std::make_shared<rclcpp::Clock>(clock_type))
|
||||
ros_clock_(std::make_shared<rclcpp::Clock>(RCL_ROS_TIME))
|
||||
{}
|
||||
|
||||
NodeClock::~NodeClock()
|
||||
@@ -40,11 +39,11 @@ NodeClock::~NodeClock()
|
||||
rclcpp::Clock::SharedPtr
|
||||
NodeClock::get_clock()
|
||||
{
|
||||
return clock_;
|
||||
return ros_clock_;
|
||||
}
|
||||
|
||||
rclcpp::Clock::ConstSharedPtr
|
||||
NodeClock::get_clock() const
|
||||
{
|
||||
return clock_;
|
||||
return ros_clock_;
|
||||
}
|
||||
|
||||
@@ -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(NodeLogging::get_logger_name());
|
||||
logger_ = rclcpp::get_logger(this->get_logger_name());
|
||||
}
|
||||
|
||||
NodeLogging::~NodeLogging()
|
||||
|
||||
@@ -39,31 +39,6 @@
|
||||
|
||||
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,
|
||||
@@ -126,41 +101,18 @@ 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) {
|
||||
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);
|
||||
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);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
@@ -305,54 +257,19 @@ __check_parameters(
|
||||
return result;
|
||||
}
|
||||
|
||||
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 OnParametersSetCallbackType =
|
||||
rclcpp::node_interfaces::NodeParametersInterface::OnParametersSetCallbackType;
|
||||
using CallbacksContainerType =
|
||||
rclcpp::node_interfaces::NodeParameters::CallbacksContainerType;
|
||||
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_set_parameters_callbacks(
|
||||
__call_on_parameters_set_callbacks(
|
||||
const std::vector<rclcpp::Parameter> & parameters,
|
||||
OnSetCallbacksHandleContainer & callback_container)
|
||||
CallbacksContainerType & callback_container,
|
||||
const OnParametersSetCallbackType & callback)
|
||||
{
|
||||
rcl_interfaces::msg::SetParametersResult result;
|
||||
result.successful = true;
|
||||
@@ -369,37 +286,19 @@ __call_on_set_parameters_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,
|
||||
OnSetCallbacksHandleContainer & on_set_callback_container,
|
||||
PostSetCallbacksHandleContainer & post_set_callback_container,
|
||||
CallbacksContainerType & callback_container,
|
||||
const OnParametersSetCallbackType & callback,
|
||||
bool allow_undeclared = false)
|
||||
{
|
||||
// Check if the value being set complies with the descriptor.
|
||||
@@ -408,9 +307,9 @@ __set_parameters_atomically_common(
|
||||
if (!result.successful) {
|
||||
return result;
|
||||
}
|
||||
// Call the user callbacks to see if the new value(s) are allowed.
|
||||
// Call the user callback to see if the new value(s) are allowed.
|
||||
result =
|
||||
__call_on_set_parameters_callbacks(parameters, on_set_callback_container);
|
||||
__call_on_parameters_set_callbacks(parameters, callback_container, callback);
|
||||
if (!result.successful) {
|
||||
return result;
|
||||
}
|
||||
@@ -422,8 +321,6 @@ __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.
|
||||
@@ -438,8 +335,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,
|
||||
OnSetCallbacksHandleContainer & on_set_callback_container,
|
||||
PostSetCallbacksHandleContainer & post_set_callback_container,
|
||||
CallbacksContainerType & callback_container,
|
||||
const OnParametersSetCallbackType & callback,
|
||||
rcl_interfaces::msg::ParameterEvent * parameter_event_out,
|
||||
bool ignore_override = false)
|
||||
{
|
||||
@@ -469,15 +366,14 @@ __declare_parameter_common(
|
||||
return result;
|
||||
}
|
||||
|
||||
// Check with the user's callbacks to see if the initial value can be set.
|
||||
// Check with the user's callback 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,
|
||||
on_set_callback_container,
|
||||
post_set_callback_container
|
||||
);
|
||||
callback_container,
|
||||
callback);
|
||||
|
||||
if (!result.successful) {
|
||||
return result;
|
||||
@@ -504,8 +400,8 @@ declare_parameter_helper(
|
||||
bool ignore_override,
|
||||
std::map<std::string, rclcpp::node_interfaces::ParameterInfo> & parameters,
|
||||
const std::map<std::string, rclcpp::ParameterValue> & overrides,
|
||||
OnSetCallbacksHandleContainer & on_set_callback_container,
|
||||
PostSetCallbacksHandleContainer & post_set_callback_container,
|
||||
CallbacksContainerType & callback_container,
|
||||
const OnParametersSetCallbackType & callback,
|
||||
rclcpp::Publisher<rcl_interfaces::msg::ParameterEvent> * events_publisher,
|
||||
const std::string & combined_name,
|
||||
rclcpp::node_interfaces::NodeClockInterface & node_clock)
|
||||
@@ -541,8 +437,8 @@ declare_parameter_helper(
|
||||
parameter_descriptor,
|
||||
parameters,
|
||||
overrides,
|
||||
on_set_callback_container,
|
||||
post_set_callback_container,
|
||||
callback_container,
|
||||
callback,
|
||||
¶meter_event,
|
||||
ignore_override);
|
||||
|
||||
@@ -589,8 +485,8 @@ NodeParameters::declare_parameter(
|
||||
ignore_override,
|
||||
parameters_,
|
||||
parameter_overrides_,
|
||||
on_set_parameters_callback_container_,
|
||||
post_set_parameters_callback_container_,
|
||||
on_parameters_set_callback_container_,
|
||||
on_parameters_set_callback_,
|
||||
events_publisher_.get(),
|
||||
combined_name_,
|
||||
*node_clock_);
|
||||
@@ -625,8 +521,8 @@ NodeParameters::declare_parameter(
|
||||
ignore_override,
|
||||
parameters_,
|
||||
parameter_overrides_,
|
||||
on_set_parameters_callback_container_,
|
||||
post_set_parameters_callback_container_,
|
||||
on_parameters_set_callback_container_,
|
||||
on_parameters_set_callback_,
|
||||
events_publisher_.get(),
|
||||
combined_name_,
|
||||
*node_clock_);
|
||||
@@ -700,27 +596,12 @@ 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_after_pre_set_callback) {
|
||||
for (const auto & parameter : parameters) {
|
||||
const std::string & name = parameter.get_name();
|
||||
|
||||
// Check to make sure the parameter name is valid.
|
||||
@@ -755,13 +636,12 @@ 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 callbacks here, so that it may be called once, with
|
||||
// We explicitly avoid calling the user callback 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_;
|
||||
OnSetCallbacksHandleContainer empty_on_set_callback_container;
|
||||
PostSetCallbacksHandleContainer empty_post_set_callback_container;
|
||||
CallbacksContainerType empty_callback_container;
|
||||
|
||||
// Implicit declare uses dynamic type descriptor.
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor;
|
||||
@@ -776,8 +656,8 @@ NodeParameters::set_parameters_atomically(const std::vector<rclcpp::Parameter> &
|
||||
staged_parameter_changes,
|
||||
parameter_overrides_,
|
||||
// Only call callbacks once below
|
||||
empty_on_set_callback_container, // callback_container is explicitly empty
|
||||
empty_post_set_callback_container, // callback_container is explicitly empty
|
||||
empty_callback_container, // callback_container is explicitly empty
|
||||
nullptr, // callback is explicitly null.
|
||||
¶meter_event_msg,
|
||||
true);
|
||||
if (!result.successful) {
|
||||
@@ -790,14 +670,12 @@ 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 = ¶meters_after_pre_set_callback;
|
||||
const std::vector<rclcpp::Parameter> * parameters_to_be_set = ¶meters;
|
||||
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_after_pre_set_callback,
|
||||
staged_parameter_change.first);
|
||||
auto it = __find_parameter_by_name(parameters, 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.
|
||||
@@ -807,7 +685,7 @@ NodeParameters::set_parameters_atomically(const std::vector<rclcpp::Parameter> &
|
||||
}
|
||||
}
|
||||
if (any_initial_values_used) {
|
||||
parameters_copy = parameters_after_pre_set_callback;
|
||||
parameters_copy = parameters;
|
||||
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);
|
||||
@@ -839,10 +717,11 @@ 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_set_parameters_callback_container_,
|
||||
post_set_parameters_callback_container_,
|
||||
// the remaining aren't called.
|
||||
on_parameters_set_callback_,
|
||||
allow_undeclared_); // allow undeclared
|
||||
|
||||
// If not successful, then stop here.
|
||||
@@ -898,18 +777,29 @@ 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;
|
||||
}
|
||||
|
||||
std::vector<rclcpp::Parameter>
|
||||
NodeParameters::get_parameters(const std::vector<std::string> & names) const
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
||||
std::vector<rclcpp::Parameter> results;
|
||||
results.reserve(names.size());
|
||||
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
||||
for (auto & name : names) {
|
||||
results.emplace_back(this->get_parameter(name));
|
||||
auto found_parameter = parameters_.find(name);
|
||||
if (found_parameter != parameters_.cend()) {
|
||||
// found
|
||||
results.emplace_back(name, found_parameter->second.value);
|
||||
} else if (this->allow_undeclared_) {
|
||||
// not found, but undeclared allowed
|
||||
results.emplace_back(name, rclcpp::ParameterValue());
|
||||
} else {
|
||||
// not found, and undeclared are not allowed
|
||||
throw rclcpp::exceptions::ParameterNotDeclaredException(name);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
@@ -920,18 +810,18 @@ NodeParameters::get_parameter(const std::string & name) const
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
||||
|
||||
auto param_iter = parameters_.find(name);
|
||||
if (parameters_.end() != param_iter) {
|
||||
if (
|
||||
param_iter->second.value.get_type() != rclcpp::ParameterType::PARAMETER_NOT_SET ||
|
||||
param_iter->second.descriptor.dynamic_typing)
|
||||
{
|
||||
return rclcpp::Parameter{name, param_iter->second.value};
|
||||
}
|
||||
throw rclcpp::exceptions::ParameterUninitializedException(name);
|
||||
if (
|
||||
parameters_.end() != param_iter &&
|
||||
(param_iter->second.value.get_type() != rclcpp::ParameterType::PARAMETER_NOT_SET ||
|
||||
param_iter->second.descriptor.dynamic_typing))
|
||||
{
|
||||
return rclcpp::Parameter{name, param_iter->second.value};
|
||||
} else if (this->allow_undeclared_) {
|
||||
return rclcpp::Parameter{name};
|
||||
} else {
|
||||
return rclcpp::Parameter{};
|
||||
} else if (parameters_.end() == param_iter) {
|
||||
throw rclcpp::exceptions::ParameterNotDeclaredException(name);
|
||||
} else {
|
||||
throw rclcpp::exceptions::ParameterUninitializedException(name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1073,26 +963,6 @@ 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)
|
||||
@@ -1101,53 +971,20 @@ NodeParameters::remove_on_set_parameters_callback(
|
||||
ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
|
||||
|
||||
auto it = std::find_if(
|
||||
on_set_parameters_callback_container_.begin(),
|
||||
on_set_parameters_callback_container_.end(),
|
||||
on_parameters_set_callback_container_.begin(),
|
||||
on_parameters_set_callback_container_.end(),
|
||||
[handle](const auto & weak_handle) {
|
||||
return handle == weak_handle.lock().get();
|
||||
});
|
||||
if (it != on_set_parameters_callback_container_.end()) {
|
||||
on_set_parameters_callback_container_.erase(it);
|
||||
if (it != on_parameters_set_callback_container_.end()) {
|
||||
on_parameters_set_callback_container_.erase(it);
|
||||
} else {
|
||||
throw std::runtime_error("On set parameter callback doesn't exist");
|
||||
throw std::runtime_error("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(OnSetParametersCallbackType callback)
|
||||
NodeParameters::add_on_set_parameters_callback(OnParametersSetCallbackType callback)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
||||
ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
|
||||
@@ -1155,21 +992,7 @@ NodeParameters::add_on_set_parameters_callback(OnSetParametersCallbackType callb
|
||||
auto handle = std::make_shared<OnSetParametersCallbackHandle>();
|
||||
handle->callback = callback;
|
||||
// the last callback registered is executed first.
|
||||
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);
|
||||
on_parameters_set_callback_container_.emplace_front(handle);
|
||||
return handle;
|
||||
}
|
||||
|
||||
|
||||
@@ -35,17 +35,15 @@ NodeServices::add_service(
|
||||
// TODO(jacquelinekay): use custom exception
|
||||
throw std::runtime_error("Cannot create service, group not in node.");
|
||||
}
|
||||
group->add_service(service_base_ptr);
|
||||
} else {
|
||||
group = node_base_->get_default_callback_group();
|
||||
node_base_->get_default_callback_group()->add_service(service_base_ptr);
|
||||
}
|
||||
|
||||
group->add_service(service_base_ptr);
|
||||
|
||||
// Notify the executor that a new service was created using the parent Node.
|
||||
auto & node_gc = node_base_->get_notify_guard_condition();
|
||||
try {
|
||||
node_gc.trigger();
|
||||
group->trigger_notify_guard_condition();
|
||||
} catch (const rclcpp::exceptions::RCLError & ex) {
|
||||
throw std::runtime_error(
|
||||
std::string("failed to notify wait set on service creation: ") + ex.what());
|
||||
@@ -62,17 +60,15 @@ NodeServices::add_client(
|
||||
// TODO(jacquelinekay): use custom exception
|
||||
throw std::runtime_error("Cannot create client, group not in node.");
|
||||
}
|
||||
group->add_client(client_base_ptr);
|
||||
} else {
|
||||
group = node_base_->get_default_callback_group();
|
||||
node_base_->get_default_callback_group()->add_client(client_base_ptr);
|
||||
}
|
||||
|
||||
group->add_client(client_base_ptr);
|
||||
|
||||
// Notify the executor that a new client was created using the parent Node.
|
||||
auto & node_gc = node_base_->get_notify_guard_condition();
|
||||
try {
|
||||
node_gc.trigger();
|
||||
group->trigger_notify_guard_condition();
|
||||
} catch (const rclcpp::exceptions::RCLError & ex) {
|
||||
throw std::runtime_error(
|
||||
std::string("failed to notify wait set on client creation: ") + ex.what());
|
||||
|
||||
@@ -37,15 +37,14 @@ NodeTimers::add_timer(
|
||||
// TODO(jacquelinekay): use custom exception
|
||||
throw std::runtime_error("Cannot create timer, group not in node.");
|
||||
}
|
||||
callback_group->add_timer(timer);
|
||||
} else {
|
||||
callback_group = node_base_->get_default_callback_group();
|
||||
node_base_->get_default_callback_group()->add_timer(timer);
|
||||
}
|
||||
callback_group->add_timer(timer);
|
||||
|
||||
auto & node_gc = node_base_->get_notify_guard_condition();
|
||||
try {
|
||||
node_gc.trigger();
|
||||
callback_group->trigger_notify_guard_condition();
|
||||
} catch (const rclcpp::exceptions::RCLError & ex) {
|
||||
throw std::runtime_error(
|
||||
std::string("failed to notify wait set on timer creation: ") + ex.what());
|
||||
|
||||
@@ -73,7 +73,6 @@ NodeTopics::add_publisher(
|
||||
auto & node_gc = node_base_->get_notify_guard_condition();
|
||||
try {
|
||||
node_gc.trigger();
|
||||
callback_group->trigger_notify_guard_condition();
|
||||
} catch (const rclcpp::exceptions::RCLError & ex) {
|
||||
throw std::runtime_error(
|
||||
std::string("failed to notify wait set on publisher creation: ") + ex.what());
|
||||
@@ -122,7 +121,6 @@ NodeTopics::add_subscription(
|
||||
auto & node_gc = node_base_->get_notify_guard_condition();
|
||||
try {
|
||||
node_gc.trigger();
|
||||
callback_group->trigger_notify_guard_condition();
|
||||
} catch (const rclcpp::exceptions::RCLError & ex) {
|
||||
throw std::runtime_error(
|
||||
std::string("failed to notify wait set on subscription creation: ") + ex.what());
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user