Compare commits
27 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7aff0ffc56 | ||
|
|
0b606918d0 | ||
|
|
81d6f897a2 | ||
|
|
206e0fd4fe | ||
|
|
4fc379196d | ||
|
|
2f0db6c802 | ||
|
|
48068130ed | ||
|
|
54c2a8ac5b | ||
|
|
468cbab1aa | ||
|
|
283925677b | ||
|
|
340309d05c | ||
|
|
6adab6eab6 | ||
|
|
910cf32489 | ||
|
|
07f6b642ca | ||
|
|
d0fa844a09 | ||
|
|
260e62d5d6 | ||
|
|
da6c0e7090 | ||
|
|
5a09a4655f | ||
|
|
e9313c3dc5 | ||
|
|
c02a6a3cd3 | ||
|
|
2d208c5df3 | ||
|
|
42fb17ff95 | ||
|
|
2f2232b723 | ||
|
|
2616dfaef9 | ||
|
|
33de648095 | ||
|
|
82e4e72a2e | ||
|
|
7596ed4db0 |
@@ -8,10 +8,10 @@ rclcpp provides the standard C++ API for interacting with ROS 2.
|
||||
|
||||
`#include "rclcpp/rclcpp.hpp"` allows use of the most common elements of the ROS 2 system.
|
||||
|
||||
Visit the [rclcpp API documentation](http://docs.ros2.org/latest/api/rclcpp/) for a complete list of its main components.
|
||||
Visit the [rclcpp API documentation](http://docs.ros2.org/galactic/api/rclcpp/) for a complete list of its main components.
|
||||
|
||||
### Examples
|
||||
|
||||
The ROS 2 tutorials [Writing a simple publisher and subscriber](https://docs.ros.org/en/rolling/Tutorials/Writing-A-Simple-Cpp-Publisher-And-Subscriber.html).
|
||||
and [Writing a simple service and client](https://docs.ros.org/en/rolling/Tutorials/Writing-A-Simple-Cpp-Service-And-Client.html)
|
||||
The ROS 2 tutorials [Writing a simple publisher and subscriber](https://docs.ros.org/en/galactic/Tutorials/Writing-A-Simple-Cpp-Publisher-And-Subscriber.html).
|
||||
and [Writing a simple service and client](https://docs.ros.org/en/galactic/Tutorials/Writing-A-Simple-Cpp-Service-And-Client.html)
|
||||
contain some examples of rclcpp APIs in use.
|
||||
|
||||
@@ -2,45 +2,39 @@
|
||||
Changelog for package rclcpp
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
11.2.0 (2021-07-21)
|
||||
-------------------
|
||||
* Support to defer to send a response in services. (`#1709 <https://github.com/ros2/rclcpp/issues/1709>`_)
|
||||
Signed-off-by: Ivan Santiago Paunovic <ivanpauno@ekumenlabs.com>
|
||||
* Fix documentation bug. (`#1719 <https://github.com/ros2/rclcpp/issues/1719>`_)
|
||||
Signed-off-by: William Woodall <william@osrfoundation.org>
|
||||
* Contributors: Ivan Santiago Paunovic, William Woodall
|
||||
9.2.2 (2022-12-06)
|
||||
------------------
|
||||
* Fix returning invalid namespace if sub_namespace is empty (`#1810 <https://github.com/ros2/rclcpp/issues/1810>`_)
|
||||
* use regex for wildcard matching (`#1987 <https://github.com/ros2/rclcpp/issues/1987>`_)
|
||||
* Add statistics for handle_loaned_message (`#1933 <https://github.com/ros2/rclcpp/issues/1933>`_)
|
||||
* Contributors: Aaron Lipinski, Barry Xu, Chen Lihui, M. Hofstätter
|
||||
|
||||
11.1.0 (2021-07-13)
|
||||
-------------------
|
||||
* Removed left over ``is_initialized()`` implementation (`#1711 <https://github.com/ros2/rclcpp/issues/1711>`_)
|
||||
Leftover from https://github.com/ros2/rclcpp/pull/1622
|
||||
* Fixed declare parameter methods for int and float vectors (`#1696 <https://github.com/ros2/rclcpp/issues/1696>`_)
|
||||
* Cleaned up implementation of the intra-process manager (`#1695 <https://github.com/ros2/rclcpp/issues/1695>`_)
|
||||
* Added the node name to an executor ``runtime_error`` (`#1686 <https://github.com/ros2/rclcpp/issues/1686>`_)
|
||||
* Fixed a typo "Attack" -> "Attach" (`#1687 <https://github.com/ros2/rclcpp/issues/1687>`_)
|
||||
* Removed use of std::allocator<>::rebind (`#1678 <https://github.com/ros2/rclcpp/issues/1678>`_)
|
||||
rebind is deprecated in c++17 and removed in c++20
|
||||
* Contributors: Alberto Soragna, Chen Lihui, Chris Lalancette, Petter Nilsson, Steve Macenski, William Woodall
|
||||
9.2.1 (2022-04-28)
|
||||
------------------
|
||||
* Add test-dep ament_cmake_google_benchmark (`#1904 <https://github.com/ros2/rclcpp/issues/1904>`_) (`#1909 <https://github.com/ros2/rclcpp/issues/1909>`_)
|
||||
* Use parantheses around logging macro parameter (`#1820 <https://github.com/ros2/rclcpp/issues/1820>`_) (`#1822 <https://github.com/ros2/rclcpp/issues/1822>`_)
|
||||
* Contributors: mergify[bot]
|
||||
|
||||
11.0.0 (2021-05-18)
|
||||
-------------------
|
||||
* Allow declare uninitialized parameters (`#1673 <https://github.com/ros2/rclcpp/issues/1673>`_)
|
||||
* Fix syntax issue with gcc (`#1674 <https://github.com/ros2/rclcpp/issues/1674>`_)
|
||||
* [service] Don't use a weak_ptr to avoid leaking (`#1668 <https://github.com/ros2/rclcpp/issues/1668>`_)
|
||||
* Contributors: Ivan Santiago Paunovic, Jacob Perron, William Woodall
|
||||
9.2.0 (2021-09-17)
|
||||
------------------
|
||||
* Added thread safe for_each_callback_group method (`#1741 <https://github.com/ros2/rclcpp/issues/1741>`_)
|
||||
* Added a function rclcpp::wait_for_message() convenience function (`#1705 <https://github.com/ros2/rclcpp/issues/1705>`_) (`#1740 <https://github.com/ros2/rclcpp/issues/1740>`_)
|
||||
* Fixed a documentation bug (`#1719 <https://github.com/ros2/rclcpp/issues/1719>`_) (`#1720 <https://github.com/ros2/rclcpp/issues/1720>`_)
|
||||
* Contributors: Aditya Pande, Karsten Knese, mergify[bot]
|
||||
|
||||
10.0.0 (2021-05-11)
|
||||
-------------------
|
||||
* Fix doc typo (`#1663 <https://github.com/ros2/rclcpp/issues/1663>`_)
|
||||
* [rclcpp] Type Adaptation feature (`#1557 <https://github.com/ros2/rclcpp/issues/1557>`_)
|
||||
* Do not attempt to use void allocators for memory allocation. (`#1657 <https://github.com/ros2/rclcpp/issues/1657>`_)
|
||||
* Keep custom allocator in publisher and subscription options alive. (`#1647 <https://github.com/ros2/rclcpp/issues/1647>`_)
|
||||
* Fix get_publishers_subscriptions_info_by_topic test in test_node.cpp (`#1648 <https://github.com/ros2/rclcpp/issues/1648>`_)
|
||||
* Use OnShutdown callback handle instead of OnShutdown callback (`#1639 <https://github.com/ros2/rclcpp/issues/1639>`_)
|
||||
* use dynamic_pointer_cast to detect allocator mismatch in intra process manager (`#1643 <https://github.com/ros2/rclcpp/issues/1643>`_)
|
||||
9.1.0 (2021-05-20)
|
||||
------------------
|
||||
* Allow declaring uninitialized statically typed parameters. (`#1673 <https://github.com/ros2/rclcpp/issues/1673>`_) (`#1681 <https://github.com/ros2/rclcpp/issues/1681>`_)
|
||||
* [service] Don't use a weak_ptr to avoid leaking. (`#1668 <https://github.com/ros2/rclcpp/issues/1668>`_) (`#1670 <https://github.com/ros2/rclcpp/issues/1670>`_)
|
||||
* Contributors: Jacob Perron, Ivan Santiago Paunovic
|
||||
|
||||
9.0.3 (2021-05-10)
|
||||
------------------
|
||||
* Use OnShutdown callback handle instead of OnShutdown callback (`#1639 <https://github.com/ros2/rclcpp/issues/1639>`_) (`#1650 <https://github.com/ros2/rclcpp/issues/1650>`_)
|
||||
* use dynamic_pointer_cast to detect allocator mismatch in intra process manager (`#1643 <https://github.com/ros2/rclcpp/issues/1643>`_) (`#1644 <https://github.com/ros2/rclcpp/issues/1644>`_)
|
||||
* Increase cppcheck timeout to 500s (`#1634 <https://github.com/ros2/rclcpp/issues/1634>`_)
|
||||
* Clarify node parameters docs (`#1631 <https://github.com/ros2/rclcpp/issues/1631>`_)
|
||||
* Contributors: Audrow Nash, Barry Xu, Jacob Perron, Michel Hidalgo, Shane Loretz, William Woodall
|
||||
* Contributors: Barry Xu, Jacob Perron, Michel Hidalgo, Shane Loretz, William Woodall
|
||||
|
||||
9.0.2 (2021-04-14)
|
||||
------------------
|
||||
|
||||
@@ -95,7 +95,7 @@ void set_allocator_for_deleter(AllocatorDeleter<T> * deleter, Alloc * alloc)
|
||||
template<typename Alloc, typename T>
|
||||
using Deleter = typename std::conditional<
|
||||
std::is_same<typename std::allocator_traits<Alloc>::template rebind_alloc<T>,
|
||||
std::allocator<T>>::value,
|
||||
typename std::allocator<void>::template rebind<T>::other>::value,
|
||||
std::default_delete<T>,
|
||||
AllocatorDeleter<Alloc>
|
||||
>::type;
|
||||
|
||||
@@ -15,12 +15,10 @@
|
||||
#ifndef RCLCPP__ANY_SERVICE_CALLBACK_HPP_
|
||||
#define RCLCPP__ANY_SERVICE_CALLBACK_HPP_
|
||||
|
||||
#include <variant>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "rclcpp/function_traits.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
@@ -31,133 +29,93 @@
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template<typename T, typename = void>
|
||||
struct can_be_nullptr : std::false_type {};
|
||||
|
||||
// Some lambdas define a comparison with nullptr,
|
||||
// but we see a warning that they can never be null when using it.
|
||||
// We also test if `T &` can be assigned to `nullptr` to avoid the issue.
|
||||
template<typename T>
|
||||
struct can_be_nullptr<T, std::void_t<
|
||||
decltype(std::declval<T>() == nullptr), decltype(std::declval<T &>() = nullptr)>>
|
||||
: std::true_type {};
|
||||
} // namespace detail
|
||||
|
||||
// Forward declare
|
||||
template<typename ServiceT>
|
||||
class Service;
|
||||
|
||||
template<typename ServiceT>
|
||||
class AnyServiceCallback
|
||||
{
|
||||
private:
|
||||
using SharedPtrCallback = std::function<
|
||||
void (
|
||||
const std::shared_ptr<typename ServiceT::Request>,
|
||||
std::shared_ptr<typename ServiceT::Response>
|
||||
)>;
|
||||
using SharedPtrWithRequestHeaderCallback = std::function<
|
||||
void (
|
||||
const std::shared_ptr<rmw_request_id_t>,
|
||||
const std::shared_ptr<typename ServiceT::Request>,
|
||||
std::shared_ptr<typename ServiceT::Response>
|
||||
)>;
|
||||
|
||||
SharedPtrCallback shared_ptr_callback_;
|
||||
SharedPtrWithRequestHeaderCallback shared_ptr_with_request_header_callback_;
|
||||
|
||||
public:
|
||||
AnyServiceCallback()
|
||||
: callback_(std::monostate{})
|
||||
: shared_ptr_callback_(nullptr), shared_ptr_with_request_header_callback_(nullptr)
|
||||
{}
|
||||
|
||||
AnyServiceCallback(const AnyServiceCallback &) = default;
|
||||
|
||||
template<
|
||||
typename CallbackT,
|
||||
typename std::enable_if_t<!detail::can_be_nullptr<CallbackT>::value, int> = 0>
|
||||
void
|
||||
set(CallbackT && callback)
|
||||
typename std::enable_if<
|
||||
rclcpp::function_traits::same_arguments<
|
||||
CallbackT,
|
||||
SharedPtrCallback
|
||||
>::value
|
||||
>::type * = nullptr
|
||||
>
|
||||
void set(CallbackT callback)
|
||||
{
|
||||
callback_ = std::forward<CallbackT>(callback);
|
||||
shared_ptr_callback_ = callback;
|
||||
}
|
||||
|
||||
template<
|
||||
typename CallbackT,
|
||||
typename std::enable_if_t<detail::can_be_nullptr<CallbackT>::value, int> = 0>
|
||||
void
|
||||
set(CallbackT && callback)
|
||||
typename std::enable_if<
|
||||
rclcpp::function_traits::same_arguments<
|
||||
CallbackT,
|
||||
SharedPtrWithRequestHeaderCallback
|
||||
>::value
|
||||
>::type * = nullptr
|
||||
>
|
||||
void set(CallbackT callback)
|
||||
{
|
||||
if (!callback) {
|
||||
throw std::invalid_argument("AnyServiceCallback::set(): callback cannot be nullptr");
|
||||
}
|
||||
callback_ = std::forward<CallbackT>(callback);
|
||||
shared_ptr_with_request_header_callback_ = callback;
|
||||
}
|
||||
|
||||
// template<typename Allocator = std::allocator<typename ServiceT::Response>>
|
||||
std::shared_ptr<typename ServiceT::Response>
|
||||
dispatch(
|
||||
const std::shared_ptr<rclcpp::Service<ServiceT>> & service_handle,
|
||||
const std::shared_ptr<rmw_request_id_t> & request_header,
|
||||
std::shared_ptr<typename ServiceT::Request> request)
|
||||
void dispatch(
|
||||
std::shared_ptr<rmw_request_id_t> request_header,
|
||||
std::shared_ptr<typename ServiceT::Request> request,
|
||||
std::shared_ptr<typename ServiceT::Response> response)
|
||||
{
|
||||
TRACEPOINT(callback_start, static_cast<const void *>(this), false);
|
||||
if (std::holds_alternative<std::monostate>(callback_)) {
|
||||
// TODO(ivanpauno): Remove the set method, and force the users of this class
|
||||
// to pass a callback at construnciton.
|
||||
throw std::runtime_error{"unexpected request without any callback set"};
|
||||
}
|
||||
if (std::holds_alternative<SharedPtrDeferResponseCallback>(callback_)) {
|
||||
const auto & cb = std::get<SharedPtrDeferResponseCallback>(callback_);
|
||||
cb(request_header, std::move(request));
|
||||
return nullptr;
|
||||
}
|
||||
if (std::holds_alternative<SharedPtrDeferResponseCallbackWithServiceHandle>(callback_)) {
|
||||
const auto & cb = std::get<SharedPtrDeferResponseCallbackWithServiceHandle>(callback_);
|
||||
cb(service_handle, request_header, std::move(request));
|
||||
return nullptr;
|
||||
}
|
||||
// auto response = allocate_shared<typename ServiceT::Response, Allocator>();
|
||||
auto response = std::make_shared<typename ServiceT::Response>();
|
||||
if (std::holds_alternative<SharedPtrCallback>(callback_)) {
|
||||
if (shared_ptr_callback_ != nullptr) {
|
||||
(void)request_header;
|
||||
const auto & cb = std::get<SharedPtrCallback>(callback_);
|
||||
cb(std::move(request), response);
|
||||
} else if (std::holds_alternative<SharedPtrWithRequestHeaderCallback>(callback_)) {
|
||||
const auto & cb = std::get<SharedPtrWithRequestHeaderCallback>(callback_);
|
||||
cb(request_header, std::move(request), response);
|
||||
shared_ptr_callback_(request, response);
|
||||
} else if (shared_ptr_with_request_header_callback_ != nullptr) {
|
||||
shared_ptr_with_request_header_callback_(request_header, request, response);
|
||||
} else {
|
||||
throw std::runtime_error("unexpected request without any callback set");
|
||||
}
|
||||
TRACEPOINT(callback_end, static_cast<const void *>(this));
|
||||
return response;
|
||||
}
|
||||
|
||||
void register_callback_for_tracing()
|
||||
{
|
||||
#ifndef TRACETOOLS_DISABLED
|
||||
std::visit(
|
||||
[this](auto && arg) {
|
||||
TRACEPOINT(
|
||||
rclcpp_callback_register,
|
||||
static_cast<const void *>(this),
|
||||
tracetools::get_symbol(arg));
|
||||
}, callback_);
|
||||
if (shared_ptr_callback_) {
|
||||
TRACEPOINT(
|
||||
rclcpp_callback_register,
|
||||
static_cast<const void *>(this),
|
||||
tracetools::get_symbol(shared_ptr_callback_));
|
||||
} else if (shared_ptr_with_request_header_callback_) {
|
||||
TRACEPOINT(
|
||||
rclcpp_callback_register,
|
||||
static_cast<const void *>(this),
|
||||
tracetools::get_symbol(shared_ptr_with_request_header_callback_));
|
||||
}
|
||||
#endif // TRACETOOLS_DISABLED
|
||||
}
|
||||
|
||||
private:
|
||||
using SharedPtrCallback = std::function<
|
||||
void (
|
||||
std::shared_ptr<typename ServiceT::Request>,
|
||||
std::shared_ptr<typename ServiceT::Response>
|
||||
)>;
|
||||
using SharedPtrWithRequestHeaderCallback = std::function<
|
||||
void (
|
||||
std::shared_ptr<rmw_request_id_t>,
|
||||
std::shared_ptr<typename ServiceT::Request>,
|
||||
std::shared_ptr<typename ServiceT::Response>
|
||||
)>;
|
||||
using SharedPtrDeferResponseCallback = std::function<
|
||||
void (
|
||||
std::shared_ptr<rmw_request_id_t>,
|
||||
std::shared_ptr<typename ServiceT::Request>
|
||||
)>;
|
||||
using SharedPtrDeferResponseCallbackWithServiceHandle = std::function<
|
||||
void (
|
||||
std::shared_ptr<rclcpp::Service<ServiceT>>,
|
||||
std::shared_ptr<rmw_request_id_t>,
|
||||
std::shared_ptr<typename ServiceT::Request>
|
||||
)>;
|
||||
|
||||
std::variant<
|
||||
std::monostate,
|
||||
SharedPtrCallback,
|
||||
SharedPtrWithRequestHeaderCallback,
|
||||
SharedPtrDeferResponseCallback,
|
||||
SharedPtrDeferResponseCallbackWithServiceHandle> callback_;
|
||||
};
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include <utility>
|
||||
#include <variant> // NOLINT[build/include_order]
|
||||
|
||||
#include "rosidl_runtime_cpp/traits.hpp"
|
||||
#include "tracetools/tracetools.h"
|
||||
#include "tracetools/utils.hpp"
|
||||
|
||||
@@ -30,9 +29,6 @@
|
||||
#include "rclcpp/detail/subscription_callback_type_helper.hpp"
|
||||
#include "rclcpp/function_traits.hpp"
|
||||
#include "rclcpp/message_info.hpp"
|
||||
#include "rclcpp/serialized_message.hpp"
|
||||
#include "rclcpp/type_adapter.hpp"
|
||||
|
||||
|
||||
template<class>
|
||||
inline constexpr bool always_false_v = false;
|
||||
@@ -46,189 +42,53 @@ namespace detail
|
||||
template<typename MessageT, typename AllocatorT>
|
||||
struct MessageDeleterHelper
|
||||
{
|
||||
using AllocTraits = allocator::AllocRebind<MessageT, AllocatorT>;
|
||||
using Alloc = typename AllocTraits::allocator_type;
|
||||
using Deleter = allocator::Deleter<Alloc, MessageT>;
|
||||
using MessageAllocTraits = allocator::AllocRebind<MessageT, AllocatorT>;
|
||||
using MessageAlloc = typename MessageAllocTraits::allocator_type;
|
||||
using MessageDeleter = allocator::Deleter<MessageAlloc, MessageT>;
|
||||
};
|
||||
|
||||
/// Struct which contains all possible callback signatures, with or without a TypeAdapter.s
|
||||
template<typename MessageT, typename AllocatorT>
|
||||
struct AnySubscriptionCallbackPossibleTypes
|
||||
struct AnySubscriptionCallbackHelper
|
||||
{
|
||||
/// MessageT::custom_type if MessageT is a TypeAdapter, otherwise just MessageT.
|
||||
using SubscribedType = typename rclcpp::TypeAdapter<MessageT>::custom_type;
|
||||
/// MessageT::ros_message_type if MessageT is a TypeAdapter, otherwise just MessageT.
|
||||
using ROSMessageType = typename rclcpp::TypeAdapter<MessageT>::ros_message_type;
|
||||
|
||||
using SubscribedMessageDeleter =
|
||||
typename MessageDeleterHelper<SubscribedType, AllocatorT>::Deleter;
|
||||
using ROSMessageDeleter =
|
||||
typename MessageDeleterHelper<ROSMessageType, AllocatorT>::Deleter;
|
||||
using SerializedMessageDeleter =
|
||||
typename MessageDeleterHelper<rclcpp::SerializedMessage, AllocatorT>::Deleter;
|
||||
using MessageDeleter = typename MessageDeleterHelper<MessageT, AllocatorT>::MessageDeleter;
|
||||
|
||||
using ConstRefCallback =
|
||||
std::function<void (const SubscribedType &)>;
|
||||
using ConstRefROSMessageCallback =
|
||||
std::function<void (const ROSMessageType &)>;
|
||||
std::function<void (const MessageT &)>;
|
||||
using ConstRefWithInfoCallback =
|
||||
std::function<void (const SubscribedType &, const rclcpp::MessageInfo &)>;
|
||||
using ConstRefWithInfoROSMessageCallback =
|
||||
std::function<void (const ROSMessageType &, const rclcpp::MessageInfo &)>;
|
||||
using ConstRefSerializedMessageCallback =
|
||||
std::function<void (const rclcpp::SerializedMessage &)>;
|
||||
using ConstRefSerializedMessageWithInfoCallback =
|
||||
std::function<void (const rclcpp::SerializedMessage &, const rclcpp::MessageInfo &)>;
|
||||
std::function<void (const MessageT &, const rclcpp::MessageInfo &)>;
|
||||
|
||||
using UniquePtrCallback =
|
||||
std::function<void (std::unique_ptr<SubscribedType, SubscribedMessageDeleter>)>;
|
||||
using UniquePtrROSMessageCallback =
|
||||
std::function<void (std::unique_ptr<ROSMessageType, ROSMessageDeleter>)>;
|
||||
std::function<void (std::unique_ptr<MessageT, MessageDeleter>)>;
|
||||
using UniquePtrWithInfoCallback =
|
||||
std::function<void (
|
||||
std::unique_ptr<SubscribedType, SubscribedMessageDeleter>,
|
||||
const rclcpp::MessageInfo &)>;
|
||||
using UniquePtrWithInfoROSMessageCallback =
|
||||
std::function<void (
|
||||
std::unique_ptr<ROSMessageType, ROSMessageDeleter>,
|
||||
const rclcpp::MessageInfo &)>;
|
||||
using UniquePtrSerializedMessageCallback =
|
||||
std::function<void (std::unique_ptr<rclcpp::SerializedMessage, SerializedMessageDeleter>)>;
|
||||
using UniquePtrSerializedMessageWithInfoCallback =
|
||||
std::function<void (
|
||||
std::unique_ptr<rclcpp::SerializedMessage, SerializedMessageDeleter>,
|
||||
const rclcpp::MessageInfo &)>;
|
||||
std::function<void (std::unique_ptr<MessageT, MessageDeleter>, const rclcpp::MessageInfo &)>;
|
||||
|
||||
using SharedConstPtrCallback =
|
||||
std::function<void (std::shared_ptr<const SubscribedType>)>;
|
||||
using SharedConstPtrROSMessageCallback =
|
||||
std::function<void (std::shared_ptr<const ROSMessageType>)>;
|
||||
std::function<void (std::shared_ptr<const MessageT>)>;
|
||||
using SharedConstPtrWithInfoCallback =
|
||||
std::function<void (
|
||||
std::shared_ptr<const SubscribedType>,
|
||||
const rclcpp::MessageInfo &)>;
|
||||
using SharedConstPtrWithInfoROSMessageCallback =
|
||||
std::function<void (
|
||||
std::shared_ptr<const ROSMessageType>,
|
||||
const rclcpp::MessageInfo &)>;
|
||||
using SharedConstPtrSerializedMessageCallback =
|
||||
std::function<void (std::shared_ptr<const rclcpp::SerializedMessage>)>;
|
||||
using SharedConstPtrSerializedMessageWithInfoCallback =
|
||||
std::function<void (
|
||||
std::shared_ptr<const rclcpp::SerializedMessage>,
|
||||
const rclcpp::MessageInfo &)>;
|
||||
std::function<void (std::shared_ptr<const MessageT>, const rclcpp::MessageInfo &)>;
|
||||
|
||||
using ConstRefSharedConstPtrCallback =
|
||||
std::function<void (const std::shared_ptr<const SubscribedType> &)>;
|
||||
using ConstRefSharedConstPtrROSMessageCallback =
|
||||
std::function<void (const std::shared_ptr<const ROSMessageType> &)>;
|
||||
std::function<void (const std::shared_ptr<const MessageT> &)>;
|
||||
using ConstRefSharedConstPtrWithInfoCallback =
|
||||
std::function<void (
|
||||
const std::shared_ptr<const SubscribedType> &,
|
||||
const rclcpp::MessageInfo &)>;
|
||||
using ConstRefSharedConstPtrWithInfoROSMessageCallback =
|
||||
std::function<void (
|
||||
const std::shared_ptr<const ROSMessageType> &,
|
||||
const rclcpp::MessageInfo &)>;
|
||||
using ConstRefSharedConstPtrSerializedMessageCallback =
|
||||
std::function<void (const std::shared_ptr<const rclcpp::SerializedMessage> &)>;
|
||||
using ConstRefSharedConstPtrSerializedMessageWithInfoCallback =
|
||||
std::function<void (
|
||||
const std::shared_ptr<const rclcpp::SerializedMessage> &,
|
||||
const rclcpp::MessageInfo &)>;
|
||||
std::function<void (const std::shared_ptr<const MessageT> &, const rclcpp::MessageInfo &)>;
|
||||
|
||||
// Deprecated signatures:
|
||||
using SharedPtrCallback =
|
||||
std::function<void (std::shared_ptr<SubscribedType>)>;
|
||||
using SharedPtrROSMessageCallback =
|
||||
std::function<void (std::shared_ptr<ROSMessageType>)>;
|
||||
std::function<void (std::shared_ptr<MessageT>)>;
|
||||
using SharedPtrWithInfoCallback =
|
||||
std::function<void (std::shared_ptr<SubscribedType>, const rclcpp::MessageInfo &)>;
|
||||
using SharedPtrWithInfoROSMessageCallback =
|
||||
std::function<void (
|
||||
std::shared_ptr<ROSMessageType>,
|
||||
const rclcpp::MessageInfo &)>;
|
||||
using SharedPtrSerializedMessageCallback =
|
||||
std::function<void (std::shared_ptr<rclcpp::SerializedMessage>)>;
|
||||
using SharedPtrSerializedMessageWithInfoCallback =
|
||||
std::function<void (std::shared_ptr<rclcpp::SerializedMessage>, const rclcpp::MessageInfo &)>;
|
||||
};
|
||||
|
||||
/// Template helper to select the variant type based on whether or not MessageT is a TypeAdapter.
|
||||
template<
|
||||
typename MessageT,
|
||||
typename AllocatorT,
|
||||
bool is_adapted_type = rclcpp::TypeAdapter<MessageT>::is_specialized::value
|
||||
>
|
||||
struct AnySubscriptionCallbackHelper;
|
||||
|
||||
/// Specialization for when MessageT is not a TypeAdapter.
|
||||
template<typename MessageT, typename AllocatorT>
|
||||
struct AnySubscriptionCallbackHelper<MessageT, AllocatorT, false>
|
||||
{
|
||||
using CallbackTypes = AnySubscriptionCallbackPossibleTypes<MessageT, AllocatorT>;
|
||||
std::function<void (std::shared_ptr<MessageT>, const rclcpp::MessageInfo &)>;
|
||||
|
||||
using variant_type = std::variant<
|
||||
typename CallbackTypes::ConstRefCallback,
|
||||
typename CallbackTypes::ConstRefWithInfoCallback,
|
||||
typename CallbackTypes::ConstRefSerializedMessageCallback,
|
||||
typename CallbackTypes::ConstRefSerializedMessageWithInfoCallback,
|
||||
typename CallbackTypes::UniquePtrCallback,
|
||||
typename CallbackTypes::UniquePtrWithInfoCallback,
|
||||
typename CallbackTypes::UniquePtrSerializedMessageCallback,
|
||||
typename CallbackTypes::UniquePtrSerializedMessageWithInfoCallback,
|
||||
typename CallbackTypes::SharedConstPtrCallback,
|
||||
typename CallbackTypes::SharedConstPtrWithInfoCallback,
|
||||
typename CallbackTypes::SharedConstPtrSerializedMessageCallback,
|
||||
typename CallbackTypes::SharedConstPtrSerializedMessageWithInfoCallback,
|
||||
typename CallbackTypes::ConstRefSharedConstPtrCallback,
|
||||
typename CallbackTypes::ConstRefSharedConstPtrWithInfoCallback,
|
||||
typename CallbackTypes::ConstRefSharedConstPtrSerializedMessageCallback,
|
||||
typename CallbackTypes::ConstRefSharedConstPtrSerializedMessageWithInfoCallback,
|
||||
typename CallbackTypes::SharedPtrCallback,
|
||||
typename CallbackTypes::SharedPtrWithInfoCallback,
|
||||
typename CallbackTypes::SharedPtrSerializedMessageCallback,
|
||||
typename CallbackTypes::SharedPtrSerializedMessageWithInfoCallback
|
||||
>;
|
||||
};
|
||||
|
||||
/// Specialization for when MessageT is a TypeAdapter.
|
||||
template<typename MessageT, typename AllocatorT>
|
||||
struct AnySubscriptionCallbackHelper<MessageT, AllocatorT, true>
|
||||
{
|
||||
using CallbackTypes = AnySubscriptionCallbackPossibleTypes<MessageT, AllocatorT>;
|
||||
|
||||
using variant_type = std::variant<
|
||||
typename CallbackTypes::ConstRefCallback,
|
||||
typename CallbackTypes::ConstRefROSMessageCallback,
|
||||
typename CallbackTypes::ConstRefWithInfoCallback,
|
||||
typename CallbackTypes::ConstRefWithInfoROSMessageCallback,
|
||||
typename CallbackTypes::ConstRefSerializedMessageCallback,
|
||||
typename CallbackTypes::ConstRefSerializedMessageWithInfoCallback,
|
||||
typename CallbackTypes::UniquePtrCallback,
|
||||
typename CallbackTypes::UniquePtrROSMessageCallback,
|
||||
typename CallbackTypes::UniquePtrWithInfoCallback,
|
||||
typename CallbackTypes::UniquePtrWithInfoROSMessageCallback,
|
||||
typename CallbackTypes::UniquePtrSerializedMessageCallback,
|
||||
typename CallbackTypes::UniquePtrSerializedMessageWithInfoCallback,
|
||||
typename CallbackTypes::SharedConstPtrCallback,
|
||||
typename CallbackTypes::SharedConstPtrROSMessageCallback,
|
||||
typename CallbackTypes::SharedConstPtrWithInfoCallback,
|
||||
typename CallbackTypes::SharedConstPtrWithInfoROSMessageCallback,
|
||||
typename CallbackTypes::SharedConstPtrSerializedMessageCallback,
|
||||
typename CallbackTypes::SharedConstPtrSerializedMessageWithInfoCallback,
|
||||
typename CallbackTypes::ConstRefSharedConstPtrCallback,
|
||||
typename CallbackTypes::ConstRefSharedConstPtrROSMessageCallback,
|
||||
typename CallbackTypes::ConstRefSharedConstPtrWithInfoCallback,
|
||||
typename CallbackTypes::ConstRefSharedConstPtrWithInfoROSMessageCallback,
|
||||
typename CallbackTypes::ConstRefSharedConstPtrSerializedMessageCallback,
|
||||
typename CallbackTypes::ConstRefSharedConstPtrSerializedMessageWithInfoCallback,
|
||||
typename CallbackTypes::SharedPtrCallback,
|
||||
typename CallbackTypes::SharedPtrROSMessageCallback,
|
||||
typename CallbackTypes::SharedPtrWithInfoCallback,
|
||||
typename CallbackTypes::SharedPtrWithInfoROSMessageCallback,
|
||||
typename CallbackTypes::SharedPtrSerializedMessageCallback,
|
||||
typename CallbackTypes::SharedPtrSerializedMessageWithInfoCallback
|
||||
ConstRefCallback,
|
||||
ConstRefWithInfoCallback,
|
||||
UniquePtrCallback,
|
||||
UniquePtrWithInfoCallback,
|
||||
SharedConstPtrCallback,
|
||||
SharedConstPtrWithInfoCallback,
|
||||
ConstRefSharedConstPtrCallback,
|
||||
ConstRefSharedConstPtrWithInfoCallback,
|
||||
SharedPtrCallback,
|
||||
SharedPtrWithInfoCallback
|
||||
>;
|
||||
};
|
||||
|
||||
@@ -241,124 +101,49 @@ template<
|
||||
class AnySubscriptionCallback
|
||||
{
|
||||
private:
|
||||
/// MessageT::custom_type if MessageT is a TypeAdapter, otherwise just MessageT.
|
||||
using SubscribedType = typename rclcpp::TypeAdapter<MessageT>::custom_type;
|
||||
/// MessageT::ros_message_type if MessageT is a TypeAdapter, otherwise just MessageT.
|
||||
using ROSMessageType = typename rclcpp::TypeAdapter<MessageT>::ros_message_type;
|
||||
|
||||
using HelperT = typename rclcpp::detail::AnySubscriptionCallbackHelper<MessageT, AllocatorT>;
|
||||
using MessageDeleterHelper = rclcpp::detail::MessageDeleterHelper<MessageT, AllocatorT>;
|
||||
|
||||
using SubscribedTypeDeleterHelper =
|
||||
rclcpp::detail::MessageDeleterHelper<SubscribedType, AllocatorT>;
|
||||
using SubscribedTypeAllocatorTraits = typename SubscribedTypeDeleterHelper::AllocTraits;
|
||||
using SubscribedTypeAllocator = typename SubscribedTypeDeleterHelper::Alloc;
|
||||
using SubscribedTypeDeleter = typename SubscribedTypeDeleterHelper::Deleter;
|
||||
using MessageAllocTraits = typename MessageDeleterHelper::MessageAllocTraits;
|
||||
using MessageAlloc = typename MessageDeleterHelper::MessageAlloc;
|
||||
using MessageDeleter = typename MessageDeleterHelper::MessageDeleter;
|
||||
|
||||
using ROSMessageTypeDeleterHelper =
|
||||
rclcpp::detail::MessageDeleterHelper<ROSMessageType, AllocatorT>;
|
||||
using ROSMessageTypeAllocatorTraits = typename ROSMessageTypeDeleterHelper::AllocTraits;
|
||||
using ROSMessageTypeAllocator = typename ROSMessageTypeDeleterHelper::Alloc;
|
||||
using ROSMessageTypeDeleter = typename ROSMessageTypeDeleterHelper::Deleter;
|
||||
// See AnySubscriptionCallbackHelper for the types of these.
|
||||
using ConstRefCallback = typename HelperT::ConstRefCallback;
|
||||
using ConstRefWithInfoCallback = typename HelperT::ConstRefWithInfoCallback;
|
||||
|
||||
using SerializedMessageDeleterHelper =
|
||||
rclcpp::detail::MessageDeleterHelper<rclcpp::SerializedMessage, AllocatorT>;
|
||||
using SerializedMessageAllocatorTraits = typename SerializedMessageDeleterHelper::AllocTraits;
|
||||
using SerializedMessageAllocator = typename SerializedMessageDeleterHelper::Alloc;
|
||||
using SerializedMessageDeleter = typename SerializedMessageDeleterHelper::Deleter;
|
||||
using UniquePtrCallback = typename HelperT::UniquePtrCallback;
|
||||
using UniquePtrWithInfoCallback = typename HelperT::UniquePtrWithInfoCallback;
|
||||
|
||||
// See AnySubscriptionCallbackPossibleTypes for the types of these.
|
||||
using CallbackTypes = detail::AnySubscriptionCallbackPossibleTypes<MessageT, AllocatorT>;
|
||||
using SharedConstPtrCallback = typename HelperT::SharedConstPtrCallback;
|
||||
using SharedConstPtrWithInfoCallback = typename HelperT::SharedConstPtrWithInfoCallback;
|
||||
|
||||
using ConstRefCallback =
|
||||
typename CallbackTypes::ConstRefCallback;
|
||||
using ConstRefROSMessageCallback =
|
||||
typename CallbackTypes::ConstRefROSMessageCallback;
|
||||
using ConstRefWithInfoCallback =
|
||||
typename CallbackTypes::ConstRefWithInfoCallback;
|
||||
using ConstRefWithInfoROSMessageCallback =
|
||||
typename CallbackTypes::ConstRefWithInfoROSMessageCallback;
|
||||
using ConstRefSerializedMessageCallback =
|
||||
typename CallbackTypes::ConstRefSerializedMessageCallback;
|
||||
using ConstRefSerializedMessageWithInfoCallback =
|
||||
typename CallbackTypes::ConstRefSerializedMessageWithInfoCallback;
|
||||
using UniquePtrCallback =
|
||||
typename CallbackTypes::UniquePtrCallback;
|
||||
using UniquePtrROSMessageCallback =
|
||||
typename CallbackTypes::UniquePtrROSMessageCallback;
|
||||
using UniquePtrWithInfoCallback =
|
||||
typename CallbackTypes::UniquePtrWithInfoCallback;
|
||||
using UniquePtrWithInfoROSMessageCallback =
|
||||
typename CallbackTypes::UniquePtrWithInfoROSMessageCallback;
|
||||
using UniquePtrSerializedMessageCallback =
|
||||
typename CallbackTypes::UniquePtrSerializedMessageCallback;
|
||||
using UniquePtrSerializedMessageWithInfoCallback =
|
||||
typename CallbackTypes::UniquePtrSerializedMessageWithInfoCallback;
|
||||
using SharedConstPtrCallback =
|
||||
typename CallbackTypes::SharedConstPtrCallback;
|
||||
using SharedConstPtrROSMessageCallback =
|
||||
typename CallbackTypes::SharedConstPtrROSMessageCallback;
|
||||
using SharedConstPtrWithInfoCallback =
|
||||
typename CallbackTypes::SharedConstPtrWithInfoCallback;
|
||||
using SharedConstPtrWithInfoROSMessageCallback =
|
||||
typename CallbackTypes::SharedConstPtrWithInfoROSMessageCallback;
|
||||
using SharedConstPtrSerializedMessageCallback =
|
||||
typename CallbackTypes::SharedConstPtrSerializedMessageCallback;
|
||||
using SharedConstPtrSerializedMessageWithInfoCallback =
|
||||
typename CallbackTypes::SharedConstPtrSerializedMessageWithInfoCallback;
|
||||
using ConstRefSharedConstPtrCallback =
|
||||
typename CallbackTypes::ConstRefSharedConstPtrCallback;
|
||||
using ConstRefSharedConstPtrROSMessageCallback =
|
||||
typename CallbackTypes::ConstRefSharedConstPtrROSMessageCallback;
|
||||
typename HelperT::ConstRefSharedConstPtrCallback;
|
||||
using ConstRefSharedConstPtrWithInfoCallback =
|
||||
typename CallbackTypes::ConstRefSharedConstPtrWithInfoCallback;
|
||||
using ConstRefSharedConstPtrWithInfoROSMessageCallback =
|
||||
typename CallbackTypes::ConstRefSharedConstPtrWithInfoROSMessageCallback;
|
||||
using ConstRefSharedConstPtrSerializedMessageCallback =
|
||||
typename CallbackTypes::ConstRefSharedConstPtrSerializedMessageCallback;
|
||||
using ConstRefSharedConstPtrSerializedMessageWithInfoCallback =
|
||||
typename CallbackTypes::ConstRefSharedConstPtrSerializedMessageWithInfoCallback;
|
||||
using SharedPtrCallback =
|
||||
typename CallbackTypes::SharedPtrCallback;
|
||||
using SharedPtrROSMessageCallback =
|
||||
typename CallbackTypes::SharedPtrROSMessageCallback;
|
||||
using SharedPtrWithInfoCallback =
|
||||
typename CallbackTypes::SharedPtrWithInfoCallback;
|
||||
using SharedPtrWithInfoROSMessageCallback =
|
||||
typename CallbackTypes::SharedPtrWithInfoROSMessageCallback;
|
||||
using SharedPtrSerializedMessageCallback =
|
||||
typename CallbackTypes::SharedPtrSerializedMessageCallback;
|
||||
using SharedPtrSerializedMessageWithInfoCallback =
|
||||
typename CallbackTypes::SharedPtrSerializedMessageWithInfoCallback;
|
||||
typename HelperT::ConstRefSharedConstPtrWithInfoCallback;
|
||||
|
||||
template<typename T>
|
||||
struct NotNull
|
||||
{
|
||||
NotNull(const T * pointer_in, const char * msg)
|
||||
: pointer(pointer_in)
|
||||
{
|
||||
if (pointer == nullptr) {
|
||||
throw std::invalid_argument(msg);
|
||||
}
|
||||
}
|
||||
|
||||
const T * pointer;
|
||||
};
|
||||
using SharedPtrCallback = typename HelperT::SharedPtrCallback;
|
||||
using SharedPtrWithInfoCallback = typename HelperT::SharedPtrWithInfoCallback;
|
||||
|
||||
public:
|
||||
explicit
|
||||
AnySubscriptionCallback(const AllocatorT & allocator = AllocatorT()) // NOLINT[runtime/explicit]
|
||||
: subscribed_type_allocator_(allocator),
|
||||
ros_message_type_allocator_(allocator)
|
||||
{
|
||||
allocator::set_allocator_for_deleter(&subscribed_type_deleter_, &subscribed_type_allocator_);
|
||||
allocator::set_allocator_for_deleter(&ros_message_type_deleter_, &ros_message_type_allocator_);
|
||||
message_allocator_ = allocator;
|
||||
allocator::set_allocator_for_deleter(&message_deleter_, &message_allocator_);
|
||||
}
|
||||
|
||||
[[deprecated("use AnySubscriptionCallback(const AllocatorT & allocator) instead")]]
|
||||
explicit
|
||||
AnySubscriptionCallback(std::shared_ptr<AllocatorT> allocator) // NOLINT[runtime/explicit]
|
||||
: AnySubscriptionCallback(*NotNull<AllocatorT>(allocator.get(), "invalid allocator").pointer)
|
||||
{}
|
||||
{
|
||||
if (allocator == nullptr) {
|
||||
throw std::runtime_error("invalid allocator");
|
||||
}
|
||||
message_allocator_ = *allocator;
|
||||
allocator::set_allocator_for_deleter(&message_deleter_, &message_allocator_);
|
||||
}
|
||||
|
||||
AnySubscriptionCallback(const AnySubscriptionCallback &) = default;
|
||||
|
||||
@@ -405,79 +190,40 @@ public:
|
||||
}
|
||||
|
||||
/// Function for shared_ptr to non-const MessageT, which is deprecated.
|
||||
template<typename SetT>
|
||||
// TODO(wjwwood): enable this deprecation after Galactic
|
||||
// [[deprecated(
|
||||
// "use 'void (std::shared_ptr<const MessageT>)' instead"
|
||||
// )]]
|
||||
void
|
||||
set_deprecated(std::function<void(std::shared_ptr<SetT>)> callback)
|
||||
set_deprecated(std::function<void(std::shared_ptr<MessageT>)> callback)
|
||||
// set(CallbackT callback)
|
||||
{
|
||||
callback_variant_ = callback;
|
||||
}
|
||||
|
||||
/// Function for shared_ptr to non-const MessageT with MessageInfo, which is deprecated.
|
||||
template<typename SetT>
|
||||
// TODO(wjwwood): enable this deprecation after Galactic
|
||||
// [[deprecated(
|
||||
// "use 'void (std::shared_ptr<const MessageT>, const rclcpp::MessageInfo &)' instead"
|
||||
// )]]
|
||||
void
|
||||
set_deprecated(std::function<void(std::shared_ptr<SetT>, const rclcpp::MessageInfo &)> callback)
|
||||
set_deprecated(
|
||||
std::function<void(std::shared_ptr<MessageT>, const rclcpp::MessageInfo &)> callback)
|
||||
{
|
||||
callback_variant_ = callback;
|
||||
}
|
||||
|
||||
std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>
|
||||
create_ros_unique_ptr_from_ros_shared_ptr_message(
|
||||
const std::shared_ptr<const ROSMessageType> & message)
|
||||
std::unique_ptr<MessageT, MessageDeleter>
|
||||
create_unique_ptr_from_shared_ptr_message(const std::shared_ptr<const MessageT> & message)
|
||||
{
|
||||
auto ptr = ROSMessageTypeAllocatorTraits::allocate(ros_message_type_allocator_, 1);
|
||||
ROSMessageTypeAllocatorTraits::construct(ros_message_type_allocator_, ptr, *message);
|
||||
return std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>(ptr, ros_message_type_deleter_);
|
||||
auto ptr = MessageAllocTraits::allocate(message_allocator_, 1);
|
||||
MessageAllocTraits::construct(message_allocator_, ptr, *message);
|
||||
return std::unique_ptr<MessageT, MessageDeleter>(ptr, message_deleter_);
|
||||
}
|
||||
|
||||
std::unique_ptr<rclcpp::SerializedMessage, SerializedMessageDeleter>
|
||||
create_serialized_message_unique_ptr_from_shared_ptr(
|
||||
const std::shared_ptr<const rclcpp::SerializedMessage> & serialized_message)
|
||||
{
|
||||
auto ptr = SerializedMessageAllocatorTraits::allocate(serialized_message_allocator_, 1);
|
||||
SerializedMessageAllocatorTraits::construct(
|
||||
serialized_message_allocator_, ptr, *serialized_message);
|
||||
return std::unique_ptr<
|
||||
rclcpp::SerializedMessage,
|
||||
SerializedMessageDeleter
|
||||
>(ptr, serialized_message_deleter_);
|
||||
}
|
||||
|
||||
std::unique_ptr<SubscribedType, SubscribedTypeDeleter>
|
||||
create_custom_unique_ptr_from_custom_shared_ptr_message(
|
||||
const std::shared_ptr<const SubscribedType> & message)
|
||||
{
|
||||
auto ptr = SubscribedTypeAllocatorTraits::allocate(subscribed_type_allocator_, 1);
|
||||
SubscribedTypeAllocatorTraits::construct(subscribed_type_allocator_, ptr, *message);
|
||||
return std::unique_ptr<SubscribedType, SubscribedTypeDeleter>(ptr, subscribed_type_deleter_);
|
||||
}
|
||||
|
||||
std::unique_ptr<SubscribedType, SubscribedTypeDeleter>
|
||||
convert_ros_message_to_custom_type_unique_ptr(const ROSMessageType & msg)
|
||||
{
|
||||
if constexpr (rclcpp::TypeAdapter<MessageT>::is_specialized::value) {
|
||||
auto ptr = SubscribedTypeAllocatorTraits::allocate(subscribed_type_allocator_, 1);
|
||||
SubscribedTypeAllocatorTraits::construct(subscribed_type_allocator_, ptr);
|
||||
rclcpp::TypeAdapter<MessageT>::convert_to_custom(msg, *ptr);
|
||||
return std::unique_ptr<SubscribedType, SubscribedTypeDeleter>(ptr, subscribed_type_deleter_);
|
||||
} else {
|
||||
throw std::runtime_error(
|
||||
"convert_ros_message_to_custom_type_unique_ptr "
|
||||
"unexpectedly called without TypeAdapter");
|
||||
}
|
||||
}
|
||||
|
||||
// Dispatch when input is a ros message and the output could be anything.
|
||||
void
|
||||
dispatch(
|
||||
std::shared_ptr<ROSMessageType> message,
|
||||
std::shared_ptr<MessageT> message,
|
||||
const rclcpp::MessageInfo & message_info)
|
||||
{
|
||||
TRACEPOINT(callback_start, static_cast<const void *>(this), false);
|
||||
@@ -492,268 +238,28 @@ public:
|
||||
std::visit(
|
||||
[&message, &message_info, this](auto && callback) {
|
||||
using T = std::decay_t<decltype(callback)>;
|
||||
static constexpr bool is_ta = rclcpp::TypeAdapter<MessageT>::is_specialized::value;
|
||||
|
||||
// conditions for output is custom message
|
||||
if constexpr (is_ta && std::is_same_v<T, ConstRefCallback>) {
|
||||
// TODO(wjwwood): consider avoiding heap allocation for small messages
|
||||
// maybe something like:
|
||||
// if constexpr (rosidl_generator_traits::has_fixed_size<T> && sizeof(T) < N) {
|
||||
// ... on stack
|
||||
// }
|
||||
auto local_message = convert_ros_message_to_custom_type_unique_ptr(*message);
|
||||
callback(*local_message);
|
||||
} else if constexpr (is_ta && std::is_same_v<T, ConstRefWithInfoCallback>) { // NOLINT
|
||||
auto local_message = convert_ros_message_to_custom_type_unique_ptr(*message);
|
||||
callback(*local_message, message_info);
|
||||
} else if constexpr (is_ta && std::is_same_v<T, UniquePtrCallback>) {
|
||||
callback(convert_ros_message_to_custom_type_unique_ptr(*message));
|
||||
} else if constexpr (is_ta && std::is_same_v<T, UniquePtrWithInfoCallback>) {
|
||||
callback(convert_ros_message_to_custom_type_unique_ptr(*message), message_info);
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
is_ta && (
|
||||
std::is_same_v<T, SharedConstPtrCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrCallback>||
|
||||
std::is_same_v<T, SharedPtrCallback>
|
||||
))
|
||||
{
|
||||
callback(convert_ros_message_to_custom_type_unique_ptr(*message));
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
is_ta && (
|
||||
std::is_same_v<T, SharedConstPtrWithInfoCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrWithInfoCallback>||
|
||||
std::is_same_v<T, SharedPtrWithInfoCallback>
|
||||
))
|
||||
{
|
||||
callback(convert_ros_message_to_custom_type_unique_ptr(*message), message_info);
|
||||
}
|
||||
// conditions for output is ros message
|
||||
else if constexpr (std::is_same_v<T, ConstRefROSMessageCallback>) { // NOLINT
|
||||
if constexpr (std::is_same_v<T, ConstRefCallback>) {
|
||||
callback(*message);
|
||||
} else if constexpr (std::is_same_v<T, ConstRefWithInfoROSMessageCallback>) {
|
||||
} else if constexpr (std::is_same_v<T, ConstRefWithInfoCallback>) {
|
||||
callback(*message, message_info);
|
||||
} else if constexpr (std::is_same_v<T, UniquePtrROSMessageCallback>) {
|
||||
callback(create_ros_unique_ptr_from_ros_shared_ptr_message(message));
|
||||
} else if constexpr (std::is_same_v<T, UniquePtrWithInfoROSMessageCallback>) {
|
||||
callback(create_ros_unique_ptr_from_ros_shared_ptr_message(message), message_info);
|
||||
} else if constexpr (std::is_same_v<T, UniquePtrCallback>) {
|
||||
callback(create_unique_ptr_from_shared_ptr_message(message));
|
||||
} else if constexpr (std::is_same_v<T, UniquePtrWithInfoCallback>) {
|
||||
callback(create_unique_ptr_from_shared_ptr_message(message), message_info);
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, SharedConstPtrROSMessageCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrROSMessageCallback>||
|
||||
std::is_same_v<T, SharedPtrROSMessageCallback>)
|
||||
{
|
||||
callback(message);
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, SharedConstPtrWithInfoROSMessageCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrWithInfoROSMessageCallback>||
|
||||
std::is_same_v<T, SharedPtrWithInfoROSMessageCallback>)
|
||||
{
|
||||
callback(message, message_info);
|
||||
}
|
||||
// condition to catch SerializedMessage types
|
||||
else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, ConstRefSerializedMessageCallback>||
|
||||
std::is_same_v<T, ConstRefSerializedMessageWithInfoCallback>||
|
||||
std::is_same_v<T, UniquePtrSerializedMessageCallback>||
|
||||
std::is_same_v<T, UniquePtrSerializedMessageWithInfoCallback>||
|
||||
std::is_same_v<T, SharedConstPtrSerializedMessageCallback>||
|
||||
std::is_same_v<T, SharedConstPtrSerializedMessageWithInfoCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrSerializedMessageCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrSerializedMessageWithInfoCallback>||
|
||||
std::is_same_v<T, SharedPtrSerializedMessageCallback>||
|
||||
std::is_same_v<T, SharedPtrSerializedMessageWithInfoCallback>)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"Cannot dispatch std::shared_ptr<ROSMessageType> message "
|
||||
"to rclcpp::SerializedMessage");
|
||||
}
|
||||
// condition to catch unhandled callback types
|
||||
else { // NOLINT[readability/braces]
|
||||
static_assert(always_false_v<T>, "unhandled callback type");
|
||||
}
|
||||
}, callback_variant_);
|
||||
TRACEPOINT(callback_end, static_cast<const void *>(this));
|
||||
}
|
||||
|
||||
// Dispatch when input is a serialized message and the output could be anything.
|
||||
void
|
||||
dispatch(
|
||||
std::shared_ptr<rclcpp::SerializedMessage> serialized_message,
|
||||
const rclcpp::MessageInfo & message_info)
|
||||
{
|
||||
TRACEPOINT(callback_start, static_cast<const void *>(this), false);
|
||||
// Check if the variant is "unset", throw if it is.
|
||||
if (callback_variant_.index() == 0) {
|
||||
if (std::get<0>(callback_variant_) == nullptr) {
|
||||
// This can happen if it is default initialized, or if it is assigned nullptr.
|
||||
throw std::runtime_error("dispatch called on an unset AnySubscriptionCallback");
|
||||
}
|
||||
}
|
||||
// Dispatch.
|
||||
std::visit(
|
||||
[&serialized_message, &message_info, this](auto && callback) {
|
||||
using T = std::decay_t<decltype(callback)>;
|
||||
|
||||
// condition to catch SerializedMessage types
|
||||
if constexpr (std::is_same_v<T, ConstRefSerializedMessageCallback>) {
|
||||
callback(*serialized_message);
|
||||
} else if constexpr (std::is_same_v<T, ConstRefSerializedMessageWithInfoCallback>) {
|
||||
callback(*serialized_message, message_info);
|
||||
} else if constexpr (std::is_same_v<T, UniquePtrSerializedMessageCallback>) {
|
||||
callback(create_serialized_message_unique_ptr_from_shared_ptr(serialized_message));
|
||||
} else if constexpr (std::is_same_v<T, UniquePtrSerializedMessageWithInfoCallback>) {
|
||||
callback(
|
||||
create_serialized_message_unique_ptr_from_shared_ptr(serialized_message),
|
||||
message_info);
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, SharedConstPtrSerializedMessageCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrSerializedMessageCallback>||
|
||||
std::is_same_v<T, SharedPtrSerializedMessageCallback>)
|
||||
{
|
||||
callback(create_serialized_message_unique_ptr_from_shared_ptr(serialized_message));
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, SharedConstPtrSerializedMessageWithInfoCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrSerializedMessageWithInfoCallback>||
|
||||
std::is_same_v<T, SharedPtrSerializedMessageWithInfoCallback>)
|
||||
{
|
||||
callback(
|
||||
create_serialized_message_unique_ptr_from_shared_ptr(serialized_message),
|
||||
message_info);
|
||||
}
|
||||
// conditions for output anything else
|
||||
else if constexpr ( // NOLINT[whitespace/newline]
|
||||
std::is_same_v<T, ConstRefCallback>||
|
||||
std::is_same_v<T, ConstRefROSMessageCallback>||
|
||||
std::is_same_v<T, ConstRefWithInfoCallback>||
|
||||
std::is_same_v<T, ConstRefWithInfoROSMessageCallback>||
|
||||
std::is_same_v<T, UniquePtrCallback>||
|
||||
std::is_same_v<T, UniquePtrROSMessageCallback>||
|
||||
std::is_same_v<T, UniquePtrWithInfoCallback>||
|
||||
std::is_same_v<T, UniquePtrWithInfoROSMessageCallback>||
|
||||
std::is_same_v<T, SharedConstPtrCallback>||
|
||||
std::is_same_v<T, SharedConstPtrROSMessageCallback>||
|
||||
std::is_same_v<T, SharedConstPtrWithInfoCallback>||
|
||||
std::is_same_v<T, SharedConstPtrWithInfoROSMessageCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrROSMessageCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrWithInfoCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrWithInfoROSMessageCallback>||
|
||||
std::is_same_v<T, SharedPtrCallback>||
|
||||
std::is_same_v<T, SharedPtrROSMessageCallback>||
|
||||
std::is_same_v<T, SharedPtrWithInfoCallback>||
|
||||
std::is_same_v<T, SharedPtrWithInfoROSMessageCallback>)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"cannot dispatch rclcpp::SerializedMessage to "
|
||||
"non-rclcpp::SerializedMessage callbacks");
|
||||
}
|
||||
// condition to catch unhandled callback types
|
||||
else { // NOLINT[readability/braces]
|
||||
static_assert(always_false_v<T>, "unhandled callback type");
|
||||
}
|
||||
}, callback_variant_);
|
||||
TRACEPOINT(callback_end, static_cast<const void *>(this));
|
||||
}
|
||||
|
||||
void
|
||||
dispatch_intra_process(
|
||||
std::shared_ptr<const ROSMessageType> message,
|
||||
const rclcpp::MessageInfo & message_info)
|
||||
{
|
||||
TRACEPOINT(callback_start, static_cast<const void *>(this), true);
|
||||
// Check if the variant is "unset", throw if it is.
|
||||
if (callback_variant_.index() == 0) {
|
||||
if (std::get<0>(callback_variant_) == nullptr) {
|
||||
// This can happen if it is default initialized, or if it is assigned nullptr.
|
||||
throw std::runtime_error("dispatch called on an unset AnySubscriptionCallback");
|
||||
}
|
||||
}
|
||||
// Dispatch.
|
||||
std::visit(
|
||||
[&message, &message_info, this](auto && callback) {
|
||||
using T = std::decay_t<decltype(callback)>;
|
||||
static constexpr bool is_ta = rclcpp::TypeAdapter<MessageT>::is_specialized::value;
|
||||
|
||||
// conditions for custom type
|
||||
if constexpr (is_ta && std::is_same_v<T, ConstRefCallback>) {
|
||||
auto local_message = convert_ros_message_to_custom_type_unique_ptr(*message);
|
||||
callback(*local_message);
|
||||
} else if constexpr (is_ta && std::is_same_v<T, ConstRefWithInfoCallback>) { // NOLINT
|
||||
auto local_message = convert_ros_message_to_custom_type_unique_ptr(*message);
|
||||
callback(*local_message, message_info);
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
is_ta && (
|
||||
std::is_same_v<T, UniquePtrCallback>||
|
||||
std::is_same_v<T, SharedPtrCallback>
|
||||
))
|
||||
{
|
||||
callback(convert_ros_message_to_custom_type_unique_ptr(*message));
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
is_ta && (
|
||||
std::is_same_v<T, UniquePtrWithInfoCallback>||
|
||||
std::is_same_v<T, SharedPtrWithInfoCallback>
|
||||
))
|
||||
{
|
||||
callback(convert_ros_message_to_custom_type_unique_ptr(*message), message_info);
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
is_ta && (
|
||||
std::is_same_v<T, SharedConstPtrCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrCallback>
|
||||
))
|
||||
{
|
||||
callback(convert_ros_message_to_custom_type_unique_ptr(*message));
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
is_ta && (
|
||||
std::is_same_v<T, SharedConstPtrWithInfoCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrWithInfoCallback>
|
||||
))
|
||||
{
|
||||
callback(convert_ros_message_to_custom_type_unique_ptr(*message), message_info);
|
||||
}
|
||||
// conditions for ros message type
|
||||
else if constexpr (std::is_same_v<T, ConstRefROSMessageCallback>) { // NOLINT
|
||||
callback(*message);
|
||||
} else if constexpr (std::is_same_v<T, ConstRefWithInfoROSMessageCallback>) {
|
||||
callback(*message, message_info);
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, UniquePtrROSMessageCallback>||
|
||||
std::is_same_v<T, SharedPtrROSMessageCallback>)
|
||||
{
|
||||
callback(create_ros_unique_ptr_from_ros_shared_ptr_message(message));
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, UniquePtrWithInfoROSMessageCallback>||
|
||||
std::is_same_v<T, SharedPtrWithInfoROSMessageCallback>)
|
||||
{
|
||||
callback(create_ros_unique_ptr_from_ros_shared_ptr_message(message), message_info);
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, SharedConstPtrROSMessageCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrROSMessageCallback>)
|
||||
std::is_same_v<T, SharedPtrCallback>)
|
||||
{
|
||||
callback(message);
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, SharedConstPtrWithInfoROSMessageCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrWithInfoROSMessageCallback>)
|
||||
std::is_same_v<T, SharedConstPtrWithInfoCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrWithInfoCallback>||
|
||||
std::is_same_v<T, SharedPtrWithInfoCallback>)
|
||||
{
|
||||
callback(message, message_info);
|
||||
}
|
||||
// condition to catch SerializedMessage types
|
||||
else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, ConstRefSerializedMessageCallback>||
|
||||
std::is_same_v<T, ConstRefSerializedMessageWithInfoCallback>||
|
||||
std::is_same_v<T, UniquePtrSerializedMessageCallback>||
|
||||
std::is_same_v<T, UniquePtrSerializedMessageWithInfoCallback>||
|
||||
std::is_same_v<T, SharedConstPtrSerializedMessageCallback>||
|
||||
std::is_same_v<T, SharedConstPtrSerializedMessageWithInfoCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrSerializedMessageCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrSerializedMessageWithInfoCallback>||
|
||||
std::is_same_v<T, SharedPtrSerializedMessageCallback>||
|
||||
std::is_same_v<T, SharedPtrSerializedMessageWithInfoCallback>)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"Cannot dispatch std::shared_ptr<const ROSMessageType> message "
|
||||
"to rclcpp::SerializedMessage");
|
||||
}
|
||||
// condition to catch unhandled callback types
|
||||
else { // NOLINT[readability/braces]
|
||||
} else {
|
||||
static_assert(always_false_v<T>, "unhandled callback type");
|
||||
}
|
||||
}, callback_variant_);
|
||||
@@ -762,7 +268,7 @@ public:
|
||||
|
||||
void
|
||||
dispatch_intra_process(
|
||||
std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter> message,
|
||||
std::shared_ptr<const MessageT> message,
|
||||
const rclcpp::MessageInfo & message_info)
|
||||
{
|
||||
TRACEPOINT(callback_start, static_cast<const void *>(this), true);
|
||||
@@ -777,89 +283,75 @@ public:
|
||||
std::visit(
|
||||
[&message, &message_info, this](auto && callback) {
|
||||
using T = std::decay_t<decltype(callback)>;
|
||||
static constexpr bool is_ta = rclcpp::TypeAdapter<MessageT>::is_specialized::value;
|
||||
|
||||
// conditions for custom type
|
||||
if constexpr (is_ta && std::is_same_v<T, ConstRefCallback>) {
|
||||
auto local_message = convert_ros_message_to_custom_type_unique_ptr(*message);
|
||||
callback(*local_message);
|
||||
} else if constexpr (is_ta && std::is_same_v<T, ConstRefWithInfoCallback>) { // NOLINT
|
||||
auto local_message = convert_ros_message_to_custom_type_unique_ptr(*message);
|
||||
callback(*local_message, message_info);
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
is_ta && (
|
||||
std::is_same_v<T, UniquePtrCallback>||
|
||||
std::is_same_v<T, SharedPtrCallback>
|
||||
))
|
||||
{
|
||||
callback(convert_ros_message_to_custom_type_unique_ptr(*message));
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
is_ta && (
|
||||
std::is_same_v<T, UniquePtrWithInfoCallback>||
|
||||
std::is_same_v<T, SharedPtrWithInfoCallback>
|
||||
))
|
||||
{
|
||||
callback(convert_ros_message_to_custom_type_unique_ptr(*message), message_info);
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
is_ta && (
|
||||
std::is_same_v<T, SharedConstPtrCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrCallback>
|
||||
))
|
||||
{
|
||||
callback(convert_ros_message_to_custom_type_unique_ptr(*message));
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
is_ta && (
|
||||
std::is_same_v<T, SharedConstPtrWithInfoCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrWithInfoCallback>
|
||||
))
|
||||
{
|
||||
callback(convert_ros_message_to_custom_type_unique_ptr(*message), message_info);
|
||||
}
|
||||
// conditions for ros message type
|
||||
else if constexpr (std::is_same_v<T, ConstRefROSMessageCallback>) { // NOLINT
|
||||
if constexpr (std::is_same_v<T, ConstRefCallback>) {
|
||||
callback(*message);
|
||||
} else if constexpr (std::is_same_v<T, ConstRefWithInfoROSMessageCallback>) {
|
||||
} else if constexpr (std::is_same_v<T, ConstRefWithInfoCallback>) {
|
||||
callback(*message, message_info);
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, UniquePtrROSMessageCallback>||
|
||||
std::is_same_v<T, SharedPtrROSMessageCallback>)
|
||||
std::is_same_v<T, UniquePtrCallback>||
|
||||
std::is_same_v<T, SharedPtrCallback>)
|
||||
{
|
||||
callback(create_unique_ptr_from_shared_ptr_message(message));
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, UniquePtrWithInfoCallback>||
|
||||
std::is_same_v<T, SharedPtrWithInfoCallback>)
|
||||
{
|
||||
callback(create_unique_ptr_from_shared_ptr_message(message), message_info);
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, SharedConstPtrCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrCallback>)
|
||||
{
|
||||
callback(message);
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, SharedConstPtrWithInfoCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrWithInfoCallback>)
|
||||
{
|
||||
callback(message, message_info);
|
||||
} else {
|
||||
static_assert(always_false_v<T>, "unhandled callback type");
|
||||
}
|
||||
}, callback_variant_);
|
||||
TRACEPOINT(callback_end, static_cast<const void *>(this));
|
||||
}
|
||||
|
||||
void
|
||||
dispatch_intra_process(
|
||||
std::unique_ptr<MessageT, MessageDeleter> message,
|
||||
const rclcpp::MessageInfo & message_info)
|
||||
{
|
||||
TRACEPOINT(callback_start, static_cast<const void *>(this), true);
|
||||
// Check if the variant is "unset", throw if it is.
|
||||
if (callback_variant_.index() == 0) {
|
||||
if (std::get<0>(callback_variant_) == nullptr) {
|
||||
// This can happen if it is default initialized, or if it is assigned nullptr.
|
||||
throw std::runtime_error("dispatch called on an unset AnySubscriptionCallback");
|
||||
}
|
||||
}
|
||||
// Dispatch.
|
||||
std::visit(
|
||||
[&message, &message_info](auto && callback) {
|
||||
using T = std::decay_t<decltype(callback)>;
|
||||
|
||||
if constexpr (std::is_same_v<T, ConstRefCallback>) {
|
||||
callback(*message);
|
||||
} else if constexpr (std::is_same_v<T, ConstRefWithInfoCallback>) {
|
||||
callback(*message, message_info);
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, UniquePtrCallback>||
|
||||
std::is_same_v<T, SharedConstPtrCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrCallback>||
|
||||
std::is_same_v<T, SharedPtrCallback>)
|
||||
{
|
||||
callback(std::move(message));
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, UniquePtrWithInfoROSMessageCallback>||
|
||||
std::is_same_v<T, SharedPtrWithInfoROSMessageCallback>)
|
||||
std::is_same_v<T, UniquePtrWithInfoCallback>||
|
||||
std::is_same_v<T, SharedConstPtrWithInfoCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrWithInfoCallback>||
|
||||
std::is_same_v<T, SharedPtrWithInfoCallback>)
|
||||
{
|
||||
callback(std::move(message), message_info);
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, SharedConstPtrROSMessageCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrROSMessageCallback>)
|
||||
{
|
||||
callback(std::move(message));
|
||||
} else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, SharedConstPtrWithInfoROSMessageCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrWithInfoROSMessageCallback>)
|
||||
{
|
||||
callback(std::move(message), message_info);
|
||||
}
|
||||
// condition to catch SerializedMessage types
|
||||
else if constexpr ( // NOLINT[readability/braces]
|
||||
std::is_same_v<T, ConstRefSerializedMessageCallback>||
|
||||
std::is_same_v<T, ConstRefSerializedMessageWithInfoCallback>||
|
||||
std::is_same_v<T, UniquePtrSerializedMessageCallback>||
|
||||
std::is_same_v<T, UniquePtrSerializedMessageWithInfoCallback>||
|
||||
std::is_same_v<T, SharedConstPtrSerializedMessageCallback>||
|
||||
std::is_same_v<T, SharedConstPtrSerializedMessageWithInfoCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrSerializedMessageCallback>||
|
||||
std::is_same_v<T, ConstRefSharedConstPtrSerializedMessageWithInfoCallback>||
|
||||
std::is_same_v<T, SharedPtrSerializedMessageCallback>||
|
||||
std::is_same_v<T, SharedPtrSerializedMessageWithInfoCallback>)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"Cannot dispatch std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter> message "
|
||||
"to rclcpp::SerializedMessage");
|
||||
}
|
||||
// condition to catch unhandled callback types
|
||||
else { // NOLINT[readability/braces]
|
||||
} else {
|
||||
static_assert(always_false_v<T>, "unhandled callback type");
|
||||
}
|
||||
}, callback_variant_);
|
||||
@@ -877,18 +369,6 @@ public:
|
||||
std::holds_alternative<ConstRefSharedConstPtrWithInfoCallback>(callback_variant_);
|
||||
}
|
||||
|
||||
constexpr
|
||||
bool
|
||||
is_serialized_message_callback() const
|
||||
{
|
||||
return
|
||||
std::holds_alternative<ConstRefSerializedMessageCallback>(callback_variant_) ||
|
||||
std::holds_alternative<UniquePtrSerializedMessageCallback>(callback_variant_) ||
|
||||
std::holds_alternative<SharedConstPtrSerializedMessageCallback>(callback_variant_) ||
|
||||
std::holds_alternative<ConstRefSharedConstPtrSerializedMessageCallback>(callback_variant_) ||
|
||||
std::holds_alternative<SharedPtrSerializedMessageCallback>(callback_variant_);
|
||||
}
|
||||
|
||||
void
|
||||
register_callback_for_tracing()
|
||||
{
|
||||
@@ -922,12 +402,8 @@ private:
|
||||
// For now, compose the variant into this class as a private attribute.
|
||||
typename HelperT::variant_type callback_variant_;
|
||||
|
||||
SubscribedTypeAllocator subscribed_type_allocator_;
|
||||
SubscribedTypeDeleter subscribed_type_deleter_;
|
||||
ROSMessageTypeAllocator ros_message_type_allocator_;
|
||||
ROSMessageTypeDeleter ros_message_type_deleter_;
|
||||
SerializedMessageAllocator serialized_message_allocator_;
|
||||
SerializedMessageDeleter serialized_message_deleter_;
|
||||
MessageAlloc message_allocator_;
|
||||
MessageDeleter message_deleter_;
|
||||
};
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
@@ -92,7 +92,7 @@ public:
|
||||
*
|
||||
* Note that this function does not setup any signal handlers, so if you want
|
||||
* it to be shutdown by the signal handler, then you need to either install
|
||||
* them manually with rclcpp::install_signal_handlers() or use rclcpp::init().
|
||||
* them manually with rclcpp::install_signal_handers() or use rclcpp::init().
|
||||
* In addition to installing the signal handlers, the shutdown_on_sigint
|
||||
* of the InitOptions needs to be `true` for this context to be shutdown by
|
||||
* the signal handler, otherwise it will be passed over.
|
||||
|
||||
@@ -47,11 +47,11 @@ template<
|
||||
typename MessageT,
|
||||
typename CallbackT,
|
||||
typename AllocatorT,
|
||||
typename CallbackMessageT,
|
||||
typename SubscriptionT,
|
||||
typename MessageMemoryStrategyT,
|
||||
typename NodeParametersT,
|
||||
typename NodeTopicsT,
|
||||
typename ROSMessageType = typename SubscriptionT::ROSMessageType>
|
||||
typename NodeTopicsT>
|
||||
typename std::shared_ptr<SubscriptionT>
|
||||
create_subscription(
|
||||
NodeParametersT & node_parameters,
|
||||
@@ -70,7 +70,7 @@ create_subscription(
|
||||
using rclcpp::node_interfaces::get_node_topics_interface;
|
||||
auto node_topics_interface = get_node_topics_interface(node_topics);
|
||||
|
||||
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics<ROSMessageType>>
|
||||
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics<CallbackMessageT>>
|
||||
subscription_topic_stats = nullptr;
|
||||
|
||||
if (rclcpp::detail::resolve_enable_topic_statistics(
|
||||
@@ -92,11 +92,11 @@ create_subscription(
|
||||
qos);
|
||||
|
||||
subscription_topic_stats = std::make_shared<
|
||||
rclcpp::topic_statistics::SubscriptionTopicStatistics<ROSMessageType>
|
||||
rclcpp::topic_statistics::SubscriptionTopicStatistics<CallbackMessageT>
|
||||
>(node_topics_interface->get_node_base_interface()->get_name(), publisher);
|
||||
|
||||
std::weak_ptr<
|
||||
rclcpp::topic_statistics::SubscriptionTopicStatistics<ROSMessageType>
|
||||
rclcpp::topic_statistics::SubscriptionTopicStatistics<CallbackMessageT>
|
||||
> weak_subscription_topic_stats(subscription_topic_stats);
|
||||
auto sub_call_back = [weak_subscription_topic_stats]() {
|
||||
auto subscription_topic_stats = weak_subscription_topic_stats.lock();
|
||||
@@ -153,6 +153,7 @@ create_subscription(
|
||||
* \tparam MessageT
|
||||
* \tparam CallbackT
|
||||
* \tparam AllocatorT
|
||||
* \tparam CallbackMessageT
|
||||
* \tparam SubscriptionT
|
||||
* \tparam MessageMemoryStrategyT
|
||||
* \tparam NodeT
|
||||
@@ -170,8 +171,13 @@ template<
|
||||
typename MessageT,
|
||||
typename CallbackT,
|
||||
typename AllocatorT = std::allocator<void>,
|
||||
typename SubscriptionT = rclcpp::Subscription<MessageT, AllocatorT>,
|
||||
typename MessageMemoryStrategyT = typename SubscriptionT::MessageMemoryStrategyType,
|
||||
typename CallbackMessageT =
|
||||
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type,
|
||||
typename SubscriptionT = rclcpp::Subscription<CallbackMessageT, AllocatorT>,
|
||||
typename MessageMemoryStrategyT = rclcpp::message_memory_strategy::MessageMemoryStrategy<
|
||||
CallbackMessageT,
|
||||
AllocatorT
|
||||
>,
|
||||
typename NodeT>
|
||||
typename std::shared_ptr<SubscriptionT>
|
||||
create_subscription(
|
||||
@@ -188,7 +194,7 @@ create_subscription(
|
||||
)
|
||||
{
|
||||
return rclcpp::detail::create_subscription<
|
||||
MessageT, CallbackT, AllocatorT, SubscriptionT, MessageMemoryStrategyT>(
|
||||
MessageT, CallbackT, AllocatorT, CallbackMessageT, SubscriptionT, MessageMemoryStrategyT>(
|
||||
node, node, topic_name, qos, std::forward<CallbackT>(callback), options, msg_mem_strat);
|
||||
}
|
||||
|
||||
@@ -200,8 +206,13 @@ template<
|
||||
typename MessageT,
|
||||
typename CallbackT,
|
||||
typename AllocatorT = std::allocator<void>,
|
||||
typename SubscriptionT = rclcpp::Subscription<MessageT, AllocatorT>,
|
||||
typename MessageMemoryStrategyT = typename SubscriptionT::MessageMemoryStrategyType>
|
||||
typename CallbackMessageT =
|
||||
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type,
|
||||
typename SubscriptionT = rclcpp::Subscription<CallbackMessageT, AllocatorT>,
|
||||
typename MessageMemoryStrategyT = rclcpp::message_memory_strategy::MessageMemoryStrategy<
|
||||
CallbackMessageT,
|
||||
AllocatorT
|
||||
>>
|
||||
typename std::shared_ptr<SubscriptionT>
|
||||
create_subscription(
|
||||
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr & node_parameters,
|
||||
@@ -218,7 +229,7 @@ create_subscription(
|
||||
)
|
||||
{
|
||||
return rclcpp::detail::create_subscription<
|
||||
MessageT, CallbackT, AllocatorT, SubscriptionT, MessageMemoryStrategyT>(
|
||||
MessageT, CallbackT, AllocatorT, CallbackMessageT, SubscriptionT, MessageMemoryStrategyT>(
|
||||
node_parameters, node_topics, topic_name, qos,
|
||||
std::forward<CallbackT>(callback), options, msg_mem_strat);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#include "rclcpp/experimental/buffers/intra_process_buffer.hpp"
|
||||
#include "rclcpp/experimental/buffers/ring_buffer_implementation.hpp"
|
||||
#include "rclcpp/intra_process_buffer_type.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
@@ -38,13 +37,13 @@ template<
|
||||
typename rclcpp::experimental::buffers::IntraProcessBuffer<MessageT, Alloc, Deleter>::UniquePtr
|
||||
create_intra_process_buffer(
|
||||
IntraProcessBufferType buffer_type,
|
||||
const rclcpp::QoS & qos,
|
||||
rmw_qos_profile_t qos,
|
||||
std::shared_ptr<Alloc> allocator)
|
||||
{
|
||||
using MessageSharedPtr = std::shared_ptr<const MessageT>;
|
||||
using MessageUniquePtr = std::unique_ptr<MessageT, Deleter>;
|
||||
|
||||
size_t buffer_size = qos.depth();
|
||||
size_t buffer_size = qos.depth;
|
||||
|
||||
using rclcpp::experimental::buffers::IntraProcessBuffer;
|
||||
typename IntraProcessBuffer<MessageT, Alloc, Deleter>::UniquePtr buffer;
|
||||
|
||||
@@ -33,7 +33,6 @@
|
||||
#include "rclcpp/allocator/allocator_deleter.hpp"
|
||||
#include "rclcpp/experimental/subscription_intra_process.hpp"
|
||||
#include "rclcpp/experimental/subscription_intra_process_base.hpp"
|
||||
#include "rclcpp/experimental/subscription_intra_process_buffer.hpp"
|
||||
#include "rclcpp/logger.hpp"
|
||||
#include "rclcpp/logging.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
@@ -182,7 +181,7 @@ public:
|
||||
do_intra_process_publish(
|
||||
uint64_t intra_process_publisher_id,
|
||||
std::unique_ptr<MessageT, Deleter> message,
|
||||
typename allocator::AllocRebind<MessageT, Alloc>::allocator_type & allocator)
|
||||
std::shared_ptr<typename allocator::AllocRebind<MessageT, Alloc>::allocator_type> allocator)
|
||||
{
|
||||
using MessageAllocTraits = allocator::AllocRebind<MessageT, Alloc>;
|
||||
using MessageAllocatorT = typename MessageAllocTraits::allocator_type;
|
||||
@@ -227,7 +226,7 @@ public:
|
||||
{
|
||||
// Construct a new shared pointer from the message
|
||||
// for the buffers that do not require ownership
|
||||
auto shared_msg = std::allocate_shared<MessageT, MessageAllocatorT>(allocator, *message);
|
||||
auto shared_msg = std::allocate_shared<MessageT, MessageAllocatorT>(*allocator, *message);
|
||||
|
||||
this->template add_shared_msg_to_buffers<MessageT, Alloc, Deleter>(
|
||||
shared_msg, sub_ids.take_shared_subscriptions);
|
||||
@@ -244,7 +243,7 @@ public:
|
||||
do_intra_process_publish_and_return_shared(
|
||||
uint64_t intra_process_publisher_id,
|
||||
std::unique_ptr<MessageT, Deleter> message,
|
||||
typename allocator::AllocRebind<MessageT, Alloc>::allocator_type & allocator)
|
||||
std::shared_ptr<typename allocator::AllocRebind<MessageT, Alloc>::allocator_type> allocator)
|
||||
{
|
||||
using MessageAllocTraits = allocator::AllocRebind<MessageT, Alloc>;
|
||||
using MessageAllocatorT = typename MessageAllocTraits::allocator_type;
|
||||
@@ -272,7 +271,7 @@ public:
|
||||
} else {
|
||||
// Construct a new shared pointer from the message for the buffers that
|
||||
// do not require ownership and to return.
|
||||
auto shared_msg = std::allocate_shared<MessageT, MessageAllocatorT>(allocator, *message);
|
||||
auto shared_msg = std::allocate_shared<MessageT, MessageAllocatorT>(*allocator, *message);
|
||||
|
||||
if (!sub_ids.take_shared_subscriptions.empty()) {
|
||||
this->template add_shared_msg_to_buffers<MessageT, Alloc, Deleter>(
|
||||
@@ -305,6 +304,25 @@ public:
|
||||
get_subscription_intra_process(uint64_t intra_process_subscription_id);
|
||||
|
||||
private:
|
||||
struct SubscriptionInfo
|
||||
{
|
||||
SubscriptionInfo() = default;
|
||||
|
||||
rclcpp::experimental::SubscriptionIntraProcessBase::WeakPtr subscription;
|
||||
rmw_qos_profile_t qos;
|
||||
const char * topic_name;
|
||||
bool use_take_shared_method;
|
||||
};
|
||||
|
||||
struct PublisherInfo
|
||||
{
|
||||
PublisherInfo() = default;
|
||||
|
||||
rclcpp::PublisherBase::WeakPtr publisher;
|
||||
rmw_qos_profile_t qos;
|
||||
const char * topic_name;
|
||||
};
|
||||
|
||||
struct SplittedSubscriptions
|
||||
{
|
||||
std::vector<uint64_t> take_shared_subscriptions;
|
||||
@@ -312,10 +330,10 @@ private:
|
||||
};
|
||||
|
||||
using SubscriptionMap =
|
||||
std::unordered_map<uint64_t, rclcpp::experimental::SubscriptionIntraProcessBase::WeakPtr>;
|
||||
std::unordered_map<uint64_t, SubscriptionInfo>;
|
||||
|
||||
using PublisherMap =
|
||||
std::unordered_map<uint64_t, rclcpp::PublisherBase::WeakPtr>;
|
||||
std::unordered_map<uint64_t, PublisherInfo>;
|
||||
|
||||
using PublisherToSubscriptionIdsMap =
|
||||
std::unordered_map<uint64_t, SplittedSubscriptions>;
|
||||
@@ -331,9 +349,7 @@ private:
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
can_communicate(
|
||||
rclcpp::PublisherBase::SharedPtr pub,
|
||||
rclcpp::experimental::SubscriptionIntraProcessBase::SharedPtr sub) const;
|
||||
can_communicate(PublisherInfo pub_info, SubscriptionInfo sub_info) const;
|
||||
|
||||
template<
|
||||
typename MessageT,
|
||||
@@ -349,15 +365,15 @@ private:
|
||||
if (subscription_it == subscriptions_.end()) {
|
||||
throw std::runtime_error("subscription has unexpectedly gone out of scope");
|
||||
}
|
||||
auto subscription_base = subscription_it->second.lock();
|
||||
auto subscription_base = subscription_it->second.subscription.lock();
|
||||
if (subscription_base) {
|
||||
auto subscription = std::dynamic_pointer_cast<
|
||||
rclcpp::experimental::SubscriptionIntraProcessBuffer<MessageT, Alloc, Deleter>
|
||||
rclcpp::experimental::SubscriptionIntraProcess<MessageT, Alloc, Deleter>
|
||||
>(subscription_base);
|
||||
if (nullptr == subscription) {
|
||||
throw std::runtime_error(
|
||||
"failed to dynamic cast SubscriptionIntraProcessBase to "
|
||||
"SubscriptionIntraProcessBuffer<MessageT, Alloc, Deleter>, which "
|
||||
"SubscriptionIntraProcess<MessageT, Alloc, Deleter>, which "
|
||||
"can happen when the publisher and subscription use different "
|
||||
"allocator types, which is not supported");
|
||||
}
|
||||
@@ -377,7 +393,7 @@ private:
|
||||
add_owned_msg_to_buffers(
|
||||
std::unique_ptr<MessageT, Deleter> message,
|
||||
std::vector<uint64_t> subscription_ids,
|
||||
typename allocator::AllocRebind<MessageT, Alloc>::allocator_type & allocator)
|
||||
std::shared_ptr<typename allocator::AllocRebind<MessageT, Alloc>::allocator_type> allocator)
|
||||
{
|
||||
using MessageAllocTraits = allocator::AllocRebind<MessageT, Alloc>;
|
||||
using MessageUniquePtr = std::unique_ptr<MessageT, Deleter>;
|
||||
@@ -387,15 +403,15 @@ private:
|
||||
if (subscription_it == subscriptions_.end()) {
|
||||
throw std::runtime_error("subscription has unexpectedly gone out of scope");
|
||||
}
|
||||
auto subscription_base = subscription_it->second.lock();
|
||||
auto subscription_base = subscription_it->second.subscription.lock();
|
||||
if (subscription_base) {
|
||||
auto subscription = std::dynamic_pointer_cast<
|
||||
rclcpp::experimental::SubscriptionIntraProcessBuffer<MessageT, Alloc, Deleter>
|
||||
rclcpp::experimental::SubscriptionIntraProcess<MessageT, Alloc, Deleter>
|
||||
>(subscription_base);
|
||||
if (nullptr == subscription) {
|
||||
throw std::runtime_error(
|
||||
"failed to dynamic cast SubscriptionIntraProcessBase to "
|
||||
"SubscriptionIntraProcessBuffer<MessageT, Alloc, Deleter>, which "
|
||||
"SubscriptionIntraProcess<MessageT, Alloc, Deleter>, which "
|
||||
"can happen when the publisher and subscription use different "
|
||||
"allocator types, which is not supported");
|
||||
}
|
||||
@@ -407,8 +423,8 @@ private:
|
||||
// Copy the message since we have additional subscriptions to serve
|
||||
MessageUniquePtr copy_message;
|
||||
Deleter deleter = message.get_deleter();
|
||||
auto ptr = MessageAllocTraits::allocate(allocator, 1);
|
||||
MessageAllocTraits::construct(allocator, ptr, *message);
|
||||
auto ptr = MessageAllocTraits::allocate(*allocator.get(), 1);
|
||||
MessageAllocTraits::construct(*allocator.get(), ptr, *message);
|
||||
copy_message = MessageUniquePtr(ptr, deleter);
|
||||
|
||||
subscription->provide_intra_process_message(std::move(copy_message));
|
||||
|
||||
@@ -30,8 +30,6 @@
|
||||
#include "rclcpp/experimental/buffers/intra_process_buffer.hpp"
|
||||
#include "rclcpp/experimental/create_intra_process_buffer.hpp"
|
||||
#include "rclcpp/experimental/subscription_intra_process_base.hpp"
|
||||
#include "rclcpp/experimental/subscription_intra_process_buffer.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
#include "rclcpp/type_support_decl.hpp"
|
||||
#include "rclcpp/waitable.hpp"
|
||||
#include "tracetools/tracetools.h"
|
||||
@@ -46,43 +44,54 @@ template<
|
||||
typename Alloc = std::allocator<void>,
|
||||
typename Deleter = std::default_delete<MessageT>,
|
||||
typename CallbackMessageT = MessageT>
|
||||
class SubscriptionIntraProcess
|
||||
: public SubscriptionIntraProcessBuffer<
|
||||
MessageT,
|
||||
Alloc,
|
||||
Deleter
|
||||
>
|
||||
class SubscriptionIntraProcess : public SubscriptionIntraProcessBase
|
||||
{
|
||||
using SubscriptionIntraProcessBufferT = SubscriptionIntraProcessBuffer<
|
||||
MessageT,
|
||||
Alloc,
|
||||
Deleter
|
||||
>;
|
||||
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(SubscriptionIntraProcess)
|
||||
|
||||
using MessageAllocTraits = typename SubscriptionIntraProcessBufferT::MessageAllocTraits;
|
||||
using MessageAlloc = typename SubscriptionIntraProcessBufferT::MessageAlloc;
|
||||
using ConstMessageSharedPtr = typename SubscriptionIntraProcessBufferT::ConstMessageSharedPtr;
|
||||
using MessageUniquePtr = typename SubscriptionIntraProcessBufferT::MessageUniquePtr;
|
||||
using BufferUniquePtr = typename SubscriptionIntraProcessBufferT::BufferUniquePtr;
|
||||
using MessageAllocTraits = allocator::AllocRebind<MessageT, Alloc>;
|
||||
using MessageAlloc = typename MessageAllocTraits::allocator_type;
|
||||
using ConstMessageSharedPtr = std::shared_ptr<const MessageT>;
|
||||
using MessageUniquePtr = std::unique_ptr<MessageT, Deleter>;
|
||||
|
||||
using BufferUniquePtr = typename rclcpp::experimental::buffers::IntraProcessBuffer<
|
||||
MessageT,
|
||||
Alloc,
|
||||
Deleter
|
||||
>::UniquePtr;
|
||||
|
||||
SubscriptionIntraProcess(
|
||||
AnySubscriptionCallback<CallbackMessageT, Alloc> callback,
|
||||
std::shared_ptr<Alloc> allocator,
|
||||
rclcpp::Context::SharedPtr context,
|
||||
const std::string & topic_name,
|
||||
const rclcpp::QoS & qos_profile,
|
||||
rmw_qos_profile_t qos_profile,
|
||||
rclcpp::IntraProcessBufferType buffer_type)
|
||||
: SubscriptionIntraProcessBuffer<MessageT, Alloc, Deleter>(
|
||||
allocator,
|
||||
context,
|
||||
topic_name,
|
||||
qos_profile,
|
||||
buffer_type),
|
||||
: SubscriptionIntraProcessBase(topic_name, qos_profile),
|
||||
any_callback_(callback)
|
||||
{
|
||||
if (!std::is_same<MessageT, CallbackMessageT>::value) {
|
||||
throw std::runtime_error("SubscriptionIntraProcess wrong callback type");
|
||||
}
|
||||
|
||||
// Create the intra-process buffer.
|
||||
buffer_ = rclcpp::experimental::create_intra_process_buffer<MessageT, Alloc, Deleter>(
|
||||
buffer_type,
|
||||
qos_profile,
|
||||
allocator);
|
||||
|
||||
// Create the guard condition.
|
||||
rcl_guard_condition_options_t guard_condition_options =
|
||||
rcl_guard_condition_get_default_options();
|
||||
|
||||
gc_ = rcl_get_zero_initialized_guard_condition();
|
||||
rcl_ret_t ret = rcl_guard_condition_init(
|
||||
&gc_, context->get_rcl_context().get(), guard_condition_options);
|
||||
|
||||
if (RCL_RET_OK != ret) {
|
||||
throw std::runtime_error("SubscriptionIntraProcess init error initializing guard condition");
|
||||
}
|
||||
|
||||
TRACEPOINT(
|
||||
rclcpp_subscription_callback_added,
|
||||
static_cast<const void *>(this),
|
||||
@@ -95,7 +104,22 @@ public:
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual ~SubscriptionIntraProcess() = default;
|
||||
~SubscriptionIntraProcess()
|
||||
{
|
||||
if (rcl_guard_condition_fini(&gc_) != RCL_RET_OK) {
|
||||
RCUTILS_LOG_ERROR_NAMED(
|
||||
"rclcpp",
|
||||
"Failed to destroy guard condition: %s",
|
||||
rcutils_get_error_string().str);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
is_ready(rcl_wait_set_t * wait_set)
|
||||
{
|
||||
(void) wait_set;
|
||||
return buffer_->has_data();
|
||||
}
|
||||
|
||||
std::shared_ptr<void>
|
||||
take_data()
|
||||
@@ -104,9 +128,9 @@ public:
|
||||
MessageUniquePtr unique_msg;
|
||||
|
||||
if (any_callback_.use_take_shared_method()) {
|
||||
shared_msg = this->buffer_->consume_shared();
|
||||
shared_msg = buffer_->consume_shared();
|
||||
} else {
|
||||
unique_msg = this->buffer_->consume_unique();
|
||||
unique_msg = buffer_->consume_unique();
|
||||
}
|
||||
return std::static_pointer_cast<void>(
|
||||
std::make_shared<std::pair<ConstMessageSharedPtr, MessageUniquePtr>>(
|
||||
@@ -117,10 +141,37 @@ public:
|
||||
|
||||
void execute(std::shared_ptr<void> & data)
|
||||
{
|
||||
execute_impl<MessageT>(data);
|
||||
execute_impl<CallbackMessageT>(data);
|
||||
}
|
||||
|
||||
void
|
||||
provide_intra_process_message(ConstMessageSharedPtr message)
|
||||
{
|
||||
buffer_->add_shared(std::move(message));
|
||||
trigger_guard_condition();
|
||||
}
|
||||
|
||||
void
|
||||
provide_intra_process_message(MessageUniquePtr message)
|
||||
{
|
||||
buffer_->add_unique(std::move(message));
|
||||
trigger_guard_condition();
|
||||
}
|
||||
|
||||
bool
|
||||
use_take_shared_method() const
|
||||
{
|
||||
return buffer_->use_take_shared_method();
|
||||
}
|
||||
|
||||
private:
|
||||
void
|
||||
trigger_guard_condition()
|
||||
{
|
||||
rcl_ret_t ret = rcl_trigger_guard_condition(&gc_);
|
||||
(void)ret;
|
||||
}
|
||||
|
||||
protected:
|
||||
template<typename T>
|
||||
typename std::enable_if<std::is_same<T, rcl_serialized_message_t>::value, void>::type
|
||||
execute_impl(std::shared_ptr<void> & data)
|
||||
@@ -155,6 +206,7 @@ protected:
|
||||
}
|
||||
|
||||
AnySubscriptionCallback<CallbackMessageT, Alloc> any_callback_;
|
||||
BufferUniquePtr buffer_;
|
||||
};
|
||||
|
||||
} // namespace experimental
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
|
||||
#include "rcl/error_handling.h"
|
||||
|
||||
#include "rclcpp/qos.hpp"
|
||||
#include "rclcpp/type_support_decl.hpp"
|
||||
#include "rclcpp/waitable.hpp"
|
||||
|
||||
@@ -40,9 +39,7 @@ public:
|
||||
RCLCPP_SMART_PTR_ALIASES_ONLY(SubscriptionIntraProcessBase)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
SubscriptionIntraProcessBase(
|
||||
const std::string & topic_name,
|
||||
const rclcpp::QoS & qos_profile)
|
||||
SubscriptionIntraProcessBase(const std::string & topic_name, rmw_qos_profile_t qos_profile)
|
||||
: topic_name_(topic_name), qos_profile_(qos_profile)
|
||||
{}
|
||||
|
||||
@@ -74,7 +71,7 @@ public:
|
||||
get_topic_name() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
QoS
|
||||
rmw_qos_profile_t
|
||||
get_actual_qos() const;
|
||||
|
||||
protected:
|
||||
@@ -86,7 +83,7 @@ private:
|
||||
trigger_guard_condition() = 0;
|
||||
|
||||
std::string topic_name_;
|
||||
QoS qos_profile_;
|
||||
rmw_qos_profile_t qos_profile_;
|
||||
};
|
||||
|
||||
} // namespace experimental
|
||||
|
||||
@@ -1,143 +0,0 @@
|
||||
// Copyright 2021 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_BUFFER_HPP_
|
||||
#define RCLCPP__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_BUFFER_HPP_
|
||||
|
||||
#include <rmw/rmw.h>
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "rcl/error_handling.h"
|
||||
|
||||
#include "rclcpp/any_subscription_callback.hpp"
|
||||
#include "rclcpp/experimental/buffers/intra_process_buffer.hpp"
|
||||
#include "rclcpp/experimental/create_intra_process_buffer.hpp"
|
||||
#include "rclcpp/experimental/subscription_intra_process_base.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
#include "rclcpp/type_support_decl.hpp"
|
||||
#include "rclcpp/waitable.hpp"
|
||||
#include "tracetools/tracetools.h"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
|
||||
template<
|
||||
typename MessageT,
|
||||
typename Alloc = std::allocator<void>,
|
||||
typename Deleter = std::default_delete<MessageT>
|
||||
>
|
||||
class SubscriptionIntraProcessBuffer : public SubscriptionIntraProcessBase
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(SubscriptionIntraProcessBuffer)
|
||||
|
||||
using MessageAllocTraits = allocator::AllocRebind<MessageT, Alloc>;
|
||||
using MessageAlloc = typename MessageAllocTraits::allocator_type;
|
||||
using ConstMessageSharedPtr = std::shared_ptr<const MessageT>;
|
||||
using MessageUniquePtr = std::unique_ptr<MessageT, Deleter>;
|
||||
|
||||
using BufferUniquePtr = typename rclcpp::experimental::buffers::IntraProcessBuffer<
|
||||
MessageT,
|
||||
Alloc,
|
||||
Deleter
|
||||
>::UniquePtr;
|
||||
|
||||
SubscriptionIntraProcessBuffer(
|
||||
std::shared_ptr<Alloc> allocator,
|
||||
rclcpp::Context::SharedPtr context,
|
||||
const std::string & topic_name,
|
||||
const rclcpp::QoS & qos_profile,
|
||||
rclcpp::IntraProcessBufferType buffer_type)
|
||||
: SubscriptionIntraProcessBase(topic_name, qos_profile)
|
||||
{
|
||||
// Create the intra-process buffer.
|
||||
buffer_ = rclcpp::experimental::create_intra_process_buffer<MessageT, Alloc, Deleter>(
|
||||
buffer_type,
|
||||
qos_profile,
|
||||
allocator);
|
||||
|
||||
// Create the guard condition.
|
||||
rcl_guard_condition_options_t guard_condition_options =
|
||||
rcl_guard_condition_get_default_options();
|
||||
|
||||
gc_ = rcl_get_zero_initialized_guard_condition();
|
||||
rcl_ret_t ret = rcl_guard_condition_init(
|
||||
&gc_, context->get_rcl_context().get(), guard_condition_options);
|
||||
|
||||
if (RCL_RET_OK != ret) {
|
||||
throw std::runtime_error(
|
||||
"SubscriptionIntraProcessBuffer init error initializing guard condition");
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~SubscriptionIntraProcessBuffer()
|
||||
{
|
||||
if (rcl_guard_condition_fini(&gc_) != RCL_RET_OK) {
|
||||
RCUTILS_LOG_ERROR_NAMED(
|
||||
"rclcpp",
|
||||
"Failed to destroy guard condition: %s",
|
||||
rcutils_get_error_string().str);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
is_ready(rcl_wait_set_t * wait_set)
|
||||
{
|
||||
(void) wait_set;
|
||||
return buffer_->has_data();
|
||||
}
|
||||
|
||||
void
|
||||
provide_intra_process_message(ConstMessageSharedPtr message)
|
||||
{
|
||||
buffer_->add_shared(std::move(message));
|
||||
trigger_guard_condition();
|
||||
}
|
||||
|
||||
void
|
||||
provide_intra_process_message(MessageUniquePtr message)
|
||||
{
|
||||
buffer_->add_unique(std::move(message));
|
||||
trigger_guard_condition();
|
||||
}
|
||||
|
||||
bool
|
||||
use_take_shared_method() const
|
||||
{
|
||||
return buffer_->use_take_shared_method();
|
||||
}
|
||||
|
||||
protected:
|
||||
void
|
||||
trigger_guard_condition()
|
||||
{
|
||||
rcl_ret_t ret = rcl_trigger_guard_condition(&gc_);
|
||||
(void)ret;
|
||||
}
|
||||
|
||||
BufferUniquePtr buffer_;
|
||||
};
|
||||
|
||||
} // namespace experimental
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_BUFFER_HPP_
|
||||
@@ -136,13 +136,6 @@ public:
|
||||
void handle_message(
|
||||
std::shared_ptr<void> & message, const rclcpp::MessageInfo & message_info) override;
|
||||
|
||||
/// Handle dispatching rclcpp::SerializedMessage to user callback.
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
handle_serialized_message(
|
||||
const std::shared_ptr<rclcpp::SerializedMessage> & serialized_message,
|
||||
const rclcpp::MessageInfo & message_info) override;
|
||||
|
||||
/// This function is currently not implemented.
|
||||
RCLCPP_PUBLIC
|
||||
void handle_loaned_message(
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
// Copyright 2021 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__GET_MESSAGE_TYPE_SUPPORT_HANDLE_HPP_
|
||||
#define RCLCPP__GET_MESSAGE_TYPE_SUPPORT_HANDLE_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "rosidl_runtime_cpp/traits.hpp"
|
||||
#include "rosidl_runtime_cpp/message_type_support_decl.hpp"
|
||||
#include "rosidl_typesupport_cpp/message_type_support.hpp"
|
||||
|
||||
#include "rclcpp/type_adapter.hpp"
|
||||
|
||||
/// Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
/// Specialization for when MessageT is an actual ROS message type.
|
||||
template<typename MessageT>
|
||||
constexpr
|
||||
typename std::enable_if_t<
|
||||
rosidl_generator_traits::is_message<MessageT>::value,
|
||||
const rosidl_message_type_support_t &
|
||||
>
|
||||
get_message_type_support_handle()
|
||||
{
|
||||
auto handle = rosidl_typesupport_cpp::get_message_type_support_handle<MessageT>();
|
||||
if (!handle) {
|
||||
throw std::runtime_error("Type support handle unexpectedly nullptr");
|
||||
}
|
||||
return *handle;
|
||||
}
|
||||
|
||||
/// Specialization for when MessageT is an adapted type using rclcpp::TypeAdapter.
|
||||
template<typename AdaptedType>
|
||||
constexpr
|
||||
typename std::enable_if_t<
|
||||
!rosidl_generator_traits::is_message<AdaptedType>::value &&
|
||||
rclcpp::TypeAdapter<AdaptedType>::is_specialized::value,
|
||||
const rosidl_message_type_support_t &
|
||||
>
|
||||
get_message_type_support_handle()
|
||||
{
|
||||
auto handle = rosidl_typesupport_cpp::get_message_type_support_handle<
|
||||
typename TypeAdapter<AdaptedType>::ros_message_type
|
||||
>();
|
||||
if (!handle) {
|
||||
throw std::runtime_error("Type support handle unexpectedly nullptr");
|
||||
}
|
||||
return *handle;
|
||||
}
|
||||
|
||||
/// Specialization for when MessageT is not a ROS message nor an adapted type.
|
||||
/**
|
||||
* This specialization is a pass through runtime check, which allows a better
|
||||
* static_assert to catch this issue further down the line.
|
||||
* This should never get to be called in practice, and is purely defensive.
|
||||
*/
|
||||
template<
|
||||
typename AdaptedType
|
||||
>
|
||||
constexpr
|
||||
typename std::enable_if_t<
|
||||
!rosidl_generator_traits::is_message<AdaptedType>::value &&
|
||||
!TypeAdapter<AdaptedType>::is_specialized::value,
|
||||
const rosidl_message_type_support_t &
|
||||
>
|
||||
get_message_type_support_handle()
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"this specialization of rclcpp::get_message_type_support_handle() "
|
||||
"should never be called");
|
||||
}
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__GET_MESSAGE_TYPE_SUPPORT_HANDLE_HPP_
|
||||
@@ -1,35 +0,0 @@
|
||||
// Copyright 2021 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__IS_ROS_COMPATIBLE_TYPE_HPP_
|
||||
#define RCLCPP__IS_ROS_COMPATIBLE_TYPE_HPP_
|
||||
|
||||
#include "rosidl_runtime_cpp/traits.hpp"
|
||||
|
||||
#include "rclcpp/type_adapter.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
template<typename T>
|
||||
struct is_ros_compatible_type
|
||||
{
|
||||
static constexpr bool value =
|
||||
rosidl_generator_traits::is_message<T>::value ||
|
||||
rclcpp::TypeAdapter<T>::is_specialized::value;
|
||||
};
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__IS_ROS_COMPATIBLE_TYPE_HPP_
|
||||
@@ -103,9 +103,6 @@ public:
|
||||
* \param[in] allocator Allocator instance in case middleware can not allocate messages
|
||||
* \throws anything rclcpp::exceptions::throw_from_rcl_error can throw.
|
||||
*/
|
||||
[[
|
||||
deprecated("used the LoanedMessage constructor that does not use a shared_ptr to the allocator")
|
||||
]]
|
||||
LoanedMessage(
|
||||
const rclcpp::PublisherBase * pub,
|
||||
std::shared_ptr<std::allocator<MessageT>> allocator)
|
||||
|
||||
@@ -153,6 +153,17 @@ public:
|
||||
const std::vector<rclcpp::CallbackGroup::WeakPtr> &
|
||||
get_callback_groups() const;
|
||||
|
||||
/// Iterate over the callback groups in the node, calling the given function on each valid one.
|
||||
/**
|
||||
* This method is called in a thread-safe way, and also makes sure to only call the given
|
||||
* function on those items that are still valid.
|
||||
*
|
||||
* \param[in] func The callback function to call on each valid callback group.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
for_each_callback_group(const node_interfaces::NodeBaseInterface::CallbackGroupFunction & func);
|
||||
|
||||
/// Create and return a Publisher.
|
||||
/**
|
||||
* The rclcpp::QoS has several convenient constructors, including a
|
||||
@@ -206,8 +217,13 @@ public:
|
||||
typename MessageT,
|
||||
typename CallbackT,
|
||||
typename AllocatorT = std::allocator<void>,
|
||||
typename SubscriptionT = rclcpp::Subscription<MessageT, AllocatorT>,
|
||||
typename MessageMemoryStrategyT = typename SubscriptionT::MessageMemoryStrategyType
|
||||
typename CallbackMessageT =
|
||||
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type,
|
||||
typename SubscriptionT = rclcpp::Subscription<CallbackMessageT, AllocatorT>,
|
||||
typename MessageMemoryStrategyT = rclcpp::message_memory_strategy::MessageMemoryStrategy<
|
||||
CallbackMessageT,
|
||||
AllocatorT
|
||||
>
|
||||
>
|
||||
std::shared_ptr<SubscriptionT>
|
||||
create_subscription(
|
||||
|
||||
@@ -86,6 +86,7 @@ template<
|
||||
typename MessageT,
|
||||
typename CallbackT,
|
||||
typename AllocatorT,
|
||||
typename CallbackMessageT,
|
||||
typename SubscriptionT,
|
||||
typename MessageMemoryStrategyT>
|
||||
std::shared_ptr<SubscriptionT>
|
||||
|
||||
@@ -16,10 +16,13 @@
|
||||
#define RCLCPP__NODE_INTERFACES__NODE_BASE_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "rcl/node.h"
|
||||
#include "rclcpp/callback_group.hpp"
|
||||
#include "rclcpp/context.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
@@ -30,12 +33,34 @@ namespace rclcpp
|
||||
namespace node_interfaces
|
||||
{
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void global_for_each_callback_group(
|
||||
NodeBaseInterface * node_base_interface,
|
||||
const NodeBaseInterface::CallbackGroupFunction & func);
|
||||
|
||||
// Class to hold the global map of mutexes
|
||||
class map_of_mutexes final
|
||||
{
|
||||
public:
|
||||
// Methods need to be protected by internal mutex
|
||||
void create_mutex_of_nodebase(const NodeBaseInterface * nodebase);
|
||||
std::shared_ptr<std::mutex>
|
||||
get_mutex_of_nodebase(const NodeBaseInterface * nodebase);
|
||||
void delete_mutex_of_nodebase(const NodeBaseInterface * nodebase);
|
||||
|
||||
private:
|
||||
std::unordered_map<const NodeBaseInterface *, std::shared_ptr<std::mutex>> data_;
|
||||
std::mutex internal_mutex_;
|
||||
};
|
||||
|
||||
/// Implementation of the NodeBase part of the Node API.
|
||||
class NodeBase : public NodeBaseInterface
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeBase)
|
||||
|
||||
static map_of_mutexes map_object;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
NodeBase(
|
||||
const std::string & node_name,
|
||||
|
||||
@@ -38,6 +38,8 @@ class NodeBaseInterface
|
||||
public:
|
||||
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeBaseInterface)
|
||||
|
||||
using CallbackGroupFunction = std::function<void (rclcpp::CallbackGroup::SharedPtr)>;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
~NodeBaseInterface() = default;
|
||||
|
||||
@@ -41,6 +41,16 @@ RCLCPP_PUBLIC
|
||||
ParameterMap
|
||||
parameter_map_from(const rcl_params_t * const c_params);
|
||||
|
||||
/// Convert parameters from rcl_yaml_param_parser into C++ class instances.
|
||||
/// \param[in] c_params C structures containing parameters for multiple nodes.
|
||||
/// \param[in] node_fqn a Fully Qualified Name of node, default value is nullptr.
|
||||
/// If it's not nullptr, return the relative node parameters belonging to this node_fqn.
|
||||
/// \returns a map where the keys are fully qualified node names and values a list of parameters.
|
||||
/// \throws InvalidParametersException if the `rcl_params_t` is inconsistent or invalid.
|
||||
RCLCPP_PUBLIC
|
||||
ParameterMap
|
||||
parameter_map_from(const rcl_params_t * const c_params, const char * node_fqn);
|
||||
|
||||
/// Convert parameter value from rcl_yaml_param_parser into a C++ class instance.
|
||||
/// \param[in] c_value C structure containing a value of a parameter.
|
||||
/// \returns an instance of a parameter value
|
||||
|
||||
@@ -301,16 +301,6 @@ public:
|
||||
return get<ParameterType::PARAMETER_BOOL_ARRAY>();
|
||||
}
|
||||
|
||||
template<typename type>
|
||||
constexpr
|
||||
typename std::enable_if<
|
||||
std::is_convertible<
|
||||
type, const std::vector<int> &>::value, const std::vector<int64_t> &>::type
|
||||
get() const
|
||||
{
|
||||
return get<ParameterType::PARAMETER_INTEGER_ARRAY>();
|
||||
}
|
||||
|
||||
template<typename type>
|
||||
constexpr
|
||||
typename std::enable_if<
|
||||
@@ -321,16 +311,6 @@ public:
|
||||
return get<ParameterType::PARAMETER_INTEGER_ARRAY>();
|
||||
}
|
||||
|
||||
template<typename type>
|
||||
constexpr
|
||||
typename std::enable_if<
|
||||
std::is_convertible<
|
||||
type, const std::vector<float> &>::value, const std::vector<double> &>::type
|
||||
get() const
|
||||
{
|
||||
return get<ParameterType::PARAMETER_DOUBLE_ARRAY>();
|
||||
}
|
||||
|
||||
template<typename type>
|
||||
constexpr
|
||||
typename std::enable_if<
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
#ifndef RCLCPP__PUBLISHER_HPP_
|
||||
#define RCLCPP__PUBLISHER_HPP_
|
||||
|
||||
#include <rmw/error_handling.h>
|
||||
#include <rmw/rmw.h>
|
||||
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
@@ -24,21 +27,16 @@
|
||||
|
||||
#include "rcl/error_handling.h"
|
||||
#include "rcl/publisher.h"
|
||||
#include "rmw/error_handling.h"
|
||||
#include "rmw/rmw.h"
|
||||
|
||||
#include "rclcpp/allocator/allocator_common.hpp"
|
||||
#include "rclcpp/allocator/allocator_deleter.hpp"
|
||||
#include "rclcpp/detail/resolve_use_intra_process.hpp"
|
||||
#include "rclcpp/experimental/intra_process_manager.hpp"
|
||||
#include "rclcpp/get_message_type_support_handle.hpp"
|
||||
#include "rclcpp/is_ros_compatible_type.hpp"
|
||||
#include "rclcpp/loaned_message.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/publisher_base.hpp"
|
||||
#include "rclcpp/publisher_options.hpp"
|
||||
#include "rclcpp/type_adapter.hpp"
|
||||
#include "rclcpp/type_support_decl.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
@@ -51,62 +49,15 @@ template<typename MessageT, typename AllocatorT>
|
||||
class LoanedMessage;
|
||||
|
||||
/// A publisher publishes messages of any type to a topic.
|
||||
/**
|
||||
* MessageT must be a:
|
||||
*
|
||||
* - ROS message type with its own type support (e.g. std_msgs::msgs::String), or a
|
||||
* - rclcpp::TypeAdapter<CustomType, ROSMessageType>
|
||||
* (e.g. rclcpp::TypeAdapter<std::string, std_msgs::msg::String), or a
|
||||
* - custom type that has been setup as the implicit type for a ROS type using
|
||||
* RCLCPP_USING_CUSTOM_TYPE_AS_ROS_MESSAGE_TYPE(custom_type, ros_message_type)
|
||||
*
|
||||
* In the case that MessageT is ROS message type (e.g. std_msgs::msg::String),
|
||||
* both PublishedType and ROSMessageType will be that type.
|
||||
* In the case that MessageT is a TypeAdapter<CustomType, ROSMessageType> type
|
||||
* (e.g. TypeAdapter<std::string, std_msgs::msg::String>), PublishedType will
|
||||
* be the custom type, and ROSMessageType will be the ros message type.
|
||||
*
|
||||
* This is achieved because of the "identity specialization" for TypeAdapter,
|
||||
* which returns itself if it is already a TypeAdapter, and the default
|
||||
* specialization which allows ROSMessageType to be void.
|
||||
* \sa rclcpp::TypeAdapter for more details.
|
||||
*/
|
||||
template<typename MessageT, typename AllocatorT = std::allocator<void>>
|
||||
class Publisher : public PublisherBase
|
||||
{
|
||||
public:
|
||||
static_assert(
|
||||
rclcpp::is_ros_compatible_type<MessageT>::value,
|
||||
"given message type is not compatible with ROS and cannot be used with a Publisher");
|
||||
|
||||
/// MessageT::custom_type if MessageT is a TypeAdapter, otherwise just MessageT.
|
||||
using PublishedType = typename rclcpp::TypeAdapter<MessageT>::custom_type;
|
||||
/// MessageT::ros_message_type if MessageT is a TypeAdapter, otherwise just MessageT.
|
||||
using ROSMessageType = typename rclcpp::TypeAdapter<MessageT>::ros_message_type;
|
||||
|
||||
using PublishedTypeAllocatorTraits = allocator::AllocRebind<PublishedType, AllocatorT>;
|
||||
using PublishedTypeAllocator = typename PublishedTypeAllocatorTraits::allocator_type;
|
||||
using PublishedTypeDeleter = allocator::Deleter<PublishedTypeAllocator, PublishedType>;
|
||||
|
||||
using ROSMessageTypeAllocatorTraits = allocator::AllocRebind<ROSMessageType, AllocatorT>;
|
||||
using ROSMessageTypeAllocator = typename ROSMessageTypeAllocatorTraits::allocator_type;
|
||||
using ROSMessageTypeDeleter = allocator::Deleter<ROSMessageTypeAllocator, ROSMessageType>;
|
||||
|
||||
using MessageAllocatorTraits
|
||||
[[deprecated("use PublishedTypeAllocatorTraits")]] =
|
||||
PublishedTypeAllocatorTraits;
|
||||
using MessageAllocator
|
||||
[[deprecated("use PublishedTypeAllocator")]] =
|
||||
PublishedTypeAllocator;
|
||||
using MessageDeleter
|
||||
[[deprecated("use PublishedTypeDeleter")]] =
|
||||
PublishedTypeDeleter;
|
||||
using MessageUniquePtr
|
||||
[[deprecated("use std::unique_ptr<PublishedType, PublishedTypeDeleter>")]] =
|
||||
std::unique_ptr<PublishedType, PublishedTypeDeleter>;
|
||||
using MessageSharedPtr
|
||||
[[deprecated("use std::shared_ptr<const PublishedType>")]] =
|
||||
std::shared_ptr<const PublishedType>;
|
||||
using MessageAllocatorTraits = allocator::AllocRebind<MessageT, AllocatorT>;
|
||||
using MessageAllocator = typename MessageAllocatorTraits::allocator_type;
|
||||
using MessageDeleter = allocator::Deleter<MessageAllocator, MessageT>;
|
||||
using MessageUniquePtr = std::unique_ptr<MessageT, MessageDeleter>;
|
||||
using MessageSharedPtr = std::shared_ptr<const MessageT>;
|
||||
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(Publisher<MessageT, AllocatorT>)
|
||||
|
||||
@@ -129,14 +80,12 @@ public:
|
||||
: PublisherBase(
|
||||
node_base,
|
||||
topic,
|
||||
rclcpp::get_message_type_support_handle<MessageT>(),
|
||||
*rosidl_typesupport_cpp::get_message_type_support_handle<MessageT>(),
|
||||
options.template to_rcl_publisher_options<MessageT>(qos)),
|
||||
options_(options),
|
||||
published_type_allocator_(*options.get_allocator()),
|
||||
ros_message_type_allocator_(*options.get_allocator())
|
||||
message_allocator_(new MessageAllocator(*options.get_allocator().get()))
|
||||
{
|
||||
allocator::set_allocator_for_deleter(&published_type_deleter_, &published_type_allocator_);
|
||||
allocator::set_allocator_for_deleter(&ros_message_type_deleter_, &ros_message_type_allocator_);
|
||||
allocator::set_allocator_for_deleter(&message_deleter_, message_allocator_.get());
|
||||
|
||||
if (options_.event_callbacks.deadline_callback) {
|
||||
this->add_event_handler(
|
||||
@@ -186,15 +135,15 @@ public:
|
||||
// Get the intra process manager instance for this context.
|
||||
auto ipm = context->get_sub_context<rclcpp::experimental::IntraProcessManager>();
|
||||
// Register the publisher with the intra process manager.
|
||||
if (qos.history() != rclcpp::HistoryPolicy::KeepLast) {
|
||||
if (qos.get_rmw_qos_profile().history == RMW_QOS_POLICY_HISTORY_KEEP_ALL) {
|
||||
throw std::invalid_argument(
|
||||
"intraprocess communication allowed only with keep last history qos policy");
|
||||
"intraprocess communication is not allowed with keep all history qos policy");
|
||||
}
|
||||
if (qos.depth() == 0) {
|
||||
if (qos.get_rmw_qos_profile().depth == 0) {
|
||||
throw std::invalid_argument(
|
||||
"intraprocess communication is not allowed with a zero qos history depth value");
|
||||
}
|
||||
if (qos.durability() != rclcpp::DurabilityPolicy::Volatile) {
|
||||
if (qos.get_rmw_qos_profile().durability != RMW_QOS_POLICY_DURABILITY_VOLATILE) {
|
||||
throw std::invalid_argument(
|
||||
"intraprocess communication allowed only with volatile durability");
|
||||
}
|
||||
@@ -221,33 +170,21 @@ public:
|
||||
* allocator.
|
||||
* \sa rclcpp::LoanedMessage for details of the LoanedMessage class.
|
||||
*
|
||||
* \return LoanedMessage containing memory for a ROS message of type ROSMessageType
|
||||
* \return LoanedMessage containing memory for a ROS message of type MessageT
|
||||
*/
|
||||
rclcpp::LoanedMessage<ROSMessageType, AllocatorT>
|
||||
rclcpp::LoanedMessage<MessageT, AllocatorT>
|
||||
borrow_loaned_message()
|
||||
{
|
||||
return rclcpp::LoanedMessage<ROSMessageType, AllocatorT>(
|
||||
*this,
|
||||
this->get_ros_message_type_allocator());
|
||||
return rclcpp::LoanedMessage<MessageT, AllocatorT>(this, this->get_allocator());
|
||||
}
|
||||
|
||||
/// Publish a message on the topic.
|
||||
/// Send a message to the topic for this publisher.
|
||||
/**
|
||||
* This signature is enabled if the element_type of the std::unique_ptr is
|
||||
* a ROS message type, as opposed to the custom_type of a TypeAdapter, and
|
||||
* that type matches the type given when creating the publisher.
|
||||
*
|
||||
* This signature allows the user to give ownership of the message to rclcpp,
|
||||
* allowing for more efficient intra-process communication optimizations.
|
||||
*
|
||||
* \param[in] msg A unique pointer to the message to send.
|
||||
* This function is templated on the input message type, MessageT.
|
||||
* \param[in] msg A shared pointer to the message to send.
|
||||
*/
|
||||
template<typename T>
|
||||
typename std::enable_if_t<
|
||||
rosidl_generator_traits::is_message<T>::value &&
|
||||
std::is_same<T, ROSMessageType>::value
|
||||
>
|
||||
publish(std::unique_ptr<T, ROSMessageTypeDeleter> msg)
|
||||
virtual void
|
||||
publish(std::unique_ptr<MessageT, MessageDeleter> msg)
|
||||
{
|
||||
if (!intra_process_is_enabled_) {
|
||||
this->do_inter_process_publish(*msg);
|
||||
@@ -270,24 +207,8 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/// Publish a message on the topic.
|
||||
/**
|
||||
* This signature is enabled if the object being published is
|
||||
* a ROS message type, as opposed to the custom_type of a TypeAdapter, and
|
||||
* that type matches the type given when creating the publisher.
|
||||
*
|
||||
* This signature allows the user to give a reference to a message, which is
|
||||
* copied onto the heap without modification so that a copy can be owned by
|
||||
* rclcpp and ownership of the copy can be moved later if needed.
|
||||
*
|
||||
* \param[in] msg A const reference to the message to send.
|
||||
*/
|
||||
template<typename T>
|
||||
typename std::enable_if_t<
|
||||
rosidl_generator_traits::is_message<T>::value &&
|
||||
std::is_same<T, ROSMessageType>::value
|
||||
>
|
||||
publish(const T & msg)
|
||||
virtual void
|
||||
publish(const MessageT & msg)
|
||||
{
|
||||
// Avoid allocating when not using intra process.
|
||||
if (!intra_process_is_enabled_) {
|
||||
@@ -297,77 +218,12 @@ public:
|
||||
// Otherwise we have to allocate memory in a unique_ptr and pass it along.
|
||||
// As the message is not const, a copy should be made.
|
||||
// A shared_ptr<const MessageT> could also be constructed here.
|
||||
auto unique_msg = this->duplicate_ros_message_as_unique_ptr(msg);
|
||||
auto ptr = MessageAllocatorTraits::allocate(*message_allocator_.get(), 1);
|
||||
MessageAllocatorTraits::construct(*message_allocator_.get(), ptr, msg);
|
||||
MessageUniquePtr unique_msg(ptr, message_deleter_);
|
||||
this->publish(std::move(unique_msg));
|
||||
}
|
||||
|
||||
/// Publish a message on the topic.
|
||||
/**
|
||||
* This signature is enabled if this class was created with a TypeAdapter and
|
||||
* the element_type of the std::unique_ptr matches the custom_type for the
|
||||
* TypeAdapter used with this class.
|
||||
*
|
||||
* This signature allows the user to give ownership of the message to rclcpp,
|
||||
* allowing for more efficient intra-process communication optimizations.
|
||||
*
|
||||
* \param[in] msg A unique pointer to the message to send.
|
||||
*/
|
||||
template<typename T>
|
||||
typename std::enable_if_t<
|
||||
rclcpp::TypeAdapter<MessageT>::is_specialized::value &&
|
||||
std::is_same<T, PublishedType>::value
|
||||
>
|
||||
publish(std::unique_ptr<T, PublishedTypeDeleter> msg)
|
||||
{
|
||||
// TODO(wjwwood): later update this to give the unique_ptr to the intra
|
||||
// process manager and let it decide if it needs to be converted or not.
|
||||
// For now, convert it unconditionally and pass it the ROSMessageType
|
||||
// publish function specialization.
|
||||
auto unique_ros_msg = this->create_ros_message_unique_ptr();
|
||||
rclcpp::TypeAdapter<MessageT>::convert_to_ros_message(*msg, *unique_ros_msg);
|
||||
this->publish(std::move(unique_ros_msg));
|
||||
}
|
||||
|
||||
/// Publish a message on the topic.
|
||||
/**
|
||||
* This signature is enabled if this class was created with a TypeAdapter and
|
||||
* the given type matches the custom_type of the TypeAdapter.
|
||||
*
|
||||
* This signature allows the user to give a reference to a message, which is
|
||||
* copied onto the heap without modification so that a copy can be owned by
|
||||
* rclcpp and ownership of the copy can be moved later if needed.
|
||||
*
|
||||
* \param[in] msg A const reference to the message to send.
|
||||
*/
|
||||
template<typename T>
|
||||
typename std::enable_if_t<
|
||||
rclcpp::TypeAdapter<MessageT>::is_specialized::value &&
|
||||
std::is_same<T, PublishedType>::value
|
||||
>
|
||||
publish(const T & msg)
|
||||
{
|
||||
// TODO(wjwwood): later update this to give the unique_ptr to the intra
|
||||
// process manager and let it decide if it needs to be converted or not.
|
||||
// For now, convert it unconditionally and pass it the ROSMessageType
|
||||
// publish function specialization.
|
||||
|
||||
// Avoid allocating when not using intra process.
|
||||
if (!intra_process_is_enabled_) {
|
||||
// Convert to the ROS message equivalent and publish it.
|
||||
ROSMessageType ros_msg;
|
||||
rclcpp::TypeAdapter<MessageT>::convert_to_ros_message(msg, ros_msg);
|
||||
// In this case we're not using intra process.
|
||||
return this->do_inter_process_publish(ros_msg);
|
||||
}
|
||||
// Otherwise we have to allocate memory in a unique_ptr, convert it,
|
||||
// and pass it along.
|
||||
// As the message is not const, a copy should be made.
|
||||
// A shared_ptr<const MessageT> could also be constructed here.
|
||||
auto unique_ros_msg = this->create_ros_message_unique_ptr();
|
||||
rclcpp::TypeAdapter<MessageT>::convert_to_ros_message(msg, *unique_ros_msg);
|
||||
this->publish(std::move(unique_ros_msg));
|
||||
}
|
||||
|
||||
void
|
||||
publish(const rcl_serialized_message_t & serialized_msg)
|
||||
{
|
||||
@@ -389,7 +245,7 @@ public:
|
||||
* \param loaned_msg The LoanedMessage instance to be published.
|
||||
*/
|
||||
void
|
||||
publish(rclcpp::LoanedMessage<ROSMessageType, AllocatorT> && loaned_msg)
|
||||
publish(rclcpp::LoanedMessage<MessageT, AllocatorT> && loaned_msg)
|
||||
{
|
||||
if (!loaned_msg.is_valid()) {
|
||||
throw std::runtime_error("loaned message is not valid");
|
||||
@@ -415,28 +271,15 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
[[deprecated("use get_published_type_allocator() or get_ros_message_type_allocator() instead")]]
|
||||
std::shared_ptr<PublishedTypeAllocator>
|
||||
std::shared_ptr<MessageAllocator>
|
||||
get_allocator() const
|
||||
{
|
||||
return std::make_shared<PublishedTypeAllocator>(published_type_allocator_);
|
||||
}
|
||||
|
||||
PublishedTypeAllocator
|
||||
get_published_type_allocator() const
|
||||
{
|
||||
return published_type_allocator_;
|
||||
}
|
||||
|
||||
ROSMessageTypeAllocator
|
||||
get_ros_message_type_allocator() const
|
||||
{
|
||||
return ros_message_type_allocator_;
|
||||
return message_allocator_;
|
||||
}
|
||||
|
||||
protected:
|
||||
void
|
||||
do_inter_process_publish(const ROSMessageType & msg)
|
||||
do_inter_process_publish(const MessageT & msg)
|
||||
{
|
||||
TRACEPOINT(
|
||||
rclcpp_publish,
|
||||
@@ -473,8 +316,7 @@ protected:
|
||||
}
|
||||
|
||||
void
|
||||
do_loaned_message_publish(
|
||||
std::unique_ptr<ROSMessageType, std::function<void(ROSMessageType *)>> msg)
|
||||
do_loaned_message_publish(std::unique_ptr<MessageT, std::function<void(MessageT *)>> msg)
|
||||
{
|
||||
auto status = rcl_publish_loaned_message(publisher_handle_.get(), msg.get(), nullptr);
|
||||
|
||||
@@ -494,7 +336,7 @@ protected:
|
||||
}
|
||||
|
||||
void
|
||||
do_intra_process_publish(std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter> msg)
|
||||
do_intra_process_publish(std::unique_ptr<MessageT, MessageDeleter> msg)
|
||||
{
|
||||
auto ipm = weak_ipm_.lock();
|
||||
if (!ipm) {
|
||||
@@ -505,15 +347,14 @@ protected:
|
||||
throw std::runtime_error("cannot publish msg which is a null pointer");
|
||||
}
|
||||
|
||||
ipm->template do_intra_process_publish<ROSMessageType, AllocatorT>(
|
||||
ipm->template do_intra_process_publish<MessageT, AllocatorT>(
|
||||
intra_process_publisher_id_,
|
||||
std::move(msg),
|
||||
ros_message_type_allocator_);
|
||||
message_allocator_);
|
||||
}
|
||||
|
||||
std::shared_ptr<const ROSMessageType>
|
||||
do_intra_process_publish_and_return_shared(
|
||||
std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter> msg)
|
||||
std::shared_ptr<const MessageT>
|
||||
do_intra_process_publish_and_return_shared(std::unique_ptr<MessageT, MessageDeleter> msg)
|
||||
{
|
||||
auto ipm = weak_ipm_.lock();
|
||||
if (!ipm) {
|
||||
@@ -524,29 +365,10 @@ protected:
|
||||
throw std::runtime_error("cannot publish msg which is a null pointer");
|
||||
}
|
||||
|
||||
return ipm->template do_intra_process_publish_and_return_shared<ROSMessageType,
|
||||
AllocatorT>(
|
||||
return ipm->template do_intra_process_publish_and_return_shared<MessageT, AllocatorT>(
|
||||
intra_process_publisher_id_,
|
||||
std::move(msg),
|
||||
ros_message_type_allocator_);
|
||||
}
|
||||
|
||||
/// Return a new unique_ptr using the ROSMessageType of the publisher.
|
||||
std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>
|
||||
create_ros_message_unique_ptr()
|
||||
{
|
||||
auto ptr = ROSMessageTypeAllocatorTraits::allocate(ros_message_type_allocator_, 1);
|
||||
ROSMessageTypeAllocatorTraits::construct(ros_message_type_allocator_, ptr);
|
||||
return std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>(ptr, ros_message_type_deleter_);
|
||||
}
|
||||
|
||||
/// Duplicate a given ros message as a unique_ptr.
|
||||
std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>
|
||||
duplicate_ros_message_as_unique_ptr(const ROSMessageType & msg)
|
||||
{
|
||||
auto ptr = ROSMessageTypeAllocatorTraits::allocate(ros_message_type_allocator_, 1);
|
||||
ROSMessageTypeAllocatorTraits::construct(ros_message_type_allocator_, ptr, msg);
|
||||
return std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>(ptr, ros_message_type_deleter_);
|
||||
message_allocator_);
|
||||
}
|
||||
|
||||
/// Copy of original options passed during construction.
|
||||
@@ -556,10 +378,9 @@ protected:
|
||||
*/
|
||||
const rclcpp::PublisherOptionsWithAllocator<AllocatorT> options_;
|
||||
|
||||
PublishedTypeAllocator published_type_allocator_;
|
||||
PublishedTypeDeleter published_type_deleter_;
|
||||
ROSMessageTypeAllocator ros_message_type_allocator_;
|
||||
ROSMessageTypeDeleter ros_message_type_deleter_;
|
||||
std::shared_ptr<MessageAllocator> message_allocator_;
|
||||
|
||||
MessageDeleter message_deleter_;
|
||||
};
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "rcl/publisher.h"
|
||||
@@ -65,10 +64,6 @@ struct PublisherOptionsBase
|
||||
template<typename Allocator>
|
||||
struct PublisherOptionsWithAllocator : public PublisherOptionsBase
|
||||
{
|
||||
static_assert(
|
||||
std::is_void_v<typename std::allocator_traits<Allocator>::value_type>,
|
||||
"Publisher allocator value type must be void");
|
||||
|
||||
/// Optional custom allocator.
|
||||
std::shared_ptr<Allocator> allocator = nullptr;
|
||||
|
||||
@@ -85,7 +80,10 @@ struct PublisherOptionsWithAllocator : public PublisherOptionsBase
|
||||
to_rcl_publisher_options(const rclcpp::QoS & qos) const
|
||||
{
|
||||
rcl_publisher_options_t result = rcl_publisher_get_default_options();
|
||||
result.allocator = this->get_rcl_allocator();
|
||||
using AllocatorTraits = std::allocator_traits<Allocator>;
|
||||
using MessageAllocatorT = typename AllocatorTraits::template rebind_alloc<MessageT>;
|
||||
auto message_alloc = std::make_shared<MessageAllocatorT>(*this->get_allocator().get());
|
||||
result.allocator = rclcpp::allocator::get_rcl_allocator<MessageT>(*message_alloc);
|
||||
result.qos = qos.get_rmw_qos_profile();
|
||||
result.rmw_publisher_options.require_unique_network_flow_endpoints =
|
||||
this->require_unique_network_flow_endpoints;
|
||||
@@ -104,35 +102,10 @@ struct PublisherOptionsWithAllocator : public PublisherOptionsBase
|
||||
get_allocator() const
|
||||
{
|
||||
if (!this->allocator) {
|
||||
if (!allocator_storage_) {
|
||||
allocator_storage_ = std::make_shared<Allocator>();
|
||||
}
|
||||
return allocator_storage_;
|
||||
return std::make_shared<Allocator>();
|
||||
}
|
||||
return this->allocator;
|
||||
}
|
||||
|
||||
private:
|
||||
using PlainAllocator =
|
||||
typename std::allocator_traits<Allocator>::template rebind_alloc<char>;
|
||||
|
||||
rcl_allocator_t
|
||||
get_rcl_allocator() const
|
||||
{
|
||||
if (!plain_allocator_storage_) {
|
||||
plain_allocator_storage_ =
|
||||
std::make_shared<PlainAllocator>(*this->get_allocator());
|
||||
}
|
||||
return rclcpp::allocator::get_rcl_allocator<char>(*plain_allocator_storage_);
|
||||
}
|
||||
|
||||
// This is a temporal workaround, to make sure that get_allocator()
|
||||
// always returns a copy of the same allocator.
|
||||
mutable std::shared_ptr<Allocator> allocator_storage_;
|
||||
|
||||
// This is a temporal workaround, to keep the plain allocator that backs
|
||||
// up the rcl allocator returned in rcl_publisher_options_t alive.
|
||||
mutable std::shared_ptr<PlainAllocator> plain_allocator_storage_;
|
||||
};
|
||||
|
||||
using PublisherOptions = PublisherOptionsWithAllocator<std::allocator<void>>;
|
||||
|
||||
@@ -47,7 +47,7 @@ public:
|
||||
* \param[in] initial_capacity The amount of memory to be allocated.
|
||||
* \param[in] allocator The allocator to be used for the initialization.
|
||||
*/
|
||||
explicit SerializedMessage(
|
||||
SerializedMessage(
|
||||
size_t initial_capacity,
|
||||
const rcl_allocator_t & allocator = rcl_get_default_allocator());
|
||||
|
||||
|
||||
@@ -141,9 +141,7 @@ protected:
|
||||
};
|
||||
|
||||
template<typename ServiceT>
|
||||
class Service
|
||||
: public ServiceBase,
|
||||
public std::enable_shared_from_this<Service<ServiceT>>
|
||||
class Service : public ServiceBase
|
||||
{
|
||||
public:
|
||||
using CallbackType = std::function<
|
||||
@@ -337,10 +335,9 @@ public:
|
||||
std::shared_ptr<void> request) override
|
||||
{
|
||||
auto typed_request = std::static_pointer_cast<typename ServiceT::Request>(request);
|
||||
auto response = any_callback_.dispatch(this->shared_from_this(), request_header, typed_request);
|
||||
if (response) {
|
||||
send_response(*request_header, *response);
|
||||
}
|
||||
auto response = std::make_shared<typename ServiceT::Response>();
|
||||
any_callback_.dispatch(request_header, typed_request, response);
|
||||
send_response(*request_header, *response);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -60,16 +60,10 @@ class NodeTopicsInterface;
|
||||
|
||||
/// Subscription implementation, templated on the type of message this subscription receives.
|
||||
template<
|
||||
typename MessageT,
|
||||
typename CallbackMessageT,
|
||||
typename AllocatorT = std::allocator<void>,
|
||||
/// MessageT::custom_type if MessageT is a TypeAdapter,
|
||||
/// otherwise just MessageT.
|
||||
typename SubscribedT = typename rclcpp::TypeAdapter<MessageT>::custom_type,
|
||||
/// MessageT::ros_message_type if MessageT is a TypeAdapter,
|
||||
/// otherwise just MessageT.
|
||||
typename ROSMessageT = typename rclcpp::TypeAdapter<MessageT>::ros_message_type,
|
||||
typename MessageMemoryStrategyT = rclcpp::message_memory_strategy::MessageMemoryStrategy<
|
||||
ROSMessageT,
|
||||
CallbackMessageT,
|
||||
AllocatorT
|
||||
>>
|
||||
class Subscription : public SubscriptionBase
|
||||
@@ -77,36 +71,14 @@ class Subscription : public SubscriptionBase
|
||||
friend class rclcpp::node_interfaces::NodeTopicsInterface;
|
||||
|
||||
public:
|
||||
// Redeclare these here to use outside of the class.
|
||||
using SubscribedType = SubscribedT;
|
||||
using ROSMessageType = ROSMessageT;
|
||||
using MessageMemoryStrategyType = MessageMemoryStrategyT;
|
||||
|
||||
using SubscribedTypeAllocatorTraits = allocator::AllocRebind<SubscribedType, AllocatorT>;
|
||||
using SubscribedTypeAllocator = typename SubscribedTypeAllocatorTraits::allocator_type;
|
||||
using SubscribedTypeDeleter = allocator::Deleter<SubscribedTypeAllocator, SubscribedType>;
|
||||
|
||||
using ROSMessageTypeAllocatorTraits = allocator::AllocRebind<ROSMessageType, AllocatorT>;
|
||||
using ROSMessageTypeAllocator = typename ROSMessageTypeAllocatorTraits::allocator_type;
|
||||
using ROSMessageTypeDeleter = allocator::Deleter<ROSMessageTypeAllocator, ROSMessageType>;
|
||||
|
||||
using MessageAllocatorTraits [[deprecated("use ROSMessageTypeAllocatorTraits")]] =
|
||||
ROSMessageTypeAllocatorTraits;
|
||||
using MessageAllocator [[deprecated("use ROSMessageTypeAllocator")]] =
|
||||
ROSMessageTypeAllocator;
|
||||
using MessageDeleter [[deprecated("use ROSMessageTypeDeleter")]] =
|
||||
ROSMessageTypeDeleter;
|
||||
|
||||
using ConstMessageSharedPtr [[deprecated]] = std::shared_ptr<const ROSMessageType>;
|
||||
using MessageUniquePtr
|
||||
[[deprecated("use std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter> instead")]] =
|
||||
std::unique_ptr<ROSMessageType, ROSMessageTypeDeleter>;
|
||||
|
||||
private:
|
||||
using MessageAllocatorTraits = allocator::AllocRebind<CallbackMessageT, AllocatorT>;
|
||||
using MessageAllocator = typename MessageAllocatorTraits::allocator_type;
|
||||
using MessageDeleter = allocator::Deleter<MessageAllocator, CallbackMessageT>;
|
||||
using ConstMessageSharedPtr = std::shared_ptr<const CallbackMessageT>;
|
||||
using MessageUniquePtr = std::unique_ptr<CallbackMessageT, MessageDeleter>;
|
||||
using SubscriptionTopicStatisticsSharedPtr =
|
||||
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics<ROSMessageType>>;
|
||||
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics<CallbackMessageT>>;
|
||||
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(Subscription)
|
||||
|
||||
/// Default constructor.
|
||||
@@ -132,7 +104,7 @@ public:
|
||||
const rosidl_message_type_support_t & type_support_handle,
|
||||
const std::string & topic_name,
|
||||
const rclcpp::QoS & qos,
|
||||
AnySubscriptionCallback<MessageT, AllocatorT> callback,
|
||||
AnySubscriptionCallback<CallbackMessageT, AllocatorT> callback,
|
||||
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options,
|
||||
typename MessageMemoryStrategyT::SharedPtr message_memory_strategy,
|
||||
SubscriptionTopicStatisticsSharedPtr subscription_topic_statistics = nullptr)
|
||||
@@ -140,8 +112,8 @@ public:
|
||||
node_base,
|
||||
type_support_handle,
|
||||
topic_name,
|
||||
options.template to_rcl_subscription_options<ROSMessageType>(qos),
|
||||
callback.is_serialized_message_callback()),
|
||||
options.template to_rcl_subscription_options<CallbackMessageT>(qos),
|
||||
rclcpp::subscription_traits::is_serialized_subscription_argument<CallbackMessageT>::value),
|
||||
any_callback_(callback),
|
||||
options_(options),
|
||||
message_memory_strategy_(message_memory_strategy)
|
||||
@@ -183,16 +155,16 @@ public:
|
||||
using rclcpp::detail::resolve_intra_process_buffer_type;
|
||||
|
||||
// Check if the QoS is compatible with intra-process.
|
||||
auto qos_profile = get_actual_qos();
|
||||
if (qos_profile.history() != rclcpp::HistoryPolicy::KeepLast) {
|
||||
rmw_qos_profile_t qos_profile = get_actual_qos().get_rmw_qos_profile();
|
||||
if (qos_profile.history == RMW_QOS_POLICY_HISTORY_KEEP_ALL) {
|
||||
throw std::invalid_argument(
|
||||
"intraprocess communication allowed only with keep last history qos policy");
|
||||
"intraprocess communication is not allowed with keep all history qos policy");
|
||||
}
|
||||
if (qos_profile.depth() == 0) {
|
||||
if (qos_profile.depth == 0) {
|
||||
throw std::invalid_argument(
|
||||
"intraprocess communication is not allowed with 0 depth qos policy");
|
||||
}
|
||||
if (qos_profile.durability() != rclcpp::DurabilityPolicy::Volatile) {
|
||||
if (qos_profile.durability != RMW_QOS_POLICY_DURABILITY_VOLATILE) {
|
||||
throw std::invalid_argument(
|
||||
"intraprocess communication allowed only with volatile durability");
|
||||
}
|
||||
@@ -269,34 +241,11 @@ public:
|
||||
* \throws any rcl errors from rcl_take, \sa rclcpp::exceptions::throw_from_rcl_error()
|
||||
*/
|
||||
bool
|
||||
take(ROSMessageType & message_out, rclcpp::MessageInfo & message_info_out)
|
||||
take(CallbackMessageT & message_out, rclcpp::MessageInfo & message_info_out)
|
||||
{
|
||||
return this->take_type_erased(static_cast<void *>(&message_out), message_info_out);
|
||||
}
|
||||
|
||||
/// Take the next message from the inter-process subscription.
|
||||
/**
|
||||
* This verison takes a SubscribedType which is different frmo the
|
||||
* ROSMessageType when a rclcpp::TypeAdapter is in used.
|
||||
*
|
||||
* \sa take(ROSMessageType &, rclcpp::MessageInfo &)
|
||||
*/
|
||||
template<typename TakeT>
|
||||
std::enable_if_t<
|
||||
!rosidl_generator_traits::is_message<TakeT>::value &&
|
||||
std::is_same_v<TakeT, SubscribedType>,
|
||||
bool
|
||||
>
|
||||
take(TakeT & message_out, rclcpp::MessageInfo & message_info_out)
|
||||
{
|
||||
ROSMessageType local_message;
|
||||
bool taken = this->take_type_erased(static_cast<void *>(&local_message), message_info_out);
|
||||
if (taken) {
|
||||
rclcpp::TypeAdapter<MessageT>::convert_to_custom(local_message, message_out);
|
||||
}
|
||||
return taken;
|
||||
}
|
||||
|
||||
std::shared_ptr<void>
|
||||
create_message() override
|
||||
{
|
||||
@@ -323,7 +272,7 @@ public:
|
||||
// we should ignore this copy of the message.
|
||||
return;
|
||||
}
|
||||
auto typed_message = std::static_pointer_cast<ROSMessageType>(message);
|
||||
auto typed_message = std::static_pointer_cast<CallbackMessageT>(message);
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> now;
|
||||
if (subscription_topic_statistics_) {
|
||||
@@ -341,25 +290,36 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
handle_serialized_message(
|
||||
const std::shared_ptr<rclcpp::SerializedMessage> & serialized_message,
|
||||
const rclcpp::MessageInfo & message_info) override
|
||||
{
|
||||
// TODO(wjwwood): enable topic statistics for serialized messages
|
||||
any_callback_.dispatch(serialized_message, message_info);
|
||||
}
|
||||
|
||||
void
|
||||
handle_loaned_message(
|
||||
void * loaned_message,
|
||||
const rclcpp::MessageInfo & message_info) override
|
||||
{
|
||||
auto typed_message = static_cast<ROSMessageType *>(loaned_message);
|
||||
if (matches_any_intra_process_publishers(&message_info.get_rmw_message_info().publisher_gid)) {
|
||||
// In this case, the message will be delivered via intra process and
|
||||
// we should ignore this copy of the message.
|
||||
return;
|
||||
}
|
||||
|
||||
auto typed_message = static_cast<CallbackMessageT *>(loaned_message);
|
||||
// message is loaned, so we have to make sure that the deleter does not deallocate the message
|
||||
auto sptr = std::shared_ptr<ROSMessageType>(
|
||||
typed_message, [](ROSMessageType * msg) {(void) msg;});
|
||||
auto sptr = std::shared_ptr<CallbackMessageT>(
|
||||
typed_message, [](CallbackMessageT * msg) {(void) msg;});
|
||||
|
||||
std::chrono::time_point<std::chrono::system_clock> now;
|
||||
if (subscription_topic_statistics_) {
|
||||
// get current time before executing callback to
|
||||
// exclude callback duration from topic statistics result.
|
||||
now = std::chrono::system_clock::now();
|
||||
}
|
||||
|
||||
any_callback_.dispatch(sptr, message_info);
|
||||
|
||||
if (subscription_topic_statistics_) {
|
||||
const auto nanos = std::chrono::time_point_cast<std::chrono::nanoseconds>(now);
|
||||
const auto time = rclcpp::Time(nanos.time_since_epoch().count());
|
||||
subscription_topic_statistics_->handle_message(*typed_message, time);
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the borrowed message.
|
||||
@@ -369,7 +329,7 @@ public:
|
||||
void
|
||||
return_message(std::shared_ptr<void> & message) override
|
||||
{
|
||||
auto typed_message = std::static_pointer_cast<ROSMessageType>(message);
|
||||
auto typed_message = std::static_pointer_cast<CallbackMessageT>(message);
|
||||
message_memory_strategy_->return_message(typed_message);
|
||||
}
|
||||
|
||||
@@ -392,24 +352,21 @@ public:
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(Subscription)
|
||||
|
||||
AnySubscriptionCallback<MessageT, AllocatorT> any_callback_;
|
||||
AnySubscriptionCallback<CallbackMessageT, AllocatorT> any_callback_;
|
||||
/// Copy of original options passed during construction.
|
||||
/**
|
||||
* It is important to save a copy of this so that the rmw payload which it
|
||||
* may contain is kept alive for the duration of the subscription.
|
||||
*/
|
||||
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> options_;
|
||||
typename message_memory_strategy::MessageMemoryStrategy<ROSMessageType, AllocatorT>::SharedPtr
|
||||
typename message_memory_strategy::MessageMemoryStrategy<CallbackMessageT, AllocatorT>::SharedPtr
|
||||
message_memory_strategy_;
|
||||
|
||||
/// Component which computes and publishes topic statistics for this subscriber
|
||||
SubscriptionTopicStatisticsSharedPtr subscription_topic_statistics_{nullptr};
|
||||
|
||||
using SubscriptionIntraProcessT = rclcpp::experimental::SubscriptionIntraProcess<
|
||||
ROSMessageType,
|
||||
CallbackMessageT,
|
||||
AllocatorT,
|
||||
ROSMessageTypeDeleter,
|
||||
MessageT>;
|
||||
typename MessageUniquePtr::deleter_type>;
|
||||
std::shared_ptr<SubscriptionIntraProcessT> subscription_intra_process_;
|
||||
};
|
||||
|
||||
|
||||
@@ -183,13 +183,6 @@ public:
|
||||
void
|
||||
handle_message(std::shared_ptr<void> & message, const rclcpp::MessageInfo & message_info) = 0;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
handle_serialized_message(
|
||||
const std::shared_ptr<rclcpp::SerializedMessage> & serialized_message,
|
||||
const rclcpp::MessageInfo & message_info) = 0;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include "rosidl_typesupport_cpp/message_type_support.hpp"
|
||||
|
||||
#include "rclcpp/any_subscription_callback.hpp"
|
||||
#include "rclcpp/get_message_type_support_handle.hpp"
|
||||
#include "rclcpp/intra_process_buffer_type.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
@@ -75,23 +74,26 @@ template<
|
||||
typename MessageT,
|
||||
typename CallbackT,
|
||||
typename AllocatorT,
|
||||
typename SubscriptionT = rclcpp::Subscription<MessageT, AllocatorT>,
|
||||
typename MessageMemoryStrategyT = typename SubscriptionT::MessageMemoryStrategyType,
|
||||
typename ROSMessageType = typename SubscriptionT::ROSMessageType
|
||||
>
|
||||
typename CallbackMessageT =
|
||||
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type,
|
||||
typename SubscriptionT = rclcpp::Subscription<CallbackMessageT, AllocatorT>,
|
||||
typename MessageMemoryStrategyT = rclcpp::message_memory_strategy::MessageMemoryStrategy<
|
||||
CallbackMessageT,
|
||||
AllocatorT
|
||||
>>
|
||||
SubscriptionFactory
|
||||
create_subscription_factory(
|
||||
CallbackT && callback,
|
||||
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options,
|
||||
typename MessageMemoryStrategyT::SharedPtr msg_mem_strat,
|
||||
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics<ROSMessageType>>
|
||||
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics<CallbackMessageT>>
|
||||
subscription_topic_stats = nullptr
|
||||
)
|
||||
{
|
||||
auto allocator = options.get_allocator();
|
||||
|
||||
using rclcpp::AnySubscriptionCallback;
|
||||
AnySubscriptionCallback<MessageT, AllocatorT> any_subscription_callback(*allocator);
|
||||
AnySubscriptionCallback<CallbackMessageT, AllocatorT> any_subscription_callback(*allocator);
|
||||
any_subscription_callback.set(std::forward<CallbackT>(callback));
|
||||
|
||||
SubscriptionFactory factory {
|
||||
@@ -105,9 +107,9 @@ create_subscription_factory(
|
||||
using rclcpp::Subscription;
|
||||
using rclcpp::SubscriptionBase;
|
||||
|
||||
auto sub = Subscription<MessageT, AllocatorT>::make_shared(
|
||||
auto sub = Subscription<CallbackMessageT, AllocatorT>::make_shared(
|
||||
node_base,
|
||||
rclcpp::get_message_type_support_handle<MessageT>(),
|
||||
*rosidl_typesupport_cpp::get_message_type_support_handle<MessageT>(),
|
||||
topic_name,
|
||||
qos,
|
||||
any_subscription_callback,
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "rclcpp/callback_group.hpp"
|
||||
@@ -87,10 +86,6 @@ struct SubscriptionOptionsBase
|
||||
template<typename Allocator>
|
||||
struct SubscriptionOptionsWithAllocator : public SubscriptionOptionsBase
|
||||
{
|
||||
static_assert(
|
||||
std::is_void_v<typename std::allocator_traits<Allocator>::value_type>,
|
||||
"Subscription allocator value type must be void");
|
||||
|
||||
/// Optional custom allocator.
|
||||
std::shared_ptr<Allocator> allocator = nullptr;
|
||||
|
||||
@@ -112,7 +107,10 @@ struct SubscriptionOptionsWithAllocator : public SubscriptionOptionsBase
|
||||
to_rcl_subscription_options(const rclcpp::QoS & qos) const
|
||||
{
|
||||
rcl_subscription_options_t result = rcl_subscription_get_default_options();
|
||||
result.allocator = this->get_rcl_allocator();
|
||||
using AllocatorTraits = std::allocator_traits<Allocator>;
|
||||
using MessageAllocatorT = typename AllocatorTraits::template rebind_alloc<MessageT>;
|
||||
auto message_alloc = std::make_shared<MessageAllocatorT>(*this->get_allocator().get());
|
||||
result.allocator = allocator::get_rcl_allocator<MessageT>(*message_alloc);
|
||||
result.qos = qos.get_rmw_qos_profile();
|
||||
result.rmw_subscription_options.ignore_local_publications = this->ignore_local_publications;
|
||||
result.rmw_subscription_options.require_unique_network_flow_endpoints =
|
||||
@@ -126,39 +124,15 @@ struct SubscriptionOptionsWithAllocator : public SubscriptionOptionsBase
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Get the allocator, creating one if needed.
|
||||
std::shared_ptr<Allocator>
|
||||
get_allocator() const
|
||||
{
|
||||
if (!this->allocator) {
|
||||
if (!allocator_storage_) {
|
||||
allocator_storage_ = std::make_shared<Allocator>();
|
||||
}
|
||||
return allocator_storage_;
|
||||
return std::make_shared<Allocator>();
|
||||
}
|
||||
return this->allocator;
|
||||
}
|
||||
|
||||
private:
|
||||
using PlainAllocator =
|
||||
typename std::allocator_traits<Allocator>::template rebind_alloc<char>;
|
||||
|
||||
rcl_allocator_t
|
||||
get_rcl_allocator() const
|
||||
{
|
||||
if (!plain_allocator_storage_) {
|
||||
plain_allocator_storage_ =
|
||||
std::make_shared<PlainAllocator>(*this->get_allocator());
|
||||
}
|
||||
return rclcpp::allocator::get_rcl_allocator<char>(*plain_allocator_storage_);
|
||||
}
|
||||
|
||||
// This is a temporal workaround, to make sure that get_allocator()
|
||||
// always returns a copy of the same allocator.
|
||||
mutable std::shared_ptr<Allocator> allocator_storage_;
|
||||
|
||||
// This is a temporal workaround, to keep the plain allocator that backs
|
||||
// up the rcl allocator returned in rcl_subscription_options_t alive.
|
||||
mutable std::shared_ptr<PlainAllocator> plain_allocator_storage_;
|
||||
};
|
||||
|
||||
using SubscriptionOptions = SubscriptionOptionsWithAllocator<std::allocator<void>>;
|
||||
|
||||
@@ -74,14 +74,14 @@ public:
|
||||
const rclcpp::QoS & qos = rclcpp::ClockQoS(),
|
||||
bool use_clock_thread = true);
|
||||
|
||||
/// Attach node to the time source.
|
||||
/// Attack node to the time source.
|
||||
/**
|
||||
* \param node std::shared pointer to a initialized node
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void attachNode(rclcpp::Node::SharedPtr node);
|
||||
|
||||
/// Attach node to the time source.
|
||||
/// Attack node to the time source.
|
||||
/**
|
||||
* If the parameter `use_sim_time` is `true` then the source time is the simulation time,
|
||||
* otherwise the source time is defined by the system.
|
||||
|
||||
@@ -1,201 +0,0 @@
|
||||
// Copyright 2021 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__TYPE_ADAPTER_HPP_
|
||||
#define RCLCPP__TYPE_ADAPTER_HPP_
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
/// Template structure used to adapt custom, user-defined types to ROS types.
|
||||
/**
|
||||
* Adapting a custom, user-defined type to a ROS type allows that custom type
|
||||
* to be used when publishing and subscribing in ROS.
|
||||
*
|
||||
* In order to adapt a custom type to a ROS type, the user must create a
|
||||
* template specialization of this structure for the custom type.
|
||||
* In that specialization they must:
|
||||
*
|
||||
* - change `is_specialized` to `std::true_type`,
|
||||
* - specify the custom type with `using custom_type = ...`,
|
||||
* - specify the ROS type with `using ros_message_type = ...`,
|
||||
* - provide static convert functions with the signatures:
|
||||
* - static void convert_to_ros(const custom_type &, ros_message_type &)
|
||||
* - static void convert_to_custom(const ros_message_type &, custom_type &)
|
||||
*
|
||||
* The convert functions must convert from one type to the other.
|
||||
*
|
||||
* For example, here is a theoretical example for adapting `std::string` to the
|
||||
* `std_msgs::msg::String` ROS message type:
|
||||
*
|
||||
* template<>
|
||||
* struct rclcpp::TypeAdapter<std::string, std_msgs::msg::String>
|
||||
* {
|
||||
* using is_specialized = std::true_type;
|
||||
* using custom_type = std::string;
|
||||
* using ros_message_type = std_msgs::msg::String;
|
||||
*
|
||||
* static
|
||||
* void
|
||||
* convert_to_ros_message(
|
||||
* const custom_type & source,
|
||||
* ros_message_type & destination)
|
||||
* {
|
||||
* destination.data = source;
|
||||
* }
|
||||
*
|
||||
* static
|
||||
* void
|
||||
* convert_to_custom(
|
||||
* const ros_message_type & source,
|
||||
* custom_type & destination)
|
||||
* {
|
||||
* destination = source.data;
|
||||
* }
|
||||
* };
|
||||
*
|
||||
* The adapter can then be used when creating a publisher or subscription,
|
||||
* e.g.:
|
||||
*
|
||||
* using MyAdaptedType = TypeAdapter<std::string, std_msgs::msg::String>;
|
||||
* auto pub = node->create_publisher<MyAdaptedType>("topic", 10);
|
||||
* auto sub = node->create_subscription<MyAdaptedType>(
|
||||
* "topic",
|
||||
* 10,
|
||||
* [](const std::string & msg) {...});
|
||||
*
|
||||
* You can also be more declarative by using the adapt_type::as metafunctions,
|
||||
* which are a bit less ambiguous to read:
|
||||
*
|
||||
* using AdaptedType = rclcpp::adapt_type<std::string>::as<std_msgs::msg::String>;
|
||||
* auto pub = node->create_publisher<AdaptedType>(...);
|
||||
*
|
||||
* If you wish, you may associate a custom type with a single ROS message type,
|
||||
* allowing you to be a bit more brief when creating entities, e.g.:
|
||||
*
|
||||
* // First you must declare the association, this is similar to how you
|
||||
* // would avoid using the namespace in C++ by doing `using std::vector;`.
|
||||
* RCLCPP_USING_CUSTOM_TYPE_AS_ROS_MESSAGE_TYPE(std::string, std_msgs::msg::String);
|
||||
*
|
||||
* // Then you can create things with just the custom type, and the ROS
|
||||
* // message type is implied based on the previous statement.
|
||||
* auto pub = node->create_publisher<std::string>(...);
|
||||
*/
|
||||
template<typename CustomType, typename ROSMessageType = void, class Enable = void>
|
||||
struct TypeAdapter
|
||||
{
|
||||
using is_specialized = std::false_type;
|
||||
using custom_type = CustomType;
|
||||
// In this case, the CustomType is the only thing given, or there is no specialization.
|
||||
// Assign ros_message_type to CustomType for the former case.
|
||||
using ros_message_type = CustomType;
|
||||
};
|
||||
|
||||
/// Helper template to determine if a type is a TypeAdapter, false specialization.
|
||||
template<typename T>
|
||||
struct is_type_adapter : std::false_type {};
|
||||
|
||||
/// Helper template to determine if a type is a TypeAdapter, true specialization.
|
||||
template<typename ... Ts>
|
||||
struct is_type_adapter<TypeAdapter<Ts...>>: std::true_type {};
|
||||
|
||||
/// Identity specialization for TypeAdapter.
|
||||
template<typename T>
|
||||
struct TypeAdapter<T, void, std::enable_if_t<is_type_adapter<T>::value>>: T {};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<typename CustomType, typename ROSMessageType>
|
||||
struct assert_type_pair_is_specialized_type_adapter
|
||||
{
|
||||
using type_adapter = TypeAdapter<CustomType, ROSMessageType>;
|
||||
static_assert(
|
||||
type_adapter::is_specialized::value,
|
||||
"No type adapter for this custom type/ros message type pair");
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// Template metafunction that can make the type being adapted explicit.
|
||||
template<typename CustomType>
|
||||
struct adapt_type
|
||||
{
|
||||
template<typename ROSMessageType>
|
||||
using as = typename ::rclcpp::detail::assert_type_pair_is_specialized_type_adapter<
|
||||
CustomType,
|
||||
ROSMessageType
|
||||
>::type_adapter;
|
||||
};
|
||||
|
||||
/// Implicit type adapter used as a short hand way to create something with just the custom type.
|
||||
/**
|
||||
* This is used when creating a publisher or subscription using just the custom
|
||||
* type in conjunction with RCLCPP_USING_CUSTOM_TYPE_AS_ROS_MESSAGE_TYPE().
|
||||
* For example:
|
||||
*
|
||||
* #include "type_adapter_for_std_string_to_std_msgs_String.hpp"
|
||||
*
|
||||
* RCLCPP_USING_CUSTOM_TYPE_AS_ROS_MESSAGE_TYPE(std::string, std_msgs::msg::String);
|
||||
*
|
||||
* int main(...) {
|
||||
* // ...
|
||||
* auto pub = node->create_publisher<std::string>(...);
|
||||
* }
|
||||
*
|
||||
* \sa TypeAdapter for more examples.
|
||||
*/
|
||||
template<typename CustomType>
|
||||
struct ImplicitTypeAdapter
|
||||
{
|
||||
using is_specialized = std::false_type;
|
||||
};
|
||||
|
||||
/// Specialization of TypeAdapter for ImplicitTypeAdapter.
|
||||
/**
|
||||
* This allows for things like this:
|
||||
*
|
||||
* RCLCPP_USING_CUSTOM_TYPE_AS_ROS_MESSAGE_TYPE(std::string, std_msgs::msg::String);
|
||||
* auto pub = node->create_publisher<std::string>("topic", 10);
|
||||
*
|
||||
*/
|
||||
template<typename T>
|
||||
struct TypeAdapter<T, void, std::enable_if_t<ImplicitTypeAdapter<T>::is_specialized::value>>
|
||||
: ImplicitTypeAdapter<T>
|
||||
{};
|
||||
|
||||
/// Assigns the custom type implicitly to the given custom type/ros message type pair.
|
||||
/**
|
||||
* Note: this macro needs to be used in the root namespace.
|
||||
* We cannot use ::rclcpp to protect against this, due to how GCC interprets the
|
||||
* syntax, see: https://stackoverflow.com/a/2781537
|
||||
*
|
||||
* \sa TypeAdapter
|
||||
* \sa ImplicitTypeAdapter
|
||||
*/
|
||||
#define RCLCPP_USING_CUSTOM_TYPE_AS_ROS_MESSAGE_TYPE(CustomType, ROSMessageType) \
|
||||
template<> \
|
||||
struct rclcpp::ImplicitTypeAdapter<CustomType> \
|
||||
: public rclcpp::TypeAdapter<CustomType, ROSMessageType> \
|
||||
{ \
|
||||
static_assert( \
|
||||
is_specialized::value, \
|
||||
"Cannot use custom type as ros type when there is no TypeAdapter for that pair"); \
|
||||
}
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__TYPE_ADAPTER_HPP_
|
||||
100
rclcpp/include/rclcpp/wait_for_message.hpp
Normal file
100
rclcpp/include/rclcpp/wait_for_message.hpp
Normal file
@@ -0,0 +1,100 @@
|
||||
// Copyright 2021 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__WAIT_FOR_MESSAGE_HPP_
|
||||
#define RCLCPP__WAIT_FOR_MESSAGE_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "rclcpp/node.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
#include "rclcpp/wait_set.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
/// Wait for the next incoming message.
|
||||
/**
|
||||
* Given an already initialized subscription,
|
||||
* wait for the next incoming message to arrive before the specified timeout.
|
||||
*
|
||||
* \param[out] out is the message to be filled when a new message is arriving.
|
||||
* \param[in] subscription shared pointer to a previously initialized subscription.
|
||||
* \param[in] context shared pointer to a context to watch for SIGINT requests.
|
||||
* \param[in] time_to_wait parameter specifying the timeout before returning.
|
||||
* \return true if a message was successfully received, false if message could not
|
||||
* be obtained or shutdown was triggered asynchronously on the context.
|
||||
*/
|
||||
template<class MsgT, class Rep = int64_t, class Period = std::milli>
|
||||
bool wait_for_message(
|
||||
MsgT & out,
|
||||
std::shared_ptr<rclcpp::Subscription<MsgT>> subscription,
|
||||
std::shared_ptr<rclcpp::Context> context,
|
||||
std::chrono::duration<Rep, Period> time_to_wait = std::chrono::duration<Rep, Period>(-1))
|
||||
{
|
||||
auto gc = std::make_shared<rclcpp::GuardCondition>(context);
|
||||
auto shutdown_callback_handle = context->add_on_shutdown_callback(
|
||||
[weak_gc = std::weak_ptr<rclcpp::GuardCondition>{gc}]() {
|
||||
auto strong_gc = weak_gc.lock();
|
||||
if (strong_gc) {
|
||||
strong_gc->trigger();
|
||||
}
|
||||
});
|
||||
|
||||
rclcpp::WaitSet wait_set;
|
||||
wait_set.add_subscription(subscription);
|
||||
wait_set.add_guard_condition(gc);
|
||||
auto ret = wait_set.wait(time_to_wait);
|
||||
if (ret.kind() != rclcpp::WaitResultKind::Ready) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (wait_set.get_rcl_wait_set().guard_conditions[0]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
rclcpp::MessageInfo info;
|
||||
if (!subscription->take(out, info)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Wait for the next incoming message.
|
||||
/**
|
||||
* Wait for the next incoming message to arrive on a specified topic before the specified timeout.
|
||||
*
|
||||
* \param[out] out is the message to be filled when a new message is arriving.
|
||||
* \param[in] node the node pointer to initialize the subscription on.
|
||||
* \param[in] topic the topic to wait for messages.
|
||||
* \param[in] time_to_wait parameter specifying the timeout before returning.
|
||||
* \return true if a message was successfully received, false if message could not
|
||||
* be obtained or shutdown was triggered asynchronously on the context.
|
||||
*/
|
||||
template<class MsgT, class Rep = int64_t, class Period = std::milli>
|
||||
bool wait_for_message(
|
||||
MsgT & out,
|
||||
rclcpp::Node::SharedPtr node,
|
||||
const std::string & topic,
|
||||
std::chrono::duration<Rep, Period> time_to_wait = std::chrono::duration<Rep, Period>(-1))
|
||||
{
|
||||
auto sub = node->create_subscription<MsgT>(topic, 1, [](const std::shared_ptr<MsgT>) {});
|
||||
return wait_for_message<MsgT, Rep, Period>(
|
||||
out, sub, node->get_node_options().context(), time_to_wait);
|
||||
}
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__WAIT_FOR_MESSAGE_HPP_
|
||||
@@ -2,7 +2,7 @@
|
||||
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="2">
|
||||
<name>rclcpp</name>
|
||||
<version>11.2.0</version>
|
||||
<version>9.2.2</version>
|
||||
<description>The ROS client library in C++.</description>
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
<maintainer email="mabel@openrobotics.org">Mabel Zhang</maintainer>
|
||||
@@ -37,6 +37,7 @@
|
||||
<depend>tracetools</depend>
|
||||
|
||||
<test_depend>ament_cmake_gmock</test_depend>
|
||||
<test_depend>ament_cmake_google_benchmark</test_depend>
|
||||
<test_depend>ament_cmake_gtest</test_depend>
|
||||
<test_depend>ament_lint_auto</test_depend>
|
||||
<test_depend>ament_lint_common</test_depend>
|
||||
|
||||
@@ -149,7 +149,7 @@ def get_rclcpp_suffix_from_features(features):
|
||||
@[ if params]@
|
||||
@(''.join([' ' + p + ', \\\n' for p in params if p != stream_arg]))@
|
||||
@[ end if]@
|
||||
logger.get_name(), \
|
||||
(logger).get_name(), \
|
||||
@[ if 'stream' not in feature_combination]@
|
||||
__VA_ARGS__); \
|
||||
@[ else]@
|
||||
|
||||
@@ -51,18 +51,13 @@ rclcpp::detail::resolve_parameter_overrides(
|
||||
[params]() {
|
||||
rcl_yaml_node_struct_fini(params);
|
||||
});
|
||||
rclcpp::ParameterMap initial_map = rclcpp::parameter_map_from(params);
|
||||
rclcpp::ParameterMap initial_map = rclcpp::parameter_map_from(params, node_fqn.c_str());
|
||||
|
||||
// Enforce wildcard matching precedence
|
||||
// TODO(cottsay) implement further wildcard matching
|
||||
const std::array<std::string, 2> node_matching_names{"/**", node_fqn};
|
||||
for (const auto & node_name : node_matching_names) {
|
||||
if (initial_map.count(node_name) > 0) {
|
||||
// Combine parameter yaml files, overwriting values in older ones
|
||||
for (const rclcpp::Parameter & param : initial_map.at(node_name)) {
|
||||
result[param.get_name()] =
|
||||
rclcpp::ParameterValue(param.get_value_message());
|
||||
}
|
||||
if (initial_map.count(node_fqn) > 0) {
|
||||
// Combine parameter yaml files, overwriting values in older ones
|
||||
for (const rclcpp::Parameter & param : initial_map.at(node_fqn)) {
|
||||
result[param.get_name()] =
|
||||
rclcpp::ParameterValue(param.get_value_message());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "rclcpp/node.hpp"
|
||||
#include "rclcpp/scope_exit.hpp"
|
||||
#include "rclcpp/utilities.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base.hpp"
|
||||
|
||||
#include "rcutils/logging_macros.h"
|
||||
|
||||
@@ -190,14 +191,13 @@ Executor::add_callback_groups_from_nodes_associated_to_executor()
|
||||
for (auto & weak_node : weak_nodes_) {
|
||||
auto node = weak_node.lock();
|
||||
if (node) {
|
||||
auto group_ptrs = node->get_callback_groups();
|
||||
std::for_each(
|
||||
group_ptrs.begin(), group_ptrs.end(),
|
||||
[this, node](rclcpp::CallbackGroup::WeakPtr group_ptr)
|
||||
rclcpp::node_interfaces::global_for_each_callback_group(
|
||||
node.get(),
|
||||
[this, node](rclcpp::CallbackGroup::SharedPtr shared_group_ptr)
|
||||
{
|
||||
auto shared_group_ptr = group_ptr.lock();
|
||||
if (shared_group_ptr && shared_group_ptr->automatically_add_to_executor_with_node() &&
|
||||
!shared_group_ptr->get_associated_with_executor_atomic().load())
|
||||
if (
|
||||
shared_group_ptr->automatically_add_to_executor_with_node() &&
|
||||
!shared_group_ptr->get_associated_with_executor_atomic().load())
|
||||
{
|
||||
this->add_callback_group_to_map(
|
||||
shared_group_ptr,
|
||||
@@ -268,23 +268,24 @@ Executor::add_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_pt
|
||||
// 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(
|
||||
std::string("Node '") + node_ptr->get_fully_qualified_name() +
|
||||
"' has already been added to an executor.");
|
||||
throw std::runtime_error("Node has already been added to an executor.");
|
||||
}
|
||||
std::lock_guard<std::mutex> guard{mutex_};
|
||||
for (auto & weak_group : node_ptr->get_callback_groups()) {
|
||||
auto group_ptr = weak_group.lock();
|
||||
if (group_ptr != nullptr && !group_ptr->get_associated_with_executor_atomic().load() &&
|
||||
group_ptr->automatically_add_to_executor_with_node())
|
||||
rclcpp::node_interfaces::global_for_each_callback_group(
|
||||
node_ptr.get(),
|
||||
[this, node_ptr, notify](rclcpp::CallbackGroup::SharedPtr group_ptr)
|
||||
{
|
||||
this->add_callback_group_to_map(
|
||||
group_ptr,
|
||||
node_ptr,
|
||||
weak_groups_to_nodes_associated_with_executor_,
|
||||
notify);
|
||||
}
|
||||
}
|
||||
if (!group_ptr->get_associated_with_executor_atomic().load() &&
|
||||
group_ptr->automatically_add_to_executor_with_node())
|
||||
{
|
||||
this->add_callback_group_to_map(
|
||||
group_ptr,
|
||||
node_ptr,
|
||||
weak_groups_to_nodes_associated_with_executor_,
|
||||
notify);
|
||||
}
|
||||
});
|
||||
|
||||
weak_nodes_.push_back(node_ptr);
|
||||
}
|
||||
|
||||
@@ -591,7 +592,8 @@ Executor::execute_subscription(rclcpp::SubscriptionBase::SharedPtr subscription)
|
||||
[&]() {return subscription->take_serialized(*serialized_msg.get(), message_info);},
|
||||
[&]()
|
||||
{
|
||||
subscription->handle_serialized_message(serialized_msg, message_info);
|
||||
auto void_serialized_msg = std::static_pointer_cast<void>(serialized_msg);
|
||||
subscription->handle_message(void_serialized_msg, message_info);
|
||||
});
|
||||
subscription->return_serialized_message(serialized_msg);
|
||||
} else if (subscription->can_loan_messages()) {
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#include "rclcpp/memory_strategy.hpp"
|
||||
#include "rclcpp/executors/static_single_threaded_executor.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base.hpp"
|
||||
|
||||
using rclcpp::executors::StaticExecutorEntitiesCollector;
|
||||
|
||||
@@ -290,18 +291,21 @@ StaticExecutorEntitiesCollector::add_node(
|
||||
if (has_executor.exchange(true)) {
|
||||
throw std::runtime_error("Node has already been added to an executor.");
|
||||
}
|
||||
for (const auto & weak_group : node_ptr->get_callback_groups()) {
|
||||
auto group_ptr = weak_group.lock();
|
||||
if (group_ptr != nullptr && !group_ptr->get_associated_with_executor_atomic().load() &&
|
||||
group_ptr->automatically_add_to_executor_with_node())
|
||||
rclcpp::node_interfaces::global_for_each_callback_group(
|
||||
node_ptr.get(),
|
||||
[this, node_ptr, &is_new_node](rclcpp::CallbackGroup::SharedPtr group_ptr)
|
||||
{
|
||||
is_new_node = (add_callback_group(
|
||||
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;
|
||||
}
|
||||
@@ -467,13 +471,11 @@ StaticExecutorEntitiesCollector::add_callback_groups_from_nodes_associated_to_ex
|
||||
for (const auto & weak_node : weak_nodes_) {
|
||||
auto node = weak_node.lock();
|
||||
if (node) {
|
||||
auto group_ptrs = node->get_callback_groups();
|
||||
std::for_each(
|
||||
group_ptrs.begin(), group_ptrs.end(),
|
||||
[this, node](rclcpp::CallbackGroup::WeakPtr group_ptr)
|
||||
rclcpp::node_interfaces::global_for_each_callback_group(
|
||||
node.get(),
|
||||
[this, node](rclcpp::CallbackGroup::SharedPtr shared_group_ptr)
|
||||
{
|
||||
auto shared_group_ptr = group_ptr.lock();
|
||||
if (shared_group_ptr && shared_group_ptr->automatically_add_to_executor_with_node() &&
|
||||
if (shared_group_ptr->automatically_add_to_executor_with_node() &&
|
||||
!shared_group_ptr->get_associated_with_executor_atomic().load())
|
||||
{
|
||||
add_callback_group(
|
||||
|
||||
@@ -36,19 +36,11 @@ std::shared_ptr<rclcpp::SerializedMessage> GenericSubscription::create_serialize
|
||||
}
|
||||
|
||||
void GenericSubscription::handle_message(
|
||||
std::shared_ptr<void> &,
|
||||
const rclcpp::MessageInfo &)
|
||||
std::shared_ptr<void> & message, const rclcpp::MessageInfo & message_info)
|
||||
{
|
||||
throw rclcpp::exceptions::UnimplementedError(
|
||||
"handle_message is not implemented for GenericSubscription");
|
||||
}
|
||||
|
||||
void
|
||||
GenericSubscription::handle_serialized_message(
|
||||
const std::shared_ptr<rclcpp::SerializedMessage> & message,
|
||||
const rclcpp::MessageInfo &)
|
||||
{
|
||||
callback_(message);
|
||||
(void) message_info;
|
||||
auto typed_message = std::static_pointer_cast<rclcpp::SerializedMessage>(message);
|
||||
callback_(typed_message);
|
||||
}
|
||||
|
||||
void GenericSubscription::handle_loaned_message(
|
||||
|
||||
@@ -36,26 +36,23 @@ IntraProcessManager::add_publisher(rclcpp::PublisherBase::SharedPtr publisher)
|
||||
{
|
||||
std::unique_lock<std::shared_timed_mutex> lock(mutex_);
|
||||
|
||||
uint64_t pub_id = IntraProcessManager::get_next_unique_id();
|
||||
auto id = IntraProcessManager::get_next_unique_id();
|
||||
|
||||
publishers_[pub_id] = publisher;
|
||||
publishers_[id].publisher = publisher;
|
||||
publishers_[id].topic_name = publisher->get_topic_name();
|
||||
publishers_[id].qos = publisher->get_actual_qos().get_rmw_qos_profile();
|
||||
|
||||
// Initialize the subscriptions storage for this publisher.
|
||||
pub_to_subs_[pub_id] = SplittedSubscriptions();
|
||||
pub_to_subs_[id] = SplittedSubscriptions();
|
||||
|
||||
// create an entry for the publisher id and populate with already existing subscriptions
|
||||
for (auto & pair : subscriptions_) {
|
||||
auto subscription = pair.second.lock();
|
||||
if (!subscription) {
|
||||
continue;
|
||||
}
|
||||
if (can_communicate(publisher, subscription)) {
|
||||
uint64_t sub_id = pair.first;
|
||||
insert_sub_id_for_pub(sub_id, pub_id, subscription->use_take_shared_method());
|
||||
if (can_communicate(publishers_[id], pair.second)) {
|
||||
insert_sub_id_for_pub(pair.first, id, pair.second.use_take_shared_method);
|
||||
}
|
||||
}
|
||||
|
||||
return pub_id;
|
||||
return id;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
@@ -63,23 +60,21 @@ IntraProcessManager::add_subscription(SubscriptionIntraProcessBase::SharedPtr su
|
||||
{
|
||||
std::unique_lock<std::shared_timed_mutex> lock(mutex_);
|
||||
|
||||
uint64_t sub_id = IntraProcessManager::get_next_unique_id();
|
||||
auto id = IntraProcessManager::get_next_unique_id();
|
||||
|
||||
subscriptions_[sub_id] = subscription;
|
||||
subscriptions_[id].subscription = subscription;
|
||||
subscriptions_[id].topic_name = subscription->get_topic_name();
|
||||
subscriptions_[id].qos = subscription->get_actual_qos();
|
||||
subscriptions_[id].use_take_shared_method = subscription->use_take_shared_method();
|
||||
|
||||
// adds the subscription id to all the matchable publishers
|
||||
for (auto & pair : publishers_) {
|
||||
auto publisher = pair.second.lock();
|
||||
if (!publisher) {
|
||||
continue;
|
||||
}
|
||||
if (can_communicate(publisher, subscription)) {
|
||||
uint64_t pub_id = pair.first;
|
||||
insert_sub_id_for_pub(sub_id, pub_id, subscription->use_take_shared_method());
|
||||
if (can_communicate(pair.second, subscriptions_[id])) {
|
||||
insert_sub_id_for_pub(id, pair.first, subscriptions_[id].use_take_shared_method);
|
||||
}
|
||||
}
|
||||
|
||||
return sub_id;
|
||||
return id;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -121,7 +116,7 @@ IntraProcessManager::matches_any_publishers(const rmw_gid_t * id) const
|
||||
std::shared_lock<std::shared_timed_mutex> lock(mutex_);
|
||||
|
||||
for (auto & publisher_pair : publishers_) {
|
||||
auto publisher = publisher_pair.second.lock();
|
||||
auto publisher = publisher_pair.second.publisher.lock();
|
||||
if (!publisher) {
|
||||
continue;
|
||||
}
|
||||
@@ -162,7 +157,7 @@ IntraProcessManager::get_subscription_intra_process(uint64_t intra_process_subsc
|
||||
if (subscription_it == subscriptions_.end()) {
|
||||
return nullptr;
|
||||
} else {
|
||||
auto subscription = subscription_it->second.lock();
|
||||
auto subscription = subscription_it->second.subscription.lock();
|
||||
if (subscription) {
|
||||
return subscription;
|
||||
} else {
|
||||
@@ -209,16 +204,25 @@ IntraProcessManager::insert_sub_id_for_pub(
|
||||
|
||||
bool
|
||||
IntraProcessManager::can_communicate(
|
||||
rclcpp::PublisherBase::SharedPtr pub,
|
||||
rclcpp::experimental::SubscriptionIntraProcessBase::SharedPtr sub) const
|
||||
PublisherInfo pub_info,
|
||||
SubscriptionInfo sub_info) const
|
||||
{
|
||||
// publisher and subscription must be on the same topic
|
||||
if (strcmp(pub->get_topic_name(), sub->get_topic_name()) != 0) {
|
||||
if (strcmp(pub_info.topic_name, sub_info.topic_name) != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto check_result = rclcpp::qos_check_compatible(pub->get_actual_qos(), sub->get_actual_qos());
|
||||
if (check_result.compatibility == rclcpp::QoSCompatibility::Error) {
|
||||
// TODO(alsora): the following checks for qos compatibility should be provided by the RMW
|
||||
// a reliable subscription can't be connected with a best effort publisher
|
||||
if (
|
||||
sub_info.qos.reliability == RMW_QOS_POLICY_RELIABILITY_RELIABLE &&
|
||||
pub_info.qos.reliability == RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// a publisher and a subscription with different durability can't communicate
|
||||
if (sub_info.qos.durability != pub_info.qos.durability) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +61,12 @@ extend_sub_namespace(const std::string & existing_sub_namespace, const std::stri
|
||||
extension.c_str(),
|
||||
"a sub-namespace should not have a leading /",
|
||||
0);
|
||||
} else if (existing_sub_namespace.empty() && extension.empty()) {
|
||||
throw rclcpp::exceptions::NameValidationError(
|
||||
"sub_namespace",
|
||||
extension.c_str(),
|
||||
"sub-nodes should not extend nodes by an empty sub-namespace",
|
||||
0);
|
||||
}
|
||||
|
||||
std::string new_sub_namespace;
|
||||
@@ -86,7 +92,11 @@ create_effective_namespace(const std::string & node_namespace, const std::string
|
||||
// and do not need trimming of `/` and other things, as they were validated
|
||||
// in other functions already.
|
||||
|
||||
if (node_namespace.back() == '/') {
|
||||
// A node may not have a sub_namespace if it is no sub_node. In this case,
|
||||
// just return the original namespace
|
||||
if (sub_namespace.empty()) {
|
||||
return node_namespace;
|
||||
} else if (node_namespace.back() == '/') {
|
||||
// this is the special case where node_namespace is just `/`
|
||||
return node_namespace + sub_namespace;
|
||||
} else {
|
||||
@@ -605,3 +615,9 @@ Node::get_node_options() const
|
||||
{
|
||||
return this->node_options_;
|
||||
}
|
||||
|
||||
void Node::for_each_callback_group(
|
||||
const node_interfaces::NodeBaseInterface::CallbackGroupFunction & func)
|
||||
{
|
||||
rclcpp::node_interfaces::global_for_each_callback_group(node_base_.get(), func);
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@ using rclcpp::exceptions::throw_from_rcl_error;
|
||||
|
||||
using rclcpp::node_interfaces::NodeBase;
|
||||
|
||||
using rclcpp::node_interfaces::map_of_mutexes;
|
||||
|
||||
NodeBase::NodeBase(
|
||||
const std::string & node_name,
|
||||
const std::string & namespace_,
|
||||
@@ -46,6 +48,9 @@ NodeBase::NodeBase(
|
||||
associated_with_executor_(false),
|
||||
notify_guard_condition_is_valid_(false)
|
||||
{
|
||||
// Generate a mutex for this instance of NodeBase
|
||||
NodeBase::map_object.create_mutex_of_nodebase(this);
|
||||
|
||||
// Setup the guard condition that is notified when changes occur in the graph.
|
||||
rcl_guard_condition_options_t guard_condition_options = rcl_guard_condition_get_default_options();
|
||||
rcl_ret_t ret = rcl_guard_condition_init(
|
||||
@@ -166,6 +171,8 @@ NodeBase::~NodeBase()
|
||||
"failed to destroy guard condition: %s", rcl_get_error_string().str);
|
||||
}
|
||||
}
|
||||
|
||||
NodeBase::map_object.delete_mutex_of_nodebase(this);
|
||||
}
|
||||
|
||||
const char *
|
||||
@@ -221,12 +228,11 @@ NodeBase::create_callback_group(
|
||||
rclcpp::CallbackGroupType group_type,
|
||||
bool automatically_add_to_executor_with_node)
|
||||
{
|
||||
using rclcpp::CallbackGroup;
|
||||
using rclcpp::CallbackGroupType;
|
||||
auto group = CallbackGroup::SharedPtr(
|
||||
new CallbackGroup(
|
||||
group_type,
|
||||
automatically_add_to_executor_with_node));
|
||||
auto group = std::make_shared<rclcpp::CallbackGroup>(
|
||||
group_type,
|
||||
automatically_add_to_executor_with_node);
|
||||
auto mutex_ptr = NodeBase::map_object.get_mutex_of_nodebase(this);
|
||||
std::lock_guard<std::mutex> lock(*mutex_ptr);
|
||||
callback_groups_.push_back(group);
|
||||
return group;
|
||||
}
|
||||
@@ -240,14 +246,16 @@ NodeBase::get_default_callback_group()
|
||||
bool
|
||||
NodeBase::callback_group_in_node(rclcpp::CallbackGroup::SharedPtr group)
|
||||
{
|
||||
bool group_belongs_to_this_node = false;
|
||||
auto mutex_ptr = NodeBase::map_object.get_mutex_of_nodebase(this);
|
||||
std::lock_guard<std::mutex> lock(*mutex_ptr);
|
||||
|
||||
for (auto & weak_group : this->callback_groups_) {
|
||||
auto cur_group = weak_group.lock();
|
||||
if (cur_group && (cur_group == group)) {
|
||||
group_belongs_to_this_node = true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return group_belongs_to_this_node;
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::vector<rclcpp::CallbackGroup::WeakPtr> &
|
||||
@@ -310,3 +318,41 @@ NodeBase::resolve_topic_or_service_name(
|
||||
allocator.deallocate(output_cstr, allocator.state);
|
||||
return output;
|
||||
}
|
||||
|
||||
map_of_mutexes NodeBase::map_object = map_of_mutexes();
|
||||
|
||||
void map_of_mutexes::create_mutex_of_nodebase(
|
||||
const rclcpp::node_interfaces::NodeBaseInterface * nodebase)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(this->internal_mutex_);
|
||||
this->data_.emplace(nodebase, std::make_shared<std::mutex>() );
|
||||
}
|
||||
|
||||
std::shared_ptr<std::mutex> map_of_mutexes::get_mutex_of_nodebase(
|
||||
const rclcpp::node_interfaces::NodeBaseInterface * nodebase)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(this->internal_mutex_);
|
||||
return this->data_[nodebase];
|
||||
}
|
||||
|
||||
void map_of_mutexes::delete_mutex_of_nodebase(
|
||||
const rclcpp::node_interfaces::NodeBaseInterface * nodebase)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(this->internal_mutex_);
|
||||
this->data_.erase(nodebase);
|
||||
}
|
||||
|
||||
// For each callback group free function implementation
|
||||
void rclcpp::node_interfaces::global_for_each_callback_group(
|
||||
NodeBaseInterface * node_base_interface, const NodeBaseInterface::CallbackGroupFunction & func)
|
||||
{
|
||||
auto mutex_ptr = NodeBase::map_object.get_mutex_of_nodebase(node_base_interface);
|
||||
std::lock_guard<std::mutex> lock(*mutex_ptr);
|
||||
|
||||
for (const auto & weak_group : node_base_interface->get_callback_groups()) {
|
||||
auto group = weak_group.lock();
|
||||
if (group) {
|
||||
func(group);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,8 +13,10 @@
|
||||
// limitations under the License.
|
||||
|
||||
#include <string>
|
||||
#include <regex>
|
||||
#include <vector>
|
||||
|
||||
#include "rcpputils/find_and_replace.hpp"
|
||||
#include "rclcpp/parameter_map.hpp"
|
||||
|
||||
using rclcpp::exceptions::InvalidParametersException;
|
||||
@@ -24,6 +26,12 @@ using rclcpp::ParameterValue;
|
||||
|
||||
ParameterMap
|
||||
rclcpp::parameter_map_from(const rcl_params_t * const c_params)
|
||||
{
|
||||
return parameter_map_from(c_params, nullptr);
|
||||
}
|
||||
|
||||
ParameterMap
|
||||
rclcpp::parameter_map_from(const rcl_params_t * const c_params, const char * node_fqn)
|
||||
{
|
||||
if (NULL == c_params) {
|
||||
throw InvalidParametersException("parameters struct is NULL");
|
||||
@@ -49,6 +57,17 @@ rclcpp::parameter_map_from(const rcl_params_t * const c_params)
|
||||
node_name = c_node_name;
|
||||
}
|
||||
|
||||
if (node_fqn) {
|
||||
// Update the regular expression ["/*" -> "(/\\w+)" and "/**" -> "(/\\w+)*"]
|
||||
std::string regex = rcpputils::find_and_replace(node_name, "/*", "(/\\w+)");
|
||||
if (!std::regex_match(node_fqn, std::regex(regex))) {
|
||||
// No need to parse the items because the user just care about node_fqn
|
||||
continue;
|
||||
}
|
||||
|
||||
node_name = node_fqn;
|
||||
}
|
||||
|
||||
const rcl_node_params_t * const c_params_node = &(c_params->params[n]);
|
||||
|
||||
std::vector<Parameter> & params_node = parameters[node_name];
|
||||
@@ -65,6 +84,7 @@ rclcpp::parameter_map_from(const rcl_params_t * const c_params)
|
||||
params_node.emplace_back(c_param_name, parameter_value_from(c_param_value));
|
||||
}
|
||||
}
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ SubscriptionIntraProcessBase::get_topic_name() const
|
||||
return topic_name_.c_str();
|
||||
}
|
||||
|
||||
rclcpp::QoS
|
||||
rmw_qos_profile_t
|
||||
SubscriptionIntraProcessBase::get_actual_qos() const
|
||||
{
|
||||
return qos_profile_;
|
||||
|
||||
@@ -156,6 +156,12 @@ ok(Context::SharedPtr context)
|
||||
return context->is_valid();
|
||||
}
|
||||
|
||||
bool
|
||||
is_initialized(Context::SharedPtr context)
|
||||
{
|
||||
return ok(context);
|
||||
}
|
||||
|
||||
bool
|
||||
shutdown(Context::SharedPtr context, const std::string & reason)
|
||||
{
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
string data
|
||||
@@ -7,7 +7,6 @@ add_definitions(-DTEST_RESOURCES_DIRECTORY="${TEST_RESOURCES_DIRECTORY}")
|
||||
rosidl_generate_interfaces(${PROJECT_NAME}_test_msgs
|
||||
../msg/Header.msg
|
||||
../msg/MessageWithHeader.msg
|
||||
../msg/String.msg
|
||||
DEPENDENCIES builtin_interfaces
|
||||
LIBRARY_NAME ${PROJECT_NAME}
|
||||
SKIP_INSTALL
|
||||
@@ -356,44 +355,6 @@ if(TARGET test_publisher)
|
||||
)
|
||||
target_link_libraries(test_publisher ${PROJECT_NAME} mimick)
|
||||
endif()
|
||||
|
||||
set(append_library_dirs "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
if(WIN32)
|
||||
set(append_library_dirs "${append_library_dirs}/$<CONFIG>")
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_publisher_with_type_adapter test_publisher_with_type_adapter.cpp
|
||||
APPEND_LIBRARY_DIRS "${append_library_dirs}"
|
||||
)
|
||||
if(TARGET test_publisher_with_type_adapter)
|
||||
ament_target_dependencies(test_publisher_with_type_adapter
|
||||
"rcutils"
|
||||
"rcl_interfaces"
|
||||
"rmw"
|
||||
"rosidl_runtime_cpp"
|
||||
"rosidl_typesupport_cpp"
|
||||
"test_msgs"
|
||||
)
|
||||
rosidl_target_interfaces(test_publisher_with_type_adapter ${PROJECT_NAME}_test_msgs "rosidl_typesupport_cpp")
|
||||
target_link_libraries(test_publisher_with_type_adapter ${PROJECT_NAME} mimick)
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_subscription_with_type_adapter test_subscription_with_type_adapter.cpp
|
||||
APPEND_LIBRARY_DIRS "${append_library_dirs}"
|
||||
)
|
||||
if(TARGET test_subscription_with_type_adapter)
|
||||
ament_target_dependencies(test_subscription_with_type_adapter
|
||||
"rcutils"
|
||||
"rcl_interfaces"
|
||||
"rmw"
|
||||
"rosidl_runtime_cpp"
|
||||
"rosidl_typesupport_cpp"
|
||||
"test_msgs"
|
||||
)
|
||||
rosidl_target_interfaces(test_subscription_with_type_adapter ${PROJECT_NAME}_test_msgs "rosidl_typesupport_cpp")
|
||||
target_link_libraries(test_subscription_with_type_adapter ${PROJECT_NAME} mimick)
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_publisher_subscription_count_api test_publisher_subscription_count_api.cpp)
|
||||
if(TARGET test_publisher_subscription_count_api)
|
||||
ament_target_dependencies(test_publisher_subscription_count_api
|
||||
@@ -546,6 +507,11 @@ if(TARGET test_find_weak_nodes)
|
||||
target_link_libraries(test_find_weak_nodes ${PROJECT_NAME})
|
||||
endif()
|
||||
|
||||
set(append_library_dirs "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
if(WIN32)
|
||||
set(append_library_dirs "${append_library_dirs}/$<CONFIG>")
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_externally_defined_services test_externally_defined_services.cpp)
|
||||
ament_target_dependencies(test_externally_defined_services
|
||||
"rcl"
|
||||
@@ -599,6 +565,13 @@ if(TARGET test_utilities)
|
||||
target_link_libraries(test_utilities ${PROJECT_NAME} mimick)
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_wait_for_message test_wait_for_message.cpp)
|
||||
if(TARGET test_wait_for_message)
|
||||
ament_target_dependencies(test_wait_for_message
|
||||
"test_msgs")
|
||||
target_link_libraries(test_wait_for_message ${PROJECT_NAME})
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_interface_traits test_interface_traits.cpp
|
||||
APPEND_LIBRARY_DIRS "${append_library_dirs}")
|
||||
if(TARGET test_interface_traits)
|
||||
|
||||
@@ -41,38 +41,38 @@ struct NumberOfEntities
|
||||
std::unique_ptr<NumberOfEntities> get_number_of_default_entities(rclcpp::Node::SharedPtr node)
|
||||
{
|
||||
auto number_of_entities = std::make_unique<NumberOfEntities>();
|
||||
for (auto & weak_group : node->get_callback_groups()) {
|
||||
auto group = weak_group.lock();
|
||||
EXPECT_NE(nullptr, group);
|
||||
if (!group || !group->can_be_taken_from().load()) {
|
||||
return nullptr;
|
||||
}
|
||||
group->find_subscription_ptrs_if(
|
||||
[&number_of_entities](rclcpp::SubscriptionBase::SharedPtr &)
|
||||
{
|
||||
number_of_entities->subscriptions++; return false;
|
||||
});
|
||||
group->find_timer_ptrs_if(
|
||||
[&number_of_entities](rclcpp::TimerBase::SharedPtr &)
|
||||
{
|
||||
number_of_entities->timers++; return false;
|
||||
});
|
||||
group->find_service_ptrs_if(
|
||||
[&number_of_entities](rclcpp::ServiceBase::SharedPtr &)
|
||||
{
|
||||
number_of_entities->services++; return false;
|
||||
});
|
||||
group->find_client_ptrs_if(
|
||||
[&number_of_entities](rclcpp::ClientBase::SharedPtr &)
|
||||
{
|
||||
number_of_entities->clients++; return false;
|
||||
});
|
||||
group->find_waitable_ptrs_if(
|
||||
[&number_of_entities](rclcpp::Waitable::SharedPtr &)
|
||||
{
|
||||
number_of_entities->waitables++; return false;
|
||||
});
|
||||
}
|
||||
node->for_each_callback_group(
|
||||
[&number_of_entities](rclcpp::CallbackGroup::SharedPtr group)
|
||||
{
|
||||
if (!group->can_be_taken_from().load()) {
|
||||
return;
|
||||
}
|
||||
group->find_subscription_ptrs_if(
|
||||
[&number_of_entities](rclcpp::SubscriptionBase::SharedPtr &)
|
||||
{
|
||||
number_of_entities->subscriptions++; return false;
|
||||
});
|
||||
group->find_timer_ptrs_if(
|
||||
[&number_of_entities](rclcpp::TimerBase::SharedPtr &)
|
||||
{
|
||||
number_of_entities->timers++; return false;
|
||||
});
|
||||
group->find_service_ptrs_if(
|
||||
[&number_of_entities](rclcpp::ServiceBase::SharedPtr &)
|
||||
{
|
||||
number_of_entities->services++; return false;
|
||||
});
|
||||
group->find_client_ptrs_if(
|
||||
[&number_of_entities](rclcpp::ClientBase::SharedPtr &)
|
||||
{
|
||||
number_of_entities->clients++; return false;
|
||||
});
|
||||
group->find_waitable_ptrs_if(
|
||||
[&number_of_entities](rclcpp::Waitable::SharedPtr &)
|
||||
{
|
||||
number_of_entities->waitables++; return false;
|
||||
});
|
||||
});
|
||||
|
||||
return number_of_entities;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
#include "../../mocking_utils/patch.hpp"
|
||||
#include "../../utils/rclcpp_gtest_macros.hpp"
|
||||
|
||||
#include "rcpputils/filesystem_helper.hpp"
|
||||
|
||||
class TestNodeParameters : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
@@ -47,6 +49,7 @@ public:
|
||||
dynamic_cast<rclcpp::node_interfaces::NodeParameters *>(
|
||||
node->get_node_parameters_interface().get());
|
||||
ASSERT_NE(nullptr, node_parameters);
|
||||
test_resources_path /= "test_node_parameters";
|
||||
}
|
||||
|
||||
void TearDown()
|
||||
@@ -57,6 +60,8 @@ public:
|
||||
protected:
|
||||
std::shared_ptr<rclcpp::Node> node;
|
||||
rclcpp::node_interfaces::NodeParameters * node_parameters;
|
||||
|
||||
rcpputils::fs::path test_resources_path{TEST_RESOURCES_DIRECTORY};
|
||||
};
|
||||
|
||||
TEST_F(TestNodeParameters, construct_destruct_rcl_errors) {
|
||||
@@ -199,3 +204,130 @@ TEST_F(TestNodeParameters, add_remove_parameters_callback) {
|
||||
node_parameters->remove_on_set_parameters_callback(handle.get()),
|
||||
std::runtime_error("Callback doesn't exist"));
|
||||
}
|
||||
|
||||
TEST_F(TestNodeParameters, wildcard_with_namespace)
|
||||
{
|
||||
rclcpp::NodeOptions opts;
|
||||
opts.arguments(
|
||||
{
|
||||
"--ros-args",
|
||||
"--params-file", (test_resources_path / "wildcards.yaml").string()
|
||||
});
|
||||
|
||||
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node2", "ns", opts);
|
||||
|
||||
auto * node_parameters =
|
||||
dynamic_cast<rclcpp::node_interfaces::NodeParameters *>(
|
||||
node->get_node_parameters_interface().get());
|
||||
ASSERT_NE(nullptr, node_parameters);
|
||||
|
||||
const auto & parameter_overrides = node_parameters->get_parameter_overrides();
|
||||
EXPECT_EQ(7u, parameter_overrides.size());
|
||||
EXPECT_EQ(parameter_overrides.at("full_wild").get<std::string>(), "full_wild");
|
||||
EXPECT_EQ(parameter_overrides.at("namespace_wild").get<std::string>(), "namespace_wild");
|
||||
EXPECT_EQ(
|
||||
parameter_overrides.at("namespace_wild_another").get<std::string>(),
|
||||
"namespace_wild_another");
|
||||
EXPECT_EQ(
|
||||
parameter_overrides.at("namespace_wild_one_star").get<std::string>(),
|
||||
"namespace_wild_one_star");
|
||||
EXPECT_EQ(parameter_overrides.at("node_wild_in_ns").get<std::string>(), "node_wild_in_ns");
|
||||
EXPECT_EQ(
|
||||
parameter_overrides.at("node_wild_in_ns_another").get<std::string>(),
|
||||
"node_wild_in_ns_another");
|
||||
EXPECT_EQ(parameter_overrides.at("explicit_in_ns").get<std::string>(), "explicit_in_ns");
|
||||
EXPECT_EQ(parameter_overrides.count("should_not_appear"), 0u);
|
||||
}
|
||||
|
||||
TEST_F(TestNodeParameters, wildcard_no_namespace)
|
||||
{
|
||||
rclcpp::NodeOptions opts;
|
||||
opts.arguments(
|
||||
{
|
||||
"--ros-args",
|
||||
"--params-file", (test_resources_path / "wildcards.yaml").string()
|
||||
});
|
||||
|
||||
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node2", opts);
|
||||
|
||||
auto * node_parameters =
|
||||
dynamic_cast<rclcpp::node_interfaces::NodeParameters *>(
|
||||
node->get_node_parameters_interface().get());
|
||||
ASSERT_NE(nullptr, node_parameters);
|
||||
|
||||
const auto & parameter_overrides = node_parameters->get_parameter_overrides();
|
||||
EXPECT_EQ(5u, parameter_overrides.size());
|
||||
EXPECT_EQ(parameter_overrides.at("full_wild").get<std::string>(), "full_wild");
|
||||
EXPECT_EQ(parameter_overrides.at("namespace_wild").get<std::string>(), "namespace_wild");
|
||||
EXPECT_EQ(
|
||||
parameter_overrides.at("namespace_wild_another").get<std::string>(),
|
||||
"namespace_wild_another");
|
||||
EXPECT_EQ(parameter_overrides.at("node_wild_no_ns").get<std::string>(), "node_wild_no_ns");
|
||||
EXPECT_EQ(parameter_overrides.at("explicit_no_ns").get<std::string>(), "explicit_no_ns");
|
||||
EXPECT_EQ(parameter_overrides.count("should_not_appear"), 0u);
|
||||
// "/*" match exactly one token, not expect to get `namespace_wild_one_star`
|
||||
EXPECT_EQ(parameter_overrides.count("namespace_wild_one_star"), 0u);
|
||||
}
|
||||
|
||||
TEST_F(TestNodeParameters, params_by_order)
|
||||
{
|
||||
rclcpp::NodeOptions opts;
|
||||
opts.arguments(
|
||||
{
|
||||
"--ros-args",
|
||||
"--params-file", (test_resources_path / "params_by_order.yaml").string()
|
||||
});
|
||||
|
||||
std::shared_ptr<rclcpp::Node> node = std::make_shared<rclcpp::Node>("node2", "ns", opts);
|
||||
|
||||
auto * node_parameters =
|
||||
dynamic_cast<rclcpp::node_interfaces::NodeParameters *>(
|
||||
node->get_node_parameters_interface().get());
|
||||
ASSERT_NE(nullptr, node_parameters);
|
||||
|
||||
const auto & parameter_overrides = node_parameters->get_parameter_overrides();
|
||||
EXPECT_EQ(3u, parameter_overrides.size());
|
||||
EXPECT_EQ(parameter_overrides.at("a_value").get<std::string>(), "last_one_win");
|
||||
EXPECT_EQ(parameter_overrides.at("foo").get<std::string>(), "foo");
|
||||
EXPECT_EQ(parameter_overrides.at("bar").get<std::string>(), "bar");
|
||||
}
|
||||
|
||||
TEST_F(TestNodeParameters, complicated_wildcards)
|
||||
{
|
||||
rclcpp::NodeOptions opts;
|
||||
opts.arguments(
|
||||
{
|
||||
"--ros-args",
|
||||
"--params-file", (test_resources_path / "complicated_wildcards.yaml").string()
|
||||
});
|
||||
|
||||
{
|
||||
// regex matched: /**/foo/*/bar
|
||||
std::shared_ptr<rclcpp::Node> node =
|
||||
std::make_shared<rclcpp::Node>("node2", "/a/b/c/foo/d/bar", opts);
|
||||
|
||||
auto * node_parameters =
|
||||
dynamic_cast<rclcpp::node_interfaces::NodeParameters *>(
|
||||
node->get_node_parameters_interface().get());
|
||||
ASSERT_NE(nullptr, node_parameters);
|
||||
|
||||
const auto & parameter_overrides = node_parameters->get_parameter_overrides();
|
||||
EXPECT_EQ(2u, parameter_overrides.size());
|
||||
EXPECT_EQ(parameter_overrides.at("foo").get<std::string>(), "foo");
|
||||
EXPECT_EQ(parameter_overrides.at("bar").get<std::string>(), "bar");
|
||||
}
|
||||
|
||||
{
|
||||
// regex not matched: /**/foo/*/bar
|
||||
std::shared_ptr<rclcpp::Node> node =
|
||||
std::make_shared<rclcpp::Node>("node2", "/a/b/c/foo/bar", opts);
|
||||
|
||||
auto * node_parameters =
|
||||
dynamic_cast<rclcpp::node_interfaces::NodeParameters *>(
|
||||
node->get_node_parameters_interface().get());
|
||||
ASSERT_NE(nullptr, node_parameters);
|
||||
|
||||
const auto & parameter_overrides = node_parameters->get_parameter_overrides();
|
||||
EXPECT_EQ(0u, parameter_overrides.size());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,8 +71,6 @@ public:
|
||||
|
||||
void handle_message(std::shared_ptr<void> &, const rclcpp::MessageInfo &) override {}
|
||||
void handle_loaned_message(void *, const rclcpp::MessageInfo &) override {}
|
||||
void handle_serialized_message(
|
||||
const std::shared_ptr<rclcpp::SerializedMessage> &, const rclcpp::MessageInfo &) override {}
|
||||
void return_message(std::shared_ptr<void> &) override {}
|
||||
void return_serialized_message(std::shared_ptr<rclcpp::SerializedMessage> &) override {}
|
||||
};
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
|
||||
#include "rclcpp/scope_exit.hpp"
|
||||
#include "rclcpp/strategies/allocator_memory_strategy.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base.hpp"
|
||||
#include "test_msgs/msg/empty.hpp"
|
||||
#include "test_msgs/srv/empty.hpp"
|
||||
|
||||
@@ -114,12 +115,11 @@ protected:
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>(name, "ns");
|
||||
|
||||
for (auto & group_weak_ptr : node->get_callback_groups()) {
|
||||
auto group = group_weak_ptr.lock();
|
||||
if (group) {
|
||||
node->for_each_callback_group(
|
||||
[](rclcpp::CallbackGroup::SharedPtr group)
|
||||
{
|
||||
group->can_be_taken_from() = false;
|
||||
}
|
||||
}
|
||||
});
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -201,15 +201,13 @@ protected:
|
||||
const RclWaitSetSizes & expected)
|
||||
{
|
||||
WeakCallbackGroupsToNodesMap weak_groups_to_nodes;
|
||||
auto callback_groups = node->get_node_base_interface()->get_callback_groups();
|
||||
std::for_each(
|
||||
callback_groups.begin(), callback_groups.end(),
|
||||
[&weak_groups_to_nodes,
|
||||
&node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
|
||||
node->for_each_callback_group(
|
||||
[node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
|
||||
{
|
||||
weak_groups_to_nodes.insert(
|
||||
std::pair<rclcpp::CallbackGroup::WeakPtr,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
|
||||
weak_group_ptr,
|
||||
group_ptr,
|
||||
node->get_node_base_interface()));
|
||||
});
|
||||
allocator_memory_strategy()->collect_entities(weak_groups_to_nodes);
|
||||
@@ -234,15 +232,13 @@ protected:
|
||||
const RclWaitSetSizes & insufficient_capacities)
|
||||
{
|
||||
WeakCallbackGroupsToNodesMap weak_groups_to_nodes;
|
||||
auto callback_groups = node->get_node_base_interface()->get_callback_groups();
|
||||
std::for_each(
|
||||
callback_groups.begin(), callback_groups.end(),
|
||||
[&weak_groups_to_nodes,
|
||||
&node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
|
||||
node->for_each_callback_group(
|
||||
[node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
|
||||
{
|
||||
weak_groups_to_nodes.insert(
|
||||
std::pair<rclcpp::CallbackGroup::WeakPtr,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
|
||||
weak_group_ptr,
|
||||
group_ptr,
|
||||
node->get_node_base_interface()));
|
||||
});
|
||||
allocator_memory_strategy()->collect_entities(weak_groups_to_nodes);
|
||||
@@ -316,26 +312,22 @@ protected:
|
||||
{
|
||||
auto basic_node = create_node_with_disabled_callback_groups("basic_node");
|
||||
WeakCallbackGroupsToNodesMap weak_groups_to_nodes;
|
||||
auto callback_groups = basic_node->get_node_base_interface()->get_callback_groups();
|
||||
std::for_each(
|
||||
callback_groups.begin(), callback_groups.end(),
|
||||
[&weak_groups_to_nodes,
|
||||
&basic_node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
|
||||
basic_node->for_each_callback_group(
|
||||
[basic_node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
|
||||
{
|
||||
weak_groups_to_nodes.insert(
|
||||
std::pair<rclcpp::CallbackGroup::WeakPtr,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
|
||||
weak_group_ptr,
|
||||
group_ptr,
|
||||
basic_node->get_node_base_interface()));
|
||||
});
|
||||
auto callback_groups1 = node_with_entity1->get_node_base_interface()->get_callback_groups();
|
||||
std::for_each(
|
||||
callback_groups1.begin(), callback_groups1.end(),
|
||||
[&weak_groups_to_nodes,
|
||||
&node_with_entity1](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
|
||||
node_with_entity1->for_each_callback_group(
|
||||
[node_with_entity1, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
|
||||
{
|
||||
weak_groups_to_nodes.insert(
|
||||
std::pair<rclcpp::CallbackGroup::WeakPtr,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
|
||||
weak_group_ptr,
|
||||
group_ptr,
|
||||
node_with_entity1->get_node_base_interface()));
|
||||
});
|
||||
allocator_memory_strategy()->collect_entities(weak_groups_to_nodes);
|
||||
@@ -348,26 +340,23 @@ protected:
|
||||
|
||||
auto basic_node2 = std::make_shared<rclcpp::Node>("basic_node2", "ns");
|
||||
WeakCallbackGroupsToNodesMap weak_groups_to_uncollected_nodes;
|
||||
auto callback_groups2 = basic_node2->get_node_base_interface()->get_callback_groups();
|
||||
std::for_each(
|
||||
callback_groups2.begin(), callback_groups2.end(),
|
||||
[&weak_groups_to_uncollected_nodes,
|
||||
&basic_node2](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
|
||||
basic_node2->for_each_callback_group(
|
||||
[basic_node2, &weak_groups_to_uncollected_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
|
||||
{
|
||||
weak_groups_to_uncollected_nodes.insert(
|
||||
std::pair<rclcpp::CallbackGroup::WeakPtr,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
|
||||
weak_group_ptr,
|
||||
group_ptr,
|
||||
basic_node2->get_node_base_interface()));
|
||||
});
|
||||
auto callback_groups3 = node_with_entity2->get_node_base_interface()->get_callback_groups();
|
||||
std::for_each(
|
||||
callback_groups3.begin(), callback_groups3.end(),
|
||||
[&weak_groups_to_uncollected_nodes,
|
||||
&node_with_entity2](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
|
||||
node_with_entity2->for_each_callback_group(
|
||||
[node_with_entity2,
|
||||
&weak_groups_to_uncollected_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
|
||||
{
|
||||
weak_groups_to_uncollected_nodes.insert(
|
||||
std::pair<rclcpp::CallbackGroup::WeakPtr,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
|
||||
weak_group_ptr,
|
||||
group_ptr,
|
||||
node_with_entity2->get_node_base_interface()));
|
||||
});
|
||||
rclcpp::AnyExecutable failed_result = get_next_entity_func(weak_groups_to_uncollected_nodes);
|
||||
@@ -388,24 +377,24 @@ protected:
|
||||
auto basic_node_base = basic_node->get_node_base_interface();
|
||||
auto node_base = node_with_entity->get_node_base_interface();
|
||||
WeakCallbackGroupsToNodesMap weak_groups_to_nodes;
|
||||
auto callback_groups = basic_node_base->get_callback_groups();
|
||||
std::for_each(
|
||||
callback_groups.begin(), callback_groups.end(),
|
||||
[&weak_groups_to_nodes, &basic_node_base](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
|
||||
rclcpp::node_interfaces::global_for_each_callback_group(
|
||||
basic_node_base.get(),
|
||||
[basic_node_base, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
|
||||
{
|
||||
weak_groups_to_nodes.insert(
|
||||
std::pair<rclcpp::CallbackGroup::WeakPtr,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
|
||||
weak_group_ptr,
|
||||
group_ptr,
|
||||
basic_node_base));
|
||||
});
|
||||
callback_groups = node_base->get_callback_groups();
|
||||
std::for_each(
|
||||
callback_groups.begin(), callback_groups.end(),
|
||||
[&weak_groups_to_nodes, &node_base](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
|
||||
rclcpp::node_interfaces::global_for_each_callback_group(
|
||||
node_base.get(),
|
||||
[node_base, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
|
||||
{
|
||||
weak_groups_to_nodes.insert(
|
||||
std::pair<rclcpp::CallbackGroup::WeakPtr,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
|
||||
weak_group_ptr,
|
||||
group_ptr,
|
||||
node_base));
|
||||
});
|
||||
allocator_memory_strategy()->collect_entities(weak_groups_to_nodes);
|
||||
@@ -447,14 +436,13 @@ private:
|
||||
TEST_F(TestAllocatorMemoryStrategy, construct_destruct) {
|
||||
auto basic_node = create_node_with_disabled_callback_groups("basic_node");
|
||||
WeakCallbackGroupsToNodesMap weak_groups_to_nodes;
|
||||
auto callback_groups = basic_node->get_node_base_interface()->get_callback_groups();
|
||||
std::for_each(
|
||||
callback_groups.begin(), callback_groups.end(),
|
||||
[&weak_groups_to_nodes, &basic_node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
|
||||
basic_node->for_each_callback_group(
|
||||
[basic_node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
|
||||
{
|
||||
weak_groups_to_nodes.insert(
|
||||
std::pair<rclcpp::CallbackGroup::WeakPtr,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
|
||||
weak_group_ptr,
|
||||
group_ptr,
|
||||
basic_node->get_node_base_interface()));
|
||||
});
|
||||
allocator_memory_strategy()->collect_entities(weak_groups_to_nodes);
|
||||
@@ -546,14 +534,13 @@ TEST_F(TestAllocatorMemoryStrategy, number_of_entities_with_timer) {
|
||||
TEST_F(TestAllocatorMemoryStrategy, add_handles_to_wait_set_bad_arguments) {
|
||||
auto node = create_node_with_subscription("subscription_node");
|
||||
WeakCallbackGroupsToNodesMap weak_groups_to_nodes;
|
||||
auto callback_groups = node->get_node_base_interface()->get_callback_groups();
|
||||
std::for_each(
|
||||
callback_groups.begin(), callback_groups.end(),
|
||||
[&weak_groups_to_nodes, &node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
|
||||
node->for_each_callback_group(
|
||||
[node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
|
||||
{
|
||||
weak_groups_to_nodes.insert(
|
||||
std::pair<rclcpp::CallbackGroup::WeakPtr,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
|
||||
weak_group_ptr,
|
||||
group_ptr,
|
||||
node->get_node_base_interface()));
|
||||
});
|
||||
allocator_memory_strategy()->collect_entities(weak_groups_to_nodes);
|
||||
@@ -787,14 +774,13 @@ TEST_F(TestAllocatorMemoryStrategy, get_next_subscription_out_of_scope) {
|
||||
test_msgs::msg::Empty, decltype(subscription_callback)>(
|
||||
"topic", qos, std::move(subscription_callback), subscription_options);
|
||||
|
||||
auto callback_groups = node->get_node_base_interface()->get_callback_groups();
|
||||
std::for_each(
|
||||
callback_groups.begin(), callback_groups.end(),
|
||||
[&weak_groups_to_nodes, &node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
|
||||
node->for_each_callback_group(
|
||||
[node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
|
||||
{
|
||||
weak_groups_to_nodes.insert(
|
||||
std::pair<rclcpp::CallbackGroup::WeakPtr,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
|
||||
weak_group_ptr,
|
||||
group_ptr,
|
||||
node->get_node_base_interface()));
|
||||
});
|
||||
allocator_memory_strategy()->collect_entities(weak_groups_to_nodes);
|
||||
@@ -821,14 +807,13 @@ TEST_F(TestAllocatorMemoryStrategy, get_next_service_out_of_scope) {
|
||||
auto service = node->create_service<test_msgs::srv::Empty>(
|
||||
"service", std::move(service_callback), rmw_qos_profile_services_default, callback_group);
|
||||
|
||||
auto callback_groups = node->get_node_base_interface()->get_callback_groups();
|
||||
std::for_each(
|
||||
callback_groups.begin(), callback_groups.end(),
|
||||
[&weak_groups_to_nodes, &node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
|
||||
node->for_each_callback_group(
|
||||
[node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
|
||||
{
|
||||
weak_groups_to_nodes.insert(
|
||||
std::pair<rclcpp::CallbackGroup::WeakPtr,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
|
||||
weak_group_ptr,
|
||||
group_ptr,
|
||||
node->get_node_base_interface()));
|
||||
});
|
||||
allocator_memory_strategy()->collect_entities(weak_groups_to_nodes);
|
||||
@@ -843,14 +828,13 @@ TEST_F(TestAllocatorMemoryStrategy, get_next_service_out_of_scope) {
|
||||
TEST_F(TestAllocatorMemoryStrategy, get_next_client_out_of_scope) {
|
||||
auto node = create_node_with_disabled_callback_groups("node");
|
||||
WeakCallbackGroupsToNodesMap weak_groups_to_nodes;
|
||||
auto callback_groups = node->get_node_base_interface()->get_callback_groups();
|
||||
std::for_each(
|
||||
callback_groups.begin(), callback_groups.end(),
|
||||
[&weak_groups_to_nodes, &node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
|
||||
node->for_each_callback_group(
|
||||
[node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
|
||||
{
|
||||
weak_groups_to_nodes.insert(
|
||||
std::pair<rclcpp::CallbackGroup::WeakPtr,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
|
||||
weak_group_ptr,
|
||||
group_ptr,
|
||||
node->get_node_base_interface()));
|
||||
});
|
||||
// Force client to go out of scope and cleanup after collecting entities.
|
||||
@@ -886,14 +870,13 @@ TEST_F(TestAllocatorMemoryStrategy, get_next_timer_out_of_scope) {
|
||||
rclcpp::CallbackGroupType::MutuallyExclusive);
|
||||
auto timer = node->create_wall_timer(
|
||||
std::chrono::seconds(10), []() {}, callback_group);
|
||||
auto callback_groups = node->get_node_base_interface()->get_callback_groups();
|
||||
std::for_each(
|
||||
callback_groups.begin(), callback_groups.end(),
|
||||
[&weak_groups_to_nodes, &node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
|
||||
node->for_each_callback_group(
|
||||
[node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
|
||||
{
|
||||
weak_groups_to_nodes.insert(
|
||||
std::pair<rclcpp::CallbackGroup::WeakPtr,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
|
||||
weak_group_ptr,
|
||||
group_ptr,
|
||||
node->get_node_base_interface()));
|
||||
});
|
||||
allocator_memory_strategy()->collect_entities(weak_groups_to_nodes);
|
||||
@@ -913,14 +896,13 @@ TEST_F(TestAllocatorMemoryStrategy, get_next_waitable_out_of_scope) {
|
||||
auto callback_group =
|
||||
node->create_callback_group(
|
||||
rclcpp::CallbackGroupType::MutuallyExclusive);
|
||||
auto callback_groups = node->get_node_base_interface()->get_callback_groups();
|
||||
std::for_each(
|
||||
callback_groups.begin(), callback_groups.end(),
|
||||
[&weak_groups_to_nodes, &node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
|
||||
node->for_each_callback_group(
|
||||
[node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
|
||||
{
|
||||
weak_groups_to_nodes.insert(
|
||||
std::pair<rclcpp::CallbackGroup::WeakPtr,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
|
||||
weak_group_ptr,
|
||||
group_ptr,
|
||||
node->get_node_base_interface()));
|
||||
});
|
||||
allocator_memory_strategy()->collect_entities(weak_groups_to_nodes);
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include <utility>
|
||||
|
||||
#include "rclcpp/any_service_callback.hpp"
|
||||
#include "rclcpp/service.hpp"
|
||||
#include "test_msgs/srv/empty.hpp"
|
||||
#include "test_msgs/srv/empty.h"
|
||||
|
||||
@@ -45,7 +44,7 @@ protected:
|
||||
|
||||
TEST_F(TestAnyServiceCallback, no_set_and_dispatch_throw) {
|
||||
EXPECT_THROW(
|
||||
any_service_callback_.dispatch(nullptr, request_header_, request_),
|
||||
any_service_callback_.dispatch(request_header_, request_, response_),
|
||||
std::runtime_error);
|
||||
}
|
||||
|
||||
@@ -58,7 +57,7 @@ TEST_F(TestAnyServiceCallback, set_and_dispatch_no_header) {
|
||||
|
||||
any_service_callback_.set(callback);
|
||||
EXPECT_NO_THROW(
|
||||
EXPECT_NE(nullptr, any_service_callback_.dispatch(nullptr, request_header_, request_)));
|
||||
any_service_callback_.dispatch(request_header_, request_, response_));
|
||||
EXPECT_EQ(callback_calls, 1);
|
||||
}
|
||||
|
||||
@@ -74,36 +73,6 @@ TEST_F(TestAnyServiceCallback, set_and_dispatch_header) {
|
||||
|
||||
any_service_callback_.set(callback_with_header);
|
||||
EXPECT_NO_THROW(
|
||||
EXPECT_NE(nullptr, any_service_callback_.dispatch(nullptr, request_header_, request_)));
|
||||
EXPECT_EQ(callback_with_header_calls, 1);
|
||||
}
|
||||
|
||||
TEST_F(TestAnyServiceCallback, set_and_dispatch_defered) {
|
||||
int callback_with_header_calls = 0;
|
||||
auto callback_with_header =
|
||||
[&callback_with_header_calls](const std::shared_ptr<rmw_request_id_t>,
|
||||
const std::shared_ptr<test_msgs::srv::Empty::Request>) {
|
||||
callback_with_header_calls++;
|
||||
};
|
||||
|
||||
any_service_callback_.set(callback_with_header);
|
||||
EXPECT_NO_THROW(
|
||||
EXPECT_EQ(nullptr, any_service_callback_.dispatch(nullptr, request_header_, request_)));
|
||||
EXPECT_EQ(callback_with_header_calls, 1);
|
||||
}
|
||||
|
||||
TEST_F(TestAnyServiceCallback, set_and_dispatch_defered_with_service_handle) {
|
||||
int callback_with_header_calls = 0;
|
||||
auto callback_with_header =
|
||||
[&callback_with_header_calls](std::shared_ptr<rclcpp::Service<test_msgs::srv::Empty>>,
|
||||
const std::shared_ptr<rmw_request_id_t>,
|
||||
const std::shared_ptr<test_msgs::srv::Empty::Request>)
|
||||
{
|
||||
callback_with_header_calls++;
|
||||
};
|
||||
|
||||
any_service_callback_.set(callback_with_header);
|
||||
EXPECT_NO_THROW(
|
||||
EXPECT_EQ(nullptr, any_service_callback_.dispatch(nullptr, request_header_, request_)));
|
||||
any_service_callback_.dispatch(request_header_, request_, response_));
|
||||
EXPECT_EQ(callback_with_header_calls, 1);
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ void construct_with_null_allocator()
|
||||
TEST(AnySubscriptionCallback, null_allocator) {
|
||||
EXPECT_THROW(
|
||||
construct_with_null_allocator(),
|
||||
std::invalid_argument);
|
||||
std::runtime_error);
|
||||
}
|
||||
|
||||
TEST_F(TestAnySubscriptionCallback, construct_destruct) {
|
||||
@@ -95,69 +95,44 @@ TEST_F(TestAnySubscriptionCallback, unset_dispatch_throw) {
|
||||
// Parameterized test to test across all callback types and dispatch types.
|
||||
//
|
||||
|
||||
// Type adapter to be used in tests.
|
||||
struct MyEmpty {};
|
||||
|
||||
template<>
|
||||
struct rclcpp::TypeAdapter<MyEmpty, test_msgs::msg::Empty>
|
||||
{
|
||||
using is_specialized = std::true_type;
|
||||
using custom_type = MyEmpty;
|
||||
using ros_message_type = test_msgs::msg::Empty;
|
||||
|
||||
static
|
||||
void
|
||||
convert_to_ros_message(const custom_type &, ros_message_type &)
|
||||
{}
|
||||
|
||||
static
|
||||
void
|
||||
convert_to_custom(const ros_message_type &, custom_type &)
|
||||
{}
|
||||
};
|
||||
|
||||
using MyTA = rclcpp::TypeAdapter<MyEmpty, test_msgs::msg::Empty>;
|
||||
|
||||
template<typename MessageT>
|
||||
class InstanceContextImpl
|
||||
{
|
||||
public:
|
||||
InstanceContextImpl() = default;
|
||||
virtual ~InstanceContextImpl() = default;
|
||||
|
||||
explicit InstanceContextImpl(rclcpp::AnySubscriptionCallback<MessageT> asc)
|
||||
explicit InstanceContextImpl(rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty> asc)
|
||||
: any_subscription_callback_(asc)
|
||||
{}
|
||||
|
||||
virtual
|
||||
rclcpp::AnySubscriptionCallback<MessageT>
|
||||
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty>
|
||||
get_any_subscription_callback_to_test() const
|
||||
{
|
||||
return any_subscription_callback_;
|
||||
}
|
||||
|
||||
protected:
|
||||
rclcpp::AnySubscriptionCallback<MessageT> any_subscription_callback_;
|
||||
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty> any_subscription_callback_;
|
||||
};
|
||||
|
||||
template<typename MessageT>
|
||||
class InstanceContext
|
||||
{
|
||||
public:
|
||||
InstanceContext(const std::string & name, std::shared_ptr<InstanceContextImpl<MessageT>> impl)
|
||||
InstanceContext(const std::string & name, std::shared_ptr<InstanceContextImpl> impl)
|
||||
: name(name), impl_(impl)
|
||||
{}
|
||||
|
||||
InstanceContext(
|
||||
const std::string & name,
|
||||
rclcpp::AnySubscriptionCallback<MessageT> asc)
|
||||
: name(name), impl_(std::make_shared<InstanceContextImpl<MessageT>>(asc))
|
||||
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty> asc)
|
||||
: name(name), impl_(std::make_shared<InstanceContextImpl>(asc))
|
||||
{}
|
||||
|
||||
InstanceContext(const InstanceContext & other)
|
||||
: InstanceContext(other.name, other.impl_) {}
|
||||
|
||||
rclcpp::AnySubscriptionCallback<MessageT>
|
||||
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty>
|
||||
get_any_subscription_callback_to_test() const
|
||||
{
|
||||
return impl_->get_any_subscription_callback_to_test();
|
||||
@@ -166,17 +141,12 @@ public:
|
||||
std::string name;
|
||||
|
||||
protected:
|
||||
std::shared_ptr<InstanceContextImpl<MessageT>> impl_;
|
||||
std::shared_ptr<InstanceContextImpl> impl_;
|
||||
};
|
||||
|
||||
class DispatchTests
|
||||
: public TestAnySubscriptionCallback,
|
||||
public ::testing::WithParamInterface<InstanceContext<test_msgs::msg::Empty>>
|
||||
{};
|
||||
|
||||
class DispatchTestsWithTA
|
||||
: public TestAnySubscriptionCallback,
|
||||
public ::testing::WithParamInterface<InstanceContext<MyTA>>
|
||||
public ::testing::WithParamInterface<InstanceContext>
|
||||
{};
|
||||
|
||||
auto
|
||||
@@ -185,67 +155,57 @@ format_parameter(const ::testing::TestParamInfo<DispatchTests::ParamType> & info
|
||||
return info.param.name;
|
||||
}
|
||||
|
||||
auto
|
||||
format_parameter_with_ta(const ::testing::TestParamInfo<DispatchTestsWithTA::ParamType> & info)
|
||||
{
|
||||
return info.param.name;
|
||||
// Testing dispatch with shared_ptr<MessageT> as input
|
||||
TEST_P(DispatchTests, test_inter_shared_dispatch) {
|
||||
auto any_subscription_callback_to_test = GetParam().get_any_subscription_callback_to_test();
|
||||
any_subscription_callback_to_test.dispatch(msg_shared_ptr_, message_info_);
|
||||
}
|
||||
|
||||
#define PARAMETERIZED_TESTS(DispatchTests_name) \
|
||||
/* Testing dispatch with shared_ptr<MessageT> as input */ \
|
||||
TEST_P(DispatchTests_name, test_inter_shared_dispatch) { \
|
||||
auto any_subscription_callback_to_test = GetParam().get_any_subscription_callback_to_test(); \
|
||||
any_subscription_callback_to_test.dispatch(msg_shared_ptr_, message_info_); \
|
||||
} \
|
||||
\
|
||||
/* Testing dispatch with shared_ptr<const MessageT> as input */ \
|
||||
TEST_P(DispatchTests_name, test_intra_shared_dispatch) { \
|
||||
auto any_subscription_callback_to_test = GetParam().get_any_subscription_callback_to_test(); \
|
||||
any_subscription_callback_to_test.dispatch_intra_process(msg_shared_ptr_, message_info_); \
|
||||
} \
|
||||
\
|
||||
/* Testing dispatch with unique_ptr<MessageT> as input */ \
|
||||
TEST_P(DispatchTests_name, test_intra_unique_dispatch) { \
|
||||
auto any_subscription_callback_to_test = GetParam().get_any_subscription_callback_to_test(); \
|
||||
any_subscription_callback_to_test.dispatch_intra_process(get_unique_ptr_msg(), message_info_); \
|
||||
}
|
||||
// Testing dispatch with shared_ptr<const MessageT> as input
|
||||
TEST_P(DispatchTests, test_intra_shared_dispatch) {
|
||||
auto any_subscription_callback_to_test = GetParam().get_any_subscription_callback_to_test();
|
||||
any_subscription_callback_to_test.dispatch_intra_process(msg_shared_ptr_, message_info_);
|
||||
}
|
||||
|
||||
PARAMETERIZED_TESTS(DispatchTests)
|
||||
PARAMETERIZED_TESTS(DispatchTestsWithTA)
|
||||
// Testing dispatch with unique_ptr<MessageT> as input
|
||||
TEST_P(DispatchTests, test_intra_unique_dispatch) {
|
||||
auto any_subscription_callback_to_test = GetParam().get_any_subscription_callback_to_test();
|
||||
any_subscription_callback_to_test.dispatch_intra_process(get_unique_ptr_msg(), message_info_);
|
||||
}
|
||||
|
||||
// Generic classes for testing callbacks using std::bind to class methods.
|
||||
template<typename MessageT, typename ... CallbackArgs>
|
||||
class BindContextImpl : public InstanceContextImpl<MessageT>
|
||||
template<typename ... CallbackArgs>
|
||||
class BindContextImpl : public InstanceContextImpl
|
||||
{
|
||||
static constexpr size_t number_of_callback_args{sizeof...(CallbackArgs)};
|
||||
|
||||
public:
|
||||
using InstanceContextImpl<MessageT>::InstanceContextImpl;
|
||||
using InstanceContextImpl::InstanceContextImpl;
|
||||
virtual ~BindContextImpl() = default;
|
||||
|
||||
void on_message(CallbackArgs ...) const {}
|
||||
|
||||
rclcpp::AnySubscriptionCallback<MessageT>
|
||||
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty>
|
||||
get_any_subscription_callback_to_test() const override
|
||||
{
|
||||
if constexpr (number_of_callback_args == 1) {
|
||||
return rclcpp::AnySubscriptionCallback<MessageT>().set(
|
||||
return rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty>().set(
|
||||
std::bind(&BindContextImpl::on_message, this, std::placeholders::_1)
|
||||
);
|
||||
} else {
|
||||
return rclcpp::AnySubscriptionCallback<MessageT>().set(
|
||||
return rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty>().set(
|
||||
std::bind(&BindContextImpl::on_message, this, std::placeholders::_1, std::placeholders::_2)
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename MessageT, typename ... CallbackArgs>
|
||||
class BindContext : public InstanceContext<MessageT>
|
||||
template<typename ... CallbackArgs>
|
||||
class BindContext : public InstanceContext
|
||||
{
|
||||
public:
|
||||
explicit BindContext(const std::string & name)
|
||||
: InstanceContext<MessageT>(name, std::make_shared<BindContextImpl<MessageT, CallbackArgs ...>>())
|
||||
: InstanceContext(name, std::make_shared<BindContextImpl<CallbackArgs ...>>())
|
||||
{}
|
||||
};
|
||||
|
||||
@@ -272,53 +232,13 @@ INSTANTIATE_TEST_SUITE_P(
|
||||
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty>().set(
|
||||
const_ref_w_info_free_func)},
|
||||
// bind function
|
||||
BindContext<test_msgs::msg::Empty, const test_msgs::msg::Empty &>("bind_method"),
|
||||
BindContext<test_msgs::msg::Empty, const test_msgs::msg::Empty &, const rclcpp::MessageInfo &>(
|
||||
BindContext<const test_msgs::msg::Empty &>("bind_method"),
|
||||
BindContext<const test_msgs::msg::Empty &, const rclcpp::MessageInfo &>(
|
||||
"bind_method_with_info")
|
||||
),
|
||||
format_parameter
|
||||
);
|
||||
|
||||
void const_ref_ta_free_func(const MyEmpty &) {}
|
||||
void const_ref_ta_w_info_free_func(const MyEmpty &, const rclcpp::MessageInfo &) {}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
ConstRefTACallbackTests,
|
||||
DispatchTestsWithTA,
|
||||
::testing::Values(
|
||||
// lambda
|
||||
InstanceContext<MyTA>{"lambda_ta", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](const MyEmpty &) {})},
|
||||
InstanceContext<MyTA>{"lambda_ta_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](const MyEmpty &, const rclcpp::MessageInfo &) {})},
|
||||
InstanceContext<MyTA>{"lambda", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](const test_msgs::msg::Empty &) {})},
|
||||
InstanceContext<MyTA>{"lambda_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](const test_msgs::msg::Empty &, const rclcpp::MessageInfo &) {})},
|
||||
// free function
|
||||
InstanceContext<MyTA>{"free_function_ta", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
const_ref_ta_free_func)},
|
||||
InstanceContext<MyTA>{"free_function_ta_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
const_ref_ta_w_info_free_func)},
|
||||
InstanceContext<MyTA>{"free_function", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
const_ref_free_func)},
|
||||
InstanceContext<MyTA>{"free_function_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
const_ref_w_info_free_func)},
|
||||
// bind function
|
||||
BindContext<MyTA, const MyEmpty &>("bind_method_ta"),
|
||||
BindContext<MyTA, const MyEmpty &, const rclcpp::MessageInfo &>(
|
||||
"bind_method_ta_with_info"),
|
||||
BindContext<MyTA, const test_msgs::msg::Empty &>("bind_method"),
|
||||
BindContext<MyTA, const test_msgs::msg::Empty &, const rclcpp::MessageInfo &>(
|
||||
"bind_method_with_info")
|
||||
),
|
||||
format_parameter_with_ta
|
||||
);
|
||||
|
||||
//
|
||||
// Versions of `std::unique_ptr<MessageT, MessageDeleter>`
|
||||
//
|
||||
@@ -344,54 +264,11 @@ INSTANTIATE_TEST_SUITE_P(
|
||||
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty>().set(
|
||||
unique_ptr_w_info_free_func)},
|
||||
// bind function
|
||||
BindContext<test_msgs::msg::Empty, std::unique_ptr<test_msgs::msg::Empty>>("bind_method"),
|
||||
BindContext<
|
||||
test_msgs::msg::Empty,
|
||||
std::unique_ptr<test_msgs::msg::Empty>,
|
||||
const rclcpp::MessageInfo &
|
||||
>("bind_method_with_info")
|
||||
),
|
||||
format_parameter
|
||||
);
|
||||
|
||||
void unique_ptr_ta_free_func(std::unique_ptr<MyEmpty>) {}
|
||||
void unique_ptr_ta_w_info_free_func(std::unique_ptr<MyEmpty>, const rclcpp::MessageInfo &) {}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
UniquePtrCallbackTests,
|
||||
DispatchTestsWithTA,
|
||||
::testing::Values(
|
||||
// lambda
|
||||
InstanceContext<MyTA>{"lambda_ta", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](std::unique_ptr<MyEmpty>) {})},
|
||||
InstanceContext<MyTA>{"lambda_ta_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](std::unique_ptr<MyEmpty>, const rclcpp::MessageInfo &) {})},
|
||||
InstanceContext<MyTA>{"lambda", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](std::unique_ptr<test_msgs::msg::Empty>) {})},
|
||||
InstanceContext<MyTA>{"lambda_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](std::unique_ptr<test_msgs::msg::Empty>, const rclcpp::MessageInfo &) {})},
|
||||
// free function
|
||||
InstanceContext<MyTA>{"free_function_ta", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
unique_ptr_ta_free_func)},
|
||||
InstanceContext<MyTA>{"free_function_ta_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
unique_ptr_ta_w_info_free_func)},
|
||||
InstanceContext<MyTA>{"free_function", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
unique_ptr_free_func)},
|
||||
InstanceContext<MyTA>{"free_function_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
unique_ptr_w_info_free_func)},
|
||||
// bind function
|
||||
BindContext<MyTA, std::unique_ptr<test_msgs::msg::Empty>>("bind_method_ta"),
|
||||
BindContext<MyTA, std::unique_ptr<test_msgs::msg::Empty>, const rclcpp::MessageInfo &>(
|
||||
"bind_method_ta_with_info"),
|
||||
BindContext<MyTA, std::unique_ptr<test_msgs::msg::Empty>>("bind_method"),
|
||||
BindContext<MyTA, std::unique_ptr<test_msgs::msg::Empty>, const rclcpp::MessageInfo &>(
|
||||
BindContext<std::unique_ptr<test_msgs::msg::Empty>>("bind_method"),
|
||||
BindContext<std::unique_ptr<test_msgs::msg::Empty>, const rclcpp::MessageInfo &>(
|
||||
"bind_method_with_info")
|
||||
),
|
||||
format_parameter_with_ta
|
||||
format_parameter
|
||||
);
|
||||
|
||||
//
|
||||
@@ -419,56 +296,13 @@ INSTANTIATE_TEST_SUITE_P(
|
||||
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty>().set(
|
||||
shared_const_ptr_w_info_free_func)},
|
||||
// bind function
|
||||
BindContext<test_msgs::msg::Empty, std::shared_ptr<const test_msgs::msg::Empty>>("bind_method"),
|
||||
BindContext<test_msgs::msg::Empty, std::shared_ptr<const test_msgs::msg::Empty>,
|
||||
const rclcpp::MessageInfo &>(
|
||||
BindContext<std::shared_ptr<const test_msgs::msg::Empty>>("bind_method"),
|
||||
BindContext<std::shared_ptr<const test_msgs::msg::Empty>, const rclcpp::MessageInfo &>(
|
||||
"bind_method_with_info")
|
||||
),
|
||||
format_parameter
|
||||
);
|
||||
|
||||
void shared_const_ptr_ta_free_func(std::shared_ptr<const MyEmpty>) {}
|
||||
void shared_const_ptr_ta_w_info_free_func(
|
||||
std::shared_ptr<const MyEmpty>, const rclcpp::MessageInfo &)
|
||||
{}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
SharedConstPtrCallbackTests,
|
||||
DispatchTestsWithTA,
|
||||
::testing::Values(
|
||||
// lambda
|
||||
InstanceContext<MyTA>{"lambda_ta", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](std::shared_ptr<const MyEmpty>) {})},
|
||||
InstanceContext<MyTA>{"lambda_ta_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](std::shared_ptr<const MyEmpty>, const rclcpp::MessageInfo &) {})},
|
||||
InstanceContext<MyTA>{"lambda", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](std::shared_ptr<const test_msgs::msg::Empty>) {})},
|
||||
InstanceContext<MyTA>{"lambda_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](std::shared_ptr<const test_msgs::msg::Empty>, const rclcpp::MessageInfo &) {})},
|
||||
// free function
|
||||
InstanceContext<MyTA>{"free_function_ta", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
shared_const_ptr_ta_free_func)},
|
||||
InstanceContext<MyTA>{"free_function_ta_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
shared_const_ptr_ta_w_info_free_func)},
|
||||
InstanceContext<MyTA>{"free_function", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
shared_const_ptr_free_func)},
|
||||
InstanceContext<MyTA>{"free_function_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
shared_const_ptr_w_info_free_func)},
|
||||
// bind function
|
||||
BindContext<MyTA, std::shared_ptr<const MyEmpty>>("bind_method_ta"),
|
||||
BindContext<MyTA, std::shared_ptr<const MyEmpty>, const rclcpp::MessageInfo &>(
|
||||
"bind_method_ta_with_info"),
|
||||
BindContext<MyTA, std::shared_ptr<const test_msgs::msg::Empty>>("bind_method"),
|
||||
BindContext<MyTA, std::shared_ptr<const test_msgs::msg::Empty>, const rclcpp::MessageInfo &>(
|
||||
"bind_method_with_info")
|
||||
),
|
||||
format_parameter_with_ta
|
||||
);
|
||||
|
||||
//
|
||||
// Versions of `const std::shared_ptr<const MessageT> &`
|
||||
//
|
||||
@@ -494,58 +328,13 @@ INSTANTIATE_TEST_SUITE_P(
|
||||
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty>().set(
|
||||
const_ref_shared_const_ptr_w_info_free_func)},
|
||||
// bind function
|
||||
BindContext<test_msgs::msg::Empty,
|
||||
const std::shared_ptr<const test_msgs::msg::Empty> &>("bind_method"),
|
||||
BindContext<test_msgs::msg::Empty, const std::shared_ptr<const test_msgs::msg::Empty> &,
|
||||
const rclcpp::MessageInfo &>(
|
||||
BindContext<const std::shared_ptr<const test_msgs::msg::Empty> &>("bind_method"),
|
||||
BindContext<const std::shared_ptr<const test_msgs::msg::Empty> &, const rclcpp::MessageInfo &>(
|
||||
"bind_method_with_info")
|
||||
),
|
||||
format_parameter
|
||||
);
|
||||
|
||||
void const_ref_shared_const_ptr_ta_free_func(const std::shared_ptr<const MyEmpty> &) {}
|
||||
void const_ref_shared_const_ptr_ta_w_info_free_func(
|
||||
const std::shared_ptr<const MyEmpty> &, const rclcpp::MessageInfo &)
|
||||
{}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
ConstRefSharedConstPtrCallbackTests,
|
||||
DispatchTestsWithTA,
|
||||
::testing::Values(
|
||||
// lambda
|
||||
InstanceContext<MyTA>{"lambda_ta", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](const std::shared_ptr<const MyEmpty> &) {})},
|
||||
InstanceContext<MyTA>{"lambda_ta_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](const std::shared_ptr<const MyEmpty> &, const rclcpp::MessageInfo &) {})},
|
||||
InstanceContext<MyTA>{"lambda", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](const std::shared_ptr<const test_msgs::msg::Empty> &) {})},
|
||||
InstanceContext<MyTA>{"lambda_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](const std::shared_ptr<const test_msgs::msg::Empty> &, const rclcpp::MessageInfo &) {})},
|
||||
// free function
|
||||
InstanceContext<MyTA>{"free_function_ta", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
const_ref_shared_const_ptr_ta_free_func)},
|
||||
InstanceContext<MyTA>{"free_function_ta_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
const_ref_shared_const_ptr_ta_w_info_free_func)},
|
||||
InstanceContext<MyTA>{"free_function", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
const_ref_shared_const_ptr_free_func)},
|
||||
InstanceContext<MyTA>{"free_function_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
const_ref_shared_const_ptr_w_info_free_func)},
|
||||
// bind function
|
||||
BindContext<MyTA, const std::shared_ptr<const MyEmpty> &>("bind_method_ta"),
|
||||
BindContext<MyTA, const std::shared_ptr<const MyEmpty> &, const rclcpp::MessageInfo &>(
|
||||
"bind_method_ta_with_info"),
|
||||
BindContext<MyTA, const std::shared_ptr<const test_msgs::msg::Empty> &>("bind_method"),
|
||||
BindContext<MyTA, const std::shared_ptr<const test_msgs::msg::Empty> &,
|
||||
const rclcpp::MessageInfo &>(
|
||||
"bind_method_with_info")
|
||||
),
|
||||
format_parameter_with_ta
|
||||
);
|
||||
|
||||
//
|
||||
// Versions of `std::shared_ptr<MessageT>`
|
||||
//
|
||||
@@ -571,52 +360,9 @@ INSTANTIATE_TEST_SUITE_P(
|
||||
rclcpp::AnySubscriptionCallback<test_msgs::msg::Empty>().set(
|
||||
shared_ptr_w_info_free_func)},
|
||||
// bind function
|
||||
BindContext<test_msgs::msg::Empty, std::shared_ptr<test_msgs::msg::Empty>>("bind_method"),
|
||||
BindContext<test_msgs::msg::Empty, std::shared_ptr<test_msgs::msg::Empty>,
|
||||
const rclcpp::MessageInfo &>(
|
||||
BindContext<std::shared_ptr<test_msgs::msg::Empty>>("bind_method"),
|
||||
BindContext<std::shared_ptr<test_msgs::msg::Empty>, const rclcpp::MessageInfo &>(
|
||||
"bind_method_with_info")
|
||||
),
|
||||
format_parameter
|
||||
);
|
||||
|
||||
void shared_ptr_ta_free_func(std::shared_ptr<MyEmpty>) {}
|
||||
void shared_ptr_ta_w_info_free_func(
|
||||
std::shared_ptr<MyEmpty>, const rclcpp::MessageInfo &)
|
||||
{}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(
|
||||
SharedPtrCallbackTests,
|
||||
DispatchTestsWithTA,
|
||||
::testing::Values(
|
||||
// lambda
|
||||
InstanceContext<MyTA>{"lambda_ta", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](std::shared_ptr<MyEmpty>) {})},
|
||||
InstanceContext<MyTA>{"lambda_ta_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](std::shared_ptr<MyEmpty>, const rclcpp::MessageInfo &) {})},
|
||||
InstanceContext<MyTA>{"lambda", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](std::shared_ptr<test_msgs::msg::Empty>) {})},
|
||||
InstanceContext<MyTA>{"lambda_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
[](std::shared_ptr<test_msgs::msg::Empty>, const rclcpp::MessageInfo &) {})},
|
||||
// free function
|
||||
InstanceContext<MyTA>{"free_function_ta", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
shared_ptr_ta_free_func)},
|
||||
InstanceContext<MyTA>{"free_function_ta_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
shared_ptr_ta_w_info_free_func)},
|
||||
InstanceContext<MyTA>{"free_function", rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
shared_ptr_free_func)},
|
||||
InstanceContext<MyTA>{"free_function_with_info",
|
||||
rclcpp::AnySubscriptionCallback<MyTA>().set(
|
||||
shared_ptr_w_info_free_func)},
|
||||
// bind function
|
||||
BindContext<MyTA, std::shared_ptr<MyEmpty>>("bind_method_ta"),
|
||||
BindContext<MyTA, std::shared_ptr<MyEmpty>, const rclcpp::MessageInfo &>(
|
||||
"bind_method_ta_with_info"),
|
||||
BindContext<MyTA, std::shared_ptr<test_msgs::msg::Empty>>("bind_method"),
|
||||
BindContext<MyTA, std::shared_ptr<test_msgs::msg::Empty>, const rclcpp::MessageInfo &>(
|
||||
"bind_method_with_info")
|
||||
),
|
||||
format_parameter_with_ta
|
||||
);
|
||||
|
||||
@@ -52,8 +52,8 @@ class PublisherBase
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(PublisherBase)
|
||||
|
||||
explicit PublisherBase(rclcpp::QoS qos = rclcpp::QoS(10))
|
||||
: qos_profile(qos),
|
||||
PublisherBase()
|
||||
: qos(rclcpp::QoS(10)),
|
||||
topic_name("topic")
|
||||
{}
|
||||
|
||||
@@ -76,7 +76,7 @@ public:
|
||||
rclcpp::QoS
|
||||
get_actual_qos() const
|
||||
{
|
||||
return qos_profile;
|
||||
return qos;
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -93,7 +93,7 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
rclcpp::QoS qos_profile;
|
||||
rclcpp::QoS qos;
|
||||
std::string topic_name;
|
||||
uint64_t intra_process_publisher_id_;
|
||||
IntraProcessManagerWeakPtr weak_ipm_;
|
||||
@@ -111,9 +111,9 @@ public:
|
||||
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(Publisher<T, Alloc>)
|
||||
|
||||
explicit Publisher(rclcpp::QoS qos = rclcpp::QoS(10))
|
||||
: PublisherBase(qos)
|
||||
Publisher()
|
||||
{
|
||||
qos = rclcpp::QoS(10);
|
||||
auto allocator = std::make_shared<Alloc>();
|
||||
message_allocator_ = std::make_shared<MessageAlloc>(*allocator.get());
|
||||
}
|
||||
@@ -136,10 +136,7 @@ namespace buffers
|
||||
{
|
||||
namespace mock
|
||||
{
|
||||
template<
|
||||
typename MessageT,
|
||||
typename Alloc = std::allocator<void>,
|
||||
typename MessageDeleter = std::default_delete<MessageT>>
|
||||
template<typename MessageT>
|
||||
class IntraProcessBuffer
|
||||
{
|
||||
public:
|
||||
@@ -194,8 +191,8 @@ class SubscriptionIntraProcessBase
|
||||
public:
|
||||
RCLCPP_SMART_PTR_ALIASES_ONLY(SubscriptionIntraProcessBase)
|
||||
|
||||
explicit SubscriptionIntraProcessBase(rclcpp::QoS qos = rclcpp::QoS(10))
|
||||
: qos_profile(qos), topic_name("topic")
|
||||
SubscriptionIntraProcessBase()
|
||||
: qos_profile(rmw_qos_profile_default), topic_name("topic")
|
||||
{}
|
||||
|
||||
virtual ~SubscriptionIntraProcessBase() {}
|
||||
@@ -203,7 +200,7 @@ public:
|
||||
virtual bool
|
||||
use_take_shared_method() const = 0;
|
||||
|
||||
QoS
|
||||
rmw_qos_profile_t
|
||||
get_actual_qos()
|
||||
{
|
||||
return qos_profile;
|
||||
@@ -215,7 +212,7 @@ public:
|
||||
return topic_name;
|
||||
}
|
||||
|
||||
rclcpp::QoS qos_profile;
|
||||
rmw_qos_profile_t qos_profile;
|
||||
const char * topic_name;
|
||||
};
|
||||
|
||||
@@ -223,13 +220,13 @@ template<
|
||||
typename MessageT,
|
||||
typename Alloc = std::allocator<void>,
|
||||
typename Deleter = std::default_delete<MessageT>>
|
||||
class SubscriptionIntraProcessBuffer : public SubscriptionIntraProcessBase
|
||||
class SubscriptionIntraProcess : public SubscriptionIntraProcessBase
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(SubscriptionIntraProcessBuffer)
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(SubscriptionIntraProcess)
|
||||
|
||||
explicit SubscriptionIntraProcessBuffer(rclcpp::QoS qos)
|
||||
: SubscriptionIntraProcessBase(qos), take_shared_method(false)
|
||||
SubscriptionIntraProcess()
|
||||
: take_shared_method(false)
|
||||
{
|
||||
buffer = std::make_unique<rclcpp::experimental::buffers::mock::IntraProcessBuffer<MessageT>>();
|
||||
}
|
||||
@@ -265,25 +262,6 @@ public:
|
||||
typename rclcpp::experimental::buffers::mock::IntraProcessBuffer<MessageT>::UniquePtr buffer;
|
||||
};
|
||||
|
||||
template<
|
||||
typename MessageT,
|
||||
typename Alloc = std::allocator<void>,
|
||||
typename Deleter = std::default_delete<MessageT>>
|
||||
class SubscriptionIntraProcess : public SubscriptionIntraProcessBuffer<
|
||||
MessageT,
|
||||
Alloc,
|
||||
Deleter
|
||||
>
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(SubscriptionIntraProcess)
|
||||
|
||||
explicit SubscriptionIntraProcess(rclcpp::QoS qos = rclcpp::QoS(10))
|
||||
: SubscriptionIntraProcessBuffer<MessageT, Alloc, Deleter>(qos)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mock
|
||||
} // namespace experimental
|
||||
} // namespace rclcpp
|
||||
@@ -292,14 +270,12 @@ public:
|
||||
#define RCLCPP__PUBLISHER_HPP_
|
||||
#define RCLCPP__PUBLISHER_BASE_HPP_
|
||||
#define RCLCPP__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_HPP_
|
||||
#define RCLCPP__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_BUFFER_HPP_
|
||||
#define RCLCPP__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_BASE_HPP_
|
||||
// Force ipm to use our mock publisher class.
|
||||
#define Publisher mock::Publisher
|
||||
#define PublisherBase mock::PublisherBase
|
||||
#define IntraProcessBuffer mock::IntraProcessBuffer
|
||||
#define SubscriptionIntraProcessBase mock::SubscriptionIntraProcessBase
|
||||
#define SubscriptionIntraProcessBuffer mock::SubscriptionIntraProcessBuffer
|
||||
#define SubscriptionIntraProcess mock::SubscriptionIntraProcess
|
||||
#include "../src/rclcpp/intra_process_manager.cpp"
|
||||
#undef Publisher
|
||||
@@ -331,7 +307,7 @@ void Publisher<T, Alloc>::publish(MessageUniquePtr msg)
|
||||
ipm->template do_intra_process_publish<T, Alloc>(
|
||||
intra_process_publisher_id_,
|
||||
std::move(msg),
|
||||
*message_allocator_);
|
||||
message_allocator_);
|
||||
}
|
||||
|
||||
} // namespace mock
|
||||
@@ -359,12 +335,15 @@ TEST(TestIntraProcessManager, add_pub_sub) {
|
||||
|
||||
auto ipm = std::make_shared<IntraProcessManagerT>();
|
||||
|
||||
auto p1 = std::make_shared<PublisherT>(rclcpp::QoS(10).best_effort());
|
||||
auto p1 = std::make_shared<PublisherT>();
|
||||
p1->qos.get_rmw_qos_profile().reliability = RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT;
|
||||
|
||||
auto p2 = std::make_shared<PublisherT>(rclcpp::QoS(10).best_effort());
|
||||
auto p2 = std::make_shared<PublisherT>();
|
||||
p2->qos.get_rmw_qos_profile().reliability = RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT;
|
||||
p2->topic_name = "different_topic_name";
|
||||
|
||||
auto s1 = std::make_shared<SubscriptionIntraProcessT>(rclcpp::QoS(10).best_effort());
|
||||
auto s1 = std::make_shared<SubscriptionIntraProcessT>();
|
||||
s1->qos_profile.reliability = RMW_QOS_POLICY_RELIABILITY_BEST_EFFORT;
|
||||
|
||||
auto p1_id = ipm->add_publisher(p1);
|
||||
auto p2_id = ipm->add_publisher(p2);
|
||||
@@ -380,9 +359,11 @@ TEST(TestIntraProcessManager, add_pub_sub) {
|
||||
ASSERT_EQ(0u, p2_subs);
|
||||
ASSERT_EQ(0u, non_existing_pub_subs);
|
||||
|
||||
auto p3 = std::make_shared<PublisherT>(rclcpp::QoS(10).reliable());
|
||||
auto p3 = std::make_shared<PublisherT>();
|
||||
p3->qos.get_rmw_qos_profile().reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE;
|
||||
|
||||
auto s2 = std::make_shared<SubscriptionIntraProcessT>(rclcpp::QoS(10).reliable());
|
||||
auto s2 = std::make_shared<SubscriptionIntraProcessT>();
|
||||
s2->qos_profile.reliability = RMW_QOS_POLICY_RELIABILITY_RELIABLE;
|
||||
|
||||
auto s2_id = ipm->add_subscription(s2);
|
||||
auto p3_id = ipm->add_publisher(p3);
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "test_msgs/msg/empty.hpp"
|
||||
@@ -31,7 +30,7 @@
|
||||
static uint32_t num_allocs = 0;
|
||||
static uint32_t num_deallocs = 0;
|
||||
// A very simple custom allocator. Counts calls to allocate and deallocate.
|
||||
template<typename T>
|
||||
template<typename T = void>
|
||||
struct MyAllocator
|
||||
{
|
||||
public:
|
||||
@@ -78,33 +77,6 @@ public:
|
||||
};
|
||||
};
|
||||
|
||||
// Explicit specialization for void
|
||||
template<>
|
||||
struct MyAllocator<void>
|
||||
{
|
||||
public:
|
||||
using value_type = void;
|
||||
using pointer = void *;
|
||||
using const_pointer = const void *;
|
||||
|
||||
MyAllocator() noexcept
|
||||
{
|
||||
}
|
||||
|
||||
~MyAllocator() noexcept {}
|
||||
|
||||
template<typename U>
|
||||
MyAllocator(const MyAllocator<U> &) noexcept
|
||||
{
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
struct rebind
|
||||
{
|
||||
typedef MyAllocator<U> other;
|
||||
};
|
||||
};
|
||||
|
||||
template<typename T, typename U>
|
||||
constexpr bool operator==(
|
||||
const MyAllocator<T> &,
|
||||
@@ -196,6 +168,7 @@ do_custom_allocator_test(
|
||||
test_msgs::msg::Empty,
|
||||
decltype(callback),
|
||||
SubscriptionAllocatorT,
|
||||
CallbackMessageT,
|
||||
rclcpp::Subscription<CallbackMessageT, SubscriptionAllocatorT>,
|
||||
rclcpp::message_memory_strategy::MessageMemoryStrategy<
|
||||
CallbackMessageT,
|
||||
|
||||
@@ -43,42 +43,7 @@ TEST_F(TestLoanedMessage, initialize) {
|
||||
auto node = std::make_shared<rclcpp::Node>("loaned_message_test_node");
|
||||
auto pub = node->create_publisher<MessageT>("loaned_message_test_topic", 1);
|
||||
|
||||
// suppress deprecated function warning
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4996)
|
||||
#endif
|
||||
|
||||
auto pub_allocator = pub->get_allocator();
|
||||
|
||||
// remove warning suppression
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic pop
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
// suppress deprecated function warning
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4996)
|
||||
#endif
|
||||
|
||||
auto loaned_msg = rclcpp::LoanedMessage<MessageT>(pub.get(), pub_allocator);
|
||||
|
||||
// remove warning suppression
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic pop
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
auto loaned_msg = rclcpp::LoanedMessage<MessageT>(pub.get(), pub->get_allocator());
|
||||
ASSERT_TRUE(loaned_msg.is_valid());
|
||||
loaned_msg.get().float32_value = 42.0f;
|
||||
ASSERT_EQ(42.0f, loaned_msg.get().float32_value);
|
||||
|
||||
@@ -229,6 +229,12 @@ TEST_F(TestLoggingMacros, test_throttle) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestLoggingMacros, test_parameter_expression) {
|
||||
RCLCPP_DEBUG_STREAM(*&g_logger, "message");
|
||||
EXPECT_EQ(1u, g_log_calls);
|
||||
EXPECT_EQ("message", g_last_log_event.message);
|
||||
}
|
||||
|
||||
bool log_function(rclcpp::Logger logger)
|
||||
{
|
||||
RCLCPP_INFO(logger, "successful log");
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
|
||||
#include "rclcpp/strategies/allocator_memory_strategy.hpp"
|
||||
#include "rclcpp/memory_strategy.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base.hpp"
|
||||
#include "test_msgs/msg/empty.hpp"
|
||||
#include "test_msgs/srv/empty.hpp"
|
||||
|
||||
@@ -84,14 +85,13 @@ TEST_F(TestMemoryStrategy, get_subscription_by_handle) {
|
||||
rclcpp::SubscriptionBase::SharedPtr found_subscription = nullptr;
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("node", "ns");
|
||||
auto callback_groups = node->get_node_base_interface()->get_callback_groups();
|
||||
std::for_each(
|
||||
callback_groups.begin(), callback_groups.end(),
|
||||
[&weak_groups_to_nodes, &node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
|
||||
node->for_each_callback_group(
|
||||
[node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
|
||||
{
|
||||
weak_groups_to_nodes.insert(
|
||||
std::pair<rclcpp::CallbackGroup::WeakPtr,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
|
||||
weak_group_ptr,
|
||||
group_ptr,
|
||||
node->get_node_base_interface()));
|
||||
});
|
||||
memory_strategy()->collect_entities(weak_groups_to_nodes);
|
||||
@@ -131,14 +131,13 @@ TEST_F(TestMemoryStrategy, get_service_by_handle) {
|
||||
rclcpp::ServiceBase::SharedPtr found_service = nullptr;
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("node", "ns");
|
||||
auto callback_groups = node->get_node_base_interface()->get_callback_groups();
|
||||
std::for_each(
|
||||
callback_groups.begin(), callback_groups.end(),
|
||||
[&weak_groups_to_nodes, &node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
|
||||
node->for_each_callback_group(
|
||||
[node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
|
||||
{
|
||||
weak_groups_to_nodes.insert(
|
||||
std::pair<rclcpp::CallbackGroup::WeakPtr,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
|
||||
weak_group_ptr,
|
||||
group_ptr,
|
||||
node->get_node_base_interface()));
|
||||
});
|
||||
memory_strategy()->collect_entities(weak_groups_to_nodes);
|
||||
@@ -184,14 +183,13 @@ TEST_F(TestMemoryStrategy, get_client_by_handle) {
|
||||
rclcpp::ClientBase::SharedPtr found_client = nullptr;
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("node", "ns");
|
||||
auto callback_groups = node->get_node_base_interface()->get_callback_groups();
|
||||
std::for_each(
|
||||
callback_groups.begin(), callback_groups.end(),
|
||||
[&weak_groups_to_nodes, &node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
|
||||
node->for_each_callback_group(
|
||||
[node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
|
||||
{
|
||||
weak_groups_to_nodes.insert(
|
||||
std::pair<rclcpp::CallbackGroup::WeakPtr,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
|
||||
weak_group_ptr,
|
||||
group_ptr,
|
||||
node->get_node_base_interface()));
|
||||
});
|
||||
memory_strategy()->collect_entities(weak_groups_to_nodes);
|
||||
@@ -232,14 +230,13 @@ TEST_F(TestMemoryStrategy, get_timer_by_handle) {
|
||||
rclcpp::TimerBase::SharedPtr found_timer = nullptr;
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("node", "ns");
|
||||
auto callback_groups = node->get_node_base_interface()->get_callback_groups();
|
||||
std::for_each(
|
||||
callback_groups.begin(), callback_groups.end(),
|
||||
[&weak_groups_to_nodes, &node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
|
||||
node->for_each_callback_group(
|
||||
[node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
|
||||
{
|
||||
weak_groups_to_nodes.insert(
|
||||
std::pair<rclcpp::CallbackGroup::WeakPtr,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
|
||||
weak_group_ptr,
|
||||
group_ptr,
|
||||
node->get_node_base_interface()));
|
||||
});
|
||||
memory_strategy()->collect_entities(weak_groups_to_nodes);
|
||||
@@ -281,14 +278,14 @@ TEST_F(TestMemoryStrategy, get_node_by_group) {
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("node", "ns");
|
||||
auto node_handle = node->get_node_base_interface();
|
||||
auto callback_groups = node_handle->get_callback_groups();
|
||||
std::for_each(
|
||||
callback_groups.begin(), callback_groups.end(),
|
||||
[&weak_groups_to_nodes, &node_handle](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
|
||||
rclcpp::node_interfaces::global_for_each_callback_group(
|
||||
node_handle.get(),
|
||||
[node_handle, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
|
||||
{
|
||||
weak_groups_to_nodes.insert(
|
||||
std::pair<rclcpp::CallbackGroup::WeakPtr,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
|
||||
weak_group_ptr,
|
||||
group_ptr,
|
||||
node_handle));
|
||||
});
|
||||
memory_strategy()->collect_entities(weak_groups_to_nodes);
|
||||
@@ -325,14 +322,13 @@ TEST_F(TestMemoryStrategy, get_group_by_subscription) {
|
||||
rclcpp::CallbackGroup::SharedPtr callback_group = nullptr;
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("node", "ns");
|
||||
auto callback_groups = node->get_node_base_interface()->get_callback_groups();
|
||||
std::for_each(
|
||||
callback_groups.begin(), callback_groups.end(),
|
||||
[&weak_groups_to_nodes, &node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
|
||||
node->for_each_callback_group(
|
||||
[node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
|
||||
{
|
||||
weak_groups_to_nodes.insert(
|
||||
std::pair<rclcpp::CallbackGroup::WeakPtr,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
|
||||
weak_group_ptr,
|
||||
group_ptr,
|
||||
node->get_node_base_interface()));
|
||||
});
|
||||
memory_strategy()->collect_entities(weak_groups_to_nodes);
|
||||
@@ -379,14 +375,13 @@ TEST_F(TestMemoryStrategy, get_group_by_service) {
|
||||
rclcpp::ServiceBase::SharedPtr service = nullptr;
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("node", "ns");
|
||||
auto callback_groups = node->get_node_base_interface()->get_callback_groups();
|
||||
std::for_each(
|
||||
callback_groups.begin(), callback_groups.end(),
|
||||
[&weak_groups_to_nodes, &node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
|
||||
node->for_each_callback_group(
|
||||
[node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
|
||||
{
|
||||
weak_groups_to_nodes.insert(
|
||||
std::pair<rclcpp::CallbackGroup::WeakPtr,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
|
||||
weak_group_ptr,
|
||||
group_ptr,
|
||||
node->get_node_base_interface()));
|
||||
});
|
||||
memory_strategy()->collect_entities(weak_groups_to_nodes);
|
||||
@@ -424,14 +419,13 @@ TEST_F(TestMemoryStrategy, get_group_by_client) {
|
||||
rclcpp::ClientBase::SharedPtr client = nullptr;
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("node", "ns");
|
||||
auto callback_groups = node->get_node_base_interface()->get_callback_groups();
|
||||
std::for_each(
|
||||
callback_groups.begin(), callback_groups.end(),
|
||||
[&weak_groups_to_nodes, &node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
|
||||
node->for_each_callback_group(
|
||||
[node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
|
||||
{
|
||||
weak_groups_to_nodes.insert(
|
||||
std::pair<rclcpp::CallbackGroup::WeakPtr,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
|
||||
weak_group_ptr,
|
||||
group_ptr,
|
||||
node->get_node_base_interface()));
|
||||
});
|
||||
memory_strategy()->collect_entities(weak_groups_to_nodes);
|
||||
@@ -464,14 +458,13 @@ TEST_F(TestMemoryStrategy, get_group_by_timer) {
|
||||
rclcpp::TimerBase::SharedPtr timer = nullptr;
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("node", "ns");
|
||||
auto callback_groups = node->get_node_base_interface()->get_callback_groups();
|
||||
std::for_each(
|
||||
callback_groups.begin(), callback_groups.end(),
|
||||
[&weak_groups_to_nodes, &node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
|
||||
node->for_each_callback_group(
|
||||
[node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
|
||||
{
|
||||
weak_groups_to_nodes.insert(
|
||||
std::pair<rclcpp::CallbackGroup::WeakPtr,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
|
||||
weak_group_ptr,
|
||||
group_ptr,
|
||||
node->get_node_base_interface()));
|
||||
});
|
||||
memory_strategy()->collect_entities(weak_groups_to_nodes);
|
||||
@@ -504,14 +497,13 @@ TEST_F(TestMemoryStrategy, get_group_by_waitable) {
|
||||
rclcpp::Waitable::SharedPtr waitable = nullptr;
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("node", "ns");
|
||||
auto callback_groups = node->get_node_base_interface()->get_callback_groups();
|
||||
std::for_each(
|
||||
callback_groups.begin(), callback_groups.end(),
|
||||
[&weak_groups_to_nodes, &node](rclcpp::CallbackGroup::WeakPtr weak_group_ptr) {
|
||||
node->for_each_callback_group(
|
||||
[node, &weak_groups_to_nodes](rclcpp::CallbackGroup::SharedPtr group_ptr)
|
||||
{
|
||||
weak_groups_to_nodes.insert(
|
||||
std::pair<rclcpp::CallbackGroup::WeakPtr,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>(
|
||||
weak_group_ptr,
|
||||
group_ptr,
|
||||
node->get_node_base_interface()));
|
||||
});
|
||||
memory_strategy()->collect_entities(weak_groups_to_nodes);
|
||||
|
||||
@@ -14,9 +14,6 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@@ -102,6 +99,7 @@ TEST_F(TestNode, get_name_and_namespace) {
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
|
||||
EXPECT_STREQ("my_node", node->get_name());
|
||||
EXPECT_STREQ("/ns", node->get_namespace());
|
||||
EXPECT_STREQ("/ns", node->get_effective_namespace().c_str());
|
||||
EXPECT_STREQ("/ns/my_node", node->get_fully_qualified_name());
|
||||
}
|
||||
{
|
||||
@@ -116,30 +114,35 @@ TEST_F(TestNode, get_name_and_namespace) {
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "ns");
|
||||
EXPECT_STREQ("my_node", node->get_name());
|
||||
EXPECT_STREQ("/ns", node->get_namespace());
|
||||
EXPECT_STREQ("/ns", node->get_effective_namespace().c_str());
|
||||
EXPECT_STREQ("/ns/my_node", node->get_fully_qualified_name());
|
||||
}
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node");
|
||||
EXPECT_STREQ("my_node", node->get_name());
|
||||
EXPECT_STREQ("/", node->get_namespace());
|
||||
EXPECT_STREQ("/", node->get_effective_namespace().c_str());
|
||||
EXPECT_STREQ("/my_node", node->get_fully_qualified_name());
|
||||
}
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "");
|
||||
EXPECT_STREQ("my_node", node->get_name());
|
||||
EXPECT_STREQ("/", node->get_namespace());
|
||||
EXPECT_STREQ("/", node->get_effective_namespace().c_str());
|
||||
EXPECT_STREQ("/my_node", node->get_fully_qualified_name());
|
||||
}
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "/my/ns");
|
||||
EXPECT_STREQ("my_node", node->get_name());
|
||||
EXPECT_STREQ("/my/ns", node->get_namespace());
|
||||
EXPECT_STREQ("/my/ns", node->get_effective_namespace().c_str());
|
||||
EXPECT_STREQ("/my/ns/my_node", node->get_fully_qualified_name());
|
||||
}
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "my/ns");
|
||||
EXPECT_STREQ("my_node", node->get_name());
|
||||
EXPECT_STREQ("/my/ns", node->get_namespace());
|
||||
EXPECT_STREQ("/my/ns", node->get_effective_namespace().c_str());
|
||||
EXPECT_STREQ("/my/ns/my_node", node->get_fully_qualified_name());
|
||||
}
|
||||
{
|
||||
@@ -278,6 +281,13 @@ TEST_F(TestNode, subnode_construction_and_destruction) {
|
||||
auto subnode = node->create_sub_node("~sub_ns");
|
||||
}, rclcpp::exceptions::InvalidNamespaceError);
|
||||
}
|
||||
{
|
||||
ASSERT_THROW(
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
|
||||
auto subnode = node->create_sub_node("");
|
||||
}, rclcpp::exceptions::NameValidationError);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestNode, get_logger) {
|
||||
@@ -2516,59 +2526,6 @@ TEST_F(TestNode, get_parameter_types_undeclared_parameters_allowed) {
|
||||
}
|
||||
}
|
||||
|
||||
// test declare parameter with int, int64_t, float and double vector
|
||||
TEST_F(TestNode, declare_parameter_with_vector) {
|
||||
auto node = std::make_shared<rclcpp::Node>(
|
||||
"test_declare_parameter_with_vector"_unq,
|
||||
rclcpp::NodeOptions().allow_undeclared_parameters(true));
|
||||
{
|
||||
// declare parameter and then get types to check
|
||||
auto name1 = "parameter"_unq;
|
||||
auto name2 = "parameter"_unq;
|
||||
auto name3 = "parameter"_unq;
|
||||
auto name4 = "parameter"_unq;
|
||||
|
||||
node->declare_parameter(name1, std::vector<int>{});
|
||||
node->declare_parameter(name2, std::vector<int64_t>{});
|
||||
node->declare_parameter(name3, std::vector<float>{});
|
||||
node->declare_parameter(name4, std::vector<double>{});
|
||||
|
||||
EXPECT_TRUE(node->has_parameter(name1));
|
||||
EXPECT_TRUE(node->has_parameter(name2));
|
||||
EXPECT_TRUE(node->has_parameter(name3));
|
||||
EXPECT_TRUE(node->has_parameter(name4));
|
||||
|
||||
auto results = node->get_parameter_types({name1, name2, name3, name4});
|
||||
EXPECT_EQ(results.size(), 4u);
|
||||
EXPECT_EQ(results[0], rcl_interfaces::msg::ParameterType::PARAMETER_INTEGER_ARRAY);
|
||||
EXPECT_EQ(results[1], rcl_interfaces::msg::ParameterType::PARAMETER_INTEGER_ARRAY);
|
||||
EXPECT_EQ(results[2], rcl_interfaces::msg::ParameterType::PARAMETER_DOUBLE_ARRAY);
|
||||
EXPECT_EQ(results[3], rcl_interfaces::msg::ParameterType::PARAMETER_DOUBLE_ARRAY);
|
||||
}
|
||||
{
|
||||
// declare parameter and then get values to check
|
||||
auto name1 = "parameter"_unq;
|
||||
auto name2 = "parameter"_unq;
|
||||
auto name3 = "parameter"_unq;
|
||||
auto name4 = "parameter"_unq;
|
||||
|
||||
int64_t bigger_than_int = INT64_MAX - 42;
|
||||
double bigger_than_float = std::numeric_limits<double>::max() - 42;
|
||||
node->declare_parameter(name1, std::vector<int>{1, 2});
|
||||
node->declare_parameter(name2, std::vector<int64_t>{3, bigger_than_int});
|
||||
node->declare_parameter(name3, std::vector<float>{1.5f, 2.8f});
|
||||
node->declare_parameter(name4, std::vector<double>{3.0, bigger_than_float});
|
||||
|
||||
std::vector<rclcpp::Parameter> expected = {
|
||||
{name1, std::vector<int>{1, 2}},
|
||||
{name2, std::vector<int64_t>{3, bigger_than_int}},
|
||||
{name3, std::vector<float>{1.5f, 2.8f}},
|
||||
{name4, std::vector<double>{3.0, bigger_than_float}},
|
||||
};
|
||||
EXPECT_EQ(node->get_parameters({name1, name2, name3, name4}), expected);
|
||||
}
|
||||
}
|
||||
|
||||
void expect_qos_profile_eq(
|
||||
const rmw_qos_profile_t & qos1, const rmw_qos_profile_t & qos2, bool is_publisher)
|
||||
{
|
||||
@@ -2586,34 +2543,6 @@ void expect_qos_profile_eq(
|
||||
EXPECT_EQ(qos1.liveliness_lease_duration.nsec, qos2.liveliness_lease_duration.nsec);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
constexpr std::chrono::nanoseconds DEFAULT_EVENT_TIMEOUT = std::chrono::seconds(3);
|
||||
|
||||
constexpr std::chrono::nanoseconds DEFAULT_EVENT_SLEEP_PERIOD = std::chrono::milliseconds(100);
|
||||
|
||||
bool wait_for_event(
|
||||
std::shared_ptr<rclcpp::Node> node,
|
||||
std::function<bool()> predicate,
|
||||
std::chrono::nanoseconds timeout = DEFAULT_EVENT_TIMEOUT,
|
||||
std::chrono::nanoseconds sleep_period = DEFAULT_EVENT_SLEEP_PERIOD)
|
||||
{
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
std::chrono::nanoseconds time_slept(0);
|
||||
|
||||
bool predicate_result;
|
||||
while (!(predicate_result = predicate()) && time_slept < timeout) {
|
||||
rclcpp::Event::SharedPtr graph_event = node->get_graph_event();
|
||||
node->wait_for_graph_change(graph_event, sleep_period);
|
||||
time_slept = std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::steady_clock::now() - start);
|
||||
}
|
||||
return predicate_result;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// test that calling get_publishers_info_by_topic and get_subscriptions_info_by_topic
|
||||
TEST_F(TestNode, get_publishers_subscriptions_info_by_topic) {
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
|
||||
@@ -2645,10 +2574,6 @@ TEST_F(TestNode, get_publishers_subscriptions_info_by_topic) {
|
||||
};
|
||||
rclcpp::QoS qos = rclcpp::QoS(qos_initialization, rmw_qos_profile_default);
|
||||
auto publisher = node->create_publisher<test_msgs::msg::BasicTypes>(topic_name, qos);
|
||||
// Wait for the underlying RMW implementation to catch up with graph changes
|
||||
auto topic_is_published =
|
||||
[&]() {return node->get_publishers_info_by_topic(fq_topic_name).size() > 0u;};
|
||||
ASSERT_TRUE(wait_for_event(node, topic_is_published));
|
||||
// List should have one item
|
||||
auto publisher_list = node->get_publishers_info_by_topic(fq_topic_name);
|
||||
ASSERT_EQ(publisher_list.size(), (size_t)1);
|
||||
@@ -2689,10 +2614,7 @@ TEST_F(TestNode, get_publishers_subscriptions_info_by_topic) {
|
||||
};
|
||||
auto subscriber =
|
||||
node->create_subscription<test_msgs::msg::BasicTypes>(topic_name, qos2, callback);
|
||||
// Wait for the underlying RMW implementation to catch up with graph changes
|
||||
auto topic_is_subscribed =
|
||||
[&]() {return node->get_subscriptions_info_by_topic(fq_topic_name).size() > 0u;};
|
||||
ASSERT_TRUE(wait_for_event(node, topic_is_subscribed));
|
||||
|
||||
// Both lists should have one item
|
||||
publisher_list = node->get_publishers_info_by_topic(fq_topic_name);
|
||||
auto subscription_list = node->get_subscriptions_info_by_topic(fq_topic_name);
|
||||
@@ -2733,13 +2655,33 @@ TEST_F(TestNode, get_publishers_subscriptions_info_by_topic) {
|
||||
|
||||
TEST_F(TestNode, callback_groups) {
|
||||
auto node = std::make_shared<rclcpp::Node>("node", "ns");
|
||||
size_t num_callback_groups_in_basic_node = node->get_callback_groups().size();
|
||||
size_t num_callback_groups_in_basic_node = 0;
|
||||
node->for_each_callback_group(
|
||||
[&num_callback_groups_in_basic_node](rclcpp::CallbackGroup::SharedPtr group)
|
||||
{
|
||||
(void)group;
|
||||
num_callback_groups_in_basic_node++;
|
||||
});
|
||||
|
||||
auto group1 = node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive);
|
||||
EXPECT_EQ(1u + num_callback_groups_in_basic_node, node->get_callback_groups().size());
|
||||
size_t num_callback_groups = 0;
|
||||
node->for_each_callback_group(
|
||||
[&num_callback_groups](rclcpp::CallbackGroup::SharedPtr group)
|
||||
{
|
||||
(void)group;
|
||||
num_callback_groups++;
|
||||
});
|
||||
EXPECT_EQ(1u + num_callback_groups_in_basic_node, num_callback_groups);
|
||||
|
||||
auto group2 = node->create_callback_group(rclcpp::CallbackGroupType::Reentrant);
|
||||
EXPECT_EQ(2u + num_callback_groups_in_basic_node, node->get_callback_groups().size());
|
||||
size_t num_callback_groups2 = 0;
|
||||
node->for_each_callback_group(
|
||||
[&num_callback_groups2](rclcpp::CallbackGroup::SharedPtr group)
|
||||
{
|
||||
(void)group;
|
||||
num_callback_groups2++;
|
||||
});
|
||||
EXPECT_EQ(2u + num_callback_groups_in_basic_node, num_callback_groups2);
|
||||
}
|
||||
|
||||
// This is tested more thoroughly in node_interfaces/test_node_graph
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <cstdio>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include "rclcpp/parameter_map.hpp"
|
||||
@@ -353,3 +354,132 @@ TEST(Test_parameter_map_from, string_array_param_value)
|
||||
c_params->params[0].parameter_values[0].string_array_value = NULL;
|
||||
rcl_yaml_node_struct_fini(c_params);
|
||||
}
|
||||
|
||||
TEST(Test_parameter_map_from, one_node_one_param_by_node_fqn)
|
||||
{
|
||||
rcl_params_t * c_params = make_params({"foo"});
|
||||
make_node_params(c_params, 0, {"string_param"});
|
||||
|
||||
std::string hello_world = "hello world";
|
||||
char * c_hello_world = new char[hello_world.length() + 1];
|
||||
std::snprintf(c_hello_world, hello_world.size() + 1, "%s", hello_world.c_str());
|
||||
c_params->params[0].parameter_values[0].string_value = c_hello_world;
|
||||
|
||||
rclcpp::ParameterMap map = rclcpp::parameter_map_from(c_params, "/foo");
|
||||
const std::vector<rclcpp::Parameter> & params = map.at("/foo");
|
||||
EXPECT_STREQ("string_param", params.at(0).get_name().c_str());
|
||||
EXPECT_STREQ(hello_world.c_str(), params.at(0).get_value<std::string>().c_str());
|
||||
|
||||
c_params->params[0].parameter_values[0].string_value = NULL;
|
||||
delete[] c_hello_world;
|
||||
rcl_yaml_node_struct_fini(c_params);
|
||||
}
|
||||
|
||||
TEST(Test_parameter_map_from, multi_nodes_same_param_name_by_node_fqn)
|
||||
{
|
||||
std::vector<std::string> node_names_keys = {
|
||||
"/**", // index: 0
|
||||
"/*", // index: 1
|
||||
"/**/node", // index: 2
|
||||
"/*/node", // index: 3
|
||||
"/ns/node" // index: 4
|
||||
};
|
||||
|
||||
rcl_params_t * c_params = make_params(node_names_keys);
|
||||
|
||||
std::vector<char *> param_values;
|
||||
for (size_t i = 0; i < node_names_keys.size(); ++i) {
|
||||
make_node_params(c_params, i, {"string_param"});
|
||||
std::string hello_world = "hello world" + std::to_string(i);
|
||||
char * c_hello_world = new char[hello_world.length() + 1];
|
||||
std::snprintf(c_hello_world, hello_world.size() + 1, "%s", hello_world.c_str());
|
||||
c_params->params[i].parameter_values[0].string_value = c_hello_world;
|
||||
param_values.push_back(c_hello_world);
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::vector<size_t>> node_fqn_expected = {
|
||||
{"/ns/foo/another_node", {0}},
|
||||
{"/another", {0, 1}},
|
||||
{"/node", {0, 1, 2}},
|
||||
{"/another_ns/node", {0, 2, 3}},
|
||||
{"/ns/node", {0, 2, 3, 4}},
|
||||
};
|
||||
|
||||
for (auto & kv : node_fqn_expected) {
|
||||
rclcpp::ParameterMap map = rclcpp::parameter_map_from(c_params, kv.first.c_str());
|
||||
const std::vector<rclcpp::Parameter> & params = map.at(kv.first);
|
||||
|
||||
EXPECT_EQ(kv.second.size(), params.size());
|
||||
for (size_t i = 0; i < params.size(); ++i) {
|
||||
std::string param_value = "hello world" + std::to_string(kv.second[i]);
|
||||
EXPECT_STREQ("string_param", params.at(i).get_name().c_str());
|
||||
EXPECT_STREQ(param_value.c_str(), params.at(i).get_value<std::string>().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < node_names_keys.size(); ++i) {
|
||||
c_params->params[i].parameter_values[0].string_value = NULL;
|
||||
}
|
||||
for (auto c_hello_world : param_values) {
|
||||
delete[] c_hello_world;
|
||||
}
|
||||
rcl_yaml_node_struct_fini(c_params);
|
||||
}
|
||||
|
||||
TEST(Test_parameter_map_from, multi_nodes_diff_param_name_by_node_fqn)
|
||||
{
|
||||
std::vector<std::string> node_names_keys = {
|
||||
"/**", // index: 0
|
||||
"/*", // index: 1
|
||||
"/**/node", // index: 2
|
||||
"/*/node", // index: 3
|
||||
"/ns/**", // index: 4
|
||||
"/ns/*", // index: 5
|
||||
"/ns/**/node", // index: 6
|
||||
"/ns/*/node", // index: 7
|
||||
"/ns/**/a/*/node", // index: 8
|
||||
"/ns/node" // index: 9
|
||||
};
|
||||
|
||||
rcl_params_t * c_params = make_params(node_names_keys);
|
||||
|
||||
for (size_t i = 0; i < node_names_keys.size(); ++i) {
|
||||
std::string param_name = "string_param" + std::to_string(i);
|
||||
make_node_params(c_params, i, {param_name});
|
||||
}
|
||||
|
||||
std::string hello_world = "hello world";
|
||||
char * c_hello_world = new char[hello_world.length() + 1];
|
||||
std::snprintf(c_hello_world, hello_world.size() + 1, "%s", hello_world.c_str());
|
||||
|
||||
for (size_t i = 0; i < node_names_keys.size(); ++i) {
|
||||
c_params->params[i].parameter_values[0].string_value = c_hello_world;
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::vector<size_t>> node_fqn_expected = {
|
||||
{"/ns/node", {0, 2, 3, 4, 5, 6, 9}},
|
||||
{"/node", {0, 1, 2}},
|
||||
{"/ns/foo/node", {0, 2, 4, 6, 7}},
|
||||
{"/ns/foo/a/node", {0, 2, 4, 6}},
|
||||
{"/ns/foo/a/bar/node", {0, 2, 4, 6, 8}},
|
||||
{"/ns/a/bar/node", {0, 2, 4, 6, 8}},
|
||||
{"/ns/foo/zoo/a/bar/node", {0, 2, 4, 6, 8}},
|
||||
};
|
||||
|
||||
for (auto & kv : node_fqn_expected) {
|
||||
rclcpp::ParameterMap map = rclcpp::parameter_map_from(c_params, kv.first.c_str());
|
||||
const std::vector<rclcpp::Parameter> & params = map.at(kv.first);
|
||||
EXPECT_EQ(kv.second.size(), params.size());
|
||||
for (size_t i = 0; i < params.size(); ++i) {
|
||||
std::string param_name = "string_param" + std::to_string(kv.second[i]);
|
||||
EXPECT_STREQ(param_name.c_str(), params.at(i).get_name().c_str());
|
||||
EXPECT_STREQ(hello_world.c_str(), params.at(i).get_value<std::string>().c_str());
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < node_names_keys.size(); ++i) {
|
||||
c_params->params[i].parameter_values[0].string_value = NULL;
|
||||
}
|
||||
delete[] c_hello_world;
|
||||
rcl_yaml_node_struct_fini(c_params);
|
||||
}
|
||||
|
||||
@@ -1,335 +0,0 @@
|
||||
// Copyright 2021 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
#include "rclcpp/loaned_message.hpp"
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
|
||||
#include "../mocking_utils/patch.hpp"
|
||||
#include "../utils/rclcpp_gtest_macros.hpp"
|
||||
|
||||
#include "test_msgs/msg/empty.hpp"
|
||||
#include "rclcpp/msg/string.hpp"
|
||||
|
||||
|
||||
#ifdef RMW_IMPLEMENTATION
|
||||
# define CLASSNAME_(NAME, SUFFIX) NAME ## __ ## SUFFIX
|
||||
# define CLASSNAME(NAME, SUFFIX) CLASSNAME_(NAME, SUFFIX)
|
||||
#else
|
||||
# define CLASSNAME(NAME, SUFFIX) NAME
|
||||
#endif
|
||||
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
static const int g_max_loops = 200;
|
||||
static const std::chrono::milliseconds g_sleep_per_loop(10);
|
||||
|
||||
|
||||
class TestPublisher : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
if (!rclcpp::ok()) {
|
||||
rclcpp::init(0, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
void initialize(const rclcpp::NodeOptions & node_options = rclcpp::NodeOptions())
|
||||
{
|
||||
node = std::make_shared<rclcpp::Node>("my_node", "/ns", node_options);
|
||||
}
|
||||
|
||||
void TearDown()
|
||||
{
|
||||
node.reset();
|
||||
}
|
||||
|
||||
rclcpp::Node::SharedPtr node;
|
||||
};
|
||||
|
||||
class CLASSNAME (test_intra_process_within_one_node, RMW_IMPLEMENTATION) : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
rclcpp::init(0, nullptr);
|
||||
}
|
||||
|
||||
static void TearDownTestCase()
|
||||
{
|
||||
rclcpp::shutdown();
|
||||
}
|
||||
};
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
template<>
|
||||
struct TypeAdapter<std::string, rclcpp::msg::String>
|
||||
{
|
||||
using is_specialized = std::true_type;
|
||||
using custom_type = std::string;
|
||||
using ros_message_type = rclcpp::msg::String;
|
||||
|
||||
static void
|
||||
convert_to_ros_message(
|
||||
const custom_type & source,
|
||||
ros_message_type & destination)
|
||||
{
|
||||
destination.data = source;
|
||||
}
|
||||
|
||||
static void
|
||||
convert_to_custom(
|
||||
const ros_message_type & source,
|
||||
custom_type & destination)
|
||||
{
|
||||
destination = source.data;
|
||||
}
|
||||
};
|
||||
|
||||
// Throws in conversion
|
||||
template<>
|
||||
struct TypeAdapter<int, rclcpp::msg::String>
|
||||
{
|
||||
using is_specialized = std::true_type;
|
||||
using custom_type = int;
|
||||
using ros_message_type = rclcpp::msg::String;
|
||||
|
||||
static void
|
||||
convert_to_ros_message(
|
||||
const custom_type & source,
|
||||
ros_message_type & destination)
|
||||
{
|
||||
(void) source;
|
||||
(void) destination;
|
||||
throw std::runtime_error("This should happen");
|
||||
}
|
||||
|
||||
static void
|
||||
convert_to_custom(
|
||||
const ros_message_type & source,
|
||||
custom_type & destination)
|
||||
{
|
||||
(void) source;
|
||||
(void) destination;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
/*
|
||||
* Testing publisher creation signatures with a type adapter.
|
||||
*/
|
||||
TEST_F(TestPublisher, various_creation_signatures) {
|
||||
for (auto is_intra_process : {true, false}) {
|
||||
rclcpp::NodeOptions options;
|
||||
options.use_intra_process_comms(is_intra_process);
|
||||
initialize(options);
|
||||
{
|
||||
using StringTypeAdapter = rclcpp::TypeAdapter<std::string, rclcpp::msg::String>;
|
||||
auto publisher = node->create_publisher<StringTypeAdapter>("topic", 42);
|
||||
(void)publisher;
|
||||
}
|
||||
{
|
||||
using StringTypeAdapter = rclcpp::adapt_type<std::string>::as<rclcpp::msg::String>;
|
||||
auto publisher = node->create_publisher<StringTypeAdapter>("topic", 42);
|
||||
(void)publisher;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Testing that conversion errors are passed up.
|
||||
*/
|
||||
TEST_F(TestPublisher, conversion_exception_is_passed_up) {
|
||||
using BadStringTypeAdapter = rclcpp::TypeAdapter<int, rclcpp::msg::String>;
|
||||
for (auto is_intra_process : {true, false}) {
|
||||
rclcpp::NodeOptions options;
|
||||
options.use_intra_process_comms(is_intra_process);
|
||||
initialize(options);
|
||||
auto pub = node->create_publisher<BadStringTypeAdapter>("topic_name", 1);
|
||||
EXPECT_THROW(pub->publish(1), std::runtime_error);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Testing that publisher sends type adapted types and ROS message types with intra proccess communications.
|
||||
*/
|
||||
TEST_F(
|
||||
CLASSNAME(test_intra_process_within_one_node, RMW_IMPLEMENTATION),
|
||||
check_type_adapted_message_is_sent_and_received_intra_process) {
|
||||
using StringTypeAdapter = rclcpp::TypeAdapter<std::string, rclcpp::msg::String>;
|
||||
const std::string message_data = "Message Data";
|
||||
const std::string topic_name = "topic_name";
|
||||
bool is_received;
|
||||
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
const rclcpp::msg::String::SharedPtr msg,
|
||||
const rclcpp::MessageInfo & message_info
|
||||
) -> void
|
||||
{
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), msg->data.c_str());
|
||||
ASSERT_TRUE(message_info.get_rmw_message_info().from_intra_process);
|
||||
};
|
||||
|
||||
auto node = rclcpp::Node::make_shared(
|
||||
"test_intra_process",
|
||||
rclcpp::NodeOptions().use_intra_process_comms(true));
|
||||
auto pub = node->create_publisher<StringTypeAdapter>(topic_name, 10);
|
||||
auto sub = node->create_subscription<rclcpp::msg::String>(topic_name, 1, callback);
|
||||
|
||||
auto wait_for_message_to_be_received = [&is_received, &node]() {
|
||||
rclcpp::executors::SingleThreadedExecutor executor;
|
||||
int i = 0;
|
||||
executor.add_node(node);
|
||||
executor.spin_once(std::chrono::milliseconds(0));
|
||||
while (!is_received && i < g_max_loops) {
|
||||
printf("spin_node_once() - callback (1) expected - try %d/%d\n", ++i, g_max_loops);
|
||||
executor.spin_once(g_sleep_per_loop);
|
||||
}
|
||||
};
|
||||
{
|
||||
{ // std::string passed by reference
|
||||
is_received = false;
|
||||
pub->publish(message_data);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received();
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
{ // unique pointer to std::string
|
||||
is_received = false;
|
||||
auto pu_message = std::make_unique<std::string>(message_data);
|
||||
pub->publish(std::move(pu_message));
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received();
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
{ // ROS message passed by reference
|
||||
is_received = false;
|
||||
rclcpp::msg::String msg;
|
||||
msg.data = message_data;
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received();
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
{ // unique ptr to ROS message
|
||||
is_received = false;
|
||||
auto pu_msg = std::make_unique<rclcpp::msg::String>();
|
||||
pu_msg->data = message_data;
|
||||
pub->publish(std::move(pu_msg));
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received();
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
/* TODO(audrow) Enable once loaned messages are supported for intra process communication
|
||||
{ // loaned ROS message
|
||||
// is_received = false;
|
||||
// std::allocator<void> allocator;
|
||||
// rclcpp::LoanedMessage<rclcpp::msg::String> loaned_msg(*pub, allocator);
|
||||
// loaned_msg.get().data = message_data;
|
||||
// pub->publish(std::move(loaned_msg));
|
||||
// ASSERT_FALSE(is_received);
|
||||
// wait_for_message_to_be_received();
|
||||
// ASSERT_TRUE(is_received);
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Testing that publisher sends type adapted types and ROS message types with inter proccess communications.
|
||||
*/
|
||||
TEST_F(TestPublisher, check_type_adapted_message_is_sent_and_received) {
|
||||
using StringTypeAdapter = rclcpp::TypeAdapter<std::string, rclcpp::msg::String>;
|
||||
|
||||
initialize();
|
||||
|
||||
const std::string message_data = "Message Data";
|
||||
const std::string topic_name = "topic_name";
|
||||
|
||||
auto do_nothing = [](std::shared_ptr<const rclcpp::msg::String>) {FAIL();};
|
||||
auto pub = node->create_publisher<StringTypeAdapter>(topic_name, 1);
|
||||
auto sub = node->create_subscription<rclcpp::msg::String>(topic_name, 1, do_nothing);
|
||||
|
||||
auto assert_no_message_was_received_yet = [sub]() {
|
||||
rclcpp::msg::String msg;
|
||||
rclcpp::MessageInfo msg_info;
|
||||
EXPECT_FALSE(sub->take(msg, msg_info));
|
||||
};
|
||||
auto assert_message_was_received = [sub, message_data]() {
|
||||
rclcpp::msg::String msg;
|
||||
rclcpp::MessageInfo msg_info;
|
||||
bool message_received = false;
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
do {
|
||||
message_received = sub->take(msg, msg_info);
|
||||
std::this_thread::sleep_for(100ms);
|
||||
} while (!message_received && std::chrono::steady_clock::now() - start < 10s);
|
||||
EXPECT_TRUE(message_received);
|
||||
ASSERT_STREQ(message_data.c_str(), msg.data.c_str());
|
||||
};
|
||||
|
||||
{ // std::string passed by reference
|
||||
assert_no_message_was_received_yet();
|
||||
pub->publish(message_data);
|
||||
assert_message_was_received();
|
||||
}
|
||||
{ // unique pointer to std::string
|
||||
assert_no_message_was_received_yet();
|
||||
auto pu_message = std::make_unique<std::string>(message_data);
|
||||
pub->publish(std::move(pu_message));
|
||||
assert_message_was_received();
|
||||
}
|
||||
{ // ROS message passed by reference
|
||||
assert_no_message_was_received_yet();
|
||||
rclcpp::msg::String msg;
|
||||
msg.data = message_data;
|
||||
pub->publish(msg);
|
||||
assert_message_was_received();
|
||||
}
|
||||
{ // unique ptr to ROS message
|
||||
assert_no_message_was_received_yet();
|
||||
auto pu_msg = std::make_unique<rclcpp::msg::String>();
|
||||
pu_msg->data = message_data;
|
||||
pub->publish(std::move(pu_msg));
|
||||
assert_message_was_received();
|
||||
}
|
||||
{ // loaned ROS message
|
||||
assert_no_message_was_received_yet();
|
||||
std::allocator<void> allocator;
|
||||
rclcpp::LoanedMessage<rclcpp::msg::String> loaned_msg(*pub, allocator);
|
||||
loaned_msg.get().data = message_data;
|
||||
pub->publish(std::move(loaned_msg));
|
||||
rclcpp::PublisherOptionsWithAllocator<std::allocator<void>> options;
|
||||
assert_message_was_received();
|
||||
}
|
||||
}
|
||||
@@ -510,7 +510,7 @@ INSTANTIATE_TEST_SUITE_P(
|
||||
TEST_F(TestSubscription, get_network_flow_endpoints_errors) {
|
||||
initialize();
|
||||
const rclcpp::QoS subscription_qos(1);
|
||||
auto subscription_callback = [](test_msgs::msg::Empty::SharedPtr msg) {
|
||||
auto subscription_callback = [](const test_msgs::msg::Empty::SharedPtr msg) {
|
||||
(void)msg;
|
||||
};
|
||||
auto subscription = node->create_subscription<test_msgs::msg::Empty>(
|
||||
|
||||
@@ -1,563 +0,0 @@
|
||||
// Copyright 2021 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
#include "rclcpp/loaned_message.hpp"
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
|
||||
#include "../mocking_utils/patch.hpp"
|
||||
#include "../utils/rclcpp_gtest_macros.hpp"
|
||||
|
||||
#include "test_msgs/msg/empty.hpp"
|
||||
#include "rclcpp/msg/string.hpp"
|
||||
|
||||
|
||||
#ifdef RMW_IMPLEMENTATION
|
||||
# define CLASSNAME_(NAME, SUFFIX) NAME ## __ ## SUFFIX
|
||||
# define CLASSNAME(NAME, SUFFIX) CLASSNAME_(NAME, SUFFIX)
|
||||
#else
|
||||
# define CLASSNAME(NAME, SUFFIX) NAME
|
||||
#endif
|
||||
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
static const int g_max_loops = 200;
|
||||
static const std::chrono::milliseconds g_sleep_per_loop(10);
|
||||
|
||||
|
||||
class TestSubscription : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
if (!rclcpp::ok()) {
|
||||
rclcpp::init(0, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
void initialize(const rclcpp::NodeOptions & node_options = rclcpp::NodeOptions())
|
||||
{
|
||||
node = std::make_shared<rclcpp::Node>("my_node", "/ns", node_options);
|
||||
}
|
||||
|
||||
void TearDown()
|
||||
{
|
||||
node.reset();
|
||||
}
|
||||
|
||||
rclcpp::Node::SharedPtr node;
|
||||
};
|
||||
|
||||
class CLASSNAME (test_intra_process_within_one_node, RMW_IMPLEMENTATION) : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
rclcpp::init(0, nullptr);
|
||||
}
|
||||
|
||||
static void TearDownTestCase()
|
||||
{
|
||||
rclcpp::shutdown();
|
||||
}
|
||||
};
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
template<>
|
||||
struct TypeAdapter<std::string, rclcpp::msg::String>
|
||||
{
|
||||
using is_specialized = std::true_type;
|
||||
using custom_type = std::string;
|
||||
using ros_message_type = rclcpp::msg::String;
|
||||
|
||||
static void
|
||||
convert_to_ros_message(
|
||||
const custom_type & source,
|
||||
ros_message_type & destination)
|
||||
{
|
||||
destination.data = source;
|
||||
}
|
||||
|
||||
static void
|
||||
convert_to_custom(
|
||||
const ros_message_type & source,
|
||||
custom_type & destination)
|
||||
{
|
||||
destination = source.data;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
void wait_for_message_to_be_received(
|
||||
bool & is_received,
|
||||
const std::shared_ptr<rclcpp::Node> & node)
|
||||
{
|
||||
rclcpp::executors::SingleThreadedExecutor executor;
|
||||
executor.add_node(node);
|
||||
executor.spin_once(std::chrono::milliseconds(0));
|
||||
int i = 0;
|
||||
while (!is_received && i < g_max_loops) {
|
||||
printf("spin_node_once() - callback (1) expected - try %d/%d\n", ++i, g_max_loops);
|
||||
executor.spin_once(g_sleep_per_loop);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Testing publisher creation signatures with a type adapter.
|
||||
*/
|
||||
TEST_F(TestSubscription, various_creation_signatures) {
|
||||
initialize();
|
||||
{
|
||||
using StringTypeAdapter = rclcpp::TypeAdapter<std::string, rclcpp::msg::String>;
|
||||
auto sub =
|
||||
node->create_subscription<StringTypeAdapter>("topic", 42, [](const std::string &) {});
|
||||
(void)sub;
|
||||
}
|
||||
{
|
||||
using StringTypeAdapter = rclcpp::adapt_type<std::string>::as<rclcpp::msg::String>;
|
||||
auto sub =
|
||||
node->create_subscription<StringTypeAdapter>("topic", 42, [](const std::string &) {});
|
||||
(void)sub;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Testing that subscriber receives type adapted types and ROS message types with intra proccess communications.
|
||||
*/
|
||||
TEST_F(
|
||||
CLASSNAME(test_intra_process_within_one_node, RMW_IMPLEMENTATION),
|
||||
check_type_adapted_messages_are_received_by_intra_process_subscription) {
|
||||
using StringTypeAdapter = rclcpp::TypeAdapter<std::string, rclcpp::msg::String>;
|
||||
const std::string message_data = "Message Data";
|
||||
const std::string topic_name = "topic_name";
|
||||
|
||||
auto node = rclcpp::Node::make_shared(
|
||||
"test_intra_process",
|
||||
rclcpp::NodeOptions().use_intra_process_comms(true));
|
||||
auto pub = node->create_publisher<rclcpp::msg::String>(topic_name, 1);
|
||||
|
||||
rclcpp::msg::String msg;
|
||||
msg.data = message_data;
|
||||
|
||||
{
|
||||
{ // const std::string &
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
const std::string & msg) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), msg.c_str());
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
{ // const std::string & with message info
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
const std::string & msg,
|
||||
const rclcpp::MessageInfo & message_info) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), msg.c_str());
|
||||
ASSERT_TRUE(message_info.get_rmw_message_info().from_intra_process);
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
|
||||
{ // std::shared_ptr<std::string>
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::shared_ptr<const std::string> msg) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), (*msg).c_str());
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
{ // std::shared_ptr<const std::string> with message info
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::shared_ptr<const std::string> msg,
|
||||
const rclcpp::MessageInfo & message_info) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), (*msg).c_str());
|
||||
ASSERT_TRUE(message_info.get_rmw_message_info().from_intra_process);
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
|
||||
{ // std::unique_ptr<std::string>
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::unique_ptr<std::string> msg) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), (*msg).c_str());
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
{ // std::unique_ptr<std::string> with message info
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::unique_ptr<std::string> msg,
|
||||
const rclcpp::MessageInfo & message_info) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), (*msg).c_str());
|
||||
ASSERT_TRUE(message_info.get_rmw_message_info().from_intra_process);
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
|
||||
{ // const rclcpp::msg::String &
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
const rclcpp::msg::String & msg) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), msg.data.c_str());
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
{ // const rclcpp::msg::String & with message info
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
const rclcpp::msg::String & msg,
|
||||
const rclcpp::MessageInfo & message_info) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), msg.data.c_str());
|
||||
ASSERT_TRUE(message_info.get_rmw_message_info().from_intra_process);
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
|
||||
{ // std::shared_ptr<rclcpp::msg::String>
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::shared_ptr<const rclcpp::msg::String> msg) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), msg->data.c_str());
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
{ // std::shared_ptr<rclcpp::msg::String> with message info
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::shared_ptr<const rclcpp::msg::String> msg,
|
||||
const rclcpp::MessageInfo & message_info) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), msg->data.c_str());
|
||||
ASSERT_TRUE(message_info.get_rmw_message_info().from_intra_process);
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
|
||||
{ // std::unique_ptr<rclcpp::msg::String>
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::unique_ptr<rclcpp::msg::String> msg) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), msg->data.c_str());
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
{ // std::unique_ptr<rclcpp::msg::String> with message info
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::unique_ptr<rclcpp::msg::String> msg,
|
||||
const rclcpp::MessageInfo & message_info) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), msg->data.c_str());
|
||||
ASSERT_TRUE(message_info.get_rmw_message_info().from_intra_process);
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Testing that subscriber receives type adapted types and ROS message types with inter proccess communications.
|
||||
*/
|
||||
TEST_F(
|
||||
CLASSNAME(test_intra_process_within_one_node, RMW_IMPLEMENTATION),
|
||||
check_type_adapted_messages_are_received_by_inter_process_subscription) {
|
||||
using StringTypeAdapter = rclcpp::TypeAdapter<std::string, rclcpp::msg::String>;
|
||||
const std::string message_data = "Message Data";
|
||||
const std::string topic_name = "topic_name";
|
||||
|
||||
auto node = rclcpp::Node::make_shared(
|
||||
"test_intra_process",
|
||||
rclcpp::NodeOptions().use_intra_process_comms(false));
|
||||
auto pub = node->create_publisher<rclcpp::msg::String>(topic_name, 1);
|
||||
|
||||
rclcpp::msg::String msg;
|
||||
msg.data = message_data;
|
||||
|
||||
{
|
||||
{ // const std::string &
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](const std::string & msg) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), msg.c_str());
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
|
||||
{ // const std::string & with message info
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
const std::string & msg, const rclcpp::MessageInfo & message_info) -> void
|
||||
{
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), msg.c_str());
|
||||
ASSERT_FALSE(message_info.get_rmw_message_info().from_intra_process);
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
|
||||
{ // std::shared_ptr<std::string>
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::shared_ptr<const std::string> msg) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), (*msg).c_str());
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
|
||||
{ // std::shared_ptr<const std::string> with message info
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::shared_ptr<const std::string> msg,
|
||||
const rclcpp::MessageInfo & message_info) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), (*msg).c_str());
|
||||
ASSERT_FALSE(message_info.get_rmw_message_info().from_intra_process);
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
|
||||
{ // std::unique_ptr<std::string>
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::unique_ptr<std::string> msg) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), (*msg).c_str());
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
{ // std::unique_ptr<std::string> with message info
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::unique_ptr<std::string> msg,
|
||||
const rclcpp::MessageInfo & message_info) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), (*msg).c_str());
|
||||
ASSERT_FALSE(message_info.get_rmw_message_info().from_intra_process);
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
|
||||
{ // const rclcpp::msg::String &
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
const rclcpp::msg::String & msg) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), msg.data.c_str());
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
{ // const rclcpp::msg::String & with message info
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
const rclcpp::msg::String & msg,
|
||||
const rclcpp::MessageInfo & message_info) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), msg.data.c_str());
|
||||
ASSERT_FALSE(message_info.get_rmw_message_info().from_intra_process);
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
|
||||
{ // std::shared_ptr<rclcpp::msg::String>
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::shared_ptr<const rclcpp::msg::String> msg) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), msg->data.c_str());
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
{ // std::shared_ptr<rclcpp::msg::String> with message info
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::shared_ptr<const rclcpp::msg::String> msg,
|
||||
const rclcpp::MessageInfo & message_info) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), msg->data.c_str());
|
||||
ASSERT_FALSE(message_info.get_rmw_message_info().from_intra_process);
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
|
||||
{ // std::unique_ptr<rclcpp::msg::String>
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::unique_ptr<rclcpp::msg::String> msg) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), msg->data.c_str());
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
{ // std::unique_ptr<rclcpp::msg::String> with message info
|
||||
bool is_received = false;
|
||||
auto callback =
|
||||
[message_data, &is_received](
|
||||
std::unique_ptr<rclcpp::msg::String> msg,
|
||||
const rclcpp::MessageInfo & message_info) -> void {
|
||||
is_received = true;
|
||||
ASSERT_STREQ(message_data.c_str(), msg->data.c_str());
|
||||
ASSERT_FALSE(message_info.get_rmw_message_info().from_intra_process);
|
||||
};
|
||||
auto sub = node->create_subscription<StringTypeAdapter>(topic_name, 1, callback);
|
||||
pub->publish(msg);
|
||||
ASSERT_FALSE(is_received);
|
||||
wait_for_message_to_be_received(is_received, node);
|
||||
ASSERT_TRUE(is_received);
|
||||
}
|
||||
}
|
||||
}
|
||||
74
rclcpp/test/rclcpp/test_wait_for_message.cpp
Normal file
74
rclcpp/test/rclcpp/test_wait_for_message.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
// Copyright 2021 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "rclcpp/node.hpp"
|
||||
#include "rclcpp/wait_for_message.hpp"
|
||||
|
||||
#include "test_msgs/msg/strings.hpp"
|
||||
#include "test_msgs/message_fixtures.hpp"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
TEST(TestUtilities, wait_for_message) {
|
||||
rclcpp::init(0, nullptr);
|
||||
|
||||
auto node = std::make_shared<rclcpp::Node>("wait_for_message_node");
|
||||
|
||||
using MsgT = test_msgs::msg::Strings;
|
||||
auto pub = node->create_publisher<MsgT>("wait_for_message_topic", 10);
|
||||
|
||||
MsgT out;
|
||||
auto received = false;
|
||||
auto wait = std::async(
|
||||
[&]() {
|
||||
auto ret = rclcpp::wait_for_message(out, node, "wait_for_message_topic", 5s);
|
||||
EXPECT_TRUE(ret);
|
||||
received = true;
|
||||
});
|
||||
|
||||
for (auto i = 0u; i < 10 && received == false; ++i) {
|
||||
pub->publish(*get_messages_strings()[0]);
|
||||
std::this_thread::sleep_for(1s);
|
||||
}
|
||||
ASSERT_TRUE(received);
|
||||
EXPECT_EQ(out, *get_messages_strings()[0]);
|
||||
|
||||
rclcpp::shutdown();
|
||||
}
|
||||
|
||||
TEST(TestUtilities, wait_for_message_indefinitely) {
|
||||
rclcpp::init(0, nullptr);
|
||||
|
||||
auto node = std::make_shared<rclcpp::Node>("wait_for_message_node2");
|
||||
|
||||
using MsgT = test_msgs::msg::Strings;
|
||||
MsgT out;
|
||||
auto received = false;
|
||||
auto wait = std::async(
|
||||
[&]() {
|
||||
auto ret = rclcpp::wait_for_message(out, node, "wait_for_message_topic" /*, -1 */);
|
||||
EXPECT_TRUE(ret);
|
||||
received = true;
|
||||
});
|
||||
|
||||
rclcpp::shutdown();
|
||||
|
||||
ASSERT_FALSE(received);
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
/**/foo/*/bar:
|
||||
node2:
|
||||
ros__parameters:
|
||||
foo: "foo"
|
||||
bar: "bar"
|
||||
@@ -0,0 +1,16 @@
|
||||
/**:
|
||||
node2:
|
||||
ros__parameters:
|
||||
a_value: "first"
|
||||
foo: "foo"
|
||||
|
||||
/ns:
|
||||
node2:
|
||||
ros__parameters:
|
||||
a_value: "second"
|
||||
bar: "bar"
|
||||
|
||||
/*:
|
||||
node2:
|
||||
ros__parameters:
|
||||
a_value: "last_one_win"
|
||||
57
rclcpp/test/resources/test_node_parameters/wildcards.yaml
Normal file
57
rclcpp/test/resources/test_node_parameters/wildcards.yaml
Normal file
@@ -0,0 +1,57 @@
|
||||
/**:
|
||||
ros__parameters:
|
||||
full_wild: "full_wild"
|
||||
|
||||
/**:
|
||||
node2:
|
||||
ros__parameters:
|
||||
namespace_wild: "namespace_wild"
|
||||
|
||||
/**/node2:
|
||||
ros__parameters:
|
||||
namespace_wild_another: "namespace_wild_another"
|
||||
|
||||
/*:
|
||||
node2:
|
||||
ros__parameters:
|
||||
namespace_wild_one_star: "namespace_wild_one_star"
|
||||
|
||||
ns:
|
||||
"*":
|
||||
ros__parameters:
|
||||
node_wild_in_ns: "node_wild_in_ns"
|
||||
|
||||
/ns/*:
|
||||
ros__parameters:
|
||||
node_wild_in_ns_another: "node_wild_in_ns_another"
|
||||
|
||||
ns:
|
||||
node2:
|
||||
ros__parameters:
|
||||
explicit_in_ns: "explicit_in_ns"
|
||||
|
||||
"*":
|
||||
ros__parameters:
|
||||
node_wild_no_ns: "node_wild_no_ns"
|
||||
|
||||
node2:
|
||||
ros__parameters:
|
||||
explicit_no_ns: "explicit_no_ns"
|
||||
|
||||
ns:
|
||||
nodeX:
|
||||
ros__parameters:
|
||||
should_not_appear: "incorrect_node_name"
|
||||
|
||||
/**/nodeX:
|
||||
ros__parameters:
|
||||
should_not_appear: "incorrect_node_name"
|
||||
|
||||
nsX:
|
||||
node2:
|
||||
ros__parameters:
|
||||
should_not_appear: "incorrect_namespace"
|
||||
|
||||
/nsX/*:
|
||||
ros__parameters:
|
||||
should_not_appear: "incorrect_namespace"
|
||||
@@ -3,24 +3,28 @@ Changelog for package rclcpp_action
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
11.2.0 (2021-07-21)
|
||||
-------------------
|
||||
9.2.2 (2022-12-06)
|
||||
------------------
|
||||
|
||||
11.1.0 (2021-07-13)
|
||||
-------------------
|
||||
* Fixed occasionally missing goal result caused by race condition (`#1677 <https://github.com/ros2/rclcpp/issues/1677>`_)
|
||||
* Contributors: Kaven Yau
|
||||
9.2.1 (2022-04-28)
|
||||
------------------
|
||||
|
||||
11.0.0 (2021-05-18)
|
||||
-------------------
|
||||
* Bump the benchmark timeout for benchmark_action_client (`#1671 <https://github.com/ros2/rclcpp/issues/1671>`_)
|
||||
9.2.0 (2021-09-17)
|
||||
------------------
|
||||
* Fixed a bug where it would occasionally miss a goal result, which was caused by race condition (`#1677 <https://github.com/ros2/rclcpp/issues/1677>`_) (`#1683 <https://github.com/ros2/rclcpp/issues/1683>`_)
|
||||
* Co-authored-by: Kaven Yau <kavenyau@foxmail.com>
|
||||
* Contributors: Tomoya Fujita
|
||||
|
||||
9.1.0 (2021-05-20)
|
||||
------------------
|
||||
* Bump the benchmark timeout for benchmark_action_client (`#1672 <https://github.com/ros2/rclcpp/issues/1672>`_)
|
||||
* Contributors: Scott K Logan
|
||||
|
||||
10.0.0 (2021-05-11)
|
||||
-------------------
|
||||
* Returns CancelResponse::REJECT while goal handle failed to transit to CANCELING state (`#1641 <https://github.com/ros2/rclcpp/issues/1641>`_)
|
||||
* Fix action server deadlock issue that caused by other mutexes locked in CancelCallback (`#1635 <https://github.com/ros2/rclcpp/issues/1635>`_)
|
||||
* Contributors: Kaven Yau
|
||||
9.0.3 (2021-05-10)
|
||||
------------------
|
||||
* Returns CancelResponse::REJECT while goal handle failed to transit to CANCELING state (`#1641 <https://github.com/ros2/rclcpp/issues/1641>`_) (`#1653 <https://github.com/ros2/rclcpp/issues/1653>`_)
|
||||
* Fix action server deadlock issue that caused by other mutexes locked in CancelCallback (`#1635 <https://github.com/ros2/rclcpp/issues/1635>`_) (`#1646 <https://github.com/ros2/rclcpp/issues/1646>`_)
|
||||
* Contributors: Jacob Perron, Kaven Yau, William Woodall
|
||||
|
||||
9.0.2 (2021-04-14)
|
||||
------------------
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="2">
|
||||
<name>rclcpp_action</name>
|
||||
<version>11.2.0</version>
|
||||
<version>9.2.2</version>
|
||||
<description>Adds action APIs for C++.</description>
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
<maintainer email="mabel@openrobotics.org">Mabel Zhang</maintainer>
|
||||
|
||||
@@ -2,21 +2,20 @@
|
||||
Changelog for package rclcpp_components
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
11.2.0 (2021-07-21)
|
||||
-------------------
|
||||
* Deprecate method names that use CamelCase in rclcpp_components. (`#1716 <https://github.com/ros2/rclcpp/issues/1716>`_)
|
||||
* Contributors: Rebecca Butler
|
||||
9.2.2 (2022-12-06)
|
||||
------------------
|
||||
|
||||
11.1.0 (2021-07-13)
|
||||
-------------------
|
||||
* Added a hook to generate node options in ComponentManager (`#1702 <https://github.com/ros2/rclcpp/issues/1702>`_)
|
||||
* Contributors: Rebecca Butler
|
||||
9.2.1 (2022-04-28)
|
||||
------------------
|
||||
|
||||
11.0.0 (2021-05-18)
|
||||
-------------------
|
||||
9.2.0 (2021-09-17)
|
||||
------------------
|
||||
|
||||
10.0.0 (2021-05-11)
|
||||
-------------------
|
||||
9.1.0 (2021-05-20)
|
||||
------------------
|
||||
|
||||
9.0.3 (2021-05-10)
|
||||
------------------
|
||||
|
||||
9.0.2 (2021-04-14)
|
||||
------------------
|
||||
|
||||
@@ -109,7 +109,7 @@ public:
|
||||
virtual ~ComponentManager();
|
||||
|
||||
/// Return a list of valid loadable components in a given package.
|
||||
/**
|
||||
/*
|
||||
* \param package_name name of the package
|
||||
* \param resource_index name of the executable
|
||||
* \throws ComponentManagerException if the resource was not found or a invalid resource entry
|
||||
@@ -122,7 +122,7 @@ public:
|
||||
const std::string & resource_index = "rclcpp_components") const;
|
||||
|
||||
/// Instantiate a component from a dynamic library.
|
||||
/**
|
||||
/*
|
||||
* \param resource a component resource (class name + library path)
|
||||
* \return a NodeFactory interface
|
||||
*/
|
||||
@@ -131,17 +131,8 @@ public:
|
||||
create_component_factory(const ComponentResource & resource);
|
||||
|
||||
protected:
|
||||
/// Create node options for loaded component
|
||||
/**
|
||||
* \param request information with the node to load
|
||||
* \return node options
|
||||
*/
|
||||
RCLCPP_COMPONENTS_PUBLIC
|
||||
virtual rclcpp::NodeOptions
|
||||
create_node_options(const std::shared_ptr<LoadNode::Request> request);
|
||||
|
||||
/// Service callback to load a new node in the component
|
||||
/**
|
||||
/*
|
||||
* This function allows to add parameters, remap rules, a specific node, name a namespace
|
||||
* and/or additional arguments.
|
||||
*
|
||||
@@ -155,27 +146,13 @@ protected:
|
||||
*/
|
||||
RCLCPP_COMPONENTS_PUBLIC
|
||||
virtual void
|
||||
on_load_node(
|
||||
OnLoadNode(
|
||||
const std::shared_ptr<rmw_request_id_t> request_header,
|
||||
const std::shared_ptr<LoadNode::Request> request,
|
||||
std::shared_ptr<LoadNode::Response> response);
|
||||
|
||||
/**
|
||||
* \deprecated Use on_load_node() instead
|
||||
*/
|
||||
[[deprecated("Use on_load_node() instead")]]
|
||||
RCLCPP_COMPONENTS_PUBLIC
|
||||
virtual void
|
||||
OnLoadNode(
|
||||
const std::shared_ptr<rmw_request_id_t> request_header,
|
||||
const std::shared_ptr<LoadNode::Request> request,
|
||||
std::shared_ptr<LoadNode::Response> response)
|
||||
{
|
||||
on_load_node(request_header, request, response);
|
||||
}
|
||||
|
||||
/// Service callback to unload a node in the component
|
||||
/**
|
||||
/*
|
||||
* \param request_header unused
|
||||
* \param request unique identifier to remove from the component
|
||||
* \param response true on the success field if the node unload was succefully, otherwise false
|
||||
@@ -183,27 +160,13 @@ protected:
|
||||
*/
|
||||
RCLCPP_COMPONENTS_PUBLIC
|
||||
virtual void
|
||||
on_unload_node(
|
||||
OnUnloadNode(
|
||||
const std::shared_ptr<rmw_request_id_t> request_header,
|
||||
const std::shared_ptr<UnloadNode::Request> request,
|
||||
std::shared_ptr<UnloadNode::Response> response);
|
||||
|
||||
/**
|
||||
* \deprecated Use on_unload_node() instead
|
||||
*/
|
||||
[[deprecated("Use on_unload_node() instead")]]
|
||||
RCLCPP_COMPONENTS_PUBLIC
|
||||
virtual void
|
||||
OnUnloadNode(
|
||||
const std::shared_ptr<rmw_request_id_t> request_header,
|
||||
const std::shared_ptr<UnloadNode::Request> request,
|
||||
std::shared_ptr<UnloadNode::Response> response)
|
||||
{
|
||||
on_unload_node(request_header, request, response);
|
||||
}
|
||||
|
||||
/// Service callback to get the list of nodes in the component
|
||||
/**
|
||||
/*
|
||||
* Return a two list: one with the unique identifiers and other with full name of the nodes.
|
||||
*
|
||||
* \param request_header unused
|
||||
@@ -212,24 +175,10 @@ protected:
|
||||
*/
|
||||
RCLCPP_COMPONENTS_PUBLIC
|
||||
virtual void
|
||||
on_list_nodes(
|
||||
const std::shared_ptr<rmw_request_id_t> request_header,
|
||||
const std::shared_ptr<ListNodes::Request> request,
|
||||
std::shared_ptr<ListNodes::Response> response);
|
||||
|
||||
/**
|
||||
* \deprecated Use on_list_nodes() instead
|
||||
*/
|
||||
[[deprecated("Use on_list_nodes() instead")]]
|
||||
RCLCPP_COMPONENTS_PUBLIC
|
||||
virtual void
|
||||
OnListNodes(
|
||||
const std::shared_ptr<rmw_request_id_t> request_header,
|
||||
const std::shared_ptr<ListNodes::Request> request,
|
||||
std::shared_ptr<ListNodes::Response> response)
|
||||
{
|
||||
on_list_nodes(request_header, request, response);
|
||||
}
|
||||
std::shared_ptr<ListNodes::Response> response);
|
||||
|
||||
private:
|
||||
std::weak_ptr<rclcpp::Executor> executor_;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="2">
|
||||
<name>rclcpp_components</name>
|
||||
<version>11.2.0</version>
|
||||
<version>9.2.2</version>
|
||||
<description>Package containing tools for dynamically loadable components</description>
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
<maintainer email="mabel@openrobotics.org">Mabel Zhang</maintainer>
|
||||
|
||||
@@ -39,13 +39,13 @@ ComponentManager::ComponentManager(
|
||||
{
|
||||
loadNode_srv_ = create_service<LoadNode>(
|
||||
"~/_container/load_node",
|
||||
std::bind(&ComponentManager::on_load_node, this, _1, _2, _3));
|
||||
std::bind(&ComponentManager::OnLoadNode, this, _1, _2, _3));
|
||||
unloadNode_srv_ = create_service<UnloadNode>(
|
||||
"~/_container/unload_node",
|
||||
std::bind(&ComponentManager::on_unload_node, this, _1, _2, _3));
|
||||
std::bind(&ComponentManager::OnUnloadNode, this, _1, _2, _3));
|
||||
listNodes_srv_ = create_service<ListNodes>(
|
||||
"~/_container/list_nodes",
|
||||
std::bind(&ComponentManager::on_list_nodes, this, _1, _2, _3));
|
||||
std::bind(&ComponentManager::OnListNodes, this, _1, _2, _3));
|
||||
}
|
||||
|
||||
ComponentManager::~ComponentManager()
|
||||
@@ -121,53 +121,8 @@ ComponentManager::create_component_factory(const ComponentResource & resource)
|
||||
return {};
|
||||
}
|
||||
|
||||
rclcpp::NodeOptions
|
||||
ComponentManager::create_node_options(const std::shared_ptr<LoadNode::Request> request)
|
||||
{
|
||||
std::vector<rclcpp::Parameter> parameters;
|
||||
for (const auto & p : request->parameters) {
|
||||
parameters.push_back(rclcpp::Parameter::from_parameter_msg(p));
|
||||
}
|
||||
|
||||
std::vector<std::string> remap_rules;
|
||||
remap_rules.reserve(request->remap_rules.size() * 2 + 1);
|
||||
remap_rules.push_back("--ros-args");
|
||||
for (const std::string & rule : request->remap_rules) {
|
||||
remap_rules.push_back("-r");
|
||||
remap_rules.push_back(rule);
|
||||
}
|
||||
|
||||
if (!request->node_name.empty()) {
|
||||
remap_rules.push_back("-r");
|
||||
remap_rules.push_back("__node:=" + request->node_name);
|
||||
}
|
||||
|
||||
if (!request->node_namespace.empty()) {
|
||||
remap_rules.push_back("-r");
|
||||
remap_rules.push_back("__ns:=" + request->node_namespace);
|
||||
}
|
||||
|
||||
auto options = rclcpp::NodeOptions()
|
||||
.use_global_arguments(false)
|
||||
.parameter_overrides(parameters)
|
||||
.arguments(remap_rules);
|
||||
|
||||
for (const auto & a : request->extra_arguments) {
|
||||
const rclcpp::Parameter extra_argument = rclcpp::Parameter::from_parameter_msg(a);
|
||||
if (extra_argument.get_name() == "use_intra_process_comms") {
|
||||
if (extra_argument.get_type() != rclcpp::ParameterType::PARAMETER_BOOL) {
|
||||
throw ComponentManagerException(
|
||||
"Extra component argument 'use_intra_process_comms' must be a boolean");
|
||||
}
|
||||
options.use_intra_process_comms(extra_argument.get_value<bool>());
|
||||
}
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
void
|
||||
ComponentManager::on_load_node(
|
||||
ComponentManager::OnLoadNode(
|
||||
const std::shared_ptr<rmw_request_id_t> request_header,
|
||||
const std::shared_ptr<LoadNode::Request> request,
|
||||
std::shared_ptr<LoadNode::Response> response)
|
||||
@@ -187,7 +142,45 @@ ComponentManager::on_load_node(
|
||||
continue;
|
||||
}
|
||||
|
||||
auto options = create_node_options(request);
|
||||
std::vector<rclcpp::Parameter> parameters;
|
||||
for (const auto & p : request->parameters) {
|
||||
parameters.push_back(rclcpp::Parameter::from_parameter_msg(p));
|
||||
}
|
||||
|
||||
std::vector<std::string> remap_rules;
|
||||
remap_rules.reserve(request->remap_rules.size() * 2 + 1);
|
||||
remap_rules.push_back("--ros-args");
|
||||
for (const std::string & rule : request->remap_rules) {
|
||||
remap_rules.push_back("-r");
|
||||
remap_rules.push_back(rule);
|
||||
}
|
||||
|
||||
if (!request->node_name.empty()) {
|
||||
remap_rules.push_back("-r");
|
||||
remap_rules.push_back("__node:=" + request->node_name);
|
||||
}
|
||||
|
||||
if (!request->node_namespace.empty()) {
|
||||
remap_rules.push_back("-r");
|
||||
remap_rules.push_back("__ns:=" + request->node_namespace);
|
||||
}
|
||||
|
||||
auto options = rclcpp::NodeOptions()
|
||||
.use_global_arguments(false)
|
||||
.parameter_overrides(parameters)
|
||||
.arguments(remap_rules);
|
||||
|
||||
for (const auto & a : request->extra_arguments) {
|
||||
const rclcpp::Parameter extra_argument = rclcpp::Parameter::from_parameter_msg(a);
|
||||
if (extra_argument.get_name() == "use_intra_process_comms") {
|
||||
if (extra_argument.get_type() != rclcpp::ParameterType::PARAMETER_BOOL) {
|
||||
throw ComponentManagerException(
|
||||
"Extra component argument 'use_intra_process_comms' must be a boolean");
|
||||
}
|
||||
options.use_intra_process_comms(extra_argument.get_value<bool>());
|
||||
}
|
||||
}
|
||||
|
||||
auto node_id = unique_id_++;
|
||||
|
||||
if (0 == node_id) {
|
||||
@@ -237,7 +230,7 @@ ComponentManager::on_load_node(
|
||||
}
|
||||
|
||||
void
|
||||
ComponentManager::on_unload_node(
|
||||
ComponentManager::OnUnloadNode(
|
||||
const std::shared_ptr<rmw_request_id_t> request_header,
|
||||
const std::shared_ptr<UnloadNode::Request> request,
|
||||
std::shared_ptr<UnloadNode::Response> response)
|
||||
@@ -262,7 +255,7 @@ ComponentManager::on_unload_node(
|
||||
}
|
||||
|
||||
void
|
||||
ComponentManager::on_list_nodes(
|
||||
ComponentManager::OnListNodes(
|
||||
const std::shared_ptr<rmw_request_id_t> request_header,
|
||||
const std::shared_ptr<ListNodes::Request> request,
|
||||
std::shared_ptr<ListNodes::Response> response)
|
||||
|
||||
@@ -3,21 +3,24 @@ Changelog for package rclcpp_lifecycle
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
11.2.0 (2021-07-21)
|
||||
-------------------
|
||||
9.2.2 (2022-12-06)
|
||||
------------------
|
||||
|
||||
11.1.0 (2021-07-13)
|
||||
-------------------
|
||||
9.2.1 (2022-04-28)
|
||||
------------------
|
||||
|
||||
11.0.0 (2021-05-18)
|
||||
-------------------
|
||||
* Fix destruction order in lifecycle benchmark (`#1675 <https://github.com/ros2/rclcpp/issues/1675>`_)
|
||||
9.2.0 (2021-09-17)
|
||||
------------------
|
||||
* Added thread safe for_each_callback_group method (`#1741 <https://github.com/ros2/rclcpp/issues/1741>`_)
|
||||
* Contributors: Aditya Pande
|
||||
|
||||
9.1.0 (2021-05-20)
|
||||
------------------
|
||||
* Fix destruction order in lifecycle benchmark (`#1676 <https://github.com/ros2/rclcpp/issues/1676>`_)
|
||||
* Contributors: Scott K Logan
|
||||
|
||||
10.0.0 (2021-05-11)
|
||||
-------------------
|
||||
* [rclcpp] Type Adaptation feature (`#1557 <https://github.com/ros2/rclcpp/issues/1557>`_)
|
||||
* Contributors: Audrow Nash, William Woodall
|
||||
9.0.3 (2021-05-10)
|
||||
------------------
|
||||
|
||||
9.0.2 (2021-04-14)
|
||||
------------------
|
||||
|
||||
@@ -200,6 +200,18 @@ public:
|
||||
const std::vector<rclcpp::CallbackGroup::WeakPtr> &
|
||||
get_callback_groups() const;
|
||||
|
||||
/// Iterate over the callback groups in the node, calling the given function on each valid one.
|
||||
/**
|
||||
* This method is called in a thread-safe way, and also makes sure to only call the given
|
||||
* function on those items that are still valid.
|
||||
*
|
||||
* \param[in] func The callback function to call on each valid callback group.
|
||||
*/
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
void
|
||||
for_each_callback_group(
|
||||
const rclcpp::node_interfaces::NodeBaseInterface::CallbackGroupFunction & func);
|
||||
|
||||
/// Create and return a Publisher.
|
||||
/**
|
||||
* \param[in] topic_name The topic for this publisher to publish on.
|
||||
@@ -230,8 +242,13 @@ public:
|
||||
typename MessageT,
|
||||
typename CallbackT,
|
||||
typename AllocatorT = std::allocator<void>,
|
||||
typename CallbackMessageT =
|
||||
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type,
|
||||
typename SubscriptionT = rclcpp::Subscription<MessageT, AllocatorT>,
|
||||
typename MessageMemoryStrategyT = typename SubscriptionT::MessageMemoryStrategyType>
|
||||
typename MessageMemoryStrategyT = rclcpp::message_memory_strategy::MessageMemoryStrategy<
|
||||
CallbackMessageT,
|
||||
AllocatorT
|
||||
>>
|
||||
std::shared_ptr<SubscriptionT>
|
||||
create_subscription(
|
||||
const std::string & topic_name,
|
||||
|
||||
@@ -61,6 +61,7 @@ template<
|
||||
typename MessageT,
|
||||
typename CallbackT,
|
||||
typename AllocatorT,
|
||||
typename CallbackMessageT,
|
||||
typename SubscriptionT,
|
||||
typename MessageMemoryStrategyT>
|
||||
std::shared_ptr<SubscriptionT>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="2">
|
||||
<name>rclcpp_lifecycle</name>
|
||||
<version>11.2.0</version>
|
||||
<version>9.2.2</version>
|
||||
<description>Package containing a prototype for lifecycle implementation</description>
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
<maintainer email="mabel@openrobotics.org">Mabel Zhang</maintainer>
|
||||
|
||||
@@ -651,4 +651,11 @@ LifecycleNode::add_timer_handle(std::shared_ptr<rclcpp::TimerBase> timer)
|
||||
impl_->add_timer_handle(timer);
|
||||
}
|
||||
|
||||
void
|
||||
LifecycleNode::for_each_callback_group(
|
||||
const rclcpp::node_interfaces::NodeBaseInterface::CallbackGroupFunction & func)
|
||||
{
|
||||
rclcpp::node_interfaces::global_for_each_callback_group(node_base_.get(), func);
|
||||
}
|
||||
|
||||
} // namespace rclcpp_lifecycle
|
||||
|
||||
@@ -717,16 +717,27 @@ TEST_F(TestDefaultStateMachine, test_graph_services_by_node) {
|
||||
|
||||
TEST_F(TestDefaultStateMachine, test_callback_groups) {
|
||||
auto test_node = std::make_shared<EmptyLifecycleNode>("testnode");
|
||||
auto groups = test_node->get_callback_groups();
|
||||
EXPECT_EQ(groups.size(), 1u);
|
||||
size_t num_groups = 0;
|
||||
test_node->for_each_callback_group(
|
||||
[&num_groups](rclcpp::CallbackGroup::SharedPtr group_ptr)
|
||||
{
|
||||
(void)group_ptr;
|
||||
num_groups++;
|
||||
});
|
||||
EXPECT_EQ(num_groups, 1u);
|
||||
|
||||
auto group = test_node->create_callback_group(
|
||||
rclcpp::CallbackGroupType::MutuallyExclusive, true);
|
||||
EXPECT_NE(nullptr, group);
|
||||
|
||||
groups = test_node->get_callback_groups();
|
||||
EXPECT_EQ(groups.size(), 2u);
|
||||
EXPECT_EQ(groups[1].lock().get(), group.get());
|
||||
num_groups = 0;
|
||||
test_node->for_each_callback_group(
|
||||
[&num_groups](rclcpp::CallbackGroup::SharedPtr group_ptr)
|
||||
{
|
||||
(void)group_ptr;
|
||||
num_groups++;
|
||||
});
|
||||
EXPECT_EQ(num_groups, 2u);
|
||||
}
|
||||
|
||||
TEST_F(TestDefaultStateMachine, wait_for_graph_change)
|
||||
|
||||
Reference in New Issue
Block a user