Compare commits
50 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b178c47134 | ||
|
|
81049c42c0 | ||
|
|
7728d8a38c | ||
|
|
b6d18ccc81 | ||
|
|
9b47f36080 | ||
|
|
cf838d1eb7 | ||
|
|
89119c6422 | ||
|
|
dfb144d3cb | ||
|
|
64c0f86f14 | ||
|
|
925460dcfb | ||
|
|
458967bb56 | ||
|
|
1fff8cbac1 | ||
|
|
a6e80fcaea | ||
|
|
f153cf7173 | ||
|
|
d5301c1c7c | ||
|
|
4feecc5945 | ||
|
|
17841d6b7c | ||
|
|
ccd5b49186 | ||
|
|
4dbc7192d2 | ||
|
|
65188b021d | ||
|
|
25f196989c | ||
|
|
78ab3731c9 | ||
|
|
41a99b64d3 | ||
|
|
871c375da7 | ||
|
|
4a5eed968c | ||
|
|
dc3c36c7f0 | ||
|
|
9be3e08cd4 | ||
|
|
9aacc6d895 | ||
|
|
c1d7c6b7be | ||
|
|
d31ea14985 | ||
|
|
94ea26bffb | ||
|
|
b214324bf2 | ||
|
|
cd063575ff | ||
|
|
c7d01d7bf3 | ||
|
|
8c48dbede7 | ||
|
|
f8d609496e | ||
|
|
207bcc5de3 | ||
|
|
378657865e | ||
|
|
61312b0576 | ||
|
|
0ccac1e3bd | ||
|
|
5a5a1fe530 | ||
|
|
890b724e6f | ||
|
|
dff36c2f67 | ||
|
|
2069594cc2 | ||
|
|
e7c463dc74 | ||
|
|
2bee266adf | ||
|
|
0ae3da49e7 | ||
|
|
91198ef917 | ||
|
|
411e748632 | ||
|
|
4532d9cf78 |
@@ -2,6 +2,49 @@
|
||||
Changelog for package rclcpp
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
0.8.0 (2019-09-26)
|
||||
------------------
|
||||
* clean up publisher and subscription creation logic (`#867 <https://github.com/ros2/rclcpp/issues/867>`_)
|
||||
* Take parameter overrides provided through the CLI. (`#865 <https://github.com/ros2/rclcpp/issues/865>`_)
|
||||
* add more context to exception message (`#858 <https://github.com/ros2/rclcpp/issues/858>`_)
|
||||
* remove features and related code which were deprecated in dashing (`#852 <https://github.com/ros2/rclcpp/issues/852>`_)
|
||||
* check valid timer handler 1st to reduce the time window for scan. (`#841 <https://github.com/ros2/rclcpp/issues/841>`_)
|
||||
* Add throwing parameter name if parameter is not set (`#833 <https://github.com/ros2/rclcpp/issues/833>`_)
|
||||
* Fix typo in deprecated warning. (`#848 <https://github.com/ros2/rclcpp/issues/848>`_)
|
||||
* Fail on invalid and unknown ROS specific arguments (`#842 <https://github.com/ros2/rclcpp/issues/842>`_)
|
||||
* Force explicit --ros-args in NodeOptions::arguments(). (`#845 <https://github.com/ros2/rclcpp/issues/845>`_)
|
||||
* Use of -r/--remap flags where appropriate. (`#834 <https://github.com/ros2/rclcpp/issues/834>`_)
|
||||
* Fix hang with timers in MultiThreadedExecutor (`#835 <https://github.com/ros2/rclcpp/issues/835>`_) (`#836 <https://github.com/ros2/rclcpp/issues/836>`_)
|
||||
* add mutex in add/remove_node and wait_for_work to protect concurrent use/change of memory_strategy\_ (`#837 <https://github.com/ros2/rclcpp/issues/837>`_)
|
||||
* Crash in callback group pointer vector iterator (`#814 <https://github.com/ros2/rclcpp/issues/814>`_)
|
||||
* Wrap documentation examples in code blocks (`#830 <https://github.com/ros2/rclcpp/issues/830>`_)
|
||||
* add callback group as member variable and constructor arg (`#811 <https://github.com/ros2/rclcpp/issues/811>`_)
|
||||
* Fix get_node_interfaces functions taking a pointer (`#821 <https://github.com/ros2/rclcpp/issues/821>`_)
|
||||
* Delete unnecessary call for get_node_by_group (`#823 <https://github.com/ros2/rclcpp/issues/823>`_)
|
||||
* Allow passing logger by const ref (`#820 <https://github.com/ros2/rclcpp/issues/820>`_)
|
||||
* Explain return value of spin_until_future_complete (`#792 <https://github.com/ros2/rclcpp/issues/792>`_)
|
||||
* Adapt to '--ros-args ... [--]'-based ROS args extraction (`#816 <https://github.com/ros2/rclcpp/issues/816>`_)
|
||||
* Add line break after first open paren in multiline function call (`#785 <https://github.com/ros2/rclcpp/issues/785>`_)
|
||||
* remove mock msgs from rclcpp (`#800 <https://github.com/ros2/rclcpp/issues/800>`_)
|
||||
* Make TimeSource ignore use_sim_time events coming from other nodes. (`#799 <https://github.com/ros2/rclcpp/issues/799>`_)
|
||||
* Allow registering multiple on_parameters_set_callback (`#772 <https://github.com/ros2/rclcpp/issues/772>`_)
|
||||
* Add free function for creating service clients (`#788 <https://github.com/ros2/rclcpp/issues/788>`_)
|
||||
* Include missing rcl headers in use. (`#782 <https://github.com/ros2/rclcpp/issues/782>`_)
|
||||
* Switch the NodeParameters lock to recursive. (`#781 <https://github.com/ros2/rclcpp/issues/781>`_)
|
||||
* changed on_parameter_event qos profile to rmw_qos_profile_parameter_events (`#774 <https://github.com/ros2/rclcpp/issues/774>`_)
|
||||
* Adding a factory method to create a Duration from seconds (`#567 <https://github.com/ros2/rclcpp/issues/567>`_)
|
||||
* Fix a comparison with a sign mismatch (`#771 <https://github.com/ros2/rclcpp/issues/771>`_)
|
||||
* delete superfluous spaces (`#770 <https://github.com/ros2/rclcpp/issues/770>`_)
|
||||
* Use params from node '/\*\*' from parameter YAML file (`#762 <https://github.com/ros2/rclcpp/issues/762>`_)
|
||||
* Add ignore override argument to declare parameter (`#767 <https://github.com/ros2/rclcpp/issues/767>`_)
|
||||
* use default parameter descriptor in parameters interface (`#765 <https://github.com/ros2/rclcpp/issues/765>`_)
|
||||
* Added support for const member functions (`#763 <https://github.com/ros2/rclcpp/issues/763>`_)
|
||||
* add get_actual_qos() feature to subscriptions (`#754 <https://github.com/ros2/rclcpp/issues/754>`_)
|
||||
* Ignore parameters overrides in set parameter methods when allowing undeclared parameters (`#756 <https://github.com/ros2/rclcpp/issues/756>`_)
|
||||
* Add rclcpp::create_timer() (`#757 <https://github.com/ros2/rclcpp/issues/757>`_)
|
||||
* checking origin of intra-process msg before taking them (`#753 <https://github.com/ros2/rclcpp/issues/753>`_)
|
||||
* Contributors: Alberto Soragna, Carl Delsey, Chris Lalancette, Dan Rose, Dirk Thomas, Esteve Fernandez, Guillaume Autran, Jacob Perron, Karsten Knese, Luca Della Vedova, M. M, Michel Hidalgo, Scott K Logan, Shane Loretz, Todd Malsbary, William Woodall, bpwilcox, fujitatomoya, ivanpauno
|
||||
|
||||
0.7.5 (2019-05-30)
|
||||
------------------
|
||||
* Avoid 'Intra process message no longer being stored when trying to handle it' warning (`#749 <https://github.com/ros2/rclcpp/issues/749>`_)
|
||||
|
||||
@@ -7,6 +7,7 @@ find_package(builtin_interfaces REQUIRED)
|
||||
find_package(rcl REQUIRED)
|
||||
find_package(rcl_interfaces REQUIRED)
|
||||
find_package(rcl_yaml_param_parser REQUIRED)
|
||||
find_package(rcpputils REQUIRED)
|
||||
find_package(rmw REQUIRED)
|
||||
find_package(rmw_implementation REQUIRED)
|
||||
find_package(rosgraph_msgs REQUIRED)
|
||||
@@ -106,6 +107,7 @@ add_library(${PROJECT_NAME}
|
||||
ament_target_dependencies(${PROJECT_NAME}
|
||||
"rcl"
|
||||
"rcl_yaml_param_parser"
|
||||
"rcpputils"
|
||||
"builtin_interfaces"
|
||||
"rosgraph_msgs"
|
||||
"rosidl_typesupport_cpp"
|
||||
@@ -129,6 +131,7 @@ ament_export_libraries(${PROJECT_NAME})
|
||||
|
||||
ament_export_dependencies(ament_cmake)
|
||||
ament_export_dependencies(rcl)
|
||||
ament_export_dependencies(rcpputils)
|
||||
ament_export_dependencies(builtin_interfaces)
|
||||
ament_export_dependencies(rosgraph_msgs)
|
||||
ament_export_dependencies(rosidl_typesupport_cpp)
|
||||
@@ -143,8 +146,12 @@ if(BUILD_TESTING)
|
||||
|
||||
find_package(rmw_implementation_cmake REQUIRED)
|
||||
|
||||
find_package(test_msgs REQUIRED)
|
||||
|
||||
include(cmake/rclcpp_add_build_failure_test.cmake)
|
||||
|
||||
add_definitions(-DTEST_RESOURCES_DIRECTORY="${CMAKE_CURRENT_BINARY_DIR}/test/resources")
|
||||
|
||||
ament_add_gtest(test_client test/test_client.cpp)
|
||||
if(TARGET test_client)
|
||||
ament_target_dependencies(test_client
|
||||
@@ -155,6 +162,18 @@ if(BUILD_TESTING)
|
||||
)
|
||||
target_link_libraries(test_client ${PROJECT_NAME})
|
||||
endif()
|
||||
ament_add_gtest(test_create_timer test/test_create_timer.cpp)
|
||||
if(TARGET test_create_timer)
|
||||
ament_target_dependencies(test_create_timer
|
||||
"rcl_interfaces"
|
||||
"rmw"
|
||||
"rcl"
|
||||
"rosidl_generator_cpp"
|
||||
"rosidl_typesupport_cpp"
|
||||
)
|
||||
target_link_libraries(test_create_timer ${PROJECT_NAME})
|
||||
target_include_directories(test_create_timer PRIVATE test/)
|
||||
endif()
|
||||
ament_add_gtest(test_expand_topic_or_service_name test/test_expand_topic_or_service_name.cpp)
|
||||
if(TARGET test_expand_topic_or_service_name)
|
||||
ament_target_dependencies(test_expand_topic_or_service_name
|
||||
@@ -198,6 +217,7 @@ if(BUILD_TESTING)
|
||||
if(TARGET test_node)
|
||||
ament_target_dependencies(test_node
|
||||
"rcl_interfaces"
|
||||
"rcpputils"
|
||||
"rmw"
|
||||
"rosidl_generator_cpp"
|
||||
"rosidl_typesupport_cpp"
|
||||
@@ -242,6 +262,11 @@ if(BUILD_TESTING)
|
||||
)
|
||||
target_link_libraries(test_node_global_args ${PROJECT_NAME})
|
||||
endif()
|
||||
ament_add_gtest(test_node_options test/test_node_options.cpp)
|
||||
if(TARGET test_node_options)
|
||||
ament_target_dependencies(test_node_options "rcl")
|
||||
target_link_libraries(test_node_options ${PROJECT_NAME})
|
||||
endif()
|
||||
ament_add_gtest(test_parameter_client test/test_parameter_client.cpp)
|
||||
if(TARGET test_parameter_client)
|
||||
ament_target_dependencies(test_parameter_client
|
||||
@@ -344,7 +369,6 @@ if(BUILD_TESTING)
|
||||
)
|
||||
target_link_libraries(test_subscription_publisher_count_api ${PROJECT_NAME})
|
||||
endif()
|
||||
find_package(test_msgs REQUIRED)
|
||||
ament_add_gtest(test_subscription_traits test/test_subscription_traits.cpp)
|
||||
if(TARGET test_subscription_traits)
|
||||
ament_target_dependencies(test_subscription_traits
|
||||
@@ -360,38 +384,17 @@ if(BUILD_TESTING)
|
||||
target_link_libraries(test_find_weak_nodes ${PROJECT_NAME})
|
||||
endif()
|
||||
|
||||
get_default_rmw_implementation(default_rmw)
|
||||
find_package(${default_rmw} REQUIRED)
|
||||
get_rmw_typesupport(typesupport_impls_cpp "${default_rmw}" LANGUAGE "cpp")
|
||||
get_rmw_typesupport(typesupport_impls_c "${default_rmw}" LANGUAGE "c")
|
||||
set(mock_msg_files
|
||||
"test/mock_msgs/srv/Mock.srv")
|
||||
rosidl_generate_interfaces(mock_msgs
|
||||
${mock_msg_files}
|
||||
LIBRARY_NAME "rclcpp"
|
||||
SKIP_INSTALL)
|
||||
|
||||
set(append_library_dirs "${CMAKE_CURRENT_BINARY_DIR}")
|
||||
if(WIN32)
|
||||
set(append_library_dirs "${append_library_dirs}/$<CONFIG>")
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_externally_defined_services test/test_externally_defined_services.cpp
|
||||
APPEND_LIBRARY_DIRS "${append_library_dirs}")
|
||||
if(TARGET test_externally_defined_services)
|
||||
ament_target_dependencies(test_externally_defined_services
|
||||
"rcl"
|
||||
)
|
||||
target_link_libraries(test_externally_defined_services ${PROJECT_NAME})
|
||||
foreach(typesupport_impl_cpp ${typesupport_impls_cpp})
|
||||
rosidl_target_interfaces(test_externally_defined_services
|
||||
mock_msgs ${typesupport_impl_cpp})
|
||||
endforeach()
|
||||
foreach(typesupport_impl_c ${typesupport_impls_c})
|
||||
rosidl_target_interfaces(test_externally_defined_services
|
||||
mock_msgs ${typesupport_impl_c})
|
||||
endforeach()
|
||||
endif()
|
||||
ament_add_gtest(test_externally_defined_services test/test_externally_defined_services.cpp)
|
||||
ament_target_dependencies(test_externally_defined_services
|
||||
"rcl"
|
||||
"test_msgs"
|
||||
)
|
||||
target_link_libraries(test_externally_defined_services ${PROJECT_NAME})
|
||||
|
||||
ament_add_gtest(test_duration test/test_duration.cpp
|
||||
APPEND_LIBRARY_DIRS "${append_library_dirs}")
|
||||
@@ -463,16 +466,10 @@ if(BUILD_TESTING)
|
||||
target_link_libraries(test_multi_threaded_executor ${PROJECT_NAME})
|
||||
endif()
|
||||
|
||||
ament_add_gtest(test_local_parameters test/test_local_parameters.cpp)
|
||||
if(TARGET test_local_parameters)
|
||||
ament_target_dependencies(test_local_parameters
|
||||
"rcl_interfaces"
|
||||
"rmw"
|
||||
"rosidl_generator_cpp"
|
||||
"rosidl_typesupport_cpp"
|
||||
)
|
||||
target_link_libraries(test_local_parameters ${PROJECT_NAME})
|
||||
endif()
|
||||
# Install test resources
|
||||
install(
|
||||
DIRECTORY test/resources
|
||||
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/test)
|
||||
endif()
|
||||
|
||||
ament_package()
|
||||
|
||||
@@ -184,10 +184,12 @@ public:
|
||||
} else if (const_shared_ptr_with_info_callback_) {
|
||||
const_shared_ptr_with_info_callback_(message, message_info);
|
||||
} else {
|
||||
if (unique_ptr_callback_ || unique_ptr_with_info_callback_ ||
|
||||
if (
|
||||
unique_ptr_callback_ || unique_ptr_with_info_callback_ ||
|
||||
shared_ptr_callback_ || shared_ptr_with_info_callback_)
|
||||
{
|
||||
throw std::runtime_error("unexpected dispatch_intra_process const shared "
|
||||
throw std::runtime_error(
|
||||
"unexpected dispatch_intra_process const shared "
|
||||
"message call with no const shared_ptr callback");
|
||||
} else {
|
||||
throw std::runtime_error("unexpected message without any callback set");
|
||||
@@ -209,7 +211,8 @@ public:
|
||||
} else if (unique_ptr_with_info_callback_) {
|
||||
unique_ptr_with_info_callback_(std::move(message), message_info);
|
||||
} else if (const_shared_ptr_callback_ || const_shared_ptr_with_info_callback_) {
|
||||
throw std::runtime_error("unexpected dispatch_intra_process unique message call"
|
||||
throw std::runtime_error(
|
||||
"unexpected dispatch_intra_process unique message call"
|
||||
" with const shared_ptr callback");
|
||||
} else {
|
||||
throw std::runtime_error("unexpected message without any callback set");
|
||||
|
||||
@@ -21,9 +21,9 @@
|
||||
#include <vector>
|
||||
|
||||
#include "rclcpp/client.hpp"
|
||||
#include "rclcpp/publisher.hpp"
|
||||
#include "rclcpp/publisher_base.hpp"
|
||||
#include "rclcpp/service.hpp"
|
||||
#include "rclcpp/subscription.hpp"
|
||||
#include "rclcpp/subscription_base.hpp"
|
||||
#include "rclcpp/timer.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
#include "rclcpp/waitable.hpp"
|
||||
@@ -62,25 +62,40 @@ public:
|
||||
RCLCPP_PUBLIC
|
||||
explicit CallbackGroup(CallbackGroupType group_type);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
const std::vector<rclcpp::SubscriptionBase::WeakPtr> &
|
||||
get_subscription_ptrs() const;
|
||||
template<typename Function>
|
||||
rclcpp::SubscriptionBase::SharedPtr
|
||||
find_subscription_ptrs_if(Function func) const
|
||||
{
|
||||
return _find_ptrs_if_impl<rclcpp::SubscriptionBase, Function>(func, subscription_ptrs_);
|
||||
}
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
const std::vector<rclcpp::TimerBase::WeakPtr> &
|
||||
get_timer_ptrs() const;
|
||||
template<typename Function>
|
||||
rclcpp::TimerBase::SharedPtr
|
||||
find_timer_ptrs_if(Function func) const
|
||||
{
|
||||
return _find_ptrs_if_impl<rclcpp::TimerBase, Function>(func, timer_ptrs_);
|
||||
}
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
const std::vector<rclcpp::ServiceBase::WeakPtr> &
|
||||
get_service_ptrs() const;
|
||||
template<typename Function>
|
||||
rclcpp::ServiceBase::SharedPtr
|
||||
find_service_ptrs_if(Function func) const
|
||||
{
|
||||
return _find_ptrs_if_impl<rclcpp::ServiceBase, Function>(func, service_ptrs_);
|
||||
}
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
const std::vector<rclcpp::ClientBase::WeakPtr> &
|
||||
get_client_ptrs() const;
|
||||
template<typename Function>
|
||||
rclcpp::ClientBase::SharedPtr
|
||||
find_client_ptrs_if(Function func) const
|
||||
{
|
||||
return _find_ptrs_if_impl<rclcpp::ClientBase, Function>(func, client_ptrs_);
|
||||
}
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
const std::vector<rclcpp::Waitable::WeakPtr> &
|
||||
get_waitable_ptrs() const;
|
||||
template<typename Function>
|
||||
rclcpp::Waitable::SharedPtr
|
||||
find_waitable_ptrs_if(Function func) const
|
||||
{
|
||||
return _find_ptrs_if_impl<rclcpp::Waitable, Function>(func, waitable_ptrs_);
|
||||
}
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
std::atomic_bool &
|
||||
@@ -130,6 +145,21 @@ protected:
|
||||
std::vector<rclcpp::ClientBase::WeakPtr> client_ptrs_;
|
||||
std::vector<rclcpp::Waitable::WeakPtr> waitable_ptrs_;
|
||||
std::atomic_bool can_be_taken_from_;
|
||||
|
||||
private:
|
||||
template<typename TypeT, typename Function>
|
||||
typename TypeT::SharedPtr _find_ptrs_if_impl(
|
||||
Function func, const std::vector<typename TypeT::WeakPtr> & vect_ptrs) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
for (auto & weak_ptr : vect_ptrs) {
|
||||
auto ref_ptr = weak_ptr.lock();
|
||||
if (ref_ptr && func(ref_ptr)) {
|
||||
return ref_ptr;
|
||||
}
|
||||
}
|
||||
return typename TypeT::SharedPtr();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace callback_group
|
||||
|
||||
56
rclcpp/include/rclcpp/create_client.hpp
Normal file
56
rclcpp/include/rclcpp/create_client.hpp
Normal file
@@ -0,0 +1,56 @@
|
||||
// Copyright 2019 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__CREATE_CLIENT_HPP_
|
||||
#define RCLCPP__CREATE_CLIENT_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_services_interface.hpp"
|
||||
#include "rmw/rmw.h"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
/// Create a service client with a given type.
|
||||
/// \internal
|
||||
template<typename ServiceT>
|
||||
typename rclcpp::Client<ServiceT>::SharedPtr
|
||||
create_client(
|
||||
std::shared_ptr<node_interfaces::NodeBaseInterface> node_base,
|
||||
std::shared_ptr<node_interfaces::NodeGraphInterface> node_graph,
|
||||
std::shared_ptr<node_interfaces::NodeServicesInterface> node_services,
|
||||
const std::string & service_name,
|
||||
const rmw_qos_profile_t & qos_profile,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group)
|
||||
{
|
||||
rcl_client_options_t options = rcl_client_get_default_options();
|
||||
options.qos = qos_profile;
|
||||
|
||||
auto cli = rclcpp::Client<ServiceT>::make_shared(
|
||||
node_base.get(),
|
||||
node_graph,
|
||||
service_name,
|
||||
options);
|
||||
|
||||
auto cli_base_ptr = std::dynamic_pointer_cast<rclcpp::ClientBase>(cli);
|
||||
node_services->add_client(cli_base_ptr, group);
|
||||
return cli;
|
||||
}
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__CREATE_CLIENT_HPP_
|
||||
@@ -29,36 +29,6 @@
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
template<
|
||||
typename MessageT,
|
||||
typename AllocatorT = std::allocator<void>,
|
||||
typename PublisherT = ::rclcpp::Publisher<MessageT, AllocatorT>>
|
||||
// cppcheck-suppress syntaxError // bug in cppcheck 1.82 for [[deprecated]] on templated function
|
||||
[[deprecated("use alternative rclcpp::create_publisher() signatures")]]
|
||||
std::shared_ptr<PublisherT>
|
||||
create_publisher(
|
||||
rclcpp::node_interfaces::NodeTopicsInterface * node_topics,
|
||||
const std::string & topic_name,
|
||||
const rmw_qos_profile_t & qos_profile,
|
||||
const PublisherEventCallbacks & event_callbacks,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group,
|
||||
bool use_intra_process_comms,
|
||||
std::shared_ptr<AllocatorT> allocator)
|
||||
{
|
||||
auto publisher_options = rcl_publisher_get_default_options();
|
||||
publisher_options.qos = qos_profile;
|
||||
|
||||
auto pub = node_topics->create_publisher(
|
||||
topic_name,
|
||||
rclcpp::create_publisher_factory<MessageT, AllocatorT, PublisherT>(event_callbacks, allocator),
|
||||
publisher_options,
|
||||
use_intra_process_comms);
|
||||
|
||||
node_topics->add_publisher(pub, group);
|
||||
|
||||
return std::dynamic_pointer_cast<PublisherT>(pub);
|
||||
}
|
||||
|
||||
/// Create and return a publisher of the given MessageT type.
|
||||
/**
|
||||
* The NodeT type only needs to have a method called get_node_topics_interface()
|
||||
@@ -67,7 +37,7 @@ create_publisher(
|
||||
template<
|
||||
typename MessageT,
|
||||
typename AllocatorT = std::allocator<void>,
|
||||
typename PublisherT = ::rclcpp::Publisher<MessageT, AllocatorT>,
|
||||
typename PublisherT = rclcpp::Publisher<MessageT, AllocatorT>,
|
||||
typename NodeT>
|
||||
std::shared_ptr<PublisherT>
|
||||
create_publisher(
|
||||
@@ -76,43 +46,23 @@ create_publisher(
|
||||
const rclcpp::QoS & qos,
|
||||
const rclcpp::PublisherOptionsWithAllocator<AllocatorT> & options = (
|
||||
rclcpp::PublisherOptionsWithAllocator<AllocatorT>()
|
||||
))
|
||||
)
|
||||
)
|
||||
{
|
||||
// Extract the NodeTopicsInterface from the NodeT.
|
||||
using rclcpp::node_interfaces::get_node_topics_interface;
|
||||
auto node_topics = get_node_topics_interface(node);
|
||||
|
||||
std::shared_ptr<AllocatorT> allocator = options.allocator;
|
||||
if (!allocator) {
|
||||
allocator = std::make_shared<AllocatorT>();
|
||||
}
|
||||
|
||||
bool use_intra_process;
|
||||
switch (options.use_intra_process_comm) {
|
||||
case IntraProcessSetting::Enable:
|
||||
use_intra_process = true;
|
||||
break;
|
||||
case IntraProcessSetting::Disable:
|
||||
use_intra_process = false;
|
||||
break;
|
||||
case IntraProcessSetting::NodeDefault:
|
||||
use_intra_process = node_topics->get_node_base_interface()->get_use_intra_process_default();
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Unrecognized IntraProcessSetting value");
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO(wjwwood): convert all of the interfaces to use QoS and PublisherOptionsBase
|
||||
// Create the publisher.
|
||||
auto pub = node_topics->create_publisher(
|
||||
topic_name,
|
||||
rclcpp::create_publisher_factory<MessageT, AllocatorT, PublisherT>(
|
||||
options.event_callbacks,
|
||||
allocator
|
||||
),
|
||||
options.template to_rcl_publisher_options<MessageT>(qos),
|
||||
use_intra_process
|
||||
rclcpp::create_publisher_factory<MessageT, AllocatorT, PublisherT>(options),
|
||||
qos
|
||||
);
|
||||
|
||||
// Add the publisher to the node topics interface.
|
||||
node_topics->add_publisher(pub, options.callback_group);
|
||||
|
||||
return std::dynamic_pointer_cast<PublisherT>(pub);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,49 +29,6 @@
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
template<
|
||||
typename MessageT,
|
||||
typename CallbackT,
|
||||
typename AllocatorT,
|
||||
typename CallbackMessageT,
|
||||
typename SubscriptionT = rclcpp::Subscription<CallbackMessageT, AllocatorT>>
|
||||
// cppcheck-suppress syntaxError // bug in cppcheck 1.82 for [[deprecated]] on templated function
|
||||
[[deprecated("use alternative rclcpp::create_subscription() signatures")]]
|
||||
typename std::shared_ptr<SubscriptionT>
|
||||
create_subscription(
|
||||
rclcpp::node_interfaces::NodeTopicsInterface * node_topics,
|
||||
const std::string & topic_name,
|
||||
CallbackT && callback,
|
||||
const rmw_qos_profile_t & qos_profile,
|
||||
const SubscriptionEventCallbacks & event_callbacks,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group,
|
||||
bool ignore_local_publications,
|
||||
bool use_intra_process_comms,
|
||||
typename rclcpp::message_memory_strategy::MessageMemoryStrategy<
|
||||
CallbackMessageT, AllocatorT>::SharedPtr
|
||||
msg_mem_strat,
|
||||
typename std::shared_ptr<AllocatorT> allocator)
|
||||
{
|
||||
auto subscription_options = rcl_subscription_get_default_options();
|
||||
subscription_options.qos = qos_profile;
|
||||
subscription_options.ignore_local_publications = ignore_local_publications;
|
||||
|
||||
auto factory = rclcpp::create_subscription_factory
|
||||
<MessageT, CallbackT, AllocatorT, CallbackMessageT, SubscriptionT>(
|
||||
std::forward<CallbackT>(callback),
|
||||
event_callbacks,
|
||||
msg_mem_strat,
|
||||
allocator);
|
||||
|
||||
auto sub = node_topics->create_subscription(
|
||||
topic_name,
|
||||
factory,
|
||||
subscription_options,
|
||||
use_intra_process_comms);
|
||||
node_topics->add_subscription(sub, group);
|
||||
return std::dynamic_pointer_cast<SubscriptionT>(sub);
|
||||
}
|
||||
|
||||
/// Create and return a subscription of the given MessageT type.
|
||||
/**
|
||||
* The NodeT type only needs to have a method called get_node_topics_interface()
|
||||
@@ -85,6 +42,10 @@ template<
|
||||
typename CallbackMessageT =
|
||||
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type,
|
||||
typename SubscriptionT = rclcpp::Subscription<CallbackMessageT, AllocatorT>,
|
||||
typename MessageMemoryStrategyT = rclcpp::message_memory_strategy::MessageMemoryStrategy<
|
||||
CallbackMessageT,
|
||||
AllocatorT
|
||||
>,
|
||||
typename NodeT>
|
||||
typename std::shared_ptr<SubscriptionT>
|
||||
create_subscription(
|
||||
@@ -95,48 +56,21 @@ create_subscription(
|
||||
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options = (
|
||||
rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>()
|
||||
),
|
||||
typename rclcpp::message_memory_strategy::MessageMemoryStrategy<
|
||||
CallbackMessageT, AllocatorT>::SharedPtr
|
||||
msg_mem_strat = nullptr)
|
||||
typename MessageMemoryStrategyT::SharedPtr msg_mem_strat = (
|
||||
MessageMemoryStrategyT::create_default()
|
||||
)
|
||||
)
|
||||
{
|
||||
using rclcpp::node_interfaces::get_node_topics_interface;
|
||||
auto node_topics = get_node_topics_interface(std::forward<NodeT>(node));
|
||||
|
||||
if (!msg_mem_strat) {
|
||||
using rclcpp::message_memory_strategy::MessageMemoryStrategy;
|
||||
msg_mem_strat = MessageMemoryStrategy<CallbackMessageT, AllocatorT>::create_default();
|
||||
}
|
||||
auto factory = rclcpp::create_subscription_factory<MessageT>(
|
||||
std::forward<CallbackT>(callback),
|
||||
options,
|
||||
msg_mem_strat
|
||||
);
|
||||
|
||||
std::shared_ptr<AllocatorT> allocator = options.allocator;
|
||||
if (!allocator) {
|
||||
allocator = std::make_shared<AllocatorT>();
|
||||
}
|
||||
auto factory = rclcpp::create_subscription_factory
|
||||
<MessageT, CallbackT, AllocatorT, CallbackMessageT, SubscriptionT>(
|
||||
std::forward<CallbackT>(callback), options.event_callbacks, msg_mem_strat, allocator);
|
||||
|
||||
bool use_intra_process;
|
||||
switch (options.use_intra_process_comm) {
|
||||
case IntraProcessSetting::Enable:
|
||||
use_intra_process = true;
|
||||
break;
|
||||
case IntraProcessSetting::Disable:
|
||||
use_intra_process = false;
|
||||
break;
|
||||
case IntraProcessSetting::NodeDefault:
|
||||
use_intra_process = node_topics->get_node_base_interface()->get_use_intra_process_default();
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Unrecognized IntraProcessSetting value");
|
||||
break;
|
||||
}
|
||||
|
||||
// TODO(wjwwood): convert all of the interfaces to use QoS and SubscriptionOptionsBase
|
||||
auto sub = node_topics->create_subscription(
|
||||
topic_name,
|
||||
factory,
|
||||
options.template to_rcl_subscription_options<MessageT>(qos),
|
||||
use_intra_process);
|
||||
auto sub = node_topics->create_subscription(topic_name, factory, qos);
|
||||
node_topics->add_subscription(sub, options.callback_group);
|
||||
return std::dynamic_pointer_cast<SubscriptionT>(sub);
|
||||
}
|
||||
|
||||
73
rclcpp/include/rclcpp/create_timer.hpp
Normal file
73
rclcpp/include/rclcpp/create_timer.hpp
Normal file
@@ -0,0 +1,73 @@
|
||||
// Copyright 2019 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__CREATE_TIMER_HPP_
|
||||
#define RCLCPP__CREATE_TIMER_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "rclcpp/duration.hpp"
|
||||
#include "rclcpp/node_interfaces/get_node_base_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/get_node_timers_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_timers_interface.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
/// Create a timer with a given clock
|
||||
/// \internal
|
||||
template<typename CallbackT>
|
||||
typename rclcpp::TimerBase::SharedPtr
|
||||
create_timer(
|
||||
node_interfaces::NodeBaseInterface * node_base,
|
||||
node_interfaces::NodeTimersInterface * node_timers,
|
||||
rclcpp::Clock::SharedPtr clock,
|
||||
rclcpp::Duration period,
|
||||
CallbackT && callback,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr)
|
||||
{
|
||||
auto timer = rclcpp::GenericTimer<CallbackT>::make_shared(
|
||||
clock,
|
||||
period.to_chrono<std::chrono::nanoseconds>(),
|
||||
std::forward<CallbackT>(callback),
|
||||
node_base->get_context());
|
||||
|
||||
node_timers->add_timer(timer, group);
|
||||
return timer;
|
||||
}
|
||||
|
||||
/// Create a timer with a given clock
|
||||
template<typename NodeT, typename CallbackT>
|
||||
typename rclcpp::TimerBase::SharedPtr
|
||||
create_timer(
|
||||
NodeT node,
|
||||
rclcpp::Clock::SharedPtr clock,
|
||||
rclcpp::Duration period,
|
||||
CallbackT && callback,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr)
|
||||
{
|
||||
return create_timer(
|
||||
rclcpp::node_interfaces::get_node_base_interface(node),
|
||||
rclcpp::node_interfaces::get_node_timers_interface(node),
|
||||
clock,
|
||||
period,
|
||||
std::forward<CallbackT>(callback),
|
||||
group);
|
||||
}
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__CREATE_TIMER_HPP_
|
||||
3
rclcpp/include/rclcpp/detail/README.md
Normal file
3
rclcpp/include/rclcpp/detail/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
Notice that headers in this folder should only provide symbols in the rclcpp::detail namespace.
|
||||
|
||||
Also that these headers are not considered part of the public API and are subject to change without notice.
|
||||
55
rclcpp/include/rclcpp/detail/resolve_use_intra_process.hpp
Normal file
55
rclcpp/include/rclcpp/detail/resolve_use_intra_process.hpp
Normal file
@@ -0,0 +1,55 @@
|
||||
// Copyright 2019 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__DETAIL__RESOLVE_USE_INTRA_PROCESS_HPP_
|
||||
#define RCLCPP__DETAIL__RESOLVE_USE_INTRA_PROCESS_HPP_
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "rclcpp/intra_process_setting.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template<typename OptionsT, typename NodeBaseT>
|
||||
bool
|
||||
resolve_use_intra_process(const OptionsT & options, const NodeBaseT & node_base)
|
||||
{
|
||||
bool use_intra_process;
|
||||
switch (options.use_intra_process_comm) {
|
||||
case IntraProcessSetting::Enable:
|
||||
use_intra_process = true;
|
||||
break;
|
||||
case IntraProcessSetting::Disable:
|
||||
use_intra_process = false;
|
||||
break;
|
||||
case IntraProcessSetting::NodeDefault:
|
||||
use_intra_process = node_base.get_use_intra_process_default();
|
||||
break;
|
||||
default:
|
||||
throw std::runtime_error("Unrecognized IntraProcessSetting value");
|
||||
break;
|
||||
}
|
||||
|
||||
return use_intra_process;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__DETAIL__RESOLVE_USE_INTRA_PROCESS_HPP_
|
||||
@@ -28,10 +28,12 @@ class RCLCPP_PUBLIC Duration
|
||||
public:
|
||||
Duration(int32_t seconds, uint32_t nanoseconds);
|
||||
|
||||
// This constructor matches any numeric value - ints or floats
|
||||
explicit Duration(rcl_duration_value_t nanoseconds);
|
||||
|
||||
explicit Duration(std::chrono::nanoseconds nanoseconds);
|
||||
|
||||
// This constructor matches any std::chrono value other than nanoseconds
|
||||
// intentionally not using explicit to create a conversion constructor
|
||||
template<class Rep, class Period>
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
@@ -94,6 +96,10 @@ public:
|
||||
double
|
||||
seconds() const;
|
||||
|
||||
// Create a duration object from a floating point number representing seconds
|
||||
static Duration
|
||||
from_seconds(double seconds);
|
||||
|
||||
template<class DurationT>
|
||||
DurationT
|
||||
to_chrono() const
|
||||
|
||||
@@ -17,11 +17,14 @@
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "rcl/error_handling.h"
|
||||
#include "rcl/types.h"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
#include "rcpputils/join.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace exceptions
|
||||
@@ -167,6 +170,31 @@ public:
|
||||
RCLInvalidArgument(const RCLErrorBase & base_exc, const std::string & prefix);
|
||||
};
|
||||
|
||||
/// Created when the ret is RCL_RET_INVALID_ROS_ARGS.
|
||||
class RCLInvalidROSArgsError : public RCLErrorBase, public std::runtime_error
|
||||
{
|
||||
public:
|
||||
RCLCPP_PUBLIC
|
||||
RCLInvalidROSArgsError(
|
||||
rcl_ret_t ret, const rcl_error_state_t * error_state, const std::string & prefix);
|
||||
RCLCPP_PUBLIC
|
||||
RCLInvalidROSArgsError(const RCLErrorBase & base_exc, const std::string & prefix);
|
||||
};
|
||||
|
||||
/// Thrown when unparsed ROS specific arguments are found.
|
||||
class UnknownROSArgsError : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit UnknownROSArgsError(std::vector<std::string> && unknown_ros_args_in)
|
||||
: std::runtime_error(
|
||||
"found unknown ROS arguments: '" + rcpputils::join(unknown_ros_args_in, "', '") + "'"),
|
||||
unknown_ros_args(unknown_ros_args_in)
|
||||
{
|
||||
}
|
||||
|
||||
const std::vector<std::string> unknown_ros_args;
|
||||
};
|
||||
|
||||
/// Thrown when an invalid rclcpp::Event object or SharedPtr is encountered.
|
||||
class InvalidEventError : public std::runtime_error
|
||||
{
|
||||
@@ -219,6 +247,13 @@ class ParameterImmutableException : public std::runtime_error
|
||||
using std::runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
/// Thrown if parameter is modified while in a set callback.
|
||||
class ParameterModifiedInCallbackException : public std::runtime_error
|
||||
{
|
||||
// Inherit constructors from runtime_error.
|
||||
using std::runtime_error::runtime_error;
|
||||
};
|
||||
|
||||
} // namespace exceptions
|
||||
} // namespace rclcpp
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -47,6 +48,7 @@ namespace executor
|
||||
/// Return codes to be used with spin_until_future_complete.
|
||||
/**
|
||||
* SUCCESS: The future is complete and can be accessed with "get" without blocking.
|
||||
* This does not indicate that the operation succeeded; "get" may still throw an exception.
|
||||
* INTERRUPTED: The future is not complete, spinning was interrupted by Ctrl-C or another error.
|
||||
* TIMEOUT: Spinning timed out.
|
||||
*/
|
||||
@@ -210,8 +212,8 @@ public:
|
||||
|
||||
/// Spin (blocking) until the future is complete, it times out waiting, or rclcpp is interrupted.
|
||||
/**
|
||||
* \param[in] future The future to wait on. If SUCCESS, the future is safe to access after this
|
||||
* function.
|
||||
* \param[in] future The future to wait on. If this function returns SUCCESS, the future can be
|
||||
* accessed without blocking (though it may still throw an exception).
|
||||
* \param[in] timeout Optional timeout parameter, which gets passed to Executor::spin_node_once.
|
||||
* `-1` is block forever, `0` is non-blocking.
|
||||
* If the time spent inside the blocking loop exceeds this timeout, return a TIMEOUT return
|
||||
@@ -332,10 +334,6 @@ protected:
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr
|
||||
get_group_by_timer(rclcpp::TimerBase::SharedPtr timer);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
get_next_timer(AnyExecutable & any_exec);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
get_next_ready_executable(AnyExecutable & any_executable);
|
||||
@@ -355,6 +353,9 @@ protected:
|
||||
/// Wait set for managing entities that the rmw layer waits on.
|
||||
rcl_wait_set_t wait_set_ = rcl_get_zero_initialized_wait_set();
|
||||
|
||||
// Mutex to protect the subsequent memory_strategy_.
|
||||
std::mutex memory_strategy_mutex_;
|
||||
|
||||
/// The memory strategy: an interface for handling user-defined memory allocation strategies.
|
||||
memory_strategy::MemoryStrategy::SharedPtr memory_strategy_;
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#ifndef RCLCPP__EXECUTORS__MULTI_THREADED_EXECUTOR_HPP_
|
||||
#define RCLCPP__EXECUTORS__MULTI_THREADED_EXECUTOR_HPP_
|
||||
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
@@ -53,7 +54,8 @@ public:
|
||||
MultiThreadedExecutor(
|
||||
const executor::ExecutorArgs & args = executor::ExecutorArgs(),
|
||||
size_t number_of_threads = 0,
|
||||
bool yield_before_execute = false);
|
||||
bool yield_before_execute = false,
|
||||
std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual ~MultiThreadedExecutor();
|
||||
@@ -77,6 +79,7 @@ private:
|
||||
std::mutex wait_mutex_;
|
||||
size_t number_of_threads_;
|
||||
bool yield_before_execute_;
|
||||
std::chrono::nanoseconds next_exec_timeout_;
|
||||
|
||||
std::set<TimerBase::SharedPtr> scheduled_timers_;
|
||||
};
|
||||
|
||||
@@ -96,6 +96,24 @@ struct function_traits<
|
||||
: function_traits<ReturnTypeT(Args ...)>
|
||||
{};
|
||||
|
||||
// std::bind for object const methods
|
||||
template<typename ClassT, typename ReturnTypeT, typename ... Args, typename ... FArgs>
|
||||
#if defined _LIBCPP_VERSION // libc++ (Clang)
|
||||
struct function_traits<std::__bind<ReturnTypeT (ClassT::*)(Args ...) const, FArgs ...>>
|
||||
#elif defined _GLIBCXX_RELEASE // glibc++ (GNU C++ >= 7.1)
|
||||
struct function_traits<std::_Bind<ReturnTypeT(ClassT::*(FArgs ...))(Args ...) const>>
|
||||
#elif defined __GLIBCXX__ // glibc++ (GNU C++)
|
||||
struct function_traits<std::_Bind<std::_Mem_fn<ReturnTypeT (ClassT::*)(Args ...) const>(FArgs ...)>>
|
||||
#elif defined _MSC_VER // MS Visual Studio
|
||||
struct function_traits<
|
||||
std::_Binder<std::_Unforced, ReturnTypeT(__cdecl ClassT::*)(Args ...) const, FArgs ...>
|
||||
>
|
||||
#else
|
||||
#error "Unsupported C++ compiler / standard library"
|
||||
#endif
|
||||
: function_traits<ReturnTypeT(Args ...)>
|
||||
{};
|
||||
|
||||
// std::bind for free functions
|
||||
template<typename ReturnTypeT, typename ... Args, typename ... FArgs>
|
||||
#if defined _LIBCPP_VERSION // libc++ (Clang)
|
||||
|
||||
@@ -79,6 +79,11 @@ public:
|
||||
rclcpp::executor::AnyExecutable & any_exec,
|
||||
const WeakNodeList & weak_nodes) = 0;
|
||||
|
||||
virtual void
|
||||
get_next_timer(
|
||||
rclcpp::executor::AnyExecutable & any_exec,
|
||||
const WeakNodeList & weak_nodes) = 0;
|
||||
|
||||
virtual void
|
||||
get_next_waitable(
|
||||
rclcpp::executor::AnyExecutable & any_exec,
|
||||
@@ -102,6 +107,11 @@ public:
|
||||
std::shared_ptr<const rcl_client_t> client_handle,
|
||||
const WeakNodeList & weak_nodes);
|
||||
|
||||
static rclcpp::TimerBase::SharedPtr
|
||||
get_timer_by_handle(
|
||||
std::shared_ptr<const rcl_timer_t> timer_handle,
|
||||
const WeakNodeList & weak_nodes);
|
||||
|
||||
static rclcpp::node_interfaces::NodeBaseInterface::SharedPtr
|
||||
get_node_by_group(
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group,
|
||||
@@ -122,6 +132,11 @@ public:
|
||||
rclcpp::ClientBase::SharedPtr client,
|
||||
const WeakNodeList & weak_nodes);
|
||||
|
||||
static rclcpp::callback_group::CallbackGroup::SharedPtr
|
||||
get_group_by_timer(
|
||||
rclcpp::TimerBase::SharedPtr timer,
|
||||
const WeakNodeList & weak_nodes);
|
||||
|
||||
static rclcpp::callback_group::CallbackGroup::SharedPtr
|
||||
get_group_by_waitable(
|
||||
rclcpp::Waitable::SharedPtr waitable,
|
||||
|
||||
@@ -95,16 +95,17 @@ public:
|
||||
rclcpp::exceptions::throw_from_rcl_error(ret);
|
||||
}
|
||||
|
||||
auto serialized_msg = std::shared_ptr<rcl_serialized_message_t>(msg,
|
||||
[](rmw_serialized_message_t * msg) {
|
||||
auto ret = rmw_serialized_message_fini(msg);
|
||||
delete msg;
|
||||
if (ret != RCL_RET_OK) {
|
||||
RCUTILS_LOG_ERROR_NAMED(
|
||||
"rclcpp",
|
||||
"failed to destroy serialized message: %s", rcl_get_error_string().str);
|
||||
}
|
||||
});
|
||||
auto serialized_msg = std::shared_ptr<rcl_serialized_message_t>(
|
||||
msg,
|
||||
[](rmw_serialized_message_t * msg) {
|
||||
auto ret = rmw_serialized_message_fini(msg);
|
||||
delete msg;
|
||||
if (ret != RCL_RET_OK) {
|
||||
RCUTILS_LOG_ERROR_NAMED(
|
||||
"rclcpp",
|
||||
"failed to destroy serialized message: %s", rcl_get_error_string().str);
|
||||
}
|
||||
});
|
||||
|
||||
return serialized_msg;
|
||||
}
|
||||
|
||||
@@ -151,15 +151,17 @@ public:
|
||||
*
|
||||
* For example, all of these cases will work:
|
||||
*
|
||||
* pub = node->create_publisher<MsgT>("chatter", 10); // implicitly KeepLast
|
||||
* pub = node->create_publisher<MsgT>("chatter", QoS(10)); // implicitly KeepLast
|
||||
* pub = node->create_publisher<MsgT>("chatter", QoS(KeepLast(10)));
|
||||
* pub = node->create_publisher<MsgT>("chatter", QoS(KeepAll()));
|
||||
* pub = node->create_publisher<MsgT>("chatter", QoS(1).best_effort().volatile());
|
||||
* {
|
||||
* rclcpp::QoS custom_qos(KeepLast(10), rmw_qos_profile_sensor_data);
|
||||
* pub = node->create_publisher<MsgT>("chatter", custom_qos);
|
||||
* }
|
||||
* ```cpp
|
||||
* pub = node->create_publisher<MsgT>("chatter", 10); // implicitly KeepLast
|
||||
* pub = node->create_publisher<MsgT>("chatter", QoS(10)); // implicitly KeepLast
|
||||
* pub = node->create_publisher<MsgT>("chatter", QoS(KeepLast(10)));
|
||||
* pub = node->create_publisher<MsgT>("chatter", QoS(KeepAll()));
|
||||
* pub = node->create_publisher<MsgT>("chatter", QoS(1).best_effort().volatile());
|
||||
* {
|
||||
* rclcpp::QoS custom_qos(KeepLast(10), rmw_qos_profile_sensor_data);
|
||||
* pub = node->create_publisher<MsgT>("chatter", custom_qos);
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* The publisher options may optionally be passed as the third argument for
|
||||
* any of the above cases.
|
||||
@@ -172,7 +174,7 @@ public:
|
||||
template<
|
||||
typename MessageT,
|
||||
typename AllocatorT = std::allocator<void>,
|
||||
typename PublisherT = ::rclcpp::Publisher<MessageT, AllocatorT>>
|
||||
typename PublisherT = rclcpp::Publisher<MessageT, AllocatorT>>
|
||||
std::shared_ptr<PublisherT>
|
||||
create_publisher(
|
||||
const std::string & topic_name,
|
||||
@@ -181,44 +183,6 @@ public:
|
||||
PublisherOptionsWithAllocator<AllocatorT>()
|
||||
);
|
||||
|
||||
/// Create and return a Publisher.
|
||||
/**
|
||||
* \param[in] topic_name The topic for this publisher to publish on.
|
||||
* \param[in] qos_history_depth The depth of the publisher message queue.
|
||||
* \param[in] allocator Custom allocator.
|
||||
* \return Shared pointer to the created publisher.
|
||||
*/
|
||||
template<
|
||||
typename MessageT,
|
||||
typename AllocatorT = std::allocator<void>,
|
||||
typename PublisherT = ::rclcpp::Publisher<MessageT, AllocatorT>>
|
||||
// cppcheck-suppress syntaxError // bug in cppcheck 1.82 for [[deprecated]] on templated function
|
||||
[[deprecated("use create_publisher(const std::string &, const rclcpp::QoS &, ...) instead")]]
|
||||
std::shared_ptr<PublisherT>
|
||||
create_publisher(
|
||||
const std::string & topic_name,
|
||||
size_t qos_history_depth,
|
||||
std::shared_ptr<AllocatorT> allocator);
|
||||
|
||||
/// Create and return a Publisher.
|
||||
/**
|
||||
* \param[in] topic_name The topic for this publisher to publish on.
|
||||
* \param[in] qos_profile The quality of service profile to pass on to the rmw implementation.
|
||||
* \param[in] allocator Optional custom allocator.
|
||||
* \return Shared pointer to the created publisher.
|
||||
*/
|
||||
template<
|
||||
typename MessageT,
|
||||
typename AllocatorT = std::allocator<void>,
|
||||
typename PublisherT = ::rclcpp::Publisher<MessageT, AllocatorT>>
|
||||
// cppcheck-suppress syntaxError // bug in cppcheck 1.82 for [[deprecated]] on templated function
|
||||
[[deprecated("use create_publisher(const std::string &, const rclcpp::QoS &, ...) instead")]]
|
||||
std::shared_ptr<PublisherT>
|
||||
create_publisher(
|
||||
const std::string & topic_name,
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_default,
|
||||
std::shared_ptr<AllocatorT> allocator = nullptr);
|
||||
|
||||
/// Create and return a Subscription.
|
||||
/**
|
||||
* \param[in] topic_name The topic to subscribe on.
|
||||
@@ -228,16 +192,18 @@ public:
|
||||
* \param[in] msg_mem_strat The message memory strategy to use for allocating messages.
|
||||
* \return Shared pointer to the created subscription.
|
||||
*/
|
||||
/* TODO(jacquelinekay):
|
||||
Windows build breaks when static member function passed as default
|
||||
argument to msg_mem_strat, nullptr is a workaround.
|
||||
*/
|
||||
template<
|
||||
typename MessageT,
|
||||
typename CallbackT,
|
||||
typename AllocatorT = std::allocator<void>,
|
||||
typename SubscriptionT = rclcpp::Subscription<
|
||||
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type, AllocatorT>>
|
||||
typename CallbackMessageT =
|
||||
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type,
|
||||
typename SubscriptionT = rclcpp::Subscription<CallbackMessageT, AllocatorT>,
|
||||
typename MessageMemoryStrategyT = rclcpp::message_memory_strategy::MessageMemoryStrategy<
|
||||
CallbackMessageT,
|
||||
AllocatorT
|
||||
>
|
||||
>
|
||||
std::shared_ptr<SubscriptionT>
|
||||
create_subscription(
|
||||
const std::string & topic_name,
|
||||
@@ -245,84 +211,10 @@ public:
|
||||
CallbackT && callback,
|
||||
const SubscriptionOptionsWithAllocator<AllocatorT> & options =
|
||||
SubscriptionOptionsWithAllocator<AllocatorT>(),
|
||||
typename rclcpp::message_memory_strategy::MessageMemoryStrategy<
|
||||
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type, AllocatorT
|
||||
>::SharedPtr
|
||||
msg_mem_strat = nullptr);
|
||||
|
||||
/// Create and return a Subscription.
|
||||
/**
|
||||
* \param[in] topic_name The topic to subscribe on.
|
||||
* \param[in] callback The user-defined callback function.
|
||||
* \param[in] qos_profile The quality of service profile to pass on to the rmw implementation.
|
||||
* \param[in] group The callback group for this subscription. NULL for no callback group.
|
||||
* \param[in] ignore_local_publications True to ignore local publications.
|
||||
* \param[in] msg_mem_strat The message memory strategy to use for allocating messages.
|
||||
* \param[in] allocator Optional custom allocator.
|
||||
* \return Shared pointer to the created subscription.
|
||||
*/
|
||||
/* TODO(jacquelinekay):
|
||||
Windows build breaks when static member function passed as default
|
||||
argument to msg_mem_strat, nullptr is a workaround.
|
||||
*/
|
||||
template<
|
||||
typename MessageT,
|
||||
typename CallbackT,
|
||||
typename Alloc = std::allocator<void>,
|
||||
typename SubscriptionT = rclcpp::Subscription<
|
||||
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type, Alloc>>
|
||||
// cppcheck-suppress syntaxError // bug in cppcheck 1.82 for [[deprecated]] on templated function
|
||||
[[deprecated(
|
||||
"use create_subscription(const std::string &, const rclcpp::QoS &, CallbackT, ...) instead"
|
||||
)]]
|
||||
std::shared_ptr<SubscriptionT>
|
||||
create_subscription(
|
||||
const std::string & topic_name,
|
||||
CallbackT && callback,
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_default,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr,
|
||||
bool ignore_local_publications = false,
|
||||
typename rclcpp::message_memory_strategy::MessageMemoryStrategy<
|
||||
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type, Alloc>::SharedPtr
|
||||
msg_mem_strat = nullptr,
|
||||
std::shared_ptr<Alloc> allocator = nullptr);
|
||||
|
||||
/// Create and return a Subscription.
|
||||
/**
|
||||
* \param[in] topic_name The topic to subscribe on.
|
||||
* \param[in] qos_history_depth The depth of the subscription's incoming message queue.
|
||||
* \param[in] callback The user-defined callback function.
|
||||
* \param[in] group The callback group for this subscription. NULL for no callback group.
|
||||
* \param[in] ignore_local_publications True to ignore local publications.
|
||||
* \param[in] msg_mem_strat The message memory strategy to use for allocating messages.
|
||||
* \param[in] allocator Optional custom allocator.
|
||||
* \return Shared pointer to the created subscription.
|
||||
*/
|
||||
/* TODO(jacquelinekay):
|
||||
Windows build breaks when static member function passed as default
|
||||
argument to msg_mem_strat, nullptr is a workaround.
|
||||
*/
|
||||
template<
|
||||
typename MessageT,
|
||||
typename CallbackT,
|
||||
typename Alloc = std::allocator<void>,
|
||||
typename SubscriptionT = rclcpp::Subscription<
|
||||
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type, Alloc>>
|
||||
// cppcheck-suppress syntaxError // bug in cppcheck 1.82 for [[deprecated]] on templated function
|
||||
[[deprecated(
|
||||
"use create_subscription(const std::string &, const rclcpp::QoS &, CallbackT, ...) instead"
|
||||
)]]
|
||||
std::shared_ptr<SubscriptionT>
|
||||
create_subscription(
|
||||
const std::string & topic_name,
|
||||
CallbackT && callback,
|
||||
size_t qos_history_depth,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr,
|
||||
bool ignore_local_publications = false,
|
||||
typename rclcpp::message_memory_strategy::MessageMemoryStrategy<
|
||||
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type, Alloc>::SharedPtr
|
||||
msg_mem_strat = nullptr,
|
||||
std::shared_ptr<Alloc> allocator = nullptr);
|
||||
typename MessageMemoryStrategyT::SharedPtr msg_mem_strat = (
|
||||
MessageMemoryStrategyT::create_default()
|
||||
)
|
||||
);
|
||||
|
||||
/// Create a timer.
|
||||
/**
|
||||
@@ -369,6 +261,8 @@ public:
|
||||
* are ignored, and should be specified using the name argument to this
|
||||
* function and the default value's type instead.
|
||||
*
|
||||
* If `ignore_override` is `true`, the parameter override will be ignored.
|
||||
*
|
||||
* This method, if successful, will result in any callback registered with
|
||||
* set_on_parameters_set_callback to be called.
|
||||
* If that callback prevents the initial value for the parameter from being
|
||||
@@ -382,6 +276,8 @@ public:
|
||||
* did not override it.
|
||||
* \param[in] parameter_descriptor An optional, custom description for
|
||||
* the parameter.
|
||||
* \param[in] ignore_override When `true`, the parameter override is ignored.
|
||||
* Default to `false`.
|
||||
* \return A const reference to the value of the parameter.
|
||||
* \throws rclcpp::exceptions::ParameterAlreadyDeclaredException if parameter
|
||||
* has already been declared.
|
||||
@@ -396,7 +292,8 @@ public:
|
||||
const std::string & name,
|
||||
const rclcpp::ParameterValue & default_value = rclcpp::ParameterValue(),
|
||||
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor =
|
||||
rcl_interfaces::msg::ParameterDescriptor());
|
||||
rcl_interfaces::msg::ParameterDescriptor(),
|
||||
bool ignore_override = false);
|
||||
|
||||
/// Declare and initialize a parameter with a type.
|
||||
/**
|
||||
@@ -425,7 +322,8 @@ public:
|
||||
const std::string & name,
|
||||
const ParameterT & default_value,
|
||||
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor =
|
||||
rcl_interfaces::msg::ParameterDescriptor());
|
||||
rcl_interfaces::msg::ParameterDescriptor(),
|
||||
bool ignore_override = false);
|
||||
|
||||
/// Declare and initialize several parameters with the same namespace and type.
|
||||
/**
|
||||
@@ -440,11 +338,12 @@ public:
|
||||
* expanding "namespace.key".
|
||||
* This allows you to declare several parameters at once without a namespace.
|
||||
*
|
||||
* The map may either contain default values for parameters, or a std::pair
|
||||
* where the first element is a default value and the second is a
|
||||
* parameter descriptor.
|
||||
* This function only takes the default value, but there is another overload
|
||||
* which takes the std::pair with the default value and descriptor.
|
||||
* The map contains default values for parameters.
|
||||
* There is another overload which takes the std::pair with the default value
|
||||
* and descriptor.
|
||||
*
|
||||
* If `ignore_overrides` is `true`, all the overrides of the parameters declared
|
||||
* by the function call will be ignored.
|
||||
*
|
||||
* This method, if successful, will result in any callback registered with
|
||||
* set_on_parameters_set_callback to be called, once for each parameter.
|
||||
@@ -453,6 +352,8 @@ public:
|
||||
*
|
||||
* \param[in] namespace_ The namespace in which to declare the parameters.
|
||||
* \param[in] parameters The parameters to set in the given namespace.
|
||||
* \param[in] ignore_overrides When `true`, the parameters overrides are ignored.
|
||||
* Default to `false`.
|
||||
* \throws rclcpp::exceptions::ParameterAlreadyDeclaredException if parameter
|
||||
* has already been declared.
|
||||
* \throws rclcpp::exceptions::InvalidParametersException if a parameter
|
||||
@@ -464,7 +365,8 @@ public:
|
||||
std::vector<ParameterT>
|
||||
declare_parameters(
|
||||
const std::string & namespace_,
|
||||
const std::map<std::string, ParameterT> & parameters);
|
||||
const std::map<std::string, ParameterT> & parameters,
|
||||
bool ignore_overrides = false);
|
||||
|
||||
/// Declare and initialize several parameters with the same namespace and type.
|
||||
/**
|
||||
@@ -480,7 +382,8 @@ public:
|
||||
const std::map<
|
||||
std::string,
|
||||
std::pair<ParameterT, rcl_interfaces::msg::ParameterDescriptor>
|
||||
> & parameters);
|
||||
> & parameters,
|
||||
bool ignore_overrides = false);
|
||||
|
||||
/// Undeclare a previously declared parameter.
|
||||
/**
|
||||
@@ -516,6 +419,7 @@ public:
|
||||
* rclcpp::NodeOptions::allow_undeclared_parameters set to true.
|
||||
* If undeclared parameters are allowed, then the parameter is implicitly
|
||||
* declared with the default parameter meta data before being set.
|
||||
* Parameter overrides are ignored by set_parameter.
|
||||
*
|
||||
* This method will result in any callback registered with
|
||||
* set_on_parameters_set_callback to be called.
|
||||
@@ -610,38 +514,6 @@ public:
|
||||
rcl_interfaces::msg::SetParametersResult
|
||||
set_parameters_atomically(const std::vector<rclcpp::Parameter> & parameters);
|
||||
|
||||
/// Set one parameter, unless that parameter has already been set.
|
||||
/**
|
||||
* Set the given parameter unless already set.
|
||||
*
|
||||
* Deprecated, instead use declare_parameter().
|
||||
*
|
||||
* \param[in] parameters The vector of parameters to be set.
|
||||
* \return The result of each set action as a vector.
|
||||
*/
|
||||
template<typename ParameterT>
|
||||
// cppcheck-suppress syntaxError // bug in cppcheck 1.82 for [[deprecated]] on templated function
|
||||
[[deprecated("use declare_parameter() instead")]]
|
||||
void
|
||||
set_parameter_if_not_set(const std::string & name, const ParameterT & value);
|
||||
|
||||
/// Set a map of parameters with the same prefix.
|
||||
/**
|
||||
* For each key in the map, a parameter with a name of "name.key" will be set
|
||||
* to the value in the map.
|
||||
*
|
||||
* Deprecated, instead use declare_parameters().
|
||||
*
|
||||
* \param[in] name The prefix of the parameters to set.
|
||||
* \param[in] values The parameters to set in the given prefix.
|
||||
*/
|
||||
template<typename ParameterT>
|
||||
[[deprecated("use declare_parameters() instead")]]
|
||||
void
|
||||
set_parameters_if_not_set(
|
||||
const std::string & name,
|
||||
const std::map<std::string, ParameterT> & values);
|
||||
|
||||
/// Return the parameter by the given name.
|
||||
/**
|
||||
* If the parameter has not been declared, then this method may throw the
|
||||
@@ -785,28 +657,6 @@ public:
|
||||
const std::string & prefix,
|
||||
std::map<std::string, ParameterT> & values) const;
|
||||
|
||||
/// Get the parameter value; if not set, set the "alternative value" and store it in the node.
|
||||
/**
|
||||
* If the parameter is set, then the "value" argument is assigned the value
|
||||
* in the parameter.
|
||||
* If the parameter is not set, then the "value" argument is assigned the "alternative_value",
|
||||
* and the parameter is set to the "alternative_value" on the node.
|
||||
*
|
||||
* Deprecated, instead use declare_parameter()'s return value, or use
|
||||
* has_parameter() to ensure it exists before getting it.
|
||||
*
|
||||
* \param[in] name The name of the parameter to get.
|
||||
* \param[out] value The output where the value of the parameter should be assigned.
|
||||
* \param[in] alternative_value Value to be used if the parameter was not set.
|
||||
*/
|
||||
template<typename ParameterT>
|
||||
[[deprecated("use declare_parameter() and it's return value instead")]]
|
||||
void
|
||||
get_parameter_or_set(
|
||||
const std::string & name,
|
||||
ParameterT & value,
|
||||
const ParameterT & alternative_value);
|
||||
|
||||
/// Return the parameter descriptor for the given parameter name.
|
||||
/**
|
||||
* Like get_parameters(), this method may throw the
|
||||
@@ -877,10 +727,12 @@ public:
|
||||
rcl_interfaces::msg::ListParametersResult
|
||||
list_parameters(const std::vector<std::string> & prefixes, uint64_t depth) const;
|
||||
|
||||
using OnSetParametersCallbackHandle =
|
||||
rclcpp::node_interfaces::OnSetParametersCallbackHandle;
|
||||
using OnParametersSetCallbackType =
|
||||
rclcpp::node_interfaces::NodeParametersInterface::OnParametersSetCallbackType;
|
||||
|
||||
/// Register a callback to be called anytime a parameter is about to be changed.
|
||||
/// Add a callback for when parameters are being set.
|
||||
/**
|
||||
* The callback signature is designed to allow handling of any of the above
|
||||
* `set_parameter*` or `declare_parameter*` methods, and so it takes a const
|
||||
@@ -890,19 +742,21 @@ public:
|
||||
*
|
||||
* For an example callback:
|
||||
*
|
||||
* rcl_interfaces::msg::SetParametersResult
|
||||
* my_callback(const std::vector<rclcpp::Parameter> & parameters)
|
||||
* {
|
||||
* rcl_interfaces::msg::SetParametersResult result;
|
||||
* result.successful = true;
|
||||
* for (const auto & parameter : parameters) {
|
||||
* if (!some_condition) {
|
||||
* result.successful = false;
|
||||
* result.reason = "the reason it could not be allowed";
|
||||
* }
|
||||
* ```cpp
|
||||
* rcl_interfaces::msg::SetParametersResult
|
||||
* my_callback(const std::vector<rclcpp::Parameter> & parameters)
|
||||
* {
|
||||
* rcl_interfaces::msg::SetParametersResult result;
|
||||
* result.successful = true;
|
||||
* for (const auto & parameter : parameters) {
|
||||
* if (!some_condition) {
|
||||
* result.successful = false;
|
||||
* result.reason = "the reason it could not be allowed";
|
||||
* }
|
||||
* return result;
|
||||
* }
|
||||
* return result;
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* You can see that the SetParametersResult is a boolean flag for success
|
||||
* and an optional reason that can be used in error reporting when it fails.
|
||||
@@ -916,9 +770,68 @@ public:
|
||||
*
|
||||
* Some constraints like read_only are enforced before the callback is called.
|
||||
*
|
||||
* There may only be one callback set at a time, so the previously set
|
||||
* callback is returned when this method is used, or nullptr will be returned
|
||||
* if no callback was previously set.
|
||||
* The callback may introspect other already set parameters (by calling any
|
||||
* of the {get,list,describe}_parameter() methods), but may *not* modify
|
||||
* other parameters (by calling any of the {set,declare}_parameter() methods)
|
||||
* or modify the registered callback itself (by calling the
|
||||
* set_on_parameters_set_callback() method). If a callback tries to do any
|
||||
* of the latter things,
|
||||
* rclcpp::exceptions::ParameterModifiedInCallbackException will be thrown.
|
||||
*
|
||||
* The callback functions must remain valid as long as the
|
||||
* returned smart pointer is valid.
|
||||
* The returned smart pointer can be promoted to a shared version.
|
||||
*
|
||||
* Resetting or letting the smart pointer go out of scope unregisters the callback.
|
||||
* `remove_on_set_parameters_callback` can also be used.
|
||||
*
|
||||
* The registered callbacks are called when a parameter is set.
|
||||
* When a callback returns a not successful result, the remaining callbacks aren't called.
|
||||
* The order of the callback is the reverse from the registration order.
|
||||
*
|
||||
* \param callback The callback to register.
|
||||
* \returns A shared pointer. The callback is valid as long as the smart pointer is alive.
|
||||
* \throws std::bad_alloc if the allocation of the OnSetParametersCallbackHandle fails.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
OnSetParametersCallbackHandle::SharedPtr
|
||||
add_on_set_parameters_callback(OnParametersSetCallbackType callback);
|
||||
|
||||
/// Remove a callback registered with `add_on_set_parameters_callback`.
|
||||
/**
|
||||
* Delete a handler returned by `add_on_set_parameters_callback`.
|
||||
*
|
||||
* e.g.:
|
||||
*
|
||||
* `remove_on_set_parameters_callback(scoped_callback.get())`
|
||||
*
|
||||
* As an alternative, the smart pointer can be reset:
|
||||
*
|
||||
* `scoped_callback.reset()`
|
||||
*
|
||||
* Supposing that `scoped_callback` was the only owner.
|
||||
*
|
||||
* Calling `remove_on_set_parameters_callback` more than once with the same handler,
|
||||
* or calling it after the shared pointer has been reset is an error.
|
||||
* Resetting or letting the smart pointer go out of scope after calling
|
||||
* `remove_on_set_parameters_callback` is not a problem.
|
||||
*
|
||||
* \param handler The callback handler to remove.
|
||||
* \throws std::runtime_error if the handler was not created with `add_on_set_parameters_callback`,
|
||||
* or if it has been removed before.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
remove_on_set_parameters_callback(const OnSetParametersCallbackHandle * const handler);
|
||||
|
||||
/// Register a callback to be called anytime a parameter is about to be changed.
|
||||
/**
|
||||
* With this method, only one callback can be set at a time. The callback that was previously
|
||||
* set by this method is returned or `nullptr` if no callback was previously set.
|
||||
*
|
||||
* The callbacks added with `add_on_set_parameters_callback` are stored in a different place.
|
||||
* `remove_on_set_parameters_callback` can't be used with the callbacks registered with this
|
||||
* method. For removing it, use `set_on_parameters_set_callback(nullptr)`.
|
||||
*
|
||||
* \param[in] callback The callback to be called when the value for a
|
||||
* parameter is about to be set.
|
||||
@@ -926,20 +839,9 @@ public:
|
||||
* otherwise nullptr.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::Node::OnParametersSetCallbackType
|
||||
OnParametersSetCallbackType
|
||||
set_on_parameters_set_callback(rclcpp::Node::OnParametersSetCallbackType callback);
|
||||
|
||||
/// Register the callback for parameter changes
|
||||
/**
|
||||
* \param[in] callback User defined callback function.
|
||||
* It is expected to atomically set parameters.
|
||||
* \note Repeated invocations of this function will overwrite previous callbacks.
|
||||
*/
|
||||
template<typename CallbackT>
|
||||
[[deprecated("use set_on_parameters_set_callback() instead")]]
|
||||
void
|
||||
register_param_change_callback(CallbackT && callback);
|
||||
|
||||
/// Get the fully-qualified names of all available nodes.
|
||||
/**
|
||||
* The fully-qualified name includes the local namespace and name of the node.
|
||||
@@ -1054,15 +956,17 @@ public:
|
||||
*
|
||||
* For example, consider:
|
||||
*
|
||||
* auto node = std::make_shared<rclcpp::Node>("my_node", "my_ns");
|
||||
* node->get_sub_namespace(); // -> ""
|
||||
* auto sub_node1 = node->create_sub_node("a");
|
||||
* sub_node1->get_sub_namespace(); // -> "a"
|
||||
* auto sub_node2 = sub_node1->create_sub_node("b");
|
||||
* sub_node2->get_sub_namespace(); // -> "a/b"
|
||||
* auto sub_node3 = node->create_sub_node("foo");
|
||||
* sub_node3->get_sub_namespace(); // -> "foo"
|
||||
* node->get_sub_namespace(); // -> ""
|
||||
* ```cpp
|
||||
* auto node = std::make_shared<rclcpp::Node>("my_node", "my_ns");
|
||||
* node->get_sub_namespace(); // -> ""
|
||||
* auto sub_node1 = node->create_sub_node("a");
|
||||
* sub_node1->get_sub_namespace(); // -> "a"
|
||||
* auto sub_node2 = sub_node1->create_sub_node("b");
|
||||
* sub_node2->get_sub_namespace(); // -> "a/b"
|
||||
* auto sub_node3 = node->create_sub_node("foo");
|
||||
* sub_node3->get_sub_namespace(); // -> "foo"
|
||||
* node->get_sub_namespace(); // -> ""
|
||||
* ```
|
||||
*
|
||||
* get_namespace() will return the original node namespace, and will not
|
||||
* include the sub-namespace if one exists.
|
||||
@@ -1084,15 +988,17 @@ public:
|
||||
*
|
||||
* For example, consider:
|
||||
*
|
||||
* auto node = std::make_shared<rclcpp::Node>("my_node", "my_ns");
|
||||
* node->get_effective_namespace(); // -> "/my_ns"
|
||||
* auto sub_node1 = node->create_sub_node("a");
|
||||
* sub_node1->get_effective_namespace(); // -> "/my_ns/a"
|
||||
* auto sub_node2 = sub_node1->create_sub_node("b");
|
||||
* sub_node2->get_effective_namespace(); // -> "/my_ns/a/b"
|
||||
* auto sub_node3 = node->create_sub_node("foo");
|
||||
* sub_node3->get_effective_namespace(); // -> "/my_ns/foo"
|
||||
* node->get_effective_namespace(); // -> "/my_ns"
|
||||
* ```cpp
|
||||
* auto node = std::make_shared<rclcpp::Node>("my_node", "my_ns");
|
||||
* node->get_effective_namespace(); // -> "/my_ns"
|
||||
* auto sub_node1 = node->create_sub_node("a");
|
||||
* sub_node1->get_effective_namespace(); // -> "/my_ns/a"
|
||||
* auto sub_node2 = sub_node1->create_sub_node("b");
|
||||
* sub_node2->get_effective_namespace(); // -> "/my_ns/a/b"
|
||||
* auto sub_node3 = node->create_sub_node("foo");
|
||||
* sub_node3->get_effective_namespace(); // -> "/my_ns/foo"
|
||||
* node->get_effective_namespace(); // -> "/my_ns"
|
||||
* ```
|
||||
*
|
||||
* \sa get_namespace()
|
||||
* \sa get_sub_namespace()
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "rcl_interfaces/msg/intra_process_message.hpp"
|
||||
|
||||
#include "rclcpp/contexts/default_context.hpp"
|
||||
#include "rclcpp/create_client.hpp"
|
||||
#include "rclcpp/create_publisher.hpp"
|
||||
#include "rclcpp/create_service.hpp"
|
||||
#include "rclcpp/create_subscription.hpp"
|
||||
@@ -78,48 +79,20 @@ Node::create_publisher(
|
||||
options);
|
||||
}
|
||||
|
||||
template<typename MessageT, typename AllocatorT, typename PublisherT>
|
||||
std::shared_ptr<PublisherT>
|
||||
Node::create_publisher(
|
||||
const std::string & topic_name,
|
||||
size_t qos_history_depth,
|
||||
std::shared_ptr<AllocatorT> allocator)
|
||||
{
|
||||
PublisherOptionsWithAllocator<AllocatorT> pub_options;
|
||||
pub_options.allocator = allocator;
|
||||
return this->create_publisher<MessageT, AllocatorT, PublisherT>(
|
||||
topic_name, rclcpp::QoS(rclcpp::KeepLast(qos_history_depth)), pub_options);
|
||||
}
|
||||
|
||||
template<typename MessageT, typename AllocatorT, typename PublisherT>
|
||||
std::shared_ptr<PublisherT>
|
||||
Node::create_publisher(
|
||||
const std::string & topic_name,
|
||||
const rmw_qos_profile_t & qos_profile,
|
||||
std::shared_ptr<AllocatorT> allocator)
|
||||
{
|
||||
rclcpp::QoS qos(rclcpp::QoSInitialization::from_rmw(qos_profile));
|
||||
qos.get_rmw_qos_profile() = qos_profile;
|
||||
|
||||
PublisherOptionsWithAllocator<AllocatorT> pub_options;
|
||||
pub_options.allocator = allocator;
|
||||
return this->create_publisher<MessageT, AllocatorT, PublisherT>(topic_name, qos, pub_options);
|
||||
}
|
||||
|
||||
template<
|
||||
typename MessageT,
|
||||
typename CallbackT,
|
||||
typename AllocatorT,
|
||||
typename SubscriptionT>
|
||||
typename CallbackMessageT,
|
||||
typename SubscriptionT,
|
||||
typename MessageMemoryStrategyT>
|
||||
std::shared_ptr<SubscriptionT>
|
||||
Node::create_subscription(
|
||||
const std::string & topic_name,
|
||||
const rclcpp::QoS & qos,
|
||||
CallbackT && callback,
|
||||
const SubscriptionOptionsWithAllocator<AllocatorT> & options,
|
||||
typename rclcpp::message_memory_strategy::MessageMemoryStrategy<
|
||||
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type, AllocatorT>::SharedPtr
|
||||
msg_mem_strat)
|
||||
typename MessageMemoryStrategyT::SharedPtr msg_mem_strat)
|
||||
{
|
||||
return rclcpp::create_subscription<MessageT>(
|
||||
*this,
|
||||
@@ -130,65 +103,6 @@ Node::create_subscription(
|
||||
msg_mem_strat);
|
||||
}
|
||||
|
||||
template<
|
||||
typename MessageT,
|
||||
typename CallbackT,
|
||||
typename Alloc,
|
||||
typename SubscriptionT>
|
||||
std::shared_ptr<SubscriptionT>
|
||||
Node::create_subscription(
|
||||
const std::string & topic_name,
|
||||
CallbackT && callback,
|
||||
const rmw_qos_profile_t & qos_profile,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group,
|
||||
bool ignore_local_publications,
|
||||
typename rclcpp::message_memory_strategy::MessageMemoryStrategy<
|
||||
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type, Alloc>::SharedPtr
|
||||
msg_mem_strat,
|
||||
std::shared_ptr<Alloc> allocator)
|
||||
{
|
||||
rclcpp::QoS qos(rclcpp::QoSInitialization::from_rmw(qos_profile));
|
||||
qos.get_rmw_qos_profile() = qos_profile;
|
||||
|
||||
SubscriptionOptionsWithAllocator<Alloc> sub_options;
|
||||
sub_options.callback_group = group;
|
||||
sub_options.ignore_local_publications = ignore_local_publications;
|
||||
sub_options.allocator = allocator;
|
||||
|
||||
return this->create_subscription<MessageT, CallbackT, Alloc, SubscriptionT>(
|
||||
topic_name, qos, std::forward<CallbackT>(callback), sub_options, msg_mem_strat);
|
||||
}
|
||||
|
||||
template<
|
||||
typename MessageT,
|
||||
typename CallbackT,
|
||||
typename Alloc,
|
||||
typename SubscriptionT>
|
||||
std::shared_ptr<SubscriptionT>
|
||||
Node::create_subscription(
|
||||
const std::string & topic_name,
|
||||
CallbackT && callback,
|
||||
size_t qos_history_depth,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group,
|
||||
bool ignore_local_publications,
|
||||
typename rclcpp::message_memory_strategy::MessageMemoryStrategy<
|
||||
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type, Alloc>::SharedPtr
|
||||
msg_mem_strat,
|
||||
std::shared_ptr<Alloc> allocator)
|
||||
{
|
||||
SubscriptionOptionsWithAllocator<Alloc> sub_options;
|
||||
sub_options.callback_group = group;
|
||||
sub_options.ignore_local_publications = ignore_local_publications;
|
||||
sub_options.allocator = allocator;
|
||||
|
||||
return this->create_subscription<MessageT, CallbackT, Alloc, SubscriptionT>(
|
||||
topic_name,
|
||||
rclcpp::QoS(rclcpp::KeepLast(qos_history_depth)),
|
||||
std::forward<CallbackT>(callback),
|
||||
sub_options,
|
||||
msg_mem_strat);
|
||||
}
|
||||
|
||||
template<typename DurationRepT, typename DurationT, typename CallbackT>
|
||||
typename rclcpp::WallTimer<CallbackT>::SharedPtr
|
||||
Node::create_wall_timer(
|
||||
@@ -211,21 +125,13 @@ Node::create_client(
|
||||
const rmw_qos_profile_t & qos_profile,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group)
|
||||
{
|
||||
rcl_client_options_t options = rcl_client_get_default_options();
|
||||
options.qos = qos_profile;
|
||||
|
||||
using rclcpp::Client;
|
||||
using rclcpp::ClientBase;
|
||||
|
||||
auto cli = Client<ServiceT>::make_shared(
|
||||
node_base_.get(),
|
||||
return rclcpp::create_client<ServiceT>(
|
||||
node_base_,
|
||||
node_graph_,
|
||||
node_services_,
|
||||
extend_name_with_sub_namespace(service_name, this->get_sub_namespace()),
|
||||
options);
|
||||
|
||||
auto cli_base_ptr = std::dynamic_pointer_cast<ClientBase>(cli);
|
||||
node_services_->add_client(cli_base_ptr, group);
|
||||
return cli;
|
||||
qos_profile,
|
||||
group);
|
||||
}
|
||||
|
||||
template<typename ServiceT, typename CallbackT>
|
||||
@@ -250,12 +156,14 @@ auto
|
||||
Node::declare_parameter(
|
||||
const std::string & name,
|
||||
const ParameterT & default_value,
|
||||
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor)
|
||||
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor,
|
||||
bool ignore_override)
|
||||
{
|
||||
return this->declare_parameter(
|
||||
name,
|
||||
rclcpp::ParameterValue(default_value),
|
||||
parameter_descriptor
|
||||
parameter_descriptor,
|
||||
ignore_override
|
||||
).get<ParameterT>();
|
||||
}
|
||||
|
||||
@@ -263,14 +171,19 @@ template<typename ParameterT>
|
||||
std::vector<ParameterT>
|
||||
Node::declare_parameters(
|
||||
const std::string & namespace_,
|
||||
const std::map<std::string, ParameterT> & parameters)
|
||||
const std::map<std::string, ParameterT> & parameters,
|
||||
bool ignore_overrides)
|
||||
{
|
||||
std::vector<ParameterT> result;
|
||||
std::string normalized_namespace = namespace_.empty() ? "" : (namespace_ + ".");
|
||||
std::transform(
|
||||
parameters.begin(), parameters.end(), std::back_inserter(result),
|
||||
[this, &normalized_namespace](auto element) {
|
||||
return this->declare_parameter(normalized_namespace + element.first, element.second);
|
||||
[this, &normalized_namespace, ignore_overrides](auto element) {
|
||||
return this->declare_parameter(
|
||||
normalized_namespace + element.first,
|
||||
element.second,
|
||||
rcl_interfaces::msg::ParameterDescriptor(),
|
||||
ignore_overrides);
|
||||
}
|
||||
);
|
||||
return result;
|
||||
@@ -283,62 +196,26 @@ Node::declare_parameters(
|
||||
const std::map<
|
||||
std::string,
|
||||
std::pair<ParameterT, rcl_interfaces::msg::ParameterDescriptor>
|
||||
> & parameters)
|
||||
> & parameters,
|
||||
bool ignore_overrides)
|
||||
{
|
||||
std::vector<ParameterT> result;
|
||||
std::string normalized_namespace = namespace_.empty() ? "" : (namespace_ + ".");
|
||||
std::transform(
|
||||
parameters.begin(), parameters.end(), std::back_inserter(result),
|
||||
[this, &normalized_namespace](auto element) {
|
||||
[this, &normalized_namespace, ignore_overrides](auto element) {
|
||||
return static_cast<ParameterT>(
|
||||
this->declare_parameter(
|
||||
normalized_namespace + element.first,
|
||||
element.second.first,
|
||||
element.second.second)
|
||||
element.second.second,
|
||||
ignore_overrides)
|
||||
);
|
||||
}
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename ParameterT>
|
||||
void
|
||||
Node::set_parameter_if_not_set(
|
||||
const std::string & name,
|
||||
const ParameterT & value)
|
||||
{
|
||||
if (
|
||||
!this->has_parameter(name) ||
|
||||
this->describe_parameter(name).type == PARAMETER_NOT_SET)
|
||||
{
|
||||
this->set_parameter(rclcpp::Parameter(name, value));
|
||||
}
|
||||
}
|
||||
|
||||
// this is a partially-specialized version of set_parameter_if_not_set above,
|
||||
// where our concrete type for ParameterT is std::map, but the to-be-determined
|
||||
// type is the value in the map.
|
||||
template<typename ParameterT>
|
||||
void
|
||||
Node::set_parameters_if_not_set(
|
||||
const std::string & name,
|
||||
const std::map<std::string, ParameterT> & values)
|
||||
{
|
||||
std::vector<rclcpp::Parameter> params;
|
||||
|
||||
for (const auto & val : values) {
|
||||
std::string parameter_name = name + "." + val.first;
|
||||
if (
|
||||
!this->has_parameter(parameter_name) ||
|
||||
this->describe_parameter(parameter_name).type == PARAMETER_NOT_SET)
|
||||
{
|
||||
params.push_back(rclcpp::Parameter(parameter_name, val.second));
|
||||
}
|
||||
}
|
||||
|
||||
this->set_parameters(params);
|
||||
}
|
||||
|
||||
template<typename ParameterT>
|
||||
bool
|
||||
Node::get_parameter(const std::string & name, ParameterT & parameter) const
|
||||
@@ -391,31 +268,6 @@ Node::get_parameters(
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename ParameterT>
|
||||
void
|
||||
Node::get_parameter_or_set(
|
||||
const std::string & name,
|
||||
ParameterT & value,
|
||||
const ParameterT & alternative_value)
|
||||
{
|
||||
std::string sub_name = extend_name_with_sub_namespace(name, this->get_sub_namespace());
|
||||
|
||||
bool got_parameter = get_parameter(sub_name, value);
|
||||
if (!got_parameter) {
|
||||
this->set_parameters({
|
||||
rclcpp::Parameter(sub_name, alternative_value),
|
||||
});
|
||||
value = alternative_value;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename CallbackT>
|
||||
void
|
||||
Node::register_param_change_callback(CallbackT && callback)
|
||||
{
|
||||
this->node_parameters_->register_param_change_callback(std::forward<CallbackT>(callback));
|
||||
}
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__NODE_IMPL_HPP_
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
// Copyright 2019 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__NODE_INTERFACES__GET_NODE_BASE_INTERFACE_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__GET_NODE_BASE_INTERFACE_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
|
||||
/// This header provides the get_node_base_interface() template function.
|
||||
/**
|
||||
* This function is useful for getting the NodeBaseInterface pointer from
|
||||
* various kinds of Node-like classes.
|
||||
*
|
||||
* It's able to get the NodeBaseInterface pointer so long as the class
|
||||
* has a method called ``get_node_base_interface()`` which returns
|
||||
* either a pointer (const or not) to a NodeBaseInterface or a
|
||||
* std::shared_ptr to a NodeBaseInterface.
|
||||
*/
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace node_interfaces
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
// This is a meta-programming checker for if a given Node-like object has a
|
||||
// getter called get_node_base_interface() which returns various types,
|
||||
// e.g. const pointer or a shared pointer.
|
||||
template<typename NodeType, typename ReturnType>
|
||||
struct has_get_node_base_interface
|
||||
{
|
||||
private:
|
||||
template<typename T>
|
||||
static constexpr
|
||||
auto
|
||||
check(T *)->typename std::is_same<
|
||||
decltype(std::declval<T>().get_node_base_interface()),
|
||||
ReturnType
|
||||
>::type;
|
||||
|
||||
template<typename>
|
||||
static constexpr
|
||||
std::false_type
|
||||
check(...);
|
||||
|
||||
public:
|
||||
using type = decltype(check<NodeType>(nullptr));
|
||||
static constexpr bool value = type::value;
|
||||
};
|
||||
|
||||
// If NodeType is a pointer to NodeBaseInterface already (just normal function overload).
|
||||
inline
|
||||
rclcpp::node_interfaces::NodeBaseInterface *
|
||||
get_node_base_interface_from_pointer(rclcpp::node_interfaces::NodeBaseInterface * pointer)
|
||||
{
|
||||
return pointer;
|
||||
}
|
||||
|
||||
// If NodeType has a method called get_node_base_interface() which returns a shared pointer.
|
||||
template<
|
||||
typename NodeType,
|
||||
typename std::enable_if<has_get_node_base_interface<
|
||||
typename std::remove_pointer<NodeType>::type,
|
||||
std::shared_ptr<rclcpp::node_interfaces::NodeBaseInterface>
|
||||
>::value, int>::type = 0
|
||||
>
|
||||
rclcpp::node_interfaces::NodeBaseInterface *
|
||||
get_node_base_interface_from_pointer(NodeType node_pointer)
|
||||
{
|
||||
return node_pointer->get_node_base_interface().get();
|
||||
}
|
||||
|
||||
// If NodeType has a method called get_node_base_interface() which returns a pointer.
|
||||
template<
|
||||
typename NodeType,
|
||||
typename std::enable_if<has_get_node_base_interface<
|
||||
typename std::remove_pointer<NodeType>::type,
|
||||
rclcpp::node_interfaces::NodeBaseInterface *
|
||||
>::value, int>::type = 0
|
||||
>
|
||||
rclcpp::node_interfaces::NodeBaseInterface *
|
||||
get_node_base_interface_from_pointer(NodeType node_pointer)
|
||||
{
|
||||
return node_pointer->get_node_base_interface();
|
||||
}
|
||||
|
||||
// Forward shared_ptr's to const node pointer signatures.
|
||||
template<
|
||||
typename NodeType,
|
||||
typename std::enable_if<std::is_same<
|
||||
NodeType,
|
||||
typename std::shared_ptr<typename std::remove_pointer<NodeType>::type::element_type> *
|
||||
>::value, int>::type = 0
|
||||
>
|
||||
rclcpp::node_interfaces::NodeBaseInterface *
|
||||
get_node_base_interface_from_pointer(NodeType node_shared_pointer)
|
||||
{
|
||||
return get_node_base_interface_from_pointer(node_shared_pointer->get());
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// Get the NodeBaseInterface as a pointer from a pointer to a "Node like" object.
|
||||
template<
|
||||
typename NodeType,
|
||||
typename std::enable_if<std::is_pointer<NodeType>::value, int>::type = 0
|
||||
>
|
||||
rclcpp::node_interfaces::NodeBaseInterface *
|
||||
get_node_base_interface(NodeType node_pointer)
|
||||
{
|
||||
// Forward pointers to detail implmentation directly.
|
||||
return detail::get_node_base_interface_from_pointer(node_pointer);
|
||||
}
|
||||
|
||||
/// Get the NodeBaseInterface as a pointer from a "Node like" object.
|
||||
template<
|
||||
typename NodeType,
|
||||
typename std::enable_if<
|
||||
!std::is_pointer<typename std::remove_reference<NodeType>::type>::value, int
|
||||
>::type = 0
|
||||
>
|
||||
rclcpp::node_interfaces::NodeBaseInterface *
|
||||
get_node_base_interface(NodeType && node_reference)
|
||||
{
|
||||
// Forward references to detail implmentation as a pointer.
|
||||
return detail::get_node_base_interface_from_pointer(&node_reference);
|
||||
}
|
||||
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__GET_NODE_BASE_INTERFACE_HPP_
|
||||
@@ -0,0 +1,149 @@
|
||||
// Copyright 2019 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__NODE_INTERFACES__GET_NODE_TIMERS_INTERFACE_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__GET_NODE_TIMERS_INTERFACE_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
|
||||
#include "rclcpp/node_interfaces/node_timers_interface.hpp"
|
||||
|
||||
/// This header provides the get_node_timers_interface() template function.
|
||||
/**
|
||||
* This function is useful for getting the NodeTimersInterface pointer from
|
||||
* various kinds of Node-like classes.
|
||||
*
|
||||
* It's able to get the NodeTimersInterface pointer so long as the class
|
||||
* has a method called ``get_node_timers_interface()`` which returns
|
||||
* either a pointer (const or not) to a NodeTimersInterface or a
|
||||
* std::shared_ptr to a NodeTimersInterface.
|
||||
*/
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace node_interfaces
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
||||
// This is a meta-programming checker for if a given Node-like object has a
|
||||
// getter called get_node_timers_interface() which returns various types,
|
||||
// e.g. const pointer or a shared pointer.
|
||||
template<typename NodeType, typename ReturnType>
|
||||
struct has_get_node_timers_interface
|
||||
{
|
||||
private:
|
||||
template<typename T>
|
||||
static constexpr
|
||||
auto
|
||||
check(T *)->typename std::is_same<
|
||||
decltype(std::declval<T>().get_node_timers_interface()),
|
||||
ReturnType
|
||||
>::type;
|
||||
|
||||
template<typename>
|
||||
static constexpr
|
||||
std::false_type
|
||||
check(...);
|
||||
|
||||
public:
|
||||
using type = decltype(check<NodeType>(nullptr));
|
||||
static constexpr bool value = type::value;
|
||||
};
|
||||
|
||||
// If NodeType is a pointer to NodeTimersInterface already (just normal function overload).
|
||||
inline
|
||||
rclcpp::node_interfaces::NodeTimersInterface *
|
||||
get_node_timers_interface_from_pointer(rclcpp::node_interfaces::NodeTimersInterface * pointer)
|
||||
{
|
||||
return pointer;
|
||||
}
|
||||
|
||||
// If NodeType has a method called get_node_timers_interface() which returns a shared pointer.
|
||||
template<
|
||||
typename NodeType,
|
||||
typename std::enable_if<has_get_node_timers_interface<
|
||||
typename std::remove_pointer<NodeType>::type,
|
||||
std::shared_ptr<rclcpp::node_interfaces::NodeTimersInterface>
|
||||
>::value, int>::type = 0
|
||||
>
|
||||
rclcpp::node_interfaces::NodeTimersInterface *
|
||||
get_node_timers_interface_from_pointer(NodeType node_pointer)
|
||||
{
|
||||
return node_pointer->get_node_timers_interface().get();
|
||||
}
|
||||
|
||||
// If NodeType has a method called get_node_timers_interface() which returns a pointer.
|
||||
template<
|
||||
typename NodeType,
|
||||
typename std::enable_if<has_get_node_timers_interface<
|
||||
typename std::remove_pointer<NodeType>::type,
|
||||
rclcpp::node_interfaces::NodeTimersInterface *
|
||||
>::value, int>::type = 0
|
||||
>
|
||||
rclcpp::node_interfaces::NodeTimersInterface *
|
||||
get_node_timers_interface_from_pointer(NodeType node_pointer)
|
||||
{
|
||||
return node_pointer->get_node_timers_interface();
|
||||
}
|
||||
|
||||
// Forward shared_ptr's to const node pointer signatures.
|
||||
template<
|
||||
typename NodeType,
|
||||
typename std::enable_if<std::is_same<
|
||||
NodeType,
|
||||
typename std::shared_ptr<typename std::remove_pointer<NodeType>::type::element_type> *
|
||||
>::value, int>::type = 0
|
||||
>
|
||||
rclcpp::node_interfaces::NodeTimersInterface *
|
||||
get_node_timers_interface_from_pointer(NodeType node_shared_pointer)
|
||||
{
|
||||
return get_node_timers_interface_from_pointer(node_shared_pointer->get());
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
/// Get the NodeTimersInterface as a pointer from a pointer to a "Node like" object.
|
||||
template<
|
||||
typename NodeType,
|
||||
typename std::enable_if<std::is_pointer<NodeType>::value, int>::type = 0
|
||||
>
|
||||
rclcpp::node_interfaces::NodeTimersInterface *
|
||||
get_node_timers_interface(NodeType node_pointer)
|
||||
{
|
||||
// Forward pointers to detail implmentation directly.
|
||||
return detail::get_node_timers_interface_from_pointer(node_pointer);
|
||||
}
|
||||
|
||||
/// Get the NodeTimersInterface as a pointer from a "Node like" object.
|
||||
template<
|
||||
typename NodeType,
|
||||
typename std::enable_if<
|
||||
!std::is_pointer<typename std::remove_reference<NodeType>::type>::value, int
|
||||
>::type = 0
|
||||
>
|
||||
rclcpp::node_interfaces::NodeTimersInterface *
|
||||
get_node_timers_interface(NodeType && node_reference)
|
||||
{
|
||||
// Forward references to detail implmentation as a pointer.
|
||||
return detail::get_node_timers_interface_from_pointer(&node_reference);
|
||||
}
|
||||
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__GET_NODE_TIMERS_INTERFACE_HPP_
|
||||
@@ -123,16 +123,18 @@ template<
|
||||
typename std::enable_if<std::is_pointer<NodeType>::value, int>::type = 0
|
||||
>
|
||||
rclcpp::node_interfaces::NodeTopicsInterface *
|
||||
get_node_topics_interface(NodeType && node_pointer)
|
||||
get_node_topics_interface(NodeType node_pointer)
|
||||
{
|
||||
// Forward pointers to detail implmentation directly.
|
||||
return detail::get_node_topics_interface_from_pointer(std::forward<NodeType>(node_pointer));
|
||||
return detail::get_node_topics_interface_from_pointer(node_pointer);
|
||||
}
|
||||
|
||||
/// Get the NodeTopicsInterface as a pointer from a "Node like" object.
|
||||
template<
|
||||
typename NodeType,
|
||||
typename std::enable_if<!std::is_pointer<NodeType>::value, int>::type = 0
|
||||
typename std::enable_if<
|
||||
!std::is_pointer<typename std::remove_reference<NodeType>::type>::value, int
|
||||
>::type = 0
|
||||
>
|
||||
rclcpp::node_interfaces::NodeTopicsInterface *
|
||||
get_node_topics_interface(NodeType && node_reference)
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -50,6 +51,30 @@ struct ParameterInfo
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor;
|
||||
};
|
||||
|
||||
// Internal RAII-style guard for mutation recursion
|
||||
class ParameterMutationRecursionGuard
|
||||
{
|
||||
public:
|
||||
explicit ParameterMutationRecursionGuard(bool & allow_mod)
|
||||
: allow_modification_(allow_mod)
|
||||
{
|
||||
if (!allow_modification_) {
|
||||
throw rclcpp::exceptions::ParameterModifiedInCallbackException(
|
||||
"cannot set or declare a parameter, or change the callback from within set callback");
|
||||
}
|
||||
|
||||
allow_modification_ = false;
|
||||
}
|
||||
|
||||
~ParameterMutationRecursionGuard()
|
||||
{
|
||||
allow_modification_ = true;
|
||||
}
|
||||
|
||||
private:
|
||||
bool & allow_modification_;
|
||||
};
|
||||
|
||||
/// Implementation of the NodeParameters part of the Node API.
|
||||
class NodeParameters : public NodeParametersInterface
|
||||
{
|
||||
@@ -80,7 +105,8 @@ public:
|
||||
declare_parameter(
|
||||
const std::string & name,
|
||||
const rclcpp::ParameterValue & default_value,
|
||||
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor) override;
|
||||
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor,
|
||||
bool ignore_override) override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
@@ -133,25 +159,37 @@ public:
|
||||
list_parameters(const std::vector<std::string> & prefixes, uint64_t depth) const override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
OnParametersSetCallbackType
|
||||
set_on_parameters_set_callback(OnParametersSetCallbackType callback) override;
|
||||
OnSetParametersCallbackHandle::SharedPtr
|
||||
add_on_set_parameters_callback(OnParametersSetCallbackType callback) override;
|
||||
|
||||
[[deprecated("use set_on_parameters_set_callback() instead")]]
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
register_param_change_callback(OnParametersSetCallbackType callback) override;
|
||||
remove_on_set_parameters_callback(const OnSetParametersCallbackHandle * const handler) override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
OnParametersSetCallbackType
|
||||
set_on_parameters_set_callback(OnParametersSetCallbackType callback) override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
const std::map<std::string, rclcpp::ParameterValue> &
|
||||
get_parameter_overrides() const override;
|
||||
|
||||
using CallbacksContainerType = std::list<OnSetParametersCallbackHandle::WeakPtr>;
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(NodeParameters)
|
||||
|
||||
mutable std::mutex mutex_;
|
||||
mutable std::recursive_mutex mutex_;
|
||||
|
||||
// There are times when we don't want to allow modifications to parameters
|
||||
// (particularly when a set_parameter callback tries to call set_parameter,
|
||||
// declare_parameter, etc). In those cases, this will be set to false.
|
||||
bool parameter_modification_enabled_{true};
|
||||
|
||||
OnParametersSetCallbackType on_parameters_set_callback_ = nullptr;
|
||||
|
||||
CallbacksContainerType on_parameters_set_callback_container_;
|
||||
|
||||
std::map<std::string, ParameterInfo> parameters_;
|
||||
|
||||
std::map<std::string, rclcpp::ParameterValue> parameter_overrides_;
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#define RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_INTERFACE_HPP_
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -32,6 +33,18 @@ namespace rclcpp
|
||||
namespace node_interfaces
|
||||
{
|
||||
|
||||
struct OnSetParametersCallbackHandle
|
||||
{
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(OnSetParametersCallbackHandle)
|
||||
|
||||
using OnParametersSetCallbackType =
|
||||
std::function<
|
||||
rcl_interfaces::msg::SetParametersResult(
|
||||
const std::vector<rclcpp::Parameter> &)>;
|
||||
|
||||
OnParametersSetCallbackType callback;
|
||||
};
|
||||
|
||||
/// Pure virtual interface class for the NodeParameters part of the Node API.
|
||||
class NodeParametersInterface
|
||||
{
|
||||
@@ -51,8 +64,10 @@ public:
|
||||
const rclcpp::ParameterValue &
|
||||
declare_parameter(
|
||||
const std::string & name,
|
||||
const rclcpp::ParameterValue & default_value,
|
||||
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor) = 0;
|
||||
const rclcpp::ParameterValue & default_value = rclcpp::ParameterValue(),
|
||||
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor =
|
||||
rcl_interfaces::msg::ParameterDescriptor(),
|
||||
bool ignore_override = false) = 0;
|
||||
|
||||
/// Undeclare a parameter.
|
||||
/**
|
||||
@@ -156,13 +171,25 @@ public:
|
||||
rcl_interfaces::msg::ListParametersResult
|
||||
list_parameters(const std::vector<std::string> & prefixes, uint64_t depth) const = 0;
|
||||
|
||||
using OnParametersSetCallbackType =
|
||||
std::function<
|
||||
rcl_interfaces::msg::SetParametersResult(const std::vector<rclcpp::Parameter> &)
|
||||
>;
|
||||
using OnParametersSetCallbackType = OnSetParametersCallbackHandle::OnParametersSetCallbackType;
|
||||
|
||||
using ParametersCallbackFunction [[deprecated("use OnParametersSetCallbackType instead")]] =
|
||||
OnParametersSetCallbackType;
|
||||
/// Add a callback for when parameters are being set.
|
||||
/**
|
||||
* \sa rclcpp::Node::add_on_set_parameters_callback
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
OnSetParametersCallbackHandle::SharedPtr
|
||||
add_on_set_parameters_callback(OnParametersSetCallbackType callback) = 0;
|
||||
|
||||
/// Remove a callback registered with `add_on_set_parameters_callback`.
|
||||
/**
|
||||
* \sa rclcpp::Node::remove_on_set_parameters_callback
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
remove_on_set_parameters_callback(const OnSetParametersCallbackHandle * const handler) = 0;
|
||||
|
||||
/// Register a callback for when parameters are being set, return an existing one.
|
||||
/**
|
||||
@@ -173,12 +200,6 @@ public:
|
||||
OnParametersSetCallbackType
|
||||
set_on_parameters_set_callback(OnParametersSetCallbackType callback) = 0;
|
||||
|
||||
[[deprecated("use set_on_parameters_set_callback() instead")]]
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
register_param_change_callback(OnParametersSetCallbackType callback) = 0;
|
||||
|
||||
/// Return the initial parameter values used by the NodeParameters to override default values.
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
|
||||
@@ -49,8 +49,7 @@ public:
|
||||
create_publisher(
|
||||
const std::string & topic_name,
|
||||
const rclcpp::PublisherFactory & publisher_factory,
|
||||
const rcl_publisher_options_t & publisher_options,
|
||||
bool use_intra_process) override;
|
||||
const rclcpp::QoS & qos) override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
@@ -63,8 +62,7 @@ public:
|
||||
create_subscription(
|
||||
const std::string & topic_name,
|
||||
const rclcpp::SubscriptionFactory & subscription_factory,
|
||||
const rcl_subscription_options_t & subscription_options,
|
||||
bool use_intra_process) override;
|
||||
const rclcpp::QoS & qos) override;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
|
||||
@@ -50,8 +50,7 @@ public:
|
||||
create_publisher(
|
||||
const std::string & topic_name,
|
||||
const rclcpp::PublisherFactory & publisher_factory,
|
||||
const rcl_publisher_options_t & publisher_options,
|
||||
bool use_intra_process) = 0;
|
||||
const rclcpp::QoS & qos) = 0;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
@@ -66,8 +65,7 @@ public:
|
||||
create_subscription(
|
||||
const std::string & topic_name,
|
||||
const rclcpp::SubscriptionFactory & subscription_factory,
|
||||
const rcl_subscription_options_t & subscription_options,
|
||||
bool use_intra_process) = 0;
|
||||
const rclcpp::QoS & qos) = 0;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
|
||||
@@ -99,7 +99,7 @@ public:
|
||||
/// Set the arguments, return this for parameter idiom.
|
||||
/**
|
||||
* These arguments are used to extract remappings used by the node and other
|
||||
* settings.
|
||||
* ROS specific settings, as well as user defined non-ROS arguments.
|
||||
*
|
||||
* This will cause the internal rcl_node_options_t struct to be invalidated.
|
||||
*/
|
||||
|
||||
@@ -53,19 +53,22 @@ public:
|
||||
const rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph_interface,
|
||||
const rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services_interface,
|
||||
const std::string & remote_node_name = "",
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters);
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
AsyncParametersClient(
|
||||
const rclcpp::Node::SharedPtr node,
|
||||
const std::string & remote_node_name = "",
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters);
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
AsyncParametersClient(
|
||||
rclcpp::Node * node,
|
||||
const std::string & remote_node_name = "",
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters);
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
std::shared_future<std::vector<rclcpp::Parameter>>
|
||||
@@ -115,7 +118,7 @@ public:
|
||||
on_parameter_event(
|
||||
CallbackT && callback,
|
||||
const rclcpp::QoS & qos = (
|
||||
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(rmw_qos_profile_default))
|
||||
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(rmw_qos_profile_parameter_events))
|
||||
),
|
||||
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options = (
|
||||
rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>()
|
||||
@@ -142,7 +145,7 @@ public:
|
||||
NodeT && node,
|
||||
CallbackT && callback,
|
||||
const rclcpp::QoS & qos = (
|
||||
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(rmw_qos_profile_default))
|
||||
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(rmw_qos_profile_parameter_events))
|
||||
),
|
||||
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options = (
|
||||
rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>()
|
||||
@@ -268,7 +271,11 @@ public:
|
||||
{
|
||||
return get_parameter_impl(
|
||||
parameter_name,
|
||||
std::function<T()>([]() -> T {throw std::runtime_error("Parameter not set");}));
|
||||
std::function<T()>([¶meter_name]() -> T
|
||||
{
|
||||
throw std::runtime_error("Parameter '" + parameter_name + "' is not set");
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
|
||||
@@ -44,16 +44,20 @@ public:
|
||||
* \param[in] event The parameter event message to filter.
|
||||
* \param[in] names A list of parameter names of interest.
|
||||
* \param[in] types A list of the types of parameter events of iterest.
|
||||
* EventType NEW, DELETED, or CHANGED
|
||||
*
|
||||
* Example Usage:
|
||||
* If you have recieved a parameter event and are only interested in parameters foo and
|
||||
* bar being added or changed but don't care about deletion.
|
||||
* auto res = rclcpp::ParameterEventsFilter(
|
||||
* event_shared_ptr,
|
||||
* {"foo", "bar"},
|
||||
* {rclcpp::ParameterEventsFilter::EventType::NEW, rclcpp::ParameterEventsFilter::EventType::CHANGED});
|
||||
*/
|
||||
* EventType NEW, DELETED, or CHANGED
|
||||
*
|
||||
* Example Usage:
|
||||
*
|
||||
* If you have recieved a parameter event and are only interested in parameters foo and
|
||||
* bar being added or changed but don't care about deletion.
|
||||
*
|
||||
* ```cpp
|
||||
* auto res = rclcpp::ParameterEventsFilter(
|
||||
* event_shared_ptr,
|
||||
* {"foo", "bar"},
|
||||
* {rclcpp::ParameterEventsFilter::EventType::NEW, rclcpp::ParameterEventsFilter::EventType::CHANGED});
|
||||
* ```
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
ParameterEventsFilter(
|
||||
rcl_interfaces::msg::ParameterEvent::SharedPtr event,
|
||||
|
||||
@@ -32,9 +32,12 @@
|
||||
|
||||
#include "rclcpp/allocator/allocator_common.hpp"
|
||||
#include "rclcpp/allocator/allocator_deleter.hpp"
|
||||
#include "rclcpp/detail/resolve_use_intra_process.hpp"
|
||||
#include "rclcpp/intra_process_manager.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/publisher_base.hpp"
|
||||
#include "rclcpp/publisher_options.hpp"
|
||||
#include "rclcpp/type_support_decl.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
@@ -42,41 +45,79 @@ namespace rclcpp
|
||||
{
|
||||
|
||||
/// A publisher publishes messages of any type to a topic.
|
||||
template<typename MessageT, typename Alloc = std::allocator<void>>
|
||||
template<typename MessageT, typename AllocatorT = std::allocator<void>>
|
||||
class Publisher : public PublisherBase
|
||||
{
|
||||
public:
|
||||
using MessageAllocTraits = allocator::AllocRebind<MessageT, Alloc>;
|
||||
using MessageAlloc = typename MessageAllocTraits::allocator_type;
|
||||
using MessageDeleter = allocator::Deleter<MessageAlloc, MessageT>;
|
||||
using MessageAllocatorTraits = allocator::AllocRebind<MessageT, AllocatorT>;
|
||||
using MessageAllocator = typename MessageAllocatorTraits::allocator_type;
|
||||
using MessageDeleter = allocator::Deleter<MessageAllocator, MessageT>;
|
||||
using MessageUniquePtr = std::unique_ptr<MessageT, MessageDeleter>;
|
||||
using MessageSharedPtr = std::shared_ptr<const MessageT>;
|
||||
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(Publisher<MessageT, Alloc>)
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(Publisher<MessageT, AllocatorT>)
|
||||
|
||||
Publisher(
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||
const std::string & topic,
|
||||
const rcl_publisher_options_t & publisher_options,
|
||||
const PublisherEventCallbacks & event_callbacks,
|
||||
const std::shared_ptr<MessageAlloc> & allocator)
|
||||
const rclcpp::QoS & qos,
|
||||
const rclcpp::PublisherOptionsWithAllocator<AllocatorT> & options)
|
||||
: PublisherBase(
|
||||
node_base,
|
||||
topic,
|
||||
*rosidl_typesupport_cpp::get_message_type_support_handle<MessageT>(),
|
||||
publisher_options),
|
||||
message_allocator_(allocator)
|
||||
options.template to_rcl_publisher_options<MessageT>(qos)),
|
||||
options_(options),
|
||||
message_allocator_(new MessageAllocator(*options.get_allocator().get()))
|
||||
{
|
||||
allocator::set_allocator_for_deleter(&message_deleter_, message_allocator_.get());
|
||||
|
||||
if (event_callbacks.deadline_callback) {
|
||||
this->add_event_handler(event_callbacks.deadline_callback,
|
||||
if (options_.event_callbacks.deadline_callback) {
|
||||
this->add_event_handler(
|
||||
options_.event_callbacks.deadline_callback,
|
||||
RCL_PUBLISHER_OFFERED_DEADLINE_MISSED);
|
||||
}
|
||||
if (event_callbacks.liveliness_callback) {
|
||||
this->add_event_handler(event_callbacks.liveliness_callback,
|
||||
if (options_.event_callbacks.liveliness_callback) {
|
||||
this->add_event_handler(
|
||||
options_.event_callbacks.liveliness_callback,
|
||||
RCL_PUBLISHER_LIVELINESS_LOST);
|
||||
}
|
||||
|
||||
// Setup continues in the post construction method, post_init_setup().
|
||||
}
|
||||
|
||||
/// Called post construction, so that construction may continue after shared_from_this() works.
|
||||
virtual
|
||||
void
|
||||
post_init_setup(
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||
const std::string & topic,
|
||||
const rclcpp::QoS & qos,
|
||||
const rclcpp::PublisherOptionsWithAllocator<AllocatorT> & options)
|
||||
{
|
||||
// Topic is unused for now.
|
||||
(void)topic;
|
||||
|
||||
// If needed, setup intra process communication.
|
||||
if (rclcpp::detail::resolve_use_intra_process(options_, *node_base)) {
|
||||
auto context = node_base->get_context();
|
||||
// Get the intra process manager instance for this context.
|
||||
auto ipm = context->get_sub_context<rclcpp::intra_process_manager::IntraProcessManager>();
|
||||
// Register the publisher with the intra process manager.
|
||||
if (qos.get_rmw_qos_profile().history == RMW_QOS_POLICY_HISTORY_KEEP_ALL) {
|
||||
throw std::invalid_argument(
|
||||
"intraprocess communication is not allowed with keep all history qos policy");
|
||||
}
|
||||
if (qos.get_rmw_qos_profile().depth == 0) {
|
||||
throw std::invalid_argument(
|
||||
"intraprocess communication is not allowed with a zero qos history depth value");
|
||||
}
|
||||
uint64_t intra_process_publisher_id = ipm->add_publisher(this->shared_from_this());
|
||||
this->setup_intra_process(
|
||||
intra_process_publisher_id,
|
||||
ipm,
|
||||
options.template to_rcl_publisher_options<MessageT>(qos));
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~Publisher()
|
||||
@@ -87,7 +128,7 @@ public:
|
||||
{
|
||||
return mapped_ring_buffer::MappedRingBuffer<
|
||||
MessageT,
|
||||
typename Publisher<MessageT, Alloc>::MessageAlloc
|
||||
typename Publisher<MessageT, AllocatorT>::MessageAllocator
|
||||
>::make_shared(size, this->get_allocator());
|
||||
}
|
||||
|
||||
@@ -127,18 +168,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
// Skip deprecated attribute in windows, as it raise a warning in template specialization.
|
||||
#if !defined(_WIN32)
|
||||
[[deprecated(
|
||||
"publishing an unique_ptr is prefered when using intra process communication."
|
||||
" If using a shared_ptr, use publish(*msg).")]]
|
||||
#endif
|
||||
virtual void
|
||||
publish(const std::shared_ptr<const MessageT> & msg)
|
||||
{
|
||||
publish(*msg);
|
||||
}
|
||||
|
||||
virtual void
|
||||
publish(const MessageT & msg)
|
||||
{
|
||||
@@ -150,55 +179,20 @@ public:
|
||||
// Otherwise we have to allocate memory in a unique_ptr and pass it along.
|
||||
// As the message is not const, a copy should be made.
|
||||
// A shared_ptr<const MessageT> could also be constructed here.
|
||||
auto ptr = MessageAllocTraits::allocate(*message_allocator_.get(), 1);
|
||||
MessageAllocTraits::construct(*message_allocator_.get(), ptr, msg);
|
||||
auto ptr = MessageAllocatorTraits::allocate(*message_allocator_.get(), 1);
|
||||
MessageAllocatorTraits::construct(*message_allocator_.get(), ptr, msg);
|
||||
MessageUniquePtr unique_msg(ptr, message_deleter_);
|
||||
this->publish(std::move(unique_msg));
|
||||
}
|
||||
|
||||
// Skip deprecated attribute in windows, as it raise a warning in template specialization.
|
||||
#if !defined(_WIN32)
|
||||
[[deprecated(
|
||||
"Use publish(*msg). Check against nullptr before calling if necessary.")]]
|
||||
#endif
|
||||
virtual void
|
||||
publish(const MessageT * msg)
|
||||
{
|
||||
if (!msg) {
|
||||
throw std::runtime_error("msg argument is nullptr");
|
||||
}
|
||||
return this->publish(*msg);
|
||||
}
|
||||
|
||||
void
|
||||
publish(const rcl_serialized_message_t & serialized_msg)
|
||||
{
|
||||
return this->do_serialized_publish(&serialized_msg);
|
||||
}
|
||||
|
||||
// Skip deprecated attribute in windows, as it raise a warning in template specialization.
|
||||
#if !defined(_WIN32)
|
||||
[[deprecated(
|
||||
"Use publish(*serialized_msg). Check against nullptr before calling if necessary.")]]
|
||||
#endif
|
||||
void
|
||||
publish(const rcl_serialized_message_t * serialized_msg)
|
||||
{
|
||||
return this->do_serialized_publish(serialized_msg);
|
||||
}
|
||||
|
||||
// Skip deprecated attribute in windows, as it raise a warning in template specialization.
|
||||
#if !defined(_WIN32)
|
||||
[[deprecated(
|
||||
"Use publish(*serialized_msg). Check against nullptr before calling if necessary.")]]
|
||||
#endif
|
||||
void
|
||||
publish(std::shared_ptr<const rcl_serialized_message_t> serialized_msg)
|
||||
{
|
||||
return this->do_serialized_publish(serialized_msg.get());
|
||||
}
|
||||
|
||||
std::shared_ptr<MessageAlloc> get_allocator() const
|
||||
std::shared_ptr<MessageAllocator>
|
||||
get_allocator() const
|
||||
{
|
||||
return message_allocator_;
|
||||
}
|
||||
@@ -272,7 +266,7 @@ protected:
|
||||
throw std::runtime_error("cannot publisher msg which is a null pointer");
|
||||
}
|
||||
uint64_t message_seq =
|
||||
ipm->template store_intra_process_message<MessageT, Alloc>(publisher_id, msg);
|
||||
ipm->template store_intra_process_message<MessageT, AllocatorT>(publisher_id, msg);
|
||||
return message_seq;
|
||||
}
|
||||
|
||||
@@ -290,11 +284,13 @@ protected:
|
||||
throw std::runtime_error("cannot publisher msg which is a null pointer");
|
||||
}
|
||||
uint64_t message_seq =
|
||||
ipm->template store_intra_process_message<MessageT, Alloc>(publisher_id, std::move(msg));
|
||||
ipm->template store_intra_process_message<MessageT, AllocatorT>(publisher_id, std::move(msg));
|
||||
return message_seq;
|
||||
}
|
||||
|
||||
std::shared_ptr<MessageAlloc> message_allocator_;
|
||||
const rclcpp::PublisherOptionsWithAllocator<AllocatorT> options_;
|
||||
|
||||
std::shared_ptr<MessageAllocator> message_allocator_;
|
||||
|
||||
MessageDeleter message_deleter_;
|
||||
};
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace intra_process_manager
|
||||
class IntraProcessManager;
|
||||
}
|
||||
|
||||
class PublisherBase
|
||||
class PublisherBase : public std::enable_shared_from_this<PublisherBase>
|
||||
{
|
||||
friend ::rclcpp::node_interfaces::NodeTopicsInterface;
|
||||
|
||||
@@ -184,8 +184,9 @@ public:
|
||||
|
||||
/// Implementation utility function that creates a typed mapped ring buffer.
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
mapped_ring_buffer::MappedRingBufferBase::SharedPtr
|
||||
virtual make_mapped_ring_buffer(size_t size) const;
|
||||
make_mapped_ring_buffer(size_t size) const;
|
||||
|
||||
/// Implementation utility function used to setup intra process publishing after creation.
|
||||
RCLCPP_PUBLIC
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "rosidl_typesupport_cpp/message_type_support.hpp"
|
||||
|
||||
#include "rclcpp/publisher.hpp"
|
||||
#include "rclcpp/publisher_options.hpp"
|
||||
#include "rclcpp/intra_process_manager.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
@@ -41,6 +42,9 @@ namespace rclcpp
|
||||
* called from a templated "create_publisher" method on the Node class, and
|
||||
* is passed to the non-templated "create_publisher" method on the NodeTopics
|
||||
* class where it is used to create and setup the Publisher.
|
||||
*
|
||||
* It also handles the two step construction of Publishers, first calling
|
||||
* the constructor and then the post_init_setup() method.
|
||||
*/
|
||||
struct PublisherFactory
|
||||
{
|
||||
@@ -49,39 +53,33 @@ struct PublisherFactory
|
||||
rclcpp::PublisherBase::SharedPtr(
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||
const std::string & topic_name,
|
||||
const rcl_publisher_options_t & publisher_options)>;
|
||||
const rclcpp::QoS & qos
|
||||
)>;
|
||||
|
||||
PublisherFactoryFunction create_typed_publisher;
|
||||
const PublisherFactoryFunction create_typed_publisher;
|
||||
};
|
||||
|
||||
/// Return a PublisherFactory with functions setup for creating a PublisherT<MessageT, Alloc>.
|
||||
template<typename MessageT, typename Alloc, typename PublisherT>
|
||||
/// Return a PublisherFactory with functions setup for creating a PublisherT<MessageT, AllocatorT>.
|
||||
template<typename MessageT, typename AllocatorT, typename PublisherT>
|
||||
PublisherFactory
|
||||
create_publisher_factory(
|
||||
const PublisherEventCallbacks & event_callbacks,
|
||||
std::shared_ptr<Alloc> allocator)
|
||||
create_publisher_factory(const rclcpp::PublisherOptionsWithAllocator<AllocatorT> & options)
|
||||
{
|
||||
PublisherFactory factory;
|
||||
|
||||
// factory function that creates a MessageT specific PublisherT
|
||||
factory.create_typed_publisher =
|
||||
[event_callbacks, allocator](
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||
const std::string & topic_name,
|
||||
const rcl_publisher_options_t & publisher_options
|
||||
PublisherFactory factory {
|
||||
// factory function that creates a MessageT specific PublisherT
|
||||
[options](
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||
const std::string & topic_name,
|
||||
const rclcpp::QoS & qos
|
||||
) -> std::shared_ptr<PublisherT>
|
||||
{
|
||||
auto options_copy = publisher_options;
|
||||
auto message_alloc = std::make_shared<typename PublisherT::MessageAlloc>(*allocator.get());
|
||||
options_copy.allocator = allocator::get_rcl_allocator<MessageT>(*message_alloc.get());
|
||||
|
||||
return std::make_shared<PublisherT>(
|
||||
node_base,
|
||||
topic_name,
|
||||
options_copy,
|
||||
event_callbacks,
|
||||
message_alloc);
|
||||
};
|
||||
auto publisher = std::make_shared<PublisherT>(node_base, topic_name, qos, options);
|
||||
// This is used for setting up things like intra process comms which
|
||||
// require this->shared_from_this() which cannot be called from
|
||||
// the constructor.
|
||||
publisher->post_init_setup(node_base, topic_name, qos, options);
|
||||
return publisher;
|
||||
}
|
||||
};
|
||||
|
||||
// return the factory now that it is populated
|
||||
return factory;
|
||||
|
||||
@@ -19,16 +19,21 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "rclcpp/callback_group.hpp"
|
||||
#include "rcl/publisher.h"
|
||||
|
||||
#include "rclcpp/allocator/allocator_common.hpp"
|
||||
#include "rclcpp/intra_process_setting.hpp"
|
||||
#include "rclcpp/qos.hpp"
|
||||
#include "rclcpp/qos_event.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
#include "rcl/publisher.h"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
namespace callback_group
|
||||
{
|
||||
class CallbackGroup;
|
||||
} // namespace callback_group
|
||||
|
||||
/// Non-templated part of PublisherOptionsWithAllocator<Allocator>.
|
||||
struct PublisherOptionsBase
|
||||
{
|
||||
@@ -39,7 +44,7 @@ struct PublisherOptionsBase
|
||||
PublisherEventCallbacks event_callbacks;
|
||||
|
||||
/// Callback group in which the waitable items from the publisher should be placed.
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr callback_group;
|
||||
std::shared_ptr<rclcpp::callback_group::CallbackGroup> callback_group;
|
||||
};
|
||||
|
||||
/// Structure containing optional configuration for Publishers.
|
||||
@@ -64,11 +69,26 @@ struct PublisherOptionsWithAllocator : public PublisherOptionsBase
|
||||
rcl_publisher_options_t result;
|
||||
using AllocatorTraits = std::allocator_traits<Allocator>;
|
||||
using MessageAllocatorT = typename AllocatorTraits::template rebind_alloc<MessageT>;
|
||||
auto message_alloc = std::make_shared<MessageAllocatorT>(*allocator.get());
|
||||
result.allocator = allocator::get_rcl_allocator<MessageT>(*message_alloc);
|
||||
auto message_alloc = std::make_shared<MessageAllocatorT>(*this->get_allocator().get());
|
||||
result.allocator = rclcpp::allocator::get_rcl_allocator<MessageT>(*message_alloc);
|
||||
result.qos = qos.get_rmw_qos_profile();
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Get the allocator, creating one if needed.
|
||||
std::shared_ptr<Allocator>
|
||||
get_allocator() const
|
||||
{
|
||||
if (!this->allocator) {
|
||||
// TODO(wjwwood): I would like to use the commented line instead, but
|
||||
// cppcheck 1.89 fails with:
|
||||
// Syntax Error: AST broken, binary operator '>' doesn't have two operands.
|
||||
// return std::make_shared<Allocator>();
|
||||
std::shared_ptr<Allocator> tmp(new Allocator());
|
||||
return tmp;
|
||||
}
|
||||
return this->allocator;
|
||||
}
|
||||
};
|
||||
|
||||
using PublisherOptions = PublisherOptionsWithAllocator<std::allocator<void>>;
|
||||
|
||||
@@ -48,7 +48,8 @@
|
||||
* - rclcpp::Node::get_parameter()
|
||||
* - rclcpp::Node::describe_parameters()
|
||||
* - rclcpp::Node::list_parameters()
|
||||
* - rclcpp::Node::register_param_change_callback()
|
||||
* - rclcpp::Node::add_on_set_parameters_callback()
|
||||
* - rclcpp::Node::remove_on_set_parameters_callback()
|
||||
* - rclcpp::Parameter
|
||||
* - rclcpp::ParameterValue
|
||||
* - rclcpp::AsyncParametersClient
|
||||
|
||||
@@ -164,40 +164,31 @@ public:
|
||||
if (!group || !group->can_be_taken_from().load()) {
|
||||
continue;
|
||||
}
|
||||
for (auto & weak_subscription : group->get_subscription_ptrs()) {
|
||||
auto subscription = weak_subscription.lock();
|
||||
if (subscription) {
|
||||
group->find_subscription_ptrs_if(
|
||||
[this](const rclcpp::SubscriptionBase::SharedPtr & subscription) {
|
||||
subscription_handles_.push_back(subscription->get_subscription_handle());
|
||||
if (subscription->get_intra_process_subscription_handle()) {
|
||||
subscription_handles_.push_back(
|
||||
subscription->get_intra_process_subscription_handle());
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto & weak_service : group->get_service_ptrs()) {
|
||||
auto service = weak_service.lock();
|
||||
if (service) {
|
||||
return false;
|
||||
});
|
||||
group->find_service_ptrs_if([this](const rclcpp::ServiceBase::SharedPtr & service) {
|
||||
service_handles_.push_back(service->get_service_handle());
|
||||
}
|
||||
}
|
||||
for (auto & weak_client : group->get_client_ptrs()) {
|
||||
auto client = weak_client.lock();
|
||||
if (client) {
|
||||
return false;
|
||||
});
|
||||
group->find_client_ptrs_if([this](const rclcpp::ClientBase::SharedPtr & client) {
|
||||
client_handles_.push_back(client->get_client_handle());
|
||||
}
|
||||
}
|
||||
for (auto & weak_timer : group->get_timer_ptrs()) {
|
||||
auto timer = weak_timer.lock();
|
||||
if (timer) {
|
||||
return false;
|
||||
});
|
||||
group->find_timer_ptrs_if([this](const rclcpp::TimerBase::SharedPtr & timer) {
|
||||
timer_handles_.push_back(timer->get_timer_handle());
|
||||
}
|
||||
}
|
||||
for (auto & weak_waitable : group->get_waitable_ptrs()) {
|
||||
auto waitable = weak_waitable.lock();
|
||||
if (waitable) {
|
||||
return false;
|
||||
});
|
||||
group->find_waitable_ptrs_if([this](const rclcpp::Waitable::SharedPtr & waitable) {
|
||||
waitable_handles_.push_back(waitable);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
}
|
||||
return has_invalid_weak_nodes;
|
||||
@@ -374,6 +365,41 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
virtual void
|
||||
get_next_timer(
|
||||
executor::AnyExecutable & any_exec,
|
||||
const WeakNodeList & weak_nodes)
|
||||
{
|
||||
auto it = timer_handles_.begin();
|
||||
while (it != timer_handles_.end()) {
|
||||
auto timer = get_timer_by_handle(*it, weak_nodes);
|
||||
if (timer) {
|
||||
// Find the group for this handle and see if it can be serviced
|
||||
auto group = get_group_by_timer(timer, weak_nodes);
|
||||
if (!group) {
|
||||
// Group was not found, meaning the timer is not valid...
|
||||
// Remove it from the ready list and continue looking
|
||||
it = timer_handles_.erase(it);
|
||||
continue;
|
||||
}
|
||||
if (!group->can_be_taken_from().load()) {
|
||||
// Group is mutually exclusive and is being used, so skip it for now
|
||||
// Leave it to be checked next time, but continue searching
|
||||
++it;
|
||||
continue;
|
||||
}
|
||||
// Otherwise it is safe to set and return the any_exec
|
||||
any_exec.timer = timer;
|
||||
any_exec.callback_group = group;
|
||||
any_exec.node_base = get_node_by_group(group, weak_nodes);
|
||||
timer_handles_.erase(it);
|
||||
return;
|
||||
}
|
||||
// Else, the service is no longer valid, remove it and continue
|
||||
it = timer_handles_.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void
|
||||
get_next_waitable(executor::AnyExecutable & any_exec, const WeakNodeList & weak_nodes)
|
||||
{
|
||||
|
||||
@@ -32,13 +32,16 @@
|
||||
#include "rcl_interfaces/msg/intra_process_message.hpp"
|
||||
|
||||
#include "rclcpp/any_subscription_callback.hpp"
|
||||
#include "rclcpp/detail/resolve_use_intra_process.hpp"
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
#include "rclcpp/expand_topic_or_service_name.hpp"
|
||||
#include "rclcpp/intra_process_manager.hpp"
|
||||
#include "rclcpp/logging.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/message_memory_strategy.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/subscription_base.hpp"
|
||||
#include "rclcpp/subscription_options.hpp"
|
||||
#include "rclcpp/subscription_traits.hpp"
|
||||
#include "rclcpp/type_support_decl.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
@@ -55,15 +58,19 @@ class NodeTopicsInterface;
|
||||
/// Subscription implementation, templated on the type of message this subscription receives.
|
||||
template<
|
||||
typename CallbackMessageT,
|
||||
typename Alloc = std::allocator<void>>
|
||||
typename AllocatorT = std::allocator<void>,
|
||||
typename MessageMemoryStrategyT = rclcpp::message_memory_strategy::MessageMemoryStrategy<
|
||||
CallbackMessageT,
|
||||
AllocatorT
|
||||
>>
|
||||
class Subscription : public SubscriptionBase
|
||||
{
|
||||
friend class rclcpp::node_interfaces::NodeTopicsInterface;
|
||||
|
||||
public:
|
||||
using MessageAllocTraits = allocator::AllocRebind<CallbackMessageT, Alloc>;
|
||||
using MessageAlloc = typename MessageAllocTraits::allocator_type;
|
||||
using MessageDeleter = allocator::Deleter<MessageAlloc, CallbackMessageT>;
|
||||
using MessageAllocatorTraits = allocator::AllocRebind<CallbackMessageT, AllocatorT>;
|
||||
using MessageAllocator = typename MessageAllocatorTraits::allocator_type;
|
||||
using MessageDeleter = allocator::Deleter<MessageAllocator, CallbackMessageT>;
|
||||
using ConstMessageSharedPtr = std::shared_ptr<const CallbackMessageT>;
|
||||
using MessageUniquePtr = std::unique_ptr<CallbackMessageT, MessageDeleter>;
|
||||
|
||||
@@ -71,44 +78,66 @@ public:
|
||||
|
||||
/// Default constructor.
|
||||
/**
|
||||
* The constructor for a subscription is almost never called directly. Instead, subscriptions
|
||||
* should be instantiated through Node::create_subscription.
|
||||
* \param[in] node_handle rcl representation of the node that owns this subscription.
|
||||
* The constructor for a subscription is almost never called directly.
|
||||
* Instead, subscriptions should be instantiated through the function
|
||||
* rclcpp::create_subscription().
|
||||
*
|
||||
* \param[in] node_base NodeBaseInterface pointer that is used in part of the setup.
|
||||
* \param[in] type_support_handle rosidl type support struct, for the Message type of the topic.
|
||||
* \param[in] topic_name Name of the topic to subscribe to.
|
||||
* \param[in] subscription_options options for the subscription.
|
||||
* \param[in] callback User defined callback to call when a message is received.
|
||||
* \param[in] memory_strategy The memory strategy to be used for managing message memory.
|
||||
* \param[in] options options for the subscription.
|
||||
* \param[in] message_memory_strategy The memory strategy to be used for managing message memory.
|
||||
*/
|
||||
Subscription(
|
||||
std::shared_ptr<rcl_node_t> node_handle,
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||
const rosidl_message_type_support_t & type_support_handle,
|
||||
const std::string & topic_name,
|
||||
const rcl_subscription_options_t & subscription_options,
|
||||
AnySubscriptionCallback<CallbackMessageT, Alloc> callback,
|
||||
const SubscriptionEventCallbacks & event_callbacks,
|
||||
typename message_memory_strategy::MessageMemoryStrategy<CallbackMessageT, Alloc>::SharedPtr
|
||||
memory_strategy = message_memory_strategy::MessageMemoryStrategy<CallbackMessageT,
|
||||
Alloc>::create_default())
|
||||
const rclcpp::QoS & qos,
|
||||
AnySubscriptionCallback<CallbackMessageT, AllocatorT> callback,
|
||||
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options,
|
||||
typename MessageMemoryStrategyT::SharedPtr message_memory_strategy)
|
||||
: SubscriptionBase(
|
||||
node_handle,
|
||||
node_base,
|
||||
type_support_handle,
|
||||
topic_name,
|
||||
subscription_options,
|
||||
options.template to_rcl_subscription_options<CallbackMessageT>(qos),
|
||||
rclcpp::subscription_traits::is_serialized_subscription_argument<CallbackMessageT>::value),
|
||||
any_callback_(callback),
|
||||
message_memory_strategy_(memory_strategy)
|
||||
message_memory_strategy_(message_memory_strategy)
|
||||
{
|
||||
if (event_callbacks.deadline_callback) {
|
||||
this->add_event_handler(event_callbacks.deadline_callback,
|
||||
if (options.event_callbacks.deadline_callback) {
|
||||
this->add_event_handler(
|
||||
options.event_callbacks.deadline_callback,
|
||||
RCL_SUBSCRIPTION_REQUESTED_DEADLINE_MISSED);
|
||||
}
|
||||
if (event_callbacks.liveliness_callback) {
|
||||
this->add_event_handler(event_callbacks.liveliness_callback,
|
||||
if (options.event_callbacks.liveliness_callback) {
|
||||
this->add_event_handler(
|
||||
options.event_callbacks.liveliness_callback,
|
||||
RCL_SUBSCRIPTION_LIVELINESS_CHANGED);
|
||||
}
|
||||
}
|
||||
|
||||
/// Called after construction to continue setup that requires shared_from_this().
|
||||
void
|
||||
post_init_setup(
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||
const rclcpp::QoS & qos,
|
||||
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options)
|
||||
{
|
||||
// Setup intra process publishing if requested.
|
||||
if (rclcpp::detail::resolve_use_intra_process(options, *node_base)) {
|
||||
auto context = node_base->get_context();
|
||||
using rclcpp::intra_process_manager::IntraProcessManager;
|
||||
auto ipm = context->get_sub_context<IntraProcessManager>();
|
||||
uint64_t intra_process_subscription_id = ipm->add_subscription(this->shared_from_this());
|
||||
this->setup_intra_process(
|
||||
intra_process_subscription_id,
|
||||
ipm,
|
||||
options.template to_rcl_subscription_options<CallbackMessageT>(qos));
|
||||
}
|
||||
}
|
||||
|
||||
/// Support dynamically setting the message memory strategy.
|
||||
/**
|
||||
* Behavior may be undefined if called while the subscription could be executing.
|
||||
@@ -116,7 +145,7 @@ public:
|
||||
*/
|
||||
void set_message_memory_strategy(
|
||||
typename message_memory_strategy::MessageMemoryStrategy<CallbackMessageT,
|
||||
Alloc>::SharedPtr message_memory_strategy)
|
||||
AllocatorT>::SharedPtr message_memory_strategy)
|
||||
{
|
||||
message_memory_strategy_ = message_memory_strategy;
|
||||
}
|
||||
@@ -170,6 +199,13 @@ public:
|
||||
// However, this can only really happen if this node has it disabled, but the other doesn't.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!matches_any_intra_process_publishers(&message_info.publisher_gid)) {
|
||||
// This intra-process message has not been created by a publisher from this context.
|
||||
// we should ignore this copy of the message.
|
||||
return;
|
||||
}
|
||||
|
||||
if (any_callback_.use_take_shared_method()) {
|
||||
ConstMessageSharedPtr msg;
|
||||
take_intra_process_message(
|
||||
@@ -228,7 +264,7 @@ private:
|
||||
throw std::runtime_error(
|
||||
"intra process take called after destruction of intra process manager");
|
||||
}
|
||||
ipm->template take_intra_process_message<CallbackMessageT, Alloc>(
|
||||
ipm->template take_intra_process_message<CallbackMessageT, AllocatorT>(
|
||||
publisher_id, message_sequence, subscription_id, message);
|
||||
}
|
||||
|
||||
@@ -244,7 +280,7 @@ private:
|
||||
throw std::runtime_error(
|
||||
"intra process take called after destruction of intra process manager");
|
||||
}
|
||||
ipm->template take_intra_process_message<CallbackMessageT, Alloc>(
|
||||
ipm->template take_intra_process_message<CallbackMessageT, AllocatorT>(
|
||||
publisher_id, message_sequence, subscription_id, message);
|
||||
}
|
||||
|
||||
@@ -265,8 +301,8 @@ private:
|
||||
|
||||
RCLCPP_DISABLE_COPY(Subscription)
|
||||
|
||||
AnySubscriptionCallback<CallbackMessageT, Alloc> any_callback_;
|
||||
typename message_memory_strategy::MessageMemoryStrategy<CallbackMessageT, Alloc>::SharedPtr
|
||||
AnySubscriptionCallback<CallbackMessageT, AllocatorT> any_callback_;
|
||||
typename message_memory_strategy::MessageMemoryStrategy<CallbackMessageT, AllocatorT>::SharedPtr
|
||||
message_memory_strategy_;
|
||||
};
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace rclcpp
|
||||
|
||||
namespace node_interfaces
|
||||
{
|
||||
class NodeTopicsInterface;
|
||||
class NodeBaseInterface;
|
||||
} // namespace node_interfaces
|
||||
|
||||
namespace intra_process_manager
|
||||
@@ -50,14 +50,14 @@ class IntraProcessManager;
|
||||
|
||||
/// Virtual base class for subscriptions. This pattern allows us to iterate over different template
|
||||
/// specializations of Subscription, among other things.
|
||||
class SubscriptionBase
|
||||
class SubscriptionBase : public std::enable_shared_from_this<SubscriptionBase>
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(SubscriptionBase)
|
||||
|
||||
/// Default constructor.
|
||||
/**
|
||||
* \param[in] node_handle The rcl representation of the node that owns this subscription.
|
||||
* \param[in] node_base NodeBaseInterface pointer used in parts of the setup.
|
||||
* \param[in] type_support_handle rosidl type support struct, for the Message type of the topic.
|
||||
* \param[in] topic_name Name of the topic to subscribe to.
|
||||
* \param[in] subscription_options options for the subscription.
|
||||
@@ -65,7 +65,7 @@ public:
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
SubscriptionBase(
|
||||
std::shared_ptr<rcl_node_t> node_handle,
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||
const rosidl_message_type_support_t & type_support_handle,
|
||||
const std::string & topic_name,
|
||||
const rcl_subscription_options_t & subscription_options,
|
||||
@@ -98,14 +98,32 @@ public:
|
||||
const std::vector<std::shared_ptr<rclcpp::QOSEventHandlerBase>> &
|
||||
get_event_handlers() const;
|
||||
|
||||
/// Get the actual QoS settings, after the defaults have been determined.
|
||||
/**
|
||||
* The actual configuration applied when using RMW_QOS_POLICY_*_SYSTEM_DEFAULT
|
||||
* can only be resolved after the creation of the publisher, and it
|
||||
* depends on the underlying rmw implementation.
|
||||
* If the underlying setting in use can't be represented in ROS terms,
|
||||
* it will be set to RMW_QOS_POLICY_*_UNKNOWN.
|
||||
* May throw runtime_error when an unexpected error occurs.
|
||||
* \return The actual qos settings.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
rmw_qos_profile_t
|
||||
get_actual_qos() const;
|
||||
|
||||
/// Borrow a new message.
|
||||
/** \return Shared pointer to the fresh message. */
|
||||
virtual std::shared_ptr<void>
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
std::shared_ptr<void>
|
||||
create_message() = 0;
|
||||
|
||||
/// Borrow a new serialized message
|
||||
/** \return Shared pointer to a rcl_message_serialized_t. */
|
||||
virtual std::shared_ptr<rcl_serialized_message_t>
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
std::shared_ptr<rcl_serialized_message_t>
|
||||
create_serialized_message() = 0;
|
||||
|
||||
/// Check if we need to handle the message, and execute the callback if we do.
|
||||
@@ -113,27 +131,37 @@ public:
|
||||
* \param[in] message Shared pointer to the message to handle.
|
||||
* \param[in] message_info Metadata associated with this message.
|
||||
*/
|
||||
virtual void
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
handle_message(std::shared_ptr<void> & message, const rmw_message_info_t & message_info) = 0;
|
||||
|
||||
/// Return the message borrowed in create_message.
|
||||
/** \param[in] message Shared pointer to the returned message. */
|
||||
virtual void
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
return_message(std::shared_ptr<void> & message) = 0;
|
||||
|
||||
/// Return the message borrowed in create_serialized_message.
|
||||
/** \param[in] message Shared pointer to the returned message. */
|
||||
virtual void
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
return_serialized_message(std::shared_ptr<rcl_serialized_message_t> & message) = 0;
|
||||
|
||||
virtual void
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
handle_intra_process_message(
|
||||
rcl_interfaces::msg::IntraProcessMessage & ipm,
|
||||
const rmw_message_info_t & message_info) = 0;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
const rosidl_message_type_support_t &
|
||||
get_message_type_support_handle() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
is_serialized() const;
|
||||
|
||||
@@ -147,7 +175,9 @@ public:
|
||||
std::weak_ptr<rclcpp::intra_process_manager::IntraProcessManager>;
|
||||
|
||||
/// Implemenation detail.
|
||||
void setup_intra_process(
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
setup_intra_process(
|
||||
uint64_t intra_process_subscription_id,
|
||||
IntraProcessManagerWeakPtr weak_ipm,
|
||||
const rcl_subscription_options_t & intra_process_options);
|
||||
|
||||
@@ -43,6 +43,9 @@ namespace rclcpp
|
||||
* usually called from a templated "create_subscription" method of the Node
|
||||
* class, and is passed to the non-templated "create_subscription" method of
|
||||
* the NodeTopics class where it is used to create and setup the Subscription.
|
||||
*
|
||||
* It also handles the two step construction of Subscriptions, first calling
|
||||
* the constructor and then the post_init_setup() method.
|
||||
*/
|
||||
struct SubscriptionFactory
|
||||
{
|
||||
@@ -51,71 +54,62 @@ struct SubscriptionFactory
|
||||
rclcpp::SubscriptionBase::SharedPtr(
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||
const std::string & topic_name,
|
||||
const rcl_subscription_options_t & subscription_options)>;
|
||||
const rclcpp::QoS & qos)>;
|
||||
|
||||
SubscriptionFactoryFunction create_typed_subscription;
|
||||
|
||||
// Function that takes a MessageT from the intra process manager
|
||||
using SetupIntraProcessFunction = std::function<
|
||||
void (
|
||||
rclcpp::intra_process_manager::IntraProcessManager::SharedPtr ipm,
|
||||
rclcpp::SubscriptionBase::SharedPtr subscription,
|
||||
const rcl_subscription_options_t & subscription_options)>;
|
||||
|
||||
SetupIntraProcessFunction setup_intra_process;
|
||||
const SubscriptionFactoryFunction create_typed_subscription;
|
||||
};
|
||||
|
||||
/// Return a SubscriptionFactory with functions for creating a SubscriptionT<MessageT, Alloc>.
|
||||
template<
|
||||
typename MessageT,
|
||||
typename CallbackT,
|
||||
typename Alloc,
|
||||
typename CallbackMessageT,
|
||||
typename SubscriptionT>
|
||||
typename AllocatorT,
|
||||
typename CallbackMessageT =
|
||||
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type,
|
||||
typename SubscriptionT = rclcpp::Subscription<CallbackMessageT, AllocatorT>,
|
||||
typename MessageMemoryStrategyT = rclcpp::message_memory_strategy::MessageMemoryStrategy<
|
||||
CallbackMessageT,
|
||||
AllocatorT
|
||||
>>
|
||||
SubscriptionFactory
|
||||
create_subscription_factory(
|
||||
CallbackT && callback,
|
||||
const SubscriptionEventCallbacks & event_callbacks,
|
||||
typename rclcpp::message_memory_strategy::MessageMemoryStrategy<
|
||||
CallbackMessageT, Alloc>::SharedPtr
|
||||
msg_mem_strat,
|
||||
std::shared_ptr<Alloc> allocator)
|
||||
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options,
|
||||
typename MessageMemoryStrategyT::SharedPtr msg_mem_strat)
|
||||
{
|
||||
SubscriptionFactory factory;
|
||||
auto allocator = options.get_allocator();
|
||||
|
||||
using rclcpp::AnySubscriptionCallback;
|
||||
AnySubscriptionCallback<CallbackMessageT, Alloc> any_subscription_callback(allocator);
|
||||
AnySubscriptionCallback<CallbackMessageT, AllocatorT> any_subscription_callback(allocator);
|
||||
any_subscription_callback.set(std::forward<CallbackT>(callback));
|
||||
|
||||
auto message_alloc =
|
||||
std::make_shared<typename Subscription<CallbackMessageT, Alloc>::MessageAlloc>();
|
||||
|
||||
// factory function that creates a MessageT specific SubscriptionT
|
||||
factory.create_typed_subscription =
|
||||
[allocator, msg_mem_strat, any_subscription_callback, event_callbacks, message_alloc](
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||
const std::string & topic_name,
|
||||
const rcl_subscription_options_t & subscription_options
|
||||
SubscriptionFactory factory {
|
||||
// factory function that creates a MessageT specific SubscriptionT
|
||||
[options, msg_mem_strat, any_subscription_callback](
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||
const std::string & topic_name,
|
||||
const rclcpp::QoS & qos
|
||||
) -> rclcpp::SubscriptionBase::SharedPtr
|
||||
{
|
||||
auto options_copy = subscription_options;
|
||||
options_copy.allocator =
|
||||
rclcpp::allocator::get_rcl_allocator<CallbackMessageT>(*message_alloc.get());
|
||||
|
||||
using rclcpp::Subscription;
|
||||
using rclcpp::SubscriptionBase;
|
||||
|
||||
auto sub = Subscription<CallbackMessageT, Alloc>::make_shared(
|
||||
node_base->get_shared_rcl_node_handle(),
|
||||
auto sub = Subscription<CallbackMessageT, AllocatorT>::make_shared(
|
||||
node_base,
|
||||
*rosidl_typesupport_cpp::get_message_type_support_handle<MessageT>(),
|
||||
topic_name,
|
||||
options_copy,
|
||||
qos,
|
||||
any_subscription_callback,
|
||||
event_callbacks,
|
||||
options,
|
||||
msg_mem_strat);
|
||||
// This is used for setting up things like intra process comms which
|
||||
// require this->shared_from_this() which cannot be called from
|
||||
// the constructor.
|
||||
sub->post_init_setup(node_base, qos, options);
|
||||
auto sub_base_ptr = std::dynamic_pointer_cast<SubscriptionBase>(sub);
|
||||
return sub_base_ptr;
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
// return the factory now that it is populated
|
||||
return factory;
|
||||
|
||||
@@ -70,6 +70,16 @@ struct SubscriptionOptionsWithAllocator : public SubscriptionOptionsBase
|
||||
result.qos = qos.get_rmw_qos_profile();
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Get the allocator, creating one if needed.
|
||||
std::shared_ptr<Allocator>
|
||||
get_allocator() const
|
||||
{
|
||||
if (!this->allocator) {
|
||||
return std::make_shared<Allocator>();
|
||||
}
|
||||
return this->allocator;
|
||||
}
|
||||
};
|
||||
|
||||
using SubscriptionOptions = SubscriptionOptionsWithAllocator<std::allocator<void>>;
|
||||
|
||||
@@ -128,7 +128,7 @@ public:
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* ```
|
||||
* ```cpp
|
||||
* // ... create a wait set and a Waitable
|
||||
* // Add the Waitable to the wait set
|
||||
* bool add_ret = waitable.add_to_wait_set(wait_set);
|
||||
|
||||
@@ -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>0.7.5</version>
|
||||
<version>0.8.0</version>
|
||||
<description>The ROS client library in C++.</description>
|
||||
<maintainer email="dthomas@osrfoundation.org">Dirk Thomas</maintainer>
|
||||
<license>Apache License 2.0</license>
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
<depend>rcl</depend>
|
||||
<depend>rcl_yaml_param_parser</depend>
|
||||
<depend>rcpputils</depend>
|
||||
<depend>rmw_implementation</depend>
|
||||
|
||||
<exec_depend>ament_cmake</exec_depend>
|
||||
|
||||
@@ -95,7 +95,7 @@ def is_supported_feature_combination(feature_combination):
|
||||
#define RCLCPP_@(severity)@(suffix)(logger, @(''.join([p + ', ' for p in get_macro_parameters(feature_combination).keys()]))...) \
|
||||
do { \
|
||||
static_assert( \
|
||||
::std::is_same<typename std::remove_reference<typename std::remove_cv<decltype(logger)>::type>::type, \
|
||||
::std::is_same<typename std::remove_cv<typename std::remove_reference<decltype(logger)>::type>::type, \
|
||||
typename ::rclcpp::Logger>::value, \
|
||||
"First argument to logging macros must be an rclcpp::Logger"); \
|
||||
RCUTILS_LOG_@(severity)@(suffix)_NAMED( \
|
||||
|
||||
@@ -23,40 +23,6 @@ CallbackGroup::CallbackGroup(CallbackGroupType group_type)
|
||||
: type_(group_type), can_be_taken_from_(true)
|
||||
{}
|
||||
|
||||
const std::vector<rclcpp::SubscriptionBase::WeakPtr> &
|
||||
CallbackGroup::get_subscription_ptrs() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
return subscription_ptrs_;
|
||||
}
|
||||
|
||||
const std::vector<rclcpp::TimerBase::WeakPtr> &
|
||||
CallbackGroup::get_timer_ptrs() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
return timer_ptrs_;
|
||||
}
|
||||
|
||||
const std::vector<rclcpp::ServiceBase::WeakPtr> &
|
||||
CallbackGroup::get_service_ptrs() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
return service_ptrs_;
|
||||
}
|
||||
|
||||
const std::vector<rclcpp::ClientBase::WeakPtr> &
|
||||
CallbackGroup::get_client_ptrs() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
return client_ptrs_;
|
||||
}
|
||||
|
||||
const std::vector<rclcpp::Waitable::WeakPtr> &
|
||||
CallbackGroup::get_waitable_ptrs() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
return waitable_ptrs_;
|
||||
}
|
||||
|
||||
std::atomic_bool &
|
||||
CallbackGroup::can_be_taken_from()
|
||||
@@ -76,6 +42,12 @@ CallbackGroup::add_subscription(
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
subscription_ptrs_.push_back(subscription_ptr);
|
||||
subscription_ptrs_.erase(
|
||||
std::remove_if(
|
||||
subscription_ptrs_.begin(),
|
||||
subscription_ptrs_.end(),
|
||||
[](rclcpp::SubscriptionBase::WeakPtr x) {return x.expired();}),
|
||||
subscription_ptrs_.end());
|
||||
}
|
||||
|
||||
void
|
||||
@@ -83,6 +55,12 @@ CallbackGroup::add_timer(const rclcpp::TimerBase::SharedPtr timer_ptr)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
timer_ptrs_.push_back(timer_ptr);
|
||||
timer_ptrs_.erase(
|
||||
std::remove_if(
|
||||
timer_ptrs_.begin(),
|
||||
timer_ptrs_.end(),
|
||||
[](rclcpp::TimerBase::WeakPtr x) {return x.expired();}),
|
||||
timer_ptrs_.end());
|
||||
}
|
||||
|
||||
void
|
||||
@@ -90,6 +68,12 @@ CallbackGroup::add_service(const rclcpp::ServiceBase::SharedPtr service_ptr)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
service_ptrs_.push_back(service_ptr);
|
||||
service_ptrs_.erase(
|
||||
std::remove_if(
|
||||
service_ptrs_.begin(),
|
||||
service_ptrs_.end(),
|
||||
[](rclcpp::ServiceBase::WeakPtr x) {return x.expired();}),
|
||||
service_ptrs_.end());
|
||||
}
|
||||
|
||||
void
|
||||
@@ -97,6 +81,12 @@ CallbackGroup::add_client(const rclcpp::ClientBase::SharedPtr client_ptr)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
client_ptrs_.push_back(client_ptr);
|
||||
client_ptrs_.erase(
|
||||
std::remove_if(
|
||||
client_ptrs_.begin(),
|
||||
client_ptrs_.end(),
|
||||
[](rclcpp::ClientBase::WeakPtr x) {return x.expired();}),
|
||||
client_ptrs_.end());
|
||||
}
|
||||
|
||||
void
|
||||
@@ -104,6 +94,12 @@ CallbackGroup::add_waitable(const rclcpp::Waitable::SharedPtr waitable_ptr)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
waitable_ptrs_.push_back(waitable_ptr);
|
||||
waitable_ptrs_.erase(
|
||||
std::remove_if(
|
||||
waitable_ptrs_.begin(),
|
||||
waitable_ptrs_.end(),
|
||||
[](rclcpp::Waitable::WeakPtr x) {return x.expired();}),
|
||||
waitable_ptrs_.end());
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -119,8 +119,9 @@ Clock::create_jump_callback(
|
||||
}
|
||||
|
||||
// Try to add the jump callback to the clock
|
||||
rcl_ret_t ret = rcl_clock_add_jump_callback(&rcl_clock_, threshold,
|
||||
Clock::on_time_jump, handler.get());
|
||||
rcl_ret_t ret = rcl_clock_add_jump_callback(
|
||||
&rcl_clock_, threshold, Clock::on_time_jump,
|
||||
handler.get());
|
||||
if (RCL_RET_OK != ret) {
|
||||
exceptions::throw_from_rcl_error(ret, "Failed to add time jump callback");
|
||||
}
|
||||
|
||||
@@ -233,4 +233,10 @@ Duration::to_rmw_time() const
|
||||
return result;
|
||||
}
|
||||
|
||||
Duration
|
||||
Duration::from_seconds(double seconds)
|
||||
{
|
||||
return Duration(static_cast<int64_t>(RCL_S_TO_NS(seconds)));
|
||||
}
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <cstdio>
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace std::string_literals;
|
||||
|
||||
@@ -68,6 +69,8 @@ from_rcl_error(
|
||||
return std::make_exception_ptr(RCLBadAlloc(base_exc));
|
||||
case RCL_RET_INVALID_ARGUMENT:
|
||||
return std::make_exception_ptr(RCLInvalidArgument(base_exc, formatted_prefix));
|
||||
case RCL_RET_INVALID_ROS_ARGS:
|
||||
return std::make_exception_ptr(RCLInvalidROSArgsError(base_exc, formatted_prefix));
|
||||
default:
|
||||
return std::make_exception_ptr(RCLError(base_exc, formatted_prefix));
|
||||
}
|
||||
@@ -126,5 +129,18 @@ RCLInvalidArgument::RCLInvalidArgument(
|
||||
: RCLErrorBase(base_exc), std::invalid_argument(prefix + base_exc.formatted_message)
|
||||
{}
|
||||
|
||||
RCLInvalidROSArgsError::RCLInvalidROSArgsError(
|
||||
rcl_ret_t ret,
|
||||
const rcl_error_state_t * error_state,
|
||||
const std::string & prefix)
|
||||
: RCLInvalidROSArgsError(RCLErrorBase(ret, error_state), prefix)
|
||||
{}
|
||||
|
||||
RCLInvalidROSArgsError::RCLInvalidROSArgsError(
|
||||
const RCLErrorBase & base_exc,
|
||||
const std::string & prefix)
|
||||
: RCLErrorBase(base_exc), std::runtime_error(prefix + base_exc.formatted_message)
|
||||
{}
|
||||
|
||||
} // namespace exceptions
|
||||
} // namespace rclcpp
|
||||
|
||||
@@ -140,6 +140,7 @@ Executor::add_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_pt
|
||||
}
|
||||
}
|
||||
// Add the node's notify condition to the guard condition handles
|
||||
std::unique_lock<std::mutex> lock(memory_strategy_mutex_);
|
||||
memory_strategy_->add_guard_condition(node_ptr->get_notify_guard_condition());
|
||||
}
|
||||
|
||||
@@ -178,6 +179,7 @@ Executor::remove_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node
|
||||
}
|
||||
}
|
||||
}
|
||||
std::unique_lock<std::mutex> lock(memory_strategy_mutex_);
|
||||
memory_strategy_->remove_guard_condition(node_ptr->get_notify_guard_condition());
|
||||
}
|
||||
|
||||
@@ -423,43 +425,47 @@ Executor::execute_client(
|
||||
void
|
||||
Executor::wait_for_work(std::chrono::nanoseconds timeout)
|
||||
{
|
||||
// Collect the subscriptions and timers to be waited on
|
||||
memory_strategy_->clear_handles();
|
||||
bool has_invalid_weak_nodes = memory_strategy_->collect_entities(weak_nodes_);
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(memory_strategy_mutex_);
|
||||
|
||||
// Clean up any invalid nodes, if they were detected
|
||||
if (has_invalid_weak_nodes) {
|
||||
auto node_it = weak_nodes_.begin();
|
||||
auto gc_it = guard_conditions_.begin();
|
||||
while (node_it != weak_nodes_.end()) {
|
||||
if (node_it->expired()) {
|
||||
node_it = weak_nodes_.erase(node_it);
|
||||
memory_strategy_->remove_guard_condition(*gc_it);
|
||||
gc_it = guard_conditions_.erase(gc_it);
|
||||
} else {
|
||||
++node_it;
|
||||
++gc_it;
|
||||
// Collect the subscriptions and timers to be waited on
|
||||
memory_strategy_->clear_handles();
|
||||
bool has_invalid_weak_nodes = memory_strategy_->collect_entities(weak_nodes_);
|
||||
|
||||
// Clean up any invalid nodes, if they were detected
|
||||
if (has_invalid_weak_nodes) {
|
||||
auto node_it = weak_nodes_.begin();
|
||||
auto gc_it = guard_conditions_.begin();
|
||||
while (node_it != weak_nodes_.end()) {
|
||||
if (node_it->expired()) {
|
||||
node_it = weak_nodes_.erase(node_it);
|
||||
memory_strategy_->remove_guard_condition(*gc_it);
|
||||
gc_it = guard_conditions_.erase(gc_it);
|
||||
} else {
|
||||
++node_it;
|
||||
++gc_it;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// clear wait set
|
||||
if (rcl_wait_set_clear(&wait_set_) != RCL_RET_OK) {
|
||||
throw std::runtime_error("Couldn't clear wait set");
|
||||
}
|
||||
// clear wait set
|
||||
if (rcl_wait_set_clear(&wait_set_) != RCL_RET_OK) {
|
||||
throw std::runtime_error("Couldn't clear wait set");
|
||||
}
|
||||
|
||||
// The size of waitables are accounted for in size of the other entities
|
||||
rcl_ret_t ret = rcl_wait_set_resize(
|
||||
&wait_set_, memory_strategy_->number_of_ready_subscriptions(),
|
||||
memory_strategy_->number_of_guard_conditions(), memory_strategy_->number_of_ready_timers(),
|
||||
memory_strategy_->number_of_ready_clients(), memory_strategy_->number_of_ready_services(),
|
||||
memory_strategy_->number_of_ready_events());
|
||||
if (RCL_RET_OK != ret) {
|
||||
throw std::runtime_error(
|
||||
std::string("Couldn't resize the wait set : ") + rcl_get_error_string().str);
|
||||
}
|
||||
// The size of waitables are accounted for in size of the other entities
|
||||
rcl_ret_t ret = rcl_wait_set_resize(
|
||||
&wait_set_, memory_strategy_->number_of_ready_subscriptions(),
|
||||
memory_strategy_->number_of_guard_conditions(), memory_strategy_->number_of_ready_timers(),
|
||||
memory_strategy_->number_of_ready_clients(), memory_strategy_->number_of_ready_services(),
|
||||
memory_strategy_->number_of_ready_events());
|
||||
if (RCL_RET_OK != ret) {
|
||||
throw std::runtime_error(
|
||||
std::string("Couldn't resize the wait set : ") + rcl_get_error_string().str);
|
||||
}
|
||||
|
||||
if (!memory_strategy_->add_handles_to_wait_set(&wait_set_)) {
|
||||
throw std::runtime_error("Couldn't fill wait set");
|
||||
if (!memory_strategy_->add_handles_to_wait_set(&wait_set_)) {
|
||||
throw std::runtime_error("Couldn't fill wait set");
|
||||
}
|
||||
}
|
||||
rcl_ret_t status =
|
||||
rcl_wait(&wait_set_, std::chrono::duration_cast<std::chrono::nanoseconds>(timeout).count());
|
||||
@@ -511,48 +517,23 @@ Executor::get_group_by_timer(rclcpp::TimerBase::SharedPtr timer)
|
||||
if (!group) {
|
||||
continue;
|
||||
}
|
||||
for (auto & weak_timer : group->get_timer_ptrs()) {
|
||||
auto t = weak_timer.lock();
|
||||
if (t == timer) {
|
||||
return group;
|
||||
}
|
||||
auto timer_ref = group->find_timer_ptrs_if(
|
||||
[timer](const rclcpp::TimerBase::SharedPtr & timer_ptr) -> bool {
|
||||
return timer_ptr == timer;
|
||||
});
|
||||
if (timer_ref) {
|
||||
return group;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rclcpp::callback_group::CallbackGroup::SharedPtr();
|
||||
}
|
||||
|
||||
void
|
||||
Executor::get_next_timer(AnyExecutable & any_exec)
|
||||
{
|
||||
for (auto & weak_node : weak_nodes_) {
|
||||
auto node = weak_node.lock();
|
||||
if (!node) {
|
||||
continue;
|
||||
}
|
||||
for (auto & weak_group : node->get_callback_groups()) {
|
||||
auto group = weak_group.lock();
|
||||
if (!group || !group->can_be_taken_from().load()) {
|
||||
continue;
|
||||
}
|
||||
for (auto & timer_ref : group->get_timer_ptrs()) {
|
||||
auto timer = timer_ref.lock();
|
||||
if (timer && timer->is_ready()) {
|
||||
any_exec.timer = timer;
|
||||
any_exec.callback_group = group;
|
||||
node = get_node_by_group(group);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
Executor::get_next_ready_executable(AnyExecutable & any_executable)
|
||||
{
|
||||
// Check the timers to see if there are any that are ready, if so return
|
||||
get_next_timer(any_executable);
|
||||
// Check the timers to see if there are any that are ready
|
||||
memory_strategy_->get_next_timer(any_executable, weak_nodes_);
|
||||
if (any_executable.timer) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -27,8 +27,11 @@ using rclcpp::executors::MultiThreadedExecutor;
|
||||
MultiThreadedExecutor::MultiThreadedExecutor(
|
||||
const rclcpp::executor::ExecutorArgs & args,
|
||||
size_t number_of_threads,
|
||||
bool yield_before_execute)
|
||||
: executor::Executor(args), yield_before_execute_(yield_before_execute)
|
||||
bool yield_before_execute,
|
||||
std::chrono::nanoseconds next_exec_timeout)
|
||||
: executor::Executor(args),
|
||||
yield_before_execute_(yield_before_execute),
|
||||
next_exec_timeout_(next_exec_timeout)
|
||||
{
|
||||
number_of_threads_ = number_of_threads ? number_of_threads : std::thread::hardware_concurrency();
|
||||
if (number_of_threads_ == 0) {
|
||||
@@ -77,12 +80,17 @@ MultiThreadedExecutor::run(size_t)
|
||||
if (!rclcpp::ok(this->context_) || !spinning.load()) {
|
||||
return;
|
||||
}
|
||||
if (!get_next_executable(any_exec)) {
|
||||
if (!get_next_executable(any_exec, next_exec_timeout_)) {
|
||||
continue;
|
||||
}
|
||||
if (any_exec.timer) {
|
||||
// Guard against multiple threads getting the same timer.
|
||||
if (scheduled_timers_.count(any_exec.timer) != 0) {
|
||||
// Make sure that any_exec's callback group is reset before
|
||||
// the lock is released.
|
||||
if (any_exec.callback_group) {
|
||||
any_exec.callback_group->can_be_taken_from().store(true);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
scheduled_timers_.insert(any_exec.timer);
|
||||
|
||||
@@ -32,16 +32,14 @@ MemoryStrategy::get_subscription_by_handle(
|
||||
if (!group) {
|
||||
continue;
|
||||
}
|
||||
for (auto & weak_subscription : group->get_subscription_ptrs()) {
|
||||
auto subscription = weak_subscription.lock();
|
||||
if (subscription) {
|
||||
if (subscription->get_subscription_handle() == subscriber_handle) {
|
||||
return subscription;
|
||||
}
|
||||
if (subscription->get_intra_process_subscription_handle() == subscriber_handle) {
|
||||
return subscription;
|
||||
}
|
||||
}
|
||||
auto match_subscription = group->find_subscription_ptrs_if(
|
||||
[&subscriber_handle](const rclcpp::SubscriptionBase::SharedPtr & subscription) -> bool {
|
||||
return
|
||||
(subscription->get_subscription_handle() == subscriber_handle) ||
|
||||
(subscription->get_intra_process_subscription_handle() == subscriber_handle);
|
||||
});
|
||||
if (match_subscription) {
|
||||
return match_subscription;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -63,11 +61,12 @@ MemoryStrategy::get_service_by_handle(
|
||||
if (!group) {
|
||||
continue;
|
||||
}
|
||||
for (auto & weak_service : group->get_service_ptrs()) {
|
||||
auto service = weak_service.lock();
|
||||
if (service && service->get_service_handle() == service_handle) {
|
||||
return service;
|
||||
}
|
||||
auto service_ref = group->find_service_ptrs_if(
|
||||
[&service_handle](const rclcpp::ServiceBase::SharedPtr & service) -> bool {
|
||||
return service->get_service_handle() == service_handle;
|
||||
});
|
||||
if (service_ref) {
|
||||
return service_ref;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -89,11 +88,39 @@ MemoryStrategy::get_client_by_handle(
|
||||
if (!group) {
|
||||
continue;
|
||||
}
|
||||
for (auto & weak_client : group->get_client_ptrs()) {
|
||||
auto client = weak_client.lock();
|
||||
if (client && client->get_client_handle() == client_handle) {
|
||||
return client;
|
||||
}
|
||||
auto client_ref = group->find_client_ptrs_if(
|
||||
[&client_handle](const rclcpp::ClientBase::SharedPtr & client) -> bool {
|
||||
return client->get_client_handle() == client_handle;
|
||||
});
|
||||
if (client_ref) {
|
||||
return client_ref;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
rclcpp::TimerBase::SharedPtr
|
||||
MemoryStrategy::get_timer_by_handle(
|
||||
std::shared_ptr<const rcl_timer_t> timer_handle,
|
||||
const WeakNodeList & weak_nodes)
|
||||
{
|
||||
for (auto & weak_node : weak_nodes) {
|
||||
auto node = weak_node.lock();
|
||||
if (!node) {
|
||||
continue;
|
||||
}
|
||||
for (auto & weak_group : node->get_callback_groups()) {
|
||||
auto group = weak_group.lock();
|
||||
if (!group) {
|
||||
continue;
|
||||
}
|
||||
auto timer_ref = group->find_timer_ptrs_if(
|
||||
[&timer_handle](const rclcpp::TimerBase::SharedPtr & timer) -> bool {
|
||||
return timer->get_timer_handle() == timer_handle;
|
||||
});
|
||||
if (timer_ref) {
|
||||
return timer_ref;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -138,11 +165,12 @@ MemoryStrategy::get_group_by_subscription(
|
||||
if (!group) {
|
||||
continue;
|
||||
}
|
||||
for (auto & weak_sub : group->get_subscription_ptrs()) {
|
||||
auto sub = weak_sub.lock();
|
||||
if (sub == subscription) {
|
||||
return group;
|
||||
}
|
||||
auto match_sub = group->find_subscription_ptrs_if(
|
||||
[&subscription](const rclcpp::SubscriptionBase::SharedPtr & sub) -> bool {
|
||||
return sub == subscription;
|
||||
});
|
||||
if (match_sub) {
|
||||
return group;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -164,11 +192,12 @@ MemoryStrategy::get_group_by_service(
|
||||
if (!group) {
|
||||
continue;
|
||||
}
|
||||
for (auto & weak_serv : group->get_service_ptrs()) {
|
||||
auto serv = weak_serv.lock();
|
||||
if (serv && serv == service) {
|
||||
return group;
|
||||
}
|
||||
auto service_ref = group->find_service_ptrs_if(
|
||||
[&service](const rclcpp::ServiceBase::SharedPtr & serv) -> bool {
|
||||
return serv == service;
|
||||
});
|
||||
if (service_ref) {
|
||||
return group;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -190,11 +219,39 @@ MemoryStrategy::get_group_by_client(
|
||||
if (!group) {
|
||||
continue;
|
||||
}
|
||||
for (auto & weak_client : group->get_client_ptrs()) {
|
||||
auto cli = weak_client.lock();
|
||||
if (cli && cli == client) {
|
||||
return group;
|
||||
}
|
||||
auto client_ref = group->find_client_ptrs_if(
|
||||
[&client](const rclcpp::ClientBase::SharedPtr & cli) -> bool {
|
||||
return cli == client;
|
||||
});
|
||||
if (client_ref) {
|
||||
return group;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr
|
||||
MemoryStrategy::get_group_by_timer(
|
||||
rclcpp::TimerBase::SharedPtr timer,
|
||||
const WeakNodeList & weak_nodes)
|
||||
{
|
||||
for (auto & weak_node : weak_nodes) {
|
||||
auto node = weak_node.lock();
|
||||
if (!node) {
|
||||
continue;
|
||||
}
|
||||
for (auto & weak_group : node->get_callback_groups()) {
|
||||
auto group = weak_group.lock();
|
||||
if (!group) {
|
||||
continue;
|
||||
}
|
||||
auto timer_ref = group->find_timer_ptrs_if(
|
||||
[&timer](const rclcpp::TimerBase::SharedPtr & time) -> bool {
|
||||
return time == timer;
|
||||
});
|
||||
if (timer_ref) {
|
||||
return group;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -216,11 +273,12 @@ MemoryStrategy::get_group_by_waitable(
|
||||
if (!group) {
|
||||
continue;
|
||||
}
|
||||
for (auto & weak_waitable : group->get_waitable_ptrs()) {
|
||||
auto group_waitable = weak_waitable.lock();
|
||||
if (group_waitable && group_waitable == waitable) {
|
||||
return group;
|
||||
}
|
||||
auto waitable_ref = group->find_waitable_ptrs_if(
|
||||
[&waitable](const rclcpp::Waitable::SharedPtr & group_waitable) -> bool {
|
||||
return group_waitable == waitable;
|
||||
});
|
||||
if (waitable_ref) {
|
||||
return group;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,17 +27,7 @@
|
||||
#include "rclcpp/node_interfaces/node_clock.hpp"
|
||||
#include "rclcpp/node_interfaces/node_graph.hpp"
|
||||
#include "rclcpp/node_interfaces/node_logging.hpp"
|
||||
// When compiling this file, Windows produces a deprecation warning for the
|
||||
// deprecated function prototype of NodeParameters::register_param_change_callback().
|
||||
// Other compilers do not.
|
||||
#if defined(_WIN32)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4996)
|
||||
#endif
|
||||
#include "rclcpp/node_interfaces/node_parameters.hpp"
|
||||
#if defined(_WIN32)
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
#include "rclcpp/node_interfaces/node_services.hpp"
|
||||
#include "rclcpp/node_interfaces/node_time_source.hpp"
|
||||
#include "rclcpp/node_interfaces/node_timers.hpp"
|
||||
@@ -236,9 +226,14 @@ const rclcpp::ParameterValue &
|
||||
Node::declare_parameter(
|
||||
const std::string & name,
|
||||
const rclcpp::ParameterValue & default_value,
|
||||
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor)
|
||||
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor,
|
||||
bool ignore_override)
|
||||
{
|
||||
return this->node_parameters_->declare_parameter(name, default_value, parameter_descriptor);
|
||||
return this->node_parameters_->declare_parameter(
|
||||
name,
|
||||
default_value,
|
||||
parameter_descriptor,
|
||||
ignore_override);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -321,6 +316,18 @@ Node::list_parameters(const std::vector<std::string> & prefixes, uint64_t depth)
|
||||
return node_parameters_->list_parameters(prefixes, depth);
|
||||
}
|
||||
|
||||
rclcpp::Node::OnSetParametersCallbackHandle::SharedPtr
|
||||
Node::add_on_set_parameters_callback(OnParametersSetCallbackType callback)
|
||||
{
|
||||
return node_parameters_->add_on_set_parameters_callback(callback);
|
||||
}
|
||||
|
||||
void
|
||||
Node::remove_on_set_parameters_callback(const OnSetParametersCallbackHandle * const callback)
|
||||
{
|
||||
return node_parameters_->remove_on_set_parameters_callback(callback);
|
||||
}
|
||||
|
||||
rclcpp::Node::OnParametersSetCallbackType
|
||||
Node::set_on_parameters_set_callback(rclcpp::Node::OnParametersSetCallbackType callback)
|
||||
{
|
||||
|
||||
@@ -137,7 +137,8 @@ NodeGraph::get_node_names() const
|
||||
std::vector<std::string> nodes;
|
||||
auto names_and_namespaces = get_node_names_and_namespaces();
|
||||
|
||||
std::transform(names_and_namespaces.begin(),
|
||||
std::transform(
|
||||
names_and_namespaces.begin(),
|
||||
names_and_namespaces.end(),
|
||||
std::back_inserter(nodes),
|
||||
[](std::pair<std::string, std::string> nns) {
|
||||
|
||||
@@ -12,22 +12,13 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// When compiling this file, Windows produces a deprecation warning for the
|
||||
// deprecated function prototype of NodeParameters::register_param_change_callback().
|
||||
// Other compilers do not.
|
||||
#if defined(_WIN32)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4996)
|
||||
#endif
|
||||
#include "rclcpp/node_interfaces/node_parameters.hpp"
|
||||
#if defined(_WIN32)
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include <rcl_yaml_param_parser/parser.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
@@ -93,66 +84,39 @@ NodeParameters::NodeParameters(
|
||||
throw std::runtime_error("Need valid node options in NodeParameters");
|
||||
}
|
||||
|
||||
// Get paths to yaml files containing initial parameter values
|
||||
std::vector<std::string> yaml_paths;
|
||||
|
||||
auto get_yaml_paths = [&yaml_paths, &options](const rcl_arguments_t * args) {
|
||||
int num_yaml_files = rcl_arguments_get_param_files_count(args);
|
||||
if (num_yaml_files > 0) {
|
||||
char ** param_files;
|
||||
rcl_ret_t ret = rcl_arguments_get_param_files(args, options->allocator, ¶m_files);
|
||||
if (RCL_RET_OK != ret) {
|
||||
rclcpp::exceptions::throw_from_rcl_error(ret);
|
||||
}
|
||||
auto cleanup_param_files = make_scope_exit(
|
||||
[¶m_files, &num_yaml_files, &options]() {
|
||||
for (int i = 0; i < num_yaml_files; ++i) {
|
||||
options->allocator.deallocate(param_files[i], options->allocator.state);
|
||||
}
|
||||
options->allocator.deallocate(param_files, options->allocator.state);
|
||||
});
|
||||
for (int i = 0; i < num_yaml_files; ++i) {
|
||||
yaml_paths.emplace_back(param_files[i]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
std::vector<const rcl_arguments_t *> argument_sources;
|
||||
// global before local so that local overwrites global
|
||||
if (options->use_global_arguments) {
|
||||
auto context_ptr = node_base->get_context()->get_rcl_context();
|
||||
get_yaml_paths(&(context_ptr->global_arguments));
|
||||
argument_sources.push_back(&(context_ptr->global_arguments));
|
||||
}
|
||||
get_yaml_paths(&(options->arguments));
|
||||
argument_sources.push_back(&options->arguments);
|
||||
|
||||
// Get fully qualified node name post-remapping to use to find node's params in yaml files
|
||||
combined_name_ = node_base->get_fully_qualified_name();
|
||||
|
||||
// TODO(sloretz) use rcl to parse yaml when circular dependency is solved
|
||||
// See https://github.com/ros2/rcl/issues/252
|
||||
for (const std::string & yaml_path : yaml_paths) {
|
||||
rcl_params_t * yaml_params = rcl_yaml_node_struct_init(options->allocator);
|
||||
if (nullptr == yaml_params) {
|
||||
throw std::bad_alloc();
|
||||
for (const rcl_arguments_t * source : argument_sources) {
|
||||
rcl_params_t * params = NULL;
|
||||
rcl_ret_t ret = rcl_arguments_get_param_overrides(source, ¶ms);
|
||||
if (RCL_RET_OK != ret) {
|
||||
rclcpp::exceptions::throw_from_rcl_error(ret);
|
||||
}
|
||||
if (!rcl_parse_yaml_file(yaml_path.c_str(), yaml_params)) {
|
||||
std::ostringstream ss;
|
||||
ss << "Failed to parse parameters from file '" << yaml_path << "': " <<
|
||||
rcl_get_error_string().str;
|
||||
rcl_reset_error();
|
||||
throw std::runtime_error(ss.str());
|
||||
}
|
||||
|
||||
rclcpp::ParameterMap initial_map = rclcpp::parameter_map_from(yaml_params);
|
||||
rcl_yaml_node_struct_fini(yaml_params);
|
||||
auto iter = initial_map.find(combined_name_);
|
||||
if (initial_map.end() == iter) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Combine parameter yaml files, overwriting values in older ones
|
||||
for (auto & param : iter->second) {
|
||||
parameter_overrides_[param.get_name()] =
|
||||
rclcpp::ParameterValue(param.get_value_message());
|
||||
if (params) {
|
||||
auto cleanup_params = make_scope_exit(
|
||||
[params]() {
|
||||
rcl_yaml_node_struct_fini(params);
|
||||
});
|
||||
rclcpp::ParameterMap initial_map = rclcpp::parameter_map_from(params);
|
||||
for (auto iter = initial_map.begin(); initial_map.end() != iter; iter++) {
|
||||
// TODO(cottsay) implement further wildcard matching
|
||||
if (iter->first == "/**" || iter->first == combined_name_) {
|
||||
// Combine parameter yaml files, overwriting values in older ones
|
||||
for (auto & param : iter->second) {
|
||||
parameter_overrides_[param.get_name()] =
|
||||
rclcpp::ParameterValue(param.get_value_message());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,7 +134,8 @@ NodeParameters::NodeParameters(
|
||||
this->declare_parameter(
|
||||
pair.first,
|
||||
pair.second,
|
||||
rcl_interfaces::msg::ParameterDescriptor());
|
||||
rcl_interfaces::msg::ParameterDescriptor(),
|
||||
true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -239,9 +204,7 @@ __check_parameter_value_in_range(
|
||||
if (!descriptor.floating_point_range.empty() && value.get_type() == rclcpp::PARAMETER_DOUBLE) {
|
||||
double v = value.get<double>();
|
||||
auto fp_range = descriptor.floating_point_range.at(0);
|
||||
if (__are_doubles_equal(v, fp_range.from_value) ||
|
||||
__are_doubles_equal(v, fp_range.to_value))
|
||||
{
|
||||
if (__are_doubles_equal(v, fp_range.from_value) || __are_doubles_equal(v, fp_range.to_value)) {
|
||||
return result;
|
||||
}
|
||||
if ((v < fp_range.from_value) || (v > fp_range.to_value)) {
|
||||
@@ -287,20 +250,50 @@ __check_parameters(
|
||||
|
||||
using OnParametersSetCallbackType =
|
||||
rclcpp::node_interfaces::NodeParametersInterface::OnParametersSetCallbackType;
|
||||
using CallbacksContainerType =
|
||||
rclcpp::node_interfaces::NodeParameters::CallbacksContainerType;
|
||||
using OnSetParametersCallbackHandle =
|
||||
rclcpp::node_interfaces::OnSetParametersCallbackHandle;
|
||||
|
||||
RCLCPP_LOCAL
|
||||
rcl_interfaces::msg::SetParametersResult
|
||||
__call_on_parameters_set_callbacks(
|
||||
const std::vector<rclcpp::Parameter> & parameters,
|
||||
CallbacksContainerType & callback_container,
|
||||
const OnParametersSetCallbackType & callback)
|
||||
{
|
||||
rcl_interfaces::msg::SetParametersResult result;
|
||||
result.successful = true;
|
||||
auto it = callback_container.begin();
|
||||
while (it != callback_container.end()) {
|
||||
auto shared_handle = it->lock();
|
||||
if (nullptr != shared_handle) {
|
||||
result = shared_handle->callback(parameters);
|
||||
if (!result.successful) {
|
||||
return result;
|
||||
}
|
||||
it++;
|
||||
} else {
|
||||
it = callback_container.erase(it);
|
||||
}
|
||||
}
|
||||
if (callback) {
|
||||
result = callback(parameters);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
RCLCPP_LOCAL
|
||||
rcl_interfaces::msg::SetParametersResult
|
||||
__set_parameters_atomically_common(
|
||||
const std::vector<rclcpp::Parameter> & parameters,
|
||||
std::map<std::string, rclcpp::node_interfaces::ParameterInfo> & parameter_infos,
|
||||
OnParametersSetCallbackType on_set_parameters_callback)
|
||||
CallbacksContainerType & callback_container,
|
||||
const OnParametersSetCallbackType & callback)
|
||||
{
|
||||
// Call the user callback to see if the new value(s) are allowed.
|
||||
rcl_interfaces::msg::SetParametersResult result;
|
||||
result.successful = true;
|
||||
if (on_set_parameters_callback) {
|
||||
result = on_set_parameters_callback(parameters);
|
||||
}
|
||||
rcl_interfaces::msg::SetParametersResult result =
|
||||
__call_on_parameters_set_callbacks(parameters, callback_container, callback);
|
||||
if (!result.successful) {
|
||||
return result;
|
||||
}
|
||||
@@ -330,19 +323,21 @@ __declare_parameter_common(
|
||||
const rclcpp::ParameterValue & default_value,
|
||||
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor,
|
||||
std::map<std::string, rclcpp::node_interfaces::ParameterInfo> & parameters_out,
|
||||
const std::map<std::string, rclcpp::ParameterValue> & initial_values,
|
||||
OnParametersSetCallbackType on_set_parameters_callback,
|
||||
rcl_interfaces::msg::ParameterEvent * parameter_event_out)
|
||||
const std::map<std::string, rclcpp::ParameterValue> & overrides,
|
||||
CallbacksContainerType & callback_container,
|
||||
const OnParametersSetCallbackType & callback,
|
||||
rcl_interfaces::msg::ParameterEvent * parameter_event_out,
|
||||
bool ignore_override = false)
|
||||
{
|
||||
using rclcpp::node_interfaces::ParameterInfo;
|
||||
std::map<std::string, ParameterInfo> parameter_infos {{name, ParameterInfo()}};
|
||||
parameter_infos.at(name).descriptor = parameter_descriptor;
|
||||
|
||||
// Use the value from the initial_values if available, otherwise use the default.
|
||||
// Use the value from the overrides if available, otherwise use the default.
|
||||
const rclcpp::ParameterValue * initial_value = &default_value;
|
||||
auto initial_value_it = initial_values.find(name);
|
||||
if (initial_value_it != initial_values.end()) {
|
||||
initial_value = &initial_value_it->second;
|
||||
auto overrides_it = overrides.find(name);
|
||||
if (!ignore_override && overrides_it != overrides.end()) {
|
||||
initial_value = &overrides_it->second;
|
||||
}
|
||||
|
||||
// Check with the user's callback to see if the initial value can be set.
|
||||
@@ -351,7 +346,8 @@ __declare_parameter_common(
|
||||
auto result = __set_parameters_atomically_common(
|
||||
parameter_wrappers,
|
||||
parameter_infos,
|
||||
on_set_parameters_callback);
|
||||
callback_container,
|
||||
callback);
|
||||
|
||||
// Add declared parameters to storage.
|
||||
parameters_out[name] = parameter_infos.at(name);
|
||||
@@ -368,9 +364,12 @@ const rclcpp::ParameterValue &
|
||||
NodeParameters::declare_parameter(
|
||||
const std::string & name,
|
||||
const rclcpp::ParameterValue & default_value,
|
||||
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor)
|
||||
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor,
|
||||
bool ignore_override)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
||||
|
||||
ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
|
||||
|
||||
// TODO(sloretz) parameter name validation
|
||||
if (name.empty()) {
|
||||
@@ -390,8 +389,10 @@ NodeParameters::declare_parameter(
|
||||
parameter_descriptor,
|
||||
parameters_,
|
||||
parameter_overrides_,
|
||||
on_parameters_set_callback_container_,
|
||||
on_parameters_set_callback_,
|
||||
¶meter_event);
|
||||
¶meter_event,
|
||||
ignore_override);
|
||||
|
||||
// If it failed to be set, then throw an exception.
|
||||
if (!result.successful) {
|
||||
@@ -410,7 +411,9 @@ NodeParameters::declare_parameter(
|
||||
void
|
||||
NodeParameters::undeclare_parameter(const std::string & name)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
||||
|
||||
ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
|
||||
|
||||
auto parameter_info = parameters_.find(name);
|
||||
if (parameter_info == parameters_.end()) {
|
||||
@@ -429,7 +432,7 @@ NodeParameters::undeclare_parameter(const std::string & name)
|
||||
bool
|
||||
NodeParameters::has_parameter(const std::string & name) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
||||
|
||||
return __lockless_has_parameter(parameters_, name);
|
||||
}
|
||||
@@ -463,7 +466,9 @@ __find_parameter_by_name(
|
||||
rcl_interfaces::msg::SetParametersResult
|
||||
NodeParameters::set_parameters_atomically(const std::vector<rclcpp::Parameter> & parameters)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
||||
|
||||
ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
|
||||
|
||||
rcl_interfaces::msg::SetParametersResult result;
|
||||
|
||||
@@ -512,6 +517,7 @@ NodeParameters::set_parameters_atomically(const std::vector<rclcpp::Parameter> &
|
||||
std::map<std::string, rclcpp::node_interfaces::ParameterInfo> staged_parameter_changes;
|
||||
rcl_interfaces::msg::ParameterEvent parameter_event_msg;
|
||||
parameter_event_msg.node = combined_name_;
|
||||
CallbacksContainerType empty_callback_container;
|
||||
for (auto parameter_to_be_declared : parameters_to_be_declared) {
|
||||
// This should not throw, because we validated the name and checked that
|
||||
// the parameter was not already declared.
|
||||
@@ -521,8 +527,11 @@ NodeParameters::set_parameters_atomically(const std::vector<rclcpp::Parameter> &
|
||||
rcl_interfaces::msg::ParameterDescriptor(), // Implicit declare uses default descriptor.
|
||||
staged_parameter_changes,
|
||||
parameter_overrides_,
|
||||
nullptr, // callback is explicitly null, so that it is called only once, when setting below.
|
||||
¶meter_event_msg);
|
||||
// Only call callbacks once below
|
||||
empty_callback_container, // callback_container is explicitly empty
|
||||
nullptr, // callback is explicitly null.
|
||||
¶meter_event_msg,
|
||||
true);
|
||||
if (!result.successful) {
|
||||
// Declare failed, return knowing that nothing was changed because the
|
||||
// staged changes were not applied.
|
||||
@@ -569,13 +578,16 @@ NodeParameters::set_parameters_atomically(const std::vector<rclcpp::Parameter> &
|
||||
}
|
||||
}
|
||||
|
||||
// Set the all of the parameters including the ones declared implicitly above.
|
||||
// Set all of the parameters including the ones declared implicitly above.
|
||||
result = __set_parameters_atomically_common(
|
||||
// either the original parameters given by the user, or ones updated with initial values
|
||||
*parameters_to_be_set,
|
||||
// they are actually set on the official parameter storage
|
||||
parameters_,
|
||||
// this will get called once, with all the parameters to be set
|
||||
on_parameters_set_callback_container_,
|
||||
// These callbacks are called once. When a callback returns an unsuccessful result,
|
||||
// the remaining aren't called.
|
||||
on_parameters_set_callback_);
|
||||
|
||||
// If not successful, then stop here.
|
||||
@@ -638,7 +650,7 @@ NodeParameters::set_parameters_atomically(const std::vector<rclcpp::Parameter> &
|
||||
std::vector<rclcpp::Parameter>
|
||||
NodeParameters::get_parameters(const std::vector<std::string> & names) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
||||
std::vector<rclcpp::Parameter> results;
|
||||
results.reserve(names.size());
|
||||
|
||||
@@ -677,7 +689,7 @@ NodeParameters::get_parameter(
|
||||
const std::string & name,
|
||||
rclcpp::Parameter & parameter) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
||||
|
||||
auto param_iter = parameters_.find(name);
|
||||
if (
|
||||
@@ -696,7 +708,7 @@ NodeParameters::get_parameters_by_prefix(
|
||||
const std::string & prefix,
|
||||
std::map<std::string, rclcpp::Parameter> & parameters) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
||||
|
||||
std::string prefix_with_dot = prefix.empty() ? prefix : prefix + ".";
|
||||
bool ret = false;
|
||||
@@ -715,7 +727,7 @@ NodeParameters::get_parameters_by_prefix(
|
||||
std::vector<rcl_interfaces::msg::ParameterDescriptor>
|
||||
NodeParameters::describe_parameters(const std::vector<std::string> & names) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
||||
std::vector<rcl_interfaces::msg::ParameterDescriptor> results;
|
||||
results.reserve(names.size());
|
||||
|
||||
@@ -743,7 +755,7 @@ NodeParameters::describe_parameters(const std::vector<std::string> & names) cons
|
||||
std::vector<uint8_t>
|
||||
NodeParameters::get_parameter_types(const std::vector<std::string> & names) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
||||
std::vector<uint8_t> results;
|
||||
results.reserve(names.size());
|
||||
|
||||
@@ -769,7 +781,7 @@ NodeParameters::get_parameter_types(const std::vector<std::string> & names) cons
|
||||
rcl_interfaces::msg::ListParametersResult
|
||||
NodeParameters::list_parameters(const std::vector<std::string> & prefixes, uint64_t depth) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
||||
rcl_interfaces::msg::ListParametersResult result;
|
||||
|
||||
// TODO(mikaelarguedas) define parameter separator different from "/" to avoid ambiguity
|
||||
@@ -779,25 +791,27 @@ NodeParameters::list_parameters(const std::vector<std::string> & prefixes, uint6
|
||||
bool get_all = (prefixes.size() == 0) &&
|
||||
((depth == rcl_interfaces::srv::ListParameters::Request::DEPTH_RECURSIVE) ||
|
||||
(static_cast<uint64_t>(std::count(kv.first.begin(), kv.first.end(), *separator)) < depth));
|
||||
bool prefix_matches = std::any_of(prefixes.cbegin(), prefixes.cend(),
|
||||
[&kv, &depth, &separator](const std::string & prefix) {
|
||||
if (kv.first == prefix) {
|
||||
return true;
|
||||
} else if (kv.first.find(prefix + separator) == 0) {
|
||||
size_t length = prefix.length();
|
||||
std::string substr = kv.first.substr(length);
|
||||
// Cast as unsigned integer to avoid warning
|
||||
return (depth == rcl_interfaces::srv::ListParameters::Request::DEPTH_RECURSIVE) ||
|
||||
(static_cast<uint64_t>(std::count(substr.begin(), substr.end(), *separator)) < depth);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
bool prefix_matches = std::any_of(
|
||||
prefixes.cbegin(), prefixes.cend(),
|
||||
[&kv, &depth, &separator](const std::string & prefix) {
|
||||
if (kv.first == prefix) {
|
||||
return true;
|
||||
} else if (kv.first.find(prefix + separator) == 0) {
|
||||
size_t length = prefix.length();
|
||||
std::string substr = kv.first.substr(length);
|
||||
// Cast as unsigned integer to avoid warning
|
||||
return (depth == rcl_interfaces::srv::ListParameters::Request::DEPTH_RECURSIVE) ||
|
||||
(static_cast<uint64_t>(std::count(substr.begin(), substr.end(), *separator)) < depth);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
if (get_all || prefix_matches) {
|
||||
result.names.push_back(kv.first);
|
||||
size_t last_separator = kv.first.find_last_of(separator);
|
||||
if (std::string::npos != last_separator) {
|
||||
std::string prefix = kv.first.substr(0, last_separator);
|
||||
if (std::find(result.prefixes.cbegin(), result.prefixes.cend(), prefix) ==
|
||||
if (
|
||||
std::find(result.prefixes.cbegin(), result.prefixes.cend(), prefix) ==
|
||||
result.prefixes.cend())
|
||||
{
|
||||
result.prefixes.push_back(prefix);
|
||||
@@ -808,37 +822,65 @@ NodeParameters::list_parameters(const std::vector<std::string> & prefixes, uint6
|
||||
return result;
|
||||
}
|
||||
|
||||
struct HandleCompare
|
||||
: public std::unary_function<OnSetParametersCallbackHandle::WeakPtr, bool>
|
||||
{
|
||||
explicit HandleCompare(const OnSetParametersCallbackHandle * const base)
|
||||
: base_(base) {}
|
||||
bool operator()(const OnSetParametersCallbackHandle::WeakPtr & handle)
|
||||
{
|
||||
auto shared_handle = handle.lock();
|
||||
if (base_ == shared_handle.get()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
const OnSetParametersCallbackHandle * const base_;
|
||||
};
|
||||
|
||||
void
|
||||
NodeParameters::remove_on_set_parameters_callback(
|
||||
const OnSetParametersCallbackHandle * const handle)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
||||
ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
|
||||
|
||||
auto it = std::find_if(
|
||||
on_parameters_set_callback_container_.begin(),
|
||||
on_parameters_set_callback_container_.end(),
|
||||
HandleCompare(handle));
|
||||
if (it != on_parameters_set_callback_container_.end()) {
|
||||
on_parameters_set_callback_container_.erase(it);
|
||||
} else {
|
||||
throw std::runtime_error("Callback doesn't exist");
|
||||
}
|
||||
}
|
||||
|
||||
OnSetParametersCallbackHandle::SharedPtr
|
||||
NodeParameters::add_on_set_parameters_callback(OnParametersSetCallbackType callback)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
||||
ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
|
||||
|
||||
auto handle = std::make_shared<OnSetParametersCallbackHandle>();
|
||||
handle->callback = callback;
|
||||
// the last callback registered is executed first.
|
||||
on_parameters_set_callback_container_.emplace_front(handle);
|
||||
return handle;
|
||||
}
|
||||
|
||||
NodeParameters::OnParametersSetCallbackType
|
||||
NodeParameters::set_on_parameters_set_callback(OnParametersSetCallbackType callback)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex_);
|
||||
|
||||
ParameterMutationRecursionGuard guard(parameter_modification_enabled_);
|
||||
|
||||
auto existing_callback = on_parameters_set_callback_;
|
||||
on_parameters_set_callback_ = callback;
|
||||
return existing_callback;
|
||||
}
|
||||
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4996)
|
||||
#endif
|
||||
void
|
||||
NodeParameters::register_param_change_callback(ParametersCallbackFunction callback)
|
||||
{
|
||||
if (on_parameters_set_callback_) {
|
||||
RCLCPP_WARN(
|
||||
node_logging_->get_logger(),
|
||||
"on_parameters_set_callback already registered, overwriting previous callback");
|
||||
}
|
||||
on_parameters_set_callback_ = callback;
|
||||
}
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic pop
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
const std::map<std::string, rclcpp::ParameterValue> &
|
||||
NodeParameters::get_parameter_overrides() const
|
||||
{
|
||||
|
||||
@@ -34,36 +34,10 @@ rclcpp::PublisherBase::SharedPtr
|
||||
NodeTopics::create_publisher(
|
||||
const std::string & topic_name,
|
||||
const rclcpp::PublisherFactory & publisher_factory,
|
||||
const rcl_publisher_options_t & publisher_options,
|
||||
bool use_intra_process)
|
||||
const rclcpp::QoS & qos)
|
||||
{
|
||||
// Create the MessageT specific Publisher using the factory, but store it as PublisherBase.
|
||||
auto publisher = publisher_factory.create_typed_publisher(
|
||||
node_base_, topic_name, publisher_options);
|
||||
|
||||
// Setup intra process publishing if requested.
|
||||
if (use_intra_process) {
|
||||
auto context = node_base_->get_context();
|
||||
// Get the intra process manager instance for this context.
|
||||
auto ipm = context->get_sub_context<rclcpp::intra_process_manager::IntraProcessManager>();
|
||||
// Register the publisher with the intra process manager.
|
||||
if (publisher_options.qos.history == RMW_QOS_POLICY_HISTORY_KEEP_ALL) {
|
||||
throw std::invalid_argument(
|
||||
"intraprocess communication is not allowed with keep all history qos policy");
|
||||
}
|
||||
if (publisher_options.qos.depth == 0) {
|
||||
throw std::invalid_argument(
|
||||
"intraprocess communication is not allowed with a zero qos history depth value");
|
||||
}
|
||||
uint64_t intra_process_publisher_id = ipm->add_publisher(publisher);
|
||||
publisher->setup_intra_process(
|
||||
intra_process_publisher_id,
|
||||
ipm,
|
||||
publisher_options);
|
||||
}
|
||||
|
||||
// Return the completed publisher.
|
||||
return publisher;
|
||||
// Create the MessageT specific Publisher using the factory, but return it as PublisherBase.
|
||||
return publisher_factory.create_typed_publisher(node_base_, topic_name, qos);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -99,25 +73,10 @@ rclcpp::SubscriptionBase::SharedPtr
|
||||
NodeTopics::create_subscription(
|
||||
const std::string & topic_name,
|
||||
const rclcpp::SubscriptionFactory & subscription_factory,
|
||||
const rcl_subscription_options_t & subscription_options,
|
||||
bool use_intra_process)
|
||||
const rclcpp::QoS & qos)
|
||||
{
|
||||
auto subscription = subscription_factory.create_typed_subscription(
|
||||
node_base_, topic_name, subscription_options);
|
||||
|
||||
// Setup intra process publishing if requested.
|
||||
if (use_intra_process) {
|
||||
auto context = node_base_->get_context();
|
||||
auto ipm =
|
||||
context->get_sub_context<rclcpp::intra_process_manager::IntraProcessManager>();
|
||||
uint64_t intra_process_subscription_id = ipm->add_subscription(subscription);
|
||||
auto options_copy = subscription_options;
|
||||
options_copy.ignore_local_publications = false;
|
||||
subscription->setup_intra_process(intra_process_subscription_id, ipm, options_copy);
|
||||
}
|
||||
|
||||
// Return the completed subscription.
|
||||
return subscription;
|
||||
// Create the MessageT specific Subscription using the factory, but return a SubscriptionBase.
|
||||
return subscription_factory.create_typed_subscription(node_base_, topic_name, qos);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
#include "rclcpp/logging.hpp"
|
||||
@@ -90,25 +91,48 @@ NodeOptions::get_rcl_node_options() const
|
||||
node_options_->use_global_arguments = this->use_global_arguments_;
|
||||
node_options_->domain_id = this->get_domain_id_from_env();
|
||||
|
||||
std::unique_ptr<const char *[]> c_args;
|
||||
int c_argc = 0;
|
||||
std::unique_ptr<const char *[]> c_argv;
|
||||
if (!this->arguments_.empty()) {
|
||||
c_args.reset(new const char *[this->arguments_.size()]);
|
||||
if (this->arguments_.size() > static_cast<size_t>(std::numeric_limits<int>::max())) {
|
||||
throw_from_rcl_error(RCL_RET_INVALID_ARGUMENT, "Too many args");
|
||||
}
|
||||
|
||||
c_argc = static_cast<int>(this->arguments_.size());
|
||||
c_argv.reset(new const char *[c_argc]);
|
||||
|
||||
for (std::size_t i = 0; i < this->arguments_.size(); ++i) {
|
||||
c_args[i] = this->arguments_[i].c_str();
|
||||
c_argv[i] = this->arguments_[i].c_str();
|
||||
}
|
||||
}
|
||||
|
||||
if (this->arguments_.size() > std::numeric_limits<int>::max()) {
|
||||
throw_from_rcl_error(RCL_RET_INVALID_ARGUMENT, "Too many args");
|
||||
}
|
||||
|
||||
rmw_ret_t ret = rcl_parse_arguments(
|
||||
static_cast<int>(this->arguments_.size()), c_args.get(), this->allocator_,
|
||||
&(node_options_->arguments));
|
||||
rcl_ret_t ret = rcl_parse_arguments(
|
||||
c_argc, c_argv.get(), this->allocator_, &(node_options_->arguments));
|
||||
|
||||
if (RCL_RET_OK != ret) {
|
||||
throw_from_rcl_error(ret, "failed to parse arguments");
|
||||
}
|
||||
|
||||
int unparsed_ros_args_count =
|
||||
rcl_arguments_get_count_unparsed_ros(&(node_options_->arguments));
|
||||
if (unparsed_ros_args_count > 0) {
|
||||
int * unparsed_ros_args_indices = nullptr;
|
||||
ret = rcl_arguments_get_unparsed_ros(
|
||||
&(node_options_->arguments), this->allocator_, &unparsed_ros_args_indices);
|
||||
if (RCL_RET_OK != ret) {
|
||||
throw_from_rcl_error(ret, "failed to get unparsed ROS arguments");
|
||||
}
|
||||
try {
|
||||
std::vector<std::string> unparsed_ros_args;
|
||||
for (int i = 0; i < unparsed_ros_args_count; ++i) {
|
||||
unparsed_ros_args.push_back(c_argv[unparsed_ros_args_indices[i]]);
|
||||
}
|
||||
throw exceptions::UnknownROSArgsError(std::move(unparsed_ros_args));
|
||||
} catch (...) {
|
||||
this->allocator_.deallocate(unparsed_ros_args_indices, this->allocator_.state);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return node_options_.get();
|
||||
|
||||
@@ -19,17 +19,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
// When compiling this file, Windows produces a deprecation warning for the
|
||||
// deprecated function prototype of NodeParameters::register_param_change_callback().
|
||||
// Other compilers do not.
|
||||
#if defined(_WIN32)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4996)
|
||||
#endif
|
||||
#include "rclcpp/node_interfaces/node_parameters.hpp"
|
||||
#if defined(_WIN32)
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
#include "rclcpp/utilities.hpp"
|
||||
|
||||
using rclcpp::ParameterType;
|
||||
|
||||
@@ -30,7 +30,8 @@ AsyncParametersClient::AsyncParametersClient(
|
||||
const rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph_interface,
|
||||
const rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services_interface,
|
||||
const std::string & remote_node_name,
|
||||
const rmw_qos_profile_t & qos_profile)
|
||||
const rmw_qos_profile_t & qos_profile,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group)
|
||||
: node_topics_interface_(node_topics_interface)
|
||||
{
|
||||
if (remote_node_name != "") {
|
||||
@@ -51,7 +52,7 @@ AsyncParametersClient::AsyncParametersClient(
|
||||
remote_node_name_ + "/" + parameter_service_names::get_parameters,
|
||||
options);
|
||||
auto get_parameters_base = std::dynamic_pointer_cast<ClientBase>(get_parameters_client_);
|
||||
node_services_interface->add_client(get_parameters_base, nullptr);
|
||||
node_services_interface->add_client(get_parameters_base, group);
|
||||
|
||||
get_parameter_types_client_ = Client<rcl_interfaces::srv::GetParameterTypes>::make_shared(
|
||||
node_base_interface.get(),
|
||||
@@ -60,7 +61,7 @@ AsyncParametersClient::AsyncParametersClient(
|
||||
options);
|
||||
auto get_parameter_types_base =
|
||||
std::dynamic_pointer_cast<ClientBase>(get_parameter_types_client_);
|
||||
node_services_interface->add_client(get_parameter_types_base, nullptr);
|
||||
node_services_interface->add_client(get_parameter_types_base, group);
|
||||
|
||||
set_parameters_client_ = Client<rcl_interfaces::srv::SetParameters>::make_shared(
|
||||
node_base_interface.get(),
|
||||
@@ -68,16 +69,17 @@ AsyncParametersClient::AsyncParametersClient(
|
||||
remote_node_name_ + "/" + parameter_service_names::set_parameters,
|
||||
options);
|
||||
auto set_parameters_base = std::dynamic_pointer_cast<ClientBase>(set_parameters_client_);
|
||||
node_services_interface->add_client(set_parameters_base, nullptr);
|
||||
node_services_interface->add_client(set_parameters_base, group);
|
||||
|
||||
set_parameters_atomically_client_ =
|
||||
Client<rcl_interfaces::srv::SetParametersAtomically>::make_shared(node_base_interface.get(),
|
||||
node_graph_interface,
|
||||
remote_node_name_ + "/" + parameter_service_names::set_parameters_atomically,
|
||||
options);
|
||||
Client<rcl_interfaces::srv::SetParametersAtomically>::make_shared(
|
||||
node_base_interface.get(),
|
||||
node_graph_interface,
|
||||
remote_node_name_ + "/" + parameter_service_names::set_parameters_atomically,
|
||||
options);
|
||||
auto set_parameters_atomically_base = std::dynamic_pointer_cast<ClientBase>(
|
||||
set_parameters_atomically_client_);
|
||||
node_services_interface->add_client(set_parameters_atomically_base, nullptr);
|
||||
node_services_interface->add_client(set_parameters_atomically_base, group);
|
||||
|
||||
list_parameters_client_ = Client<rcl_interfaces::srv::ListParameters>::make_shared(
|
||||
node_base_interface.get(),
|
||||
@@ -85,7 +87,7 @@ AsyncParametersClient::AsyncParametersClient(
|
||||
remote_node_name_ + "/" + parameter_service_names::list_parameters,
|
||||
options);
|
||||
auto list_parameters_base = std::dynamic_pointer_cast<ClientBase>(list_parameters_client_);
|
||||
node_services_interface->add_client(list_parameters_base, nullptr);
|
||||
node_services_interface->add_client(list_parameters_base, group);
|
||||
|
||||
describe_parameters_client_ = Client<rcl_interfaces::srv::DescribeParameters>::make_shared(
|
||||
node_base_interface.get(),
|
||||
@@ -94,33 +96,37 @@ AsyncParametersClient::AsyncParametersClient(
|
||||
options);
|
||||
auto describe_parameters_base =
|
||||
std::dynamic_pointer_cast<ClientBase>(describe_parameters_client_);
|
||||
node_services_interface->add_client(describe_parameters_base, nullptr);
|
||||
node_services_interface->add_client(describe_parameters_base, group);
|
||||
}
|
||||
|
||||
AsyncParametersClient::AsyncParametersClient(
|
||||
const rclcpp::Node::SharedPtr node,
|
||||
const std::string & remote_node_name,
|
||||
const rmw_qos_profile_t & qos_profile)
|
||||
const rmw_qos_profile_t & qos_profile,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group)
|
||||
: AsyncParametersClient(
|
||||
node->get_node_base_interface(),
|
||||
node->get_node_topics_interface(),
|
||||
node->get_node_graph_interface(),
|
||||
node->get_node_services_interface(),
|
||||
remote_node_name,
|
||||
qos_profile)
|
||||
qos_profile,
|
||||
group)
|
||||
{}
|
||||
|
||||
AsyncParametersClient::AsyncParametersClient(
|
||||
rclcpp::Node * node,
|
||||
const std::string & remote_node_name,
|
||||
const rmw_qos_profile_t & qos_profile)
|
||||
const rmw_qos_profile_t & qos_profile,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group)
|
||||
: AsyncParametersClient(
|
||||
node->get_node_base_interface(),
|
||||
node->get_node_topics_interface(),
|
||||
node->get_node_graph_interface(),
|
||||
node->get_node_services_interface(),
|
||||
remote_node_name,
|
||||
qos_profile)
|
||||
qos_profile,
|
||||
group)
|
||||
{}
|
||||
|
||||
std::shared_future<std::vector<rclcpp::Parameter>>
|
||||
@@ -150,8 +156,7 @@ AsyncParametersClient::get_parameters(
|
||||
rcl_interfaces::msg::Parameter parameter;
|
||||
parameter.name = request->names[i];
|
||||
parameter.value = pvalue;
|
||||
parameters.push_back(rclcpp::Parameter::from_parameter_msg(
|
||||
parameter));
|
||||
parameters.push_back(rclcpp::Parameter::from_parameter_msg(parameter));
|
||||
}
|
||||
|
||||
promise_result->set_value(parameters);
|
||||
@@ -211,10 +216,9 @@ AsyncParametersClient::set_parameters(
|
||||
|
||||
auto request = std::make_shared<rcl_interfaces::srv::SetParameters::Request>();
|
||||
|
||||
std::transform(parameters.begin(), parameters.end(), std::back_inserter(request->parameters),
|
||||
[](rclcpp::Parameter p) {
|
||||
return p.to_parameter_msg();
|
||||
}
|
||||
std::transform(
|
||||
parameters.begin(), parameters.end(), std::back_inserter(request->parameters),
|
||||
[](rclcpp::Parameter p) {return p.to_parameter_msg();}
|
||||
);
|
||||
|
||||
set_parameters_client_->async_send_request(
|
||||
@@ -245,10 +249,9 @@ AsyncParametersClient::set_parameters_atomically(
|
||||
|
||||
auto request = std::make_shared<rcl_interfaces::srv::SetParametersAtomically::Request>();
|
||||
|
||||
std::transform(parameters.begin(), parameters.end(), std::back_inserter(request->parameters),
|
||||
[](rclcpp::Parameter p) {
|
||||
return p.to_parameter_msg();
|
||||
}
|
||||
std::transform(
|
||||
parameters.begin(), parameters.end(), std::back_inserter(request->parameters),
|
||||
[](rclcpp::Parameter p) {return p.to_parameter_msg();}
|
||||
);
|
||||
|
||||
set_parameters_atomically_client_->async_send_request(
|
||||
@@ -411,8 +414,10 @@ SyncParametersClient::get_parameters(const std::vector<std::string> & parameter_
|
||||
{
|
||||
auto f = async_parameters_client_->get_parameters(parameter_names);
|
||||
using rclcpp::executors::spin_node_until_future_complete;
|
||||
if (spin_node_until_future_complete(*executor_, node_base_interface_, f) ==
|
||||
rclcpp::executor::FutureReturnCode::SUCCESS)
|
||||
if (
|
||||
spin_node_until_future_complete(
|
||||
*executor_, node_base_interface_,
|
||||
f) == rclcpp::executor::FutureReturnCode::SUCCESS)
|
||||
{
|
||||
return f.get();
|
||||
}
|
||||
@@ -435,8 +440,10 @@ SyncParametersClient::get_parameter_types(const std::vector<std::string> & param
|
||||
auto f = async_parameters_client_->get_parameter_types(parameter_names);
|
||||
|
||||
using rclcpp::executors::spin_node_until_future_complete;
|
||||
if (spin_node_until_future_complete(*executor_, node_base_interface_, f) ==
|
||||
rclcpp::executor::FutureReturnCode::SUCCESS)
|
||||
if (
|
||||
spin_node_until_future_complete(
|
||||
*executor_, node_base_interface_,
|
||||
f) == rclcpp::executor::FutureReturnCode::SUCCESS)
|
||||
{
|
||||
return f.get();
|
||||
}
|
||||
@@ -450,8 +457,10 @@ SyncParametersClient::set_parameters(
|
||||
auto f = async_parameters_client_->set_parameters(parameters);
|
||||
|
||||
using rclcpp::executors::spin_node_until_future_complete;
|
||||
if (spin_node_until_future_complete(*executor_, node_base_interface_, f) ==
|
||||
rclcpp::executor::FutureReturnCode::SUCCESS)
|
||||
if (
|
||||
spin_node_until_future_complete(
|
||||
*executor_, node_base_interface_,
|
||||
f) == rclcpp::executor::FutureReturnCode::SUCCESS)
|
||||
{
|
||||
return f.get();
|
||||
}
|
||||
@@ -465,8 +474,10 @@ SyncParametersClient::set_parameters_atomically(
|
||||
auto f = async_parameters_client_->set_parameters_atomically(parameters);
|
||||
|
||||
using rclcpp::executors::spin_node_until_future_complete;
|
||||
if (spin_node_until_future_complete(*executor_, node_base_interface_, f) ==
|
||||
rclcpp::executor::FutureReturnCode::SUCCESS)
|
||||
if (
|
||||
spin_node_until_future_complete(
|
||||
*executor_, node_base_interface_,
|
||||
f) == rclcpp::executor::FutureReturnCode::SUCCESS)
|
||||
{
|
||||
return f.get();
|
||||
}
|
||||
@@ -482,8 +493,10 @@ SyncParametersClient::list_parameters(
|
||||
auto f = async_parameters_client_->list_parameters(parameter_prefixes, depth);
|
||||
|
||||
using rclcpp::executors::spin_node_until_future_complete;
|
||||
if (spin_node_until_future_complete(*executor_, node_base_interface_, f) ==
|
||||
rclcpp::executor::FutureReturnCode::SUCCESS)
|
||||
if (
|
||||
spin_node_until_future_complete(
|
||||
*executor_, node_base_interface_,
|
||||
f) == rclcpp::executor::FutureReturnCode::SUCCESS)
|
||||
{
|
||||
return f.get();
|
||||
}
|
||||
|
||||
@@ -59,10 +59,11 @@ ParameterService::ParameterService(
|
||||
{
|
||||
try {
|
||||
auto types = node_params->get_parameter_types(request->names);
|
||||
std::transform(types.cbegin(), types.cend(),
|
||||
std::back_inserter(response->types), [](const uint8_t & type) {
|
||||
return static_cast<rclcpp::ParameterType>(type);
|
||||
});
|
||||
std::transform(
|
||||
types.cbegin(), types.cend(),
|
||||
std::back_inserter(response->types), [](const uint8_t & type) {
|
||||
return static_cast<rclcpp::ParameterType>(type);
|
||||
});
|
||||
} catch (const rclcpp::exceptions::ParameterNotDeclaredException & ex) {
|
||||
RCLCPP_WARN(rclcpp::get_logger("rclcpp"), "Failed to get parameter types: %s", ex.what());
|
||||
}
|
||||
@@ -103,11 +104,12 @@ ParameterService::ParameterService(
|
||||
std::shared_ptr<rcl_interfaces::srv::SetParametersAtomically::Response> response)
|
||||
{
|
||||
std::vector<rclcpp::Parameter> pvariants;
|
||||
std::transform(request->parameters.cbegin(), request->parameters.cend(),
|
||||
std::back_inserter(pvariants),
|
||||
[](const rcl_interfaces::msg::Parameter & p) {
|
||||
return rclcpp::Parameter::from_parameter_msg(p);
|
||||
});
|
||||
std::transform(
|
||||
request->parameters.cbegin(), request->parameters.cend(),
|
||||
std::back_inserter(pvariants),
|
||||
[](const rcl_interfaces::msg::Parameter & p) {
|
||||
return rclcpp::Parameter::from_parameter_msg(p);
|
||||
});
|
||||
try {
|
||||
auto result = node_params->set_parameters_atomically(pvariants);
|
||||
response->result = result;
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "rclcpp/expand_topic_or_service_name.hpp"
|
||||
#include "rclcpp/intra_process_manager.hpp"
|
||||
#include "rclcpp/logging.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
|
||||
#include "rmw/error_handling.h"
|
||||
#include "rmw/rmw.h"
|
||||
@@ -30,18 +31,18 @@
|
||||
using rclcpp::SubscriptionBase;
|
||||
|
||||
SubscriptionBase::SubscriptionBase(
|
||||
std::shared_ptr<rcl_node_t> node_handle,
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||
const rosidl_message_type_support_t & type_support_handle,
|
||||
const std::string & topic_name,
|
||||
const rcl_subscription_options_t & subscription_options,
|
||||
bool is_serialized)
|
||||
: node_handle_(node_handle),
|
||||
: node_handle_(node_base->get_shared_rcl_node_handle()),
|
||||
use_intra_process_(false),
|
||||
intra_process_subscription_id_(0),
|
||||
type_support_(type_support_handle),
|
||||
is_serialized_(is_serialized)
|
||||
{
|
||||
auto custom_deletor = [node_handle](rcl_subscription_t * rcl_subs)
|
||||
auto custom_deletor = [node_handle = this->node_handle_](rcl_subscription_t * rcl_subs)
|
||||
{
|
||||
if (rcl_subscription_fini(rcl_subs, node_handle.get()) != RCL_RET_OK) {
|
||||
RCLCPP_ERROR(
|
||||
@@ -128,6 +129,18 @@ SubscriptionBase::get_event_handlers() const
|
||||
return event_handlers_;
|
||||
}
|
||||
|
||||
rmw_qos_profile_t
|
||||
SubscriptionBase::get_actual_qos() const
|
||||
{
|
||||
const rmw_qos_profile_t * qos = rcl_subscription_get_actual_qos(subscription_handle_.get());
|
||||
if (!qos) {
|
||||
auto msg = std::string("failed to get qos settings: ") + rcl_get_error_string().str;
|
||||
rcl_reset_error();
|
||||
throw std::runtime_error(msg);
|
||||
}
|
||||
return *qos;
|
||||
}
|
||||
|
||||
const rosidl_message_type_support_t &
|
||||
SubscriptionBase::get_message_type_support_handle() const
|
||||
{
|
||||
@@ -155,7 +168,8 @@ SubscriptionBase::get_publisher_count() const
|
||||
return inter_process_publisher_count;
|
||||
}
|
||||
|
||||
void SubscriptionBase::setup_intra_process(
|
||||
void
|
||||
SubscriptionBase::setup_intra_process(
|
||||
uint64_t intra_process_subscription_id,
|
||||
IntraProcessManagerWeakPtr weak_ipm,
|
||||
const rcl_subscription_options_t & intra_process_options)
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "rclcpp/clock.hpp"
|
||||
@@ -194,7 +195,10 @@ Duration
|
||||
Time::operator-(const rclcpp::Time & rhs) const
|
||||
{
|
||||
if (rcl_time_.clock_type != rhs.rcl_time_.clock_type) {
|
||||
throw std::runtime_error("can't subtract times with different time sources");
|
||||
throw std::runtime_error(
|
||||
std::string("can't subtract times with different time sources [") +
|
||||
std::to_string(rcl_time_.clock_type) + " != " +
|
||||
std::to_string(rhs.rcl_time_.clock_type) + "]");
|
||||
}
|
||||
|
||||
if (rclcpp::sub_will_overflow(rcl_time_.nanoseconds, rhs.rcl_time_.nanoseconds)) {
|
||||
|
||||
@@ -100,7 +100,8 @@ void TimeSource::attachNode(
|
||||
} else {
|
||||
// TODO(wjwwood): use set_on_parameters_set_callback to catch the type mismatch,
|
||||
// before the use_sim_time parameter can ever be set to an invalid value
|
||||
RCLCPP_ERROR(logger_, "Invalid type '%s' for parameter 'use_sim_time', should be 'bool'",
|
||||
RCLCPP_ERROR(
|
||||
logger_, "Invalid type '%s' for parameter 'use_sim_time', should be 'bool'",
|
||||
rclcpp::to_string(use_sim_time_param.get_type()).c_str());
|
||||
}
|
||||
|
||||
@@ -154,7 +155,8 @@ void TimeSource::detachClock(std::shared_ptr<rclcpp::Clock> clock)
|
||||
|
||||
TimeSource::~TimeSource()
|
||||
{
|
||||
if (node_base_ || node_topics_ || node_graph_ || node_services_ ||
|
||||
if (
|
||||
node_base_ || node_topics_ || node_graph_ || node_services_ ||
|
||||
node_logging_ || node_clock_ || node_parameters_)
|
||||
{
|
||||
this->detachNode();
|
||||
@@ -220,13 +222,17 @@ void TimeSource::destroy_clock_sub()
|
||||
|
||||
void TimeSource::on_parameter_event(const rcl_interfaces::msg::ParameterEvent::SharedPtr event)
|
||||
{
|
||||
// Filter out events on 'use_sim_time' parameter instances in other nodes.
|
||||
if (event->node != node_base_->get_fully_qualified_name()) {
|
||||
return;
|
||||
}
|
||||
// Filter for only 'use_sim_time' being added or changed.
|
||||
rclcpp::ParameterEventsFilter filter(event, {"use_sim_time"},
|
||||
{rclcpp::ParameterEventsFilter::EventType::NEW,
|
||||
rclcpp::ParameterEventsFilter::EventType::CHANGED});
|
||||
for (auto & it : filter.get_events()) {
|
||||
if (it.second->value.type != ParameterType::PARAMETER_BOOL) {
|
||||
RCLCPP_ERROR(logger_, "use_sim_time parameter set to something besides a bool");
|
||||
RCLCPP_ERROR(logger_, "use_sim_time parameter cannot be set to anything but a bool");
|
||||
continue;
|
||||
}
|
||||
if (it.second->value.bool_value) {
|
||||
|
||||
@@ -55,7 +55,8 @@ TimerBase::TimerBase(
|
||||
*timer_handle_.get() = rcl_get_zero_initialized_timer();
|
||||
|
||||
rcl_clock_t * clock_handle = clock_->get_clock_handle();
|
||||
if (rcl_timer_init(
|
||||
if (
|
||||
rcl_timer_init(
|
||||
timer_handle_.get(), clock_handle, rcl_context.get(), period.count(), nullptr,
|
||||
rcl_get_default_allocator()) != RCL_RET_OK)
|
||||
{
|
||||
@@ -110,12 +111,14 @@ std::chrono::nanoseconds
|
||||
TimerBase::time_until_trigger()
|
||||
{
|
||||
int64_t time_until_next_call = 0;
|
||||
if (rcl_timer_get_time_until_next_call(timer_handle_.get(),
|
||||
&time_until_next_call) != RCL_RET_OK)
|
||||
if (
|
||||
rcl_timer_get_time_until_next_call(
|
||||
timer_handle_.get(),
|
||||
&time_until_next_call) != RCL_RET_OK)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
std::string("Timer could not get time until next call: ") +
|
||||
rcl_get_error_string().str);
|
||||
std::string(
|
||||
"Timer could not get time until next call: ") + rcl_get_error_string().str);
|
||||
}
|
||||
return std::chrono::nanoseconds(time_until_next_call);
|
||||
}
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
bool request
|
||||
---
|
||||
bool response
|
||||
@@ -85,6 +85,26 @@ TEST_F(TestGetNodeInterfaces, node_reference) {
|
||||
>::value, "expected rclcpp::node_interfaces::NodeTopicsInterface *");
|
||||
}
|
||||
|
||||
TEST_F(TestGetNodeInterfaces, rclcpp_node_pointer) {
|
||||
rclcpp::Node * node_pointer = this->node.get();
|
||||
auto result = rclcpp::node_interfaces::get_node_topics_interface(node_pointer);
|
||||
static_assert(
|
||||
std::is_same<
|
||||
rclcpp::node_interfaces::NodeTopicsInterface *,
|
||||
decltype(result)
|
||||
>::value, "expected rclcpp::node_interfaces::NodeTopicsInterface *");
|
||||
}
|
||||
|
||||
TEST_F(TestGetNodeInterfaces, node_pointer) {
|
||||
NodeWrapper * wrapped_node_pointer = this->wrapped_node.get();
|
||||
auto result = rclcpp::node_interfaces::get_node_topics_interface(wrapped_node_pointer);
|
||||
static_assert(
|
||||
std::is_same<
|
||||
rclcpp::node_interfaces::NodeTopicsInterface *,
|
||||
decltype(result)
|
||||
>::value, "expected rclcpp::node_interfaces::NodeTopicsInterface *");
|
||||
}
|
||||
|
||||
TEST_F(TestGetNodeInterfaces, interface_shared_pointer) {
|
||||
std::shared_ptr<rclcpp::node_interfaces::NodeTopicsInterface> interface_shared_ptr =
|
||||
this->node->get_node_topics_interface();
|
||||
|
||||
4
rclcpp/test/resources/test_node/test_parameters.yaml
Normal file
4
rclcpp/test/resources/test_node/test_parameters.yaml
Normal file
@@ -0,0 +1,4 @@
|
||||
/**:
|
||||
ros__parameters:
|
||||
parameter_int: 21
|
||||
parameter_string_array: [baz, baz, baz]
|
||||
@@ -75,12 +75,37 @@ TEST_F(TestClient, construction_and_destruction) {
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW({
|
||||
ASSERT_THROW(
|
||||
{
|
||||
auto client = node->create_client<ListParameters>("invalid_service?");
|
||||
}, rclcpp::exceptions::InvalidServiceNameError);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestClient, construction_with_free_function) {
|
||||
{
|
||||
auto client = rclcpp::create_client<rcl_interfaces::srv::ListParameters>(
|
||||
node->get_node_base_interface(),
|
||||
node->get_node_graph_interface(),
|
||||
node->get_node_services_interface(),
|
||||
"service",
|
||||
rmw_qos_profile_services_default,
|
||||
nullptr);
|
||||
}
|
||||
{
|
||||
ASSERT_THROW(
|
||||
{
|
||||
auto client = rclcpp::create_client<rcl_interfaces::srv::ListParameters>(
|
||||
node->get_node_base_interface(),
|
||||
node->get_node_graph_interface(),
|
||||
node->get_node_services_interface(),
|
||||
"invalid_?service",
|
||||
rmw_qos_profile_services_default,
|
||||
nullptr);
|
||||
}, rclcpp::exceptions::InvalidServiceNameError);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Testing client construction and destruction for subnodes.
|
||||
*/
|
||||
@@ -92,7 +117,8 @@ TEST_F(TestClientSub, construction_and_destruction) {
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW({
|
||||
ASSERT_THROW(
|
||||
{
|
||||
auto client = node->create_client<ListParameters>("invalid_service?");
|
||||
}, rclcpp::exceptions::InvalidServiceNameError);
|
||||
}
|
||||
|
||||
63
rclcpp/test/test_create_timer.cpp
Normal file
63
rclcpp/test/test_create_timer.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
// Copyright 2019 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
|
||||
#include "rclcpp/create_timer.hpp"
|
||||
#include "rclcpp/executors.hpp"
|
||||
#include "rclcpp/node.hpp"
|
||||
#include "node_interfaces/node_wrapper.hpp"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
TEST(TestCreateTimer, timer_executes)
|
||||
{
|
||||
rclcpp::init(0, nullptr);
|
||||
auto node = std::make_shared<rclcpp::Node>("test_create_timer_node");
|
||||
|
||||
std::atomic<bool> got_callback{false};
|
||||
|
||||
rclcpp::TimerBase::SharedPtr timer;
|
||||
timer = rclcpp::create_timer(
|
||||
node,
|
||||
node->get_clock(),
|
||||
rclcpp::Duration(0ms),
|
||||
[&got_callback, &timer]() {
|
||||
got_callback = true;
|
||||
timer->cancel();
|
||||
});
|
||||
|
||||
rclcpp::spin_some(node);
|
||||
|
||||
ASSERT_TRUE(got_callback);
|
||||
rclcpp::shutdown();
|
||||
}
|
||||
|
||||
TEST(TestCreateTimer, call_with_node_wrapper_compiles)
|
||||
{
|
||||
rclcpp::init(0, nullptr);
|
||||
NodeWrapper node("test_create_timer_call_with_node_wrapper_compiles");
|
||||
|
||||
rclcpp::TimerBase::SharedPtr timer;
|
||||
timer = rclcpp::create_timer(
|
||||
node,
|
||||
node.get_node_clock_interface()->get_clock(),
|
||||
rclcpp::Duration(0ms),
|
||||
[]() {});
|
||||
rclcpp::shutdown();
|
||||
}
|
||||
@@ -136,3 +136,20 @@ TEST(TestDuration, maximum_duration) {
|
||||
|
||||
EXPECT_EQ(max_duration, max);
|
||||
}
|
||||
|
||||
static const int64_t HALF_SEC_IN_NS = 500 * 1000 * 1000;
|
||||
static const int64_t ONE_AND_HALF_SEC_IN_NS = 3 * HALF_SEC_IN_NS;
|
||||
|
||||
TEST(TestDuration, from_seconds) {
|
||||
EXPECT_EQ(rclcpp::Duration(0), rclcpp::Duration::from_seconds(0.0));
|
||||
EXPECT_EQ(rclcpp::Duration(0), rclcpp::Duration::from_seconds(0));
|
||||
EXPECT_EQ(rclcpp::Duration(1, HALF_SEC_IN_NS), rclcpp::Duration::from_seconds(1.5));
|
||||
EXPECT_EQ(rclcpp::Duration(-ONE_AND_HALF_SEC_IN_NS), rclcpp::Duration::from_seconds(-1.5));
|
||||
}
|
||||
|
||||
TEST(TestDuration, std_chrono_constructors) {
|
||||
EXPECT_EQ(rclcpp::Duration(0), rclcpp::Duration(0.0s));
|
||||
EXPECT_EQ(rclcpp::Duration(0), rclcpp::Duration(0s));
|
||||
EXPECT_EQ(rclcpp::Duration(1, HALF_SEC_IN_NS), rclcpp::Duration(1.5s));
|
||||
EXPECT_EQ(rclcpp::Duration(-1, 0), rclcpp::Duration(-1s));
|
||||
}
|
||||
|
||||
@@ -33,39 +33,45 @@ TEST(TestExpandTopicOrServiceName, normal) {
|
||||
TEST(TestExpandTopicOrServiceName, exceptions) {
|
||||
using rclcpp::expand_topic_or_service_name;
|
||||
{
|
||||
ASSERT_THROW({
|
||||
ASSERT_THROW(
|
||||
{
|
||||
expand_topic_or_service_name("chatter", "invalid_node?", "/ns");
|
||||
}, rclcpp::exceptions::InvalidNodeNameError);
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW({
|
||||
ASSERT_THROW(
|
||||
{
|
||||
expand_topic_or_service_name("chatter", "node", "/invalid_ns?");
|
||||
}, rclcpp::exceptions::InvalidNamespaceError);
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW({
|
||||
ASSERT_THROW(
|
||||
{
|
||||
expand_topic_or_service_name("chatter/42invalid", "node", "/ns");
|
||||
}, rclcpp::exceptions::InvalidTopicNameError);
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW({
|
||||
ASSERT_THROW(
|
||||
{
|
||||
// this one will only fail on the "full" topic name validation check
|
||||
expand_topic_or_service_name("chatter/{ns}/invalid", "node", "/ns");
|
||||
}, rclcpp::exceptions::InvalidTopicNameError);
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW({
|
||||
ASSERT_THROW(
|
||||
{
|
||||
// is_service = true
|
||||
expand_topic_or_service_name("chatter/42invalid", "node", "/ns", true);
|
||||
}, rclcpp::exceptions::InvalidServiceNameError);
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW({
|
||||
ASSERT_THROW(
|
||||
{
|
||||
// is_service = true
|
||||
// this one will only fail on the "full" topic name validation check
|
||||
expand_topic_or_service_name("chatter/{ns}/invalid", "node", "/ns", true);
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
|
||||
#include "rcl/service.h"
|
||||
|
||||
#include "rclcpp/srv/mock.hpp"
|
||||
#include "rclcpp/srv/mock.h"
|
||||
#include "test_msgs/srv/empty.hpp"
|
||||
#include "test_msgs/srv/empty.h"
|
||||
|
||||
class TestExternallyDefinedServices : public ::testing::Test
|
||||
{
|
||||
@@ -38,16 +38,15 @@ protected:
|
||||
|
||||
void
|
||||
callback(
|
||||
const std::shared_ptr<rclcpp::srv::Mock::Request>/*req*/,
|
||||
std::shared_ptr<rclcpp::srv::Mock::Response>/*resp*/)
|
||||
const std::shared_ptr<test_msgs::srv::Empty::Request>/*req*/,
|
||||
std::shared_ptr<test_msgs::srv::Empty::Response>/*resp*/)
|
||||
{}
|
||||
|
||||
TEST_F(TestExternallyDefinedServices, default_behavior) {
|
||||
auto node_handle = rclcpp::Node::make_shared("base_node");
|
||||
|
||||
try {
|
||||
auto srv = node_handle->create_service<rclcpp::srv::Mock>("test",
|
||||
callback);
|
||||
auto srv = node_handle->create_service<test_msgs::srv::Empty>("test", callback);
|
||||
} catch (const std::exception &) {
|
||||
FAIL();
|
||||
return;
|
||||
@@ -55,19 +54,18 @@ TEST_F(TestExternallyDefinedServices, default_behavior) {
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
TEST_F(TestExternallyDefinedServices, extern_defined_uninitialized) {
|
||||
auto node_handle = rclcpp::Node::make_shared("base_node");
|
||||
|
||||
// mock for externally defined service
|
||||
rcl_service_t service_handle = rcl_get_zero_initialized_service();
|
||||
|
||||
rclcpp::AnyServiceCallback<rclcpp::srv::Mock> cb;
|
||||
rclcpp::AnyServiceCallback<test_msgs::srv::Empty> cb;
|
||||
|
||||
// don't initialize the service
|
||||
// expect fail
|
||||
try {
|
||||
rclcpp::Service<rclcpp::srv::Mock>(
|
||||
rclcpp::Service<test_msgs::srv::Empty>(
|
||||
node_handle->get_node_base_interface()->get_shared_rcl_node_handle(),
|
||||
&service_handle, cb);
|
||||
} catch (const std::runtime_error &) {
|
||||
@@ -85,7 +83,7 @@ TEST_F(TestExternallyDefinedServices, extern_defined_initialized) {
|
||||
rcl_service_t service_handle = rcl_get_zero_initialized_service();
|
||||
rcl_service_options_t service_options = rcl_service_get_default_options();
|
||||
const rosidl_service_type_support_t * ts =
|
||||
rosidl_typesupport_cpp::get_service_type_support_handle<rclcpp::srv::Mock>();
|
||||
rosidl_typesupport_cpp::get_service_type_support_handle<test_msgs::srv::Empty>();
|
||||
rcl_ret_t ret = rcl_service_init(
|
||||
&service_handle,
|
||||
node_handle->get_node_base_interface()->get_rcl_node_handle(),
|
||||
@@ -95,10 +93,10 @@ TEST_F(TestExternallyDefinedServices, extern_defined_initialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
rclcpp::AnyServiceCallback<rclcpp::srv::Mock> cb;
|
||||
rclcpp::AnyServiceCallback<test_msgs::srv::Empty> cb;
|
||||
|
||||
try {
|
||||
rclcpp::Service<rclcpp::srv::Mock>(
|
||||
rclcpp::Service<test_msgs::srv::Empty>(
|
||||
node_handle->get_node_base_interface()->get_shared_rcl_node_handle(),
|
||||
&service_handle, cb);
|
||||
} catch (const std::runtime_error &) {
|
||||
@@ -125,7 +123,7 @@ TEST_F(TestExternallyDefinedServices, extern_defined_destructor) {
|
||||
rcl_service_t service_handle = rcl_get_zero_initialized_service();
|
||||
rcl_service_options_t service_options = rcl_service_get_default_options();
|
||||
const rosidl_service_type_support_t * ts =
|
||||
rosidl_typesupport_cpp::get_service_type_support_handle<rclcpp::srv::Mock>();
|
||||
rosidl_typesupport_cpp::get_service_type_support_handle<test_msgs::srv::Empty>();
|
||||
rcl_ret_t ret = rcl_service_init(
|
||||
&service_handle,
|
||||
node_handle->get_node_base_interface()->get_rcl_node_handle(),
|
||||
@@ -134,11 +132,11 @@ TEST_F(TestExternallyDefinedServices, extern_defined_destructor) {
|
||||
FAIL();
|
||||
return;
|
||||
}
|
||||
rclcpp::AnyServiceCallback<rclcpp::srv::Mock> cb;
|
||||
rclcpp::AnyServiceCallback<test_msgs::srv::Empty> cb;
|
||||
|
||||
{
|
||||
// Call constructor
|
||||
rclcpp::Service<rclcpp::srv::Mock> srv_cpp(
|
||||
rclcpp::Service<test_msgs::srv::Empty> srv_cpp(
|
||||
node_handle->get_node_base_interface()->get_shared_rcl_node_handle(),
|
||||
&service_handle, cb);
|
||||
// Call destructor
|
||||
|
||||
@@ -80,6 +80,12 @@ struct ObjectMember
|
||||
return 7;
|
||||
}
|
||||
|
||||
int callback_one_bool_const(bool a) const
|
||||
{
|
||||
(void)a;
|
||||
return 7;
|
||||
}
|
||||
|
||||
int callback_two_bools(bool a, bool b)
|
||||
{
|
||||
(void)a;
|
||||
@@ -394,6 +400,16 @@ TEST(TestFunctionTraits, argument_types) {
|
||||
rclcpp::function_traits::function_traits<decltype(bind_one_bool)>::template argument_type<0>
|
||||
>::value, "Functor accepts a bool as first argument");
|
||||
|
||||
auto bind_one_bool_const = std::bind(
|
||||
&ObjectMember::callback_one_bool_const, &object_member, std::placeholders::_1);
|
||||
|
||||
static_assert(
|
||||
std::is_same<
|
||||
bool,
|
||||
rclcpp::function_traits::function_traits<decltype(bind_one_bool_const)>::template
|
||||
argument_type<0>
|
||||
>::value, "Functor accepts a bool as first argument");
|
||||
|
||||
auto bind_two_bools = std::bind(
|
||||
&ObjectMember::callback_two_bools, &object_member, std::placeholders::_1,
|
||||
std::placeholders::_2);
|
||||
@@ -561,6 +577,14 @@ TEST(TestFunctionTraits, check_arguments) {
|
||||
static_assert(
|
||||
rclcpp::function_traits::check_arguments<decltype(bind_one_bool), bool>::value,
|
||||
"Functor accepts a single bool as arguments");
|
||||
|
||||
auto bind_one_bool_const = std::bind(
|
||||
&ObjectMember::callback_one_bool_const, &object_member, std::placeholders::_1);
|
||||
|
||||
// Test std::bind functions
|
||||
static_assert(
|
||||
rclcpp::function_traits::check_arguments<decltype(bind_one_bool_const), bool>::value,
|
||||
"Functor accepts a single bool as arguments");
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -718,8 +742,9 @@ public:
|
||||
TEST_F GTest macro.
|
||||
*/
|
||||
TEST_F(TestMember, bind_member_functor) {
|
||||
auto bind_member_functor = std::bind(&TestMember::MemberFunctor, this, std::placeholders::_1,
|
||||
std::placeholders::_2, std::placeholders::_3);
|
||||
auto bind_member_functor = std::bind(
|
||||
&TestMember::MemberFunctor, this, std::placeholders::_1,
|
||||
std::placeholders::_2, std::placeholders::_3);
|
||||
|
||||
static_assert(
|
||||
rclcpp::function_traits::check_arguments<decltype(bind_member_functor), int, float,
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
// Copyright 2018 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 <cstdio>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
|
||||
TEST(test_local_parameters, set_parameter_if_not_set) {
|
||||
auto node = rclcpp::Node::make_shared(
|
||||
"test_local_parameters_set_parameter_if_not_set",
|
||||
rclcpp::NodeOptions().allow_undeclared_parameters(true));
|
||||
|
||||
{
|
||||
// try to set a map of parameters
|
||||
std::map<std::string, double> bar_map{
|
||||
{"x", 0.5},
|
||||
{"y", 1.0},
|
||||
};
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4996)
|
||||
#endif
|
||||
node->set_parameters_if_not_set("bar", bar_map);
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic pop
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
double bar_x_value;
|
||||
ASSERT_TRUE(node->get_parameter("bar.x", bar_x_value));
|
||||
EXPECT_EQ(bar_x_value, 0.5);
|
||||
double bar_y_value;
|
||||
ASSERT_TRUE(node->get_parameter("bar.y", bar_y_value));
|
||||
EXPECT_EQ(bar_y_value, 1.0);
|
||||
std::map<std::string, double> new_map;
|
||||
ASSERT_TRUE(node->get_parameters("bar", new_map));
|
||||
ASSERT_EQ(new_map.size(), 2U);
|
||||
EXPECT_EQ(new_map["x"], 0.5);
|
||||
EXPECT_EQ(new_map["y"], 1.0);
|
||||
}
|
||||
|
||||
{
|
||||
// try to get a map of parameters that doesn't exist
|
||||
std::map<std::string, double> no_exist_map;
|
||||
ASSERT_FALSE(node->get_parameters("no_exist", no_exist_map));
|
||||
}
|
||||
|
||||
{
|
||||
// set parameters for a map with different types, then try to get them back as a map
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4996)
|
||||
#endif
|
||||
node->set_parameter_if_not_set("baz.x", 1.0);
|
||||
node->set_parameter_if_not_set("baz.y", "hello");
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic pop
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
std::map<std::string, double> baz_map;
|
||||
EXPECT_THROW(node->get_parameters("baz", baz_map), rclcpp::ParameterTypeException);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
::setvbuf(stdout, NULL, _IONBF, BUFSIZ);
|
||||
|
||||
// NOTE: use custom main to ensure that rclcpp::init is called only once
|
||||
rclcpp::init(argc, argv);
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
int ret = RUN_ALL_TESTS();
|
||||
rclcpp::shutdown();
|
||||
return ret;
|
||||
}
|
||||
@@ -162,3 +162,28 @@ TEST_F(TestLoggingMacros, test_logging_skipfirst) {
|
||||
EXPECT_EQ(i - 1, g_log_calls);
|
||||
}
|
||||
}
|
||||
|
||||
bool log_function(rclcpp::Logger logger)
|
||||
{
|
||||
RCLCPP_INFO(logger, "successful log");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool log_function_const(const rclcpp::Logger logger)
|
||||
{
|
||||
RCLCPP_INFO(logger, "successful log");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool log_function_const_ref(const rclcpp::Logger & logger)
|
||||
{
|
||||
RCLCPP_INFO(logger, "successful log");
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST_F(TestLoggingMacros, test_log_from_node) {
|
||||
auto logger = rclcpp::get_logger("test_logging_logger");
|
||||
EXPECT_TRUE(log_function(logger));
|
||||
EXPECT_TRUE(log_function_const(logger));
|
||||
EXPECT_TRUE(log_function_const_ref(logger));
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#include "rclcpp/scope_exit.hpp"
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
|
||||
#include "rcpputils/filesystem_helper.hpp"
|
||||
|
||||
class TestNode : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
@@ -32,6 +34,13 @@ protected:
|
||||
{
|
||||
rclcpp::init(0, nullptr);
|
||||
}
|
||||
|
||||
void SetUp() override
|
||||
{
|
||||
test_resources_path /= "test_node";
|
||||
}
|
||||
|
||||
rcpputils::fs::path test_resources_path{TEST_RESOURCES_DIRECTORY};
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -43,13 +52,15 @@ TEST_F(TestNode, construction_and_destruction) {
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW({
|
||||
ASSERT_THROW(
|
||||
{
|
||||
std::make_shared<rclcpp::Node>("invalid_node?", "/ns");
|
||||
}, rclcpp::exceptions::InvalidNodeNameError);
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW({
|
||||
ASSERT_THROW(
|
||||
{
|
||||
std::make_shared<rclcpp::Node>("my_node", "/invalid_ns?");
|
||||
}, rclcpp::exceptions::InvalidNamespaceError);
|
||||
}
|
||||
@@ -64,7 +75,7 @@ TEST_F(TestNode, get_name_and_namespace) {
|
||||
}
|
||||
{
|
||||
auto options = rclcpp::NodeOptions()
|
||||
.arguments({"__ns:=/another_ns"});
|
||||
.arguments({"--ros-args", "-r", "__ns:=/another_ns"});
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns", options);
|
||||
EXPECT_STREQ("my_node", node->get_name());
|
||||
EXPECT_STREQ("/another_ns", node->get_namespace());
|
||||
@@ -106,8 +117,9 @@ TEST_F(TestNode, get_name_and_namespace) {
|
||||
auto node3 = std::make_shared<rclcpp::Node>("my_node3", "/ns2");
|
||||
auto node4 = std::make_shared<rclcpp::Node>("my_node4", "my/ns3");
|
||||
auto names_and_namespaces = node1->get_node_names();
|
||||
auto name_namespace_set = std::unordered_set<std::string>(names_and_namespaces.begin(),
|
||||
names_and_namespaces.end());
|
||||
auto name_namespace_set = std::unordered_set<std::string>(
|
||||
names_and_namespaces.begin(),
|
||||
names_and_namespaces.end());
|
||||
std::function<bool(std::string)> Set_Contains = [&](std::string string_key)
|
||||
{
|
||||
return name_namespace_set.find(string_key) != name_namespace_set.end();
|
||||
@@ -172,7 +184,8 @@ TEST_F(TestNode, subnode_get_name_and_namespace) {
|
||||
}
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node");
|
||||
ASSERT_THROW({
|
||||
ASSERT_THROW(
|
||||
{
|
||||
auto subnode = node->create_sub_node("/sub_ns");
|
||||
}, rclcpp::exceptions::NameValidationError);
|
||||
}
|
||||
@@ -182,60 +195,70 @@ TEST_F(TestNode, subnode_get_name_and_namespace) {
|
||||
*/
|
||||
TEST_F(TestNode, subnode_construction_and_destruction) {
|
||||
{
|
||||
ASSERT_NO_THROW({
|
||||
ASSERT_NO_THROW(
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "ns");
|
||||
auto subnode = node->create_sub_node("sub_ns");
|
||||
});
|
||||
}
|
||||
{
|
||||
ASSERT_THROW({
|
||||
ASSERT_THROW(
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "ns");
|
||||
auto subnode = node->create_sub_node("invalid_ns?");
|
||||
}, rclcpp::exceptions::InvalidNamespaceError);
|
||||
}
|
||||
{
|
||||
ASSERT_THROW({
|
||||
ASSERT_THROW(
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "ns/");
|
||||
}, rclcpp::exceptions::InvalidNamespaceError);
|
||||
}
|
||||
{
|
||||
ASSERT_THROW({
|
||||
ASSERT_THROW(
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "ns/");
|
||||
auto subnode = node->create_sub_node("/sub_ns");
|
||||
}, rclcpp::exceptions::InvalidNamespaceError);
|
||||
}
|
||||
{
|
||||
ASSERT_THROW({
|
||||
ASSERT_THROW(
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "ns");
|
||||
auto subnode = node->create_sub_node("/sub_ns");
|
||||
}, rclcpp::exceptions::NameValidationError);
|
||||
}
|
||||
{
|
||||
ASSERT_THROW({
|
||||
ASSERT_THROW(
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "ns");
|
||||
auto subnode = node->create_sub_node("~sub_ns");
|
||||
}, rclcpp::exceptions::InvalidNamespaceError);
|
||||
}
|
||||
{
|
||||
ASSERT_THROW({
|
||||
ASSERT_THROW(
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
|
||||
auto subnode = node->create_sub_node("invalid_ns?");
|
||||
}, rclcpp::exceptions::InvalidNamespaceError);
|
||||
}
|
||||
{
|
||||
ASSERT_NO_THROW({
|
||||
ASSERT_NO_THROW(
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
|
||||
auto subnode = node->create_sub_node("sub_ns");
|
||||
});
|
||||
}
|
||||
{
|
||||
ASSERT_THROW({
|
||||
ASSERT_THROW(
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
|
||||
auto subnode = node->create_sub_node("/sub_ns");
|
||||
}, rclcpp::exceptions::NameValidationError);
|
||||
}
|
||||
{
|
||||
ASSERT_THROW({
|
||||
ASSERT_THROW(
|
||||
{
|
||||
auto node = std::make_shared<rclcpp::Node>("my_node", "/ns");
|
||||
auto subnode = node->create_sub_node("~sub_ns");
|
||||
}, rclcpp::exceptions::InvalidNamespaceError);
|
||||
@@ -362,29 +385,109 @@ TEST_F(TestNode, declare_parameter_with_no_initial_values) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestNode, declare_parameter_with_initial_values) {
|
||||
// test cases with initial values
|
||||
auto get_fixed_on_parameter_set_callback(const std::string & name, bool successful)
|
||||
{
|
||||
return
|
||||
[name, successful](const std::vector<rclcpp::Parameter> & parameters) {
|
||||
(void)parameters;
|
||||
rcl_interfaces::msg::SetParametersResult result;
|
||||
result.successful = successful;
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
TEST_F(TestNode, test_registering_multiple_callbacks_api) {
|
||||
auto node = std::make_shared<rclcpp::Node>("test_declare_parameter_node"_unq);
|
||||
{
|
||||
int64_t default_value{42};
|
||||
auto name1 = "parameter"_unq;
|
||||
auto scoped_callback1 = node->add_on_set_parameters_callback(
|
||||
get_fixed_on_parameter_set_callback(name1, true));
|
||||
EXPECT_NE(scoped_callback1, nullptr);
|
||||
int64_t value{node->declare_parameter(name1, default_value)};
|
||||
EXPECT_EQ(value, default_value);
|
||||
|
||||
auto name2 = "parameter"_unq;
|
||||
auto scoped_callback2 = node->add_on_set_parameters_callback(
|
||||
get_fixed_on_parameter_set_callback(name2, false));
|
||||
EXPECT_NE(scoped_callback2, nullptr);
|
||||
EXPECT_THROW(
|
||||
{node->declare_parameter(name2, default_value);},
|
||||
rclcpp::exceptions::InvalidParameterValueException);
|
||||
|
||||
auto name3 = "parameter"_unq;
|
||||
scoped_callback2.reset();
|
||||
value = node->declare_parameter(name3, default_value);
|
||||
EXPECT_EQ(value, default_value);
|
||||
}
|
||||
{
|
||||
int64_t default_value{42};
|
||||
auto name1 = "parameter"_unq;
|
||||
auto scoped_callback1 = node->add_on_set_parameters_callback(
|
||||
get_fixed_on_parameter_set_callback(name1, true));
|
||||
EXPECT_NE(scoped_callback1, nullptr);
|
||||
int64_t value{node->declare_parameter(name1, default_value)};
|
||||
EXPECT_EQ(value, default_value);
|
||||
|
||||
auto name2 = "parameter"_unq;
|
||||
auto scoped_callback2 = node->add_on_set_parameters_callback(
|
||||
get_fixed_on_parameter_set_callback(name2, false));
|
||||
EXPECT_NE(scoped_callback2, nullptr);
|
||||
EXPECT_THROW(
|
||||
{node->declare_parameter(name2, default_value);},
|
||||
rclcpp::exceptions::InvalidParameterValueException);
|
||||
|
||||
auto name3 = "parameter"_unq;
|
||||
node->remove_on_set_parameters_callback(scoped_callback2.get());
|
||||
value = node->declare_parameter(name3, default_value);
|
||||
EXPECT_EQ(value, default_value);
|
||||
}
|
||||
{
|
||||
int64_t default_value{42};
|
||||
auto name1 = "parameter"_unq;
|
||||
rclcpp::Node::OnSetParametersCallbackHandle::SharedPtr scoped_callback(
|
||||
node->add_on_set_parameters_callback(
|
||||
get_fixed_on_parameter_set_callback(name1, false)));
|
||||
rclcpp::Node::OnSetParametersCallbackHandle::SharedPtr scoped_callback_copy(scoped_callback);
|
||||
scoped_callback.reset();
|
||||
|
||||
EXPECT_THROW(
|
||||
{node->declare_parameter("parameter"_unq, default_value);},
|
||||
rclcpp::exceptions::InvalidParameterValueException);
|
||||
|
||||
scoped_callback_copy.reset();
|
||||
// All the shared_ptr has been reset
|
||||
int64_t value = node->declare_parameter("parameter"_unq, default_value);
|
||||
EXPECT_EQ(value, default_value);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestNode, declare_parameter_with_overrides) {
|
||||
// test cases with overrides
|
||||
rclcpp::NodeOptions no;
|
||||
no.parameter_overrides({
|
||||
no.parameter_overrides(
|
||||
{
|
||||
{"parameter_no_default", 42},
|
||||
{"parameter_no_default_set", 42},
|
||||
{"parameter_no_default_set_cvref", 42},
|
||||
{"parameter_and_default", 42},
|
||||
{"parameter_and_default_ignore_override", 42},
|
||||
{"parameter_custom", 42},
|
||||
{"parameter_template", 42},
|
||||
{"parameter_already_declared", 42},
|
||||
{"parameter_rejected", 42},
|
||||
{"parameter_type_mismatch", "not an int"},
|
||||
});
|
||||
|
||||
auto node = std::make_shared<rclcpp::Node>("test_declare_parameter_node"_unq, no);
|
||||
{
|
||||
// no default, with initial
|
||||
// no default, with override
|
||||
rclcpp::ParameterValue value = node->declare_parameter("parameter_no_default");
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_INTEGER);
|
||||
EXPECT_EQ(value.get<int>(), 42);
|
||||
}
|
||||
{
|
||||
// no default, with initial, and set after
|
||||
// no default, with override, and set after
|
||||
rclcpp::ParameterValue value = node->declare_parameter("parameter_no_default_set");
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_INTEGER);
|
||||
EXPECT_EQ(value.get<int>(), 42);
|
||||
@@ -393,7 +496,7 @@ TEST_F(TestNode, declare_parameter_with_initial_values) {
|
||||
EXPECT_EQ(node->get_parameter("parameter_no_default_set").get_value<int>(), 44);
|
||||
}
|
||||
{
|
||||
// no default, with initial
|
||||
// no default, with override
|
||||
const rclcpp::ParameterValue & value =
|
||||
node->declare_parameter("parameter_no_default_set_cvref");
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_INTEGER);
|
||||
@@ -403,12 +506,23 @@ TEST_F(TestNode, declare_parameter_with_initial_values) {
|
||||
EXPECT_EQ(value.get<int>(), 44);
|
||||
}
|
||||
{
|
||||
// int default, with initial
|
||||
// int default, with override
|
||||
rclcpp::ParameterValue default_value(43);
|
||||
rclcpp::ParameterValue value = node->declare_parameter("parameter_and_default", default_value);
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_INTEGER);
|
||||
EXPECT_EQ(value.get<int>(), 42); // and not 43 which is the default value
|
||||
}
|
||||
{
|
||||
// int default, with override and ignoring it
|
||||
rclcpp::ParameterValue default_value(43);
|
||||
rclcpp::ParameterValue value = node->declare_parameter(
|
||||
"parameter_and_default_ignore_override",
|
||||
default_value,
|
||||
rcl_interfaces::msg::ParameterDescriptor(),
|
||||
true);
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_INTEGER);
|
||||
EXPECT_EQ(value.get<int>(), 43); // and not 42, the parameter override is ignored.
|
||||
}
|
||||
{
|
||||
// int default, with initial, custom parameter descriptor
|
||||
rclcpp::ParameterValue default_value(43);
|
||||
@@ -482,7 +596,8 @@ TEST_F(TestNode, declare_parameters_with_no_initial_values) {
|
||||
{
|
||||
// with namespace, defaults, no custom descriptors, no initial
|
||||
int64_t bigger_than_int = INT64_MAX - 42;
|
||||
auto values = node->declare_parameters<int64_t>("namespace1", {
|
||||
auto values = node->declare_parameters<int64_t>(
|
||||
"namespace1", {
|
||||
{"parameter_a", 42},
|
||||
{"parameter_b", 256},
|
||||
{"parameter_c", bigger_than_int},
|
||||
@@ -495,7 +610,8 @@ TEST_F(TestNode, declare_parameters_with_no_initial_values) {
|
||||
}
|
||||
{
|
||||
// without namespace, defaults, no custom descriptors, no initial
|
||||
auto values = node->declare_parameters<int64_t>("", {
|
||||
auto values = node->declare_parameters<int64_t>(
|
||||
"", {
|
||||
{"parameter_without_ns_a", 42},
|
||||
{"parameter_without_ns_b", 256},
|
||||
});
|
||||
@@ -508,7 +624,8 @@ TEST_F(TestNode, declare_parameters_with_no_initial_values) {
|
||||
// with namespace, defaults, custom descriptors, no initial
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor;
|
||||
descriptor.read_only = true;
|
||||
auto values = node->declare_parameters<int64_t>("namespace2", {
|
||||
auto values = node->declare_parameters<int64_t>(
|
||||
"namespace2", {
|
||||
{"parameter_a", {42, descriptor}},
|
||||
{"parameter_b", {256, descriptor}},
|
||||
});
|
||||
@@ -522,7 +639,8 @@ TEST_F(TestNode, declare_parameters_with_no_initial_values) {
|
||||
// without namespace, defaults, custom descriptors, no initial
|
||||
rcl_interfaces::msg::ParameterDescriptor descriptor;
|
||||
descriptor.read_only = true;
|
||||
auto values = node->declare_parameters<int64_t>("", {
|
||||
auto values = node->declare_parameters<int64_t>(
|
||||
"", {
|
||||
{"parameter_without_ns_c", {42, descriptor}},
|
||||
{"parameter_without_ns_d", {256, descriptor}},
|
||||
});
|
||||
@@ -577,6 +695,72 @@ TEST_F(TestNode, declare_parameters_with_no_initial_values) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestNode, declare_parameter_with_cli_overrides) {
|
||||
const std::string parameters_filepath = (
|
||||
test_resources_path / "test_parameters.yaml").string();
|
||||
// test cases with overrides
|
||||
rclcpp::NodeOptions no;
|
||||
no.arguments({
|
||||
"--ros-args",
|
||||
"-p", "parameter_bool:=true",
|
||||
"-p", "parameter_int:=42",
|
||||
"-p", "parameter_double:=0.42",
|
||||
"-p", "parameter_string:=foo",
|
||||
"--params-file", parameters_filepath.c_str(),
|
||||
"-p", "parameter_bool_array:=[false, true]",
|
||||
"-p", "parameter_int_array:=[-21, 42]",
|
||||
"-p", "parameter_double_array:=[-1.0, .42]",
|
||||
"-p", "parameter_string_array:=[foo, bar]"
|
||||
});
|
||||
|
||||
auto node = std::make_shared<rclcpp::Node>("test_declare_parameter_node"_unq, no);
|
||||
{
|
||||
rclcpp::ParameterValue value = node->declare_parameter("parameter_bool");
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_BOOL);
|
||||
EXPECT_EQ(value.get<bool>(), true);
|
||||
}
|
||||
{
|
||||
rclcpp::ParameterValue value = node->declare_parameter("parameter_int");
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_INTEGER);
|
||||
EXPECT_EQ(value.get<int64_t>(), 21); // set to 42 in CLI, overriden by file
|
||||
}
|
||||
{
|
||||
rclcpp::ParameterValue value = node->declare_parameter("parameter_double");
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_DOUBLE);
|
||||
EXPECT_EQ(value.get<double>(), 0.42);
|
||||
}
|
||||
{
|
||||
rclcpp::ParameterValue value = node->declare_parameter("parameter_string");
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_STRING);
|
||||
EXPECT_EQ(value.get<std::string>(), "foo");
|
||||
}
|
||||
{
|
||||
rclcpp::ParameterValue value = node->declare_parameter("parameter_bool_array");
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_BOOL_ARRAY);
|
||||
std::vector<bool> expected_value{false, true};
|
||||
EXPECT_EQ(value.get<std::vector<bool>>(), expected_value);
|
||||
}
|
||||
{
|
||||
rclcpp::ParameterValue value = node->declare_parameter("parameter_int_array");
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_INTEGER_ARRAY);
|
||||
std::vector<int64_t> expected_value{-21, 42};
|
||||
EXPECT_EQ(value.get<std::vector<int64_t>>(), expected_value);
|
||||
}
|
||||
{
|
||||
rclcpp::ParameterValue value = node->declare_parameter("parameter_double_array");
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_DOUBLE_ARRAY);
|
||||
std::vector<double> expected_value{-1.0, 0.42};
|
||||
EXPECT_EQ(value.get<std::vector<double>>(), expected_value);
|
||||
}
|
||||
{
|
||||
rclcpp::ParameterValue value = node->declare_parameter("parameter_string_array");
|
||||
EXPECT_EQ(value.get_type(), rclcpp::PARAMETER_STRING_ARRAY);
|
||||
std::vector<std::string> expected_value{"foo", "bar"};
|
||||
// set to [baz, baz, baz] in file, overriden by CLI
|
||||
EXPECT_EQ(value.get<std::vector<std::string>>(), expected_value);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(TestNode, undeclare_parameter) {
|
||||
auto node = std::make_shared<rclcpp::Node>("test_undeclare_parameter_node"_unq);
|
||||
{
|
||||
@@ -1066,9 +1250,21 @@ TEST_F(TestNode, set_parameter_undeclared_parameters_not_allowed) {
|
||||
}
|
||||
|
||||
TEST_F(TestNode, set_parameter_undeclared_parameters_allowed) {
|
||||
auto node = std::make_shared<rclcpp::Node>(
|
||||
"test_set_parameter_node"_unq,
|
||||
rclcpp::NodeOptions().allow_undeclared_parameters(true));
|
||||
rclcpp::NodeOptions no;
|
||||
no.parameter_overrides(
|
||||
{
|
||||
{"parameter_with_override", 30},
|
||||
});
|
||||
no.allow_undeclared_parameters(true);
|
||||
auto node = std::make_shared<rclcpp::Node>("test_set_parameter_node"_unq, no);
|
||||
{
|
||||
// overrides are ignored when not declaring a parameter
|
||||
auto name = "parameter_with_override";
|
||||
EXPECT_FALSE(node->has_parameter(name));
|
||||
EXPECT_TRUE(node->set_parameter(rclcpp::Parameter(name, 43)).successful);
|
||||
EXPECT_TRUE(node->has_parameter(name));
|
||||
EXPECT_EQ(node->get_parameter(name).get_value<int>(), 43);
|
||||
}
|
||||
{
|
||||
// normal use (declare first) still works with this true
|
||||
auto name = "parameter"_unq;
|
||||
@@ -1103,7 +1299,8 @@ TEST_F(TestNode, set_parameters_undeclared_parameters_not_allowed) {
|
||||
node->declare_parameter(name2, true);
|
||||
node->declare_parameter<std::string>(name3, "blue");
|
||||
|
||||
auto rets = node->set_parameters({
|
||||
auto rets = node->set_parameters(
|
||||
{
|
||||
{name1, 2},
|
||||
{name2, false},
|
||||
{name3, "red"},
|
||||
@@ -1118,7 +1315,8 @@ TEST_F(TestNode, set_parameters_undeclared_parameters_not_allowed) {
|
||||
auto name = "parameter"_unq;
|
||||
node->declare_parameter(name, 1);
|
||||
|
||||
auto rets = node->set_parameters({
|
||||
auto rets = node->set_parameters(
|
||||
{
|
||||
{name, 42},
|
||||
{name, 2},
|
||||
});
|
||||
@@ -1137,7 +1335,8 @@ TEST_F(TestNode, set_parameters_undeclared_parameters_not_allowed) {
|
||||
|
||||
EXPECT_THROW(
|
||||
{
|
||||
node->set_parameters({
|
||||
node->set_parameters(
|
||||
{
|
||||
{name1, 2},
|
||||
{name2, "not declared :("},
|
||||
{name3, 101},
|
||||
@@ -1174,7 +1373,8 @@ TEST_F(TestNode, set_parameters_undeclared_parameters_not_allowed) {
|
||||
};
|
||||
node->set_on_parameters_set_callback(on_set_parameters);
|
||||
|
||||
auto rets = node->set_parameters({
|
||||
auto rets = node->set_parameters(
|
||||
{
|
||||
{name1, 2},
|
||||
{name2, false},
|
||||
{name3, "red"},
|
||||
@@ -1234,7 +1434,8 @@ TEST_F(TestNode, set_parameters_undeclared_parameters_allowed) {
|
||||
EXPECT_TRUE(node->has_parameter(name2));
|
||||
EXPECT_EQ(node->get_parameter(name2).get_value<std::string>(), "test");
|
||||
|
||||
auto rets = node->set_parameters({
|
||||
auto rets = node->set_parameters(
|
||||
{
|
||||
rclcpp::Parameter(name1, 43),
|
||||
rclcpp::Parameter(name2, "other"),
|
||||
});
|
||||
@@ -1250,7 +1451,8 @@ TEST_F(TestNode, set_parameters_undeclared_parameters_allowed) {
|
||||
EXPECT_FALSE(node->has_parameter(name1));
|
||||
EXPECT_FALSE(node->has_parameter(name2));
|
||||
|
||||
auto rets = node->set_parameters({
|
||||
auto rets = node->set_parameters(
|
||||
{
|
||||
rclcpp::Parameter(name1, 42),
|
||||
rclcpp::Parameter(name2, "test"),
|
||||
});
|
||||
@@ -1273,7 +1475,8 @@ TEST_F(TestNode, set_parameters_atomically_undeclared_parameters_not_allowed) {
|
||||
node->declare_parameter(name2, true);
|
||||
node->declare_parameter<std::string>(name3, "blue");
|
||||
|
||||
auto ret = node->set_parameters_atomically({
|
||||
auto ret = node->set_parameters_atomically(
|
||||
{
|
||||
{name1, 2},
|
||||
{name2, false},
|
||||
{name3, "red"},
|
||||
@@ -1288,7 +1491,8 @@ TEST_F(TestNode, set_parameters_atomically_undeclared_parameters_not_allowed) {
|
||||
auto name = "parameter"_unq;
|
||||
node->declare_parameter(name, 1);
|
||||
|
||||
auto ret = node->set_parameters_atomically({
|
||||
auto ret = node->set_parameters_atomically(
|
||||
{
|
||||
{name, 42},
|
||||
{name, 2},
|
||||
});
|
||||
@@ -1307,7 +1511,8 @@ TEST_F(TestNode, set_parameters_atomically_undeclared_parameters_not_allowed) {
|
||||
|
||||
EXPECT_THROW(
|
||||
{
|
||||
node->set_parameters_atomically({
|
||||
node->set_parameters_atomically(
|
||||
{
|
||||
{name1, 2},
|
||||
{name2, "not declared :("},
|
||||
{name3, 101},
|
||||
@@ -1345,7 +1550,8 @@ TEST_F(TestNode, set_parameters_atomically_undeclared_parameters_not_allowed) {
|
||||
};
|
||||
node->set_on_parameters_set_callback(on_set_parameters);
|
||||
|
||||
auto ret = node->set_parameters_atomically({
|
||||
auto ret = node->set_parameters_atomically(
|
||||
{
|
||||
{name1, 2},
|
||||
{name2, false}, // should fail to be set, failing the whole operation
|
||||
{name3, "red"},
|
||||
@@ -1402,7 +1608,8 @@ TEST_F(TestNode, set_parameters_atomically_undeclared_parameters_allowed) {
|
||||
EXPECT_TRUE(node->has_parameter(name2));
|
||||
EXPECT_EQ(node->get_parameter(name2).get_value<std::string>(), "test");
|
||||
|
||||
auto ret = node->set_parameters_atomically({
|
||||
auto ret = node->set_parameters_atomically(
|
||||
{
|
||||
rclcpp::Parameter(name1, 43),
|
||||
rclcpp::Parameter(name2, "other"),
|
||||
});
|
||||
@@ -1418,7 +1625,8 @@ TEST_F(TestNode, set_parameters_atomically_undeclared_parameters_allowed) {
|
||||
EXPECT_FALSE(node->has_parameter(name1));
|
||||
EXPECT_FALSE(node->has_parameter(name2));
|
||||
|
||||
auto ret = node->set_parameters_atomically({
|
||||
auto ret = node->set_parameters_atomically(
|
||||
{
|
||||
rclcpp::Parameter(name1, 42),
|
||||
rclcpp::Parameter(name2, "test"),
|
||||
});
|
||||
@@ -1453,7 +1661,8 @@ TEST_F(TestNode, set_parameters_atomically_undeclared_parameters_allowed) {
|
||||
};
|
||||
node->set_on_parameters_set_callback(on_set_parameters);
|
||||
|
||||
auto ret = node->set_parameters_atomically({
|
||||
auto ret = node->set_parameters_atomically(
|
||||
{
|
||||
rclcpp::Parameter(name1, 43),
|
||||
rclcpp::Parameter(name2, true), // this would cause implicit declaration
|
||||
rclcpp::Parameter(name3, "other"), // this set should fail, and fail the whole operation
|
||||
@@ -1833,7 +2042,8 @@ TEST_F(TestNode, describe_parameter_undeclared_parameters_not_allowed) {
|
||||
auto name = "parameter"_unq;
|
||||
|
||||
{
|
||||
EXPECT_THROW({
|
||||
EXPECT_THROW(
|
||||
{
|
||||
node->describe_parameter(name);
|
||||
}, rclcpp::exceptions::ParameterNotDeclaredException);
|
||||
}
|
||||
@@ -1913,7 +2123,8 @@ TEST_F(TestNode, describe_parameters_undeclared_parameters_not_allowed) {
|
||||
auto name = "parameter"_unq;
|
||||
|
||||
{
|
||||
EXPECT_THROW({
|
||||
EXPECT_THROW(
|
||||
{
|
||||
node->describe_parameters({name});
|
||||
}, rclcpp::exceptions::ParameterNotDeclaredException);
|
||||
}
|
||||
@@ -1926,7 +2137,8 @@ TEST_F(TestNode, describe_parameters_undeclared_parameters_not_allowed) {
|
||||
node->declare_parameter(name1, 42);
|
||||
|
||||
{
|
||||
EXPECT_THROW({
|
||||
EXPECT_THROW(
|
||||
{
|
||||
node->describe_parameters({name1, name2});
|
||||
}, rclcpp::exceptions::ParameterNotDeclaredException);
|
||||
}
|
||||
@@ -2049,7 +2261,8 @@ TEST_F(TestNode, get_parameter_types_undeclared_parameters_not_allowed) {
|
||||
auto name = "parameter"_unq;
|
||||
|
||||
{
|
||||
EXPECT_THROW({
|
||||
EXPECT_THROW(
|
||||
{
|
||||
node->get_parameter_types({name});
|
||||
}, rclcpp::exceptions::ParameterNotDeclaredException);
|
||||
}
|
||||
@@ -2125,3 +2338,187 @@ TEST_F(TestNode, get_parameter_types_undeclared_parameters_allowed) {
|
||||
EXPECT_EQ(results[2], rcl_interfaces::msg::ParameterType::PARAMETER_NOT_SET);
|
||||
}
|
||||
}
|
||||
|
||||
// test that it is possible to call get_parameter within the set_callback
|
||||
TEST_F(TestNode, set_on_parameters_set_callback_get_parameter) {
|
||||
auto node = std::make_shared<rclcpp::Node>("test_set_callback_get_parameter_node"_unq);
|
||||
|
||||
int64_t intval = node->declare_parameter("intparam", 42);
|
||||
EXPECT_EQ(intval, 42);
|
||||
double floatval = node->declare_parameter("floatparam", 5.4);
|
||||
EXPECT_EQ(floatval, 5.4);
|
||||
|
||||
double floatout;
|
||||
RCLCPP_SCOPE_EXIT({node->set_on_parameters_set_callback(nullptr);}); // always reset
|
||||
auto on_set_parameters =
|
||||
[&node, &floatout](const std::vector<rclcpp::Parameter> & parameters) {
|
||||
rcl_interfaces::msg::SetParametersResult result;
|
||||
result.successful = true;
|
||||
if (parameters.size() != 1) {
|
||||
result.successful = false;
|
||||
}
|
||||
|
||||
if (parameters[0].get_value<int>() != 40) {
|
||||
result.successful = false;
|
||||
}
|
||||
|
||||
rclcpp::Parameter floatparam = node->get_parameter("floatparam");
|
||||
if (floatparam.get_value<double>() != 5.4) {
|
||||
result.successful = false;
|
||||
}
|
||||
floatout = floatparam.get_value<double>();
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
EXPECT_EQ(node->set_on_parameters_set_callback(on_set_parameters), nullptr);
|
||||
ASSERT_NO_THROW(node->set_parameter({"intparam", 40}));
|
||||
ASSERT_EQ(floatout, 5.4);
|
||||
}
|
||||
|
||||
// test that calling set_parameter inside of a set_callback throws an exception
|
||||
TEST_F(TestNode, set_on_parameters_set_callback_set_parameter) {
|
||||
auto node = std::make_shared<rclcpp::Node>("test_set_callback_set_parameter_node"_unq);
|
||||
|
||||
int64_t intval = node->declare_parameter("intparam", 42);
|
||||
EXPECT_EQ(intval, 42);
|
||||
double floatval = node->declare_parameter("floatparam", 5.4);
|
||||
EXPECT_EQ(floatval, 5.4);
|
||||
|
||||
RCLCPP_SCOPE_EXIT({node->set_on_parameters_set_callback(nullptr);}); // always reset
|
||||
auto on_set_parameters =
|
||||
[&node](const std::vector<rclcpp::Parameter> & parameters) {
|
||||
rcl_interfaces::msg::SetParametersResult result;
|
||||
result.successful = true;
|
||||
if (parameters.size() != 1) {
|
||||
result.successful = false;
|
||||
}
|
||||
|
||||
if (parameters[0].get_value<int>() != 40) {
|
||||
result.successful = false;
|
||||
}
|
||||
|
||||
// This should throw an exception
|
||||
node->set_parameter({"floatparam", 5.6});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
EXPECT_EQ(node->set_on_parameters_set_callback(on_set_parameters), nullptr);
|
||||
EXPECT_THROW(
|
||||
{
|
||||
node->set_parameter(rclcpp::Parameter("intparam", 40));
|
||||
}, rclcpp::exceptions::ParameterModifiedInCallbackException);
|
||||
}
|
||||
|
||||
// test that calling declare_parameter inside of a set_callback throws an exception
|
||||
TEST_F(TestNode, set_on_parameters_set_callback_declare_parameter) {
|
||||
auto node = std::make_shared<rclcpp::Node>("test_set_callback_declare_parameter_node"_unq);
|
||||
|
||||
int64_t intval = node->declare_parameter("intparam", 42);
|
||||
EXPECT_EQ(intval, 42);
|
||||
double floatval = node->declare_parameter("floatparam", 5.4);
|
||||
EXPECT_EQ(floatval, 5.4);
|
||||
|
||||
RCLCPP_SCOPE_EXIT({node->set_on_parameters_set_callback(nullptr);}); // always reset
|
||||
auto on_set_parameters =
|
||||
[&node](const std::vector<rclcpp::Parameter> & parameters) {
|
||||
rcl_interfaces::msg::SetParametersResult result;
|
||||
result.successful = true;
|
||||
if (parameters.size() != 1) {
|
||||
result.successful = false;
|
||||
}
|
||||
|
||||
if (parameters[0].get_value<int>() != 40) {
|
||||
result.successful = false;
|
||||
}
|
||||
|
||||
// This should throw an exception
|
||||
node->declare_parameter("floatparam2", 5.6);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
EXPECT_EQ(node->set_on_parameters_set_callback(on_set_parameters), nullptr);
|
||||
EXPECT_THROW(
|
||||
{
|
||||
node->set_parameter(rclcpp::Parameter("intparam", 40));
|
||||
}, rclcpp::exceptions::ParameterModifiedInCallbackException);
|
||||
}
|
||||
|
||||
// test that calling undeclare_parameter inside a set_callback throws an exception
|
||||
TEST_F(TestNode, set_on_parameters_set_callback_undeclare_parameter) {
|
||||
auto node = std::make_shared<rclcpp::Node>("test_set_callback_undeclare_parameter_node"_unq);
|
||||
|
||||
int64_t intval = node->declare_parameter("intparam", 42);
|
||||
EXPECT_EQ(intval, 42);
|
||||
double floatval = node->declare_parameter("floatparam", 5.4);
|
||||
EXPECT_EQ(floatval, 5.4);
|
||||
|
||||
RCLCPP_SCOPE_EXIT({node->set_on_parameters_set_callback(nullptr);}); // always reset
|
||||
auto on_set_parameters =
|
||||
[&node](const std::vector<rclcpp::Parameter> & parameters) {
|
||||
rcl_interfaces::msg::SetParametersResult result;
|
||||
result.successful = true;
|
||||
if (parameters.size() != 1) {
|
||||
result.successful = false;
|
||||
}
|
||||
|
||||
if (parameters[0].get_value<int>() != 40) {
|
||||
result.successful = false;
|
||||
}
|
||||
|
||||
// This should throw an exception
|
||||
node->undeclare_parameter("floatparam");
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
EXPECT_EQ(node->set_on_parameters_set_callback(on_set_parameters), nullptr);
|
||||
EXPECT_THROW(
|
||||
{
|
||||
node->set_parameter(rclcpp::Parameter("intparam", 40));
|
||||
}, rclcpp::exceptions::ParameterModifiedInCallbackException);
|
||||
}
|
||||
|
||||
// test that calling set_on_parameters_set_callback from a set_callback throws an exception
|
||||
TEST_F(TestNode, set_on_parameters_set_callback_set_on_parameters_set_callback) {
|
||||
auto node = std::make_shared<rclcpp::Node>("test_set_callback_set_callback_node"_unq);
|
||||
|
||||
int64_t intval = node->declare_parameter("intparam", 42);
|
||||
EXPECT_EQ(intval, 42);
|
||||
double floatval = node->declare_parameter("floatparam", 5.4);
|
||||
EXPECT_EQ(floatval, 5.4);
|
||||
|
||||
RCLCPP_SCOPE_EXIT({node->set_on_parameters_set_callback(nullptr);}); // always reset
|
||||
auto on_set_parameters =
|
||||
[&node](const std::vector<rclcpp::Parameter> & parameters) {
|
||||
rcl_interfaces::msg::SetParametersResult result;
|
||||
result.successful = true;
|
||||
if (parameters.size() != 1) {
|
||||
result.successful = false;
|
||||
}
|
||||
|
||||
if (parameters[0].get_value<int>() != 40) {
|
||||
result.successful = false;
|
||||
}
|
||||
|
||||
auto bad_parameters =
|
||||
[](const std::vector<rclcpp::Parameter> & parameters) {
|
||||
(void)parameters;
|
||||
rcl_interfaces::msg::SetParametersResult result;
|
||||
return result;
|
||||
};
|
||||
|
||||
// This should throw an exception
|
||||
node->set_on_parameters_set_callback(bad_parameters);
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
EXPECT_EQ(node->set_on_parameters_set_callback(on_set_parameters), nullptr);
|
||||
EXPECT_THROW(
|
||||
{
|
||||
node->set_parameter(rclcpp::Parameter("intparam", 40));
|
||||
}, rclcpp::exceptions::ParameterModifiedInCallbackException);
|
||||
}
|
||||
|
||||
@@ -28,14 +28,15 @@ class TestNodeWithGlobalArgs : public ::testing::Test
|
||||
protected:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
const char * const args[] = {"proc", "__node:=global_node_name"};
|
||||
rclcpp::init(2, args);
|
||||
const char * const args[] = {"proc", "--ros-args", "-r", "__node:=global_node_name"};
|
||||
const int argc = sizeof(args) / sizeof(const char *);
|
||||
rclcpp::init(argc, args);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(TestNodeWithGlobalArgs, local_arguments_before_global) {
|
||||
auto options = rclcpp::NodeOptions()
|
||||
.arguments({"__node:=local_arguments_test"});
|
||||
.arguments({"--ros-args", "-r", "__node:=local_arguments_test"});
|
||||
|
||||
auto node = rclcpp::Node::make_shared("orig_name", options);
|
||||
EXPECT_STREQ("local_arguments_test", node->get_name());
|
||||
|
||||
100
rclcpp/test/test_node_options.cpp
Normal file
100
rclcpp/test/test_node_options.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
// Copyright 2019 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "rcl/allocator.h"
|
||||
#include "rcl/arguments.h"
|
||||
#include "rcl/remap.h"
|
||||
|
||||
#include "rclcpp/node_options.hpp"
|
||||
|
||||
|
||||
TEST(TestNodeOptions, ros_args_only) {
|
||||
rcl_allocator_t allocator = rcl_get_default_allocator();
|
||||
auto options = rclcpp::NodeOptions(allocator)
|
||||
.arguments({"--ros-args", "-r", "__node:=some_node", "-r", "__ns:=/some_ns"});
|
||||
|
||||
const rcl_node_options_t * rcl_options = options.get_rcl_node_options();
|
||||
ASSERT_TRUE(rcl_options != nullptr);
|
||||
ASSERT_EQ(0, rcl_arguments_get_count_unparsed(&rcl_options->arguments));
|
||||
ASSERT_EQ(0, rcl_arguments_get_count_unparsed_ros(&rcl_options->arguments));
|
||||
|
||||
char * node_name = nullptr;
|
||||
EXPECT_EQ(RCL_RET_OK, rcl_remap_node_name(
|
||||
&rcl_options->arguments, nullptr, "my_node", allocator, &node_name));
|
||||
ASSERT_TRUE(node_name != nullptr);
|
||||
EXPECT_STREQ("some_node", node_name);
|
||||
allocator.deallocate(node_name, allocator.state);
|
||||
|
||||
char * namespace_name = nullptr;
|
||||
EXPECT_EQ(RCL_RET_OK, rcl_remap_node_namespace(
|
||||
&rcl_options->arguments, nullptr, "my_ns", allocator, &namespace_name));
|
||||
ASSERT_TRUE(namespace_name != nullptr);
|
||||
EXPECT_STREQ("/some_ns", namespace_name);
|
||||
allocator.deallocate(namespace_name, allocator.state);
|
||||
}
|
||||
|
||||
TEST(TestNodeOptions, ros_args_and_non_ros_args) {
|
||||
rcl_allocator_t allocator = rcl_get_default_allocator();
|
||||
auto options = rclcpp::NodeOptions(allocator).arguments({
|
||||
"--non-ros-flag", "--ros-args", "-r", "__node:=some_node",
|
||||
"-r", "__ns:=/some_ns", "--", "non-ros-arg"});
|
||||
|
||||
const rcl_node_options_t * rcl_options = options.get_rcl_node_options();
|
||||
ASSERT_TRUE(rcl_options != nullptr);
|
||||
ASSERT_EQ(0, rcl_arguments_get_count_unparsed_ros(&rcl_options->arguments));
|
||||
ASSERT_EQ(2, rcl_arguments_get_count_unparsed(&rcl_options->arguments));
|
||||
|
||||
char * node_name = nullptr;
|
||||
EXPECT_EQ(RCL_RET_OK, rcl_remap_node_name(
|
||||
&rcl_options->arguments, nullptr, "my_node", allocator, &node_name));
|
||||
ASSERT_TRUE(node_name != nullptr);
|
||||
EXPECT_STREQ("some_node", node_name);
|
||||
allocator.deallocate(node_name, allocator.state);
|
||||
|
||||
char * namespace_name = nullptr;
|
||||
EXPECT_EQ(RCL_RET_OK, rcl_remap_node_namespace(
|
||||
&rcl_options->arguments, nullptr, "my_ns", allocator, &namespace_name));
|
||||
ASSERT_TRUE(namespace_name != nullptr);
|
||||
EXPECT_STREQ("/some_ns", namespace_name);
|
||||
allocator.deallocate(namespace_name, allocator.state);
|
||||
|
||||
int * output_indices = nullptr;
|
||||
EXPECT_EQ(RCL_RET_OK, rcl_arguments_get_unparsed(
|
||||
&rcl_options->arguments, allocator, &output_indices));
|
||||
ASSERT_TRUE(output_indices != nullptr);
|
||||
const std::vector<std::string> & args = options.arguments();
|
||||
EXPECT_EQ("--non-ros-flag", args[output_indices[0]]);
|
||||
EXPECT_EQ("non-ros-arg", args[output_indices[1]]);
|
||||
allocator.deallocate(output_indices, allocator.state);
|
||||
}
|
||||
|
||||
TEST(TestNodeOptions, bad_ros_args) {
|
||||
rcl_allocator_t allocator = rcl_get_default_allocator();
|
||||
auto options = rclcpp::NodeOptions(allocator)
|
||||
.arguments({"--ros-args", "-r", "foo:="});
|
||||
|
||||
EXPECT_THROW(
|
||||
options.get_rcl_node_options(),
|
||||
rclcpp::exceptions::RCLInvalidROSArgsError);
|
||||
|
||||
options.arguments({"--ros-args", "-r", "foo:=bar", "not-a-ros-arg"});
|
||||
EXPECT_THROW(
|
||||
options.get_rcl_node_options(),
|
||||
rclcpp::exceptions::UnknownROSArgsError);
|
||||
}
|
||||
@@ -53,7 +53,8 @@ TEST(TestParameter, not_set_variant) {
|
||||
EXPECT_EQ(rcl_interfaces::msg::ParameterType::PARAMETER_NOT_SET, not_set_param.value.type);
|
||||
|
||||
// From parameter message
|
||||
EXPECT_EQ(rclcpp::ParameterType::PARAMETER_NOT_SET,
|
||||
EXPECT_EQ(
|
||||
rclcpp::ParameterType::PARAMETER_NOT_SET,
|
||||
rclcpp::Parameter::from_parameter_msg(not_set_param).get_type());
|
||||
}
|
||||
|
||||
@@ -65,7 +66,8 @@ TEST(TestParameter, bool_variant) {
|
||||
EXPECT_EQ("bool", bool_variant_true.get_type_name());
|
||||
EXPECT_TRUE(bool_variant_true.get_value<rclcpp::ParameterType::PARAMETER_BOOL>());
|
||||
EXPECT_TRUE(bool_variant_true.get_value_message().bool_value);
|
||||
EXPECT_EQ(rcl_interfaces::msg::ParameterType::PARAMETER_BOOL,
|
||||
EXPECT_EQ(
|
||||
rcl_interfaces::msg::ParameterType::PARAMETER_BOOL,
|
||||
bool_variant_true.get_value_message().type);
|
||||
EXPECT_TRUE(bool_variant_true.as_bool());
|
||||
|
||||
@@ -83,7 +85,8 @@ TEST(TestParameter, bool_variant) {
|
||||
rclcpp::Parameter bool_variant_false("bool_param", false);
|
||||
EXPECT_FALSE(bool_variant_false.get_value<rclcpp::ParameterType::PARAMETER_BOOL>());
|
||||
EXPECT_FALSE(bool_variant_false.get_value_message().bool_value);
|
||||
EXPECT_EQ(rcl_interfaces::msg::ParameterType::PARAMETER_BOOL,
|
||||
EXPECT_EQ(
|
||||
rcl_interfaces::msg::ParameterType::PARAMETER_BOOL,
|
||||
bool_variant_false.get_value_message().type);
|
||||
|
||||
rcl_interfaces::msg::Parameter bool_param = bool_variant_true.to_parameter_msg();
|
||||
@@ -99,7 +102,8 @@ TEST(TestParameter, bool_variant) {
|
||||
EXPECT_EQ("bool", from_msg_true.get_type_name());
|
||||
EXPECT_TRUE(from_msg_true.get_value<rclcpp::ParameterType::PARAMETER_BOOL>());
|
||||
EXPECT_TRUE(from_msg_true.get_value_message().bool_value);
|
||||
EXPECT_EQ(rcl_interfaces::msg::ParameterType::PARAMETER_BOOL,
|
||||
EXPECT_EQ(
|
||||
rcl_interfaces::msg::ParameterType::PARAMETER_BOOL,
|
||||
bool_variant_false.get_value_message().type);
|
||||
|
||||
bool_param.value.bool_value = false;
|
||||
@@ -107,7 +111,8 @@ TEST(TestParameter, bool_variant) {
|
||||
rclcpp::Parameter::from_parameter_msg(bool_param);
|
||||
EXPECT_FALSE(from_msg_false.get_value<rclcpp::ParameterType::PARAMETER_BOOL>());
|
||||
EXPECT_FALSE(from_msg_false.get_value_message().bool_value);
|
||||
EXPECT_EQ(rcl_interfaces::msg::ParameterType::PARAMETER_BOOL,
|
||||
EXPECT_EQ(
|
||||
rcl_interfaces::msg::ParameterType::PARAMETER_BOOL,
|
||||
bool_variant_false.get_value_message().type);
|
||||
}
|
||||
|
||||
@@ -119,10 +124,12 @@ TEST(TestParameter, integer_variant) {
|
||||
EXPECT_EQ("integer_param", integer_variant.get_name());
|
||||
EXPECT_EQ(rclcpp::ParameterType::PARAMETER_INTEGER, integer_variant.get_type());
|
||||
EXPECT_EQ("integer", integer_variant.get_type_name());
|
||||
EXPECT_EQ(TEST_VALUE,
|
||||
EXPECT_EQ(
|
||||
TEST_VALUE,
|
||||
integer_variant.get_value<rclcpp::ParameterType::PARAMETER_INTEGER>());
|
||||
EXPECT_EQ(TEST_VALUE, integer_variant.get_value_message().integer_value);
|
||||
EXPECT_EQ(rcl_interfaces::msg::ParameterType::PARAMETER_INTEGER,
|
||||
EXPECT_EQ(
|
||||
rcl_interfaces::msg::ParameterType::PARAMETER_INTEGER,
|
||||
integer_variant.get_value_message().type);
|
||||
EXPECT_EQ(TEST_VALUE, integer_variant.as_int());
|
||||
|
||||
@@ -148,10 +155,12 @@ TEST(TestParameter, integer_variant) {
|
||||
EXPECT_EQ("integer_param", from_msg.get_name());
|
||||
EXPECT_EQ(rclcpp::ParameterType::PARAMETER_INTEGER, from_msg.get_type());
|
||||
EXPECT_EQ("integer", from_msg.get_type_name());
|
||||
EXPECT_EQ(TEST_VALUE,
|
||||
EXPECT_EQ(
|
||||
TEST_VALUE,
|
||||
from_msg.get_value<rclcpp::ParameterType::PARAMETER_INTEGER>());
|
||||
EXPECT_EQ(TEST_VALUE, from_msg.get_value_message().integer_value);
|
||||
EXPECT_EQ(rcl_interfaces::msg::ParameterType::PARAMETER_INTEGER,
|
||||
EXPECT_EQ(
|
||||
rcl_interfaces::msg::ParameterType::PARAMETER_INTEGER,
|
||||
from_msg.get_value_message().type);
|
||||
}
|
||||
|
||||
@@ -163,10 +172,12 @@ TEST(TestParameter, long_integer_variant) {
|
||||
EXPECT_EQ("long_integer_param", long_variant.get_name());
|
||||
EXPECT_EQ(rclcpp::ParameterType::PARAMETER_INTEGER, long_variant.get_type());
|
||||
EXPECT_EQ("integer", long_variant.get_type_name());
|
||||
EXPECT_EQ(TEST_VALUE,
|
||||
EXPECT_EQ(
|
||||
TEST_VALUE,
|
||||
long_variant.get_value<rclcpp::ParameterType::PARAMETER_INTEGER>());
|
||||
EXPECT_EQ(TEST_VALUE, long_variant.get_value_message().integer_value);
|
||||
EXPECT_EQ(rcl_interfaces::msg::ParameterType::PARAMETER_INTEGER,
|
||||
EXPECT_EQ(
|
||||
rcl_interfaces::msg::ParameterType::PARAMETER_INTEGER,
|
||||
long_variant.get_value_message().type);
|
||||
EXPECT_EQ(TEST_VALUE, long_variant.as_int());
|
||||
|
||||
@@ -192,10 +203,12 @@ TEST(TestParameter, long_integer_variant) {
|
||||
EXPECT_EQ("long_integer_param", from_msg.get_name());
|
||||
EXPECT_EQ(rclcpp::ParameterType::PARAMETER_INTEGER, from_msg.get_type());
|
||||
EXPECT_EQ("integer", from_msg.get_type_name());
|
||||
EXPECT_EQ(TEST_VALUE,
|
||||
EXPECT_EQ(
|
||||
TEST_VALUE,
|
||||
from_msg.get_value<rclcpp::ParameterType::PARAMETER_INTEGER>());
|
||||
EXPECT_EQ(TEST_VALUE, from_msg.get_value_message().integer_value);
|
||||
EXPECT_EQ(rcl_interfaces::msg::ParameterType::PARAMETER_INTEGER,
|
||||
EXPECT_EQ(
|
||||
rcl_interfaces::msg::ParameterType::PARAMETER_INTEGER,
|
||||
from_msg.get_value_message().type);
|
||||
}
|
||||
|
||||
@@ -207,10 +220,12 @@ TEST(TestParameter, float_variant) {
|
||||
EXPECT_EQ("float_param", float_variant.get_name());
|
||||
EXPECT_EQ(rclcpp::ParameterType::PARAMETER_DOUBLE, float_variant.get_type());
|
||||
EXPECT_EQ("double", float_variant.get_type_name());
|
||||
EXPECT_EQ(TEST_VALUE,
|
||||
EXPECT_EQ(
|
||||
TEST_VALUE,
|
||||
float_variant.get_value<rclcpp::ParameterType::PARAMETER_DOUBLE>());
|
||||
EXPECT_EQ(TEST_VALUE, float_variant.get_value_message().double_value);
|
||||
EXPECT_EQ(rcl_interfaces::msg::ParameterType::PARAMETER_DOUBLE,
|
||||
EXPECT_EQ(
|
||||
rcl_interfaces::msg::ParameterType::PARAMETER_DOUBLE,
|
||||
float_variant.get_value_message().type);
|
||||
EXPECT_EQ(TEST_VALUE, float_variant.as_double());
|
||||
|
||||
@@ -236,10 +251,12 @@ TEST(TestParameter, float_variant) {
|
||||
EXPECT_EQ("float_param", from_msg.get_name());
|
||||
EXPECT_EQ(rclcpp::ParameterType::PARAMETER_DOUBLE, from_msg.get_type());
|
||||
EXPECT_EQ("double", from_msg.get_type_name());
|
||||
EXPECT_EQ(TEST_VALUE,
|
||||
EXPECT_EQ(
|
||||
TEST_VALUE,
|
||||
from_msg.get_value<rclcpp::ParameterType::PARAMETER_DOUBLE>());
|
||||
EXPECT_EQ(TEST_VALUE, from_msg.get_value_message().double_value);
|
||||
EXPECT_EQ(rcl_interfaces::msg::ParameterType::PARAMETER_DOUBLE,
|
||||
EXPECT_EQ(
|
||||
rcl_interfaces::msg::ParameterType::PARAMETER_DOUBLE,
|
||||
from_msg.get_value_message().type);
|
||||
}
|
||||
|
||||
@@ -251,10 +268,12 @@ TEST(TestParameter, double_variant) {
|
||||
EXPECT_EQ("double_param", double_variant.get_name());
|
||||
EXPECT_EQ(rclcpp::ParameterType::PARAMETER_DOUBLE, double_variant.get_type());
|
||||
EXPECT_EQ("double", double_variant.get_type_name());
|
||||
EXPECT_EQ(TEST_VALUE,
|
||||
EXPECT_EQ(
|
||||
TEST_VALUE,
|
||||
double_variant.get_value<rclcpp::ParameterType::PARAMETER_DOUBLE>());
|
||||
EXPECT_EQ(TEST_VALUE, double_variant.get_value_message().double_value);
|
||||
EXPECT_EQ(rcl_interfaces::msg::ParameterType::PARAMETER_DOUBLE,
|
||||
EXPECT_EQ(
|
||||
rcl_interfaces::msg::ParameterType::PARAMETER_DOUBLE,
|
||||
double_variant.get_value_message().type);
|
||||
EXPECT_EQ(TEST_VALUE, double_variant.as_double());
|
||||
|
||||
@@ -280,10 +299,12 @@ TEST(TestParameter, double_variant) {
|
||||
EXPECT_EQ("double_param", from_msg.get_name());
|
||||
EXPECT_EQ(rclcpp::ParameterType::PARAMETER_DOUBLE, from_msg.get_type());
|
||||
EXPECT_EQ("double", from_msg.get_type_name());
|
||||
EXPECT_EQ(TEST_VALUE,
|
||||
EXPECT_EQ(
|
||||
TEST_VALUE,
|
||||
from_msg.get_value<rclcpp::ParameterType::PARAMETER_DOUBLE>());
|
||||
EXPECT_EQ(TEST_VALUE, from_msg.get_value_message().double_value);
|
||||
EXPECT_EQ(rcl_interfaces::msg::ParameterType::PARAMETER_DOUBLE,
|
||||
EXPECT_EQ(
|
||||
rcl_interfaces::msg::ParameterType::PARAMETER_DOUBLE,
|
||||
from_msg.get_value_message().type);
|
||||
}
|
||||
|
||||
@@ -295,10 +316,12 @@ TEST(TestParameter, string_variant) {
|
||||
EXPECT_EQ("string_param", string_variant.get_name());
|
||||
EXPECT_EQ(rclcpp::ParameterType::PARAMETER_STRING, string_variant.get_type());
|
||||
EXPECT_EQ("string", string_variant.get_type_name());
|
||||
EXPECT_EQ(TEST_VALUE,
|
||||
EXPECT_EQ(
|
||||
TEST_VALUE,
|
||||
string_variant.get_value<rclcpp::ParameterType::PARAMETER_STRING>());
|
||||
EXPECT_EQ(TEST_VALUE, string_variant.get_value_message().string_value);
|
||||
EXPECT_EQ(rcl_interfaces::msg::ParameterType::PARAMETER_STRING,
|
||||
EXPECT_EQ(
|
||||
rcl_interfaces::msg::ParameterType::PARAMETER_STRING,
|
||||
string_variant.get_value_message().type);
|
||||
EXPECT_EQ(TEST_VALUE, string_variant.as_string());
|
||||
|
||||
@@ -326,7 +349,8 @@ TEST(TestParameter, string_variant) {
|
||||
EXPECT_EQ("string", from_msg.get_type_name());
|
||||
EXPECT_EQ(TEST_VALUE, from_msg.get_value<rclcpp::ParameterType::PARAMETER_STRING>());
|
||||
EXPECT_EQ(TEST_VALUE, from_msg.get_value_message().string_value);
|
||||
EXPECT_EQ(rcl_interfaces::msg::ParameterType::PARAMETER_STRING,
|
||||
EXPECT_EQ(
|
||||
rcl_interfaces::msg::ParameterType::PARAMETER_STRING,
|
||||
from_msg.get_value_message().type);
|
||||
}
|
||||
|
||||
@@ -338,10 +362,12 @@ TEST(TestParameter, byte_array_variant) {
|
||||
EXPECT_EQ("byte_array_param", byte_array_variant.get_name());
|
||||
EXPECT_EQ(rclcpp::ParameterType::PARAMETER_BYTE_ARRAY, byte_array_variant.get_type());
|
||||
EXPECT_EQ("byte_array", byte_array_variant.get_type_name());
|
||||
EXPECT_EQ(TEST_VALUE,
|
||||
EXPECT_EQ(
|
||||
TEST_VALUE,
|
||||
byte_array_variant.get_value<rclcpp::ParameterType::PARAMETER_BYTE_ARRAY>());
|
||||
EXPECT_EQ(TEST_VALUE, byte_array_variant.get_value_message().byte_array_value);
|
||||
EXPECT_EQ(rcl_interfaces::msg::ParameterType::PARAMETER_BYTE_ARRAY,
|
||||
EXPECT_EQ(
|
||||
rcl_interfaces::msg::ParameterType::PARAMETER_BYTE_ARRAY,
|
||||
byte_array_variant.get_value_message().type);
|
||||
EXPECT_EQ(TEST_VALUE, byte_array_variant.as_byte_array());
|
||||
|
||||
@@ -367,10 +393,12 @@ TEST(TestParameter, byte_array_variant) {
|
||||
EXPECT_EQ("byte_array_param", from_msg.get_name());
|
||||
EXPECT_EQ(rclcpp::ParameterType::PARAMETER_BYTE_ARRAY, from_msg.get_type());
|
||||
EXPECT_EQ("byte_array", from_msg.get_type_name());
|
||||
EXPECT_EQ(TEST_VALUE,
|
||||
EXPECT_EQ(
|
||||
TEST_VALUE,
|
||||
from_msg.get_value<rclcpp::ParameterType::PARAMETER_BYTE_ARRAY>());
|
||||
EXPECT_EQ(TEST_VALUE, from_msg.get_value_message().byte_array_value);
|
||||
EXPECT_EQ(rcl_interfaces::msg::ParameterType::PARAMETER_BYTE_ARRAY,
|
||||
EXPECT_EQ(
|
||||
rcl_interfaces::msg::ParameterType::PARAMETER_BYTE_ARRAY,
|
||||
from_msg.get_value_message().type);
|
||||
}
|
||||
|
||||
@@ -382,10 +410,12 @@ TEST(TestParameter, bool_array_variant) {
|
||||
EXPECT_EQ("bool_array_param", bool_array_variant.get_name());
|
||||
EXPECT_EQ(rclcpp::ParameterType::PARAMETER_BOOL_ARRAY, bool_array_variant.get_type());
|
||||
EXPECT_EQ("bool_array", bool_array_variant.get_type_name());
|
||||
EXPECT_EQ(TEST_VALUE,
|
||||
EXPECT_EQ(
|
||||
TEST_VALUE,
|
||||
bool_array_variant.get_value<rclcpp::ParameterType::PARAMETER_BOOL_ARRAY>());
|
||||
EXPECT_EQ(TEST_VALUE, bool_array_variant.get_value_message().bool_array_value);
|
||||
EXPECT_EQ(rcl_interfaces::msg::ParameterType::PARAMETER_BOOL_ARRAY,
|
||||
EXPECT_EQ(
|
||||
rcl_interfaces::msg::ParameterType::PARAMETER_BOOL_ARRAY,
|
||||
bool_array_variant.get_value_message().type);
|
||||
EXPECT_EQ(TEST_VALUE, bool_array_variant.as_bool_array());
|
||||
|
||||
@@ -411,10 +441,12 @@ TEST(TestParameter, bool_array_variant) {
|
||||
EXPECT_EQ("bool_array_param", from_msg.get_name());
|
||||
EXPECT_EQ(rclcpp::ParameterType::PARAMETER_BOOL_ARRAY, from_msg.get_type());
|
||||
EXPECT_EQ("bool_array", from_msg.get_type_name());
|
||||
EXPECT_EQ(TEST_VALUE,
|
||||
EXPECT_EQ(
|
||||
TEST_VALUE,
|
||||
from_msg.get_value<rclcpp::ParameterType::PARAMETER_BOOL_ARRAY>());
|
||||
EXPECT_EQ(TEST_VALUE, from_msg.get_value_message().bool_array_value);
|
||||
EXPECT_EQ(rcl_interfaces::msg::ParameterType::PARAMETER_BOOL_ARRAY,
|
||||
EXPECT_EQ(
|
||||
rcl_interfaces::msg::ParameterType::PARAMETER_BOOL_ARRAY,
|
||||
from_msg.get_value_message().type);
|
||||
}
|
||||
|
||||
@@ -426,10 +458,12 @@ TEST(TestParameter, integer_array_variant) {
|
||||
rclcpp::Parameter integer_array_variant("integer_array_param", TEST_VALUE);
|
||||
|
||||
EXPECT_EQ("integer_array_param", integer_array_variant.get_name());
|
||||
EXPECT_EQ(rclcpp::ParameterType::PARAMETER_INTEGER_ARRAY,
|
||||
EXPECT_EQ(
|
||||
rclcpp::ParameterType::PARAMETER_INTEGER_ARRAY,
|
||||
integer_array_variant.get_type());
|
||||
EXPECT_EQ("integer_array", integer_array_variant.get_type_name());
|
||||
EXPECT_EQ(rcl_interfaces::msg::ParameterType::PARAMETER_INTEGER_ARRAY,
|
||||
EXPECT_EQ(
|
||||
rcl_interfaces::msg::ParameterType::PARAMETER_INTEGER_ARRAY,
|
||||
integer_array_variant.get_value_message().type);
|
||||
|
||||
// No direct comparison of vectors of ints and long ints
|
||||
@@ -464,7 +498,8 @@ TEST(TestParameter, integer_array_variant) {
|
||||
|
||||
rcl_interfaces::msg::Parameter integer_array_param = integer_array_variant.to_parameter_msg();
|
||||
EXPECT_EQ("integer_array_param", integer_array_param.name);
|
||||
EXPECT_EQ(rcl_interfaces::msg::ParameterType::PARAMETER_INTEGER_ARRAY,
|
||||
EXPECT_EQ(
|
||||
rcl_interfaces::msg::ParameterType::PARAMETER_INTEGER_ARRAY,
|
||||
integer_array_param.value.type);
|
||||
|
||||
param_value = integer_array_param.value.integer_array_value;
|
||||
@@ -489,7 +524,8 @@ TEST(TestParameter, integer_array_variant) {
|
||||
EXPECT_EQ(TEST_VALUE.end(), mismatches.first);
|
||||
EXPECT_EQ(param_value.end(), mismatches.second);
|
||||
|
||||
EXPECT_EQ(from_msg.get_value_message().type,
|
||||
EXPECT_EQ(
|
||||
from_msg.get_value_message().type,
|
||||
rcl_interfaces::msg::ParameterType::PARAMETER_INTEGER_ARRAY);
|
||||
}
|
||||
|
||||
@@ -499,12 +535,15 @@ TEST(TestParameter, long_integer_array_variant) {
|
||||
|
||||
rclcpp::Parameter long_array_variant("long_integer_array_param", TEST_VALUE);
|
||||
EXPECT_EQ("long_integer_array_param", long_array_variant.get_name());
|
||||
EXPECT_EQ(rclcpp::ParameterType::PARAMETER_INTEGER_ARRAY,
|
||||
EXPECT_EQ(
|
||||
rclcpp::ParameterType::PARAMETER_INTEGER_ARRAY,
|
||||
long_array_variant.get_type());
|
||||
EXPECT_EQ("integer_array", long_array_variant.get_type_name());
|
||||
EXPECT_EQ(rcl_interfaces::msg::ParameterType::PARAMETER_INTEGER_ARRAY,
|
||||
EXPECT_EQ(
|
||||
rcl_interfaces::msg::ParameterType::PARAMETER_INTEGER_ARRAY,
|
||||
long_array_variant.get_value_message().type);
|
||||
EXPECT_EQ(TEST_VALUE,
|
||||
EXPECT_EQ(
|
||||
TEST_VALUE,
|
||||
long_array_variant.get_value<rclcpp::ParameterType::PARAMETER_INTEGER_ARRAY>());
|
||||
EXPECT_EQ(TEST_VALUE, long_array_variant.get_value_message().integer_array_value);
|
||||
EXPECT_EQ(TEST_VALUE, long_array_variant.as_integer_array());
|
||||
@@ -524,7 +563,8 @@ TEST(TestParameter, long_integer_array_variant) {
|
||||
|
||||
rcl_interfaces::msg::Parameter integer_array_param = long_array_variant.to_parameter_msg();
|
||||
EXPECT_EQ("long_integer_array_param", integer_array_param.name);
|
||||
EXPECT_EQ(rcl_interfaces::msg::ParameterType::PARAMETER_INTEGER_ARRAY,
|
||||
EXPECT_EQ(
|
||||
rcl_interfaces::msg::ParameterType::PARAMETER_INTEGER_ARRAY,
|
||||
integer_array_param.value.type);
|
||||
EXPECT_EQ(TEST_VALUE, integer_array_param.value.integer_array_value);
|
||||
|
||||
@@ -534,10 +574,12 @@ TEST(TestParameter, long_integer_array_variant) {
|
||||
EXPECT_EQ("long_integer_array_param", from_msg.get_name());
|
||||
EXPECT_EQ(rclcpp::ParameterType::PARAMETER_INTEGER_ARRAY, from_msg.get_type());
|
||||
EXPECT_EQ("integer_array", from_msg.get_type_name());
|
||||
EXPECT_EQ(TEST_VALUE,
|
||||
EXPECT_EQ(
|
||||
TEST_VALUE,
|
||||
from_msg.get_value<rclcpp::ParameterType::PARAMETER_INTEGER_ARRAY>());
|
||||
EXPECT_EQ(TEST_VALUE, from_msg.get_value_message().integer_array_value);
|
||||
EXPECT_EQ(rcl_interfaces::msg::ParameterType::PARAMETER_INTEGER_ARRAY,
|
||||
EXPECT_EQ(
|
||||
rcl_interfaces::msg::ParameterType::PARAMETER_INTEGER_ARRAY,
|
||||
from_msg.get_value_message().type);
|
||||
}
|
||||
|
||||
@@ -549,10 +591,12 @@ TEST(TestParameter, float_array_variant) {
|
||||
rclcpp::Parameter float_array_variant("float_array_param", TEST_VALUE);
|
||||
|
||||
EXPECT_EQ("float_array_param", float_array_variant.get_name());
|
||||
EXPECT_EQ(rclcpp::ParameterType::PARAMETER_DOUBLE_ARRAY,
|
||||
EXPECT_EQ(
|
||||
rclcpp::ParameterType::PARAMETER_DOUBLE_ARRAY,
|
||||
float_array_variant.get_type());
|
||||
EXPECT_EQ("double_array", float_array_variant.get_type_name());
|
||||
EXPECT_EQ(rcl_interfaces::msg::ParameterType::PARAMETER_DOUBLE_ARRAY,
|
||||
EXPECT_EQ(
|
||||
rcl_interfaces::msg::ParameterType::PARAMETER_DOUBLE_ARRAY,
|
||||
float_array_variant.get_value_message().type);
|
||||
|
||||
// No direct comparison of vectors of floats and doubles
|
||||
@@ -587,7 +631,8 @@ TEST(TestParameter, float_array_variant) {
|
||||
|
||||
rcl_interfaces::msg::Parameter float_array_param = float_array_variant.to_parameter_msg();
|
||||
EXPECT_EQ("float_array_param", float_array_param.name);
|
||||
EXPECT_EQ(rcl_interfaces::msg::ParameterType::PARAMETER_DOUBLE_ARRAY,
|
||||
EXPECT_EQ(
|
||||
rcl_interfaces::msg::ParameterType::PARAMETER_DOUBLE_ARRAY,
|
||||
float_array_param.value.type);
|
||||
|
||||
param_value = float_array_param.value.double_array_value;
|
||||
@@ -612,7 +657,8 @@ TEST(TestParameter, float_array_variant) {
|
||||
EXPECT_EQ(TEST_VALUE.end(), mismatches.first);
|
||||
EXPECT_EQ(param_value.end(), mismatches.second);
|
||||
|
||||
EXPECT_EQ(rcl_interfaces::msg::ParameterType::PARAMETER_DOUBLE_ARRAY,
|
||||
EXPECT_EQ(
|
||||
rcl_interfaces::msg::ParameterType::PARAMETER_DOUBLE_ARRAY,
|
||||
from_msg.get_value_message().type);
|
||||
}
|
||||
|
||||
@@ -622,12 +668,15 @@ TEST(TestParameter, double_array_variant) {
|
||||
|
||||
rclcpp::Parameter double_array_variant("double_array_param", TEST_VALUE);
|
||||
EXPECT_EQ("double_array_param", double_array_variant.get_name());
|
||||
EXPECT_EQ(rclcpp::ParameterType::PARAMETER_DOUBLE_ARRAY,
|
||||
EXPECT_EQ(
|
||||
rclcpp::ParameterType::PARAMETER_DOUBLE_ARRAY,
|
||||
double_array_variant.get_type());
|
||||
EXPECT_EQ("double_array", double_array_variant.get_type_name());
|
||||
EXPECT_EQ(rcl_interfaces::msg::ParameterType::PARAMETER_DOUBLE_ARRAY,
|
||||
EXPECT_EQ(
|
||||
rcl_interfaces::msg::ParameterType::PARAMETER_DOUBLE_ARRAY,
|
||||
double_array_variant.get_value_message().type);
|
||||
EXPECT_EQ(TEST_VALUE,
|
||||
EXPECT_EQ(
|
||||
TEST_VALUE,
|
||||
double_array_variant.get_value<rclcpp::ParameterType::PARAMETER_DOUBLE_ARRAY>());
|
||||
EXPECT_EQ(TEST_VALUE, double_array_variant.get_value_message().double_array_value);
|
||||
EXPECT_EQ(TEST_VALUE, double_array_variant.as_double_array());
|
||||
@@ -647,7 +696,8 @@ TEST(TestParameter, double_array_variant) {
|
||||
|
||||
rcl_interfaces::msg::Parameter double_array_param = double_array_variant.to_parameter_msg();
|
||||
EXPECT_EQ("double_array_param", double_array_param.name);
|
||||
EXPECT_EQ(rcl_interfaces::msg::ParameterType::PARAMETER_DOUBLE_ARRAY,
|
||||
EXPECT_EQ(
|
||||
rcl_interfaces::msg::ParameterType::PARAMETER_DOUBLE_ARRAY,
|
||||
double_array_param.value.type);
|
||||
EXPECT_EQ(TEST_VALUE, double_array_param.value.double_array_value);
|
||||
|
||||
@@ -657,10 +707,12 @@ TEST(TestParameter, double_array_variant) {
|
||||
EXPECT_EQ("double_array_param", from_msg.get_name());
|
||||
EXPECT_EQ(rclcpp::ParameterType::PARAMETER_DOUBLE_ARRAY, from_msg.get_type());
|
||||
EXPECT_EQ("double_array", from_msg.get_type_name());
|
||||
EXPECT_EQ(TEST_VALUE,
|
||||
EXPECT_EQ(
|
||||
TEST_VALUE,
|
||||
from_msg.get_value<rclcpp::ParameterType::PARAMETER_DOUBLE_ARRAY>());
|
||||
EXPECT_EQ(TEST_VALUE, from_msg.get_value_message().double_array_value);
|
||||
EXPECT_EQ(rcl_interfaces::msg::ParameterType::PARAMETER_DOUBLE_ARRAY,
|
||||
EXPECT_EQ(
|
||||
rcl_interfaces::msg::ParameterType::PARAMETER_DOUBLE_ARRAY,
|
||||
from_msg.get_value_message().type);
|
||||
}
|
||||
|
||||
@@ -670,13 +722,16 @@ TEST(TestParameter, string_array_variant) {
|
||||
// Direct instantiation
|
||||
rclcpp::Parameter string_array_variant("string_array_param", TEST_VALUE);
|
||||
EXPECT_EQ("string_array_param", string_array_variant.get_name());
|
||||
EXPECT_EQ(rclcpp::ParameterType::PARAMETER_STRING_ARRAY,
|
||||
EXPECT_EQ(
|
||||
rclcpp::ParameterType::PARAMETER_STRING_ARRAY,
|
||||
string_array_variant.get_type());
|
||||
EXPECT_EQ("string_array", string_array_variant.get_type_name());
|
||||
EXPECT_EQ(TEST_VALUE,
|
||||
EXPECT_EQ(
|
||||
TEST_VALUE,
|
||||
string_array_variant.get_value<rclcpp::ParameterType::PARAMETER_STRING_ARRAY>());
|
||||
EXPECT_EQ(TEST_VALUE, string_array_variant.get_value_message().string_array_value);
|
||||
EXPECT_EQ(rcl_interfaces::msg::ParameterType::PARAMETER_STRING_ARRAY,
|
||||
EXPECT_EQ(
|
||||
rcl_interfaces::msg::ParameterType::PARAMETER_STRING_ARRAY,
|
||||
string_array_variant.get_value_message().type);
|
||||
EXPECT_EQ(TEST_VALUE, string_array_variant.as_string_array());
|
||||
|
||||
@@ -693,7 +748,8 @@ TEST(TestParameter, string_array_variant) {
|
||||
|
||||
rcl_interfaces::msg::Parameter string_array_param = string_array_variant.to_parameter_msg();
|
||||
EXPECT_EQ("string_array_param", string_array_param.name);
|
||||
EXPECT_EQ(rcl_interfaces::msg::ParameterType::PARAMETER_STRING_ARRAY,
|
||||
EXPECT_EQ(
|
||||
rcl_interfaces::msg::ParameterType::PARAMETER_STRING_ARRAY,
|
||||
string_array_param.value.type);
|
||||
EXPECT_EQ(TEST_VALUE, string_array_param.value.string_array_value);
|
||||
|
||||
@@ -703,9 +759,11 @@ TEST(TestParameter, string_array_variant) {
|
||||
EXPECT_EQ("string_array_param", from_msg.get_name());
|
||||
EXPECT_EQ(rclcpp::ParameterType::PARAMETER_STRING_ARRAY, from_msg.get_type());
|
||||
EXPECT_EQ("string_array", from_msg.get_type_name());
|
||||
EXPECT_EQ(TEST_VALUE,
|
||||
EXPECT_EQ(
|
||||
TEST_VALUE,
|
||||
from_msg.get_value<rclcpp::ParameterType::PARAMETER_STRING_ARRAY>());
|
||||
EXPECT_EQ(TEST_VALUE, from_msg.get_value_message().string_array_value);
|
||||
EXPECT_EQ(rcl_interfaces::msg::ParameterType::PARAMETER_STRING_ARRAY,
|
||||
EXPECT_EQ(
|
||||
rcl_interfaces::msg::ParameterType::PARAMETER_STRING_ARRAY,
|
||||
from_msg.get_value_message().type);
|
||||
}
|
||||
|
||||
@@ -67,7 +67,8 @@ TEST_F(TestParameterClient, async_construction_and_destruction) {
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW({
|
||||
ASSERT_THROW(
|
||||
{
|
||||
std::make_shared<rclcpp::AsyncParametersClient>(node, "invalid_remote_node?");
|
||||
}, rclcpp::exceptions::InvalidServiceNameError);
|
||||
}
|
||||
@@ -100,7 +101,8 @@ TEST_F(TestParameterClient, sync_construction_and_destruction) {
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW({
|
||||
ASSERT_THROW(
|
||||
{
|
||||
std::make_shared<rclcpp::SyncParametersClient>(node, "invalid_remote_node?");
|
||||
}, rclcpp::exceptions::InvalidServiceNameError);
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <rcl/allocator.h>
|
||||
#include <rcl_yaml_param_parser/parser.h>
|
||||
#include <rcutils/strdup.h>
|
||||
|
||||
|
||||
@@ -98,7 +98,8 @@ TEST_F(TestPublisher, construction_and_destruction) {
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW({
|
||||
ASSERT_THROW(
|
||||
{
|
||||
auto publisher = node->create_publisher<IntraProcessMessage>("invalid_topic?", 42);
|
||||
}, rclcpp::exceptions::InvalidTopicNameError);
|
||||
}
|
||||
@@ -138,41 +139,6 @@ TEST_F(TestPublisher, various_creation_signatures) {
|
||||
rclcpp::create_publisher<IntraProcessMessage>(node, "topic", 42, rclcpp::PublisherOptions());
|
||||
(void)publisher;
|
||||
}
|
||||
// Now deprecated functions.
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4996)
|
||||
#endif
|
||||
{
|
||||
auto publisher = node->create_publisher<IntraProcessMessage>("topic");
|
||||
(void)publisher;
|
||||
}
|
||||
{
|
||||
auto publisher = node->create_publisher<IntraProcessMessage>(
|
||||
"topic",
|
||||
42,
|
||||
std::make_shared<std::allocator<IntraProcessMessage>>());
|
||||
(void)publisher;
|
||||
}
|
||||
{
|
||||
auto publisher = node->create_publisher<IntraProcessMessage>("topic", rmw_qos_profile_default);
|
||||
(void)publisher;
|
||||
}
|
||||
{
|
||||
auto publisher = node->create_publisher<IntraProcessMessage>(
|
||||
"topic",
|
||||
rmw_qos_profile_default,
|
||||
std::make_shared<std::allocator<IntraProcessMessage>>());
|
||||
(void)publisher;
|
||||
}
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic pop
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -233,7 +199,8 @@ TEST_F(TestPublisherSub, construction_and_destruction) {
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW({
|
||||
ASSERT_THROW(
|
||||
{
|
||||
auto publisher = subnode->create_publisher<IntraProcessMessage>("invalid_topic?", 42);
|
||||
}, rclcpp::exceptions::InvalidTopicNameError);
|
||||
}
|
||||
|
||||
@@ -56,8 +56,9 @@ TEST(TestSerializedMessageAllocator, borrow_from_subscription) {
|
||||
|
||||
auto node = std::make_shared<rclcpp::Node>("test_serialized_message_allocator_node");
|
||||
std::shared_ptr<rclcpp::SubscriptionBase> sub =
|
||||
node->create_subscription<test_msgs::msg::Empty>("~/dummy_topic", 10,
|
||||
[](std::shared_ptr<test_msgs::msg::Empty> test_msg) {(void) test_msg;});
|
||||
node->create_subscription<test_msgs::msg::Empty>(
|
||||
"~/dummy_topic", 10,
|
||||
[](std::shared_ptr<test_msgs::msg::Empty> test_msg) {(void) test_msg;});
|
||||
|
||||
auto msg0 = sub->create_serialized_message();
|
||||
EXPECT_EQ(0u, msg0->buffer_capacity);
|
||||
|
||||
@@ -78,7 +78,8 @@ TEST_F(TestService, construction_and_destruction) {
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW({
|
||||
ASSERT_THROW(
|
||||
{
|
||||
auto service = node->create_service<ListParameters>("invalid_service?", callback);
|
||||
}, rclcpp::exceptions::InvalidServiceNameError);
|
||||
}
|
||||
@@ -98,7 +99,8 @@ TEST_F(TestServiceSub, construction_and_destruction) {
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW({
|
||||
ASSERT_THROW(
|
||||
{
|
||||
auto service = node->create_service<ListParameters>("invalid_service?", callback);
|
||||
}, rclcpp::exceptions::InvalidServiceNameError);
|
||||
}
|
||||
|
||||
@@ -129,7 +129,8 @@ TEST_F(TestSubscription, construction_and_destruction) {
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW({
|
||||
ASSERT_THROW(
|
||||
{
|
||||
auto sub = node->create_subscription<IntraProcessMessage>("invalid_topic?", 10, callback);
|
||||
}, rclcpp::exceptions::InvalidTopicNameError);
|
||||
}
|
||||
@@ -161,7 +162,8 @@ TEST_F(TestSubscriptionSub, construction_and_destruction) {
|
||||
}
|
||||
|
||||
{
|
||||
ASSERT_THROW({
|
||||
ASSERT_THROW(
|
||||
{
|
||||
auto sub = node->create_subscription<IntraProcessMessage>("invalid_topic?", 1, callback);
|
||||
}, rclcpp::exceptions::InvalidTopicNameError);
|
||||
}
|
||||
@@ -201,40 +203,6 @@ TEST_F(TestSubscription, various_creation_signatures) {
|
||||
node, "topic", 42, cb, rclcpp::SubscriptionOptions());
|
||||
(void)sub;
|
||||
}
|
||||
// Now deprecated functions.
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4996)
|
||||
#endif
|
||||
{
|
||||
auto sub = node->create_subscription<IntraProcessMessage>("topic", cb, 42);
|
||||
(void)sub;
|
||||
}
|
||||
{
|
||||
auto sub = node->create_subscription<IntraProcessMessage>("topic", cb);
|
||||
(void)sub;
|
||||
}
|
||||
{
|
||||
auto sub = node->create_subscription<IntraProcessMessage>("topic", cb, rmw_qos_profile_default);
|
||||
(void)sub;
|
||||
}
|
||||
{
|
||||
auto sub =
|
||||
node->create_subscription<IntraProcessMessage>("topic", cb, rmw_qos_profile_default, nullptr);
|
||||
(void)sub;
|
||||
}
|
||||
{
|
||||
auto sub = node->create_subscription<IntraProcessMessage>("topic", cb, 42, nullptr);
|
||||
(void)sub;
|
||||
}
|
||||
#if !defined(_WIN32)
|
||||
# pragma GCC diagnostic pop
|
||||
#else // !defined(_WIN32)
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -97,13 +97,15 @@ TEST(TestTime, conversions) {
|
||||
negative_time_msg.sec = -1;
|
||||
negative_time_msg.nanosec = 1;
|
||||
|
||||
EXPECT_ANY_THROW({
|
||||
EXPECT_ANY_THROW(
|
||||
{
|
||||
rclcpp::Time negative_time = negative_time_msg;
|
||||
});
|
||||
|
||||
EXPECT_ANY_THROW(rclcpp::Time(-1, 1));
|
||||
|
||||
EXPECT_ANY_THROW({
|
||||
EXPECT_ANY_THROW(
|
||||
{
|
||||
rclcpp::Time assignment(1, 2);
|
||||
assignment = negative_time_msg;
|
||||
});
|
||||
|
||||
@@ -161,7 +161,8 @@ void set_use_sim_time_parameter(
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
EXPECT_TRUE(parameters_client->wait_for_service(2s));
|
||||
auto set_parameters_results = parameters_client->set_parameters({
|
||||
auto set_parameters_results = parameters_client->set_parameters(
|
||||
{
|
||||
rclcpp::Parameter("use_sim_time", value)
|
||||
});
|
||||
for (auto & result : set_parameters_results) {
|
||||
|
||||
@@ -40,17 +40,18 @@ protected:
|
||||
|
||||
test_node = std::make_shared<rclcpp::Node>("test_timer_node");
|
||||
|
||||
timer = test_node->create_wall_timer(100ms,
|
||||
[this]() -> void
|
||||
{
|
||||
this->has_timer_run.store(true);
|
||||
timer = test_node->create_wall_timer(
|
||||
100ms,
|
||||
[this]() -> void
|
||||
{
|
||||
this->has_timer_run.store(true);
|
||||
|
||||
if (this->cancel_timer.load()) {
|
||||
this->timer->cancel();
|
||||
}
|
||||
// prevent any tests running timer from blocking
|
||||
this->executor->cancel();
|
||||
if (this->cancel_timer.load()) {
|
||||
this->timer->cancel();
|
||||
}
|
||||
// prevent any tests running timer from blocking
|
||||
this->executor->cancel();
|
||||
}
|
||||
);
|
||||
|
||||
executor->add_node(test_node);
|
||||
|
||||
@@ -22,8 +22,13 @@
|
||||
#include "rclcpp/utilities.hpp"
|
||||
|
||||
TEST(TestUtilities, remove_ros_arguments) {
|
||||
const char * const argv[] = {"process_name", "-d", "__ns:=/foo/bar",
|
||||
"__ns:=/fiz/buz", "--foo=bar", "--baz"};
|
||||
const char * const argv[] = {
|
||||
"process_name",
|
||||
"-d", "--ros-args",
|
||||
"-r", "__ns:=/foo/bar",
|
||||
"-r", "__ns:=/fiz/buz",
|
||||
"--", "--foo=bar", "--baz"
|
||||
};
|
||||
int argc = sizeof(argv) / sizeof(const char *);
|
||||
auto args = rclcpp::remove_ros_arguments(argc, argv);
|
||||
|
||||
@@ -37,7 +42,8 @@ TEST(TestUtilities, remove_ros_arguments) {
|
||||
TEST(TestUtilities, remove_ros_arguments_null) {
|
||||
// In the case of a C executable, we would expect to get
|
||||
// argc=1 and argv = ["process_name"], so this is an invalid input.
|
||||
ASSERT_THROW({
|
||||
ASSERT_THROW(
|
||||
{
|
||||
rclcpp::remove_ros_arguments(0, nullptr);
|
||||
}, rclcpp::exceptions::RCLErrorBase);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,14 @@ Changelog for package rclcpp_action
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
0.8.0 (2019-09-26)
|
||||
------------------
|
||||
* Fix UnknownGoalHandle error string. (`#856 <https://github.com/ros2/rclcpp/issues/856>`_)
|
||||
* Guard against making multiple result requests for a goal handle (`#808 <https://github.com/ros2/rclcpp/issues/808>`_)
|
||||
* Add line break after first open paren in multiline function call (`#785 <https://github.com/ros2/rclcpp/issues/785>`_)
|
||||
* Fix typo in test fixture tear down method name (`#787 <https://github.com/ros2/rclcpp/issues/787>`_)
|
||||
* Contributors: Chris Lalancette, Dan Rose, Jacob Perron
|
||||
|
||||
0.7.5 (2019-05-30)
|
||||
------------------
|
||||
|
||||
|
||||
@@ -410,10 +410,7 @@ public:
|
||||
// This will override any previously registered callback
|
||||
goal_handle->set_result_callback(result_callback);
|
||||
}
|
||||
// If the user chose to ignore the result before, then ask the server for the result now.
|
||||
if (!goal_handle->is_result_aware()) {
|
||||
this->make_result_aware(goal_handle);
|
||||
}
|
||||
this->make_result_aware(goal_handle);
|
||||
return goal_handle->async_result();
|
||||
}
|
||||
|
||||
@@ -595,6 +592,10 @@ private:
|
||||
void
|
||||
make_result_aware(typename GoalHandle::SharedPtr goal_handle)
|
||||
{
|
||||
// Avoid making more than one request
|
||||
if (goal_handle->set_result_awareness(true)) {
|
||||
return;
|
||||
}
|
||||
using GoalResultRequest = typename ActionT::Impl::GetResultService::Request;
|
||||
auto goal_result_request = std::make_shared<GoalResultRequest>();
|
||||
goal_result_request->goal_id.uuid = goal_handle->get_goal_id();
|
||||
@@ -614,7 +615,6 @@ private:
|
||||
std::lock_guard<std::mutex> lock(goal_handles_mutex_);
|
||||
goal_handles_.erase(goal_handle->get_goal_id());
|
||||
});
|
||||
goal_handle->set_result_awareness(true);
|
||||
}
|
||||
|
||||
/// \internal
|
||||
|
||||
@@ -134,7 +134,8 @@ private:
|
||||
typename ClientGoalHandle<ActionT>::SharedPtr shared_this,
|
||||
typename std::shared_ptr<const Feedback> feedback_message);
|
||||
|
||||
void
|
||||
/// Returns the previous value of awareness
|
||||
bool
|
||||
set_result_awareness(bool awareness);
|
||||
|
||||
void
|
||||
|
||||
@@ -127,11 +127,13 @@ ClientGoalHandle<ActionT>::is_result_aware()
|
||||
}
|
||||
|
||||
template<typename ActionT>
|
||||
void
|
||||
bool
|
||||
ClientGoalHandle<ActionT>::set_result_awareness(bool awareness)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(handle_mutex_);
|
||||
bool previous = is_result_aware_;
|
||||
is_result_aware_ = awareness;
|
||||
return previous;
|
||||
}
|
||||
|
||||
template<typename ActionT>
|
||||
@@ -140,8 +142,7 @@ ClientGoalHandle<ActionT>::invalidate()
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(handle_mutex_);
|
||||
status_ = GoalStatus::STATUS_UNKNOWN;
|
||||
result_promise_.set_exception(std::make_exception_ptr(
|
||||
exceptions::UnawareGoalHandleError()));
|
||||
result_promise_.set_exception(std::make_exception_ptr(exceptions::UnawareGoalHandleError()));
|
||||
}
|
||||
|
||||
template<typename ActionT>
|
||||
|
||||
@@ -25,7 +25,7 @@ class UnknownGoalHandleError : public std::invalid_argument
|
||||
{
|
||||
public:
|
||||
UnknownGoalHandleError()
|
||||
: std::invalid_argument("Goal handle is not know to this client.")
|
||||
: std::invalid_argument("Goal handle is not known to this client.")
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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>0.7.5</version>
|
||||
<version>0.8.0</version>
|
||||
<description>Adds action APIs for C++.</description>
|
||||
<maintainer email="dthomas@osrfoundation.org">Dirk Thomas</maintainer>
|
||||
<license>Apache License 2.0</license>
|
||||
|
||||
@@ -89,7 +89,8 @@ ServerBase::ServerBase(
|
||||
rcl_node_t * rcl_node = node_base->get_rcl_node_handle();
|
||||
rcl_ret_t ret = rcl_action_server_fini(ptr, rcl_node);
|
||||
(void)ret;
|
||||
RCLCPP_DEBUG(rclcpp::get_logger("rclcpp_action"),
|
||||
RCLCPP_DEBUG(
|
||||
rclcpp::get_logger("rclcpp_action"),
|
||||
"failed to fini rcl_action_server_t in deleter");
|
||||
}
|
||||
delete ptr;
|
||||
@@ -254,7 +255,8 @@ ServerBase::execute_goal_request_received()
|
||||
if (nullptr != ptr) {
|
||||
rcl_ret_t fail_ret = rcl_action_goal_handle_fini(ptr);
|
||||
(void)fail_ret;
|
||||
RCLCPP_DEBUG(rclcpp::get_logger("rclcpp_action"),
|
||||
RCLCPP_DEBUG(
|
||||
rclcpp::get_logger("rclcpp_action"),
|
||||
"failed to fini rcl_action_goal_handle_t in deleter");
|
||||
delete ptr;
|
||||
}
|
||||
@@ -329,7 +331,8 @@ ServerBase::execute_cancel_request_received()
|
||||
rclcpp::exceptions::throw_from_rcl_error(ret);
|
||||
}
|
||||
|
||||
RCLCPP_SCOPE_EXIT({
|
||||
RCLCPP_SCOPE_EXIT(
|
||||
{
|
||||
ret = rcl_action_cancel_response_fini(&cancel_response);
|
||||
if (RCL_RET_OK != ret) {
|
||||
RCLCPP_ERROR(pimpl_->logger_, "Failed to fini cancel response");
|
||||
@@ -478,7 +481,8 @@ ServerBase::publish_status()
|
||||
rclcpp::exceptions::throw_from_rcl_error(ret);
|
||||
}
|
||||
|
||||
RCLCPP_SCOPE_EXIT({
|
||||
RCLCPP_SCOPE_EXIT(
|
||||
{
|
||||
ret = rcl_action_goal_status_array_fini(&c_status_array);
|
||||
if (RCL_RET_OK != ret) {
|
||||
RCLCPP_ERROR(pimpl_->logger_, "Failed to fini status array message");
|
||||
|
||||
@@ -219,7 +219,7 @@ protected:
|
||||
ASSERT_EQ(RCL_RET_OK, rcl_set_ros_time_override(clock.get_clock_handle(), RCL_S_TO_NS(1)));
|
||||
}
|
||||
|
||||
void Teardown()
|
||||
void TearDown()
|
||||
{
|
||||
status_publisher.reset();
|
||||
feedback_publisher.reset();
|
||||
@@ -396,7 +396,8 @@ TEST_F(TestClient, async_send_goal_with_result_callback_wait_for_result)
|
||||
[&result_callback_received](
|
||||
const typename ActionGoalHandle::WrappedResult & result) mutable
|
||||
{
|
||||
if (rclcpp_action::ResultCode::SUCCEEDED == result.code &&
|
||||
if (
|
||||
rclcpp_action::ResultCode::SUCCEEDED == result.code &&
|
||||
result.result->sequence.size() == 5u)
|
||||
{
|
||||
result_callback_received = true;
|
||||
|
||||
@@ -48,7 +48,8 @@ protected:
|
||||
auto request = std::make_shared<Fibonacci::Impl::SendGoalService::Request>();
|
||||
request->goal_id.uuid = uuid;
|
||||
auto future = client->async_send_request(request);
|
||||
if (rclcpp::executor::FutureReturnCode::SUCCESS !=
|
||||
if (
|
||||
rclcpp::executor::FutureReturnCode::SUCCESS !=
|
||||
rclcpp::spin_until_future_complete(node, future))
|
||||
{
|
||||
throw std::runtime_error("send goal future didn't complete succesfully");
|
||||
@@ -67,7 +68,8 @@ protected:
|
||||
auto request = std::make_shared<Fibonacci::Impl::CancelGoalService::Request>();
|
||||
request->goal_info.goal_id.uuid = uuid;
|
||||
auto future = cancel_client->async_send_request(request);
|
||||
if (rclcpp::executor::FutureReturnCode::SUCCESS !=
|
||||
if (
|
||||
rclcpp::executor::FutureReturnCode::SUCCESS !=
|
||||
rclcpp::spin_until_future_complete(node, future))
|
||||
{
|
||||
throw std::runtime_error("cancel goal future didn't complete succesfully");
|
||||
@@ -81,14 +83,15 @@ TEST_F(TestServer, construction_and_destruction)
|
||||
auto node = std::make_shared<rclcpp::Node>("construct_node", "/rclcpp_action/construct");
|
||||
|
||||
using GoalHandle = rclcpp_action::ServerGoalHandle<Fibonacci>;
|
||||
auto as = rclcpp_action::create_server<Fibonacci>(node, "fibonacci",
|
||||
[](const GoalUUID &, std::shared_ptr<const Fibonacci::Goal>) {
|
||||
return rclcpp_action::GoalResponse::REJECT;
|
||||
},
|
||||
[](std::shared_ptr<GoalHandle>) {
|
||||
return rclcpp_action::CancelResponse::REJECT;
|
||||
},
|
||||
[](std::shared_ptr<GoalHandle>) {});
|
||||
auto as = rclcpp_action::create_server<Fibonacci>(
|
||||
node, "fibonacci",
|
||||
[](const GoalUUID &, std::shared_ptr<const Fibonacci::Goal>) {
|
||||
return rclcpp_action::GoalResponse::REJECT;
|
||||
},
|
||||
[](std::shared_ptr<GoalHandle>) {
|
||||
return rclcpp_action::CancelResponse::REJECT;
|
||||
},
|
||||
[](std::shared_ptr<GoalHandle>) {});
|
||||
(void)as;
|
||||
}
|
||||
|
||||
@@ -105,12 +108,13 @@ TEST_F(TestServer, handle_goal_called)
|
||||
};
|
||||
|
||||
using GoalHandle = rclcpp_action::ServerGoalHandle<Fibonacci>;
|
||||
auto as = rclcpp_action::create_server<Fibonacci>(node, "fibonacci",
|
||||
handle_goal,
|
||||
[](std::shared_ptr<GoalHandle>) {
|
||||
return rclcpp_action::CancelResponse::REJECT;
|
||||
},
|
||||
[](std::shared_ptr<GoalHandle>) {});
|
||||
auto as = rclcpp_action::create_server<Fibonacci>(
|
||||
node, "fibonacci",
|
||||
handle_goal,
|
||||
[](std::shared_ptr<GoalHandle>) {
|
||||
return rclcpp_action::CancelResponse::REJECT;
|
||||
},
|
||||
[](std::shared_ptr<GoalHandle>) {});
|
||||
(void)as;
|
||||
|
||||
// Create a client that calls the goal request service
|
||||
@@ -153,12 +157,13 @@ TEST_F(TestServer, handle_accepted_called)
|
||||
received_handle = handle;
|
||||
};
|
||||
|
||||
auto as = rclcpp_action::create_server<Fibonacci>(node, "fibonacci",
|
||||
handle_goal,
|
||||
[](std::shared_ptr<GoalHandle>) {
|
||||
return rclcpp_action::CancelResponse::REJECT;
|
||||
},
|
||||
handle_accepted);
|
||||
auto as = rclcpp_action::create_server<Fibonacci>(
|
||||
node, "fibonacci",
|
||||
handle_goal,
|
||||
[](std::shared_ptr<GoalHandle>) {
|
||||
return rclcpp_action::CancelResponse::REJECT;
|
||||
},
|
||||
handle_accepted);
|
||||
(void)as;
|
||||
|
||||
auto request = send_goal_request(node, uuid);
|
||||
@@ -193,10 +198,11 @@ TEST_F(TestServer, handle_cancel_called)
|
||||
received_handle = handle;
|
||||
};
|
||||
|
||||
auto as = rclcpp_action::create_server<Fibonacci>(node, "fibonacci",
|
||||
handle_goal,
|
||||
handle_cancel,
|
||||
handle_accepted);
|
||||
auto as = rclcpp_action::create_server<Fibonacci>(
|
||||
node, "fibonacci",
|
||||
handle_goal,
|
||||
handle_cancel,
|
||||
handle_accepted);
|
||||
(void)as;
|
||||
|
||||
send_goal_request(node, uuid);
|
||||
@@ -233,10 +239,11 @@ TEST_F(TestServer, handle_cancel_reject)
|
||||
received_handle = handle;
|
||||
};
|
||||
|
||||
auto as = rclcpp_action::create_server<Fibonacci>(node, "fibonacci",
|
||||
handle_goal,
|
||||
handle_cancel,
|
||||
handle_accepted);
|
||||
auto as = rclcpp_action::create_server<Fibonacci>(
|
||||
node, "fibonacci",
|
||||
handle_goal,
|
||||
handle_cancel,
|
||||
handle_accepted);
|
||||
(void)as;
|
||||
|
||||
send_goal_request(node, uuid);
|
||||
@@ -275,10 +282,11 @@ TEST_F(TestServer, handle_cancel_unknown_goal)
|
||||
received_handle = handle;
|
||||
};
|
||||
|
||||
auto as = rclcpp_action::create_server<Fibonacci>(node, "fibonacci",
|
||||
handle_goal,
|
||||
handle_cancel,
|
||||
handle_accepted);
|
||||
auto as = rclcpp_action::create_server<Fibonacci>(
|
||||
node, "fibonacci",
|
||||
handle_goal,
|
||||
handle_cancel,
|
||||
handle_accepted);
|
||||
(void)as;
|
||||
|
||||
send_goal_request(node, uuid);
|
||||
@@ -317,10 +325,11 @@ TEST_F(TestServer, handle_cancel_terminated_goal)
|
||||
handle->succeed(std::make_shared<Fibonacci::Result>());
|
||||
};
|
||||
|
||||
auto as = rclcpp_action::create_server<Fibonacci>(node, "fibonacci",
|
||||
handle_goal,
|
||||
handle_cancel,
|
||||
handle_accepted);
|
||||
auto as = rclcpp_action::create_server<Fibonacci>(
|
||||
node, "fibonacci",
|
||||
handle_goal,
|
||||
handle_cancel,
|
||||
handle_accepted);
|
||||
(void)as;
|
||||
|
||||
send_goal_request(node, uuid);
|
||||
@@ -358,10 +367,11 @@ TEST_F(TestServer, publish_status_accepted)
|
||||
received_handle = handle;
|
||||
};
|
||||
|
||||
auto as = rclcpp_action::create_server<Fibonacci>(node, "fibonacci",
|
||||
handle_goal,
|
||||
handle_cancel,
|
||||
handle_accepted);
|
||||
auto as = rclcpp_action::create_server<Fibonacci>(
|
||||
node, "fibonacci",
|
||||
handle_goal,
|
||||
handle_cancel,
|
||||
handle_accepted);
|
||||
(void)as;
|
||||
|
||||
// Subscribe to status messages
|
||||
@@ -420,10 +430,11 @@ TEST_F(TestServer, publish_status_canceling)
|
||||
received_handle = handle;
|
||||
};
|
||||
|
||||
auto as = rclcpp_action::create_server<Fibonacci>(node, "fibonacci",
|
||||
handle_goal,
|
||||
handle_cancel,
|
||||
handle_accepted);
|
||||
auto as = rclcpp_action::create_server<Fibonacci>(
|
||||
node, "fibonacci",
|
||||
handle_goal,
|
||||
handle_cancel,
|
||||
handle_accepted);
|
||||
(void)as;
|
||||
|
||||
// Subscribe to status messages
|
||||
@@ -476,10 +487,11 @@ TEST_F(TestServer, publish_status_canceled)
|
||||
received_handle = handle;
|
||||
};
|
||||
|
||||
auto as = rclcpp_action::create_server<Fibonacci>(node, "fibonacci",
|
||||
handle_goal,
|
||||
handle_cancel,
|
||||
handle_accepted);
|
||||
auto as = rclcpp_action::create_server<Fibonacci>(
|
||||
node, "fibonacci",
|
||||
handle_goal,
|
||||
handle_cancel,
|
||||
handle_accepted);
|
||||
(void)as;
|
||||
|
||||
// Subscribe to status messages
|
||||
@@ -534,10 +546,11 @@ TEST_F(TestServer, publish_status_succeeded)
|
||||
received_handle = handle;
|
||||
};
|
||||
|
||||
auto as = rclcpp_action::create_server<Fibonacci>(node, "fibonacci",
|
||||
handle_goal,
|
||||
handle_cancel,
|
||||
handle_accepted);
|
||||
auto as = rclcpp_action::create_server<Fibonacci>(
|
||||
node, "fibonacci",
|
||||
handle_goal,
|
||||
handle_cancel,
|
||||
handle_accepted);
|
||||
(void)as;
|
||||
|
||||
// Subscribe to status messages
|
||||
@@ -590,10 +603,11 @@ TEST_F(TestServer, publish_status_aborted)
|
||||
received_handle = handle;
|
||||
};
|
||||
|
||||
auto as = rclcpp_action::create_server<Fibonacci>(node, "fibonacci",
|
||||
handle_goal,
|
||||
handle_cancel,
|
||||
handle_accepted);
|
||||
auto as = rclcpp_action::create_server<Fibonacci>(
|
||||
node, "fibonacci",
|
||||
handle_goal,
|
||||
handle_cancel,
|
||||
handle_accepted);
|
||||
(void)as;
|
||||
|
||||
// Subscribe to status messages
|
||||
@@ -646,10 +660,11 @@ TEST_F(TestServer, publish_feedback)
|
||||
received_handle = handle;
|
||||
};
|
||||
|
||||
auto as = rclcpp_action::create_server<Fibonacci>(node, "fibonacci",
|
||||
handle_goal,
|
||||
handle_cancel,
|
||||
handle_accepted);
|
||||
auto as = rclcpp_action::create_server<Fibonacci>(
|
||||
node, "fibonacci",
|
||||
handle_goal,
|
||||
handle_cancel,
|
||||
handle_accepted);
|
||||
(void)as;
|
||||
|
||||
// Subscribe to feedback messages
|
||||
@@ -703,10 +718,11 @@ TEST_F(TestServer, get_result)
|
||||
received_handle = handle;
|
||||
};
|
||||
|
||||
auto as = rclcpp_action::create_server<Fibonacci>(node, "fibonacci",
|
||||
handle_goal,
|
||||
handle_cancel,
|
||||
handle_accepted);
|
||||
auto as = rclcpp_action::create_server<Fibonacci>(
|
||||
node, "fibonacci",
|
||||
handle_goal,
|
||||
handle_cancel,
|
||||
handle_accepted);
|
||||
(void)as;
|
||||
|
||||
send_goal_request(node, uuid);
|
||||
@@ -727,7 +743,8 @@ TEST_F(TestServer, get_result)
|
||||
received_handle->succeed(result);
|
||||
|
||||
// Wait for the result request to be received
|
||||
ASSERT_EQ(rclcpp::executor::FutureReturnCode::SUCCESS,
|
||||
ASSERT_EQ(
|
||||
rclcpp::executor::FutureReturnCode::SUCCESS,
|
||||
rclcpp::spin_until_future_complete(node, future));
|
||||
|
||||
auto response = future.get();
|
||||
@@ -759,10 +776,11 @@ TEST_F(TestServer, deferred_execution)
|
||||
received_handle = handle;
|
||||
};
|
||||
|
||||
auto as = rclcpp_action::create_server<test_msgs::action::Fibonacci>(node, "fibonacci",
|
||||
handle_goal,
|
||||
handle_cancel,
|
||||
handle_accepted);
|
||||
auto as = rclcpp_action::create_server<test_msgs::action::Fibonacci>(
|
||||
node, "fibonacci",
|
||||
handle_goal,
|
||||
handle_cancel,
|
||||
handle_accepted);
|
||||
(void)as;
|
||||
|
||||
send_goal_request(node, uuid);
|
||||
|
||||
@@ -2,6 +2,17 @@
|
||||
Changelog for package rclcpp_components
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
0.8.0 (2019-09-26)
|
||||
------------------
|
||||
* Force explicit --ros-args in NodeOptions::arguments(). (`#845 <https://github.com/ros2/rclcpp/issues/845>`_)
|
||||
* Use of -r/--remap flags where appropriate. (`#834 <https://github.com/ros2/rclcpp/issues/834>`_)
|
||||
* Add line break after first open paren in multiline function call (`#785 <https://github.com/ros2/rclcpp/issues/785>`_)
|
||||
* fix linter issue (`#795 <https://github.com/ros2/rclcpp/issues/795>`_)
|
||||
* Remove non-package from ament_target_dependencies() (`#793 <https://github.com/ros2/rclcpp/issues/793>`_)
|
||||
* fix for multiple nodes not being recognized (`#790 <https://github.com/ros2/rclcpp/issues/790>`_)
|
||||
* Cmake infrastructure for creating components (`#784 <https://github.com/ros2/rclcpp/issues/784>`_)
|
||||
* Contributors: Dan Rose, Michel Hidalgo, Shane Loretz, Siddharth Kucheria
|
||||
|
||||
0.7.5 (2019-05-30)
|
||||
------------------
|
||||
|
||||
|
||||
@@ -41,6 +41,11 @@ ament_target_dependencies(component_container
|
||||
"rclcpp"
|
||||
)
|
||||
|
||||
set(node_main_template_install_dir "share/${PROJECT_NAME}")
|
||||
install(FILES
|
||||
src/node_main.cpp.in
|
||||
DESTINATION ${node_main_template_install_dir})
|
||||
|
||||
add_executable(
|
||||
component_container_mt
|
||||
src/component_container_mt.cpp
|
||||
@@ -63,8 +68,7 @@ if(BUILD_TESTING)
|
||||
add_library(test_component SHARED test/components/test_component.cpp)
|
||||
ament_target_dependencies(test_component
|
||||
"class_loader"
|
||||
"rclcpp"
|
||||
"rclcpp_components")
|
||||
"rclcpp")
|
||||
#rclcpp_components_register_nodes(test_component "test_rclcpp_components::TestComponent")
|
||||
set(components "${components}test_rclcpp_components::TestComponentFoo;$<TARGET_FILE:test_component>\n")
|
||||
set(components "${components}test_rclcpp_components::TestComponentBar;$<TARGET_FILE:test_component>\n")
|
||||
@@ -119,4 +123,4 @@ install(
|
||||
ament_export_include_directories(include)
|
||||
ament_export_dependencies(class_loader)
|
||||
ament_export_dependencies(rclcpp)
|
||||
ament_package(CONFIG_EXTRAS rclcpp_components-extras.cmake)
|
||||
ament_package(CONFIG_EXTRAS rclcpp_components-extras.cmake.in)
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
# Copyright 2019 Open Source Robotics Foundation, Inc.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# usage: rclcpp_components_register_node(
|
||||
# <target> PLUGIN <component> EXECUTABLE <node>)
|
||||
#
|
||||
# Register an rclcpp component with the ament
|
||||
# resource index and create an executable.
|
||||
#
|
||||
# :param target: the shared library target
|
||||
# :type target: string
|
||||
# :param PLUGIN: the plugin name
|
||||
# :type PLUGIN: string
|
||||
# :type EXECUTABLE: the node's executable name
|
||||
# :type EXECUTABLE: string
|
||||
#
|
||||
macro(rclcpp_components_register_node target)
|
||||
cmake_parse_arguments(ARGS "" "PLUGIN;EXECUTABLE" "" ${ARGN})
|
||||
set(component ${ARGS_PLUGIN})
|
||||
set(node ${ARGS_EXECUTABLE})
|
||||
_rclcpp_components_register_package_hook()
|
||||
set(_path "lib")
|
||||
set(library_name "$<TARGET_FILE_NAME:${target}>")
|
||||
if(WIN32)
|
||||
set(_path "bin")
|
||||
endif()
|
||||
set(_RCLCPP_COMPONENTS__NODES
|
||||
"${_RCLCPP_COMPONENTS__NODES}${component};${_path}/$<TARGET_FILE_NAME:${target}>\n")
|
||||
configure_file(${rclcpp_components_NODE_TEMPLATE}
|
||||
${PROJECT_BINARY_DIR}/rclcpp_components/node_main_configured_${node}.cpp.in)
|
||||
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")
|
||||
install(TARGETS
|
||||
${node}
|
||||
DESTINATION lib/${PROJECT_NAME})
|
||||
endmacro()
|
||||
@@ -31,7 +31,8 @@
|
||||
* Note: NodeClass does not need to inherit from `rclcpp::Node`, but it is the easiest way.
|
||||
*/
|
||||
#define RCLCPP_COMPONENTS_REGISTER_NODE(NodeClass) \
|
||||
CLASS_LOADER_REGISTER_CLASS(rclcpp_components::NodeFactoryTemplate<NodeClass>, \
|
||||
CLASS_LOADER_REGISTER_CLASS( \
|
||||
rclcpp_components::NodeFactoryTemplate<NodeClass>, \
|
||||
rclcpp_components::NodeFactory)
|
||||
|
||||
#endif // RCLCPP_COMPONENTS__REGISTER_NODE_MACRO_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_components</name>
|
||||
<version>0.7.5</version>
|
||||
<version>0.8.0</version>
|
||||
<description>Package containing tools for dynamically loadable components</description>
|
||||
<maintainer email="michael@openrobotics.org">Michael Carroll</maintainer>
|
||||
<license>Apache License 2.0</license>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user