Compare commits
52 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
676897df9d | ||
|
|
6602fcf7bc | ||
|
|
a5221336f6 | ||
|
|
7901bb9da4 | ||
|
|
6f6b5f2e36 | ||
|
|
126d517193 | ||
|
|
5d2b32b5c3 | ||
|
|
21f8a22311 | ||
|
|
2bb1dc2c71 | ||
|
|
d9b2744057 | ||
|
|
a19ad2134b | ||
|
|
26f6efa840 | ||
|
|
d08d9cf5ff | ||
|
|
2446fd000b | ||
|
|
411dbe8212 | ||
|
|
de841d9c8b | ||
|
|
9c098e544e | ||
|
|
0f331f90a9 | ||
|
|
620fcf1e05 | ||
|
|
d407a5e331 | ||
|
|
7f411371b3 | ||
|
|
76e2b2677b | ||
|
|
5049c45f85 | ||
|
|
4691063a61 | ||
|
|
f294488e17 | ||
|
|
8a02e3934c | ||
|
|
fff009a751 | ||
|
|
2204e44305 | ||
|
|
fcbe64cff4 | ||
|
|
c366e531fa | ||
|
|
5ffc963e1a | ||
|
|
7f7ffcf6ed | ||
|
|
13abc1beed | ||
|
|
e77c1fe550 | ||
|
|
00b9d0a018 | ||
|
|
77c7aaf917 | ||
|
|
9019a8d9b7 | ||
|
|
0644f220a2 | ||
|
|
32438a6a67 | ||
|
|
d6bd8baac5 | ||
|
|
623c3eb874 | ||
|
|
7c1143dc15 | ||
|
|
9ff864c6ae | ||
|
|
13182b5aad | ||
|
|
9284d7cefa | ||
|
|
c42745c5ba | ||
|
|
ea31f94eb4 | ||
|
|
f496291e81 | ||
|
|
dd6fad6d42 | ||
|
|
38734d769a | ||
|
|
e103b8d37e | ||
|
|
253d395d4e |
@@ -2,6 +2,64 @@
|
||||
Changelog for package rclcpp
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
26.0.0 (2024-01-24)
|
||||
-------------------
|
||||
* Increase the cppcheck timeout to 600 seconds. (`#2409 <https://github.com/ros2/rclcpp/issues/2409>`_)
|
||||
* Add transient local durability support to publisher and subscriptions when using intra-process communication (`#2303 <https://github.com/ros2/rclcpp/issues/2303>`_)
|
||||
* Stop storing the context in the guard condition. (`#2400 <https://github.com/ros2/rclcpp/issues/2400>`_)
|
||||
* Contributors: Chris Lalancette, Jeffery Hsu
|
||||
|
||||
25.0.0 (2023-12-26)
|
||||
-------------------
|
||||
* Updated GenericSubscription to AnySubscriptionCallback (`#1928 <https://github.com/ros2/rclcpp/issues/1928>`_)
|
||||
* make type support helper supported for service (`#2209 <https://github.com/ros2/rclcpp/issues/2209>`_)
|
||||
* Adding QoS to subscription options (`#2323 <https://github.com/ros2/rclcpp/issues/2323>`_)
|
||||
* Switch to target_link_libraries. (`#2374 <https://github.com/ros2/rclcpp/issues/2374>`_)
|
||||
* aligh with rcl that a rosout publisher of a node might not exist (`#2357 <https://github.com/ros2/rclcpp/issues/2357>`_)
|
||||
* Fix data race in EventHandlerBase (`#2349 <https://github.com/ros2/rclcpp/issues/2349>`_)
|
||||
* Support users holding onto shared pointers in the message memory pool (`#2336 <https://github.com/ros2/rclcpp/issues/2336>`_)
|
||||
* Contributors: Chen Lihui, Chris Lalancette, DensoADAS, Lucas Wendland, mauropasse
|
||||
|
||||
24.0.0 (2023-11-06)
|
||||
-------------------
|
||||
* fix (signal_handler.hpp): spelling (`#2356 <https://github.com/ros2/rclcpp/issues/2356>`_)
|
||||
* Updates to not use std::move in some places. (`#2353 <https://github.com/ros2/rclcpp/issues/2353>`_)
|
||||
* rclcpp::Time::max() clock type support. (`#2352 <https://github.com/ros2/rclcpp/issues/2352>`_)
|
||||
* Serialized Messages with Topic Statistics (`#2274 <https://github.com/ros2/rclcpp/issues/2274>`_)
|
||||
* Add a custom deleter when constructing rcl_service_t (`#2351 <https://github.com/ros2/rclcpp/issues/2351>`_)
|
||||
* Disable the loaned messages inside the executor. (`#2335 <https://github.com/ros2/rclcpp/issues/2335>`_)
|
||||
* Use message_info in SubscriptionTopicStatistics instead of typed message (`#2337 <https://github.com/ros2/rclcpp/issues/2337>`_)
|
||||
* Add missing 'enable_rosout' comments (`#2345 <https://github.com/ros2/rclcpp/issues/2345>`_)
|
||||
* Adjust rclcpp usage of type description service (`#2344 <https://github.com/ros2/rclcpp/issues/2344>`_)
|
||||
* address rate related flaky tests. (`#2329 <https://github.com/ros2/rclcpp/issues/2329>`_)
|
||||
* Fixes pointed out by the clang analyzer. (`#2339 <https://github.com/ros2/rclcpp/issues/2339>`_)
|
||||
* Remove useless ROSRate class (`#2326 <https://github.com/ros2/rclcpp/issues/2326>`_)
|
||||
* Contributors: Alexey Merzlyakov, Chris Lalancette, Jiaqi Li, Lucas Wendland, Michael Carroll, Michael Orlov, Tomoya Fujita, Zard-C
|
||||
|
||||
23.2.0 (2023-10-09)
|
||||
-------------------
|
||||
* add clients & services count (`#2072 <https://github.com/ros2/rclcpp/issues/2072>`_)
|
||||
* remove invalid sized allocation test for SerializedMessage. (`#2330 <https://github.com/ros2/rclcpp/issues/2330>`_)
|
||||
* Adding API to copy all parameters from one node to another (`#2304 <https://github.com/ros2/rclcpp/issues/2304>`_)
|
||||
* Contributors: Minju, Lee, Steve Macenski, Tomoya Fujita
|
||||
|
||||
23.1.0 (2023-10-04)
|
||||
-------------------
|
||||
* Add locking to protect the TimeSource::NodeState::node_base\_ (`#2320 <https://github.com/ros2/rclcpp/issues/2320>`_)
|
||||
* Update SignalHandler get_global_signal_handler to avoid complex types in static memory (`#2316 <https://github.com/ros2/rclcpp/issues/2316>`_)
|
||||
* Removing Old Connext Tests (`#2313 <https://github.com/ros2/rclcpp/issues/2313>`_)
|
||||
* Documentation for list_parameters (`#2315 <https://github.com/ros2/rclcpp/issues/2315>`_)
|
||||
* Decouple rosout publisher init from node init. (`#2174 <https://github.com/ros2/rclcpp/issues/2174>`_)
|
||||
* fix the depth to relative in list_parameters (`#2300 <https://github.com/ros2/rclcpp/issues/2300>`_)
|
||||
* Contributors: Chris Lalancette, Lucas Wendland, Minju, Lee, Tomoya Fujita, Tully Foote
|
||||
|
||||
23.0.0 (2023-09-08)
|
||||
-------------------
|
||||
* Fix the return type of Rate::period. (`#2301 <https://github.com/ros2/rclcpp/issues/2301>`_)
|
||||
* Update API docs links in package READMEs (`#2302 <https://github.com/ros2/rclcpp/issues/2302>`_)
|
||||
* Cleanup flaky timers_manager tests. (`#2299 <https://github.com/ros2/rclcpp/issues/2299>`_)
|
||||
* Contributors: Chris Lalancette, Christophe Bedard
|
||||
|
||||
22.2.0 (2023-09-07)
|
||||
-------------------
|
||||
* Topic correct typeadapter deduction (`#2294 <https://github.com/ros2/rclcpp/issues/2294>`_)
|
||||
|
||||
@@ -16,6 +16,8 @@ find_package(rcpputils REQUIRED)
|
||||
find_package(rcutils REQUIRED)
|
||||
find_package(rmw REQUIRED)
|
||||
find_package(rosgraph_msgs REQUIRED)
|
||||
find_package(rosidl_dynamic_typesupport REQUIRED)
|
||||
find_package(rosidl_runtime_c REQUIRED)
|
||||
find_package(rosidl_runtime_cpp REQUIRED)
|
||||
find_package(rosidl_typesupport_c REQUIRED)
|
||||
find_package(rosidl_typesupport_cpp REQUIRED)
|
||||
@@ -44,6 +46,7 @@ set(${PROJECT_NAME}_SRCS
|
||||
src/rclcpp/context.cpp
|
||||
src/rclcpp/contexts/default_context.cpp
|
||||
src/rclcpp/detail/add_guard_condition_to_rcl_wait_set.cpp
|
||||
src/rclcpp/detail/resolve_intra_process_buffer_type.cpp
|
||||
src/rclcpp/detail/resolve_parameter_overrides.cpp
|
||||
src/rclcpp/detail/rmw_implementation_specific_payload.cpp
|
||||
src/rclcpp/detail/rmw_implementation_specific_publisher_payload.cpp
|
||||
@@ -202,23 +205,28 @@ target_include_directories(${PROJECT_NAME} PUBLIC
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>"
|
||||
"$<INSTALL_INTERFACE:include/${PROJECT_NAME}>")
|
||||
target_link_libraries(${PROJECT_NAME} ${CMAKE_THREAD_LIBS_INIT})
|
||||
# specific order: dependents before dependencies
|
||||
ament_target_dependencies(${PROJECT_NAME}
|
||||
"ament_index_cpp"
|
||||
"libstatistics_collector"
|
||||
"rcl"
|
||||
"rcl_interfaces"
|
||||
"rcl_logging_interface"
|
||||
"rcl_yaml_param_parser"
|
||||
"rcpputils"
|
||||
"rcutils"
|
||||
"builtin_interfaces"
|
||||
"rosgraph_msgs"
|
||||
"rosidl_typesupport_cpp"
|
||||
"rosidl_runtime_cpp"
|
||||
"statistics_msgs"
|
||||
"tracetools"
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC
|
||||
${builtin_interfaces_TARGETS}
|
||||
libstatistics_collector::libstatistics_collector
|
||||
rcl::rcl
|
||||
${rcl_interfaces_TARGETS}
|
||||
rcl_yaml_param_parser::rcl_yaml_param_parser
|
||||
rcpputils::rcpputils
|
||||
rcutils::rcutils
|
||||
rmw::rmw
|
||||
${rosgraph_msgs_TARGETS}
|
||||
rosidl_dynamic_typesupport::rosidl_dynamic_typesupport
|
||||
rosidl_runtime_c::rosidl_runtime_c
|
||||
rosidl_runtime_cpp::rosidl_runtime_cpp
|
||||
rosidl_typesupport_cpp::rosidl_typesupport_cpp
|
||||
${statistics_msgs_TARGETS}
|
||||
tracetools::tracetools
|
||||
${CMAKE_THREAD_LIBS_INIT}
|
||||
)
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||
ament_index_cpp::ament_index_cpp
|
||||
rcl_logging_interface::rcl_logging_interface
|
||||
)
|
||||
|
||||
# Causes the visibility macros to use dllexport rather than dllimport,
|
||||
@@ -240,20 +248,23 @@ ament_export_libraries(${PROJECT_NAME})
|
||||
# Export modern CMake targets
|
||||
ament_export_targets(${PROJECT_NAME})
|
||||
|
||||
# specific order: dependents before dependencies
|
||||
ament_export_dependencies(ament_index_cpp)
|
||||
ament_export_dependencies(libstatistics_collector)
|
||||
ament_export_dependencies(rcl)
|
||||
ament_export_dependencies(rcpputils)
|
||||
ament_export_dependencies(rcutils)
|
||||
ament_export_dependencies(builtin_interfaces)
|
||||
ament_export_dependencies(rosgraph_msgs)
|
||||
ament_export_dependencies(rosidl_typesupport_cpp)
|
||||
ament_export_dependencies(rosidl_typesupport_c)
|
||||
ament_export_dependencies(rosidl_runtime_cpp)
|
||||
ament_export_dependencies(rcl_yaml_param_parser)
|
||||
ament_export_dependencies(statistics_msgs)
|
||||
ament_export_dependencies(tracetools)
|
||||
ament_export_dependencies(
|
||||
builtin_interfaces
|
||||
libstatistics_collector
|
||||
rcl
|
||||
rcl_interfaces
|
||||
rcl_yaml_param_parser
|
||||
rcpputils
|
||||
rcutils
|
||||
rmw
|
||||
rosgraph_msgs
|
||||
rosidl_dynamic_typesupport
|
||||
rosidl_runtime_c
|
||||
rosidl_runtime_cpp
|
||||
rosidl_typesupport_cpp
|
||||
statistics_msgs
|
||||
tracetools
|
||||
)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
find_package(ament_lint_auto REQUIRED)
|
||||
@@ -271,7 +282,7 @@ install(
|
||||
|
||||
if(TEST cppcheck)
|
||||
# must set the property after ament_package()
|
||||
set_tests_properties(cppcheck PROPERTIES TIMEOUT 500)
|
||||
set_tests_properties(cppcheck PROPERTIES TIMEOUT 600)
|
||||
endif()
|
||||
|
||||
if(TEST cpplint)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
The ROS client library in C++.
|
||||
|
||||
Visit the [rclcpp API documentation](http://docs.ros2.org/latest/api/rclcpp/) for a complete list of its main components and features.
|
||||
The link to the latest rclcpp API documentation, which includes a complete list of its main components and features, can be found on the rclcpp package info page, at the [ROS Index](https://index.ros.org/p/rclcpp/).
|
||||
|
||||
## Quality Declaration
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "rclcpp/detail/subscription_callback_type_helper.hpp"
|
||||
#include "rclcpp/function_traits.hpp"
|
||||
#include "rclcpp/message_info.hpp"
|
||||
#include "rclcpp/serialization.hpp"
|
||||
#include "rclcpp/serialized_message.hpp"
|
||||
#include "rclcpp/type_adapter.hpp"
|
||||
|
||||
@@ -158,13 +159,14 @@ struct AnySubscriptionCallbackPossibleTypes
|
||||
template<
|
||||
typename MessageT,
|
||||
typename AllocatorT,
|
||||
bool is_adapted_type = rclcpp::TypeAdapter<MessageT>::is_specialized::value
|
||||
bool is_adapted_type = rclcpp::TypeAdapter<MessageT>::is_specialized::value,
|
||||
bool is_serialized_type = serialization_traits::is_serialized_message_class<MessageT>::value
|
||||
>
|
||||
struct AnySubscriptionCallbackHelper;
|
||||
|
||||
/// Specialization for when MessageT is not a TypeAdapter.
|
||||
template<typename MessageT, typename AllocatorT>
|
||||
struct AnySubscriptionCallbackHelper<MessageT, AllocatorT, false>
|
||||
struct AnySubscriptionCallbackHelper<MessageT, AllocatorT, false, false>
|
||||
{
|
||||
using CallbackTypes = AnySubscriptionCallbackPossibleTypes<MessageT, AllocatorT>;
|
||||
|
||||
@@ -194,7 +196,7 @@ struct AnySubscriptionCallbackHelper<MessageT, AllocatorT, false>
|
||||
|
||||
/// Specialization for when MessageT is a TypeAdapter.
|
||||
template<typename MessageT, typename AllocatorT>
|
||||
struct AnySubscriptionCallbackHelper<MessageT, AllocatorT, true>
|
||||
struct AnySubscriptionCallbackHelper<MessageT, AllocatorT, true, false>
|
||||
{
|
||||
using CallbackTypes = AnySubscriptionCallbackPossibleTypes<MessageT, AllocatorT>;
|
||||
|
||||
@@ -232,6 +234,26 @@ struct AnySubscriptionCallbackHelper<MessageT, AllocatorT, true>
|
||||
>;
|
||||
};
|
||||
|
||||
/// Specialization for when MessageT is a SerializedMessage to exclude duplicated declarations.
|
||||
template<typename MessageT, typename AllocatorT>
|
||||
struct AnySubscriptionCallbackHelper<MessageT, AllocatorT, false, true>
|
||||
{
|
||||
using CallbackTypes = AnySubscriptionCallbackPossibleTypes<MessageT, AllocatorT>;
|
||||
|
||||
using variant_type = std::variant<
|
||||
typename CallbackTypes::ConstRefSerializedMessageCallback,
|
||||
typename CallbackTypes::ConstRefSerializedMessageWithInfoCallback,
|
||||
typename CallbackTypes::UniquePtrSerializedMessageCallback,
|
||||
typename CallbackTypes::UniquePtrSerializedMessageWithInfoCallback,
|
||||
typename CallbackTypes::SharedConstPtrSerializedMessageCallback,
|
||||
typename CallbackTypes::SharedConstPtrSerializedMessageWithInfoCallback,
|
||||
typename CallbackTypes::ConstRefSharedConstPtrSerializedMessageCallback,
|
||||
typename CallbackTypes::ConstRefSharedConstPtrSerializedMessageWithInfoCallback,
|
||||
typename CallbackTypes::SharedPtrSerializedMessageCallback,
|
||||
typename CallbackTypes::SharedPtrSerializedMessageWithInfoCallback
|
||||
>;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template<
|
||||
@@ -487,7 +509,9 @@ public:
|
||||
}
|
||||
|
||||
// Dispatch when input is a ros message and the output could be anything.
|
||||
void
|
||||
template<typename TMsg = ROSMessageType>
|
||||
typename std::enable_if<!serialization_traits::is_serialized_message_class<TMsg>::value,
|
||||
void>::type
|
||||
dispatch(
|
||||
std::shared_ptr<ROSMessageType> message,
|
||||
const rclcpp::MessageInfo & message_info)
|
||||
@@ -589,7 +613,7 @@ public:
|
||||
// Dispatch when input is a serialized message and the output could be anything.
|
||||
void
|
||||
dispatch(
|
||||
std::shared_ptr<rclcpp::SerializedMessage> serialized_message,
|
||||
std::shared_ptr<const rclcpp::SerializedMessage> serialized_message,
|
||||
const rclcpp::MessageInfo & message_info)
|
||||
{
|
||||
TRACETOOLS_TRACEPOINT(callback_start, static_cast<const void *>(this), false);
|
||||
|
||||
@@ -129,8 +129,7 @@ public:
|
||||
* added to the executor in either case.
|
||||
*
|
||||
* \param[in] group_type The type of the callback group.
|
||||
* \param[in] get_node_context Lambda to retrieve the node context when
|
||||
* checking that the creating node is valid and using the guard condition.
|
||||
* \param[in] context A weak pointer to the context associated with this callback group.
|
||||
* \param[in] automatically_add_to_executor_with_node A boolean that
|
||||
* determines whether a callback group is automatically added to an executor
|
||||
* with the node with which it is associated.
|
||||
@@ -138,7 +137,7 @@ public:
|
||||
RCLCPP_PUBLIC
|
||||
explicit CallbackGroup(
|
||||
CallbackGroupType group_type,
|
||||
std::function<rclcpp::Context::SharedPtr(void)> get_node_context,
|
||||
rclcpp::Context::WeakPtr context,
|
||||
bool automatically_add_to_executor_with_node = true);
|
||||
|
||||
/// Default destructor.
|
||||
@@ -228,16 +227,6 @@ public:
|
||||
bool
|
||||
automatically_add_to_executor_with_node() const;
|
||||
|
||||
/// Retrieve the guard condition used to signal changes to this callback group.
|
||||
/**
|
||||
* \param[in] context_ptr context to use when creating the guard condition
|
||||
* \return guard condition if it is valid, otherwise nullptr.
|
||||
*/
|
||||
[[deprecated("Use get_notify_guard_condition() without arguments")]]
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::GuardCondition::SharedPtr
|
||||
get_notify_guard_condition(const rclcpp::Context::SharedPtr context_ptr);
|
||||
|
||||
/// Retrieve the guard condition used to signal changes to this callback group.
|
||||
/**
|
||||
* \return guard condition if it is valid, otherwise nullptr.
|
||||
@@ -297,7 +286,7 @@ protected:
|
||||
std::shared_ptr<rclcpp::GuardCondition> notify_guard_condition_ = nullptr;
|
||||
std::recursive_mutex notify_guard_condition_mutex_;
|
||||
|
||||
std::function<rclcpp::Context::SharedPtr(void)> get_context_;
|
||||
rclcpp::Context::WeakPtr context_;
|
||||
|
||||
private:
|
||||
template<typename TypeT, typename Function>
|
||||
|
||||
82
rclcpp/include/rclcpp/copy_all_parameter_values.hpp
Normal file
82
rclcpp/include/rclcpp/copy_all_parameter_values.hpp
Normal file
@@ -0,0 +1,82 @@
|
||||
// Copyright 2023 Open Navigation LLC
|
||||
//
|
||||
// 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__COPY_ALL_PARAMETER_VALUES_HPP_
|
||||
#define RCLCPP__COPY_ALL_PARAMETER_VALUES_HPP_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "rcl_interfaces/srv/list_parameters.hpp"
|
||||
#include "rcl_interfaces/msg/parameter_descriptor.hpp"
|
||||
#include "rcl_interfaces/msg/set_parameters_result.hpp"
|
||||
|
||||
#include "rclcpp/parameter.hpp"
|
||||
#include "rclcpp/logger.hpp"
|
||||
#include "rclcpp/logging.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
/**
|
||||
* Copy all parameters from one source node to another destination node.
|
||||
* May throw exceptions if parameters from source are uninitialized or undeclared.
|
||||
* \param source Node to copy parameters from
|
||||
* \param destination Node to copy parameters to
|
||||
* \param override_existing_params Default false. Whether to override existing destination params
|
||||
* if both the source and destination contain the same parameter.
|
||||
*/
|
||||
template<typename NodeT1, typename NodeT2>
|
||||
void
|
||||
copy_all_parameter_values(
|
||||
const NodeT1 & source, const NodeT2 & destination, const bool override_existing_params = false)
|
||||
{
|
||||
using Parameters = std::vector<rclcpp::Parameter>;
|
||||
using Descriptions = std::vector<rcl_interfaces::msg::ParameterDescriptor>;
|
||||
auto source_params = source->get_node_parameters_interface();
|
||||
auto dest_params = destination->get_node_parameters_interface();
|
||||
rclcpp::Logger logger = destination->get_node_logging_interface()->get_logger();
|
||||
|
||||
std::vector<std::string> param_names = source_params->list_parameters({}, 0).names;
|
||||
Parameters params = source_params->get_parameters(param_names);
|
||||
Descriptions descriptions = source_params->describe_parameters(param_names);
|
||||
|
||||
for (unsigned int idx = 0; idx != params.size(); idx++) {
|
||||
if (!dest_params->has_parameter(params[idx].get_name())) {
|
||||
dest_params->declare_parameter(
|
||||
params[idx].get_name(), params[idx].get_parameter_value(), descriptions[idx]);
|
||||
} else if (override_existing_params) {
|
||||
try {
|
||||
rcl_interfaces::msg::SetParametersResult result =
|
||||
dest_params->set_parameters_atomically({params[idx]});
|
||||
if (!result.successful) {
|
||||
// Parameter update rejected or read-only
|
||||
RCLCPP_WARN(
|
||||
logger,
|
||||
"Unable to set parameter (%s): %s!",
|
||||
params[idx].get_name().c_str(), result.reason.c_str());
|
||||
}
|
||||
} catch (const rclcpp::exceptions::InvalidParameterTypeException & e) {
|
||||
RCLCPP_WARN(
|
||||
logger,
|
||||
"Unable to set parameter (%s): incompatable parameter type (%s)!",
|
||||
params[idx].get_name().c_str(), e.what());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__COPY_ALL_PARAMETER_VALUES_HPP_
|
||||
@@ -45,13 +45,15 @@ namespace rclcpp
|
||||
* Not all publisher options are currently respected, the only relevant options for this
|
||||
* publisher are `event_callbacks`, `use_default_callbacks`, and `%callback_group`.
|
||||
*/
|
||||
template<typename AllocatorT = std::allocator<void>>
|
||||
template<
|
||||
typename CallbackT,
|
||||
typename AllocatorT = std::allocator<void>>
|
||||
std::shared_ptr<GenericSubscription> create_generic_subscription(
|
||||
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr topics_interface,
|
||||
const std::string & topic_name,
|
||||
const std::string & topic_type,
|
||||
const rclcpp::QoS & qos,
|
||||
std::function<void(std::shared_ptr<rclcpp::SerializedMessage>)> callback,
|
||||
CallbackT && callback,
|
||||
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options = (
|
||||
rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>()
|
||||
)
|
||||
@@ -60,13 +62,20 @@ std::shared_ptr<GenericSubscription> create_generic_subscription(
|
||||
auto ts_lib = rclcpp::get_typesupport_library(
|
||||
topic_type, "rosidl_typesupport_cpp");
|
||||
|
||||
auto allocator = options.get_allocator();
|
||||
|
||||
using rclcpp::AnySubscriptionCallback;
|
||||
AnySubscriptionCallback<rclcpp::SerializedMessage, AllocatorT>
|
||||
any_subscription_callback(*allocator);
|
||||
any_subscription_callback.set(std::forward<CallbackT>(callback));
|
||||
|
||||
auto subscription = std::make_shared<GenericSubscription>(
|
||||
topics_interface->get_node_base_interface(),
|
||||
std::move(ts_lib),
|
||||
topic_name,
|
||||
topic_type,
|
||||
qos,
|
||||
callback,
|
||||
any_subscription_callback,
|
||||
options);
|
||||
|
||||
topics_interface->add_subscription(subscription, options.callback_group);
|
||||
|
||||
@@ -50,8 +50,8 @@ template<
|
||||
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>
|
||||
subscription_topic_stats = nullptr;
|
||||
|
||||
if (rclcpp::detail::resolve_enable_topic_statistics(
|
||||
@@ -80,8 +80,7 @@ create_subscription(
|
||||
if (options.topic_stats_options.publish_period <= std::chrono::milliseconds(0)) {
|
||||
throw std::invalid_argument(
|
||||
"topic_stats_options.publish_period must be greater than 0, specified value of " +
|
||||
std::to_string(options.topic_stats_options.publish_period.count()) +
|
||||
" ms");
|
||||
std::to_string(options.topic_stats_options.publish_period.count()) + " ms");
|
||||
}
|
||||
|
||||
std::shared_ptr<Publisher<statistics_msgs::msg::MetricsMessage>>
|
||||
@@ -89,14 +88,14 @@ create_subscription(
|
||||
node_parameters,
|
||||
node_topics_interface,
|
||||
options.topic_stats_options.publish_topic,
|
||||
qos);
|
||||
options.topic_stats_options.qos);
|
||||
|
||||
subscription_topic_stats = std::make_shared<
|
||||
rclcpp::topic_statistics::SubscriptionTopicStatistics<ROSMessageType>
|
||||
>(node_topics_interface->get_node_base_interface()->get_name(), publisher);
|
||||
subscription_topic_stats =
|
||||
std::make_shared<rclcpp::topic_statistics::SubscriptionTopicStatistics>(
|
||||
node_topics_interface->get_node_base_interface()->get_name(), publisher);
|
||||
|
||||
std::weak_ptr<
|
||||
rclcpp::topic_statistics::SubscriptionTopicStatistics<ROSMessageType>
|
||||
rclcpp::topic_statistics::SubscriptionTopicStatistics
|
||||
> weak_subscription_topic_stats(subscription_topic_stats);
|
||||
auto sub_call_back = [weak_subscription_topic_stats]() {
|
||||
auto subscription_topic_stats = weak_subscription_topic_stats.lock();
|
||||
|
||||
@@ -47,6 +47,11 @@ resolve_intra_process_buffer_type(
|
||||
return resolved_buffer_type;
|
||||
}
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::IntraProcessBufferType
|
||||
resolve_intra_process_buffer_type(
|
||||
const rclcpp::IntraProcessBufferType buffer_type);
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
@@ -260,6 +260,16 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
~EventHandler()
|
||||
{
|
||||
// Since the rmw event listener holds a reference to the
|
||||
// "on ready" callback, we need to clear it on destruction of this class.
|
||||
// This clearing is not needed for other rclcpp entities like pub/subs, since
|
||||
// they do own the underlying rmw entities, which are destroyed
|
||||
// on their rclcpp destructors, thus no risk of dangling pointers.
|
||||
clear_on_ready_callback();
|
||||
}
|
||||
|
||||
/// Take data so that the callback cannot be scheduled again
|
||||
std::shared_ptr<void>
|
||||
take_data() override
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#ifndef RCLCPP__EXPERIMENTAL__BUFFERS__BUFFER_IMPLEMENTATION_BASE_HPP_
|
||||
#define RCLCPP__EXPERIMENTAL__BUFFERS__BUFFER_IMPLEMENTATION_BASE_HPP_
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace experimental
|
||||
@@ -31,6 +33,8 @@ public:
|
||||
virtual BufferT dequeue() = 0;
|
||||
virtual void enqueue(BufferT request) = 0;
|
||||
|
||||
virtual std::vector<BufferT> get_all_data() = 0;
|
||||
|
||||
virtual void clear() = 0;
|
||||
virtual bool has_data() const = 0;
|
||||
virtual size_t available_capacity() const = 0;
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "rclcpp/allocator/allocator_common.hpp"
|
||||
#include "rclcpp/allocator/allocator_deleter.hpp"
|
||||
@@ -66,6 +67,9 @@ public:
|
||||
|
||||
virtual MessageSharedPtr consume_shared() = 0;
|
||||
virtual MessageUniquePtr consume_unique() = 0;
|
||||
|
||||
virtual std::vector<MessageSharedPtr> get_all_data_shared() = 0;
|
||||
virtual std::vector<MessageUniquePtr> get_all_data_unique() = 0;
|
||||
};
|
||||
|
||||
template<
|
||||
@@ -129,6 +133,16 @@ public:
|
||||
return consume_unique_impl<BufferT>();
|
||||
}
|
||||
|
||||
std::vector<MessageSharedPtr> get_all_data_shared() override
|
||||
{
|
||||
return get_all_data_shared_impl();
|
||||
}
|
||||
|
||||
std::vector<MessageUniquePtr> get_all_data_unique() override
|
||||
{
|
||||
return get_all_data_unique_impl();
|
||||
}
|
||||
|
||||
bool has_data() const override
|
||||
{
|
||||
return buffer_->has_data();
|
||||
@@ -243,6 +257,71 @@ private:
|
||||
{
|
||||
return buffer_->dequeue();
|
||||
}
|
||||
|
||||
// MessageSharedPtr to MessageSharedPtr
|
||||
template<typename T = BufferT>
|
||||
typename std::enable_if<
|
||||
std::is_same<T, MessageSharedPtr>::value,
|
||||
std::vector<MessageSharedPtr>
|
||||
>::type
|
||||
get_all_data_shared_impl()
|
||||
{
|
||||
return buffer_->get_all_data();
|
||||
}
|
||||
|
||||
// MessageUniquePtr to MessageSharedPtr
|
||||
template<typename T = BufferT>
|
||||
typename std::enable_if<
|
||||
std::is_same<T, MessageUniquePtr>::value,
|
||||
std::vector<MessageSharedPtr>
|
||||
>::type
|
||||
get_all_data_shared_impl()
|
||||
{
|
||||
std::vector<MessageSharedPtr> result;
|
||||
auto uni_ptr_vec = buffer_->get_all_data();
|
||||
result.reserve(uni_ptr_vec.size());
|
||||
for (MessageUniquePtr & uni_ptr : uni_ptr_vec) {
|
||||
result.emplace_back(std::move(uni_ptr));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// MessageSharedPtr to MessageUniquePtr
|
||||
template<typename T = BufferT>
|
||||
typename std::enable_if<
|
||||
std::is_same<T, MessageSharedPtr>::value,
|
||||
std::vector<MessageUniquePtr>
|
||||
>::type
|
||||
get_all_data_unique_impl()
|
||||
{
|
||||
std::vector<MessageUniquePtr> result;
|
||||
auto shared_ptr_vec = buffer_->get_all_data();
|
||||
result.reserve(shared_ptr_vec.size());
|
||||
for (MessageSharedPtr shared_msg : shared_ptr_vec) {
|
||||
MessageUniquePtr unique_msg;
|
||||
MessageDeleter * deleter = std::get_deleter<MessageDeleter, const MessageT>(shared_msg);
|
||||
auto ptr = MessageAllocTraits::allocate(*message_allocator_.get(), 1);
|
||||
MessageAllocTraits::construct(*message_allocator_.get(), ptr, *shared_msg);
|
||||
if (deleter) {
|
||||
unique_msg = MessageUniquePtr(ptr, *deleter);
|
||||
} else {
|
||||
unique_msg = MessageUniquePtr(ptr);
|
||||
}
|
||||
result.push_back(std::move(unique_msg));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// MessageUniquePtr to MessageUniquePtr
|
||||
template<typename T = BufferT>
|
||||
typename std::enable_if<
|
||||
std::is_same<T, MessageUniquePtr>::value,
|
||||
std::vector<MessageUniquePtr>
|
||||
>::type
|
||||
get_all_data_unique_impl()
|
||||
{
|
||||
return buffer_->get_all_data();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace buffers
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#ifndef RCLCPP__EXPERIMENTAL__BUFFERS__RING_BUFFER_IMPLEMENTATION_HPP_
|
||||
#define RCLCPP__EXPERIMENTAL__BUFFERS__RING_BUFFER_IMPLEMENTATION_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
@@ -113,6 +114,17 @@ public:
|
||||
return request;
|
||||
}
|
||||
|
||||
/// Get all the elements from the ring buffer
|
||||
/**
|
||||
* This member function is thread-safe.
|
||||
*
|
||||
* \return a vector containing all the elements from the ring buffer
|
||||
*/
|
||||
std::vector<BufferT> get_all_data() override
|
||||
{
|
||||
return get_all_data_impl();
|
||||
}
|
||||
|
||||
/// Get the next index value for the ring buffer
|
||||
/**
|
||||
* This member function is thread-safe.
|
||||
@@ -215,6 +227,71 @@ private:
|
||||
return capacity_ - size_;
|
||||
}
|
||||
|
||||
/// Traits for checking if a type is std::unique_ptr
|
||||
template<typename ...>
|
||||
struct is_std_unique_ptr final : std::false_type {};
|
||||
template<class T, typename ... Args>
|
||||
struct is_std_unique_ptr<std::unique_ptr<T, Args...>> final : std::true_type
|
||||
{
|
||||
typedef T Ptr_type;
|
||||
};
|
||||
|
||||
/// Get all the elements from the ring buffer
|
||||
/**
|
||||
* This member function is thread-safe.
|
||||
* Two versions for the implementation of the function.
|
||||
* One for buffer containing unique_ptr and the other for other types
|
||||
*
|
||||
* \return a vector containing all the elements from the ring buffer
|
||||
*/
|
||||
template<typename T = BufferT, std::enable_if_t<is_std_unique_ptr<T>::value &&
|
||||
std::is_copy_constructible<
|
||||
typename is_std_unique_ptr<T>::Ptr_type
|
||||
>::value,
|
||||
void> * = nullptr>
|
||||
std::vector<BufferT> get_all_data_impl()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
std::vector<BufferT> result_vtr;
|
||||
result_vtr.reserve(size_);
|
||||
for (size_t id = 0; id < size_; ++id) {
|
||||
result_vtr.emplace_back(
|
||||
new typename is_std_unique_ptr<T>::Ptr_type(
|
||||
*(ring_buffer_[(read_index_ + id) % capacity_])));
|
||||
}
|
||||
return result_vtr;
|
||||
}
|
||||
|
||||
template<typename T = BufferT, std::enable_if_t<
|
||||
std::is_copy_constructible<T>::value, void> * = nullptr>
|
||||
std::vector<BufferT> get_all_data_impl()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
std::vector<BufferT> result_vtr;
|
||||
result_vtr.reserve(size_);
|
||||
for (size_t id = 0; id < size_; ++id) {
|
||||
result_vtr.emplace_back(ring_buffer_[(read_index_ + id) % capacity_]);
|
||||
}
|
||||
return result_vtr;
|
||||
}
|
||||
|
||||
template<typename T = BufferT, std::enable_if_t<!is_std_unique_ptr<T>::value &&
|
||||
!std::is_copy_constructible<T>::value, void> * = nullptr>
|
||||
std::vector<BufferT> get_all_data_impl()
|
||||
{
|
||||
throw std::logic_error("Underlined type results in invalid get_all_data_impl()");
|
||||
return {};
|
||||
}
|
||||
|
||||
template<typename T = BufferT, std::enable_if_t<is_std_unique_ptr<T>::value &&
|
||||
!std::is_copy_constructible<typename is_std_unique_ptr<T>::Ptr_type>::value,
|
||||
void> * = nullptr>
|
||||
std::vector<BufferT> get_all_data_impl()
|
||||
{
|
||||
throw std::logic_error("Underlined type in unique_ptr results in invalid get_all_data_impl()");
|
||||
return {};
|
||||
}
|
||||
|
||||
size_t capacity_;
|
||||
|
||||
std::vector<BufferT> ring_buffer_;
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <typeinfo>
|
||||
|
||||
#include "rclcpp/allocator/allocator_deleter.hpp"
|
||||
#include "rclcpp/experimental/buffers/intra_process_buffer.hpp"
|
||||
#include "rclcpp/experimental/ros_message_intra_process_buffer.hpp"
|
||||
#include "rclcpp/experimental/subscription_intra_process.hpp"
|
||||
#include "rclcpp/experimental/subscription_intra_process_base.hpp"
|
||||
@@ -112,9 +113,40 @@ public:
|
||||
* \param subscription the SubscriptionIntraProcess to register.
|
||||
* \return an unsigned 64-bit integer which is the subscription's unique id.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
template<
|
||||
typename ROSMessageType,
|
||||
typename Alloc = std::allocator<ROSMessageType>
|
||||
>
|
||||
uint64_t
|
||||
add_subscription(rclcpp::experimental::SubscriptionIntraProcessBase::SharedPtr subscription);
|
||||
add_subscription(rclcpp::experimental::SubscriptionIntraProcessBase::SharedPtr subscription)
|
||||
{
|
||||
std::unique_lock<std::shared_timed_mutex> lock(mutex_);
|
||||
|
||||
uint64_t sub_id = IntraProcessManager::get_next_unique_id();
|
||||
|
||||
subscriptions_[sub_id] = subscription;
|
||||
|
||||
// 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 (publisher->is_durability_transient_local() &&
|
||||
subscription->is_durability_transient_local())
|
||||
{
|
||||
do_transient_local_publish<ROSMessageType, Alloc>(
|
||||
pub_id, sub_id,
|
||||
subscription->use_take_shared_method());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sub_id;
|
||||
}
|
||||
|
||||
/// Unregister a subscription using the subscription's unique id.
|
||||
/**
|
||||
@@ -131,14 +163,21 @@ public:
|
||||
* This method stores the publisher intra process object, together with
|
||||
* the information of its wrapped publisher (i.e. topic name and QoS).
|
||||
*
|
||||
* If the publisher's durability is transient local, its buffer pointer should
|
||||
* be passed and the method will store it as well.
|
||||
*
|
||||
* In addition this generates a unique intra process id for the publisher.
|
||||
*
|
||||
* \param publisher publisher to be registered with the manager.
|
||||
* \param buffer publisher's buffer to be stored if its duability is transient local.
|
||||
* \return an unsigned 64-bit integer which is the publisher's unique id.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
uint64_t
|
||||
add_publisher(rclcpp::PublisherBase::SharedPtr publisher);
|
||||
add_publisher(
|
||||
rclcpp::PublisherBase::SharedPtr publisher,
|
||||
rclcpp::experimental::buffers::IntraProcessBufferBase::SharedPtr buffer =
|
||||
rclcpp::experimental::buffers::IntraProcessBufferBase::SharedPtr());
|
||||
|
||||
/// Unregister a publisher using the publisher's unique id.
|
||||
/**
|
||||
@@ -292,6 +331,34 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
template<
|
||||
typename MessageT,
|
||||
typename Alloc,
|
||||
typename Deleter,
|
||||
typename ROSMessageType>
|
||||
void
|
||||
add_shared_msg_to_buffer(
|
||||
std::shared_ptr<const MessageT> message,
|
||||
uint64_t subscription_id)
|
||||
{
|
||||
add_shared_msg_to_buffers<MessageT, Alloc, Deleter, ROSMessageType>(message, {subscription_id});
|
||||
}
|
||||
|
||||
template<
|
||||
typename MessageT,
|
||||
typename Alloc,
|
||||
typename Deleter,
|
||||
typename ROSMessageType>
|
||||
void
|
||||
add_owned_msg_to_buffer(
|
||||
std::unique_ptr<MessageT, Deleter> message,
|
||||
uint64_t subscription_id,
|
||||
typename allocator::AllocRebind<MessageT, Alloc>::allocator_type & allocator)
|
||||
{
|
||||
add_owned_msg_to_buffers<MessageT, Alloc, Deleter, ROSMessageType>(
|
||||
std::move(message), {subscription_id}, allocator);
|
||||
}
|
||||
|
||||
/// Return true if the given rmw_gid_t matches any stored Publishers.
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
@@ -324,6 +391,9 @@ private:
|
||||
using PublisherMap =
|
||||
std::unordered_map<uint64_t, rclcpp::PublisherBase::WeakPtr>;
|
||||
|
||||
using PublisherBufferMap =
|
||||
std::unordered_map<uint64_t, rclcpp::experimental::buffers::IntraProcessBufferBase::WeakPtr>;
|
||||
|
||||
using PublisherToSubscriptionIdsMap =
|
||||
std::unordered_map<uint64_t, SplittedSubscriptions>;
|
||||
|
||||
@@ -342,6 +412,54 @@ private:
|
||||
rclcpp::PublisherBase::SharedPtr pub,
|
||||
rclcpp::experimental::SubscriptionIntraProcessBase::SharedPtr sub) const;
|
||||
|
||||
template<
|
||||
typename ROSMessageType,
|
||||
typename Alloc = std::allocator<ROSMessageType>
|
||||
>
|
||||
void do_transient_local_publish(
|
||||
const uint64_t pub_id, const uint64_t sub_id,
|
||||
const bool use_take_shared_method)
|
||||
{
|
||||
using ROSMessageTypeAllocatorTraits = allocator::AllocRebind<ROSMessageType, Alloc>;
|
||||
using ROSMessageTypeAllocator = typename ROSMessageTypeAllocatorTraits::allocator_type;
|
||||
using ROSMessageTypeDeleter = allocator::Deleter<ROSMessageTypeAllocator, ROSMessageType>;
|
||||
|
||||
auto publisher_buffer = publisher_buffers_[pub_id].lock();
|
||||
if (!publisher_buffer) {
|
||||
throw std::runtime_error("publisher buffer has unexpectedly gone out of scope");
|
||||
}
|
||||
auto buffer = std::dynamic_pointer_cast<
|
||||
rclcpp::experimental::buffers::IntraProcessBuffer<
|
||||
ROSMessageType,
|
||||
ROSMessageTypeAllocator,
|
||||
ROSMessageTypeDeleter
|
||||
>
|
||||
>(publisher_buffer);
|
||||
if (!buffer) {
|
||||
throw std::runtime_error(
|
||||
"failed to dynamic cast publisher's IntraProcessBufferBase to "
|
||||
"IntraProcessBuffer<ROSMessageType,ROSMessageTypeAllocator,"
|
||||
"ROSMessageTypeDeleter> which can happen when the publisher and "
|
||||
"subscription use different allocator types, which is not supported");
|
||||
}
|
||||
if (use_take_shared_method) {
|
||||
auto data_vec = buffer->get_all_data_shared();
|
||||
for (auto shared_data : data_vec) {
|
||||
this->template add_shared_msg_to_buffer<
|
||||
ROSMessageType, ROSMessageTypeAllocator, ROSMessageTypeDeleter, ROSMessageType>(
|
||||
shared_data, sub_id);
|
||||
}
|
||||
} else {
|
||||
auto data_vec = buffer->get_all_data_unique();
|
||||
for (auto & owned_data : data_vec) {
|
||||
auto allocator = ROSMessageTypeAllocator();
|
||||
this->template add_owned_msg_to_buffer<
|
||||
ROSMessageType, ROSMessageTypeAllocator, ROSMessageTypeDeleter, ROSMessageType>(
|
||||
std::move(owned_data), sub_id, allocator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<
|
||||
typename MessageT,
|
||||
typename Alloc,
|
||||
@@ -467,7 +585,7 @@ private:
|
||||
auto ptr = MessageAllocTraits::allocate(allocator, 1);
|
||||
MessageAllocTraits::construct(allocator, ptr, *message);
|
||||
|
||||
subscription->provide_intra_process_data(std::move(MessageUniquePtr(ptr, deleter)));
|
||||
subscription->provide_intra_process_data(MessageUniquePtr(ptr, deleter));
|
||||
}
|
||||
|
||||
continue;
|
||||
@@ -510,7 +628,7 @@ private:
|
||||
MessageAllocTraits::construct(allocator, ptr, *message);
|
||||
|
||||
ros_message_subscription->provide_intra_process_message(
|
||||
std::move(MessageUniquePtr(ptr, deleter)));
|
||||
MessageUniquePtr(ptr, deleter));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -520,6 +638,7 @@ private:
|
||||
PublisherToSubscriptionIdsMap pub_to_subs_;
|
||||
SubscriptionMap subscriptions_;
|
||||
PublisherMap publishers_;
|
||||
PublisherBufferMap publisher_buffers_;
|
||||
|
||||
mutable std::shared_timed_mutex mutex_;
|
||||
};
|
||||
|
||||
@@ -67,6 +67,10 @@ public:
|
||||
size_t
|
||||
available_capacity() const = 0;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
is_durability_transient_local() const;
|
||||
|
||||
bool
|
||||
is_ready(rcl_wait_set_t * wait_set) override = 0;
|
||||
|
||||
|
||||
@@ -527,7 +527,7 @@ private:
|
||||
void execute_ready_timers_unsafe();
|
||||
|
||||
// Callback to be called when timer is ready
|
||||
std::function<void(const rclcpp::TimerBase *)> on_ready_callback_ = nullptr;
|
||||
std::function<void(const rclcpp::TimerBase *)> on_ready_callback_;
|
||||
|
||||
// Thread used to run the timers execution task
|
||||
std::thread timers_thread_;
|
||||
|
||||
@@ -77,7 +77,7 @@ public:
|
||||
: rclcpp::PublisherBase(
|
||||
node_base,
|
||||
topic_name,
|
||||
*rclcpp::get_typesupport_handle(topic_type, "rosidl_typesupport_cpp", *ts_lib),
|
||||
*rclcpp::get_message_typesupport_handle(topic_type, "rosidl_typesupport_cpp", *ts_lib),
|
||||
options.template to_rcl_publisher_options<rclcpp::SerializedMessage>(qos),
|
||||
// NOTE(methylDragon): Passing these args separately is necessary for event binding
|
||||
options.event_callbacks,
|
||||
|
||||
@@ -74,18 +74,21 @@ public:
|
||||
const std::string & topic_name,
|
||||
const std::string & topic_type,
|
||||
const rclcpp::QoS & qos,
|
||||
// TODO(nnmm): Add variant for callback with message info. See issue #1604.
|
||||
std::function<void(std::shared_ptr<rclcpp::SerializedMessage>)> callback,
|
||||
AnySubscriptionCallback<rclcpp::SerializedMessage, AllocatorT> callback,
|
||||
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options)
|
||||
: SubscriptionBase(
|
||||
node_base,
|
||||
*rclcpp::get_typesupport_handle(topic_type, "rosidl_typesupport_cpp", *ts_lib),
|
||||
*rclcpp::get_message_typesupport_handle(topic_type, "rosidl_typesupport_cpp", *ts_lib),
|
||||
topic_name,
|
||||
options.to_rcl_subscription_options(qos),
|
||||
options.event_callbacks,
|
||||
options.use_default_callbacks,
|
||||
DeliveredMessageKind::SERIALIZED_MESSAGE),
|
||||
callback_(callback),
|
||||
callback_([callback](
|
||||
std::shared_ptr<const rclcpp::SerializedMessage> serialized_message,
|
||||
const rclcpp::MessageInfo & message_info) mutable {
|
||||
callback.dispatch(serialized_message, message_info);
|
||||
}),
|
||||
ts_lib_(ts_lib)
|
||||
{}
|
||||
|
||||
@@ -151,7 +154,9 @@ public:
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(GenericSubscription)
|
||||
|
||||
std::function<void(std::shared_ptr<rclcpp::SerializedMessage>)> callback_;
|
||||
std::function<void(
|
||||
std::shared_ptr<const rclcpp::SerializedMessage>,
|
||||
const rclcpp::MessageInfo)> callback_;
|
||||
// The type support library should stay loaded, so it is stored in the GenericSubscription
|
||||
std::shared_ptr<rcpputils::SharedLibrary> ts_lib_;
|
||||
};
|
||||
|
||||
@@ -48,7 +48,7 @@ public:
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
explicit GuardCondition(
|
||||
rclcpp::Context::SharedPtr context =
|
||||
const rclcpp::Context::SharedPtr & context =
|
||||
rclcpp::contexts::get_global_default_context(),
|
||||
rcl_guard_condition_options_t guard_condition_options =
|
||||
rcl_guard_condition_get_default_options());
|
||||
@@ -57,11 +57,6 @@ public:
|
||||
virtual
|
||||
~GuardCondition();
|
||||
|
||||
/// Return the context used when creating this guard condition.
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::Context::SharedPtr
|
||||
get_context() const;
|
||||
|
||||
/// Return the underlying rcl guard condition structure.
|
||||
RCLCPP_PUBLIC
|
||||
rcl_guard_condition_t &
|
||||
@@ -128,7 +123,6 @@ public:
|
||||
set_on_trigger_callback(std::function<void(size_t)> callback);
|
||||
|
||||
protected:
|
||||
rclcpp::Context::SharedPtr context_;
|
||||
rcl_guard_condition_t rcl_guard_condition_;
|
||||
std::atomic<bool> in_use_by_wait_set_{false};
|
||||
std::recursive_mutex reentrant_mutex_;
|
||||
|
||||
@@ -126,9 +126,6 @@ private:
|
||||
std::shared_ptr<std::pair<std::string, std::string>> logger_sublogger_pairname_ = nullptr;
|
||||
|
||||
public:
|
||||
RCLCPP_PUBLIC
|
||||
Logger(const Logger &) = default;
|
||||
|
||||
/// Get the name of this logger.
|
||||
/**
|
||||
* \return the full name of the logger including any prefixes, or
|
||||
|
||||
@@ -358,12 +358,14 @@ public:
|
||||
* `%callback_group`.
|
||||
* \return Shared pointer to the created generic subscription.
|
||||
*/
|
||||
template<typename AllocatorT = std::allocator<void>>
|
||||
template<
|
||||
typename CallbackT,
|
||||
typename AllocatorT = std::allocator<void>>
|
||||
std::shared_ptr<rclcpp::GenericSubscription> create_generic_subscription(
|
||||
const std::string & topic_name,
|
||||
const std::string & topic_type,
|
||||
const rclcpp::QoS & qos,
|
||||
std::function<void(std::shared_ptr<rclcpp::SerializedMessage>)> callback,
|
||||
CallbackT && callback,
|
||||
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options = (
|
||||
rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>()
|
||||
)
|
||||
@@ -972,7 +974,16 @@ public:
|
||||
|
||||
/// Return a list of parameters with any of the given prefixes, up to the given depth.
|
||||
/**
|
||||
* \todo: properly document and test this method.
|
||||
* Parameters are separated into a hierarchy using the "." (dot) character.
|
||||
* The "prefixes" argument is a way to select only particular parts of the hierarchy.
|
||||
*
|
||||
* \param[in] prefixes The list of prefixes that should be searched for within the
|
||||
* current parameters. If this vector of prefixes is empty, then list_parameters
|
||||
* will return all parameters.
|
||||
* \param[in] depth An unsigned integer that represents the recursive depth to search.
|
||||
* If this depth = 0, then all parameters that fit the prefixes will be returned.
|
||||
* \returns A ListParametersResult message which contains both an array of unique prefixes
|
||||
* and an array of names that were matched to the prefixes given.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
rcl_interfaces::msg::ListParametersResult
|
||||
@@ -1305,6 +1316,26 @@ public:
|
||||
size_t
|
||||
count_subscribers(const std::string & topic_name) const;
|
||||
|
||||
/// Return the number of clients created for a given service.
|
||||
/**
|
||||
* \param[in] service_name the actual service name used; it will not be automatically remapped.
|
||||
* \return number of clients that have been created for the given service.
|
||||
* \throws std::runtime_error if clients could not be counted
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
size_t
|
||||
count_clients(const std::string & service_name) const;
|
||||
|
||||
/// Return the number of services created for a given service.
|
||||
/**
|
||||
* \param[in] service_name the actual service name used; it will not be automatically remapped.
|
||||
* \return number of services that have been created for the given service.
|
||||
* \throws std::runtime_error if services could not be counted
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
size_t
|
||||
count_services(const std::string & service_name) const;
|
||||
|
||||
/// Return the topic endpoint information about publishers on a given topic.
|
||||
/**
|
||||
* The returned parameter is a list of topic endpoint information, where each item will contain
|
||||
|
||||
@@ -221,13 +221,13 @@ Node::create_generic_publisher(
|
||||
);
|
||||
}
|
||||
|
||||
template<typename AllocatorT>
|
||||
template<typename CallbackT, typename AllocatorT>
|
||||
std::shared_ptr<rclcpp::GenericSubscription>
|
||||
Node::create_generic_subscription(
|
||||
const std::string & topic_name,
|
||||
const std::string & topic_type,
|
||||
const rclcpp::QoS & qos,
|
||||
std::function<void(std::shared_ptr<rclcpp::SerializedMessage>)> callback,
|
||||
CallbackT && callback,
|
||||
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options)
|
||||
{
|
||||
return rclcpp::create_generic_subscription(
|
||||
@@ -235,7 +235,7 @@ Node::create_generic_subscription(
|
||||
extend_name_with_sub_namespace(topic_name, this->get_sub_namespace()),
|
||||
topic_type,
|
||||
qos,
|
||||
std::move(callback),
|
||||
std::forward<CallbackT>(callback),
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
@@ -113,6 +113,14 @@ public:
|
||||
size_t
|
||||
count_subscribers(const std::string & topic_name) const override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
size_t
|
||||
count_clients(const std::string & service_name) const override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
size_t
|
||||
count_services(const std::string & service_name) const override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
const rcl_guard_condition_t *
|
||||
get_graph_guard_condition() const override;
|
||||
|
||||
@@ -305,6 +305,24 @@ public:
|
||||
size_t
|
||||
count_subscribers(const std::string & topic_name) const = 0;
|
||||
|
||||
/// Return the number of clients created for a given service.
|
||||
/*
|
||||
* \param[in] service_name the actual service name used; it will not be automatically remapped.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
size_t
|
||||
count_clients(const std::string & service_name) const = 0;
|
||||
|
||||
/// Return the number of services created for a given service.
|
||||
/*
|
||||
* \param[in] service_name the actual service name used; it will not be automatically remapped.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
size_t
|
||||
count_services(const std::string & service_name) const = 0;
|
||||
|
||||
/// Return the rcl guard condition which is triggered when the ROS graph changes.
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
|
||||
@@ -43,6 +43,7 @@ public:
|
||||
* - arguments = {}
|
||||
* - parameter_overrides = {}
|
||||
* - use_global_arguments = true
|
||||
* - enable_rosout = true
|
||||
* - use_intra_process_comms = false
|
||||
* - enable_topic_statistics = false
|
||||
* - start_parameter_services = true
|
||||
|
||||
@@ -32,6 +32,9 @@
|
||||
#include "rclcpp/allocator/allocator_common.hpp"
|
||||
#include "rclcpp/allocator/allocator_deleter.hpp"
|
||||
#include "rclcpp/detail/resolve_use_intra_process.hpp"
|
||||
#include "rclcpp/detail/resolve_intra_process_buffer_type.hpp"
|
||||
#include "rclcpp/experimental/buffers/intra_process_buffer.hpp"
|
||||
#include "rclcpp/experimental/create_intra_process_buffer.hpp"
|
||||
#include "rclcpp/experimental/intra_process_manager.hpp"
|
||||
#include "rclcpp/get_message_type_support_handle.hpp"
|
||||
#include "rclcpp/is_ros_compatible_type.hpp"
|
||||
@@ -109,6 +112,12 @@ public:
|
||||
[[deprecated("use std::shared_ptr<const PublishedType>")]] =
|
||||
std::shared_ptr<const PublishedType>;
|
||||
|
||||
using BufferSharedPtr = typename rclcpp::experimental::buffers::IntraProcessBuffer<
|
||||
ROSMessageType,
|
||||
ROSMessageTypeAllocator,
|
||||
ROSMessageTypeDeleter
|
||||
>::SharedPtr;
|
||||
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(Publisher<MessageT, AllocatorT>)
|
||||
|
||||
/// Default constructor.
|
||||
@@ -171,11 +180,14 @@ public:
|
||||
throw std::invalid_argument(
|
||||
"intraprocess communication is not allowed with a zero qos history depth value");
|
||||
}
|
||||
if (qos.durability() != rclcpp::DurabilityPolicy::Volatile) {
|
||||
throw std::invalid_argument(
|
||||
"intraprocess communication allowed only with volatile durability");
|
||||
if (qos.durability() == rclcpp::DurabilityPolicy::TransientLocal) {
|
||||
buffer_ = rclcpp::experimental::create_intra_process_buffer<
|
||||
ROSMessageType, ROSMessageTypeAllocator, ROSMessageTypeDeleter>(
|
||||
rclcpp::detail::resolve_intra_process_buffer_type(options_.intra_process_buffer_type),
|
||||
qos,
|
||||
std::make_shared<ROSMessageTypeAllocator>(ros_message_type_allocator_));
|
||||
}
|
||||
uint64_t intra_process_publisher_id = ipm->add_publisher(this->shared_from_this());
|
||||
uint64_t intra_process_publisher_id = ipm->add_publisher(this->shared_from_this(), buffer_);
|
||||
this->setup_intra_process(
|
||||
intra_process_publisher_id,
|
||||
ipm);
|
||||
@@ -242,9 +254,18 @@ public:
|
||||
if (inter_process_publish_needed) {
|
||||
auto shared_msg =
|
||||
this->do_intra_process_ros_message_publish_and_return_shared(std::move(msg));
|
||||
if (buffer_) {
|
||||
buffer_->add_shared(shared_msg);
|
||||
}
|
||||
this->do_inter_process_publish(*shared_msg);
|
||||
} else {
|
||||
this->do_intra_process_ros_message_publish(std::move(msg));
|
||||
if (buffer_) {
|
||||
auto shared_msg =
|
||||
this->do_intra_process_ros_message_publish_and_return_shared(std::move(msg));
|
||||
buffer_->add_shared(shared_msg);
|
||||
} else {
|
||||
this->do_intra_process_ros_message_publish(std::move(msg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,14 +330,22 @@ public:
|
||||
get_subscription_count() > get_intra_process_subscription_count();
|
||||
|
||||
if (inter_process_publish_needed) {
|
||||
ROSMessageType ros_msg;
|
||||
auto ros_msg_ptr = std::make_shared<ROSMessageType>();
|
||||
// TODO(clalancette): This is unnecessarily doing an additional conversion
|
||||
// that may have already been done in do_intra_process_publish_and_return_shared().
|
||||
// We should just reuse that effort.
|
||||
rclcpp::TypeAdapter<MessageT>::convert_to_ros_message(*msg, ros_msg);
|
||||
rclcpp::TypeAdapter<MessageT>::convert_to_ros_message(*msg, *ros_msg_ptr);
|
||||
this->do_intra_process_publish(std::move(msg));
|
||||
this->do_inter_process_publish(ros_msg);
|
||||
this->do_inter_process_publish(*ros_msg_ptr);
|
||||
if (buffer_) {
|
||||
buffer_->add_shared(ros_msg_ptr);
|
||||
}
|
||||
} else {
|
||||
if (buffer_) {
|
||||
auto ros_msg_ptr = std::make_shared<ROSMessageType>();
|
||||
rclcpp::TypeAdapter<MessageT>::convert_to_ros_message(*msg, *ros_msg_ptr);
|
||||
buffer_->add_shared(ros_msg_ptr);
|
||||
}
|
||||
this->do_intra_process_publish(std::move(msg));
|
||||
}
|
||||
}
|
||||
@@ -390,7 +419,7 @@ public:
|
||||
if (this->can_loan_messages()) {
|
||||
// we release the ownership from the rclpp::LoanedMessage instance
|
||||
// and let the middleware clean up the memory.
|
||||
this->do_loaned_message_publish(std::move(loaned_msg.release()));
|
||||
this->do_loaned_message_publish(loaned_msg.release());
|
||||
} else {
|
||||
// we don't release the ownership, let the middleware copy the ros message
|
||||
// and thus the destructor of rclcpp::LoanedMessage cleans up the memory.
|
||||
@@ -581,6 +610,8 @@ protected:
|
||||
PublishedTypeDeleter published_type_deleter_;
|
||||
ROSMessageTypeAllocator ros_message_type_allocator_;
|
||||
ROSMessageTypeDeleter ros_message_type_deleter_;
|
||||
|
||||
BufferSharedPtr buffer_{nullptr};
|
||||
};
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
@@ -139,6 +139,12 @@ public:
|
||||
size_t
|
||||
get_intra_process_subscription_count() const;
|
||||
|
||||
/// Get if durability is transient local
|
||||
/** \return If durability is transient local*/
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
is_durability_transient_local() const;
|
||||
|
||||
/// Manually assert that this Publisher is alive (for RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC).
|
||||
/**
|
||||
* If the rmw Liveliness policy is set to RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC, the creator
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include "rclcpp/allocator/allocator_common.hpp"
|
||||
#include "rclcpp/detail/rmw_implementation_specific_publisher_payload.hpp"
|
||||
#include "rclcpp/intra_process_buffer_type.hpp"
|
||||
#include "rclcpp/intra_process_setting.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
#include "rclcpp/event_handler.hpp"
|
||||
@@ -40,6 +41,9 @@ struct PublisherOptionsBase
|
||||
/// Setting to explicitly set intraprocess communications.
|
||||
IntraProcessSetting use_intra_process_comm = IntraProcessSetting::NodeDefault;
|
||||
|
||||
/// Setting the data-type stored in the intraprocess buffer
|
||||
IntraProcessBufferType intra_process_buffer_type = IntraProcessBufferType::SharedPtr;
|
||||
|
||||
/// Callbacks for various events related to publishers.
|
||||
PublisherEventCallbacks event_callbacks;
|
||||
|
||||
|
||||
@@ -163,7 +163,7 @@ public:
|
||||
reset();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
Duration
|
||||
std::chrono::nanoseconds
|
||||
period() const;
|
||||
|
||||
private:
|
||||
@@ -184,16 +184,6 @@ public:
|
||||
explicit WallRate(const Duration & period);
|
||||
};
|
||||
|
||||
class ROSRate : public Rate
|
||||
{
|
||||
public:
|
||||
RCLCPP_PUBLIC
|
||||
explicit ROSRate(const double rate);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
explicit ROSRate(const Duration & period);
|
||||
};
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__RATE_HPP_
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
* - rclcpp::ParameterValue
|
||||
* - rclcpp::AsyncParametersClient
|
||||
* - rclcpp::SyncParametersClient
|
||||
* - rclcpp::copy_all_parameter_values()
|
||||
* - rclcpp/parameter.hpp
|
||||
* - rclcpp/parameter_value.hpp
|
||||
* - rclcpp/parameter_client.hpp
|
||||
@@ -95,6 +96,9 @@
|
||||
* - Get the number of publishers or subscribers on a topic:
|
||||
* - rclcpp::Node::count_publishers()
|
||||
* - rclcpp::Node::count_subscribers()
|
||||
* - Get the number of clients or servers on a service:
|
||||
* - rclcpp::Node::count_clients()
|
||||
* - rclcpp::Node::count_services()
|
||||
*
|
||||
* And components related to logging:
|
||||
*
|
||||
@@ -164,6 +168,7 @@
|
||||
#include <csignal>
|
||||
#include <memory>
|
||||
|
||||
#include "rclcpp/copy_all_parameter_values.hpp"
|
||||
#include "rclcpp/executors.hpp"
|
||||
#include "rclcpp/guard_condition.hpp"
|
||||
#include "rclcpp/logging.hpp"
|
||||
|
||||
@@ -15,10 +15,17 @@
|
||||
#ifndef RCLCPP__STRATEGIES__MESSAGE_POOL_MEMORY_STRATEGY_HPP_
|
||||
#define RCLCPP__STRATEGIES__MESSAGE_POOL_MEMORY_STRATEGY_HPP_
|
||||
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
|
||||
#include "rosidl_runtime_cpp/traits.hpp"
|
||||
|
||||
#include "rclcpp/logger.hpp"
|
||||
#include "rclcpp/logging.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/message_memory_strategy.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
@@ -50,13 +57,24 @@ class MessagePoolMemoryStrategy
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(MessagePoolMemoryStrategy)
|
||||
|
||||
/// Default constructor
|
||||
MessagePoolMemoryStrategy()
|
||||
: next_array_index_(0)
|
||||
{
|
||||
pool_mutex_ = std::make_shared<std::mutex>();
|
||||
|
||||
pool_ = std::shared_ptr<std::array<MessageT *, Size>>(
|
||||
new std::array<MessageT *, Size>,
|
||||
[](std::array<MessageT *, Size> * arr) {
|
||||
for (size_t i = 0; i < Size; ++i) {
|
||||
free((*arr)[i]);
|
||||
}
|
||||
delete arr;
|
||||
});
|
||||
|
||||
free_list_ = std::make_shared<CircularArray<Size>>();
|
||||
|
||||
for (size_t i = 0; i < Size; ++i) {
|
||||
pool_[i].msg_ptr_ = std::make_shared<MessageT>();
|
||||
pool_[i].used = false;
|
||||
(*pool_)[i] = static_cast<MessageT *>(malloc(sizeof(MessageT)));
|
||||
free_list_->push_back(i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,43 +86,85 @@ public:
|
||||
*/
|
||||
std::shared_ptr<MessageT> borrow_message()
|
||||
{
|
||||
size_t current_index = next_array_index_;
|
||||
next_array_index_ = (next_array_index_ + 1) % Size;
|
||||
if (pool_[current_index].used) {
|
||||
throw std::runtime_error("Tried to access message that was still in use! Abort.");
|
||||
std::lock_guard<std::mutex> lock(*pool_mutex_);
|
||||
if (free_list_->size() == 0) {
|
||||
throw std::runtime_error("No more free slots in the pool");
|
||||
}
|
||||
pool_[current_index].msg_ptr_->~MessageT();
|
||||
new (pool_[current_index].msg_ptr_.get())MessageT;
|
||||
|
||||
pool_[current_index].used = true;
|
||||
return pool_[current_index].msg_ptr_;
|
||||
size_t current_index = free_list_->pop_front();
|
||||
|
||||
return std::shared_ptr<MessageT>(
|
||||
new((*pool_)[current_index]) MessageT(),
|
||||
[pool = this->pool_, pool_mutex = this->pool_mutex_,
|
||||
free_list = this->free_list_](MessageT * p) {
|
||||
std::lock_guard<std::mutex> lock(*pool_mutex);
|
||||
for (size_t i = 0; i < Size; ++i) {
|
||||
if ((*pool)[i] == p) {
|
||||
p->~MessageT();
|
||||
free_list->push_back(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Return a message to the message pool.
|
||||
/**
|
||||
* Manage metadata in the message pool ring buffer to release the message.
|
||||
* This does nothing since the message isn't returned to the pool until the user has dropped
|
||||
* all references.
|
||||
* \param[in] msg Shared pointer to the message to return.
|
||||
*/
|
||||
void return_message(std::shared_ptr<MessageT> & msg)
|
||||
{
|
||||
for (size_t i = 0; i < Size; ++i) {
|
||||
if (pool_[i].msg_ptr_ == msg) {
|
||||
pool_[i].used = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw std::runtime_error("Unrecognized message ptr in return_message.");
|
||||
(void)msg;
|
||||
}
|
||||
|
||||
protected:
|
||||
struct PoolMember
|
||||
template<size_t N>
|
||||
class CircularArray
|
||||
{
|
||||
std::shared_ptr<MessageT> msg_ptr_;
|
||||
bool used;
|
||||
public:
|
||||
void push_back(const size_t v)
|
||||
{
|
||||
if (size_ + 1 > N) {
|
||||
throw std::runtime_error("Tried to push too many items into the array");
|
||||
}
|
||||
array_[(front_ + size_) % N] = v;
|
||||
++size_;
|
||||
}
|
||||
|
||||
size_t pop_front()
|
||||
{
|
||||
if (size_ < 1) {
|
||||
throw std::runtime_error("Tried to pop item from empty array");
|
||||
}
|
||||
|
||||
size_t val = array_[front_];
|
||||
|
||||
front_ = (front_ + 1) % N;
|
||||
--size_;
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t front_ = 0;
|
||||
size_t size_ = 0;
|
||||
std::array<size_t, N> array_;
|
||||
};
|
||||
|
||||
std::array<PoolMember, Size> pool_;
|
||||
size_t next_array_index_;
|
||||
// It's very important that these are shared_ptrs, since users of this class might hold a
|
||||
// reference to a pool item longer than the lifetime of the class. In that scenario, the
|
||||
// shared_ptr ensures that the lifetime of these variables outlives this class, and hence ensures
|
||||
// the custom destructor for each pool item can successfully run.
|
||||
std::shared_ptr<std::mutex> pool_mutex_;
|
||||
std::shared_ptr<std::array<MessageT *, Size>> pool_;
|
||||
std::shared_ptr<CircularArray<Size>> free_list_;
|
||||
};
|
||||
|
||||
} // namespace message_pool_memory_strategy
|
||||
|
||||
@@ -104,7 +104,7 @@ public:
|
||||
|
||||
private:
|
||||
using SubscriptionTopicStatisticsSharedPtr =
|
||||
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics<ROSMessageType>>;
|
||||
std::shared_ptr<rclcpp::topic_statistics::SubscriptionTopicStatistics>;
|
||||
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(Subscription)
|
||||
@@ -163,10 +163,6 @@ public:
|
||||
throw std::invalid_argument(
|
||||
"intraprocess communication is not allowed with 0 depth qos policy");
|
||||
}
|
||||
if (qos_profile.durability() != rclcpp::DurabilityPolicy::Volatile) {
|
||||
throw std::invalid_argument(
|
||||
"intraprocess communication allowed only with volatile durability");
|
||||
}
|
||||
|
||||
using SubscriptionIntraProcessT = rclcpp::experimental::SubscriptionIntraProcess<
|
||||
MessageT,
|
||||
@@ -193,7 +189,8 @@ public:
|
||||
// Add it to the intra process manager.
|
||||
using rclcpp::experimental::IntraProcessManager;
|
||||
auto ipm = context->get_sub_context<IntraProcessManager>();
|
||||
uint64_t intra_process_subscription_id = ipm->add_subscription(subscription_intra_process_);
|
||||
uint64_t intra_process_subscription_id = ipm->template add_subscription<
|
||||
ROSMessageType, ROSMessageTypeAllocator>(subscription_intra_process_);
|
||||
this->setup_intra_process(intra_process_subscription_id, ipm);
|
||||
}
|
||||
|
||||
@@ -316,7 +313,7 @@ public:
|
||||
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);
|
||||
subscription_topic_statistics_->handle_message(message_info.get_rmw_message_info(), time);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,8 +322,20 @@ public:
|
||||
const std::shared_ptr<rclcpp::SerializedMessage> & serialized_message,
|
||||
const rclcpp::MessageInfo & message_info) override
|
||||
{
|
||||
// TODO(wjwwood): enable topic statistics for serialized messages
|
||||
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(serialized_message, 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(message_info.get_rmw_message_info(), time);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -357,7 +366,7 @@ public:
|
||||
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);
|
||||
subscription_topic_statistics_->handle_message(message_info.get_rmw_message_info(), time);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -75,15 +75,14 @@ template<
|
||||
typename CallbackT,
|
||||
typename AllocatorT,
|
||||
typename SubscriptionT = rclcpp::Subscription<MessageT, AllocatorT>,
|
||||
typename MessageMemoryStrategyT = typename SubscriptionT::MessageMemoryStrategyType,
|
||||
typename ROSMessageType = typename SubscriptionT::ROSMessageType
|
||||
typename MessageMemoryStrategyT = typename SubscriptionT::MessageMemoryStrategyType
|
||||
>
|
||||
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>
|
||||
subscription_topic_stats = nullptr
|
||||
)
|
||||
{
|
||||
|
||||
@@ -77,6 +77,10 @@ struct SubscriptionOptionsBase
|
||||
// Topic statistics publication period in ms. Defaults to one second.
|
||||
// Only values greater than zero are allowed.
|
||||
std::chrono::milliseconds publish_period{std::chrono::seconds(1)};
|
||||
|
||||
// An optional QoS which can provide topic_statistics with a stable QoS separate from
|
||||
// the subscription's current QoS settings which could be unstable.
|
||||
rclcpp::QoS qos = SystemDefaultsQoS();
|
||||
};
|
||||
|
||||
TopicStatisticsOptions topic_stats_options;
|
||||
|
||||
@@ -189,7 +189,7 @@ public:
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
static Time
|
||||
max();
|
||||
max(rcl_clock_type_t clock_type = RCL_SYSTEM_TIME); // NOLINT
|
||||
|
||||
/// Get the seconds since epoch
|
||||
/**
|
||||
|
||||
@@ -48,21 +48,12 @@ using libstatistics_collector::moving_average_statistics::StatisticData;
|
||||
/**
|
||||
* Class used to collect, measure, and publish topic statistics data. Current statistics
|
||||
* supported for subscribers are received message age and received message period.
|
||||
*
|
||||
* \tparam CallbackMessageT the subscribed message type
|
||||
*/
|
||||
template<typename CallbackMessageT>
|
||||
*/
|
||||
class SubscriptionTopicStatistics
|
||||
{
|
||||
using TopicStatsCollector =
|
||||
libstatistics_collector::topic_statistics_collector::TopicStatisticsCollector<
|
||||
CallbackMessageT>;
|
||||
using ReceivedMessageAge =
|
||||
libstatistics_collector::topic_statistics_collector::ReceivedMessageAgeCollector<
|
||||
CallbackMessageT>;
|
||||
using ReceivedMessagePeriod =
|
||||
libstatistics_collector::topic_statistics_collector::ReceivedMessagePeriodCollector<
|
||||
CallbackMessageT>;
|
||||
using TopicStatsCollector = libstatistics_collector::TopicStatisticsCollector;
|
||||
using ReceivedMessageAge = libstatistics_collector::ReceivedMessageAgeCollector;
|
||||
using ReceivedMessagePeriod = libstatistics_collector::ReceivedMessagePeriodCollector;
|
||||
|
||||
public:
|
||||
/// Construct a SubscriptionTopicStatistics object.
|
||||
@@ -101,16 +92,16 @@ public:
|
||||
/**
|
||||
* This method acquires a lock to prevent race conditions to collectors list.
|
||||
*
|
||||
* \param received_message the message received by the subscription
|
||||
* \param message_info the message info corresponding to the received message
|
||||
* \param now_nanoseconds current time in nanoseconds
|
||||
*/
|
||||
virtual void handle_message(
|
||||
const CallbackMessageT & received_message,
|
||||
const rmw_message_info_t & message_info,
|
||||
const rclcpp::Time now_nanoseconds) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
for (const auto & collector : subscriber_statistics_collectors_) {
|
||||
collector->OnMessageReceived(received_message, now_nanoseconds.nanoseconds());
|
||||
collector->OnMessageReceived(message_info, now_nanoseconds.nanoseconds());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include "rcpputils/shared_library.hpp"
|
||||
#include "rosidl_runtime_cpp/message_type_support_decl.hpp"
|
||||
#include "rosidl_runtime_cpp/service_type_support_decl.hpp"
|
||||
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
@@ -40,11 +41,15 @@ get_typesupport_library(const std::string & type, const std::string & typesuppor
|
||||
/// Extract the type support handle from the library.
|
||||
/**
|
||||
* The library needs to match the topic type. The shared library must stay loaded for the lifetime of the result.
|
||||
*
|
||||
* \deprecated Use get_message_typesupport_handle() instead
|
||||
*
|
||||
* \param[in] type The topic type, e.g. "std_msgs/msg/String"
|
||||
* \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
|
||||
* \param[in] library The shared type support library
|
||||
* \return A type support handle
|
||||
*/
|
||||
[[deprecated("Use `get_message_typesupport_handle` instead")]]
|
||||
RCLCPP_PUBLIC
|
||||
const rosidl_message_type_support_t *
|
||||
get_typesupport_handle(
|
||||
@@ -52,6 +57,40 @@ get_typesupport_handle(
|
||||
const std::string & typesupport_identifier,
|
||||
rcpputils::SharedLibrary & library);
|
||||
|
||||
/// Extract the message type support handle from the library.
|
||||
/**
|
||||
* The library needs to match the topic type. The shared library must stay loaded for the lifetime of the result.
|
||||
*
|
||||
* \param[in] type The topic type, e.g. "std_msgs/msg/String"
|
||||
* \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
|
||||
* \param[in] library The shared type support library
|
||||
* \throws std::runtime_error if the symbol of type not found in the library.
|
||||
* \return A message type support handle
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
const rosidl_message_type_support_t *
|
||||
get_message_typesupport_handle(
|
||||
const std::string & type,
|
||||
const std::string & typesupport_identifier,
|
||||
rcpputils::SharedLibrary & library);
|
||||
|
||||
/// Extract the service type support handle from the library.
|
||||
/**
|
||||
* The library needs to match the topic type. The shared library must stay loaded for the lifetime of the result.
|
||||
*
|
||||
* \param[in] type The service type, e.g. "std_srvs/srv/Empty"
|
||||
* \param[in] typesupport_identifier Type support identifier, typically "rosidl_typesupport_cpp"
|
||||
* \param[in] library The shared type support library
|
||||
* \throws std::runtime_error if the symbol of type not found in the library.
|
||||
* \return A service type support handle
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
const rosidl_service_type_support_t *
|
||||
get_service_typesupport_handle(
|
||||
const std::string & type,
|
||||
const std::string & typesupport_identifier,
|
||||
rcpputils::SharedLibrary & library);
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__TYPESUPPORT_HELPERS_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>22.2.0</version>
|
||||
<version>26.0.0</version>
|
||||
<description>The ROS client library in C++.</description>
|
||||
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
@@ -22,6 +22,7 @@
|
||||
<build_depend>builtin_interfaces</build_depend>
|
||||
<build_depend>rcl_interfaces</build_depend>
|
||||
<build_depend>rosgraph_msgs</build_depend>
|
||||
<build_depend>rosidl_runtime_c</build_depend>
|
||||
<build_depend>rosidl_runtime_cpp</build_depend>
|
||||
<build_depend>rosidl_typesupport_c</build_depend>
|
||||
<build_depend>rosidl_typesupport_cpp</build_depend>
|
||||
@@ -29,6 +30,7 @@
|
||||
<build_export_depend>builtin_interfaces</build_export_depend>
|
||||
<build_export_depend>rcl_interfaces</build_export_depend>
|
||||
<build_export_depend>rosgraph_msgs</build_export_depend>
|
||||
<build_export_depend>rosidl_runtime_c</build_export_depend>
|
||||
<build_export_depend>rosidl_runtime_cpp</build_export_depend>
|
||||
<build_export_depend>rosidl_typesupport_c</build_export_depend>
|
||||
<build_export_depend>rosidl_typesupport_cpp</build_export_depend>
|
||||
|
||||
@@ -31,12 +31,12 @@ using rclcpp::CallbackGroupType;
|
||||
|
||||
CallbackGroup::CallbackGroup(
|
||||
CallbackGroupType group_type,
|
||||
std::function<rclcpp::Context::SharedPtr(void)> get_context,
|
||||
rclcpp::Context::WeakPtr context,
|
||||
bool automatically_add_to_executor_with_node)
|
||||
: type_(group_type), associated_with_executor_(false),
|
||||
can_be_taken_from_(true),
|
||||
automatically_add_to_executor_with_node_(automatically_add_to_executor_with_node),
|
||||
get_context_(get_context)
|
||||
context_(context)
|
||||
{}
|
||||
|
||||
CallbackGroup::~CallbackGroup()
|
||||
@@ -123,40 +123,12 @@ CallbackGroup::automatically_add_to_executor_with_node() const
|
||||
return automatically_add_to_executor_with_node_;
|
||||
}
|
||||
|
||||
// \TODO(mjcarroll) Deprecated, remove on tock
|
||||
rclcpp::GuardCondition::SharedPtr
|
||||
CallbackGroup::get_notify_guard_condition(const rclcpp::Context::SharedPtr context_ptr)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(notify_guard_condition_mutex_);
|
||||
if (notify_guard_condition_ && context_ptr != notify_guard_condition_->get_context()) {
|
||||
if (associated_with_executor_) {
|
||||
trigger_notify_guard_condition();
|
||||
}
|
||||
notify_guard_condition_ = nullptr;
|
||||
}
|
||||
|
||||
if (!notify_guard_condition_) {
|
||||
notify_guard_condition_ = std::make_shared<rclcpp::GuardCondition>(context_ptr);
|
||||
}
|
||||
|
||||
return notify_guard_condition_;
|
||||
}
|
||||
|
||||
rclcpp::GuardCondition::SharedPtr
|
||||
CallbackGroup::get_notify_guard_condition()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(notify_guard_condition_mutex_);
|
||||
if (!this->get_context_) {
|
||||
throw std::runtime_error("Callback group was created without context and not passed context");
|
||||
}
|
||||
auto context_ptr = this->get_context_();
|
||||
rclcpp::Context::SharedPtr context_ptr = context_.lock();
|
||||
if (context_ptr && context_ptr->is_valid()) {
|
||||
if (notify_guard_condition_ && context_ptr != notify_guard_condition_->get_context()) {
|
||||
if (associated_with_executor_) {
|
||||
trigger_notify_guard_condition();
|
||||
}
|
||||
notify_guard_condition_ = nullptr;
|
||||
}
|
||||
if (!notify_guard_condition_) {
|
||||
notify_guard_condition_ = std::make_shared<rclcpp::GuardCondition>(context_ptr);
|
||||
}
|
||||
|
||||
@@ -462,7 +462,7 @@ template<Context::ShutdownType shutdown_type>
|
||||
std::vector<rclcpp::Context::ShutdownCallback>
|
||||
Context::get_shutdown_callback() const
|
||||
{
|
||||
const auto get_callback_vector = [this](auto & mutex, auto & callback_set) {
|
||||
const auto get_callback_vector = [](auto & mutex, auto & callback_set) {
|
||||
const std::lock_guard<std::mutex> lock(mutex);
|
||||
std::vector<rclcpp::Context::ShutdownCallback> callbacks;
|
||||
for (auto & callback : callback_set) {
|
||||
@@ -496,7 +496,7 @@ Context::sleep_for(const std::chrono::nanoseconds & nanoseconds)
|
||||
std::unique_lock<std::mutex> lock(interrupt_mutex_);
|
||||
auto start = std::chrono::steady_clock::now();
|
||||
// this will release the lock while waiting
|
||||
interrupt_condition_variable_.wait_for(lock, nanoseconds);
|
||||
interrupt_condition_variable_.wait_for(lock, time_left);
|
||||
time_left -= std::chrono::steady_clock::now() - start;
|
||||
}
|
||||
} while (time_left > std::chrono::nanoseconds::zero() && this->is_valid());
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
// Copyright 2023 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 <rclcpp/detail/resolve_intra_process_buffer_type.hpp>
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
rclcpp::IntraProcessBufferType
|
||||
resolve_intra_process_buffer_type(
|
||||
const rclcpp::IntraProcessBufferType buffer_type)
|
||||
{
|
||||
if (buffer_type == IntraProcessBufferType::CallbackDefault) {
|
||||
throw std::invalid_argument(
|
||||
"IntraProcessBufferType::CallbackDefault is not allowed "
|
||||
"when there is no callback function");
|
||||
}
|
||||
|
||||
return buffer_type;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace rclcpp
|
||||
@@ -39,13 +39,6 @@ UnsupportedEventTypeException::UnsupportedEventTypeException(
|
||||
|
||||
EventHandlerBase::~EventHandlerBase()
|
||||
{
|
||||
// Since the rmw event listener holds a reference to
|
||||
// this callback, we need to clear it on destruction of this class.
|
||||
// This clearing is not needed for other rclcpp entities like pub/subs, since
|
||||
// they do own the underlying rmw entities, which are destroyed
|
||||
// on their rclcpp destructors, thus no risk of dangling pointers.
|
||||
clear_on_ready_callback();
|
||||
|
||||
if (rcl_event_fini(&event_handle_) != RCL_RET_OK) {
|
||||
RCUTILS_LOG_ERROR_NAMED(
|
||||
"rclcpp",
|
||||
|
||||
@@ -669,6 +669,11 @@ Executor::execute_subscription(rclcpp::SubscriptionBase::SharedPtr subscription)
|
||||
subscription->get_topic_name(),
|
||||
[&]() {return subscription->take_type_erased(message.get(), message_info);},
|
||||
[&]() {subscription->handle_message(message, message_info);});
|
||||
// TODO(clalancette): In the case that the user is using the MessageMemoryPool,
|
||||
// and they take a shared_ptr reference to the message in the callback, this can
|
||||
// inadvertently return the message to the pool when the user is still using it.
|
||||
// This is a bug that needs to be fixed in the pool, and we should probably have
|
||||
// a custom deleter for the message that actually does the return_message().
|
||||
subscription->return_message(message);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -28,9 +28,9 @@ using rclcpp::experimental::TimersManager;
|
||||
TimersManager::TimersManager(
|
||||
std::shared_ptr<rclcpp::Context> context,
|
||||
std::function<void(const rclcpp::TimerBase *)> on_ready_callback)
|
||||
: on_ready_callback_(on_ready_callback),
|
||||
context_(context)
|
||||
{
|
||||
context_ = context;
|
||||
on_ready_callback_ = on_ready_callback;
|
||||
}
|
||||
|
||||
TimersManager::~TimersManager()
|
||||
|
||||
@@ -49,9 +49,9 @@ GenericSubscription::handle_message(
|
||||
void
|
||||
GenericSubscription::handle_serialized_message(
|
||||
const std::shared_ptr<rclcpp::SerializedMessage> & message,
|
||||
const rclcpp::MessageInfo &)
|
||||
const rclcpp::MessageInfo & message_info)
|
||||
{
|
||||
callback_(message);
|
||||
callback_(message, message_info);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -23,16 +23,17 @@ namespace rclcpp
|
||||
{
|
||||
|
||||
GuardCondition::GuardCondition(
|
||||
rclcpp::Context::SharedPtr context,
|
||||
const rclcpp::Context::SharedPtr & context,
|
||||
rcl_guard_condition_options_t guard_condition_options)
|
||||
: context_(context), rcl_guard_condition_{rcl_get_zero_initialized_guard_condition()}
|
||||
: rcl_guard_condition_{rcl_get_zero_initialized_guard_condition()}
|
||||
{
|
||||
if (!context_) {
|
||||
if (!context) {
|
||||
throw std::invalid_argument("context argument unexpectedly nullptr");
|
||||
}
|
||||
|
||||
rcl_ret_t ret = rcl_guard_condition_init(
|
||||
&this->rcl_guard_condition_,
|
||||
context_->get_rcl_context().get(),
|
||||
context->get_rcl_context().get(),
|
||||
guard_condition_options);
|
||||
if (RCL_RET_OK != ret) {
|
||||
rclcpp::exceptions::throw_from_rcl_error(ret, "failed to create guard condition");
|
||||
@@ -53,12 +54,6 @@ GuardCondition::~GuardCondition()
|
||||
}
|
||||
}
|
||||
|
||||
rclcpp::Context::SharedPtr
|
||||
GuardCondition::get_context() const
|
||||
{
|
||||
return context_;
|
||||
}
|
||||
|
||||
rcl_guard_condition_t &
|
||||
GuardCondition::get_rcl_guard_condition()
|
||||
{
|
||||
|
||||
@@ -32,13 +32,24 @@ IntraProcessManager::~IntraProcessManager()
|
||||
{}
|
||||
|
||||
uint64_t
|
||||
IntraProcessManager::add_publisher(rclcpp::PublisherBase::SharedPtr publisher)
|
||||
IntraProcessManager::add_publisher(
|
||||
rclcpp::PublisherBase::SharedPtr publisher,
|
||||
rclcpp::experimental::buffers::IntraProcessBufferBase::SharedPtr buffer)
|
||||
{
|
||||
std::unique_lock<std::shared_timed_mutex> lock(mutex_);
|
||||
|
||||
uint64_t pub_id = IntraProcessManager::get_next_unique_id();
|
||||
|
||||
publishers_[pub_id] = publisher;
|
||||
if (publisher->is_durability_transient_local()) {
|
||||
if (buffer) {
|
||||
publisher_buffers_[pub_id] = buffer;
|
||||
} else {
|
||||
throw std::runtime_error(
|
||||
"transient_local publisher needs to pass"
|
||||
"a valid publisher buffer ptr when calling add_publisher()");
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize the subscriptions storage for this publisher.
|
||||
pub_to_subs_[pub_id] = SplittedSubscriptions();
|
||||
@@ -58,30 +69,6 @@ IntraProcessManager::add_publisher(rclcpp::PublisherBase::SharedPtr publisher)
|
||||
return pub_id;
|
||||
}
|
||||
|
||||
uint64_t
|
||||
IntraProcessManager::add_subscription(SubscriptionIntraProcessBase::SharedPtr subscription)
|
||||
{
|
||||
std::unique_lock<std::shared_timed_mutex> lock(mutex_);
|
||||
|
||||
uint64_t sub_id = IntraProcessManager::get_next_unique_id();
|
||||
|
||||
subscriptions_[sub_id] = subscription;
|
||||
|
||||
// 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());
|
||||
}
|
||||
}
|
||||
|
||||
return sub_id;
|
||||
}
|
||||
|
||||
void
|
||||
IntraProcessManager::remove_subscription(uint64_t intra_process_subscription_id)
|
||||
{
|
||||
@@ -112,6 +99,7 @@ IntraProcessManager::remove_publisher(uint64_t intra_process_publisher_id)
|
||||
std::unique_lock<std::shared_timed_mutex> lock(mutex_);
|
||||
|
||||
publishers_.erase(intra_process_publisher_id);
|
||||
publisher_buffers_.erase(intra_process_publisher_id);
|
||||
pub_to_subs_.erase(intra_process_publisher_id);
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <utility>
|
||||
|
||||
#include "rcl_logging_interface/rcl_logging_interface.h"
|
||||
#include "rcl/error_handling.h"
|
||||
#include "rcl/logging_rosout.h"
|
||||
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
@@ -80,10 +81,12 @@ Logger::get_child(const std::string & suffix)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(*logging_mutex);
|
||||
rcl_ret = rcl_logging_rosout_add_sublogger((*name_).c_str(), suffix.c_str());
|
||||
if (RCL_RET_OK != rcl_ret) {
|
||||
if (RCL_RET_NOT_FOUND == rcl_ret) {
|
||||
rcl_reset_error();
|
||||
} else if (RCL_RET_OK != rcl_ret) {
|
||||
exceptions::throw_from_rcl_error(
|
||||
rcl_ret, "failed to call rcl_logging_rosout_add_sublogger",
|
||||
rcutils_get_error_state(), rcutils_reset_error);
|
||||
rcl_get_error_state(), rcl_reset_error);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,9 +101,7 @@ Logger::get_child(const std::string & suffix)
|
||||
logger_sublogger_pairname_ptr->second.c_str());
|
||||
delete logger_sublogger_pairname_ptr;
|
||||
if (RCL_RET_OK != rcl_ret) {
|
||||
exceptions::throw_from_rcl_error(
|
||||
rcl_ret, "failed to call rcl_logging_rosout_remove_sublogger",
|
||||
rcutils_get_error_state(), rcutils_reset_error);
|
||||
rcl_reset_error();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -522,6 +522,18 @@ Node::count_subscribers(const std::string & topic_name) const
|
||||
return node_graph_->count_subscribers(topic_name);
|
||||
}
|
||||
|
||||
size_t
|
||||
Node::count_clients(const std::string & service_name) const
|
||||
{
|
||||
return node_graph_->count_clients(service_name);
|
||||
}
|
||||
|
||||
size_t
|
||||
Node::count_services(const std::string & service_name) const
|
||||
{
|
||||
return node_graph_->count_services(service_name);
|
||||
}
|
||||
|
||||
std::vector<rclcpp::TopicEndpointInfo>
|
||||
Node::get_publishers_info_by_topic(const std::string & topic_name, bool no_mangle) const
|
||||
{
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
|
||||
#include "rcl/arguments.h"
|
||||
#include "rcl/node_type_cache.h"
|
||||
#include "rcl/logging.h"
|
||||
#include "rcl/logging_rosout.h"
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
#include "rcutils/logging_macros.h"
|
||||
#include "rmw/validate_namespace.h"
|
||||
@@ -55,17 +57,12 @@ NodeBase::NodeBase(
|
||||
std::shared_ptr<std::recursive_mutex> logging_mutex = get_global_logging_mutex();
|
||||
|
||||
rcl_ret_t ret;
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(*logging_mutex);
|
||||
// TODO(ivanpauno): /rosout Qos should be reconfigurable.
|
||||
// TODO(ivanpauno): Instead of mutually excluding rcl_node_init with the global logger mutex,
|
||||
// rcl_logging_rosout_init_publisher_for_node could be decoupled from there and be called
|
||||
// here directly.
|
||||
ret = rcl_node_init(
|
||||
rcl_node.get(),
|
||||
node_name.c_str(), namespace_.c_str(),
|
||||
context_->get_rcl_context().get(), &rcl_node_options);
|
||||
}
|
||||
|
||||
// TODO(ivanpauno): /rosout Qos should be reconfigurable.
|
||||
ret = rcl_node_init(
|
||||
rcl_node.get(),
|
||||
node_name.c_str(), namespace_.c_str(),
|
||||
context_->get_rcl_context().get(), &rcl_node_options);
|
||||
if (ret != RCL_RET_OK) {
|
||||
if (ret == RCL_RET_NODE_INVALID_NAME) {
|
||||
rcl_reset_error(); // discard rcl_node_init error
|
||||
@@ -115,13 +112,29 @@ NodeBase::NodeBase(
|
||||
throw_from_rcl_error(ret, "failed to initialize rcl node");
|
||||
}
|
||||
|
||||
// The initialization for the rosout publisher
|
||||
if (rcl_logging_rosout_enabled() && rcl_node_options.enable_rosout) {
|
||||
std::lock_guard<std::recursive_mutex> guard(*logging_mutex);
|
||||
ret = rcl_logging_rosout_init_publisher_for_node(rcl_node.get());
|
||||
if (ret != RCL_RET_OK) {
|
||||
throw_from_rcl_error(ret, "failed to initialize rosout publisher");
|
||||
}
|
||||
}
|
||||
|
||||
node_handle_.reset(
|
||||
rcl_node.release(),
|
||||
[logging_mutex](rcl_node_t * node) -> void {
|
||||
std::lock_guard<std::recursive_mutex> guard(*logging_mutex);
|
||||
// TODO(ivanpauno): Instead of mutually excluding rcl_node_fini with the global logger mutex,
|
||||
// rcl_logging_rosout_fini_publisher_for_node could be decoupled from there and be called
|
||||
// here directly.
|
||||
[logging_mutex, rcl_node_options](rcl_node_t * node) -> void {
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> guard(*logging_mutex);
|
||||
if (rcl_logging_rosout_enabled() && rcl_node_options.enable_rosout) {
|
||||
rcl_ret_t ret = rcl_logging_rosout_fini_publisher_for_node(node);
|
||||
if (ret != RCL_RET_OK) {
|
||||
RCUTILS_LOG_ERROR_NAMED(
|
||||
"rclcpp",
|
||||
"Error in destruction of rosout publisher: %s", rcl_get_error_string().str);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (rcl_node_fini(node) != RCL_RET_OK) {
|
||||
RCUTILS_LOG_ERROR_NAMED(
|
||||
"rclcpp",
|
||||
@@ -205,14 +218,9 @@ NodeBase::create_callback_group(
|
||||
rclcpp::CallbackGroupType group_type,
|
||||
bool automatically_add_to_executor_with_node)
|
||||
{
|
||||
auto weak_context = this->get_context()->weak_from_this();
|
||||
auto get_node_context = [weak_context]() -> rclcpp::Context::SharedPtr {
|
||||
return weak_context.lock();
|
||||
};
|
||||
|
||||
auto group = std::make_shared<rclcpp::CallbackGroup>(
|
||||
group_type,
|
||||
get_node_context,
|
||||
context_->weak_from_this(),
|
||||
automatically_add_to_executor_with_node);
|
||||
std::lock_guard<std::mutex> lock(callback_groups_mutex_);
|
||||
callback_groups_.push_back(group);
|
||||
|
||||
@@ -498,6 +498,50 @@ NodeGraph::count_subscribers(const std::string & topic_name) const
|
||||
return count;
|
||||
}
|
||||
|
||||
size_t
|
||||
NodeGraph::count_clients(const std::string & service_name) const
|
||||
{
|
||||
auto rcl_node_handle = node_base_->get_rcl_node_handle();
|
||||
|
||||
auto fqdn = rclcpp::expand_topic_or_service_name(
|
||||
service_name,
|
||||
rcl_node_get_name(rcl_node_handle),
|
||||
rcl_node_get_namespace(rcl_node_handle),
|
||||
true);
|
||||
|
||||
size_t count;
|
||||
auto ret = rcl_count_clients(rcl_node_handle, fqdn.c_str(), &count);
|
||||
if (ret != RMW_RET_OK) {
|
||||
// *INDENT-OFF*
|
||||
throw std::runtime_error(
|
||||
std::string("could not count clients: ") + rmw_get_error_string().str);
|
||||
// *INDENT-ON*
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
size_t
|
||||
NodeGraph::count_services(const std::string & service_name) const
|
||||
{
|
||||
auto rcl_node_handle = node_base_->get_rcl_node_handle();
|
||||
|
||||
auto fqdn = rclcpp::expand_topic_or_service_name(
|
||||
service_name,
|
||||
rcl_node_get_name(rcl_node_handle),
|
||||
rcl_node_get_namespace(rcl_node_handle),
|
||||
true);
|
||||
|
||||
size_t count;
|
||||
auto ret = rcl_count_services(rcl_node_handle, fqdn.c_str(), &count);
|
||||
if (ret != RMW_RET_OK) {
|
||||
// *INDENT-OFF*
|
||||
throw std::runtime_error(
|
||||
std::string("could not count services: ") + rmw_get_error_string().str);
|
||||
// *INDENT-ON*
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
const rcl_guard_condition_t *
|
||||
NodeGraph::get_graph_guard_condition() const
|
||||
{
|
||||
|
||||
@@ -1059,7 +1059,7 @@ NodeParameters::list_parameters(const std::vector<std::string> & prefixes, uint6
|
||||
if (depth == rcl_interfaces::srv::ListParameters::Request::DEPTH_RECURSIVE) {
|
||||
return true;
|
||||
}
|
||||
std::string substr = kv.first.substr(prefix.length());
|
||||
std::string substr = kv.first.substr(prefix.length() + 1);
|
||||
return separators_less_than_depth(substr);
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -84,23 +84,31 @@ public:
|
||||
}
|
||||
|
||||
if (enabled) {
|
||||
auto rcl_node = node_base->get_rcl_node_handle();
|
||||
rcl_ret_t rcl_ret = rcl_node_type_description_service_init(rcl_node);
|
||||
auto * rcl_node = node_base->get_rcl_node_handle();
|
||||
std::shared_ptr<rcl_service_t> rcl_srv(
|
||||
new rcl_service_t,
|
||||
[rcl_node, logger = this->logger_](rcl_service_t * service)
|
||||
{
|
||||
if (rcl_service_fini(service, rcl_node) != RCL_RET_OK) {
|
||||
RCLCPP_ERROR(
|
||||
logger,
|
||||
"Error in destruction of rcl service handle [~/get_type_description]: %s",
|
||||
rcl_get_error_string().str);
|
||||
rcl_reset_error();
|
||||
}
|
||||
delete service;
|
||||
});
|
||||
*rcl_srv = rcl_get_zero_initialized_service();
|
||||
rcl_ret_t rcl_ret = rcl_node_type_description_service_init(rcl_srv.get(), rcl_node);
|
||||
|
||||
if (rcl_ret != RCL_RET_OK) {
|
||||
RCLCPP_ERROR(
|
||||
logger_, "Failed to initialize ~/get_type_description_service: %s",
|
||||
logger_, "Failed to initialize ~/get_type_description service: %s",
|
||||
rcl_get_error_string().str);
|
||||
throw std::runtime_error(
|
||||
"Failed to initialize ~/get_type_description service.");
|
||||
}
|
||||
|
||||
rcl_service_t * rcl_srv = nullptr;
|
||||
rcl_ret = rcl_node_get_type_description_service(rcl_node, &rcl_srv);
|
||||
if (rcl_ret != RCL_RET_OK) {
|
||||
throw std::runtime_error(
|
||||
"Failed to get initialized ~/get_type_description service from rcl.");
|
||||
}
|
||||
|
||||
rclcpp::AnyServiceCallback<ServiceT> cb;
|
||||
cb.set(
|
||||
[this](
|
||||
@@ -124,18 +132,6 @@ public:
|
||||
nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
~NodeTypeDescriptionsImpl()
|
||||
{
|
||||
if (
|
||||
type_description_srv_ &&
|
||||
RCL_RET_OK != rcl_node_type_description_service_fini(node_base_->get_rcl_node_handle()))
|
||||
{
|
||||
RCLCPP_ERROR(
|
||||
logger_,
|
||||
"Error in shutdown of get_type_description service: %s", rcl_get_error_string().str);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
NodeTypeDescriptions::NodeTypeDescriptions(
|
||||
|
||||
@@ -270,6 +270,13 @@ PublisherBase::get_intra_process_subscription_count() const
|
||||
return ipm->get_subscription_count(intra_process_publisher_id_);
|
||||
}
|
||||
|
||||
bool
|
||||
PublisherBase::is_durability_transient_local() const
|
||||
{
|
||||
return rcl_publisher_get_actual_qos(publisher_handle_.get())->durability ==
|
||||
RMW_QOS_POLICY_DURABILITY_TRANSIENT_LOCAL;
|
||||
}
|
||||
|
||||
rclcpp::QoS
|
||||
PublisherBase::get_actual_qos() const
|
||||
{
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
#include "rclcpp/rate.hpp"
|
||||
|
||||
#include <chrono>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace rclcpp
|
||||
@@ -66,7 +67,8 @@ Rate::sleep()
|
||||
// Calculate the time to sleep
|
||||
auto time_to_sleep = next_interval - now;
|
||||
// Sleep (will get interrupted by ctrl-c, may not sleep full time)
|
||||
return clock_->sleep_for(time_to_sleep);
|
||||
clock_->sleep_for(time_to_sleep);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -87,10 +89,10 @@ Rate::reset()
|
||||
last_interval_ = clock_->now();
|
||||
}
|
||||
|
||||
Duration
|
||||
std::chrono::nanoseconds
|
||||
Rate::period() const
|
||||
{
|
||||
return period_;
|
||||
return std::chrono::nanoseconds(period_.nanoseconds());
|
||||
}
|
||||
|
||||
WallRate::WallRate(const double rate)
|
||||
@@ -101,12 +103,4 @@ WallRate::WallRate(const Duration & period)
|
||||
: Rate(period, std::make_shared<Clock>(RCL_STEADY_TIME))
|
||||
{}
|
||||
|
||||
ROSRate::ROSRate(const double rate)
|
||||
: Rate(rate, std::make_shared<Clock>(RCL_ROS_TIME))
|
||||
{}
|
||||
|
||||
ROSRate::ROSRate(const Duration & period)
|
||||
: Rate(period, std::make_shared<Clock>(RCL_ROS_TIME))
|
||||
{}
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
@@ -113,7 +113,7 @@ SignalHandler::get_logger()
|
||||
SignalHandler &
|
||||
SignalHandler::get_global_signal_handler()
|
||||
{
|
||||
static SignalHandler signal_handler;
|
||||
static SignalHandler & signal_handler = *new SignalHandler();
|
||||
return signal_handler;
|
||||
}
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ public:
|
||||
bool
|
||||
install(SignalHandlerOptions signal_handler_options = SignalHandlerOptions::All);
|
||||
|
||||
/// Uninstall the signal handler for SIGINT/SIGTERM and join the dedicated singal handling
|
||||
/// Uninstall the signal handler for SIGINT/SIGTERM and join the dedicated signal handling
|
||||
/// thread.
|
||||
/**
|
||||
* Also restores the previous signal handler.
|
||||
@@ -189,7 +189,7 @@ private:
|
||||
|
||||
// Whether or not a signal has been received.
|
||||
std::atomic_bool signal_received_ = false;
|
||||
// A thread to which singal handling tasks are deferred.
|
||||
// A thread to which signal handling tasks are deferred.
|
||||
std::thread signal_handler_thread_;
|
||||
|
||||
// A mutex used to synchronize the install() and uninstall() methods.
|
||||
|
||||
@@ -298,7 +298,20 @@ SubscriptionBase::setup_intra_process(
|
||||
bool
|
||||
SubscriptionBase::can_loan_messages() const
|
||||
{
|
||||
return rcl_subscription_can_loan_messages(subscription_handle_.get());
|
||||
bool retval = rcl_subscription_can_loan_messages(subscription_handle_.get());
|
||||
if (retval) {
|
||||
// TODO(clalancette): The loaned message interface is currently not safe to use with
|
||||
// shared_ptr callbacks. If a user takes a copy of the shared_ptr, it can get freed from
|
||||
// underneath them via rcl_return_loaned_message_from_subscription(). The correct solution is
|
||||
// to return the loaned message in a custom deleter, but that needs to be carefully handled
|
||||
// with locking. Warn the user about this until we fix it.
|
||||
RCLCPP_WARN_ONCE(
|
||||
this->node_logger_,
|
||||
"Loaned messages are only safe with const ref subscription callbacks. "
|
||||
"If you are using any other kind of subscriptions, "
|
||||
"set the ROS_DISABLE_LOANED_MESSAGES environment variable to 1 (the default).");
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
rclcpp::Waitable::SharedPtr
|
||||
|
||||
@@ -34,3 +34,9 @@ SubscriptionIntraProcessBase::get_actual_qos() const
|
||||
{
|
||||
return qos_profile_;
|
||||
}
|
||||
|
||||
bool
|
||||
SubscriptionIntraProcessBase::is_durability_transient_local() const
|
||||
{
|
||||
return qos_profile_.durability() == rclcpp::DurabilityPolicy::TransientLocal;
|
||||
}
|
||||
|
||||
@@ -276,9 +276,9 @@ Time::operator-=(const rclcpp::Duration & rhs)
|
||||
}
|
||||
|
||||
Time
|
||||
Time::max()
|
||||
Time::max(rcl_clock_type_t clock_type)
|
||||
{
|
||||
return Time(std::numeric_limits<int32_t>::max(), 999999999);
|
||||
return Time(std::numeric_limits<int32_t>::max(), 999999999, clock_type);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -236,6 +236,7 @@ public:
|
||||
rclcpp::node_interfaces::NodeClockInterface::SharedPtr node_clock_interface,
|
||||
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr node_parameters_interface)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(node_base_lock_);
|
||||
node_base_ = node_base_interface;
|
||||
node_topics_ = node_topics_interface;
|
||||
node_graph_ = node_graph_interface;
|
||||
@@ -280,17 +281,14 @@ public:
|
||||
parameter_subscription_ = rclcpp::AsyncParametersClient::on_parameter_event(
|
||||
node_topics_,
|
||||
[this](std::shared_ptr<const rcl_interfaces::msg::ParameterEvent> event) {
|
||||
if (node_base_ != nullptr) {
|
||||
this->on_parameter_event(event);
|
||||
}
|
||||
// Do nothing if node_base_ is nullptr because it means the TimeSource is now
|
||||
// without an attached node
|
||||
this->on_parameter_event(event);
|
||||
});
|
||||
}
|
||||
|
||||
// Detach the attached node
|
||||
void detachNode()
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(node_base_lock_);
|
||||
// destroy_clock_sub() *must* be first here, to ensure that the executor
|
||||
// can't possibly call any of the callbacks as we are cleaning up.
|
||||
destroy_clock_sub();
|
||||
@@ -327,6 +325,7 @@ private:
|
||||
std::thread clock_executor_thread_;
|
||||
|
||||
// Preserve the node reference
|
||||
std::mutex node_base_lock_;
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_{nullptr};
|
||||
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics_{nullptr};
|
||||
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph_{nullptr};
|
||||
@@ -464,6 +463,14 @@ private:
|
||||
// Callback for parameter updates
|
||||
void on_parameter_event(std::shared_ptr<const rcl_interfaces::msg::ParameterEvent> event)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(node_base_lock_);
|
||||
|
||||
if (node_base_ == nullptr) {
|
||||
// Do nothing if node_base_ is nullptr because it means the TimeSource is now
|
||||
// without an attached node
|
||||
return;
|
||||
}
|
||||
|
||||
// Filter out events on 'use_sim_time' parameter instances in other nodes.
|
||||
if (event->node != node_base_->get_fully_qualified_name()) {
|
||||
return;
|
||||
|
||||
@@ -91,6 +91,44 @@ extract_type_identifier(const std::string & full_type)
|
||||
return std::make_tuple(package_name, middle_module, type_name);
|
||||
}
|
||||
|
||||
const void * get_typesupport_handle_impl(
|
||||
const std::string & type,
|
||||
const std::string & typesupport_identifier,
|
||||
const std::string & typesupport_name,
|
||||
const std::string & symbol_part_name,
|
||||
const std::string & middle_module_additional,
|
||||
rcpputils::SharedLibrary & library)
|
||||
{
|
||||
std::string package_name;
|
||||
std::string middle_module;
|
||||
std::string type_name;
|
||||
std::tie(package_name, middle_module, type_name) = extract_type_identifier(type);
|
||||
|
||||
if (middle_module.empty()) {
|
||||
middle_module = middle_module_additional;
|
||||
}
|
||||
|
||||
auto mk_error = [&package_name, &type_name, &typesupport_name](auto reason) {
|
||||
std::stringstream rcutils_dynamic_loading_error;
|
||||
rcutils_dynamic_loading_error <<
|
||||
"Something went wrong loading the typesupport library for " <<
|
||||
typesupport_name << " type " << package_name <<
|
||||
"/" << type_name << ". " << reason;
|
||||
return rcutils_dynamic_loading_error.str();
|
||||
};
|
||||
|
||||
try {
|
||||
std::string symbol_name = typesupport_identifier + symbol_part_name +
|
||||
package_name + "__" + middle_module + "__" + type_name;
|
||||
const void * (* get_ts)() = nullptr;
|
||||
// This will throw runtime_error if the symbol was not found.
|
||||
get_ts = reinterpret_cast<decltype(get_ts)>(library.get_symbol(symbol_name));
|
||||
return get_ts();
|
||||
} catch (std::runtime_error &) {
|
||||
throw std::runtime_error{mk_error("Library could not be found.")};
|
||||
}
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
std::shared_ptr<rcpputils::SharedLibrary>
|
||||
@@ -101,36 +139,42 @@ get_typesupport_library(const std::string & type, const std::string & typesuppor
|
||||
return std::make_shared<rcpputils::SharedLibrary>(library_path);
|
||||
}
|
||||
|
||||
const rosidl_message_type_support_t *
|
||||
get_typesupport_handle(
|
||||
const rosidl_message_type_support_t * get_typesupport_handle(
|
||||
const std::string & type,
|
||||
const std::string & typesupport_identifier,
|
||||
rcpputils::SharedLibrary & library)
|
||||
{
|
||||
std::string package_name;
|
||||
std::string middle_module;
|
||||
std::string type_name;
|
||||
std::tie(package_name, middle_module, type_name) = extract_type_identifier(type);
|
||||
return get_message_typesupport_handle(type, typesupport_identifier, library);
|
||||
}
|
||||
|
||||
auto mk_error = [&package_name, &type_name](auto reason) {
|
||||
std::stringstream rcutils_dynamic_loading_error;
|
||||
rcutils_dynamic_loading_error <<
|
||||
"Something went wrong loading the typesupport library for message type " << package_name <<
|
||||
"/" << type_name << ". " << reason;
|
||||
return rcutils_dynamic_loading_error.str();
|
||||
};
|
||||
const rosidl_message_type_support_t * get_message_typesupport_handle(
|
||||
const std::string & type,
|
||||
const std::string & typesupport_identifier,
|
||||
rcpputils::SharedLibrary & library)
|
||||
{
|
||||
static const std::string typesupport_name = "message";
|
||||
static const std::string symbol_part_name = "__get_message_type_support_handle__";
|
||||
static const std::string middle_module_additional = "msg";
|
||||
|
||||
try {
|
||||
std::string symbol_name = typesupport_identifier + "__get_message_type_support_handle__" +
|
||||
package_name + "__" + (middle_module.empty() ? "msg" : middle_module) + "__" + type_name;
|
||||
return static_cast<const rosidl_message_type_support_t *>(get_typesupport_handle_impl(
|
||||
type, typesupport_identifier, typesupport_name, symbol_part_name,
|
||||
middle_module_additional, library
|
||||
));
|
||||
}
|
||||
|
||||
const rosidl_message_type_support_t * (* get_ts)() = nullptr;
|
||||
// This will throw runtime_error if the symbol was not found.
|
||||
get_ts = reinterpret_cast<decltype(get_ts)>(library.get_symbol(symbol_name));
|
||||
return get_ts();
|
||||
} catch (std::runtime_error &) {
|
||||
throw std::runtime_error{mk_error("Library could not be found.")};
|
||||
}
|
||||
const rosidl_service_type_support_t * get_service_typesupport_handle(
|
||||
const std::string & type,
|
||||
const std::string & typesupport_identifier,
|
||||
rcpputils::SharedLibrary & library)
|
||||
{
|
||||
static const std::string typesupport_name = "service";
|
||||
static const std::string symbol_part_name = "__get_service_type_support_handle__";
|
||||
static const std::string middle_module_additional = "srv";
|
||||
|
||||
return static_cast<const rosidl_service_type_support_t *>(get_typesupport_handle_impl(
|
||||
type, typesupport_identifier, typesupport_name, symbol_part_name,
|
||||
middle_module_additional, library
|
||||
));
|
||||
}
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
@@ -7,14 +7,12 @@ find_package(performance_test_fixture REQUIRED)
|
||||
|
||||
add_performance_test(benchmark_client benchmark_client.cpp)
|
||||
if(TARGET benchmark_client)
|
||||
target_link_libraries(benchmark_client ${PROJECT_NAME})
|
||||
ament_target_dependencies(benchmark_client test_msgs rcl_interfaces)
|
||||
target_link_libraries(benchmark_client ${PROJECT_NAME} ${rcl_interfaces_TARGETS} ${test_msgs_TARGETS})
|
||||
endif()
|
||||
|
||||
add_performance_test(benchmark_executor benchmark_executor.cpp)
|
||||
if(TARGET benchmark_executor)
|
||||
target_link_libraries(benchmark_executor ${PROJECT_NAME})
|
||||
ament_target_dependencies(benchmark_executor test_msgs)
|
||||
target_link_libraries(benchmark_executor ${PROJECT_NAME} ${test_msgs_TARGETS})
|
||||
endif()
|
||||
|
||||
add_performance_test(benchmark_init_shutdown benchmark_init_shutdown.cpp)
|
||||
@@ -39,6 +37,5 @@ endif()
|
||||
|
||||
add_performance_test(benchmark_service benchmark_service.cpp)
|
||||
if(TARGET benchmark_service)
|
||||
target_link_libraries(benchmark_service ${PROJECT_NAME})
|
||||
ament_target_dependencies(benchmark_service test_msgs rcl_interfaces)
|
||||
target_link_libraries(benchmark_service ${PROJECT_NAME} ${rcl_interfaces_TARGETS} ${test_msgs_TARGETS})
|
||||
endif()
|
||||
|
||||
@@ -34,71 +34,38 @@ if(TARGET test_exceptions)
|
||||
target_link_libraries(test_exceptions ${PROJECT_NAME} mimick)
|
||||
endif()
|
||||
|
||||
# Increasing timeout because connext can take a long time to destroy nodes
|
||||
# TODO(brawner) remove when destroying Node for Connext is resolved. See:
|
||||
# https://github.com/ros2/rclcpp/issues/1250
|
||||
ament_add_gtest(
|
||||
test_allocator_memory_strategy
|
||||
strategies/test_allocator_memory_strategy.cpp
|
||||
TIMEOUT 360)
|
||||
ament_add_gtest(test_allocator_memory_strategy strategies/test_allocator_memory_strategy.cpp)
|
||||
if(TARGET test_allocator_memory_strategy)
|
||||
ament_target_dependencies(test_allocator_memory_strategy
|
||||
"rcl"
|
||||
"test_msgs"
|
||||
)
|
||||
target_link_libraries(test_allocator_memory_strategy ${PROJECT_NAME})
|
||||
target_link_libraries(test_allocator_memory_strategy ${PROJECT_NAME} rcpputils::rcpputils ${test_msgs_TARGETS})
|
||||
endif()
|
||||
ament_add_gtest(test_message_pool_memory_strategy strategies/test_message_pool_memory_strategy.cpp)
|
||||
if(TARGET test_message_pool_memory_strategy)
|
||||
ament_target_dependencies(test_message_pool_memory_strategy
|
||||
"rcl"
|
||||
"test_msgs"
|
||||
)
|
||||
target_link_libraries(test_message_pool_memory_strategy ${PROJECT_NAME})
|
||||
target_link_libraries(test_message_pool_memory_strategy ${PROJECT_NAME} ${test_msgs_TARGETS})
|
||||
endif()
|
||||
ament_add_gtest(test_any_service_callback test_any_service_callback.cpp)
|
||||
if(TARGET test_any_service_callback)
|
||||
ament_target_dependencies(test_any_service_callback
|
||||
"test_msgs"
|
||||
)
|
||||
target_link_libraries(test_any_service_callback ${PROJECT_NAME})
|
||||
target_link_libraries(test_any_service_callback ${PROJECT_NAME} ${test_msgs_TARGETS})
|
||||
endif()
|
||||
ament_add_gtest(test_any_subscription_callback test_any_subscription_callback.cpp)
|
||||
if(TARGET test_any_subscription_callback)
|
||||
ament_target_dependencies(test_any_subscription_callback
|
||||
"test_msgs"
|
||||
)
|
||||
target_link_libraries(test_any_subscription_callback ${PROJECT_NAME})
|
||||
target_link_libraries(test_any_subscription_callback ${PROJECT_NAME} ${test_msgs_TARGETS})
|
||||
endif()
|
||||
ament_add_gtest(test_client test_client.cpp)
|
||||
if(TARGET test_client)
|
||||
ament_target_dependencies(test_client
|
||||
"rcl_interfaces"
|
||||
"rmw"
|
||||
"rosidl_runtime_cpp"
|
||||
"rosidl_typesupport_cpp"
|
||||
"test_msgs"
|
||||
)
|
||||
target_link_libraries(test_client ${PROJECT_NAME} mimick)
|
||||
target_link_libraries(test_client ${PROJECT_NAME} mimick ${rcl_interfaces_TARGETS} ${test_msgs_TARGETS})
|
||||
endif()
|
||||
ament_add_gtest(test_copy_all_parameter_values test_copy_all_parameter_values.cpp)
|
||||
if(TARGET test_copy_all_parameter_values)
|
||||
target_link_libraries(test_copy_all_parameter_values ${PROJECT_NAME})
|
||||
endif()
|
||||
ament_add_gtest(test_create_timer test_create_timer.cpp)
|
||||
if(TARGET test_create_timer)
|
||||
ament_target_dependencies(test_create_timer
|
||||
"rcl_interfaces"
|
||||
"rmw"
|
||||
"rcl"
|
||||
"rosidl_runtime_cpp"
|
||||
"rosidl_typesupport_cpp"
|
||||
)
|
||||
target_link_libraries(test_create_timer ${PROJECT_NAME})
|
||||
target_include_directories(test_create_timer PRIVATE ./)
|
||||
endif()
|
||||
ament_add_gtest(test_create_subscription test_create_subscription.cpp)
|
||||
if(TARGET test_create_subscription)
|
||||
target_link_libraries(test_create_subscription ${PROJECT_NAME})
|
||||
ament_target_dependencies(test_create_subscription
|
||||
"test_msgs"
|
||||
)
|
||||
target_link_libraries(test_create_subscription ${PROJECT_NAME} ${test_msgs_TARGETS})
|
||||
endif()
|
||||
function(test_add_callback_groups_to_executor_for_rmw_implementation)
|
||||
set(rmw_implementation_env_var RMW_IMPLEMENTATION=${rmw_implementation})
|
||||
@@ -107,32 +74,17 @@ function(test_add_callback_groups_to_executor_for_rmw_implementation)
|
||||
TIMEOUT 120
|
||||
)
|
||||
if(TARGET test_add_callback_groups_to_executor${target_suffix})
|
||||
target_link_libraries(test_add_callback_groups_to_executor${target_suffix} ${PROJECT_NAME})
|
||||
ament_target_dependencies(test_add_callback_groups_to_executor${target_suffix}
|
||||
"test_msgs"
|
||||
)
|
||||
target_link_libraries(test_add_callback_groups_to_executor${target_suffix} ${PROJECT_NAME} ${test_msgs_TARGETS})
|
||||
endif()
|
||||
endfunction()
|
||||
call_for_each_rmw_implementation(test_add_callback_groups_to_executor_for_rmw_implementation)
|
||||
ament_add_gtest(test_expand_topic_or_service_name test_expand_topic_or_service_name.cpp)
|
||||
if(TARGET test_expand_topic_or_service_name)
|
||||
ament_target_dependencies(test_expand_topic_or_service_name
|
||||
"rcl_interfaces"
|
||||
"rmw"
|
||||
"rosidl_runtime_cpp"
|
||||
"rosidl_typesupport_cpp"
|
||||
)
|
||||
target_link_libraries(test_expand_topic_or_service_name ${PROJECT_NAME} mimick)
|
||||
target_link_libraries(test_expand_topic_or_service_name ${PROJECT_NAME} mimick rcl::rcl rmw::rmw)
|
||||
endif()
|
||||
ament_add_gtest(test_function_traits test_function_traits.cpp)
|
||||
if(TARGET test_function_traits)
|
||||
target_include_directories(test_function_traits PUBLIC ../../include)
|
||||
ament_target_dependencies(test_function_traits
|
||||
"rcl_interfaces"
|
||||
"rmw"
|
||||
"rosidl_runtime_cpp"
|
||||
"rosidl_typesupport_cpp"
|
||||
)
|
||||
target_link_libraries(test_function_traits ${PROJECT_NAME})
|
||||
endif()
|
||||
ament_add_gtest(
|
||||
test_future_return_code
|
||||
@@ -142,72 +94,33 @@ if(TARGET test_future_return_code)
|
||||
endif()
|
||||
ament_add_gmock(test_intra_process_manager test_intra_process_manager.cpp)
|
||||
if(TARGET test_intra_process_manager)
|
||||
ament_target_dependencies(test_intra_process_manager
|
||||
"rcl"
|
||||
"rcl_interfaces"
|
||||
"rmw"
|
||||
"rosidl_runtime_cpp"
|
||||
"rosidl_typesupport_cpp"
|
||||
)
|
||||
target_link_libraries(test_intra_process_manager ${PROJECT_NAME})
|
||||
target_link_libraries(test_intra_process_manager ${PROJECT_NAME} ${rcl_interfaces_TARGETS} rmw::rmw)
|
||||
endif()
|
||||
ament_add_gmock(test_intra_process_manager_with_allocators test_intra_process_manager_with_allocators.cpp)
|
||||
if(TARGET test_intra_process_manager_with_allocators)
|
||||
ament_target_dependencies(test_intra_process_manager_with_allocators
|
||||
"test_msgs"
|
||||
)
|
||||
target_link_libraries(test_intra_process_manager_with_allocators ${PROJECT_NAME})
|
||||
target_link_libraries(test_intra_process_manager_with_allocators ${PROJECT_NAME} ${test_msgs_TARGETS})
|
||||
endif()
|
||||
ament_add_gtest(test_ring_buffer_implementation test_ring_buffer_implementation.cpp)
|
||||
if(TARGET test_ring_buffer_implementation)
|
||||
ament_target_dependencies(test_ring_buffer_implementation
|
||||
"rcl_interfaces"
|
||||
"rmw"
|
||||
"rosidl_runtime_cpp"
|
||||
"rosidl_typesupport_cpp"
|
||||
)
|
||||
target_link_libraries(test_ring_buffer_implementation ${PROJECT_NAME})
|
||||
endif()
|
||||
ament_add_gtest(test_intra_process_buffer test_intra_process_buffer.cpp)
|
||||
if(TARGET test_intra_process_buffer)
|
||||
ament_target_dependencies(test_intra_process_buffer
|
||||
"rcl_interfaces"
|
||||
"rmw"
|
||||
"rosidl_runtime_cpp"
|
||||
"rosidl_typesupport_cpp"
|
||||
)
|
||||
target_link_libraries(test_intra_process_buffer ${PROJECT_NAME})
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_loaned_message test_loaned_message.cpp)
|
||||
ament_target_dependencies(test_loaned_message
|
||||
"test_msgs"
|
||||
)
|
||||
target_link_libraries(test_loaned_message ${PROJECT_NAME} mimick)
|
||||
target_link_libraries(test_loaned_message ${PROJECT_NAME} mimick ${test_msgs_TARGETS})
|
||||
|
||||
ament_add_gtest(test_memory_strategy test_memory_strategy.cpp)
|
||||
ament_target_dependencies(test_memory_strategy
|
||||
"test_msgs"
|
||||
)
|
||||
target_link_libraries(test_memory_strategy ${PROJECT_NAME})
|
||||
target_link_libraries(test_memory_strategy ${PROJECT_NAME} ${test_msgs_TARGETS})
|
||||
|
||||
ament_add_gtest(test_message_memory_strategy test_message_memory_strategy.cpp)
|
||||
ament_target_dependencies(test_message_memory_strategy
|
||||
"test_msgs"
|
||||
)
|
||||
target_link_libraries(test_message_memory_strategy ${PROJECT_NAME})
|
||||
target_link_libraries(test_message_memory_strategy ${PROJECT_NAME} ${test_msgs_TARGETS})
|
||||
|
||||
ament_add_gtest(test_node test_node.cpp TIMEOUT 240)
|
||||
if(TARGET test_node)
|
||||
ament_target_dependencies(test_node
|
||||
"rcl_interfaces"
|
||||
"rcpputils"
|
||||
"rmw"
|
||||
"rosidl_runtime_cpp"
|
||||
"rosidl_typesupport_cpp"
|
||||
"test_msgs"
|
||||
)
|
||||
target_link_libraries(test_node ${PROJECT_NAME} mimick)
|
||||
target_link_libraries(test_node ${PROJECT_NAME} mimick rcpputils::rcpputils rmw::rmw ${test_msgs_TARGETS})
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_node_interfaces__get_node_interfaces
|
||||
@@ -218,7 +131,7 @@ endif()
|
||||
ament_add_gtest(test_node_interfaces__node_base
|
||||
node_interfaces/test_node_base.cpp)
|
||||
if(TARGET test_node_interfaces__node_base)
|
||||
target_link_libraries(test_node_interfaces__node_base ${PROJECT_NAME} mimick)
|
||||
target_link_libraries(test_node_interfaces__node_base ${PROJECT_NAME} mimick rcl::rcl rmw::rmw)
|
||||
endif()
|
||||
ament_add_gtest(test_node_interfaces__node_clock
|
||||
node_interfaces/test_node_clock.cpp)
|
||||
@@ -229,48 +142,42 @@ ament_add_gtest(test_node_interfaces__node_graph
|
||||
node_interfaces/test_node_graph.cpp
|
||||
TIMEOUT 120)
|
||||
if(TARGET test_node_interfaces__node_graph)
|
||||
ament_target_dependencies(
|
||||
test_node_interfaces__node_graph
|
||||
"test_msgs")
|
||||
target_link_libraries(test_node_interfaces__node_graph ${PROJECT_NAME} mimick)
|
||||
target_link_libraries(test_node_interfaces__node_graph ${PROJECT_NAME} mimick rcl::rcl ${test_msgs_TARGETS})
|
||||
endif()
|
||||
ament_add_gtest(test_node_interfaces__node_interfaces
|
||||
node_interfaces/test_node_interfaces.cpp)
|
||||
if(TARGET test_node_interfaces__node_interfaces)
|
||||
target_link_libraries(test_node_interfaces__node_interfaces ${PROJECT_NAME} mimick)
|
||||
target_link_libraries(test_node_interfaces__node_interfaces ${PROJECT_NAME})
|
||||
endif()
|
||||
ament_add_gtest(test_node_interfaces__node_parameters
|
||||
node_interfaces/test_node_parameters.cpp)
|
||||
if(TARGET test_node_interfaces__node_parameters)
|
||||
target_link_libraries(test_node_interfaces__node_parameters ${PROJECT_NAME} mimick)
|
||||
target_link_libraries(test_node_interfaces__node_parameters ${PROJECT_NAME} mimick rcpputils::rcpputils)
|
||||
endif()
|
||||
ament_add_gtest(test_node_interfaces__node_services
|
||||
node_interfaces/test_node_services.cpp)
|
||||
if(TARGET test_node_interfaces__node_services)
|
||||
target_link_libraries(test_node_interfaces__node_services ${PROJECT_NAME} mimick)
|
||||
target_link_libraries(test_node_interfaces__node_services ${PROJECT_NAME} mimick rcl::rcl)
|
||||
endif()
|
||||
ament_add_gtest(test_node_interfaces__node_timers
|
||||
node_interfaces/test_node_timers.cpp)
|
||||
if(TARGET test_node_interfaces__node_timers)
|
||||
target_link_libraries(test_node_interfaces__node_timers ${PROJECT_NAME} mimick)
|
||||
target_link_libraries(test_node_interfaces__node_timers ${PROJECT_NAME} mimick rcl::rcl)
|
||||
endif()
|
||||
ament_add_gtest(test_node_interfaces__node_topics
|
||||
node_interfaces/test_node_topics.cpp)
|
||||
if(TARGET test_node_interfaces__node_topics)
|
||||
ament_target_dependencies(
|
||||
test_node_interfaces__node_topics
|
||||
"test_msgs")
|
||||
target_link_libraries(test_node_interfaces__node_topics ${PROJECT_NAME} mimick)
|
||||
target_link_libraries(test_node_interfaces__node_topics ${PROJECT_NAME} mimick rcl::rcl ${test_msgs_TARGETS})
|
||||
endif()
|
||||
ament_add_gtest(test_node_interfaces__node_type_descriptions
|
||||
node_interfaces/test_node_type_descriptions.cpp)
|
||||
if(TARGET test_node_interfaces__node_type_descriptions)
|
||||
target_link_libraries(test_node_interfaces__node_type_descriptions ${PROJECT_NAME} mimick)
|
||||
target_link_libraries(test_node_interfaces__node_type_descriptions ${PROJECT_NAME})
|
||||
endif()
|
||||
ament_add_gtest(test_node_interfaces__node_waitables
|
||||
node_interfaces/test_node_waitables.cpp)
|
||||
if(TARGET test_node_interfaces__node_waitables)
|
||||
target_link_libraries(test_node_interfaces__node_waitables ${PROJECT_NAME} mimick)
|
||||
target_link_libraries(test_node_interfaces__node_waitables ${PROJECT_NAME} mimick rcl::rcl)
|
||||
endif()
|
||||
ament_add_gtest(test_node_interfaces__test_template_utils # Compile time test
|
||||
node_interfaces/detail/test_template_utils.cpp)
|
||||
@@ -301,82 +208,43 @@ endif()
|
||||
|
||||
ament_add_gtest(test_node_global_args test_node_global_args.cpp)
|
||||
if(TARGET test_node_global_args)
|
||||
ament_target_dependencies(test_node_global_args
|
||||
"rcl_interfaces"
|
||||
"rmw"
|
||||
"rosidl_runtime_cpp"
|
||||
"rosidl_typesupport_cpp"
|
||||
)
|
||||
target_link_libraries(test_node_global_args ${PROJECT_NAME})
|
||||
endif()
|
||||
ament_add_gtest(test_node_options test_node_options.cpp)
|
||||
if(TARGET test_node_options)
|
||||
ament_target_dependencies(test_node_options "rcl")
|
||||
target_link_libraries(test_node_options ${PROJECT_NAME} mimick)
|
||||
target_link_libraries(test_node_options ${PROJECT_NAME} mimick rcl::rcl)
|
||||
endif()
|
||||
ament_add_gtest(test_init_options test_init_options.cpp)
|
||||
if(TARGET test_init_options)
|
||||
ament_target_dependencies(test_init_options "rcl")
|
||||
target_link_libraries(test_init_options ${PROJECT_NAME} mimick)
|
||||
target_link_libraries(test_init_options ${PROJECT_NAME} mimick rcl::rcl)
|
||||
endif()
|
||||
ament_add_gmock(test_parameter_client test_parameter_client.cpp)
|
||||
if(TARGET test_parameter_client)
|
||||
ament_target_dependencies(test_parameter_client
|
||||
"rcl_interfaces"
|
||||
)
|
||||
target_link_libraries(test_parameter_client ${PROJECT_NAME})
|
||||
target_link_libraries(test_parameter_client ${PROJECT_NAME} ${rcl_interfaces_TARGETS})
|
||||
endif()
|
||||
ament_add_gtest(test_parameter_service test_parameter_service.cpp)
|
||||
if(TARGET test_parameter_service)
|
||||
ament_target_dependencies(test_parameter_service
|
||||
"rcl_interfaces"
|
||||
)
|
||||
target_link_libraries(test_parameter_service ${PROJECT_NAME})
|
||||
endif()
|
||||
ament_add_gtest(test_parameter_events_filter test_parameter_events_filter.cpp)
|
||||
if(TARGET test_parameter_events_filter)
|
||||
ament_target_dependencies(test_parameter_events_filter
|
||||
"rcl_interfaces"
|
||||
"rmw"
|
||||
"rosidl_runtime_cpp"
|
||||
"rosidl_typesupport_cpp"
|
||||
)
|
||||
target_link_libraries(test_parameter_events_filter ${PROJECT_NAME})
|
||||
target_link_libraries(test_parameter_events_filter ${PROJECT_NAME} ${rcl_interfaces_TARGETS})
|
||||
endif()
|
||||
ament_add_gtest(test_parameter test_parameter.cpp)
|
||||
if(TARGET test_parameter)
|
||||
ament_target_dependencies(test_parameter
|
||||
"rcl_interfaces"
|
||||
"rmw"
|
||||
"rosidl_runtime_cpp"
|
||||
"rosidl_typesupport_cpp"
|
||||
)
|
||||
target_link_libraries(test_parameter ${PROJECT_NAME})
|
||||
endif()
|
||||
ament_add_gtest(test_parameter_event_handler test_parameter_event_handler.cpp)
|
||||
if(TARGET test_parameter_event_handler)
|
||||
ament_target_dependencies(test_parameter_event_handler
|
||||
"rcl_interfaces"
|
||||
"rmw"
|
||||
"rosidl_generator_cpp"
|
||||
"rosidl_typesupport_cpp"
|
||||
)
|
||||
target_link_libraries(test_parameter_event_handler ${PROJECT_NAME})
|
||||
endif()
|
||||
ament_add_gtest(test_parameter_map test_parameter_map.cpp)
|
||||
if(TARGET test_parameter_map)
|
||||
target_link_libraries(test_parameter_map ${PROJECT_NAME})
|
||||
target_link_libraries(test_parameter_map ${PROJECT_NAME} rcl::rcl rcl_yaml_param_parser::rcl_yaml_param_parser rcutils::rcutils)
|
||||
endif()
|
||||
ament_add_gtest(test_publisher test_publisher.cpp TIMEOUT 120)
|
||||
if(TARGET test_publisher)
|
||||
ament_target_dependencies(test_publisher
|
||||
"rcl"
|
||||
"rmw"
|
||||
"rosidl_runtime_cpp"
|
||||
"rosidl_typesupport_cpp"
|
||||
"test_msgs"
|
||||
)
|
||||
target_link_libraries(test_publisher ${PROJECT_NAME} mimick)
|
||||
target_link_libraries(test_publisher ${PROJECT_NAME} mimick rcl::rcl rcutils::rcutils ${test_msgs_TARGETS})
|
||||
endif()
|
||||
|
||||
set(append_library_dirs "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
@@ -406,32 +274,22 @@ ament_add_gtest(test_subscription_publisher_with_same_type_adapter test_subscrip
|
||||
APPEND_LIBRARY_DIRS "${append_library_dirs}"
|
||||
)
|
||||
if(TARGET test_subscription_publisher_with_same_type_adapter)
|
||||
ament_target_dependencies(test_subscription_publisher_with_same_type_adapter
|
||||
"statistics_msgs"
|
||||
)
|
||||
target_link_libraries(test_subscription_publisher_with_same_type_adapter
|
||||
${PROJECT_NAME}
|
||||
${cpp_typesupport_target})
|
||||
${cpp_typesupport_target}
|
||||
${statistics_msgs_TARGETS}
|
||||
)
|
||||
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
|
||||
"rcl_interfaces"
|
||||
"rmw"
|
||||
"rosidl_runtime_cpp"
|
||||
"rosidl_typesupport_cpp"
|
||||
"test_msgs"
|
||||
)
|
||||
target_link_libraries(test_publisher_subscription_count_api ${PROJECT_NAME})
|
||||
target_link_libraries(test_publisher_subscription_count_api ${PROJECT_NAME} ${test_msgs_TARGETS})
|
||||
endif()
|
||||
ament_add_gtest(test_qos test_qos.cpp)
|
||||
if(TARGET test_qos)
|
||||
ament_target_dependencies(test_qos
|
||||
"rmw"
|
||||
)
|
||||
target_link_libraries(test_qos
|
||||
${PROJECT_NAME}
|
||||
rmw::rmw
|
||||
)
|
||||
endif()
|
||||
function(test_generic_pubsub_for_rmw_implementation)
|
||||
@@ -440,12 +298,7 @@ function(test_generic_pubsub_for_rmw_implementation)
|
||||
ENV ${rmw_implementation_env_var}
|
||||
)
|
||||
if(TARGET test_generic_pubsub${target_suffix})
|
||||
target_link_libraries(test_generic_pubsub${target_suffix} ${PROJECT_NAME})
|
||||
ament_target_dependencies(test_generic_pubsub${target_suffix}
|
||||
"rcpputils"
|
||||
"rosidl_typesupport_cpp"
|
||||
"test_msgs"
|
||||
)
|
||||
target_link_libraries(test_generic_pubsub${target_suffix} ${PROJECT_NAME} rcl::rcl ${test_msgs_TARGETS})
|
||||
endif()
|
||||
endfunction()
|
||||
call_for_each_rmw_implementation(test_generic_pubsub_for_rmw_implementation)
|
||||
@@ -456,153 +309,79 @@ function(test_qos_event_for_rmw_implementation)
|
||||
ENV ${rmw_implementation_env_var}
|
||||
)
|
||||
if(TARGET test_qos_event${target_suffix})
|
||||
target_link_libraries(test_qos_event${target_suffix} ${PROJECT_NAME} mimick)
|
||||
ament_target_dependencies(test_qos_event${target_suffix}
|
||||
"rmw"
|
||||
"rosidl_typesupport_cpp"
|
||||
"test_msgs"
|
||||
)
|
||||
target_link_libraries(test_qos_event${target_suffix} ${PROJECT_NAME} mimick rcutils::rcutils rmw::rmw ${test_msgs_TARGETS})
|
||||
endif()
|
||||
endfunction()
|
||||
call_for_each_rmw_implementation(test_qos_event_for_rmw_implementation)
|
||||
|
||||
ament_add_gmock(test_qos_overriding_options test_qos_overriding_options.cpp)
|
||||
if(TARGET test_qos_overriding_options)
|
||||
target_link_libraries(test_qos_overriding_options
|
||||
${PROJECT_NAME}
|
||||
)
|
||||
target_link_libraries(test_qos_overriding_options ${PROJECT_NAME})
|
||||
endif()
|
||||
ament_add_gmock(test_qos_parameters test_qos_parameters.cpp)
|
||||
if(TARGET test_qos_parameters)
|
||||
target_link_libraries(test_qos_parameters
|
||||
${PROJECT_NAME}
|
||||
)
|
||||
target_link_libraries(test_qos_parameters ${PROJECT_NAME})
|
||||
endif()
|
||||
ament_add_gtest(test_rate test_rate.cpp)
|
||||
if(TARGET test_rate)
|
||||
ament_target_dependencies(test_rate
|
||||
"rcl_interfaces"
|
||||
"rmw"
|
||||
"rosidl_runtime_cpp"
|
||||
"rosidl_typesupport_cpp"
|
||||
)
|
||||
target_link_libraries(test_rate
|
||||
${PROJECT_NAME}
|
||||
)
|
||||
target_link_libraries(test_rate ${PROJECT_NAME})
|
||||
endif()
|
||||
ament_add_gtest(test_serialized_message_allocator test_serialized_message_allocator.cpp)
|
||||
if(TARGET test_serialized_message_allocator)
|
||||
ament_target_dependencies(test_serialized_message_allocator
|
||||
test_msgs
|
||||
)
|
||||
target_link_libraries(test_serialized_message_allocator
|
||||
${PROJECT_NAME}
|
||||
)
|
||||
target_link_libraries(test_serialized_message_allocator ${PROJECT_NAME} rcl::rcl ${test_msgs_TARGETS})
|
||||
endif()
|
||||
ament_add_gtest(test_serialized_message test_serialized_message.cpp)
|
||||
if(TARGET test_serialized_message)
|
||||
ament_target_dependencies(test_serialized_message
|
||||
test_msgs
|
||||
)
|
||||
target_link_libraries(test_serialized_message
|
||||
${PROJECT_NAME}
|
||||
)
|
||||
target_link_libraries(test_serialized_message ${PROJECT_NAME} rcpputils::rcpputils ${test_msgs_TARGETS})
|
||||
endif()
|
||||
ament_add_gtest(test_service test_service.cpp)
|
||||
if(TARGET test_service)
|
||||
ament_target_dependencies(test_service
|
||||
"rcl_interfaces"
|
||||
"rmw"
|
||||
"rosidl_runtime_cpp"
|
||||
"rosidl_typesupport_cpp"
|
||||
"test_msgs"
|
||||
)
|
||||
target_link_libraries(test_service ${PROJECT_NAME} mimick)
|
||||
target_link_libraries(test_service ${PROJECT_NAME} mimick ${rcl_interfaces_TARGES} ${test_msgs_TARGETS})
|
||||
endif()
|
||||
ament_add_gmock(test_service_introspection test_service_introspection.cpp)
|
||||
if(TARGET test_service)
|
||||
ament_target_dependencies(test_service_introspection
|
||||
"rcl_interfaces"
|
||||
"rmw"
|
||||
"rosidl_runtime_cpp"
|
||||
"rosidl_typesupport_cpp"
|
||||
"test_msgs"
|
||||
)
|
||||
target_link_libraries(test_service_introspection ${PROJECT_NAME} mimick)
|
||||
if(TARGET test_service_introspection)
|
||||
target_link_libraries(test_service_introspection ${PROJECT_NAME} mimick ${service_msgs_TARGETS} ${test_msgs_TARGETS})
|
||||
endif()
|
||||
# Creating and destroying nodes is slow with Connext, so this needs larger timeout.
|
||||
ament_add_gtest(test_subscription test_subscription.cpp TIMEOUT 120)
|
||||
if(TARGET test_subscription)
|
||||
ament_target_dependencies(test_subscription
|
||||
"rcl_interfaces"
|
||||
"rmw"
|
||||
"rosidl_runtime_cpp"
|
||||
"rosidl_typesupport_cpp"
|
||||
"test_msgs"
|
||||
)
|
||||
target_link_libraries(test_subscription ${PROJECT_NAME} mimick)
|
||||
target_link_libraries(test_subscription ${PROJECT_NAME} mimick ${test_msgs_TARGETS})
|
||||
endif()
|
||||
ament_add_gtest(test_subscription_publisher_count_api test_subscription_publisher_count_api.cpp)
|
||||
if(TARGET test_subscription_publisher_count_api)
|
||||
ament_target_dependencies(test_subscription_publisher_count_api
|
||||
"rcl_interfaces"
|
||||
"rmw"
|
||||
"rosidl_runtime_cpp"
|
||||
"rosidl_typesupport_cpp"
|
||||
"test_msgs"
|
||||
)
|
||||
target_link_libraries(test_subscription_publisher_count_api ${PROJECT_NAME})
|
||||
target_link_libraries(test_subscription_publisher_count_api ${PROJECT_NAME} ${test_msgs_TARGETS})
|
||||
endif()
|
||||
ament_add_gtest(test_subscription_traits test_subscription_traits.cpp)
|
||||
if(TARGET test_subscription_traits)
|
||||
ament_target_dependencies(test_subscription_traits
|
||||
"rcl"
|
||||
"test_msgs"
|
||||
)
|
||||
target_link_libraries(test_subscription_traits ${PROJECT_NAME})
|
||||
target_link_libraries(test_subscription_traits ${PROJECT_NAME} rcl::rcl ${test_msgs_TARGETS})
|
||||
endif()
|
||||
ament_add_gtest(test_type_support test_type_support.cpp)
|
||||
if(TARGET test_type_support)
|
||||
ament_target_dependencies(test_type_support
|
||||
"rmw"
|
||||
"rosidl_runtime_cpp"
|
||||
"rosidl_typesupport_cpp"
|
||||
"test_msgs"
|
||||
)
|
||||
target_link_libraries(test_type_support ${PROJECT_NAME})
|
||||
target_link_libraries(test_type_support ${PROJECT_NAME} ${test_msgs_TARGETS})
|
||||
endif()
|
||||
ament_add_gmock(test_typesupport_helpers test_typesupport_helpers.cpp)
|
||||
if(TARGET test_typesupport_helpers)
|
||||
target_link_libraries(test_typesupport_helpers ${PROJECT_NAME})
|
||||
target_link_libraries(test_typesupport_helpers ${PROJECT_NAME} rcpputils::rcpputils)
|
||||
endif()
|
||||
ament_add_gtest(test_find_weak_nodes test_find_weak_nodes.cpp)
|
||||
if(TARGET test_find_weak_nodes)
|
||||
ament_target_dependencies(test_find_weak_nodes
|
||||
"rcl"
|
||||
)
|
||||
target_link_libraries(test_find_weak_nodes ${PROJECT_NAME})
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_externally_defined_services test_externally_defined_services.cpp)
|
||||
ament_target_dependencies(test_externally_defined_services
|
||||
"rcl"
|
||||
"test_msgs"
|
||||
)
|
||||
target_link_libraries(test_externally_defined_services ${PROJECT_NAME})
|
||||
target_link_libraries(test_externally_defined_services ${PROJECT_NAME} rcl::rcl ${test_msgs_TARGETS})
|
||||
|
||||
ament_add_gtest(test_duration test_duration.cpp
|
||||
APPEND_LIBRARY_DIRS "${append_library_dirs}")
|
||||
if(TARGET test_duration)
|
||||
ament_target_dependencies(test_duration
|
||||
"rcl")
|
||||
target_link_libraries(test_duration ${PROJECT_NAME})
|
||||
target_link_libraries(test_duration ${PROJECT_NAME} rcl::rcl)
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_logger test_logger.cpp)
|
||||
target_link_libraries(test_logger ${PROJECT_NAME})
|
||||
target_link_libraries(test_logger ${PROJECT_NAME} rcutils::rcutils)
|
||||
|
||||
ament_add_gmock(test_logging test_logging.cpp)
|
||||
target_link_libraries(test_logging ${PROJECT_NAME})
|
||||
target_link_libraries(test_logging ${PROJECT_NAME} rcutils::rcutils)
|
||||
|
||||
ament_add_gmock(test_context test_context.cpp)
|
||||
target_link_libraries(test_context ${PROJECT_NAME})
|
||||
@@ -610,134 +389,96 @@ target_link_libraries(test_context ${PROJECT_NAME})
|
||||
ament_add_gtest(test_time test_time.cpp
|
||||
APPEND_LIBRARY_DIRS "${append_library_dirs}")
|
||||
if(TARGET test_time)
|
||||
ament_target_dependencies(test_time
|
||||
"rcl")
|
||||
target_link_libraries(test_time ${PROJECT_NAME})
|
||||
target_link_libraries(test_time ${PROJECT_NAME} rcl::rcl rcutils::rcutils)
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_timer test_timer.cpp
|
||||
APPEND_LIBRARY_DIRS "${append_library_dirs}")
|
||||
if(TARGET test_timer)
|
||||
ament_target_dependencies(test_timer
|
||||
"rcl")
|
||||
target_link_libraries(test_timer ${PROJECT_NAME} mimick)
|
||||
target_link_libraries(test_timer ${PROJECT_NAME} mimick rcl::rcl)
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_timers_manager test_timers_manager.cpp
|
||||
APPEND_LIBRARY_DIRS "${append_library_dirs}")
|
||||
if(TARGET test_timers_manager)
|
||||
ament_target_dependencies(test_timers_manager
|
||||
"rcl")
|
||||
target_link_libraries(test_timers_manager ${PROJECT_NAME} mimick)
|
||||
target_link_libraries(test_timers_manager ${PROJECT_NAME})
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_time_source test_time_source.cpp
|
||||
APPEND_LIBRARY_DIRS "${append_library_dirs}")
|
||||
if(TARGET test_time_source)
|
||||
ament_target_dependencies(test_time_source
|
||||
"rcl")
|
||||
target_link_libraries(test_time_source ${PROJECT_NAME})
|
||||
target_link_libraries(test_time_source ${PROJECT_NAME} rcl::rcl)
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_utilities test_utilities.cpp
|
||||
APPEND_LIBRARY_DIRS "${append_library_dirs}")
|
||||
if(TARGET test_utilities)
|
||||
ament_target_dependencies(test_utilities
|
||||
"rcl")
|
||||
target_link_libraries(test_utilities ${PROJECT_NAME} mimick)
|
||||
target_link_libraries(test_utilities ${PROJECT_NAME} mimick rcl::rcl)
|
||||
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})
|
||||
target_link_libraries(test_wait_for_message ${PROJECT_NAME} ${test_msgs_TARGETS})
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_logger_service test_logger_service.cpp)
|
||||
if(TARGET test_logger_service)
|
||||
ament_target_dependencies(test_logger_service
|
||||
"rcl_interfaces")
|
||||
target_link_libraries(test_logger_service ${PROJECT_NAME})
|
||||
target_link_libraries(test_logger_service ${PROJECT_NAME} ${rcl_interfaces_TARGETS})
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_interface_traits test_interface_traits.cpp
|
||||
APPEND_LIBRARY_DIRS "${append_library_dirs}")
|
||||
if(TARGET test_interface_traits)
|
||||
ament_target_dependencies(test_interface_traits
|
||||
"rcl")
|
||||
target_link_libraries(test_interface_traits ${PROJECT_NAME})
|
||||
endif()
|
||||
|
||||
# TODO(brawner) remove when destroying Node for Connext is resolved. See:
|
||||
# https://github.com/ros2/rclcpp/issues/1250
|
||||
ament_add_gtest(
|
||||
test_executors
|
||||
executors/test_executors.cpp
|
||||
APPEND_LIBRARY_DIRS "${append_library_dirs}"
|
||||
TIMEOUT 180)
|
||||
if(TARGET test_executors)
|
||||
ament_target_dependencies(test_executors
|
||||
"rcl"
|
||||
"test_msgs")
|
||||
target_link_libraries(test_executors ${PROJECT_NAME})
|
||||
target_link_libraries(test_executors ${PROJECT_NAME} rcl::rcl ${test_msgs_TARGETS})
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_static_single_threaded_executor executors/test_static_single_threaded_executor.cpp
|
||||
APPEND_LIBRARY_DIRS "${append_library_dirs}")
|
||||
if(TARGET test_static_single_threaded_executor)
|
||||
ament_target_dependencies(test_static_single_threaded_executor
|
||||
"test_msgs")
|
||||
target_link_libraries(test_static_single_threaded_executor ${PROJECT_NAME} mimick)
|
||||
target_link_libraries(test_static_single_threaded_executor ${PROJECT_NAME} mimick ${test_msgs_TARGETS})
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_multi_threaded_executor executors/test_multi_threaded_executor.cpp
|
||||
APPEND_LIBRARY_DIRS "${append_library_dirs}")
|
||||
if(TARGET test_multi_threaded_executor)
|
||||
ament_target_dependencies(test_multi_threaded_executor
|
||||
"rcl")
|
||||
target_link_libraries(test_multi_threaded_executor ${PROJECT_NAME})
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_static_executor_entities_collector executors/test_static_executor_entities_collector.cpp
|
||||
APPEND_LIBRARY_DIRS "${append_library_dirs}" TIMEOUT 120)
|
||||
if(TARGET test_static_executor_entities_collector)
|
||||
ament_target_dependencies(test_static_executor_entities_collector
|
||||
"rcl"
|
||||
"test_msgs")
|
||||
target_link_libraries(test_static_executor_entities_collector ${PROJECT_NAME} mimick)
|
||||
target_link_libraries(test_static_executor_entities_collector ${PROJECT_NAME} mimick rcpputils::rcpputils ${test_msgs_TARGETS})
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_entities_collector executors/test_entities_collector.cpp
|
||||
APPEND_LIBRARY_DIRS "${append_library_dirs}" TIMEOUT 120)
|
||||
if(TARGET test_entities_collector)
|
||||
ament_target_dependencies(test_entities_collector
|
||||
"rcl"
|
||||
"test_msgs")
|
||||
target_link_libraries(test_entities_collector ${PROJECT_NAME} mimick)
|
||||
target_link_libraries(test_entities_collector ${PROJECT_NAME})
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_executor_notify_waitable executors/test_executor_notify_waitable.cpp
|
||||
APPEND_LIBRARY_DIRS "${append_library_dirs}" TIMEOUT 120)
|
||||
if(TARGET test_executor_notify_waitable)
|
||||
ament_target_dependencies(test_executor_notify_waitable
|
||||
"rcl"
|
||||
"test_msgs")
|
||||
target_link_libraries(test_executor_notify_waitable ${PROJECT_NAME} mimick)
|
||||
target_link_libraries(test_executor_notify_waitable ${PROJECT_NAME} mimick rcpputils::rcpputils)
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_events_executor executors/test_events_executor.cpp TIMEOUT 5)
|
||||
if(TARGET test_events_executor)
|
||||
ament_target_dependencies(test_events_executor
|
||||
"test_msgs")
|
||||
target_link_libraries(test_events_executor ${PROJECT_NAME})
|
||||
target_link_libraries(test_events_executor ${PROJECT_NAME} ${test_msgs_TARGETS})
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_events_queue executors/test_events_queue.cpp
|
||||
APPEND_LIBRARY_DIRS "${append_library_dirs}")
|
||||
if(TARGET test_events_queue)
|
||||
ament_target_dependencies(test_events_queue
|
||||
"test_msgs")
|
||||
target_link_libraries(test_events_queue ${PROJECT_NAME})
|
||||
endif()
|
||||
|
||||
@@ -750,76 +491,60 @@ endif()
|
||||
ament_add_gtest(test_wait_set test_wait_set.cpp
|
||||
APPEND_LIBRARY_DIRS "${append_library_dirs}")
|
||||
if(TARGET test_wait_set)
|
||||
ament_target_dependencies(test_wait_set "test_msgs")
|
||||
target_link_libraries(test_wait_set ${PROJECT_NAME})
|
||||
target_link_libraries(test_wait_set ${PROJECT_NAME} ${rcl_interfaces_TARGETS} ${test_msgs_TARGETS})
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_subscription_topic_statistics topic_statistics/test_subscription_topic_statistics.cpp
|
||||
APPEND_LIBRARY_DIRS "${append_library_dirs}"
|
||||
)
|
||||
if(TARGET test_subscription_topic_statistics)
|
||||
ament_target_dependencies(test_subscription_topic_statistics
|
||||
"builtin_interfaces"
|
||||
"libstatistics_collector"
|
||||
"rcl_interfaces"
|
||||
"rcutils"
|
||||
"rmw"
|
||||
"rosidl_runtime_cpp"
|
||||
"rosidl_typesupport_cpp"
|
||||
"statistics_msgs"
|
||||
"test_msgs")
|
||||
target_link_libraries(test_subscription_topic_statistics
|
||||
${PROJECT_NAME}
|
||||
${cpp_typesupport_target})
|
||||
libstatistics_collector::libstatistics_collector
|
||||
${statistics_msgs_TARGETS}
|
||||
${test_msgs_TARGETS}
|
||||
)
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_subscription_options test_subscription_options.cpp)
|
||||
if(TARGET test_subscription_options)
|
||||
ament_target_dependencies(test_subscription_options "rcl")
|
||||
target_link_libraries(test_subscription_options ${PROJECT_NAME})
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_dynamic_storage wait_set_policies/test_dynamic_storage.cpp)
|
||||
if(TARGET test_dynamic_storage)
|
||||
ament_target_dependencies(test_dynamic_storage "rcl" "test_msgs")
|
||||
target_link_libraries(test_dynamic_storage ${PROJECT_NAME})
|
||||
target_link_libraries(test_dynamic_storage ${PROJECT_NAME} ${test_msgs_TARGETS})
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_storage_policy_common wait_set_policies/test_storage_policy_common.cpp)
|
||||
if(TARGET test_storage_policy_common)
|
||||
ament_target_dependencies(test_storage_policy_common "rcl" "test_msgs")
|
||||
target_link_libraries(test_storage_policy_common ${PROJECT_NAME} mimick)
|
||||
target_link_libraries(test_storage_policy_common ${PROJECT_NAME} mimick ${test_msgs_TARGETS})
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_static_storage wait_set_policies/test_static_storage.cpp)
|
||||
if(TARGET test_static_storage)
|
||||
ament_target_dependencies(test_static_storage "rcl" "test_msgs")
|
||||
target_link_libraries(test_static_storage ${PROJECT_NAME})
|
||||
target_link_libraries(test_static_storage ${PROJECT_NAME} ${test_msgs_TARGETS})
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_thread_safe_synchronization wait_set_policies/test_thread_safe_synchronization.cpp)
|
||||
if(TARGET test_thread_safe_synchronization)
|
||||
ament_target_dependencies(test_thread_safe_synchronization "rcl" "test_msgs")
|
||||
target_link_libraries(test_thread_safe_synchronization ${PROJECT_NAME})
|
||||
target_link_libraries(test_thread_safe_synchronization ${PROJECT_NAME} ${test_msgs_TARGETS})
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_rosout_qos test_rosout_qos.cpp)
|
||||
if(TARGET test_rosout_qos)
|
||||
ament_target_dependencies(test_rosout_qos "rcl")
|
||||
target_link_libraries(test_rosout_qos ${PROJECT_NAME})
|
||||
target_link_libraries(test_rosout_qos ${PROJECT_NAME} rcl::rcl rmw::rmw)
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_rosout_subscription test_rosout_subscription.cpp)
|
||||
if(TARGET test_rosout_subscription)
|
||||
ament_target_dependencies(test_rosout_subscription "rcl")
|
||||
target_link_libraries(test_rosout_subscription ${PROJECT_NAME})
|
||||
target_link_libraries(test_rosout_subscription ${PROJECT_NAME} ${rcl_interfaces_TARGETS})
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_executor test_executor.cpp
|
||||
APPEND_LIBRARY_DIRS "${append_library_dirs}"
|
||||
TIMEOUT 120)
|
||||
if(TARGET test_executor)
|
||||
ament_target_dependencies(test_executor "rcl")
|
||||
target_link_libraries(test_executor ${PROJECT_NAME} mimick)
|
||||
endif()
|
||||
|
||||
@@ -836,12 +561,7 @@ function(test_subscription_content_filter_for_rmw_implementation)
|
||||
TIMEOUT 120
|
||||
)
|
||||
if(TARGET test_subscription_content_filter${target_suffix})
|
||||
target_link_libraries(test_subscription_content_filter${target_suffix} ${PROJECT_NAME} mimick)
|
||||
ament_target_dependencies(test_subscription_content_filter${target_suffix}
|
||||
"rcpputils"
|
||||
"rosidl_typesupport_cpp"
|
||||
"test_msgs"
|
||||
)
|
||||
target_link_libraries(test_subscription_content_filter${target_suffix} ${PROJECT_NAME} mimick ${test_msgs_TARGETS})
|
||||
endif()
|
||||
endfunction()
|
||||
call_for_each_rmw_implementation(test_subscription_content_filter_for_rmw_implementation)
|
||||
|
||||
@@ -644,6 +644,7 @@ TYPED_TEST(TestExecutors, testRaceConditionAddNode)
|
||||
break;
|
||||
}
|
||||
total += k * (i + 42);
|
||||
(void)total;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -129,6 +129,9 @@ TEST_F(TestNodeGraph, construct_from_node)
|
||||
|
||||
EXPECT_EQ(0u, node_graph()->count_publishers("not_a_topic"));
|
||||
EXPECT_EQ(0u, node_graph()->count_subscribers("not_a_topic"));
|
||||
EXPECT_EQ(0u, node_graph()->count_clients("not_a_service"));
|
||||
EXPECT_EQ(0u, node_graph()->count_services("not_a_service"));
|
||||
|
||||
EXPECT_NE(nullptr, node_graph()->get_graph_guard_condition());
|
||||
|
||||
// get_graph_event is non-const
|
||||
@@ -534,6 +537,22 @@ TEST_F(TestNodeGraph, count_subscribers_rcl_error)
|
||||
std::runtime_error("could not count subscribers: error not set"));
|
||||
}
|
||||
|
||||
TEST_F(TestNodeGraph, count_clients_rcl_error)
|
||||
{
|
||||
auto mock = mocking_utils::patch_and_return("lib:rclcpp", rcl_count_clients, RCL_RET_ERROR);
|
||||
RCLCPP_EXPECT_THROW_EQ(
|
||||
node_graph()->count_clients("service"),
|
||||
std::runtime_error("could not count clients: error not set"));
|
||||
}
|
||||
|
||||
TEST_F(TestNodeGraph, count_services_rcl_error)
|
||||
{
|
||||
auto mock = mocking_utils::patch_and_return("lib:rclcpp", rcl_count_services, RCL_RET_ERROR);
|
||||
RCLCPP_EXPECT_THROW_EQ(
|
||||
node_graph()->count_services("service"),
|
||||
std::runtime_error("could not count services: error not set"));
|
||||
}
|
||||
|
||||
TEST_F(TestNodeGraph, notify_shutdown)
|
||||
{
|
||||
EXPECT_NO_THROW(node()->get_node_graph_interface()->notify_shutdown());
|
||||
|
||||
@@ -95,15 +95,15 @@ TEST_F(TestNodeParameters, list_parameters)
|
||||
std::find(list_result2.names.begin(), list_result2.names.end(), parameter_name),
|
||||
list_result2.names.end());
|
||||
|
||||
// Check prefixes
|
||||
// Check prefixes and the depth relative to the given prefixes
|
||||
const std::string parameter_name2 = "prefix.new_parameter";
|
||||
const rclcpp::ParameterValue value2(true);
|
||||
const rcl_interfaces::msg::ParameterDescriptor descriptor2;
|
||||
const auto added_parameter_value2 =
|
||||
node_parameters->declare_parameter(parameter_name2, value2, descriptor2, false);
|
||||
EXPECT_EQ(value.get<bool>(), added_parameter_value.get<bool>());
|
||||
EXPECT_EQ(value2.get<bool>(), added_parameter_value2.get<bool>());
|
||||
prefixes = {"prefix"};
|
||||
auto list_result3 = node_parameters->list_parameters(prefixes, 2u);
|
||||
auto list_result3 = node_parameters->list_parameters(prefixes, 1u);
|
||||
EXPECT_EQ(1u, list_result3.names.size());
|
||||
EXPECT_NE(
|
||||
std::find(list_result3.names.begin(), list_result3.names.end(), parameter_name2),
|
||||
@@ -116,6 +116,13 @@ TEST_F(TestNodeParameters, list_parameters)
|
||||
EXPECT_NE(
|
||||
std::find(list_result4.names.begin(), list_result4.names.end(), parameter_name),
|
||||
list_result4.names.end());
|
||||
|
||||
// Return all parameters when the depth = 0
|
||||
auto list_result5 = node_parameters->list_parameters(prefixes, 0u);
|
||||
EXPECT_EQ(1u, list_result5.names.size());
|
||||
EXPECT_NE(
|
||||
std::find(list_result5.names.begin(), list_result5.names.end(), parameter_name),
|
||||
list_result5.names.end());
|
||||
}
|
||||
|
||||
TEST_F(TestNodeParameters, parameter_overrides)
|
||||
|
||||
@@ -43,10 +43,9 @@ TEST_F(TestNodeTypeDescriptions, disabled_no_service)
|
||||
node_options.append_parameter_override("start_type_description_service", false);
|
||||
rclcpp::Node node{"node", "ns", node_options};
|
||||
|
||||
rcl_node_t * rcl_node = node.get_node_base_interface()->get_rcl_node_handle();
|
||||
rcl_service_t * srv = nullptr;
|
||||
rcl_ret_t ret = rcl_node_get_type_description_service(rcl_node, &srv);
|
||||
ASSERT_EQ(RCL_RET_NOT_INIT, ret);
|
||||
auto services = node.get_node_graph_interface()->get_service_names_and_types_by_node(
|
||||
"node", "/ns");
|
||||
EXPECT_TRUE(services.find("/ns/node/get_type_description") == services.end());
|
||||
}
|
||||
|
||||
TEST_F(TestNodeTypeDescriptions, enabled_creates_service)
|
||||
@@ -55,9 +54,8 @@ TEST_F(TestNodeTypeDescriptions, enabled_creates_service)
|
||||
node_options.append_parameter_override("start_type_description_service", true);
|
||||
rclcpp::Node node{"node", "ns", node_options};
|
||||
|
||||
rcl_node_t * rcl_node = node.get_node_base_interface()->get_rcl_node_handle();
|
||||
rcl_service_t * srv = nullptr;
|
||||
rcl_ret_t ret = rcl_node_get_type_description_service(rcl_node, &srv);
|
||||
ASSERT_EQ(RCL_RET_OK, ret);
|
||||
ASSERT_NE(nullptr, srv);
|
||||
auto services = node.get_node_graph_interface()->get_service_names_and_types_by_node(
|
||||
"node", "/ns");
|
||||
|
||||
EXPECT_TRUE(services.find("/ns/node/get_type_description") != services.end());
|
||||
}
|
||||
|
||||
@@ -56,18 +56,28 @@ TEST_F(TestMessagePoolMemoryStrategy, borrow_too_many) {
|
||||
// Size is 1, borrowing second time should fail
|
||||
RCLCPP_EXPECT_THROW_EQ(
|
||||
message_memory_strategy_->borrow_message(),
|
||||
std::runtime_error("Tried to access message that was still in use! Abort."));
|
||||
std::runtime_error("No more free slots in the pool"));
|
||||
EXPECT_NO_THROW(message_memory_strategy_->return_message(message));
|
||||
}
|
||||
|
||||
TEST_F(TestMessagePoolMemoryStrategy, return_unrecognized) {
|
||||
auto message = message_memory_strategy_->borrow_message();
|
||||
ASSERT_NE(nullptr, message);
|
||||
TEST_F(TestMessagePoolMemoryStrategy, borrow_hold_reference) {
|
||||
{
|
||||
auto message = message_memory_strategy_->borrow_message();
|
||||
ASSERT_NE(nullptr, message);
|
||||
|
||||
auto unrecognized = std::make_shared<test_msgs::msg::Empty>();
|
||||
// Unrecognized does not belong to pool
|
||||
RCLCPP_EXPECT_THROW_EQ(
|
||||
message_memory_strategy_->return_message(unrecognized),
|
||||
std::runtime_error("Unrecognized message ptr in return_message."));
|
||||
EXPECT_NO_THROW(message_memory_strategy_->return_message(message));
|
||||
// Return it.
|
||||
EXPECT_NO_THROW(message_memory_strategy_->return_message(message));
|
||||
|
||||
// But we are still holding the reference, so we expect that there is still no room in the pool.
|
||||
RCLCPP_EXPECT_THROW_EQ(
|
||||
message_memory_strategy_->borrow_message(),
|
||||
std::runtime_error("No more free slots in the pool"));
|
||||
}
|
||||
|
||||
// Now that we've dropped the reference (left the scope), we expect to be able to borrow again.
|
||||
|
||||
auto message2 = message_memory_strategy_->borrow_message();
|
||||
ASSERT_NE(nullptr, message2);
|
||||
|
||||
EXPECT_NO_THROW(message_memory_strategy_->return_message(message2));
|
||||
}
|
||||
|
||||
@@ -214,3 +214,25 @@ TEST(TestContext, check_on_shutdown_callback_order_after_del) {
|
||||
|
||||
EXPECT_TRUE(result[0] == 1 && result[1] == 3 && result[2] == 4 && result[3] == 0);
|
||||
}
|
||||
|
||||
// This test checks that contexts will be properly destroyed when leaving a scope, after a
|
||||
// guard condition has been created.
|
||||
TEST(TestContext, check_context_destroyed) {
|
||||
rclcpp::Context::SharedPtr ctx;
|
||||
{
|
||||
ctx = std::make_shared<rclcpp::Context>();
|
||||
ctx->init(0, nullptr);
|
||||
|
||||
auto group = std::make_shared<rclcpp::CallbackGroup>(
|
||||
rclcpp::CallbackGroupType::MutuallyExclusive,
|
||||
ctx->weak_from_this(),
|
||||
false);
|
||||
|
||||
rclcpp::GuardCondition::SharedPtr gc = group->get_notify_guard_condition();
|
||||
ASSERT_NE(gc, nullptr);
|
||||
|
||||
ASSERT_EQ(ctx.use_count(), 1u);
|
||||
}
|
||||
|
||||
ASSERT_EQ(ctx.use_count(), 1u);
|
||||
}
|
||||
|
||||
88
rclcpp/test/rclcpp/test_copy_all_parameter_values.cpp
Normal file
88
rclcpp/test/rclcpp/test_copy_all_parameter_values.cpp
Normal file
@@ -0,0 +1,88 @@
|
||||
// Copyright 2023 Open Navigation LLC
|
||||
//
|
||||
// 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 "rclcpp/copy_all_parameter_values.hpp"
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
|
||||
class TestNode : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
rclcpp::init(0, nullptr);
|
||||
}
|
||||
|
||||
static void TearDownTestCase()
|
||||
{
|
||||
rclcpp::shutdown();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(TestNode, TestParamCopying)
|
||||
{
|
||||
auto node1 = std::make_shared<rclcpp::Node>("test_node1");
|
||||
auto node2 = std::make_shared<rclcpp::Node>("test_node2");
|
||||
|
||||
// Tests for (1) multiple types, (2) recursion, (3) overriding values
|
||||
node1->declare_parameter("Foo1", rclcpp::ParameterValue(std::string(("bar1"))));
|
||||
node1->declare_parameter("Foo2", rclcpp::ParameterValue(0.123));
|
||||
node1->declare_parameter("Foo", rclcpp::ParameterValue(std::string(("bar"))));
|
||||
node1->declare_parameter("Foo.bar", rclcpp::ParameterValue(std::string(("steve"))));
|
||||
node2->declare_parameter("Foo", rclcpp::ParameterValue(std::string(("barz2"))));
|
||||
|
||||
// Show Node2 is empty of Node1's parameters, but contains its own
|
||||
EXPECT_FALSE(node2->has_parameter("Foo1"));
|
||||
EXPECT_FALSE(node2->has_parameter("Foo2"));
|
||||
EXPECT_FALSE(node2->has_parameter("Foo.bar"));
|
||||
EXPECT_TRUE(node2->has_parameter("Foo"));
|
||||
EXPECT_EQ(node2->get_parameter("Foo").as_string(), std::string("barz2"));
|
||||
|
||||
bool override = false;
|
||||
rclcpp::copy_all_parameter_values(node1, node2, override);
|
||||
|
||||
// Test new parameters exist, of expected value, and original param is not overridden
|
||||
EXPECT_TRUE(node2->has_parameter("Foo1"));
|
||||
EXPECT_EQ(node2->get_parameter("Foo1").as_string(), std::string("bar1"));
|
||||
EXPECT_TRUE(node2->has_parameter("Foo2"));
|
||||
EXPECT_EQ(node2->get_parameter("Foo2").as_double(), 0.123);
|
||||
EXPECT_TRUE(node2->has_parameter("Foo.bar"));
|
||||
EXPECT_EQ(node2->get_parameter("Foo.bar").as_string(), std::string("steve"));
|
||||
EXPECT_TRUE(node2->has_parameter("Foo"));
|
||||
EXPECT_EQ(node2->get_parameter("Foo").as_string(), std::string("barz2"));
|
||||
|
||||
// Test if parameter overrides are permissible that Node2's value is overridden
|
||||
override = true;
|
||||
rclcpp::copy_all_parameter_values(node1, node2, override);
|
||||
EXPECT_EQ(node2->get_parameter("Foo").as_string(), std::string("bar"));
|
||||
}
|
||||
|
||||
TEST_F(TestNode, TestParamCopyingExceptions)
|
||||
{
|
||||
auto node1 = std::make_shared<rclcpp::Node>("test_node1");
|
||||
auto node2 = std::make_shared<rclcpp::Node>("test_node2");
|
||||
|
||||
// Tests for Parameter value conflicts handled
|
||||
node1->declare_parameter("Foo", rclcpp::ParameterValue(std::string(("bar"))));
|
||||
node2->declare_parameter("Foo", rclcpp::ParameterValue(0.123));
|
||||
|
||||
bool override = true;
|
||||
EXPECT_NO_THROW(
|
||||
rclcpp::copy_all_parameter_values(node1, node2, override));
|
||||
|
||||
// Tests for Parameter read-only handled
|
||||
node1->declare_parameter("Foo1", rclcpp::ParameterValue(std::string(("bar"))));
|
||||
node2->declare_parameter("Foo1", rclcpp::ParameterValue(0.123));
|
||||
EXPECT_NO_THROW(rclcpp::copy_all_parameter_values(node1, node2, override));
|
||||
}
|
||||
@@ -69,7 +69,7 @@ public:
|
||||
size_t counter = 0;
|
||||
auto subscription = node_->create_generic_subscription(
|
||||
topic_name, type, rclcpp::QoS(1),
|
||||
[&counter, &messages, this](std::shared_ptr<rclcpp::SerializedMessage> message) {
|
||||
[&counter, &messages, this](const std::shared_ptr<const rclcpp::SerializedMessage> message) {
|
||||
T2 deserialized_message;
|
||||
rclcpp::Serialization<T2> serializer;
|
||||
serializer.deserialize_message(message.get(), &deserialized_message);
|
||||
@@ -236,7 +236,7 @@ TEST_F(RclcppGenericNodeFixture, generic_subscription_uses_qos)
|
||||
auto publisher = node_->create_publisher<test_msgs::msg::Strings>(topic_name, qos);
|
||||
auto subscription = node_->create_generic_subscription(
|
||||
topic_name, topic_type, qos,
|
||||
[](std::shared_ptr<rclcpp::SerializedMessage>/* message */) {});
|
||||
[](std::shared_ptr<const rclcpp::SerializedMessage>/* message */) {});
|
||||
auto connected = [publisher, subscription]() -> bool {
|
||||
return publisher->get_subscription_count() && subscription->get_publisher_count();
|
||||
};
|
||||
@@ -263,3 +263,49 @@ TEST_F(RclcppGenericNodeFixture, generic_publisher_uses_qos)
|
||||
// It normally takes < 20ms, 5s chosen as "a very long time"
|
||||
ASSERT_TRUE(wait_for(connected, 5s));
|
||||
}
|
||||
|
||||
TEST_F(RclcppGenericNodeFixture, generic_subscription_different_callbacks)
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
std::string topic_name = "string_topic";
|
||||
std::string topic_type = "test_msgs/msg/Strings";
|
||||
rclcpp::QoS qos = rclcpp::QoS(1);
|
||||
|
||||
auto publisher = node_->create_publisher<test_msgs::msg::Strings>(topic_name, qos);
|
||||
|
||||
// Test shared_ptr for const messages
|
||||
{
|
||||
auto subscription = node_->create_generic_subscription(
|
||||
topic_name, topic_type, qos,
|
||||
[](const std::shared_ptr<const rclcpp::SerializedMessage>/* message */) {});
|
||||
auto connected = [publisher, subscription]() -> bool {
|
||||
return publisher->get_subscription_count() && subscription->get_publisher_count();
|
||||
};
|
||||
// It normally takes < 20ms, 5s chosen as "a very long time"
|
||||
ASSERT_TRUE(wait_for(connected, 5s));
|
||||
}
|
||||
|
||||
// Test unique_ptr
|
||||
{
|
||||
auto subscription = node_->create_generic_subscription(
|
||||
topic_name, topic_type, qos,
|
||||
[](std::unique_ptr<rclcpp::SerializedMessage>/* message */) {});
|
||||
auto connected = [publisher, subscription]() -> bool {
|
||||
return publisher->get_subscription_count() && subscription->get_publisher_count();
|
||||
};
|
||||
// It normally takes < 20ms, 5s chosen as "a very long time"
|
||||
ASSERT_TRUE(wait_for(connected, 5s));
|
||||
}
|
||||
|
||||
// Test message callback
|
||||
{
|
||||
auto subscription = node_->create_generic_subscription(
|
||||
topic_name, topic_type, qos,
|
||||
[](rclcpp::SerializedMessage /* message */) {});
|
||||
auto connected = [publisher, subscription]() -> bool {
|
||||
return publisher->get_subscription_count() && subscription->get_publisher_count();
|
||||
};
|
||||
// It normally takes < 20ms, 5s chosen as "a very long time"
|
||||
ASSERT_TRUE(wait_for(connected, 5s));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,16 +66,6 @@ TEST_F(TestGuardCondition, construction_and_destruction) {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Testing context accessor.
|
||||
*/
|
||||
TEST_F(TestGuardCondition, get_context) {
|
||||
{
|
||||
auto gc = std::make_shared<rclcpp::GuardCondition>();
|
||||
gc->get_context();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Testing rcl guard condition accessor.
|
||||
*/
|
||||
|
||||
@@ -190,6 +190,33 @@ TEST(TestIntraProcessBuffer, shared_buffer_consume) {
|
||||
EXPECT_EQ(1L, original_shared_msg.use_count());
|
||||
EXPECT_EQ(*original_shared_msg, *popped_unique_msg);
|
||||
EXPECT_NE(original_message_pointer, popped_message_pointer);
|
||||
|
||||
original_shared_msg = std::make_shared<char>('c');
|
||||
original_message_pointer = reinterpret_cast<std::uintptr_t>(original_shared_msg.get());
|
||||
auto original_shared_msg_2 = std::make_shared<char>('d');
|
||||
auto original_message_pointer_2 = reinterpret_cast<std::uintptr_t>(original_shared_msg_2.get());
|
||||
intra_process_buffer.add_shared(original_shared_msg);
|
||||
intra_process_buffer.add_shared(original_shared_msg_2);
|
||||
|
||||
auto shared_data_vec = intra_process_buffer.get_all_data_shared();
|
||||
EXPECT_EQ(2L, shared_data_vec.size());
|
||||
EXPECT_EQ(3L, original_shared_msg.use_count());
|
||||
EXPECT_EQ(original_shared_msg.use_count(), shared_data_vec[0].use_count());
|
||||
EXPECT_EQ(*original_shared_msg, *shared_data_vec[0]);
|
||||
EXPECT_EQ(original_message_pointer, reinterpret_cast<std::uintptr_t>(shared_data_vec[0].get()));
|
||||
EXPECT_EQ(3L, original_shared_msg_2.use_count());
|
||||
EXPECT_EQ(original_shared_msg_2.use_count(), shared_data_vec[1].use_count());
|
||||
EXPECT_EQ(*original_shared_msg_2, *shared_data_vec[1]);
|
||||
EXPECT_EQ(original_message_pointer_2, reinterpret_cast<std::uintptr_t>(shared_data_vec[1].get()));
|
||||
|
||||
auto unique_data_vec = intra_process_buffer.get_all_data_unique();
|
||||
EXPECT_EQ(2L, unique_data_vec.size());
|
||||
EXPECT_EQ(3L, original_shared_msg.use_count());
|
||||
EXPECT_EQ(*original_shared_msg, *unique_data_vec[0]);
|
||||
EXPECT_NE(original_message_pointer, reinterpret_cast<std::uintptr_t>(unique_data_vec[0].get()));
|
||||
EXPECT_EQ(3L, original_shared_msg_2.use_count());
|
||||
EXPECT_EQ(*original_shared_msg_2, *unique_data_vec[1]);
|
||||
EXPECT_NE(original_message_pointer_2, reinterpret_cast<std::uintptr_t>(unique_data_vec[1].get()));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -237,6 +264,33 @@ TEST(TestIntraProcessBuffer, unique_buffer_consume) {
|
||||
|
||||
EXPECT_EQ(original_value, *popped_unique_msg);
|
||||
EXPECT_EQ(original_message_pointer, popped_message_pointer);
|
||||
|
||||
original_unique_msg = std::make_unique<char>('c');
|
||||
original_message_pointer = reinterpret_cast<std::uintptr_t>(original_unique_msg.get());
|
||||
original_value = *original_unique_msg;
|
||||
auto original_unique_msg_2 = std::make_unique<char>('d');
|
||||
auto original_message_pointer_2 = reinterpret_cast<std::uintptr_t>(original_unique_msg.get());
|
||||
auto original_value_2 = *original_unique_msg_2;
|
||||
intra_process_buffer.add_unique(std::move(original_unique_msg));
|
||||
intra_process_buffer.add_unique(std::move(original_unique_msg_2));
|
||||
|
||||
auto shared_data_vec = intra_process_buffer.get_all_data_shared();
|
||||
EXPECT_EQ(2L, shared_data_vec.size());
|
||||
EXPECT_EQ(1L, shared_data_vec[0].use_count());
|
||||
EXPECT_EQ(original_value, *shared_data_vec[0]);
|
||||
EXPECT_NE(original_message_pointer, reinterpret_cast<std::uintptr_t>(shared_data_vec[0].get()));
|
||||
EXPECT_EQ(1L, shared_data_vec[1].use_count());
|
||||
EXPECT_EQ(original_value_2, *shared_data_vec[1]);
|
||||
EXPECT_NE(original_message_pointer_2, reinterpret_cast<std::uintptr_t>(shared_data_vec[1].get()));
|
||||
|
||||
auto unique_data_vec = intra_process_buffer.get_all_data_unique();
|
||||
EXPECT_EQ(2L, unique_data_vec.size());
|
||||
EXPECT_EQ(1L, shared_data_vec[0].use_count());
|
||||
EXPECT_EQ(original_value, *unique_data_vec[0]);
|
||||
EXPECT_NE(original_message_pointer, reinterpret_cast<std::uintptr_t>(unique_data_vec[0].get()));
|
||||
EXPECT_EQ(1L, shared_data_vec[1].use_count());
|
||||
EXPECT_EQ(original_value_2, *unique_data_vec[1]);
|
||||
EXPECT_NE(original_message_pointer_2, reinterpret_cast<std::uintptr_t>(unique_data_vec[1].get()));
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -31,6 +31,111 @@
|
||||
// NOLINTNEXTLINE(build/include_order)
|
||||
#include <rcl_interfaces/msg/log.hpp>
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace buffers
|
||||
{
|
||||
namespace mock
|
||||
{
|
||||
|
||||
class IntraProcessBufferBase
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_ALIASES_ONLY(IntraProcessBufferBase)
|
||||
|
||||
virtual ~IntraProcessBufferBase() {}
|
||||
};
|
||||
|
||||
} // namespace mock
|
||||
} // namespace buffers
|
||||
} // namespace experimental
|
||||
} // namespace rclcpp
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace buffers
|
||||
{
|
||||
namespace mock
|
||||
{
|
||||
template<
|
||||
typename MessageT,
|
||||
typename Alloc = std::allocator<MessageT>,
|
||||
typename MessageDeleter = std::default_delete<MessageT>>
|
||||
class IntraProcessBuffer : public IntraProcessBufferBase
|
||||
{
|
||||
public:
|
||||
using ConstMessageSharedPtr = std::shared_ptr<const MessageT>;
|
||||
using MessageUniquePtr = std::unique_ptr<MessageT>;
|
||||
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(IntraProcessBuffer)
|
||||
|
||||
IntraProcessBuffer()
|
||||
{}
|
||||
|
||||
void add(ConstMessageSharedPtr msg)
|
||||
{
|
||||
message_ptr = reinterpret_cast<std::uintptr_t>(msg.get());
|
||||
shared_msg = msg;
|
||||
++num_msgs;
|
||||
}
|
||||
|
||||
void add(MessageUniquePtr msg)
|
||||
{
|
||||
message_ptr = reinterpret_cast<std::uintptr_t>(msg.get());
|
||||
unique_msg = std::move(msg);
|
||||
++num_msgs;
|
||||
}
|
||||
|
||||
void pop(std::uintptr_t & msg_ptr)
|
||||
{
|
||||
msg_ptr = message_ptr;
|
||||
message_ptr = 0;
|
||||
--num_msgs;
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
return num_msgs;
|
||||
}
|
||||
|
||||
std::vector<ConstMessageSharedPtr> get_all_data_shared()
|
||||
{
|
||||
if (shared_msg) {
|
||||
return {shared_msg};
|
||||
} else if (unique_msg) {
|
||||
return {std::make_shared<const MessageT>(*unique_msg)};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<MessageUniquePtr> get_all_data_unique()
|
||||
{
|
||||
std::vector<MessageUniquePtr> result;
|
||||
if (shared_msg) {
|
||||
result.push_back(std::make_unique<MessageT>(*shared_msg));
|
||||
} else if (unique_msg) {
|
||||
result.push_back(std::make_unique<MessageT>(*unique_msg));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// need to store the messages somewhere otherwise the memory address will be reused
|
||||
ConstMessageSharedPtr shared_msg;
|
||||
MessageUniquePtr unique_msg;
|
||||
|
||||
std::uintptr_t message_ptr;
|
||||
// count add and pop
|
||||
size_t num_msgs = 0u;
|
||||
};
|
||||
|
||||
} // namespace mock
|
||||
} // namespace buffers
|
||||
} // namespace experimental
|
||||
} // namespace rclcpp
|
||||
namespace rclcpp
|
||||
{
|
||||
// forward declaration
|
||||
@@ -80,6 +185,12 @@ public:
|
||||
return qos_profile;
|
||||
}
|
||||
|
||||
bool
|
||||
is_durability_transient_local() const
|
||||
{
|
||||
return qos_profile.durability() == rclcpp::DurabilityPolicy::TransientLocal;
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(const rmw_gid_t & gid) const
|
||||
{
|
||||
@@ -117,6 +228,9 @@ public:
|
||||
{
|
||||
auto allocator = std::make_shared<Alloc>();
|
||||
message_allocator_ = std::make_shared<MessageAlloc>(*allocator.get());
|
||||
if (qos.durability() == rclcpp::DurabilityPolicy::TransientLocal) {
|
||||
buffer = std::make_shared<rclcpp::experimental::buffers::mock::IntraProcessBuffer<T>>();
|
||||
}
|
||||
}
|
||||
|
||||
// The following functions use the IntraProcessManager
|
||||
@@ -124,75 +238,12 @@ public:
|
||||
void publish(MessageUniquePtr msg);
|
||||
|
||||
std::shared_ptr<MessageAlloc> message_allocator_;
|
||||
typename rclcpp::experimental::buffers::mock::IntraProcessBuffer<T>::SharedPtr buffer{nullptr};
|
||||
};
|
||||
|
||||
} // namespace mock
|
||||
} // namespace rclcpp
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace buffers
|
||||
{
|
||||
namespace mock
|
||||
{
|
||||
template<
|
||||
typename MessageT,
|
||||
typename Alloc = std::allocator<void>,
|
||||
typename MessageDeleter = std::default_delete<MessageT>>
|
||||
class IntraProcessBuffer
|
||||
{
|
||||
public:
|
||||
using ConstMessageSharedPtr = std::shared_ptr<const MessageT>;
|
||||
using MessageUniquePtr = std::unique_ptr<MessageT>;
|
||||
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(IntraProcessBuffer)
|
||||
|
||||
IntraProcessBuffer()
|
||||
{}
|
||||
|
||||
void add(ConstMessageSharedPtr msg)
|
||||
{
|
||||
message_ptr = reinterpret_cast<std::uintptr_t>(msg.get());
|
||||
shared_msg = msg;
|
||||
++num_msgs;
|
||||
}
|
||||
|
||||
void add(MessageUniquePtr msg)
|
||||
{
|
||||
message_ptr = reinterpret_cast<std::uintptr_t>(msg.get());
|
||||
unique_msg = std::move(msg);
|
||||
++num_msgs;
|
||||
}
|
||||
|
||||
void pop(std::uintptr_t & msg_ptr)
|
||||
{
|
||||
msg_ptr = message_ptr;
|
||||
message_ptr = 0;
|
||||
--num_msgs;
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
return num_msgs;
|
||||
}
|
||||
|
||||
// need to store the messages somewhere otherwise the memory address will be reused
|
||||
ConstMessageSharedPtr shared_msg;
|
||||
MessageUniquePtr unique_msg;
|
||||
|
||||
std::uintptr_t message_ptr;
|
||||
// count add and pop
|
||||
size_t num_msgs = 0u;
|
||||
};
|
||||
|
||||
} // namespace mock
|
||||
} // namespace buffers
|
||||
} // namespace experimental
|
||||
} // namespace rclcpp
|
||||
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace experimental
|
||||
@@ -231,6 +282,12 @@ public:
|
||||
return topic_name.c_str();
|
||||
}
|
||||
|
||||
bool
|
||||
is_durability_transient_local() const
|
||||
{
|
||||
return qos_profile.durability() == rclcpp::DurabilityPolicy::TransientLocal;
|
||||
}
|
||||
|
||||
virtual
|
||||
size_t
|
||||
available_capacity() const = 0;
|
||||
@@ -289,7 +346,7 @@ public:
|
||||
}
|
||||
|
||||
bool
|
||||
use_take_shared_method() const
|
||||
use_take_shared_method() const override
|
||||
{
|
||||
return take_shared_method;
|
||||
}
|
||||
@@ -331,12 +388,14 @@ public:
|
||||
// Prevent the header files of the mocked classes to be included
|
||||
#define RCLCPP__PUBLISHER_HPP_
|
||||
#define RCLCPP__PUBLISHER_BASE_HPP_
|
||||
#define RCLCPP__EXPERIMENTAL__BUFFERS__INTRA_PROCESS_BUFFER_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 IntraProcessBufferBase mock::IntraProcessBufferBase
|
||||
#define IntraProcessBuffer mock::IntraProcessBuffer
|
||||
#define SubscriptionIntraProcessBase mock::SubscriptionIntraProcessBase
|
||||
#define SubscriptionIntraProcessBuffer mock::SubscriptionIntraProcessBuffer
|
||||
@@ -368,28 +427,36 @@ void Publisher<T, Alloc>::publish(MessageUniquePtr msg)
|
||||
throw std::runtime_error("cannot publish msg which is a null pointer");
|
||||
}
|
||||
|
||||
ipm->template do_intra_process_publish<T, T, Alloc>(
|
||||
intra_process_publisher_id_,
|
||||
std::move(msg),
|
||||
*message_allocator_);
|
||||
if (buffer) {
|
||||
auto shared_msg = ipm->template do_intra_process_publish_and_return_shared<T, T, Alloc>(
|
||||
intra_process_publisher_id_,
|
||||
std::move(msg),
|
||||
*message_allocator_);
|
||||
buffer->add(shared_msg);
|
||||
} else {
|
||||
ipm->template do_intra_process_publish<T, T, Alloc>(
|
||||
intra_process_publisher_id_,
|
||||
std::move(msg),
|
||||
*message_allocator_);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mock
|
||||
} // namespace rclcpp
|
||||
|
||||
/*
|
||||
This tests how the class connects and disconnects publishers and subscriptions:
|
||||
- Creates 2 publishers on different topics and a subscription to one of them.
|
||||
Add everything to the intra-process manager.
|
||||
- All the entities are expected to have different ids.
|
||||
- Check the subscriptions count for each publisher.
|
||||
- One of the publishers is expected to have 1 subscription, while the other 0.
|
||||
- Check the subscription count for a non existing publisher id, should return 0.
|
||||
- Add a new publisher and a new subscription both with reliable QoS.
|
||||
- The subscriptions count of the previous publisher is expected to remain unchanged,
|
||||
while the new publisher is expected to have 2 subscriptions (it's compatible with both QoS).
|
||||
- Remove the just added subscriptions.
|
||||
- The count for the last publisher is expected to decrease to 1.
|
||||
* This tests how the class connects and disconnects publishers and subscriptions:
|
||||
* - Creates 2 publishers on different topics and a subscription to one of them.
|
||||
* Add everything to the intra-process manager.
|
||||
* - All the entities are expected to have different ids.
|
||||
* - Check the subscriptions count for each publisher.
|
||||
* - One of the publishers is expected to have 1 subscription, while the other 0.
|
||||
* - Check the subscription count for a non existing publisher id, should return 0.
|
||||
* - Add a new publisher and a new subscription both with reliable QoS.
|
||||
* - The subscriptions count of the previous publisher is expected to remain unchanged,
|
||||
* while the new publisher is expected to have 2 subscriptions (it's compatible with both QoS).
|
||||
* - Remove the just added subscriptions.
|
||||
* - The count for the last publisher is expected to decrease to 1.
|
||||
*/
|
||||
TEST(TestIntraProcessManager, add_pub_sub) {
|
||||
using IntraProcessManagerT = rclcpp::experimental::IntraProcessManager;
|
||||
@@ -408,7 +475,7 @@ TEST(TestIntraProcessManager, add_pub_sub) {
|
||||
|
||||
auto p1_id = ipm->add_publisher(p1);
|
||||
auto p2_id = ipm->add_publisher(p2);
|
||||
auto s1_id = ipm->add_subscription(s1);
|
||||
auto s1_id = ipm->template add_subscription<MessageT>(s1);
|
||||
|
||||
bool unique_ids = p1_id != p2_id && p2_id != s1_id;
|
||||
ASSERT_TRUE(unique_ids);
|
||||
@@ -424,7 +491,7 @@ TEST(TestIntraProcessManager, add_pub_sub) {
|
||||
|
||||
auto s2 = std::make_shared<SubscriptionIntraProcessT>(rclcpp::QoS(10).reliable());
|
||||
|
||||
auto s2_id = ipm->add_subscription(s2);
|
||||
auto s2_id = ipm->template add_subscription<MessageT>(s2);
|
||||
auto p3_id = ipm->add_publisher(p3);
|
||||
|
||||
p1_subs = ipm->get_subscription_count(p1_id);
|
||||
@@ -444,14 +511,14 @@ TEST(TestIntraProcessManager, add_pub_sub) {
|
||||
}
|
||||
|
||||
/*
|
||||
This tests the minimal usage of the class where there is a single subscription per publisher:
|
||||
- Publishes a unique_ptr message with a subscription requesting ownership.
|
||||
- The received message is expected to be the same.
|
||||
- Remove the first subscription from ipm and add a new one.
|
||||
- Publishes a unique_ptr message with a subscription not requesting ownership.
|
||||
- The received message is expected to be the same, the first subscription do not receive it.
|
||||
- Publishes a shared_ptr message with a subscription not requesting ownership.
|
||||
- The received message is expected to be the same.
|
||||
* This tests the minimal usage of the class where there is a single subscription per publisher:
|
||||
* - Publishes a unique_ptr message with a subscription requesting ownership.
|
||||
* - The received message is expected to be the same.
|
||||
* - Remove the first subscription from ipm and add a new one.
|
||||
* - Publishes a unique_ptr message with a subscription not requesting ownership.
|
||||
* - The received message is expected to be the same, the first subscription do not receive it.
|
||||
* - Publishes a shared_ptr message with a subscription not requesting ownership.
|
||||
* - The received message is expected to be the same.
|
||||
*/
|
||||
TEST(TestIntraProcessManager, single_subscription) {
|
||||
using IntraProcessManagerT = rclcpp::experimental::IntraProcessManager;
|
||||
@@ -467,7 +534,7 @@ TEST(TestIntraProcessManager, single_subscription) {
|
||||
|
||||
auto s1 = std::make_shared<SubscriptionIntraProcessT>();
|
||||
s1->take_shared_method = false;
|
||||
auto s1_id = ipm->add_subscription(s1);
|
||||
auto s1_id = ipm->template add_subscription<MessageT>(s1);
|
||||
|
||||
auto unique_msg = std::make_unique<MessageT>();
|
||||
auto original_message_pointer = reinterpret_cast<std::uintptr_t>(unique_msg.get());
|
||||
@@ -478,7 +545,7 @@ TEST(TestIntraProcessManager, single_subscription) {
|
||||
ipm->remove_subscription(s1_id);
|
||||
auto s2 = std::make_shared<SubscriptionIntraProcessT>();
|
||||
s2->take_shared_method = true;
|
||||
auto s2_id = ipm->add_subscription(s2);
|
||||
auto s2_id = ipm->template add_subscription<MessageT>(s2);
|
||||
(void)s2_id;
|
||||
|
||||
unique_msg = std::make_unique<MessageT>();
|
||||
@@ -497,15 +564,15 @@ TEST(TestIntraProcessManager, single_subscription) {
|
||||
}
|
||||
|
||||
/*
|
||||
This tests the usage of the class where there are multiple subscriptions of the same type:
|
||||
- Publishes a unique_ptr message with 2 subscriptions requesting ownership.
|
||||
- One is expected to receive the published message, while the other will receive a copy.
|
||||
- Publishes a unique_ptr message with 2 subscriptions not requesting ownership.
|
||||
- Both received messages are expected to be the same as the published one.
|
||||
- Publishes a shared_ptr message with 2 subscriptions requesting ownership.
|
||||
- Both received messages are expected to be a copy of the published one.
|
||||
- Publishes a shared_ptr message with 2 subscriptions not requesting ownership.
|
||||
- Both received messages are expected to be the same as the published one.
|
||||
* This tests the usage of the class where there are multiple subscriptions of the same type:
|
||||
* - Publishes a unique_ptr message with 2 subscriptions requesting ownership.
|
||||
* - One is expected to receive the published message, while the other will receive a copy.
|
||||
* - Publishes a unique_ptr message with 2 subscriptions not requesting ownership.
|
||||
* - Both received messages are expected to be the same as the published one.
|
||||
* - Publishes a shared_ptr message with 2 subscriptions requesting ownership.
|
||||
* - Both received messages are expected to be a copy of the published one.
|
||||
* - Publishes a shared_ptr message with 2 subscriptions not requesting ownership.
|
||||
* - Both received messages are expected to be the same as the published one.
|
||||
*/
|
||||
TEST(TestIntraProcessManager, multiple_subscriptions_same_type) {
|
||||
using IntraProcessManagerT = rclcpp::experimental::IntraProcessManager;
|
||||
@@ -521,11 +588,11 @@ TEST(TestIntraProcessManager, multiple_subscriptions_same_type) {
|
||||
|
||||
auto s1 = std::make_shared<SubscriptionIntraProcessT>();
|
||||
s1->take_shared_method = false;
|
||||
auto s1_id = ipm->add_subscription(s1);
|
||||
auto s1_id = ipm->template add_subscription<MessageT>(s1);
|
||||
|
||||
auto s2 = std::make_shared<SubscriptionIntraProcessT>();
|
||||
s2->take_shared_method = false;
|
||||
auto s2_id = ipm->add_subscription(s2);
|
||||
auto s2_id = ipm->template add_subscription<MessageT>(s2);
|
||||
|
||||
auto unique_msg = std::make_unique<MessageT>();
|
||||
auto original_message_pointer = reinterpret_cast<std::uintptr_t>(unique_msg.get());
|
||||
@@ -541,11 +608,11 @@ TEST(TestIntraProcessManager, multiple_subscriptions_same_type) {
|
||||
|
||||
auto s3 = std::make_shared<SubscriptionIntraProcessT>();
|
||||
s3->take_shared_method = true;
|
||||
auto s3_id = ipm->add_subscription(s3);
|
||||
auto s3_id = ipm->template add_subscription<MessageT>(s3);
|
||||
|
||||
auto s4 = std::make_shared<SubscriptionIntraProcessT>();
|
||||
s4->take_shared_method = true;
|
||||
auto s4_id = ipm->add_subscription(s4);
|
||||
auto s4_id = ipm->template add_subscription<MessageT>(s4);
|
||||
|
||||
unique_msg = std::make_unique<MessageT>();
|
||||
original_message_pointer = reinterpret_cast<std::uintptr_t>(unique_msg.get());
|
||||
@@ -560,11 +627,11 @@ TEST(TestIntraProcessManager, multiple_subscriptions_same_type) {
|
||||
|
||||
auto s5 = std::make_shared<SubscriptionIntraProcessT>();
|
||||
s5->take_shared_method = false;
|
||||
auto s5_id = ipm->add_subscription(s5);
|
||||
auto s5_id = ipm->template add_subscription<MessageT>(s5);
|
||||
|
||||
auto s6 = std::make_shared<SubscriptionIntraProcessT>();
|
||||
s6->take_shared_method = false;
|
||||
auto s6_id = ipm->add_subscription(s6);
|
||||
auto s6_id = ipm->template add_subscription<MessageT>(s6);
|
||||
|
||||
unique_msg = std::make_unique<MessageT>();
|
||||
original_message_pointer = reinterpret_cast<std::uintptr_t>(unique_msg.get());
|
||||
@@ -580,12 +647,12 @@ TEST(TestIntraProcessManager, multiple_subscriptions_same_type) {
|
||||
|
||||
auto s7 = std::make_shared<SubscriptionIntraProcessT>();
|
||||
s7->take_shared_method = true;
|
||||
auto s7_id = ipm->add_subscription(s7);
|
||||
auto s7_id = ipm->template add_subscription<MessageT>(s7);
|
||||
(void)s7_id;
|
||||
|
||||
auto s8 = std::make_shared<SubscriptionIntraProcessT>();
|
||||
s8->take_shared_method = true;
|
||||
auto s8_id = ipm->add_subscription(s8);
|
||||
auto s8_id = ipm->template add_subscription<MessageT>(s8);
|
||||
(void)s8_id;
|
||||
|
||||
unique_msg = std::make_unique<MessageT>();
|
||||
@@ -598,20 +665,20 @@ TEST(TestIntraProcessManager, multiple_subscriptions_same_type) {
|
||||
}
|
||||
|
||||
/*
|
||||
This tests the usage of the class where there are multiple subscriptions of different types:
|
||||
- Publishes a unique_ptr message with 1 subscription requesting ownership and 1 not.
|
||||
- The one requesting ownership is expected to receive the published message,
|
||||
while the other is expected to receive a copy.
|
||||
- Publishes a unique_ptr message with 2 subscriptions requesting ownership and 1 not.
|
||||
- One of the subscriptions requesting ownership is expected to receive the published message,
|
||||
while both other subscriptions are expected to receive different copies.
|
||||
- Publishes a unique_ptr message with 2 subscriptions requesting ownership and 2 not.
|
||||
- The 2 subscriptions not requesting ownership are expected to both receive the same copy
|
||||
of the message, one of the subscription requesting ownership is expected to receive a
|
||||
different copy, while the last is expected to receive the published message.
|
||||
- Publishes a shared_ptr message with 1 subscription requesting ownership and 1 not.
|
||||
- The subscription requesting ownership is expected to receive a copy of the message, while
|
||||
the other is expected to receive the published message
|
||||
* This tests the usage of the class where there are multiple subscriptions of different types:
|
||||
* - Publishes a unique_ptr message with 1 subscription requesting ownership and 1 not.
|
||||
* - The one requesting ownership is expected to receive the published message,
|
||||
* while the other is expected to receive a copy.
|
||||
* - Publishes a unique_ptr message with 2 subscriptions requesting ownership and 1 not.
|
||||
* - One of the subscriptions requesting ownership is expected to receive the published message,
|
||||
* while both other subscriptions are expected to receive different copies.
|
||||
* - Publishes a unique_ptr message with 2 subscriptions requesting ownership and 2 not.
|
||||
* - The 2 subscriptions not requesting ownership are expected to both receive the same copy
|
||||
* of the message, one of the subscription requesting ownership is expected to receive a
|
||||
* different copy, while the last is expected to receive the published message.
|
||||
* - Publishes a shared_ptr message with 1 subscription requesting ownership and 1 not.
|
||||
* - The subscription requesting ownership is expected to receive a copy of the message, while
|
||||
* the other is expected to receive the published message
|
||||
*/
|
||||
TEST(TestIntraProcessManager, multiple_subscriptions_different_type) {
|
||||
using IntraProcessManagerT = rclcpp::experimental::IntraProcessManager;
|
||||
@@ -627,11 +694,11 @@ TEST(TestIntraProcessManager, multiple_subscriptions_different_type) {
|
||||
|
||||
auto s1 = std::make_shared<SubscriptionIntraProcessT>();
|
||||
s1->take_shared_method = true;
|
||||
auto s1_id = ipm->add_subscription(s1);
|
||||
auto s1_id = ipm->template add_subscription<MessageT>(s1);
|
||||
|
||||
auto s2 = std::make_shared<SubscriptionIntraProcessT>();
|
||||
s2->take_shared_method = false;
|
||||
auto s2_id = ipm->add_subscription(s2);
|
||||
auto s2_id = ipm->template add_subscription<MessageT>(s2);
|
||||
|
||||
auto unique_msg = std::make_unique<MessageT>();
|
||||
auto original_message_pointer = reinterpret_cast<std::uintptr_t>(unique_msg.get());
|
||||
@@ -646,15 +713,15 @@ TEST(TestIntraProcessManager, multiple_subscriptions_different_type) {
|
||||
|
||||
auto s3 = std::make_shared<SubscriptionIntraProcessT>();
|
||||
s3->take_shared_method = false;
|
||||
auto s3_id = ipm->add_subscription(s3);
|
||||
auto s3_id = ipm->template add_subscription<MessageT>(s3);
|
||||
|
||||
auto s4 = std::make_shared<SubscriptionIntraProcessT>();
|
||||
s4->take_shared_method = false;
|
||||
auto s4_id = ipm->add_subscription(s4);
|
||||
auto s4_id = ipm->template add_subscription<MessageT>(s4);
|
||||
|
||||
auto s5 = std::make_shared<SubscriptionIntraProcessT>();
|
||||
s5->take_shared_method = true;
|
||||
auto s5_id = ipm->add_subscription(s5);
|
||||
auto s5_id = ipm->template add_subscription<MessageT>(s5);
|
||||
|
||||
unique_msg = std::make_unique<MessageT>();
|
||||
original_message_pointer = reinterpret_cast<std::uintptr_t>(unique_msg.get());
|
||||
@@ -678,19 +745,19 @@ TEST(TestIntraProcessManager, multiple_subscriptions_different_type) {
|
||||
|
||||
auto s6 = std::make_shared<SubscriptionIntraProcessT>();
|
||||
s6->take_shared_method = true;
|
||||
auto s6_id = ipm->add_subscription(s6);
|
||||
auto s6_id = ipm->template add_subscription<MessageT>(s6);
|
||||
|
||||
auto s7 = std::make_shared<SubscriptionIntraProcessT>();
|
||||
s7->take_shared_method = true;
|
||||
auto s7_id = ipm->add_subscription(s7);
|
||||
auto s7_id = ipm->template add_subscription<MessageT>(s7);
|
||||
|
||||
auto s8 = std::make_shared<SubscriptionIntraProcessT>();
|
||||
s8->take_shared_method = false;
|
||||
auto s8_id = ipm->add_subscription(s8);
|
||||
auto s8_id = ipm->template add_subscription<MessageT>(s8);
|
||||
|
||||
auto s9 = std::make_shared<SubscriptionIntraProcessT>();
|
||||
s9->take_shared_method = false;
|
||||
auto s9_id = ipm->add_subscription(s9);
|
||||
auto s9_id = ipm->template add_subscription<MessageT>(s9);
|
||||
|
||||
unique_msg = std::make_unique<MessageT>();
|
||||
original_message_pointer = reinterpret_cast<std::uintptr_t>(unique_msg.get());
|
||||
@@ -716,12 +783,12 @@ TEST(TestIntraProcessManager, multiple_subscriptions_different_type) {
|
||||
|
||||
auto s10 = std::make_shared<SubscriptionIntraProcessT>();
|
||||
s10->take_shared_method = false;
|
||||
auto s10_id = ipm->add_subscription(s10);
|
||||
auto s10_id = ipm->template add_subscription<MessageT>(s10);
|
||||
(void)s10_id;
|
||||
|
||||
auto s11 = std::make_shared<SubscriptionIntraProcessT>();
|
||||
s11->take_shared_method = true;
|
||||
auto s11_id = ipm->add_subscription(s11);
|
||||
auto s11_id = ipm->template add_subscription<MessageT>(s11);
|
||||
(void)s11_id;
|
||||
|
||||
unique_msg = std::make_unique<MessageT>();
|
||||
@@ -734,25 +801,25 @@ TEST(TestIntraProcessManager, multiple_subscriptions_different_type) {
|
||||
}
|
||||
|
||||
/*
|
||||
This tests the method "lowest_available_capacity":
|
||||
- Creates 1 publisher.
|
||||
- The available buffer capacity should be at least history size.
|
||||
- Add 2 subscribers.
|
||||
- Add everything to the intra-process manager.
|
||||
- All the entities are expected to have different ids.
|
||||
- Check the subscriptions count for the publisher.
|
||||
- The available buffer capacity should be the history size.
|
||||
- Publish one message (without receiving it).
|
||||
- The available buffer capacity should decrease by 1.
|
||||
- Publish another message (without receiving it).
|
||||
- The available buffer capacity should decrease by 1.
|
||||
- One subscriber receives one message.
|
||||
- The available buffer capacity should stay the same,
|
||||
as the other subscriber still has not freed its buffer.
|
||||
- The other subscriber receives one message.
|
||||
- The available buffer capacity should increase by 1.
|
||||
- One subscription goes out of scope.
|
||||
- The available buffer capacity should not change.
|
||||
* This tests the method "lowest_available_capacity":
|
||||
* - Creates 1 publisher.
|
||||
* - The available buffer capacity should be at least history size.
|
||||
* - Add 2 subscribers.
|
||||
* - Add everything to the intra-process manager.
|
||||
* - All the entities are expected to have different ids.
|
||||
* - Check the subscriptions count for the publisher.
|
||||
* - The available buffer capacity should be the history size.
|
||||
* - Publish one message (without receiving it).
|
||||
* - The available buffer capacity should decrease by 1.
|
||||
* - Publish another message (without receiving it).
|
||||
* - The available buffer capacity should decrease by 1.
|
||||
* - One subscriber receives one message.
|
||||
* - The available buffer capacity should stay the same,
|
||||
* as the other subscriber still has not freed its buffer.
|
||||
* - The other subscriber receives one message.
|
||||
* - The available buffer capacity should increase by 1.
|
||||
* - One subscription goes out of scope.
|
||||
* - The available buffer capacity should not change.
|
||||
*/
|
||||
TEST(TestIntraProcessManager, lowest_available_capacity) {
|
||||
using IntraProcessManagerT = rclcpp::experimental::IntraProcessManager;
|
||||
@@ -776,8 +843,8 @@ TEST(TestIntraProcessManager, lowest_available_capacity) {
|
||||
|
||||
ASSERT_LE(0u, c1);
|
||||
|
||||
auto s1_id = ipm->add_subscription(s1);
|
||||
auto s2_id = ipm->add_subscription(s2);
|
||||
auto s1_id = ipm->template add_subscription<MessageT>(s1);
|
||||
auto s2_id = ipm->template add_subscription<MessageT>(s2);
|
||||
|
||||
bool unique_ids = s1_id != s2_id && p1_id != s1_id;
|
||||
ASSERT_TRUE(unique_ids);
|
||||
@@ -820,3 +887,82 @@ TEST(TestIntraProcessManager, lowest_available_capacity) {
|
||||
c1 = ipm->lowest_available_capacity(p1_id);
|
||||
ASSERT_EQ(history_depth - 1u, c1);
|
||||
}
|
||||
|
||||
/*
|
||||
* This tests the check inside add_publisher for transient_local
|
||||
* durability publishers
|
||||
* - add_publisher should throw runtime_error when no valid buffer ptr
|
||||
* is passed with a transient_local publisher
|
||||
*/
|
||||
TEST(TestIntraProcessManager, transient_local_invalid_buffer) {
|
||||
using IntraProcessManagerT = rclcpp::experimental::IntraProcessManager;
|
||||
using MessageT = rcl_interfaces::msg::Log;
|
||||
using PublisherT = rclcpp::mock::Publisher<MessageT>;
|
||||
constexpr auto history_depth = 10u;
|
||||
|
||||
auto ipm = std::make_shared<IntraProcessManagerT>();
|
||||
|
||||
auto p1 = std::make_shared<PublisherT>(rclcpp::QoS(history_depth).transient_local());
|
||||
|
||||
ASSERT_THROW(
|
||||
{
|
||||
ipm->add_publisher(p1, nullptr);
|
||||
}, std::runtime_error);
|
||||
}
|
||||
|
||||
/*
|
||||
* This tests publishing function for transient_local durability publihers
|
||||
* - A message is published before three transient_local subscriptions are added to
|
||||
* ipm. Two of the subscriptions use take_shared method. Delivery of the message is verified
|
||||
* along with the contents and pointer addresses from the subscriptions.
|
||||
*/
|
||||
TEST(TestIntraProcessManager, transient_local) {
|
||||
using IntraProcessManagerT = rclcpp::experimental::IntraProcessManager;
|
||||
using MessageT = rcl_interfaces::msg::Log;
|
||||
using PublisherT = rclcpp::mock::Publisher<MessageT>;
|
||||
using SubscriptionIntraProcessT = rclcpp::experimental::mock::SubscriptionIntraProcess<MessageT>;
|
||||
|
||||
constexpr auto history_depth = 10u;
|
||||
|
||||
auto ipm = std::make_shared<IntraProcessManagerT>();
|
||||
|
||||
auto p1 = std::make_shared<PublisherT>(rclcpp::QoS(history_depth).transient_local());
|
||||
|
||||
auto s1 =
|
||||
std::make_shared<SubscriptionIntraProcessT>(rclcpp::QoS(history_depth).transient_local());
|
||||
auto s2 =
|
||||
std::make_shared<SubscriptionIntraProcessT>(rclcpp::QoS(history_depth).transient_local());
|
||||
auto s3 =
|
||||
std::make_shared<SubscriptionIntraProcessT>(rclcpp::QoS(history_depth).transient_local());
|
||||
|
||||
s1->take_shared_method = false;
|
||||
s2->take_shared_method = true;
|
||||
s3->take_shared_method = true;
|
||||
|
||||
auto p1_id = ipm->add_publisher(p1, p1->buffer);
|
||||
|
||||
p1->set_intra_process_manager(p1_id, ipm);
|
||||
|
||||
auto unique_msg = std::make_unique<MessageT>();
|
||||
unique_msg->msg = "Test";
|
||||
p1->publish(std::move(unique_msg));
|
||||
|
||||
ipm->template add_subscription<MessageT>(s1);
|
||||
ipm->template add_subscription<MessageT>(s2);
|
||||
ipm->template add_subscription<MessageT>(s3);
|
||||
|
||||
auto received_message_pointer_1 = s1->pop();
|
||||
auto received_message_pointer_2 = s2->pop();
|
||||
auto received_message_pointer_3 = s3->pop();
|
||||
ASSERT_NE(0u, received_message_pointer_1);
|
||||
ASSERT_NE(0u, received_message_pointer_2);
|
||||
ASSERT_NE(0u, received_message_pointer_3);
|
||||
ASSERT_EQ(received_message_pointer_3, received_message_pointer_2);
|
||||
ASSERT_EQ(
|
||||
reinterpret_cast<MessageT *>(received_message_pointer_1)->msg,
|
||||
reinterpret_cast<MessageT *>(received_message_pointer_2)->msg);
|
||||
ASSERT_EQ(
|
||||
reinterpret_cast<MessageT *>(received_message_pointer_1)->msg,
|
||||
reinterpret_cast<MessageT *>(received_message_pointer_3)->msg);
|
||||
ASSERT_EQ("Test", reinterpret_cast<MessageT *>(received_message_pointer_1)->msg);
|
||||
}
|
||||
|
||||
@@ -3311,6 +3311,9 @@ TEST_F(TestNode, get_entity_names) {
|
||||
const auto service_names_and_types = node->get_service_names_and_types();
|
||||
EXPECT_EQ(service_names_and_types.end(), service_names_and_types.find("service"));
|
||||
|
||||
EXPECT_EQ(0u, node->count_clients("service"));
|
||||
EXPECT_EQ(0u, node->count_services("service"));
|
||||
|
||||
const auto service_names_and_types_by_node =
|
||||
node->get_service_names_and_types_by_node("node", "/ns");
|
||||
EXPECT_EQ(
|
||||
|
||||
@@ -196,11 +196,7 @@ static std::vector<TestParameters> invalid_qos_profiles()
|
||||
{
|
||||
std::vector<TestParameters> parameters;
|
||||
|
||||
parameters.reserve(2);
|
||||
parameters.push_back(
|
||||
TestParameters(
|
||||
rclcpp::QoS(rclcpp::KeepLast(10)).transient_local(),
|
||||
"transient_local_qos"));
|
||||
parameters.reserve(1);
|
||||
parameters.push_back(
|
||||
TestParameters(
|
||||
rclcpp::QoS(rclcpp::KeepAll()),
|
||||
@@ -482,7 +478,7 @@ public:
|
||||
|
||||
void publish_loaned_message(rclcpp::LoanedMessage<MessageT, AllocatorT> && loaned_msg)
|
||||
{
|
||||
this->do_loaned_message_publish(std::move(loaned_msg.release()));
|
||||
this->do_loaned_message_publish(loaned_msg.release());
|
||||
}
|
||||
|
||||
void call_default_incompatible_qos_callback(rclcpp::QOSOfferedIncompatibleQoSInfo & event) const
|
||||
@@ -674,3 +670,96 @@ INSTANTIATE_TEST_SUITE_P(
|
||||
rclcpp::QoS(1).best_effort(), rclcpp::QoS(1).best_effort()),
|
||||
std::pair<rclcpp::QoS, rclcpp::QoS>(
|
||||
rclcpp::QoS(1).reliable(), rclcpp::QoS(1).best_effort())));
|
||||
|
||||
TEST_F(TestPublisher, intra_process_transient_local) {
|
||||
constexpr auto history_depth = 10u;
|
||||
initialize(rclcpp::NodeOptions().use_intra_process_comms(true));
|
||||
rclcpp::PublisherOptionsWithAllocator<std::allocator<void>> pub_options_ipm_disabled;
|
||||
pub_options_ipm_disabled.use_intra_process_comm = rclcpp::IntraProcessSetting::Disable;
|
||||
|
||||
rclcpp::PublisherOptionsWithAllocator<std::allocator<void>> pub_options_ipm_enabled;
|
||||
pub_options_ipm_enabled.use_intra_process_comm = rclcpp::IntraProcessSetting::Enable;
|
||||
|
||||
auto pub_ipm_enabled_transient_local_enabled = node->create_publisher<test_msgs::msg::Empty>(
|
||||
"topic1",
|
||||
rclcpp::QoS(rclcpp::KeepLast(history_depth)).transient_local(), pub_options_ipm_enabled);
|
||||
auto pub_ipm_disabled_transient_local_enabled = node->create_publisher<test_msgs::msg::Empty>(
|
||||
"topic2",
|
||||
rclcpp::QoS(rclcpp::KeepLast(history_depth)).transient_local(), pub_options_ipm_disabled);
|
||||
auto pub_ipm_enabled_transient_local_disabled = node->create_publisher<test_msgs::msg::Empty>(
|
||||
"topic3",
|
||||
rclcpp::QoS(rclcpp::KeepLast(history_depth)), pub_options_ipm_enabled);
|
||||
auto pub_ipm_disabled_transient_local_disabled = node->create_publisher<test_msgs::msg::Empty>(
|
||||
"topic4",
|
||||
rclcpp::QoS(rclcpp::KeepLast(history_depth)), pub_options_ipm_disabled);
|
||||
|
||||
test_msgs::msg::Empty msg;
|
||||
pub_ipm_enabled_transient_local_enabled->publish(msg);
|
||||
pub_ipm_disabled_transient_local_enabled->publish(msg);
|
||||
pub_ipm_enabled_transient_local_disabled->publish(msg);
|
||||
pub_ipm_disabled_transient_local_disabled->publish(msg);
|
||||
|
||||
auto do_nothing = [](std::shared_ptr<const test_msgs::msg::Empty>) {};
|
||||
struct IntraProcessCallback
|
||||
{
|
||||
void callback_fun(size_t s)
|
||||
{
|
||||
(void) s;
|
||||
called = true;
|
||||
}
|
||||
bool called = false;
|
||||
};
|
||||
rclcpp::SubscriptionOptions sub_options_ipm_disabled;
|
||||
sub_options_ipm_disabled.use_intra_process_comm = rclcpp::IntraProcessSetting::Disable;
|
||||
rclcpp::SubscriptionOptions sub_options_ipm_enabled;
|
||||
sub_options_ipm_enabled.use_intra_process_comm = rclcpp::IntraProcessSetting::Enable;
|
||||
IntraProcessCallback callback1, callback2, callback3, callback4;
|
||||
auto sub_ipm_enabled_transient_local_enabled = node->create_subscription<test_msgs::msg::Empty>(
|
||||
"topic1",
|
||||
rclcpp::QoS(rclcpp::KeepLast(history_depth)).transient_local(),
|
||||
do_nothing, sub_options_ipm_enabled);
|
||||
sub_ipm_enabled_transient_local_enabled->set_on_new_intra_process_message_callback(
|
||||
std::bind(&IntraProcessCallback::callback_fun, &callback1, std::placeholders::_1));
|
||||
auto sub_ipm_disabled_transient_local_enabled = node->create_subscription<test_msgs::msg::Empty>(
|
||||
"topic2",
|
||||
rclcpp::QoS(rclcpp::KeepLast(history_depth)).transient_local(),
|
||||
do_nothing, sub_options_ipm_disabled);
|
||||
sub_ipm_disabled_transient_local_enabled->set_on_new_intra_process_message_callback(
|
||||
std::bind(&IntraProcessCallback::callback_fun, &callback2, std::placeholders::_1));
|
||||
auto sub_ipm_enabled_transient_local_disabled = node->create_subscription<test_msgs::msg::Empty>(
|
||||
"topic3",
|
||||
rclcpp::QoS(rclcpp::KeepLast(history_depth)),
|
||||
do_nothing, sub_options_ipm_enabled);
|
||||
sub_ipm_enabled_transient_local_disabled->set_on_new_intra_process_message_callback(
|
||||
std::bind(&IntraProcessCallback::callback_fun, &callback3, std::placeholders::_1));
|
||||
auto sub_ipm_disabled_transient_local_disabled = node->create_subscription<test_msgs::msg::Empty>(
|
||||
"topic4",
|
||||
rclcpp::QoS(rclcpp::KeepLast(history_depth)),
|
||||
do_nothing, sub_options_ipm_disabled);
|
||||
sub_ipm_disabled_transient_local_disabled->set_on_new_intra_process_message_callback(
|
||||
std::bind(&IntraProcessCallback::callback_fun, &callback4, std::placeholders::_1));
|
||||
|
||||
EXPECT_TRUE(pub_ipm_enabled_transient_local_enabled->is_durability_transient_local());
|
||||
EXPECT_TRUE(pub_ipm_disabled_transient_local_enabled->is_durability_transient_local());
|
||||
EXPECT_FALSE(pub_ipm_enabled_transient_local_disabled->is_durability_transient_local());
|
||||
EXPECT_FALSE(pub_ipm_disabled_transient_local_disabled->is_durability_transient_local());
|
||||
|
||||
EXPECT_EQ(1, pub_ipm_enabled_transient_local_enabled->get_intra_process_subscription_count());
|
||||
EXPECT_EQ(0, pub_ipm_disabled_transient_local_enabled->get_intra_process_subscription_count());
|
||||
EXPECT_EQ(1, pub_ipm_enabled_transient_local_disabled->get_intra_process_subscription_count());
|
||||
EXPECT_EQ(0, pub_ipm_disabled_transient_local_disabled->get_intra_process_subscription_count());
|
||||
|
||||
EXPECT_EQ(
|
||||
history_depth - 1u,
|
||||
pub_ipm_enabled_transient_local_enabled->lowest_available_ipm_capacity());
|
||||
EXPECT_EQ(0, pub_ipm_disabled_transient_local_enabled->lowest_available_ipm_capacity());
|
||||
EXPECT_EQ(
|
||||
history_depth,
|
||||
pub_ipm_enabled_transient_local_disabled->lowest_available_ipm_capacity());
|
||||
EXPECT_EQ(0, pub_ipm_disabled_transient_local_disabled->lowest_available_ipm_capacity());
|
||||
|
||||
EXPECT_TRUE(callback1.called);
|
||||
EXPECT_FALSE(callback2.called);
|
||||
EXPECT_FALSE(callback3.called);
|
||||
EXPECT_FALSE(callback4.called);
|
||||
}
|
||||
|
||||
@@ -21,12 +21,24 @@
|
||||
|
||||
#include "../utils/rclcpp_gtest_macros.hpp"
|
||||
|
||||
/*
|
||||
Basic tests for the Rate, WallRate and ROSRate classes.
|
||||
*/
|
||||
TEST(TestRate, rate_basics) {
|
||||
rclcpp::init(0, nullptr);
|
||||
class TestRate : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
void SetUp()
|
||||
{
|
||||
rclcpp::init(0, nullptr);
|
||||
}
|
||||
|
||||
void TearDown()
|
||||
{
|
||||
rclcpp::shutdown();
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
Basic tests for the Rate and WallRate classes.
|
||||
*/
|
||||
TEST_F(TestRate, rate_basics) {
|
||||
auto period = std::chrono::milliseconds(1000);
|
||||
auto offset = std::chrono::milliseconds(500);
|
||||
auto epsilon = std::chrono::milliseconds(100);
|
||||
@@ -79,13 +91,9 @@ TEST(TestRate, rate_basics) {
|
||||
auto five = std::chrono::system_clock::now();
|
||||
delta = five - four;
|
||||
ASSERT_TRUE(epsilon > delta);
|
||||
|
||||
rclcpp::shutdown();
|
||||
}
|
||||
|
||||
TEST(TestRate, wall_rate_basics) {
|
||||
rclcpp::init(0, nullptr);
|
||||
|
||||
TEST_F(TestRate, wall_rate_basics) {
|
||||
auto period = std::chrono::milliseconds(100);
|
||||
auto offset = std::chrono::milliseconds(50);
|
||||
auto epsilon = std::chrono::milliseconds(1);
|
||||
@@ -140,77 +148,12 @@ TEST(TestRate, wall_rate_basics) {
|
||||
auto five = std::chrono::steady_clock::now();
|
||||
delta = five - four;
|
||||
EXPECT_GT(epsilon, delta);
|
||||
|
||||
rclcpp::shutdown();
|
||||
}
|
||||
|
||||
TEST(TestRate, ros_rate_basics) {
|
||||
rclcpp::init(0, nullptr);
|
||||
|
||||
auto period = std::chrono::milliseconds(100);
|
||||
auto offset = std::chrono::milliseconds(50);
|
||||
auto epsilon = std::chrono::milliseconds(1);
|
||||
double overrun_ratio = 1.5;
|
||||
|
||||
rclcpp::Clock clock(RCL_ROS_TIME);
|
||||
|
||||
auto start = clock.now();
|
||||
rclcpp::ROSRate r(period);
|
||||
EXPECT_EQ(rclcpp::Duration(period), r.period());
|
||||
// suppress deprecated warnings
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4996)
|
||||
#endif
|
||||
ASSERT_FALSE(r.is_steady());
|
||||
// suppress deprecated warnings
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4996)
|
||||
#endif
|
||||
ASSERT_EQ(RCL_ROS_TIME, r.get_type());
|
||||
ASSERT_TRUE(r.sleep());
|
||||
auto one = clock.now();
|
||||
auto delta = one - start;
|
||||
EXPECT_LT(rclcpp::Duration(period), delta);
|
||||
EXPECT_GT(rclcpp::Duration(period * overrun_ratio), delta);
|
||||
|
||||
clock.sleep_for(offset);
|
||||
ASSERT_TRUE(r.sleep());
|
||||
auto two = clock.now();
|
||||
delta = two - start;
|
||||
EXPECT_LT(rclcpp::Duration(2 * period), delta + epsilon);
|
||||
EXPECT_GT(rclcpp::Duration(2 * period * overrun_ratio), delta);
|
||||
|
||||
clock.sleep_for(offset);
|
||||
auto two_offset = clock.now();
|
||||
r.reset();
|
||||
ASSERT_TRUE(r.sleep());
|
||||
auto three = clock.now();
|
||||
delta = three - two_offset;
|
||||
EXPECT_LT(rclcpp::Duration(period), delta);
|
||||
EXPECT_GT(rclcpp::Duration(period * overrun_ratio), delta);
|
||||
|
||||
clock.sleep_for(offset + period);
|
||||
auto four = clock.now();
|
||||
ASSERT_FALSE(r.sleep());
|
||||
auto five = clock.now();
|
||||
delta = five - four;
|
||||
EXPECT_GT(rclcpp::Duration(epsilon), delta);
|
||||
|
||||
rclcpp::shutdown();
|
||||
}
|
||||
|
||||
/*
|
||||
Basic test for the deprecated GenericRate class.
|
||||
*/
|
||||
TEST(TestRate, generic_rate) {
|
||||
TEST_F(TestRate, generic_rate) {
|
||||
auto period = std::chrono::milliseconds(100);
|
||||
auto offset = std::chrono::milliseconds(50);
|
||||
auto epsilon = std::chrono::milliseconds(1);
|
||||
@@ -325,13 +268,13 @@ TEST(TestRate, generic_rate) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TestRate, from_double) {
|
||||
TEST_F(TestRate, from_double) {
|
||||
{
|
||||
rclcpp::Rate rate(1.0);
|
||||
EXPECT_EQ(rclcpp::Duration(std::chrono::seconds(1)), rate.period());
|
||||
}
|
||||
{
|
||||
rclcpp::WallRate rate(2.0);
|
||||
rclcpp::Rate rate(2.0);
|
||||
EXPECT_EQ(rclcpp::Duration(std::chrono::milliseconds(500)), rate.period());
|
||||
}
|
||||
{
|
||||
@@ -339,12 +282,12 @@ TEST(TestRate, from_double) {
|
||||
EXPECT_EQ(rclcpp::Duration(std::chrono::seconds(2)), rate.period());
|
||||
}
|
||||
{
|
||||
rclcpp::ROSRate rate(4.0);
|
||||
rclcpp::WallRate rate(4.0);
|
||||
EXPECT_EQ(rclcpp::Duration(std::chrono::milliseconds(250)), rate.period());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TestRate, clock_types) {
|
||||
TEST_F(TestRate, clock_types) {
|
||||
{
|
||||
rclcpp::Rate rate(1.0, std::make_shared<rclcpp::Clock>(RCL_SYSTEM_TIME));
|
||||
// suppress deprecated warnings
|
||||
@@ -404,7 +347,7 @@ TEST(TestRate, clock_types) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TestRate, incorrect_constuctor) {
|
||||
TEST_F(TestRate, incorrect_constuctor) {
|
||||
// Constructor with 0-frequency
|
||||
RCLCPP_EXPECT_THROW_EQ(
|
||||
rclcpp::Rate rate(0.0),
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
#include "rclcpp/experimental/buffers/ring_buffer_implementation.hpp"
|
||||
|
||||
/*
|
||||
Construtctor
|
||||
* Construtctor
|
||||
*/
|
||||
TEST(TestRingBufferImplementation, constructor) {
|
||||
// Cannot create a buffer of size zero.
|
||||
@@ -37,10 +37,11 @@ TEST(TestRingBufferImplementation, constructor) {
|
||||
}
|
||||
|
||||
/*
|
||||
Basic usage
|
||||
- insert data and check that it has data
|
||||
- extract data
|
||||
- overwrite old data writing over the buffer capacity
|
||||
* Basic usage
|
||||
* - insert data and check that it has data
|
||||
* - get all data
|
||||
* - extract data
|
||||
* - overwrite old data writing over the buffer capacity
|
||||
*/
|
||||
TEST(TestRingBufferImplementation, basic_usage) {
|
||||
rclcpp::experimental::buffers::RingBufferImplementation<char> rb(2);
|
||||
@@ -64,6 +65,12 @@ TEST(TestRingBufferImplementation, basic_usage) {
|
||||
|
||||
rb.enqueue('d');
|
||||
|
||||
const auto all_data_vec = rb.get_all_data();
|
||||
|
||||
EXPECT_EQ(2u, all_data_vec.size());
|
||||
EXPECT_EQ('c', all_data_vec[0]);
|
||||
EXPECT_EQ('d', all_data_vec[1]);
|
||||
|
||||
EXPECT_EQ(true, rb.has_data());
|
||||
EXPECT_EQ(true, rb.is_full());
|
||||
|
||||
@@ -79,3 +86,56 @@ TEST(TestRingBufferImplementation, basic_usage) {
|
||||
EXPECT_EQ(false, rb.has_data());
|
||||
EXPECT_EQ(false, rb.is_full());
|
||||
}
|
||||
|
||||
/*
|
||||
* Basic usage with unique_ptr
|
||||
* - insert unique_ptr data and check that it has data
|
||||
* - get all data
|
||||
* - extract data
|
||||
* - overwrite old data writing over the buffer capacity
|
||||
*/
|
||||
TEST(TestRingBufferImplementation, basic_usage_unique_ptr) {
|
||||
rclcpp::experimental::buffers::RingBufferImplementation<std::unique_ptr<char>> rb(2);
|
||||
|
||||
auto a = std::make_unique<char>('a');
|
||||
auto b = std::make_unique<char>('b');
|
||||
auto original_b_pointer = reinterpret_cast<std::uintptr_t>(b.get());
|
||||
auto c = std::make_unique<char>('c');
|
||||
auto original_c_pointer = reinterpret_cast<std::uintptr_t>(c.get());
|
||||
|
||||
rb.enqueue(std::move(a));
|
||||
|
||||
EXPECT_EQ(true, rb.has_data());
|
||||
EXPECT_EQ(false, rb.is_full());
|
||||
|
||||
rb.enqueue(std::move(b));
|
||||
rb.enqueue(std::move(c));
|
||||
|
||||
EXPECT_EQ(true, rb.has_data());
|
||||
EXPECT_EQ(true, rb.is_full());
|
||||
|
||||
const auto all_data_vec = rb.get_all_data();
|
||||
|
||||
EXPECT_EQ(2u, all_data_vec.size());
|
||||
EXPECT_EQ('b', *all_data_vec[0]);
|
||||
EXPECT_EQ('c', *all_data_vec[1]);
|
||||
EXPECT_NE(original_b_pointer, reinterpret_cast<std::uintptr_t>(all_data_vec[0].get()));
|
||||
EXPECT_NE(original_c_pointer, reinterpret_cast<std::uintptr_t>(all_data_vec[1].get()));
|
||||
|
||||
EXPECT_EQ(true, rb.has_data());
|
||||
EXPECT_EQ(true, rb.is_full());
|
||||
|
||||
auto uni_ptr = rb.dequeue();
|
||||
|
||||
EXPECT_EQ('b', *uni_ptr);
|
||||
EXPECT_EQ(original_b_pointer, reinterpret_cast<std::uintptr_t>(uni_ptr.get()));
|
||||
EXPECT_EQ(true, rb.has_data());
|
||||
EXPECT_EQ(false, rb.is_full());
|
||||
|
||||
uni_ptr = rb.dequeue();
|
||||
|
||||
EXPECT_EQ('c', *uni_ptr);
|
||||
EXPECT_EQ(original_c_pointer, reinterpret_cast<std::uintptr_t>(uni_ptr.get()));
|
||||
EXPECT_EQ(false, rb.has_data());
|
||||
EXPECT_EQ(false, rb.is_full());
|
||||
}
|
||||
|
||||
@@ -178,3 +178,13 @@ TEST_F(TestRosoutSubscription, test_rosoutsubscription_getchild_hierarchy) {
|
||||
EXPECT_TRUE(future.get());
|
||||
received_msg_promise = {};
|
||||
}
|
||||
|
||||
TEST_F(TestRosoutSubscription, test_rosoutsubscription_node_rosout_disabled) {
|
||||
rclcpp::NodeOptions options = rclcpp::NodeOptions().enable_rosout(false);
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", options);
|
||||
auto log_func = [&node] {
|
||||
auto logger = node->get_logger().get_child("child");
|
||||
RCLCPP_INFO(logger, "test");
|
||||
};
|
||||
ASSERT_NO_THROW(log_func());
|
||||
}
|
||||
|
||||
@@ -145,11 +145,6 @@ TEST(TestSerializedMessage, reserve) {
|
||||
// Resize using reserve method
|
||||
serialized_msg.reserve(15);
|
||||
EXPECT_EQ(15u, serialized_msg.capacity());
|
||||
|
||||
// Use invalid value throws exception
|
||||
EXPECT_THROW(
|
||||
{serialized_msg.reserve(-1);},
|
||||
rclcpp::exceptions::RCLBadAlloc);
|
||||
}
|
||||
|
||||
TEST(TestSerializedMessage, serialization) {
|
||||
|
||||
@@ -611,11 +611,7 @@ static std::vector<TestParameters> invalid_qos_profiles()
|
||||
{
|
||||
std::vector<TestParameters> parameters;
|
||||
|
||||
parameters.reserve(3);
|
||||
parameters.push_back(
|
||||
TestParameters(
|
||||
rclcpp::QoS(rclcpp::KeepLast(10)).transient_local(),
|
||||
"transient_local_qos"));
|
||||
parameters.reserve(1);
|
||||
parameters.push_back(
|
||||
TestParameters(
|
||||
rclcpp::QoS(rclcpp::KeepAll()),
|
||||
|
||||
@@ -60,14 +60,17 @@ TEST_F(TestSubscriptionOptions, topic_statistics_options_default_and_set) {
|
||||
EXPECT_EQ(options.topic_stats_options.state, rclcpp::TopicStatisticsState::NodeDefault);
|
||||
EXPECT_EQ(options.topic_stats_options.publish_topic, defaultPublishTopic);
|
||||
EXPECT_EQ(options.topic_stats_options.publish_period, 1s);
|
||||
EXPECT_EQ(options.topic_stats_options.qos, rclcpp::SystemDefaultsQoS());
|
||||
|
||||
options.topic_stats_options.state = rclcpp::TopicStatisticsState::Enable;
|
||||
options.topic_stats_options.publish_topic = "topic_statistics";
|
||||
options.topic_stats_options.publish_period = 5min;
|
||||
options.topic_stats_options.qos = rclcpp::BestAvailableQoS();
|
||||
|
||||
EXPECT_EQ(options.topic_stats_options.state, rclcpp::TopicStatisticsState::Enable);
|
||||
EXPECT_EQ(options.topic_stats_options.publish_topic, "topic_statistics");
|
||||
EXPECT_EQ(options.topic_stats_options.publish_period, 5min);
|
||||
EXPECT_EQ(options.topic_stats_options.qos, rclcpp::BestAvailableQoS());
|
||||
}
|
||||
|
||||
TEST_F(TestSubscriptionOptions, topic_statistics_options_node_default_mode) {
|
||||
|
||||
@@ -363,10 +363,27 @@ TEST_F(TestTime, seconds) {
|
||||
}
|
||||
|
||||
TEST_F(TestTime, test_max) {
|
||||
const rclcpp::Time time_max = rclcpp::Time::max();
|
||||
const rclcpp::Time max_time(std::numeric_limits<int32_t>::max(), 999999999);
|
||||
EXPECT_DOUBLE_EQ(max_time.seconds(), time_max.seconds());
|
||||
EXPECT_EQ(max_time.nanoseconds(), time_max.nanoseconds());
|
||||
// Same clock types
|
||||
for (rcl_clock_type_t type = RCL_ROS_TIME;
|
||||
type != RCL_STEADY_TIME; type = static_cast<rcl_clock_type_t>(type + 1))
|
||||
{
|
||||
const rclcpp::Time time_max = rclcpp::Time::max(type);
|
||||
const rclcpp::Time max_time(std::numeric_limits<int32_t>::max(), 999999999, type);
|
||||
EXPECT_DOUBLE_EQ(max_time.seconds(), time_max.seconds());
|
||||
EXPECT_EQ(max_time.nanoseconds(), time_max.nanoseconds());
|
||||
}
|
||||
// Different clock types
|
||||
{
|
||||
const rclcpp::Time time_max = rclcpp::Time::max(RCL_ROS_TIME);
|
||||
const rclcpp::Time max_time(std::numeric_limits<int32_t>::max(), 999999999, RCL_STEADY_TIME);
|
||||
EXPECT_ANY_THROW((void)(time_max == max_time));
|
||||
EXPECT_ANY_THROW((void)(time_max != max_time));
|
||||
EXPECT_ANY_THROW((void)(time_max <= max_time));
|
||||
EXPECT_ANY_THROW((void)(time_max >= max_time));
|
||||
EXPECT_ANY_THROW((void)(time_max < max_time));
|
||||
EXPECT_ANY_THROW((void)(time_max > max_time));
|
||||
EXPECT_ANY_THROW((void)(time_max - max_time));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestTime, test_constructor_from_rcl_time_point) {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
@@ -65,8 +66,10 @@ TEST_F(TestTimersManager, empty_manager)
|
||||
TEST_F(TestTimersManager, add_run_remove_timer)
|
||||
{
|
||||
size_t t_runs = 0;
|
||||
std::chrono::milliseconds timer_period(10);
|
||||
|
||||
auto t = TimerT::make_shared(
|
||||
10ms,
|
||||
timer_period,
|
||||
[&t_runs]() {
|
||||
t_runs++;
|
||||
},
|
||||
@@ -79,7 +82,7 @@ TEST_F(TestTimersManager, add_run_remove_timer)
|
||||
timers_manager->add_timer(t);
|
||||
|
||||
// Sleep for more 3 times the timer period
|
||||
std::this_thread::sleep_for(30ms);
|
||||
std::this_thread::sleep_for(3 * timer_period);
|
||||
|
||||
// The timer is executed only once, even if we slept 3 times the period
|
||||
execute_all_ready_timers(timers_manager);
|
||||
@@ -191,67 +194,6 @@ TEST_F(TestTimersManager, head_not_ready)
|
||||
EXPECT_EQ(0u, t_runs);
|
||||
}
|
||||
|
||||
TEST_F(TestTimersManager, timers_order)
|
||||
{
|
||||
auto timers_manager = std::make_shared<TimersManager>(
|
||||
rclcpp::contexts::get_global_default_context());
|
||||
|
||||
size_t t1_runs = 0;
|
||||
auto t1 = TimerT::make_shared(
|
||||
10ms,
|
||||
[&t1_runs]() {
|
||||
t1_runs++;
|
||||
},
|
||||
rclcpp::contexts::get_global_default_context());
|
||||
|
||||
size_t t2_runs = 0;
|
||||
auto t2 = TimerT::make_shared(
|
||||
30ms,
|
||||
[&t2_runs]() {
|
||||
t2_runs++;
|
||||
},
|
||||
rclcpp::contexts::get_global_default_context());
|
||||
|
||||
size_t t3_runs = 0;
|
||||
auto t3 = TimerT::make_shared(
|
||||
100ms,
|
||||
[&t3_runs]() {
|
||||
t3_runs++;
|
||||
},
|
||||
rclcpp::contexts::get_global_default_context());
|
||||
|
||||
// Add timers in a random order
|
||||
timers_manager->add_timer(t2);
|
||||
timers_manager->add_timer(t3);
|
||||
timers_manager->add_timer(t1);
|
||||
|
||||
std::this_thread::sleep_for(10ms);
|
||||
execute_all_ready_timers(timers_manager);
|
||||
EXPECT_EQ(1u, t1_runs);
|
||||
EXPECT_EQ(0u, t2_runs);
|
||||
EXPECT_EQ(0u, t3_runs);
|
||||
|
||||
std::this_thread::sleep_for(30ms);
|
||||
execute_all_ready_timers(timers_manager);
|
||||
EXPECT_EQ(2u, t1_runs);
|
||||
EXPECT_EQ(1u, t2_runs);
|
||||
EXPECT_EQ(0u, t3_runs);
|
||||
|
||||
std::this_thread::sleep_for(100ms);
|
||||
execute_all_ready_timers(timers_manager);
|
||||
EXPECT_EQ(3u, t1_runs);
|
||||
EXPECT_EQ(2u, t2_runs);
|
||||
EXPECT_EQ(1u, t3_runs);
|
||||
|
||||
timers_manager->remove_timer(t1);
|
||||
|
||||
std::this_thread::sleep_for(30ms);
|
||||
execute_all_ready_timers(timers_manager);
|
||||
EXPECT_EQ(3u, t1_runs);
|
||||
EXPECT_EQ(3u, t2_runs);
|
||||
EXPECT_EQ(1u, t3_runs);
|
||||
}
|
||||
|
||||
TEST_F(TestTimersManager, start_stop_timers_thread)
|
||||
{
|
||||
auto timers_manager = std::make_shared<TimersManager>(
|
||||
@@ -274,7 +216,7 @@ TEST_F(TestTimersManager, timers_thread)
|
||||
auto timers_manager = std::make_shared<TimersManager>(
|
||||
rclcpp::contexts::get_global_default_context());
|
||||
|
||||
size_t t1_runs = 0;
|
||||
int t1_runs = 0;
|
||||
auto t1 = TimerT::make_shared(
|
||||
1ms,
|
||||
[&t1_runs]() {
|
||||
@@ -282,7 +224,7 @@ TEST_F(TestTimersManager, timers_thread)
|
||||
},
|
||||
rclcpp::contexts::get_global_default_context());
|
||||
|
||||
size_t t2_runs = 0;
|
||||
int t2_runs = 0;
|
||||
auto t2 = TimerT::make_shared(
|
||||
1ms,
|
||||
[&t2_runs]() {
|
||||
@@ -296,12 +238,12 @@ TEST_F(TestTimersManager, timers_thread)
|
||||
|
||||
// Run timers thread for a while
|
||||
timers_manager->start();
|
||||
std::this_thread::sleep_for(5ms);
|
||||
std::this_thread::sleep_for(50ms);
|
||||
timers_manager->stop();
|
||||
|
||||
EXPECT_LT(1u, t1_runs);
|
||||
EXPECT_LT(1u, t2_runs);
|
||||
EXPECT_EQ(t1_runs, t2_runs);
|
||||
EXPECT_LE(std::abs(t1_runs - t2_runs), 1);
|
||||
}
|
||||
|
||||
TEST_F(TestTimersManager, destructor)
|
||||
@@ -365,13 +307,13 @@ TEST_F(TestTimersManager, add_remove_while_thread_running)
|
||||
timers_manager->start();
|
||||
|
||||
// After a while remove t1 and add t2
|
||||
std::this_thread::sleep_for(5ms);
|
||||
std::this_thread::sleep_for(50ms);
|
||||
timers_manager->remove_timer(t1);
|
||||
size_t tmp_t1 = t1_runs;
|
||||
timers_manager->add_timer(t2);
|
||||
|
||||
// Wait some more time and then stop
|
||||
std::this_thread::sleep_for(5ms);
|
||||
std::this_thread::sleep_for(50ms);
|
||||
timers_manager->stop();
|
||||
|
||||
// t1 has stopped running
|
||||
|
||||
@@ -50,7 +50,7 @@ TEST(TypesupportHelpersTest, returns_c_type_info_for_valid_legacy_library) {
|
||||
try {
|
||||
auto library = rclcpp::get_typesupport_library(
|
||||
"test_msgs/BasicTypes", "rosidl_typesupport_cpp");
|
||||
auto string_typesupport = rclcpp::get_typesupport_handle(
|
||||
auto string_typesupport = rclcpp::get_message_typesupport_handle(
|
||||
"test_msgs/BasicTypes", "rosidl_typesupport_cpp", *library);
|
||||
|
||||
EXPECT_THAT(
|
||||
@@ -65,7 +65,7 @@ TEST(TypesupportHelpersTest, returns_c_type_info_for_valid_library) {
|
||||
try {
|
||||
auto library = rclcpp::get_typesupport_library(
|
||||
"test_msgs/msg/BasicTypes", "rosidl_typesupport_cpp");
|
||||
auto string_typesupport = rclcpp::get_typesupport_handle(
|
||||
auto string_typesupport = rclcpp::get_message_typesupport_handle(
|
||||
"test_msgs/msg/BasicTypes", "rosidl_typesupport_cpp", *library);
|
||||
|
||||
EXPECT_THAT(
|
||||
@@ -75,3 +75,52 @@ TEST(TypesupportHelpersTest, returns_c_type_info_for_valid_library) {
|
||||
FAIL() << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TypesupportHelpersTest, returns_service_type_info_for_valid_legacy_library) {
|
||||
try {
|
||||
auto library = rclcpp::get_typesupport_library(
|
||||
"test_msgs/Empty", "rosidl_typesupport_cpp");
|
||||
auto empty_typesupport = rclcpp::get_service_typesupport_handle(
|
||||
"test_msgs/Empty", "rosidl_typesupport_cpp", *library);
|
||||
|
||||
EXPECT_THAT(
|
||||
std::string(empty_typesupport->typesupport_identifier),
|
||||
ContainsRegex("rosidl_typesupport"));
|
||||
} catch (const std::runtime_error & e) {
|
||||
FAIL() << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TypesupportHelpersTest, returns_service_type_info_for_valid_library) {
|
||||
try {
|
||||
auto library = rclcpp::get_typesupport_library(
|
||||
"test_msgs/srv/Empty", "rosidl_typesupport_cpp");
|
||||
auto empty_typesupport = rclcpp::get_service_typesupport_handle(
|
||||
"test_msgs/srv/Empty", "rosidl_typesupport_cpp", *library);
|
||||
|
||||
EXPECT_THAT(
|
||||
std::string(empty_typesupport->typesupport_identifier),
|
||||
ContainsRegex("rosidl_typesupport"));
|
||||
} catch (const std::runtime_error & e) {
|
||||
FAIL() << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(TypesupportHelpersTest, test_throw_exception_with_invalid_type) {
|
||||
// message
|
||||
std::string invalid_type = "test_msgs/msg/InvalidType";
|
||||
auto library = rclcpp::get_typesupport_library(invalid_type, "rosidl_typesupport_cpp");
|
||||
EXPECT_THROW(
|
||||
rclcpp::get_message_typesupport_handle(invalid_type, "rosidl_typesupport_cpp", *library),
|
||||
std::runtime_error);
|
||||
EXPECT_THROW(
|
||||
rclcpp::get_service_typesupport_handle(invalid_type, "rosidl_typesupport_cpp", *library),
|
||||
std::runtime_error);
|
||||
|
||||
// service
|
||||
invalid_type = "test_msgs/srv/InvalidType";
|
||||
library = rclcpp::get_typesupport_library(invalid_type, "rosidl_typesupport_cpp");
|
||||
EXPECT_THROW(
|
||||
rclcpp::get_service_typesupport_handle(invalid_type, "rosidl_typesupport_cpp", *library),
|
||||
std::runtime_error);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
@@ -22,12 +21,12 @@
|
||||
#include <set>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "libstatistics_collector/moving_average_statistics/types.hpp"
|
||||
|
||||
#include "rclcpp/create_publisher.hpp"
|
||||
#include "rclcpp/msg/message_with_header.hpp"
|
||||
#include "rclcpp/node.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
@@ -36,10 +35,10 @@
|
||||
#include "rclcpp/topic_statistics/subscription_topic_statistics.hpp"
|
||||
|
||||
#include "statistics_msgs/msg/metrics_message.hpp"
|
||||
#include "statistics_msgs/msg/statistic_data_point.hpp"
|
||||
#include "statistics_msgs/msg/statistic_data_type.hpp"
|
||||
|
||||
#include "test_msgs/msg/empty.hpp"
|
||||
#include "test_msgs/msg/strings.hpp"
|
||||
|
||||
#include "test_topic_stats_utils.hpp"
|
||||
|
||||
@@ -67,7 +66,6 @@ constexpr const std::chrono::seconds kUnstableMessageAgeWindowDuration{
|
||||
constexpr const std::chrono::seconds kUnstableMessageAgeOffset{std::chrono::seconds{1}};
|
||||
} // namespace
|
||||
|
||||
using rclcpp::msg::MessageWithHeader;
|
||||
using test_msgs::msg::Empty;
|
||||
using rclcpp::topic_statistics::SubscriptionTopicStatistics;
|
||||
using statistics_msgs::msg::MetricsMessage;
|
||||
@@ -76,114 +74,73 @@ using statistics_msgs::msg::StatisticDataType;
|
||||
using libstatistics_collector::moving_average_statistics::StatisticData;
|
||||
|
||||
/**
|
||||
* Wrapper class to test and expose parts of the SubscriptionTopicStatistics<T> class.
|
||||
* \tparam CallbackMessageT
|
||||
* Wrapper class to test and expose parts of the SubscriptionTopicStatistics class.
|
||||
*/
|
||||
template<typename CallbackMessageT>
|
||||
class TestSubscriptionTopicStatistics : public SubscriptionTopicStatistics<CallbackMessageT>
|
||||
class TestSubscriptionTopicStatistics : public SubscriptionTopicStatistics
|
||||
{
|
||||
public:
|
||||
TestSubscriptionTopicStatistics(
|
||||
const std::string & node_name,
|
||||
rclcpp::Publisher<statistics_msgs::msg::MetricsMessage>::SharedPtr publisher)
|
||||
: SubscriptionTopicStatistics<CallbackMessageT>(node_name, publisher)
|
||||
: SubscriptionTopicStatistics(node_name, std::move(publisher))
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~TestSubscriptionTopicStatistics() = default;
|
||||
~TestSubscriptionTopicStatistics() override = default;
|
||||
|
||||
/// Exposed for testing
|
||||
std::vector<StatisticData> get_current_collector_data() const
|
||||
{
|
||||
return SubscriptionTopicStatistics<CallbackMessageT>::get_current_collector_data();
|
||||
}
|
||||
using SubscriptionTopicStatistics::get_current_collector_data;
|
||||
};
|
||||
|
||||
/**
|
||||
* Empty publisher node: used to publish empty messages
|
||||
* PublisherNode wrapper: used to create publisher node
|
||||
*/
|
||||
class EmptyPublisher : public rclcpp::Node
|
||||
template<typename MessageT>
|
||||
class PublisherNode : public rclcpp::Node
|
||||
{
|
||||
public:
|
||||
EmptyPublisher(
|
||||
PublisherNode(
|
||||
const std::string & name, const std::string & topic,
|
||||
const std::chrono::milliseconds & publish_period = std::chrono::milliseconds{100})
|
||||
: Node(name)
|
||||
{
|
||||
publisher_ = create_publisher<Empty>(topic, 10);
|
||||
publisher_ = create_publisher<MessageT>(topic, 10);
|
||||
publish_timer_ = this->create_wall_timer(
|
||||
publish_period, [this]() {
|
||||
this->publish_message();
|
||||
});
|
||||
}
|
||||
|
||||
virtual ~EmptyPublisher() = default;
|
||||
~PublisherNode() override = default;
|
||||
|
||||
private:
|
||||
void publish_message()
|
||||
{
|
||||
auto msg = Empty{};
|
||||
auto msg = MessageT{};
|
||||
publisher_->publish(msg);
|
||||
}
|
||||
|
||||
rclcpp::Publisher<Empty>::SharedPtr publisher_;
|
||||
typename rclcpp::Publisher<MessageT>::SharedPtr publisher_;
|
||||
rclcpp::TimerBase::SharedPtr publish_timer_;
|
||||
};
|
||||
|
||||
/**
|
||||
* MessageWithHeader publisher node: used to publish MessageWithHeader with `header` value set
|
||||
*/
|
||||
class MessageWithHeaderPublisher : public rclcpp::Node
|
||||
{
|
||||
public:
|
||||
MessageWithHeaderPublisher(
|
||||
const std::string & name, const std::string & topic,
|
||||
const std::chrono::milliseconds & publish_period = std::chrono::milliseconds{100})
|
||||
: Node(name)
|
||||
{
|
||||
publisher_ = create_publisher<MessageWithHeader>(topic, 10);
|
||||
publish_timer_ = this->create_wall_timer(
|
||||
publish_period, [this]() {
|
||||
this->publish_message();
|
||||
});
|
||||
uniform_dist_ = std::uniform_int_distribution<uint32_t>{1000000, 100000000};
|
||||
}
|
||||
|
||||
virtual ~MessageWithHeaderPublisher() = default;
|
||||
|
||||
private:
|
||||
void publish_message()
|
||||
{
|
||||
std::random_device rd;
|
||||
std::mt19937 gen{rd()};
|
||||
uint32_t d = uniform_dist_(gen);
|
||||
auto msg = MessageWithHeader{};
|
||||
// Subtract ~1 second (add some noise for a non-zero standard deviation)
|
||||
// so the received message age calculation is always > 0
|
||||
msg.header.stamp = this->now() - rclcpp::Duration{1, d};
|
||||
publisher_->publish(msg);
|
||||
}
|
||||
|
||||
rclcpp::Publisher<MessageWithHeader>::SharedPtr publisher_;
|
||||
rclcpp::TimerBase::SharedPtr publish_timer_;
|
||||
std::uniform_int_distribution<uint32_t> uniform_dist_;
|
||||
};
|
||||
|
||||
/**
|
||||
* TransitionMessageStamp publisher node : used to publish MessageWithHeader with `header` value set
|
||||
* TransitionMessageStamp publisher emulator node : used to emulate publishing messages by
|
||||
* directly calling rclcpp::Subscription::handle_message(msg_shared_ptr, message_info).
|
||||
* The message age results change during the test.
|
||||
*/
|
||||
|
||||
class TransitionMessageStampPublisher : public rclcpp::Node
|
||||
template<typename MessageT>
|
||||
class TransitionMessageStampPublisherEmulator : public rclcpp::Node
|
||||
{
|
||||
public:
|
||||
TransitionMessageStampPublisher(
|
||||
const std::string & name, const std::string & topic,
|
||||
TransitionMessageStampPublisherEmulator(
|
||||
const std::string & name,
|
||||
const std::chrono::seconds transition_duration, const std::chrono::seconds message_age_offset,
|
||||
typename rclcpp::Subscription<MessageT>::SharedPtr subscription,
|
||||
const std::chrono::milliseconds & publish_period = std::chrono::milliseconds{100})
|
||||
: Node(name), transition_duration_(transition_duration), message_age_offset_(message_age_offset)
|
||||
: Node(name), transition_duration_(transition_duration), message_age_offset_(message_age_offset),
|
||||
subscription_(std::move(subscription))
|
||||
{
|
||||
publisher_ = create_publisher<MessageWithHeader>(topic, 10);
|
||||
publish_timer_ = this->create_wall_timer(publish_period, [this]() {this->publish_message();});
|
||||
start_time_ = this->now();
|
||||
}
|
||||
@@ -191,84 +148,66 @@ public:
|
||||
private:
|
||||
void publish_message()
|
||||
{
|
||||
auto msg = MessageWithHeader{};
|
||||
std::shared_ptr<void> msg_shared_ptr = std::make_shared<MessageT>();
|
||||
rmw_message_info_t rmw_message_info = rmw_get_zero_initialized_message_info();
|
||||
|
||||
auto now = this->now();
|
||||
auto elapsed_time = now - start_time_;
|
||||
if (elapsed_time < transition_duration_) {
|
||||
// Apply only to the topic statistics in the first half
|
||||
// Subtract offset so message_age is always >= offset.
|
||||
msg.header.stamp = now - message_age_offset_;
|
||||
rmw_message_info.source_timestamp = (now - message_age_offset_).nanoseconds();
|
||||
} else {
|
||||
msg.header.stamp = now;
|
||||
rmw_message_info.source_timestamp = now.nanoseconds();
|
||||
}
|
||||
publisher_->publish(msg);
|
||||
rclcpp::MessageInfo message_info{rmw_message_info};
|
||||
subscription_->handle_message(msg_shared_ptr, message_info);
|
||||
}
|
||||
|
||||
std::chrono::seconds transition_duration_;
|
||||
std::chrono::seconds message_age_offset_;
|
||||
typename rclcpp::Subscription<MessageT>::SharedPtr subscription_;
|
||||
rclcpp::Time start_time_;
|
||||
|
||||
rclcpp::Publisher<MessageWithHeader>::SharedPtr publisher_;
|
||||
rclcpp::TimerBase::SharedPtr publish_timer_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Empty subscriber node: used to create subscriber topic statistics requirements
|
||||
* Message subscriber node: used to create subscriber with enabled topic statistics collectors
|
||||
*
|
||||
*/
|
||||
class EmptySubscriber : public rclcpp::Node
|
||||
template<typename MessageT>
|
||||
class SubscriberWithTopicStatistics : public rclcpp::Node
|
||||
{
|
||||
public:
|
||||
EmptySubscriber(const std::string & name, const std::string & topic)
|
||||
SubscriberWithTopicStatistics(
|
||||
const std::string & name, const std::string & topic,
|
||||
std::chrono::milliseconds publish_period = defaultStatisticsPublishPeriod)
|
||||
: Node(name)
|
||||
{
|
||||
// manually enable topic statistics via options
|
||||
// Manually enable topic statistics via options
|
||||
auto options = rclcpp::SubscriptionOptions();
|
||||
options.topic_stats_options.state = rclcpp::TopicStatisticsState::Enable;
|
||||
options.topic_stats_options.publish_period = publish_period;
|
||||
|
||||
auto callback = [](Empty::UniquePtr msg) {
|
||||
auto callback = [](typename MessageT::UniquePtr msg) {
|
||||
(void) msg;
|
||||
};
|
||||
subscription_ = create_subscription<Empty,
|
||||
std::function<void(Empty::UniquePtr)>>(
|
||||
subscription_ = create_subscription<MessageT,
|
||||
std::function<void(typename MessageT::UniquePtr)>>(
|
||||
topic,
|
||||
rclcpp::QoS(rclcpp::KeepAll()),
|
||||
callback,
|
||||
options);
|
||||
}
|
||||
virtual ~EmptySubscriber() = default;
|
||||
~SubscriberWithTopicStatistics() override = default;
|
||||
|
||||
private:
|
||||
rclcpp::Subscription<Empty>::SharedPtr subscription_;
|
||||
};
|
||||
|
||||
/**
|
||||
* MessageWithHeader subscriber node: used to create subscriber topic statistics requirements
|
||||
*/
|
||||
class MessageWithHeaderSubscriber : public rclcpp::Node
|
||||
{
|
||||
public:
|
||||
MessageWithHeaderSubscriber(const std::string & name, const std::string & topic)
|
||||
: Node(name)
|
||||
typename rclcpp::Subscription<MessageT>::SharedPtr get_subscription()
|
||||
{
|
||||
// manually enable topic statistics via options
|
||||
auto options = rclcpp::SubscriptionOptions();
|
||||
options.topic_stats_options.state = rclcpp::TopicStatisticsState::Enable;
|
||||
options.topic_stats_options.publish_period = defaultStatisticsPublishPeriod;
|
||||
|
||||
auto callback = [](MessageWithHeader::UniquePtr msg) {
|
||||
(void) msg;
|
||||
};
|
||||
subscription_ = create_subscription<MessageWithHeader,
|
||||
std::function<void(MessageWithHeader::UniquePtr)>>(
|
||||
topic,
|
||||
rclcpp::QoS(rclcpp::KeepAll()),
|
||||
callback,
|
||||
options);
|
||||
return subscription_;
|
||||
}
|
||||
virtual ~MessageWithHeaderSubscriber() = default;
|
||||
|
||||
private:
|
||||
rclcpp::Subscription<MessageWithHeader>::SharedPtr subscription_;
|
||||
typename rclcpp::Subscription<MessageT>::SharedPtr subscription_;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -277,43 +216,17 @@ private:
|
||||
class TestSubscriptionTopicStatisticsFixture : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
void SetUp()
|
||||
void SetUp() override
|
||||
{
|
||||
rclcpp::init(0 /* argc */, nullptr /* argv */);
|
||||
}
|
||||
|
||||
void TearDown()
|
||||
void TearDown() override
|
||||
{
|
||||
rclcpp::shutdown();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if a received statistics message is empty (no data was observed)
|
||||
* \param message_to_check
|
||||
*/
|
||||
void check_if_statistics_message_is_empty(const MetricsMessage & message_to_check)
|
||||
{
|
||||
for (const auto & stats_point : message_to_check.statistics) {
|
||||
const auto type = stats_point.data_type;
|
||||
switch (type) {
|
||||
case StatisticDataType::STATISTICS_DATA_TYPE_SAMPLE_COUNT:
|
||||
EXPECT_EQ(0, stats_point.data) << "unexpected sample count" << stats_point.data;
|
||||
break;
|
||||
case StatisticDataType::STATISTICS_DATA_TYPE_AVERAGE:
|
||||
case StatisticDataType::STATISTICS_DATA_TYPE_MINIMUM:
|
||||
case StatisticDataType::STATISTICS_DATA_TYPE_MAXIMUM:
|
||||
case StatisticDataType::STATISTICS_DATA_TYPE_STDDEV:
|
||||
EXPECT_TRUE(std::isnan(stats_point.data)) << "unexpected value" << stats_point.data <<
|
||||
" for type:" << type;
|
||||
break;
|
||||
default:
|
||||
FAIL() << "received unknown statistics type: " << std::dec <<
|
||||
static_cast<unsigned int>(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a received statistics message observed data and contains some calculation
|
||||
* \param message_to_check
|
||||
@@ -348,28 +261,13 @@ void check_if_statistic_message_is_populated(const MetricsMessage & message_to_c
|
||||
/**
|
||||
* Test an invalid argument is thrown for a bad input publish period.
|
||||
*/
|
||||
TEST(TestSubscriptionTopicStatistics, test_invalid_publish_period)
|
||||
TEST_F(TestSubscriptionTopicStatisticsFixture, test_invalid_publish_period)
|
||||
{
|
||||
rclcpp::init(0 /* argc */, nullptr /* argv */);
|
||||
|
||||
auto node = std::make_shared<rclcpp::Node>("test_period_node");
|
||||
|
||||
auto options = rclcpp::SubscriptionOptions();
|
||||
options.topic_stats_options.state = rclcpp::TopicStatisticsState::Enable;
|
||||
options.topic_stats_options.publish_period = std::chrono::milliseconds(0);
|
||||
|
||||
auto callback = [](Empty::UniquePtr msg) {
|
||||
(void) msg;
|
||||
};
|
||||
|
||||
ASSERT_THROW(
|
||||
(node->create_subscription<Empty, std::function<void(Empty::UniquePtr)>>(
|
||||
"should_throw_invalid_arg",
|
||||
rclcpp::QoS(rclcpp::KeepAll()),
|
||||
callback,
|
||||
options)), std::invalid_argument);
|
||||
|
||||
rclcpp::shutdown();
|
||||
SubscriberWithTopicStatistics<Empty>(
|
||||
"test_period_node", "should_throw_invalid_arg", std::chrono::milliseconds(0)
|
||||
),
|
||||
std::invalid_argument);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -378,7 +276,7 @@ TEST(TestSubscriptionTopicStatistics, test_invalid_publish_period)
|
||||
*/
|
||||
TEST_F(TestSubscriptionTopicStatisticsFixture, test_manual_construction)
|
||||
{
|
||||
auto empty_subscriber = std::make_shared<EmptySubscriber>(
|
||||
auto empty_subscriber = std::make_shared<SubscriberWithTopicStatistics<Empty>>(
|
||||
kTestSubNodeName,
|
||||
kTestSubStatsEmptyTopic);
|
||||
|
||||
@@ -389,7 +287,7 @@ TEST_F(TestSubscriptionTopicStatisticsFixture, test_manual_construction)
|
||||
10);
|
||||
|
||||
// Construct a separate instance
|
||||
auto sub_topic_stats = std::make_unique<TestSubscriptionTopicStatistics<Empty>>(
|
||||
auto sub_topic_stats = std::make_unique<TestSubscriptionTopicStatistics>(
|
||||
empty_subscriber->get_name(),
|
||||
topic_stats_publisher);
|
||||
|
||||
@@ -410,7 +308,7 @@ TEST_F(TestSubscriptionTopicStatisticsFixture, test_manual_construction)
|
||||
TEST_F(TestSubscriptionTopicStatisticsFixture, test_receive_stats_for_message_no_header)
|
||||
{
|
||||
// Create an empty publisher
|
||||
auto empty_publisher = std::make_shared<EmptyPublisher>(
|
||||
auto empty_publisher = std::make_shared<PublisherNode<Empty>>(
|
||||
kTestPubNodeName,
|
||||
kTestSubStatsEmptyTopic);
|
||||
// empty_subscriber has a topic statistics instance as part of its subscription
|
||||
@@ -422,7 +320,7 @@ TEST_F(TestSubscriptionTopicStatisticsFixture, test_receive_stats_for_message_no
|
||||
"/statistics",
|
||||
kNumExpectedMessages);
|
||||
|
||||
auto empty_subscriber = std::make_shared<EmptySubscriber>(
|
||||
auto empty_subscriber = std::make_shared<SubscriberWithTopicStatistics<Empty>>(
|
||||
kTestSubNodeName,
|
||||
kTestSubStatsEmptyTopic);
|
||||
|
||||
@@ -432,74 +330,7 @@ TEST_F(TestSubscriptionTopicStatisticsFixture, test_receive_stats_for_message_no
|
||||
ex.add_node(empty_subscriber);
|
||||
|
||||
// Spin and get future
|
||||
ex.spin_until_future_complete(
|
||||
statistics_listener->GetFuture(),
|
||||
kTestTimeout);
|
||||
|
||||
// Compare message counts, sample count should be the same as published and received count
|
||||
EXPECT_EQ(kNumExpectedMessages, statistics_listener->GetNumberOfMessagesReceived());
|
||||
|
||||
// Check the received message total count
|
||||
const auto received_messages = statistics_listener->GetReceivedMessages();
|
||||
EXPECT_EQ(kNumExpectedMessages, received_messages.size());
|
||||
|
||||
// check the type of statistics that were received and their counts
|
||||
uint64_t message_age_count{0};
|
||||
uint64_t message_period_count{0};
|
||||
|
||||
std::set<std::string> received_metrics;
|
||||
for (const auto & msg : received_messages) {
|
||||
if (msg.metrics_source == "message_age") {
|
||||
message_age_count++;
|
||||
}
|
||||
if (msg.metrics_source == "message_period") {
|
||||
message_period_count++;
|
||||
}
|
||||
}
|
||||
EXPECT_EQ(kNumExpectedMessageAgeMessages, message_age_count);
|
||||
EXPECT_EQ(kNumExpectedMessagePeriodMessages, message_period_count);
|
||||
|
||||
// Check the collected statistics for message period.
|
||||
// Message age statistics will not be calculated because Empty messages
|
||||
// don't have a `header` with timestamp. This means that we expect to receive a `message_age`
|
||||
// and `message_period` message for each empty message published.
|
||||
for (const auto & msg : received_messages) {
|
||||
if (msg.metrics_source == kMessageAgeSourceLabel) {
|
||||
check_if_statistics_message_is_empty(msg);
|
||||
} else if (msg.metrics_source == kMessagePeriodSourceLabel) {
|
||||
check_if_statistic_message_is_populated(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestSubscriptionTopicStatisticsFixture, test_receive_stats_for_message_with_header)
|
||||
{
|
||||
// Create a MessageWithHeader publisher
|
||||
auto msg_with_header_publisher = std::make_shared<MessageWithHeaderPublisher>(
|
||||
kTestPubNodeName,
|
||||
kTestSubStatsTopic);
|
||||
// empty_subscriber has a topic statistics instance as part of its subscription
|
||||
// this will listen to and generate statistics for the empty message
|
||||
|
||||
// Create a listener for topic statistics messages
|
||||
auto statistics_listener = std::make_shared<rclcpp::topic_statistics::MetricsMessageSubscriber>(
|
||||
"test_receive_stats_for_message_with_header",
|
||||
"/statistics",
|
||||
kNumExpectedMessages);
|
||||
|
||||
auto msg_with_header_subscriber = std::make_shared<MessageWithHeaderSubscriber>(
|
||||
kTestSubNodeName,
|
||||
kTestSubStatsTopic);
|
||||
|
||||
rclcpp::executors::SingleThreadedExecutor ex;
|
||||
ex.add_node(msg_with_header_publisher);
|
||||
ex.add_node(statistics_listener);
|
||||
ex.add_node(msg_with_header_subscriber);
|
||||
|
||||
// Spin and get future
|
||||
ex.spin_until_future_complete(
|
||||
statistics_listener->GetFuture(),
|
||||
kTestTimeout);
|
||||
ex.spin_until_future_complete(statistics_listener->GetFuture(), kTestTimeout);
|
||||
|
||||
// Compare message counts, sample count should be the same as published and received count
|
||||
EXPECT_EQ(kNumExpectedMessages, statistics_listener->GetNumberOfMessagesReceived());
|
||||
@@ -524,6 +355,7 @@ TEST_F(TestSubscriptionTopicStatisticsFixture, test_receive_stats_for_message_wi
|
||||
EXPECT_EQ(kNumExpectedMessageAgeMessages, message_age_count);
|
||||
EXPECT_EQ(kNumExpectedMessagePeriodMessages, message_period_count);
|
||||
|
||||
// Check the collected statistics for message period.
|
||||
for (const auto & msg : received_messages) {
|
||||
check_if_statistic_message_is_populated(msg);
|
||||
}
|
||||
@@ -531,23 +363,27 @@ TEST_F(TestSubscriptionTopicStatisticsFixture, test_receive_stats_for_message_wi
|
||||
|
||||
TEST_F(TestSubscriptionTopicStatisticsFixture, test_receive_stats_include_window_reset)
|
||||
{
|
||||
// Create a MessageWithHeader publisher
|
||||
auto msg_with_header_publisher = std::make_shared<TransitionMessageStampPublisher>(
|
||||
kTestPubNodeName, kTestSubStatsTopic, kUnstableMessageAgeWindowDuration,
|
||||
kUnstableMessageAgeOffset);
|
||||
|
||||
// msg_with_header_subscriber has a topic statistics instance as part of its
|
||||
// msg_subscriber_with_topic_statistics has a topic statistics instance as part of its
|
||||
// subscription this will listen to and generate statistics
|
||||
auto msg_with_header_subscriber =
|
||||
std::make_shared<MessageWithHeaderSubscriber>(kTestSubNodeName, kTestSubStatsTopic);
|
||||
auto msg_subscriber_with_topic_statistics =
|
||||
std::make_shared<SubscriberWithTopicStatistics<test_msgs::msg::Strings>>(
|
||||
kTestSubNodeName,
|
||||
kTestSubStatsTopic);
|
||||
|
||||
// Create a message publisher
|
||||
auto msg_publisher =
|
||||
std::make_shared<TransitionMessageStampPublisherEmulator<test_msgs::msg::Strings>>(
|
||||
kTestPubNodeName, kUnstableMessageAgeWindowDuration,
|
||||
kUnstableMessageAgeOffset, msg_subscriber_with_topic_statistics->get_subscription());
|
||||
|
||||
// Create a listener for topic statistics messages
|
||||
auto statistics_listener = std::make_shared<rclcpp::topic_statistics::MetricsMessageSubscriber>(
|
||||
"test_receive_stats_include_window_reset", "/statistics", kNumExpectedMessages);
|
||||
|
||||
rclcpp::executors::SingleThreadedExecutor ex;
|
||||
ex.add_node(msg_with_header_publisher);
|
||||
ex.add_node(msg_publisher);
|
||||
ex.add_node(statistics_listener);
|
||||
ex.add_node(msg_with_header_subscriber);
|
||||
ex.add_node(msg_subscriber_with_topic_statistics);
|
||||
|
||||
// Spin and get future
|
||||
ex.spin_until_future_complete(statistics_listener->GetFuture(), kTestTimeout);
|
||||
|
||||
@@ -3,6 +3,29 @@ Changelog for package rclcpp_action
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
26.0.0 (2024-01-24)
|
||||
-------------------
|
||||
|
||||
25.0.0 (2023-12-26)
|
||||
-------------------
|
||||
* Switch to target_link_libraries. (`#2374 <https://github.com/ros2/rclcpp/issues/2374>`_)
|
||||
* Contributors: Chris Lalancette
|
||||
|
||||
24.0.0 (2023-11-06)
|
||||
-------------------
|
||||
|
||||
23.2.0 (2023-10-09)
|
||||
-------------------
|
||||
|
||||
23.1.0 (2023-10-04)
|
||||
-------------------
|
||||
|
||||
23.0.0 (2023-09-08)
|
||||
-------------------
|
||||
* Update API docs links in package READMEs (`#2302 <https://github.com/ros2/rclcpp/issues/2302>`_)
|
||||
* fix(ClientGoalHandle): Made mutex recursive to prevent deadlocks (`#2267 <https://github.com/ros2/rclcpp/issues/2267>`_)
|
||||
* Contributors: Christophe Bedard, jmachowinski
|
||||
|
||||
22.2.0 (2023-09-07)
|
||||
-------------------
|
||||
* Correct the position of a comment. (`#2290 <https://github.com/ros2/rclcpp/issues/2290>`_)
|
||||
|
||||
@@ -5,6 +5,7 @@ project(rclcpp_action)
|
||||
find_package(ament_cmake_ros REQUIRED)
|
||||
find_package(action_msgs REQUIRED)
|
||||
find_package(rclcpp REQUIRED)
|
||||
find_package(rcl REQUIRED)
|
||||
find_package(rcl_action REQUIRED)
|
||||
find_package(rcpputils REQUIRED)
|
||||
find_package(rosidl_runtime_c REQUIRED)
|
||||
@@ -21,28 +22,26 @@ if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
)
|
||||
endif()
|
||||
|
||||
set(${PROJECT_NAME}_SRCS
|
||||
add_library(${PROJECT_NAME}
|
||||
src/client.cpp
|
||||
src/qos.cpp
|
||||
src/server.cpp
|
||||
src/server_goal_handle.cpp
|
||||
src/types.cpp
|
||||
)
|
||||
|
||||
add_library(${PROJECT_NAME}
|
||||
${${PROJECT_NAME}_SRCS})
|
||||
|
||||
target_include_directories(${PROJECT_NAME}
|
||||
PUBLIC
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
|
||||
"$<INSTALL_INTERFACE:include/${PROJECT_NAME}>")
|
||||
|
||||
ament_target_dependencies(${PROJECT_NAME}
|
||||
"action_msgs"
|
||||
"rcl_action"
|
||||
"rclcpp"
|
||||
"rcpputils"
|
||||
"rosidl_runtime_c"
|
||||
target_link_libraries(${PROJECT_NAME} PUBLIC
|
||||
${action_msgs_TARGETS}
|
||||
rcl::rcl
|
||||
rcl_action::rcl_action
|
||||
rclcpp::rclcpp
|
||||
rosidl_runtime_c::rosidl_runtime_c
|
||||
)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE
|
||||
rcpputils::rcpputils
|
||||
)
|
||||
|
||||
# Causes the visibility macros to use dllexport rather than dllimport,
|
||||
@@ -69,12 +68,7 @@ ament_export_libraries(${PROJECT_NAME})
|
||||
# Export modern CMake targets
|
||||
ament_export_targets(${PROJECT_NAME})
|
||||
|
||||
# specific order: dependents before dependencies
|
||||
ament_export_dependencies(ament_cmake)
|
||||
ament_export_dependencies(action_msgs)
|
||||
ament_export_dependencies(rclcpp)
|
||||
ament_export_dependencies(rcl_action)
|
||||
ament_export_dependencies(rosidl_runtime_c)
|
||||
ament_export_dependencies(action_msgs rcl_action rclcpp rosidl_runtime_c)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
find_package(ament_cmake_gtest REQUIRED)
|
||||
@@ -87,58 +81,52 @@ if(BUILD_TESTING)
|
||||
|
||||
ament_add_gtest(test_client test/test_client.cpp TIMEOUT 180)
|
||||
if(TARGET test_client)
|
||||
ament_target_dependencies(test_client
|
||||
"rcutils"
|
||||
"test_msgs"
|
||||
)
|
||||
target_link_libraries(test_client
|
||||
${PROJECT_NAME}
|
||||
mimick
|
||||
rcl::rcl
|
||||
rcl_action::rcl_action
|
||||
rclcpp::rclcpp
|
||||
rcutils::rcutils
|
||||
${test_msgs_TARGETS}
|
||||
)
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_server test/test_server.cpp TIMEOUT 180)
|
||||
if(TARGET test_server)
|
||||
ament_target_dependencies(test_server
|
||||
"rcpputils"
|
||||
"rcutils"
|
||||
"test_msgs"
|
||||
)
|
||||
target_link_libraries(test_server
|
||||
${PROJECT_NAME}
|
||||
mimick
|
||||
rcl_action::rcl_action
|
||||
rclcpp::rclcpp
|
||||
${test_msgs_TARGETS}
|
||||
)
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_server_goal_handle test/test_server_goal_handle.cpp)
|
||||
if(TARGET test_server_goal_handle)
|
||||
ament_target_dependencies(test_server_goal_handle
|
||||
"rcutils"
|
||||
"test_msgs"
|
||||
)
|
||||
target_link_libraries(test_server_goal_handle
|
||||
${PROJECT_NAME}
|
||||
${action_msgs_TARGETS}
|
||||
mimick
|
||||
rclcpp::rclcpp
|
||||
${test_msgs_TARGETS}
|
||||
)
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_traits test/test_traits.cpp)
|
||||
if(TARGET test_traits)
|
||||
ament_target_dependencies(test_traits
|
||||
"test_msgs"
|
||||
)
|
||||
target_link_libraries(test_traits
|
||||
${PROJECT_NAME}
|
||||
${test_msgs_TARGETS}
|
||||
)
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_types test/test_types.cpp)
|
||||
if(TARGET test_types)
|
||||
ament_target_dependencies(test_types
|
||||
"test_msgs"
|
||||
)
|
||||
target_link_libraries(test_types
|
||||
${PROJECT_NAME}
|
||||
${test_msgs_TARGETS}
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
Adds action APIs for C++.
|
||||
|
||||
Visit the [rclcpp_action API documentation](http://docs.ros2.org/latest/api/rclcpp_action/) for a complete list of its main components and features. For more information about Actions in ROS 2, see the [design document](http://design.ros2.org/articles/actions.html).
|
||||
The link to the latest rclcpp_action API documentation, which includes a complete list of its main components and features, can be found on the rclcpp_action package info page, at the [ROS Index](https://index.ros.org/p/rclcpp_action/).
|
||||
For more information about Actions in ROS 2, see the [design document](http://design.ros2.org/articles/actions.html).
|
||||
|
||||
## Quality Declaration
|
||||
|
||||
|
||||
@@ -163,7 +163,7 @@ private:
|
||||
ResultCallback result_callback_{nullptr};
|
||||
int8_t status_{GoalStatus::STATUS_ACCEPTED};
|
||||
|
||||
std::mutex handle_mutex_;
|
||||
std::recursive_mutex handle_mutex_;
|
||||
};
|
||||
} // namespace rclcpp_action
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ template<typename ActionT>
|
||||
std::shared_future<typename ClientGoalHandle<ActionT>::WrappedResult>
|
||||
ClientGoalHandle<ActionT>::async_get_result()
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(handle_mutex_);
|
||||
std::lock_guard<std::recursive_mutex> guard(handle_mutex_);
|
||||
if (!is_result_aware_) {
|
||||
throw exceptions::UnawareGoalHandleError();
|
||||
}
|
||||
@@ -70,7 +70,7 @@ template<typename ActionT>
|
||||
void
|
||||
ClientGoalHandle<ActionT>::set_result(const WrappedResult & wrapped_result)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(handle_mutex_);
|
||||
std::lock_guard<std::recursive_mutex> guard(handle_mutex_);
|
||||
status_ = static_cast<int8_t>(wrapped_result.code);
|
||||
result_promise_.set_value(wrapped_result);
|
||||
if (result_callback_) {
|
||||
@@ -82,7 +82,7 @@ template<typename ActionT>
|
||||
void
|
||||
ClientGoalHandle<ActionT>::set_feedback_callback(FeedbackCallback callback)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(handle_mutex_);
|
||||
std::lock_guard<std::recursive_mutex> guard(handle_mutex_);
|
||||
feedback_callback_ = callback;
|
||||
}
|
||||
|
||||
@@ -90,7 +90,7 @@ template<typename ActionT>
|
||||
void
|
||||
ClientGoalHandle<ActionT>::set_result_callback(ResultCallback callback)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(handle_mutex_);
|
||||
std::lock_guard<std::recursive_mutex> guard(handle_mutex_);
|
||||
result_callback_ = callback;
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ template<typename ActionT>
|
||||
int8_t
|
||||
ClientGoalHandle<ActionT>::get_status()
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(handle_mutex_);
|
||||
std::lock_guard<std::recursive_mutex> guard(handle_mutex_);
|
||||
return status_;
|
||||
}
|
||||
|
||||
@@ -106,7 +106,7 @@ template<typename ActionT>
|
||||
void
|
||||
ClientGoalHandle<ActionT>::set_status(int8_t status)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(handle_mutex_);
|
||||
std::lock_guard<std::recursive_mutex> guard(handle_mutex_);
|
||||
status_ = status;
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ template<typename ActionT>
|
||||
bool
|
||||
ClientGoalHandle<ActionT>::is_feedback_aware()
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(handle_mutex_);
|
||||
std::lock_guard<std::recursive_mutex> guard(handle_mutex_);
|
||||
return feedback_callback_ != nullptr;
|
||||
}
|
||||
|
||||
@@ -122,7 +122,7 @@ template<typename ActionT>
|
||||
bool
|
||||
ClientGoalHandle<ActionT>::is_result_aware()
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(handle_mutex_);
|
||||
std::lock_guard<std::recursive_mutex> guard(handle_mutex_);
|
||||
return is_result_aware_;
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ template<typename ActionT>
|
||||
bool
|
||||
ClientGoalHandle<ActionT>::set_result_awareness(bool awareness)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(handle_mutex_);
|
||||
std::lock_guard<std::recursive_mutex> guard(handle_mutex_);
|
||||
bool previous = is_result_aware_;
|
||||
is_result_aware_ = awareness;
|
||||
return previous;
|
||||
@@ -140,7 +140,7 @@ template<typename ActionT>
|
||||
void
|
||||
ClientGoalHandle<ActionT>::invalidate(const exceptions::UnawareGoalHandleError & ex)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(handle_mutex_);
|
||||
std::lock_guard<std::recursive_mutex> guard(handle_mutex_);
|
||||
// Guard against multiple calls
|
||||
if (is_invalidated()) {
|
||||
return;
|
||||
@@ -168,7 +168,7 @@ ClientGoalHandle<ActionT>::call_feedback_callback(
|
||||
RCLCPP_ERROR(rclcpp::get_logger("rclcpp_action"), "Sent feedback to wrong goal handle.");
|
||||
return;
|
||||
}
|
||||
std::lock_guard<std::mutex> guard(handle_mutex_);
|
||||
std::lock_guard<std::recursive_mutex> guard(handle_mutex_);
|
||||
if (nullptr == feedback_callback_) {
|
||||
// Normal, some feedback messages may arrive after the goal result.
|
||||
RCLCPP_DEBUG(rclcpp::get_logger("rclcpp_action"), "Received feedback but goal ignores it.");
|
||||
|
||||
@@ -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>22.2.0</version>
|
||||
<version>26.0.0</version>
|
||||
<description>Adds action APIs for C++.</description>
|
||||
|
||||
<maintainer email="ivanpauno@ekumenlabs.com">Ivan Paunovic</maintainer>
|
||||
@@ -23,6 +23,7 @@
|
||||
<depend>action_msgs</depend>
|
||||
<depend>rclcpp</depend>
|
||||
<depend>rcl_action</depend>
|
||||
<depend>rcl</depend>
|
||||
<depend>rcpputils</depend>
|
||||
|
||||
<depend>ament_cmake</depend>
|
||||
|
||||
@@ -9,8 +9,7 @@ add_performance_test(
|
||||
benchmark_action_client.cpp
|
||||
TIMEOUT 240)
|
||||
if(TARGET benchmark_action_client)
|
||||
target_link_libraries(benchmark_action_client ${PROJECT_NAME})
|
||||
ament_target_dependencies(benchmark_action_client rclcpp test_msgs)
|
||||
target_link_libraries(benchmark_action_client ${PROJECT_NAME} rclcpp::rclcpp ${test_msgs_TARGETS})
|
||||
endif()
|
||||
|
||||
add_performance_test(
|
||||
@@ -18,6 +17,5 @@ add_performance_test(
|
||||
benchmark_action_server.cpp
|
||||
TIMEOUT 120)
|
||||
if(TARGET benchmark_action_server)
|
||||
target_link_libraries(benchmark_action_server ${PROJECT_NAME})
|
||||
ament_target_dependencies(benchmark_action_server rclcpp test_msgs)
|
||||
target_link_libraries(benchmark_action_server ${PROJECT_NAME} rclcpp::rclcpp ${test_msgs_TARGETS})
|
||||
endif()
|
||||
|
||||
@@ -852,6 +852,86 @@ TEST_F(TestClientAgainstServer, async_cancel_some_goals_with_callback)
|
||||
EXPECT_EQ(rclcpp_action::GoalStatus::STATUS_CANCELED, goal_handle0->get_status());
|
||||
}
|
||||
|
||||
TEST_F(TestClientAgainstServer, deadlock_in_callbacks)
|
||||
{
|
||||
std::atomic<bool> feedback_callback_called = false;
|
||||
std::atomic<bool> response_callback_called = false;
|
||||
std::atomic<bool> result_callback_called = false;
|
||||
std::atomic<bool> no_deadlock = false;
|
||||
|
||||
std::thread tr = std::thread(
|
||||
[&]() {
|
||||
auto action_client = rclcpp_action::create_client<ActionType>(client_node, action_name);
|
||||
ASSERT_TRUE(action_client->wait_for_action_server(WAIT_FOR_SERVER_TIMEOUT));
|
||||
|
||||
ActionGoal goal;
|
||||
|
||||
using GoalHandle = rclcpp_action::ClientGoalHandle<ActionType>;
|
||||
rclcpp_action::Client<ActionType>::SendGoalOptions ops;
|
||||
ops.feedback_callback =
|
||||
[&feedback_callback_called](const GoalHandle::SharedPtr handle,
|
||||
ActionType::Feedback::ConstSharedPtr) {
|
||||
// call functions on the handle that acquire the lock
|
||||
handle->get_status();
|
||||
handle->is_feedback_aware();
|
||||
handle->is_result_aware();
|
||||
|
||||
feedback_callback_called = true;
|
||||
};
|
||||
ops.goal_response_callback = [&response_callback_called](
|
||||
const GoalHandle::SharedPtr & handle) {
|
||||
// call functions on the handle that acquire the lock
|
||||
handle->get_status();
|
||||
handle->is_feedback_aware();
|
||||
handle->is_result_aware();
|
||||
|
||||
response_callback_called = true;
|
||||
};
|
||||
ops.result_callback = [&result_callback_called](
|
||||
const GoalHandle::WrappedResult &) {
|
||||
result_callback_called = true;
|
||||
};
|
||||
|
||||
goal.order = 6;
|
||||
auto future_goal_handle = action_client->async_send_goal(goal, ops);
|
||||
dual_spin_until_future_complete(future_goal_handle);
|
||||
auto goal_handle = future_goal_handle.get();
|
||||
|
||||
ASSERT_TRUE(goal_handle);
|
||||
|
||||
ASSERT_EQ(RCL_RET_OK, rcl_set_ros_time_override(clock.get_clock_handle(), RCL_S_TO_NS(2)));
|
||||
|
||||
auto result_future = action_client->async_get_result(goal_handle);
|
||||
dual_spin_until_future_complete(result_future);
|
||||
|
||||
EXPECT_TRUE(result_future.valid());
|
||||
auto result = result_future.get();
|
||||
|
||||
no_deadlock = true;
|
||||
});
|
||||
|
||||
auto start_time = std::chrono::system_clock::now();
|
||||
|
||||
while (std::chrono::system_clock::now() - start_time < std::chrono::milliseconds(2000) &&
|
||||
!no_deadlock)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
|
||||
if (no_deadlock) {
|
||||
tr.join();
|
||||
} else {
|
||||
// In case of a failure, the thread is assumed to be in a deadlock.
|
||||
// We detach the thread so we don't block further tests.
|
||||
tr.detach();
|
||||
}
|
||||
|
||||
EXPECT_TRUE(no_deadlock);
|
||||
EXPECT_TRUE(response_callback_called);
|
||||
EXPECT_TRUE(result_callback_called);
|
||||
EXPECT_TRUE(feedback_callback_called);
|
||||
}
|
||||
|
||||
TEST_F(TestClientAgainstServer, send_rcl_errors)
|
||||
{
|
||||
auto action_client = rclcpp_action::create_client<ActionType>(client_node, action_name);
|
||||
|
||||
@@ -2,6 +2,32 @@
|
||||
Changelog for package rclcpp_components
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
26.0.0 (2024-01-24)
|
||||
-------------------
|
||||
|
||||
25.0.0 (2023-12-26)
|
||||
-------------------
|
||||
* Switch to target_link_libraries. (`#2374 <https://github.com/ros2/rclcpp/issues/2374>`_)
|
||||
* feat(rclcpp_components): support events executor in node main template (`#2366 <https://github.com/ros2/rclcpp/issues/2366>`_)
|
||||
* fix(rclcpp_components): increase the service queue sizes in component_container (`#2363 <https://github.com/ros2/rclcpp/issues/2363>`_)
|
||||
* Contributors: Chris Lalancette, Daisuke Nishimatsu, M. Fatih Cırıt
|
||||
|
||||
24.0.0 (2023-11-06)
|
||||
-------------------
|
||||
|
||||
23.2.0 (2023-10-09)
|
||||
-------------------
|
||||
|
||||
23.1.0 (2023-10-04)
|
||||
-------------------
|
||||
* Add missing header required by the rclcpp::NodeOptions type (`#2324 <https://github.com/ros2/rclcpp/issues/2324>`_)
|
||||
* Contributors: Ignacio Vizzo
|
||||
|
||||
23.0.0 (2023-09-08)
|
||||
-------------------
|
||||
* Update API docs links in package READMEs (`#2302 <https://github.com/ros2/rclcpp/issues/2302>`_)
|
||||
* Contributors: Christophe Bedard
|
||||
|
||||
22.2.0 (2023-09-07)
|
||||
-------------------
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ find_package(composition_interfaces REQUIRED)
|
||||
find_package(rclcpp REQUIRED)
|
||||
find_package(rcpputils REQUIRED)
|
||||
|
||||
# Add an interface library that can be dependend upon by libraries who register components
|
||||
# Add an interface library that can be depended upon by libraries who register components
|
||||
add_library(component INTERFACE)
|
||||
target_include_directories(component INTERFACE
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
|
||||
@@ -38,12 +38,14 @@ add_library(
|
||||
target_include_directories(component_manager PUBLIC
|
||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
|
||||
"$<INSTALL_INTERFACE:include/${PROJECT_NAME}>")
|
||||
ament_target_dependencies(component_manager
|
||||
"ament_index_cpp"
|
||||
"class_loader"
|
||||
"composition_interfaces"
|
||||
"rclcpp"
|
||||
"rcpputils"
|
||||
target_link_libraries(component_manager PUBLIC
|
||||
${composition_interfaces_TARGETS}
|
||||
rclcpp::rclcpp
|
||||
)
|
||||
target_link_libraries(component_manager PRIVATE
|
||||
ament_index_cpp::ament_index_cpp
|
||||
class_loader::class_loader
|
||||
rcpputils::rcpputils
|
||||
)
|
||||
target_compile_definitions(component_manager
|
||||
PRIVATE "RCLCPP_COMPONENTS_BUILDING_LIBRARY")
|
||||
@@ -52,10 +54,7 @@ add_executable(
|
||||
component_container
|
||||
src/component_container.cpp
|
||||
)
|
||||
target_link_libraries(component_container component_manager)
|
||||
ament_target_dependencies(component_container
|
||||
"rclcpp"
|
||||
)
|
||||
target_link_libraries(component_container component_manager rclcpp::rclcpp)
|
||||
|
||||
set(node_main_template_install_dir "share/${PROJECT_NAME}")
|
||||
install(FILES
|
||||
@@ -66,20 +65,13 @@ add_executable(
|
||||
component_container_mt
|
||||
src/component_container_mt.cpp
|
||||
)
|
||||
target_link_libraries(component_container_mt component_manager)
|
||||
ament_target_dependencies(component_container_mt
|
||||
"rclcpp"
|
||||
)
|
||||
target_link_libraries(component_container_mt component_manager rclcpp::rclcpp)
|
||||
|
||||
add_executable(
|
||||
component_container_isolated
|
||||
src/component_container_isolated.cpp
|
||||
)
|
||||
target_link_libraries(component_container_isolated component_manager)
|
||||
ament_target_dependencies(component_container_isolated
|
||||
"rclcpp"
|
||||
)
|
||||
|
||||
target_link_libraries(component_container_isolated component_manager rclcpp::rclcpp)
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
target_link_libraries(component_container "stdc++fs")
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
Package containing tools for dynamically loadable components.
|
||||
|
||||
Visit the [rclcpp_components API documentation](http://docs.ros2.org/latest/api/rclcpp_components/) for a complete list of its main components and features.
|
||||
The link to the latest rclcpp_components API documentation, which includes a complete list of its main components and features, can be found on the rclcpp_components package info page, at the [ROS Index](https://index.ros.org/p/rclcpp_components/).
|
||||
|
||||
## Quality Declaration
|
||||
|
||||
|
||||
@@ -70,10 +70,11 @@ macro(rclcpp_components_register_node target)
|
||||
file(GENERATE OUTPUT ${PROJECT_BINARY_DIR}/rclcpp_components/node_main_${node}.cpp
|
||||
INPUT ${PROJECT_BINARY_DIR}/rclcpp_components/node_main_configured_${node}.cpp.in)
|
||||
add_executable(${node} ${PROJECT_BINARY_DIR}/rclcpp_components/node_main_${node}.cpp)
|
||||
ament_target_dependencies(${node}
|
||||
"rclcpp"
|
||||
"class_loader"
|
||||
"rclcpp_components")
|
||||
target_link_libraries(${node}
|
||||
class_loader::class_loader
|
||||
rclcpp::rclcpp
|
||||
rclcpp_components::component
|
||||
)
|
||||
install(TARGETS
|
||||
${node}
|
||||
DESTINATION lib/${PROJECT_NAME})
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#ifndef RCLCPP_COMPONENTS__NODE_FACTORY_HPP__
|
||||
#define RCLCPP_COMPONENTS__NODE_FACTORY_HPP__
|
||||
|
||||
#include "rclcpp/node_options.hpp"
|
||||
#include "rclcpp_components/node_instance_wrapper.hpp"
|
||||
|
||||
namespace rclcpp_components
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user