Compare commits
33 Commits
release-al
...
release-be
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d00a441195 | ||
|
|
2c6d95946e | ||
|
|
d241a730fe | ||
|
|
cc98d00add | ||
|
|
e2f53b09b4 | ||
|
|
734ac278db | ||
|
|
2309e5e250 | ||
|
|
3fe1924c63 | ||
|
|
3405f489d3 | ||
|
|
1b5168195b | ||
|
|
a987f8d015 | ||
|
|
aa2d0a3954 | ||
|
|
5894a9cd4e | ||
|
|
80fc2a59cd | ||
|
|
d12154b1f9 | ||
|
|
a06a397cc6 | ||
|
|
4c876d5966 | ||
|
|
da14d88cd6 | ||
|
|
01317def07 | ||
|
|
74505f25fa | ||
|
|
ec71e6562e | ||
|
|
7f714a8601 | ||
|
|
7494350ad2 | ||
|
|
d158dd46db | ||
|
|
a71ce25a5a | ||
|
|
f28bb11078 | ||
|
|
29a1bd44dc | ||
|
|
4e74edf8d4 | ||
|
|
6ea435f743 | ||
|
|
902d558e64 | ||
|
|
1402715d76 | ||
|
|
8c5f6e4e06 | ||
|
|
2401c0f197 |
@@ -9,9 +9,11 @@ find_package(rmw REQUIRED)
|
||||
find_package(rmw_implementation REQUIRED)
|
||||
find_package(rmw_implementation_cmake REQUIRED)
|
||||
find_package(rosidl_generator_cpp REQUIRED)
|
||||
find_package(rosidl_typesupport_cpp REQUIRED)
|
||||
|
||||
if(NOT WIN32)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -Wextra")
|
||||
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-std=c++14")
|
||||
add_compile_options(-Wall -Wextra -Wpedantic)
|
||||
endif()
|
||||
|
||||
include_directories(include)
|
||||
@@ -33,11 +35,17 @@ set(${PROJECT_NAME}_SRCS
|
||||
src/rclcpp/intra_process_manager_impl.cpp
|
||||
src/rclcpp/memory_strategies.cpp
|
||||
src/rclcpp/memory_strategy.cpp
|
||||
src/rclcpp/node.cpp
|
||||
src/rclcpp/node_interfaces/node_base.cpp
|
||||
src/rclcpp/node_interfaces/node_graph.cpp
|
||||
src/rclcpp/node_interfaces/node_parameters.cpp
|
||||
src/rclcpp/node_interfaces/node_services.cpp
|
||||
src/rclcpp/node_interfaces/node_timers.cpp
|
||||
src/rclcpp/node_interfaces/node_topics.cpp
|
||||
src/rclcpp/parameter.cpp
|
||||
src/rclcpp/parameter_client.cpp
|
||||
src/rclcpp/parameter_service.cpp
|
||||
src/rclcpp/publisher.cpp
|
||||
src/rclcpp/node.cpp
|
||||
src/rclcpp/service.cpp
|
||||
src/rclcpp/subscription.cpp
|
||||
src/rclcpp/timer.cpp
|
||||
@@ -53,7 +61,8 @@ macro(target)
|
||||
${${PROJECT_NAME}_SRCS})
|
||||
ament_target_dependencies(${PROJECT_NAME}${target_suffix}
|
||||
"rcl${target_suffix}"
|
||||
"rosidl_generator_cpp")
|
||||
"rosidl_generator_cpp"
|
||||
"rosidl_typesupport_cpp")
|
||||
|
||||
# Causes the visibility macros to use dllexport rather than dllimport,
|
||||
# which is appropriate when building the dll but not consuming it.
|
||||
@@ -73,6 +82,7 @@ call_for_each_rmw_implementation(target GENERATE_DEFAULT)
|
||||
ament_export_dependencies(ament_cmake)
|
||||
ament_export_dependencies(rcl)
|
||||
ament_export_dependencies(rosidl_generator_cpp)
|
||||
ament_export_dependencies(rosidl_typesupport_cpp)
|
||||
|
||||
ament_export_include_directories(include)
|
||||
|
||||
@@ -88,6 +98,7 @@ if(BUILD_TESTING)
|
||||
${rcl_interfaces_INCLUDE_DIRS}
|
||||
${rmw_INCLUDE_DIRS}
|
||||
${rosidl_generator_cpp_INCLUDE_DIRS}
|
||||
${rosidl_typesupport_cpp_INCLUDE_DIRS}
|
||||
)
|
||||
endif()
|
||||
ament_add_gtest(test_mapped_ring_buffer test/test_mapped_ring_buffer.cpp)
|
||||
@@ -97,6 +108,7 @@ if(BUILD_TESTING)
|
||||
${rcl_interfaces_INCLUDE_DIRS}
|
||||
${rmw_INCLUDE_DIRS}
|
||||
${rosidl_generator_cpp_INCLUDE_DIRS}
|
||||
${rosidl_typesupport_cpp_INCLUDE_DIRS}
|
||||
)
|
||||
endif()
|
||||
ament_add_gtest(test_intra_process_manager test/test_intra_process_manager.cpp)
|
||||
@@ -106,6 +118,7 @@ if(BUILD_TESTING)
|
||||
${rcl_interfaces_INCLUDE_DIRS}
|
||||
${rmw_INCLUDE_DIRS}
|
||||
${rosidl_generator_cpp_INCLUDE_DIRS}
|
||||
${rosidl_typesupport_cpp_INCLUDE_DIRS}
|
||||
)
|
||||
endif()
|
||||
ament_add_gtest(test_rate test/test_rate.cpp
|
||||
@@ -115,11 +128,52 @@ if(BUILD_TESTING)
|
||||
${rcl_interfaces_INCLUDE_DIRS}
|
||||
${rmw_INCLUDE_DIRS}
|
||||
${rosidl_generator_cpp_INCLUDE_DIRS}
|
||||
${rosidl_typesupport_cpp_INCLUDE_DIRS}
|
||||
)
|
||||
target_link_libraries(test_rate
|
||||
${PROJECT_NAME}
|
||||
)
|
||||
endif()
|
||||
ament_add_gtest(test_find_weak_nodes test/test_find_weak_nodes.cpp)
|
||||
if(TARGET test_find_weak_nodes)
|
||||
target_include_directories(test_find_weak_nodes PUBLIC
|
||||
${rcl_INCLUDE_DIRS}
|
||||
)
|
||||
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}/$<CONFIGURATION>")
|
||||
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)
|
||||
target_include_directories(test_externally_defined_services PUBLIC
|
||||
${rcl_INCLUDE_DIRS}
|
||||
)
|
||||
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()
|
||||
endif()
|
||||
|
||||
ament_package(
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
# with the given prefix.
|
||||
#
|
||||
# :param rmw_implementation: the RMW implementation name
|
||||
# :type target: string
|
||||
# :type rmw_implementation: string
|
||||
# :param var_prefix: the prefix of all output variable names
|
||||
# :type var_prefix: string
|
||||
#
|
||||
@@ -69,7 +69,8 @@ macro(get_rclcpp_information rmw_implementation var_prefix)
|
||||
set(_exported_dependencies
|
||||
"rcl_interfaces"
|
||||
"rcl${target_suffix}"
|
||||
"rosidl_generator_cpp")
|
||||
"rosidl_generator_cpp"
|
||||
"rosidl_typesupport_cpp")
|
||||
set(${var_prefix}_DEFINITIONS)
|
||||
foreach(_dep ${_exported_dependencies})
|
||||
if(NOT ${_dep}_FOUND)
|
||||
|
||||
26
rclcpp/cmake/rclcpp_create_node_main.cmake
Normal file
26
rclcpp/cmake/rclcpp_create_node_main.cmake
Normal file
@@ -0,0 +1,26 @@
|
||||
# Copyright 2015 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.
|
||||
|
||||
|
||||
set(rclcpp_node_main_SRC "${rclcpp_DIR}/../../../src/rclcpp/node_main.cpp")
|
||||
|
||||
function(rclcpp_create_node_main node_library_target)
|
||||
if(NOT TARGET ${node_library_target})
|
||||
message(FATAL_ERROR "rclcpp_create_node_main() the first argument must be a valid target name")
|
||||
endif()
|
||||
set(executable_name_ ${node_library_target}_node)
|
||||
add_executable(${executable_name_} ${rclcpp_node_main_SRC})
|
||||
target_link_libraries(${executable_name_} ${node_library_target})
|
||||
install(TARGETS ${executable_name_} DESTINATION bin)
|
||||
endfunction()
|
||||
17
rclcpp/cmake/rclcpp_package_hook.cmake
Normal file
17
rclcpp/cmake/rclcpp_package_hook.cmake
Normal file
@@ -0,0 +1,17 @@
|
||||
# Copyright 2016 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.
|
||||
|
||||
# register node plugins
|
||||
ament_index_register_resource(
|
||||
"node_plugin" CONTENT "${_RCLCPP__NODE_PLUGINS}")
|
||||
61
rclcpp/cmake/rclcpp_register_node_plugins.cmake
Normal file
61
rclcpp/cmake/rclcpp_register_node_plugins.cmake
Normal file
@@ -0,0 +1,61 @@
|
||||
# Copyright 2016 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.
|
||||
|
||||
#
|
||||
# Register a node plugin with the ament resource index.
|
||||
#
|
||||
# The passed library can contain multiple plugins extending the node interface.
|
||||
#
|
||||
# :param target: the shared library target
|
||||
# :type target: string
|
||||
# :param ARGN: the unique plugin names being exported using class_loader
|
||||
# :type ARGN: list of strings
|
||||
#
|
||||
macro(rclcpp_register_node_plugins target)
|
||||
if(NOT TARGET ${target})
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"rclcpp_register_node_plugins() first argument "
|
||||
"'${target}' is not a target")
|
||||
endif()
|
||||
get_target_property(_target_type ${target} TYPE)
|
||||
if(NOT _target_type STREQUAL "SHARED_LIBRARY")
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"rclcpp_register_node_plugins() first argument "
|
||||
"'${target}' is not a shared library target")
|
||||
endif()
|
||||
|
||||
if(${ARGC} GREATER 0)
|
||||
_rclcpp_register_package_hook()
|
||||
set(_unique_names)
|
||||
foreach(_arg ${ARGN})
|
||||
if(_arg IN_LIST _unique_names)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"rclcpp_register_node_plugins() the plugin names "
|
||||
"must be unique (multiple '${_arg}')")
|
||||
endif()
|
||||
list(APPEND _unique_names "${_arg}")
|
||||
|
||||
if(WIN32)
|
||||
set(_path "bin")
|
||||
else()
|
||||
set(_path "lib")
|
||||
endif()
|
||||
set(_RCLCPP__NODE_PLUGINS
|
||||
"${_RCLCPP__NODE_PLUGINS}${_arg};${_path}/$<TARGET_FILE_NAME:${target}>\n")
|
||||
endforeach()
|
||||
endif()
|
||||
endmacro()
|
||||
@@ -74,6 +74,8 @@ rcl_allocator_t get_rcl_allocator(Alloc & allocator)
|
||||
rcl_allocator.deallocate = &retyped_deallocate<T, Alloc>;
|
||||
rcl_allocator.reallocate = &retyped_reallocate<T, Alloc>;
|
||||
rcl_allocator.state = &allocator;
|
||||
#else
|
||||
(void)allocator; // Remove warning
|
||||
#endif
|
||||
return rcl_allocator;
|
||||
}
|
||||
|
||||
@@ -17,8 +17,13 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "rclcpp/callback_group.hpp"
|
||||
#include "rclcpp/client.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/service.hpp"
|
||||
#include "rclcpp/subscription.hpp"
|
||||
#include "rclcpp/timer.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
@@ -28,7 +33,7 @@ namespace executor
|
||||
|
||||
struct AnyExecutable
|
||||
{
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(AnyExecutable);
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(AnyExecutable)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
AnyExecutable();
|
||||
@@ -44,7 +49,7 @@ struct AnyExecutable
|
||||
rclcpp::client::ClientBase::SharedPtr client;
|
||||
// These are used to keep the scope on the containing items
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr callback_group;
|
||||
rclcpp::node::Node::SharedPtr node;
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base;
|
||||
};
|
||||
|
||||
} // namespace executor
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "rclcpp/allocator/allocator_common.hpp"
|
||||
#include "rclcpp/function_traits.hpp"
|
||||
|
||||
@@ -30,10 +30,12 @@ namespace rclcpp
|
||||
{
|
||||
|
||||
// Forward declarations for friend statement in class CallbackGroup
|
||||
namespace node
|
||||
namespace node_interfaces
|
||||
{
|
||||
class Node;
|
||||
} // namespace node
|
||||
class NodeServices;
|
||||
class NodeTimers;
|
||||
class NodeTopics;
|
||||
} // namespace node_interfaces
|
||||
|
||||
namespace callback_group
|
||||
{
|
||||
@@ -46,10 +48,12 @@ enum class CallbackGroupType
|
||||
|
||||
class CallbackGroup
|
||||
{
|
||||
friend class rclcpp::node::Node;
|
||||
friend class rclcpp::node_interfaces::NodeServices;
|
||||
friend class rclcpp::node_interfaces::NodeTimers;
|
||||
friend class rclcpp::node_interfaces::NodeTopics;
|
||||
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(CallbackGroup);
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(CallbackGroup)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
explicit CallbackGroup(CallbackGroupType group_type);
|
||||
@@ -63,7 +67,7 @@ public:
|
||||
get_timer_ptrs() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
const std::vector<rclcpp::service::ServiceBase::SharedPtr> &
|
||||
const std::vector<rclcpp::service::ServiceBase::WeakPtr> &
|
||||
get_service_ptrs() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
@@ -78,8 +82,8 @@ public:
|
||||
const CallbackGroupType &
|
||||
type() const;
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(CallbackGroup);
|
||||
protected:
|
||||
RCLCPP_DISABLE_COPY(CallbackGroup)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
@@ -102,7 +106,7 @@ private:
|
||||
mutable std::mutex mutex_;
|
||||
std::vector<rclcpp::subscription::SubscriptionBase::WeakPtr> subscription_ptrs_;
|
||||
std::vector<rclcpp::timer::TimerBase::WeakPtr> timer_ptrs_;
|
||||
std::vector<rclcpp::service::ServiceBase::SharedPtr> service_ptrs_;
|
||||
std::vector<rclcpp::service::ServiceBase::WeakPtr> service_ptrs_;
|
||||
std::vector<rclcpp::client::ClientBase::WeakPtr> client_ptrs_;
|
||||
std::atomic_bool can_be_taken_from_;
|
||||
};
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
|
||||
#include "rclcpp/function_traits.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/node_graph_interface.hpp"
|
||||
#include "rclcpp/type_support_decl.hpp"
|
||||
#include "rclcpp/utilities.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
@@ -39,10 +40,10 @@
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
namespace node
|
||||
namespace node_interfaces
|
||||
{
|
||||
class Node;
|
||||
} // namespace node
|
||||
class NodeBaseInterface;
|
||||
} // namespace node_interfaces
|
||||
|
||||
namespace client
|
||||
{
|
||||
@@ -50,11 +51,12 @@ namespace client
|
||||
class ClientBase
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(ClientBase);
|
||||
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(ClientBase)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
ClientBase(
|
||||
std::shared_ptr<rclcpp::node::Node> parent_node,
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph,
|
||||
const std::string & service_name);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
@@ -88,7 +90,7 @@ public:
|
||||
std::shared_ptr<rmw_request_id_t> request_header, std::shared_ptr<void> response) = 0;
|
||||
|
||||
protected:
|
||||
RCLCPP_DISABLE_COPY(ClientBase);
|
||||
RCLCPP_DISABLE_COPY(ClientBase)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
@@ -98,7 +100,7 @@ protected:
|
||||
rcl_node_t *
|
||||
get_rcl_node_handle() const;
|
||||
|
||||
std::weak_ptr<rclcpp::node::Node> node_;
|
||||
rclcpp::node_interfaces::NodeGraphInterface::WeakPtr node_graph_;
|
||||
std::shared_ptr<rcl_node_t> node_handle_;
|
||||
|
||||
rcl_client_t client_handle_ = rcl_get_zero_initialized_client();
|
||||
@@ -124,15 +126,16 @@ public:
|
||||
using CallbackType = std::function<void(SharedFuture)>;
|
||||
using CallbackWithRequestType = std::function<void(SharedFutureWithRequest)>;
|
||||
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(Client);
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(Client)
|
||||
|
||||
Client(
|
||||
std::shared_ptr<rclcpp::node::Node> parent_node,
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph,
|
||||
const std::string & service_name,
|
||||
rcl_client_options_t & client_options)
|
||||
: ClientBase(parent_node, service_name)
|
||||
: ClientBase(node_base, node_graph, service_name)
|
||||
{
|
||||
using rosidl_generator_cpp::get_service_type_support_handle;
|
||||
using rosidl_typesupport_cpp::get_service_type_support_handle;
|
||||
auto service_type_support_handle =
|
||||
get_service_type_support_handle<ServiceT>();
|
||||
if (rcl_client_init(&client_handle_, this->get_rcl_node_handle(),
|
||||
@@ -250,7 +253,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(Client);
|
||||
RCLCPP_DISABLE_COPY(Client)
|
||||
|
||||
std::map<int64_t, std::tuple<SharedPromise, CallbackType, SharedFuture>> pending_requests_;
|
||||
std::mutex pending_requests_mutex_;
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <typeindex>
|
||||
#include <typeinfo>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
@@ -35,7 +36,7 @@ namespace context
|
||||
class Context
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(Context);
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(Context)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
Context();
|
||||
@@ -67,7 +68,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(Context);
|
||||
RCLCPP_DISABLE_COPY(Context)
|
||||
|
||||
std::unordered_map<std::type_index, std::shared_ptr<void>> sub_contexts_;
|
||||
std::mutex mutex_;
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace default_context
|
||||
class DefaultContext : public rclcpp::context::Context
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(DefaultContext);
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(DefaultContext)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
DefaultContext();
|
||||
|
||||
51
rclcpp/include/rclcpp/create_publisher.hpp
Normal file
51
rclcpp/include/rclcpp/create_publisher.hpp
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright 2016 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_PUBLISHER_HPP_
|
||||
#define RCLCPP__CREATE_PUBLISHER_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
|
||||
#include "rclcpp/publisher_factory.hpp"
|
||||
#include "rmw/qos_profiles.h"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
template<typename MessageT, typename AllocatorT, typename PublisherT>
|
||||
std::shared_ptr<PublisherT>
|
||||
create_publisher(
|
||||
rclcpp::node_interfaces::NodeTopicsInterface * node_topics,
|
||||
const std::string & topic_name,
|
||||
const rmw_qos_profile_t & qos_profile,
|
||||
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>(allocator),
|
||||
publisher_options,
|
||||
use_intra_process_comms);
|
||||
node_topics->add_publisher(pub);
|
||||
return std::dynamic_pointer_cast<PublisherT>(pub);
|
||||
}
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__CREATE_PUBLISHER_HPP_
|
||||
62
rclcpp/include/rclcpp/create_subscription.hpp
Normal file
62
rclcpp/include/rclcpp/create_subscription.hpp
Normal file
@@ -0,0 +1,62 @@
|
||||
// Copyright 2016 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_SUBSCRIPTION_HPP_
|
||||
#define RCLCPP__CREATE_SUBSCRIPTION_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
|
||||
#include "rclcpp/subscription_factory.hpp"
|
||||
#include "rmw/qos_profiles.h"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
template<typename MessageT, typename CallbackT, typename AllocatorT, typename SubscriptionT>
|
||||
typename rclcpp::subscription::Subscription<MessageT, AllocatorT>::SharedPtr
|
||||
create_subscription(
|
||||
rclcpp::node_interfaces::NodeTopicsInterface * node_topics,
|
||||
const std::string & topic_name,
|
||||
CallbackT && callback,
|
||||
const rmw_qos_profile_t & qos_profile,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group,
|
||||
bool ignore_local_publications,
|
||||
bool use_intra_process_comms,
|
||||
typename rclcpp::message_memory_strategy::MessageMemoryStrategy<MessageT, 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, SubscriptionT>(
|
||||
std::forward<CallbackT>(callback), 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);
|
||||
}
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__CREATE_SUBSCRIPTION_HPP_
|
||||
@@ -29,7 +29,7 @@ namespace event
|
||||
class Event
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(Event);
|
||||
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(Event)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
Event();
|
||||
@@ -47,7 +47,7 @@ public:
|
||||
check_and_clear();
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(Event);
|
||||
RCLCPP_DISABLE_COPY(Event)
|
||||
|
||||
std::atomic_bool state_;
|
||||
};
|
||||
|
||||
@@ -95,6 +95,22 @@ public:
|
||||
RCLInvalidArgument(const RCLErrorBase & base_exc, const std::string & prefix);
|
||||
};
|
||||
|
||||
/// Thrown when an invalid rclcpp::Event object or SharedPtr is encountered.
|
||||
class InvalidEventError : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
InvalidEventError()
|
||||
: std::runtime_error("event is invalid") {}
|
||||
};
|
||||
|
||||
/// Thrown when an unregistered rclcpp::Event is encountered where a registered one was expected.
|
||||
class EventNotRegisteredError : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
EventNotRegisteredError()
|
||||
: std::runtime_error("event already registered") {}
|
||||
};
|
||||
|
||||
} // namespace exceptions
|
||||
} // namespace rclcpp
|
||||
|
||||
|
||||
@@ -28,16 +28,21 @@
|
||||
#include "rcl/guard_condition.h"
|
||||
#include "rcl/wait.h"
|
||||
|
||||
#include "rclcpp/any_executable.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/memory_strategies.hpp"
|
||||
#include "rclcpp/memory_strategy.hpp"
|
||||
#include "rclcpp/node.hpp"
|
||||
#include "rclcpp/utilities.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
// Forward declaration is used in convenience method signature.
|
||||
namespace node
|
||||
{
|
||||
class Node;
|
||||
} // namespace node
|
||||
|
||||
namespace executor
|
||||
{
|
||||
|
||||
@@ -88,7 +93,7 @@ static inline ExecutorArgs create_default_executor_arguments()
|
||||
class Executor
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(Executor);
|
||||
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(Executor)
|
||||
|
||||
/// Default constructor.
|
||||
// \param[in] ms The memory strategy to be used with this executor.
|
||||
@@ -114,7 +119,12 @@ public:
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual void
|
||||
add_node(rclcpp::node::Node::SharedPtr node_ptr, bool notify = true);
|
||||
add_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr, bool notify = true);
|
||||
|
||||
/// Convenience function which takes Node and forwards NodeBaseInterface.
|
||||
RCLCPP_PUBLIC
|
||||
virtual void
|
||||
add_node(std::shared_ptr<rclcpp::node::Node> node_ptr, bool notify = true);
|
||||
|
||||
/// Remove a node from the executor.
|
||||
/**
|
||||
@@ -125,7 +135,12 @@ public:
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual void
|
||||
remove_node(rclcpp::node::Node::SharedPtr node_ptr, bool notify = true);
|
||||
remove_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr, bool notify = true);
|
||||
|
||||
/// Convenience function which takes Node and forwards NodeBaseInterface.
|
||||
RCLCPP_PUBLIC
|
||||
virtual void
|
||||
remove_node(std::shared_ptr<rclcpp::node::Node> node_ptr, bool notify = true);
|
||||
|
||||
/// Add a node to executor, execute the next available unit of work, and remove the node.
|
||||
/**
|
||||
@@ -136,7 +151,7 @@ public:
|
||||
*/
|
||||
template<typename T = std::milli>
|
||||
void
|
||||
spin_node_once(rclcpp::node::Node::SharedPtr node,
|
||||
spin_node_once(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node,
|
||||
std::chrono::duration<int64_t, T> timeout = std::chrono::duration<int64_t, T>(-1))
|
||||
{
|
||||
return spin_node_once_nanoseconds(
|
||||
@@ -145,13 +160,30 @@ public:
|
||||
);
|
||||
}
|
||||
|
||||
/// Convenience function which takes Node and forwards NodeBaseInterface.
|
||||
template<typename NodeT = rclcpp::node::Node, typename T = std::milli>
|
||||
void
|
||||
spin_node_once(std::shared_ptr<NodeT> node,
|
||||
std::chrono::duration<int64_t, T> timeout = std::chrono::duration<int64_t, T>(-1))
|
||||
{
|
||||
return spin_node_once_nanoseconds(
|
||||
node->get_node_base_interface(),
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
|
||||
);
|
||||
}
|
||||
|
||||
/// Add a node, complete all immediately available work, and remove the node.
|
||||
/**
|
||||
* \param[in] node Shared pointer to the node to add.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
spin_node_some(rclcpp::node::Node::SharedPtr node);
|
||||
spin_node_some(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node);
|
||||
|
||||
/// Convenience function which takes Node and forwards NodeBaseInterface.
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
spin_node_some(std::shared_ptr<rclcpp::node::Node> node);
|
||||
|
||||
/// Complete all available queued work without blocking.
|
||||
/**
|
||||
@@ -247,7 +279,9 @@ public:
|
||||
protected:
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
spin_node_once_nanoseconds(rclcpp::node::Node::SharedPtr node, std::chrono::nanoseconds timeout);
|
||||
spin_node_once_nanoseconds(
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node,
|
||||
std::chrono::nanoseconds timeout);
|
||||
|
||||
/// Find the next available executable and do the work associated with it.
|
||||
/** \param[in] any_exec Union structure that can hold any executable type (timer, subscription,
|
||||
@@ -284,7 +318,7 @@ protected:
|
||||
wait_for_work(std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::node::Node::SharedPtr
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr
|
||||
get_node_by_group(rclcpp::callback_group::CallbackGroup::SharedPtr group);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
@@ -316,9 +350,9 @@ protected:
|
||||
memory_strategy::MemoryStrategy::SharedPtr memory_strategy_;
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(Executor);
|
||||
RCLCPP_DISABLE_COPY(Executor)
|
||||
|
||||
std::vector<std::weak_ptr<rclcpp::node::Node>> weak_nodes_;
|
||||
std::vector<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr> weak_nodes_;
|
||||
};
|
||||
|
||||
} // namespace executor
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#define RCLCPP__EXECUTORS_HPP_
|
||||
|
||||
#include <future>
|
||||
#include <memory>
|
||||
|
||||
#include "rclcpp/executors/multi_threaded_executor.hpp"
|
||||
#include "rclcpp/executors/single_threaded_executor.hpp"
|
||||
@@ -30,13 +31,21 @@ namespace rclcpp
|
||||
// \param[in] node_ptr Shared pointer to the node to spin.
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
spin_some(node::Node::SharedPtr node_ptr);
|
||||
spin_some(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
spin_some(rclcpp::node::Node::SharedPtr node_ptr);
|
||||
|
||||
/// Create a default single-threaded executor and spin the specified node.
|
||||
// \param[in] node_ptr Shared pointer to the node to spin.
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
spin(node::Node::SharedPtr node_ptr);
|
||||
spin(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
spin(rclcpp::node::Node::SharedPtr node_ptr);
|
||||
|
||||
namespace executors
|
||||
{
|
||||
@@ -57,7 +66,8 @@ using rclcpp::executors::single_threaded_executor::SingleThreadedExecutor;
|
||||
template<typename ResponseT, typename TimeT = std::milli>
|
||||
rclcpp::executor::FutureReturnCode
|
||||
spin_node_until_future_complete(
|
||||
rclcpp::executor::Executor & executor, rclcpp::node::Node::SharedPtr node_ptr,
|
||||
rclcpp::executor::Executor & executor,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
|
||||
std::shared_future<ResponseT> & future,
|
||||
std::chrono::duration<int64_t, TimeT> timeout = std::chrono::duration<int64_t, TimeT>(-1))
|
||||
{
|
||||
@@ -69,18 +79,44 @@ spin_node_until_future_complete(
|
||||
return retcode;
|
||||
}
|
||||
|
||||
template<typename NodeT = rclcpp::node::Node, typename ResponseT, typename TimeT = std::milli>
|
||||
rclcpp::executor::FutureReturnCode
|
||||
spin_node_until_future_complete(
|
||||
rclcpp::executor::Executor & executor,
|
||||
std::shared_ptr<NodeT> node_ptr,
|
||||
std::shared_future<ResponseT> & future,
|
||||
std::chrono::duration<int64_t, TimeT> timeout = std::chrono::duration<int64_t, TimeT>(-1))
|
||||
{
|
||||
return rclcpp::executors::spin_node_until_future_complete(
|
||||
executor,
|
||||
node_ptr->get_node_base_interface(),
|
||||
future,
|
||||
timeout);
|
||||
}
|
||||
|
||||
} // namespace executors
|
||||
|
||||
template<typename FutureT, typename TimeT = std::milli>
|
||||
rclcpp::executor::FutureReturnCode
|
||||
spin_until_future_complete(
|
||||
node::Node::SharedPtr node_ptr, std::shared_future<FutureT> & future,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
|
||||
std::shared_future<FutureT> & future,
|
||||
std::chrono::duration<int64_t, TimeT> timeout = std::chrono::duration<int64_t, TimeT>(-1))
|
||||
{
|
||||
rclcpp::executors::SingleThreadedExecutor executor;
|
||||
return executors::spin_node_until_future_complete<FutureT>(executor, node_ptr, future, timeout);
|
||||
}
|
||||
|
||||
template<typename NodeT = rclcpp::node::Node, typename FutureT, typename TimeT = std::milli>
|
||||
rclcpp::executor::FutureReturnCode
|
||||
spin_until_future_complete(
|
||||
std::shared_ptr<NodeT> node_ptr,
|
||||
std::shared_future<FutureT> & future,
|
||||
std::chrono::duration<int64_t, TimeT> timeout = std::chrono::duration<int64_t, TimeT>(-1))
|
||||
{
|
||||
return rclcpp::spin_until_future_complete(node_ptr->get_node_base_interface(), future, timeout);
|
||||
}
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__EXECUTORS_HPP_
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace multi_threaded_executor
|
||||
class MultiThreadedExecutor : public executor::Executor
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(MultiThreadedExecutor);
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(MultiThreadedExecutor)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
MultiThreadedExecutor(
|
||||
@@ -57,7 +57,7 @@ protected:
|
||||
run(size_t this_thread_number);
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(MultiThreadedExecutor);
|
||||
RCLCPP_DISABLE_COPY(MultiThreadedExecutor)
|
||||
|
||||
std::mutex wait_mutex_;
|
||||
size_t number_of_threads_;
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace single_threaded_executor
|
||||
class SingleThreadedExecutor : public executor::Executor
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(SingleThreadedExecutor);
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(SingleThreadedExecutor)
|
||||
|
||||
/// Default constructor. See the default constructor for Executor.
|
||||
RCLCPP_PUBLIC
|
||||
@@ -61,7 +61,7 @@ public:
|
||||
spin();
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(SingleThreadedExecutor);
|
||||
RCLCPP_DISABLE_COPY(SingleThreadedExecutor)
|
||||
};
|
||||
|
||||
} // namespace single_threaded_executor
|
||||
|
||||
@@ -24,16 +24,12 @@
|
||||
#include "rcl/guard_condition.h"
|
||||
#include "rcl/wait.h"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/node_graph_interface.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
namespace node
|
||||
{
|
||||
class Node;
|
||||
} // namespace node
|
||||
|
||||
namespace graph_listener
|
||||
{
|
||||
|
||||
@@ -91,7 +87,7 @@ public:
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
add_node(rclcpp::node::Node * node);
|
||||
add_node(rclcpp::node_interfaces::NodeGraphInterface * node_graph);
|
||||
|
||||
/// Return true if the given node is in the graph listener's list of nodes.
|
||||
/* Also return false if given nullptr.
|
||||
@@ -101,7 +97,7 @@ public:
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
bool
|
||||
has_node(rclcpp::node::Node * node);
|
||||
has_node(rclcpp::node_interfaces::NodeGraphInterface * node_graph);
|
||||
|
||||
/// Remove a node from the graph listener's list of nodes.
|
||||
/*
|
||||
@@ -112,7 +108,7 @@ public:
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
remove_node(rclcpp::node::Node * node);
|
||||
remove_node(rclcpp::node_interfaces::NodeGraphInterface * node_graph);
|
||||
|
||||
/// Stop the listening thread.
|
||||
/* The thread cannot be restarted, and the class is defunct after calling.
|
||||
@@ -152,16 +148,16 @@ protected:
|
||||
run_loop();
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(GraphListener);
|
||||
RCLCPP_DISABLE_COPY(GraphListener)
|
||||
|
||||
std::thread listener_thread_;
|
||||
bool is_started_;
|
||||
std::atomic_bool is_shutdown_;
|
||||
mutable std::mutex shutdown_mutex_;
|
||||
|
||||
mutable std::mutex nodes_barrier_mutex_;
|
||||
mutable std::mutex nodes_mutex_;
|
||||
std::vector<rclcpp::node::Node *> nodes_;
|
||||
mutable std::mutex node_graph_interfaces_barrier_mutex_;
|
||||
mutable std::mutex node_graph_interfaces_mutex_;
|
||||
std::vector<rclcpp::node_interfaces::NodeGraphInterface *> node_graph_interfaces_;
|
||||
|
||||
rcl_guard_condition_t interrupt_guard_condition_ = rcl_get_zero_initialized_guard_condition();
|
||||
rcl_guard_condition_t * shutdown_guard_condition_;
|
||||
|
||||
@@ -120,10 +120,10 @@ namespace intra_process_manager
|
||||
class IntraProcessManager
|
||||
{
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(IntraProcessManager);
|
||||
RCLCPP_DISABLE_COPY(IntraProcessManager)
|
||||
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(IntraProcessManager);
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(IntraProcessManager)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
explicit IntraProcessManager(
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <atomic>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
@@ -41,7 +42,7 @@ namespace intra_process_manager
|
||||
class IntraProcessManagerImplBase
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(IntraProcessManagerImplBase);
|
||||
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(IntraProcessManagerImplBase)
|
||||
|
||||
IntraProcessManagerImplBase() = default;
|
||||
~IntraProcessManagerImplBase() = default;
|
||||
@@ -78,7 +79,7 @@ public:
|
||||
matches_any_publishers(const rmw_gid_t * id) const = 0;
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(IntraProcessManagerImplBase);
|
||||
RCLCPP_DISABLE_COPY(IntraProcessManagerImplBase)
|
||||
};
|
||||
|
||||
template<typename Allocator = std::allocator<void>>
|
||||
@@ -92,6 +93,8 @@ public:
|
||||
add_subscription(uint64_t id, subscription::SubscriptionBase::SharedPtr subscription)
|
||||
{
|
||||
subscriptions_[id] = subscription;
|
||||
// subscription->get_topic_name() -> const char * can be used as the key,
|
||||
// since subscriptions_ shares the ownership of subscription
|
||||
subscription_ids_by_topic_[subscription->get_topic_name()].insert(id);
|
||||
}
|
||||
|
||||
@@ -242,7 +245,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(IntraProcessManagerImpl);
|
||||
RCLCPP_DISABLE_COPY(IntraProcessManagerImpl)
|
||||
|
||||
template<typename T>
|
||||
using RebindAlloc = typename std::allocator_traits<Allocator>::template rebind_alloc<T>;
|
||||
@@ -253,8 +256,20 @@ private:
|
||||
using SubscriptionMap = std::unordered_map<uint64_t, subscription::SubscriptionBase::WeakPtr,
|
||||
std::hash<uint64_t>, std::equal_to<uint64_t>,
|
||||
RebindAlloc<std::pair<const uint64_t, subscription::SubscriptionBase::WeakPtr>>>;
|
||||
using IDTopicMap = std::map<std::string, AllocSet,
|
||||
std::less<std::string>, RebindAlloc<std::pair<std::string, AllocSet>>>;
|
||||
|
||||
struct strcmp_wrapper : public std::binary_function<const char *, const char *, bool>
|
||||
{
|
||||
bool
|
||||
operator()(const char * lhs, const char * rhs) const
|
||||
{
|
||||
return std::strcmp(lhs, rhs) < 0;
|
||||
}
|
||||
};
|
||||
using IDTopicMap = std::map<
|
||||
const char *,
|
||||
AllocSet,
|
||||
strcmp_wrapper,
|
||||
RebindAlloc<std::pair<const std::string, AllocSet>>>;
|
||||
|
||||
SubscriptionMap subscriptions_;
|
||||
|
||||
@@ -262,7 +277,7 @@ private:
|
||||
|
||||
struct PublisherInfo
|
||||
{
|
||||
RCLCPP_DISABLE_COPY(PublisherInfo);
|
||||
RCLCPP_DISABLE_COPY(PublisherInfo)
|
||||
|
||||
PublisherInfo() = default;
|
||||
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#ifndef RCLCPP__MACROS_HPP_
|
||||
#define RCLCPP__MACROS_HPP_
|
||||
|
||||
@@ -47,7 +50,23 @@
|
||||
RCLCPP_WEAK_PTR_DEFINITIONS(__VA_ARGS__) \
|
||||
__RCLCPP_UNIQUE_PTR_ALIAS(__VA_ARGS__)
|
||||
|
||||
#define __RCLCPP_SHARED_PTR_ALIAS(...) using SharedPtr = std::shared_ptr<__VA_ARGS__>;
|
||||
/* Defines aliases only for using the Class with smart pointers.
|
||||
*
|
||||
* Same as RCLCPP_SMART_PTR_DEFINITIONS expect it excludes the static
|
||||
* method definitions which do not work on pure virtual classes and classes
|
||||
* which are not CopyConstructable.
|
||||
*
|
||||
* Use in the public section of the class.
|
||||
* Make sure to include <memory> in the header when using this.
|
||||
*/
|
||||
#define RCLCPP_SMART_PTR_ALIASES_ONLY(...) \
|
||||
__RCLCPP_SHARED_PTR_ALIAS(__VA_ARGS__) \
|
||||
__RCLCPP_WEAK_PTR_ALIAS(__VA_ARGS__) \
|
||||
__RCLCPP_MAKE_SHARED_DEFINITION(__VA_ARGS__)
|
||||
|
||||
#define __RCLCPP_SHARED_PTR_ALIAS(...) \
|
||||
using SharedPtr = std::shared_ptr<__VA_ARGS__>; \
|
||||
using ConstSharedPtr = std::shared_ptr<const __VA_ARGS__>;
|
||||
|
||||
#define __RCLCPP_MAKE_SHARED_DEFINITION(...) \
|
||||
template<typename ... Args> \
|
||||
@@ -62,7 +81,9 @@
|
||||
__RCLCPP_SHARED_PTR_ALIAS(__VA_ARGS__) \
|
||||
__RCLCPP_MAKE_SHARED_DEFINITION(__VA_ARGS__)
|
||||
|
||||
#define __RCLCPP_WEAK_PTR_ALIAS(...) using WeakPtr = std::weak_ptr<__VA_ARGS__>;
|
||||
#define __RCLCPP_WEAK_PTR_ALIAS(...) \
|
||||
using WeakPtr = std::weak_ptr<__VA_ARGS__>; \
|
||||
using ConstWeakPtr = std::weak_ptr<const __VA_ARGS__>;
|
||||
|
||||
/// Defines aliases and static functions for using the Class with weak_ptrs.
|
||||
#define RCLCPP_WEAK_PTR_DEFINITIONS(...) __RCLCPP_WEAK_PTR_ALIAS(__VA_ARGS__)
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "rclcpp/allocator/allocator_common.hpp"
|
||||
@@ -34,7 +35,7 @@ namespace mapped_ring_buffer
|
||||
class RCLCPP_PUBLIC MappedRingBufferBase
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(MappedRingBufferBase);
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(MappedRingBufferBase)
|
||||
};
|
||||
|
||||
/// Ring buffer container of unique_ptr's of T, which can be accessed by a key.
|
||||
@@ -57,7 +58,7 @@ template<typename T, typename Alloc = std::allocator<void>>
|
||||
class MappedRingBuffer : public MappedRingBufferBase
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(MappedRingBuffer<T, Alloc>);
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(MappedRingBuffer<T, Alloc>)
|
||||
using ElemAllocTraits = allocator::AllocRebind<T, Alloc>;
|
||||
using ElemAlloc = typename ElemAllocTraits::allocator_type;
|
||||
using ElemDeleter = allocator::Deleter<ElemAlloc, T>;
|
||||
@@ -206,7 +207,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(MappedRingBuffer<T, Alloc>);
|
||||
RCLCPP_DISABLE_COPY(MappedRingBuffer<T, Alloc>)
|
||||
|
||||
struct element
|
||||
{
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
|
||||
#include "rclcpp/any_executable.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
@@ -40,8 +40,8 @@ namespace memory_strategy
|
||||
class RCLCPP_PUBLIC MemoryStrategy
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(MemoryStrategy);
|
||||
using WeakNodeVector = std::vector<std::weak_ptr<rclcpp::node::Node>>;
|
||||
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(MemoryStrategy)
|
||||
using WeakNodeVector = std::vector<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr>;
|
||||
|
||||
virtual bool collect_entities(const WeakNodeVector & weak_nodes) = 0;
|
||||
|
||||
@@ -88,7 +88,7 @@ public:
|
||||
static rclcpp::client::ClientBase::SharedPtr
|
||||
get_client_by_handle(const rcl_client_t * client_handle, const WeakNodeVector & weak_nodes);
|
||||
|
||||
static rclcpp::node::Node::SharedPtr
|
||||
static rclcpp::node_interfaces::NodeBaseInterface::SharedPtr
|
||||
get_node_by_group(rclcpp::callback_group::CallbackGroup::SharedPtr group,
|
||||
const WeakNodeVector & weak_nodes);
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ template<typename MessageT, typename Alloc = std::allocator<void>>
|
||||
class MessageMemoryStrategy
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(MessageMemoryStrategy);
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(MessageMemoryStrategy)
|
||||
|
||||
using MessageAllocTraits = allocator::AllocRebind<MessageT, Alloc>;
|
||||
using MessageAlloc = typename MessageAllocTraits::allocator_type;
|
||||
|
||||
@@ -39,6 +39,12 @@
|
||||
#include "rclcpp/event.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/message_memory_strategy.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_graph_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_parameters_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_services_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_timers_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
|
||||
#include "rclcpp/parameter.hpp"
|
||||
#include "rclcpp/publisher.hpp"
|
||||
#include "rclcpp/service.hpp"
|
||||
@@ -46,41 +52,17 @@
|
||||
#include "rclcpp/timer.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rcl
|
||||
{
|
||||
struct rcl_node_t;
|
||||
} // namespace rcl
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
namespace graph_listener
|
||||
{
|
||||
class GraphListener;
|
||||
} // namespace graph_listener
|
||||
|
||||
namespace node
|
||||
{
|
||||
|
||||
class InvalidEventError : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
InvalidEventError()
|
||||
: std::runtime_error("event is invalid") {}
|
||||
};
|
||||
|
||||
class EventNotRegisteredError : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
EventNotRegisteredError()
|
||||
: std::runtime_error("event already registered") {}
|
||||
};
|
||||
|
||||
/// Node is the single point of entry for creating publishers and subscribers.
|
||||
class Node : public std::enable_shared_from_this<Node>
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(Node);
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(Node)
|
||||
|
||||
/// Create a new node with the specified name.
|
||||
/**
|
||||
@@ -109,7 +91,7 @@ public:
|
||||
/// Get the name of the node.
|
||||
// \return The name of the node.
|
||||
RCLCPP_PUBLIC
|
||||
const std::string &
|
||||
const char *
|
||||
get_name() const;
|
||||
|
||||
/// Create and return a callback group.
|
||||
@@ -117,14 +99,21 @@ public:
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr
|
||||
create_callback_group(rclcpp::callback_group::CallbackGroupType group_type);
|
||||
|
||||
/// Return the list of callback groups in the node.
|
||||
RCLCPP_PUBLIC
|
||||
const std::vector<rclcpp::callback_group::CallbackGroup::WeakPtr> &
|
||||
get_callback_groups() const;
|
||||
|
||||
/// 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.
|
||||
* \return Shared pointer to the created publisher.
|
||||
*/
|
||||
template<typename MessageT, typename Alloc = std::allocator<void>>
|
||||
typename rclcpp::publisher::Publisher<MessageT, Alloc>::SharedPtr
|
||||
template<
|
||||
typename MessageT, typename Alloc = std::allocator<void>,
|
||||
typename PublisherT = ::rclcpp::publisher::Publisher<MessageT, Alloc>>
|
||||
std::shared_ptr<PublisherT>
|
||||
create_publisher(
|
||||
const std::string & topic_name, size_t qos_history_depth,
|
||||
std::shared_ptr<Alloc> allocator = nullptr);
|
||||
@@ -135,8 +124,10 @@ public:
|
||||
* \param[in] qos_profile The quality of service profile to pass on to the rmw implementation.
|
||||
* \return Shared pointer to the created publisher.
|
||||
*/
|
||||
template<typename MessageT, typename Alloc = std::allocator<void>>
|
||||
typename rclcpp::publisher::Publisher<MessageT, Alloc>::SharedPtr
|
||||
template<
|
||||
typename MessageT, typename Alloc = std::allocator<void>,
|
||||
typename PublisherT = ::rclcpp::publisher::Publisher<MessageT, Alloc>>
|
||||
std::shared_ptr<PublisherT>
|
||||
create_publisher(
|
||||
const std::string & topic_name,
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_default,
|
||||
@@ -156,8 +147,12 @@ public:
|
||||
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 rclcpp::subscription::Subscription<MessageT, Alloc>::SharedPtr
|
||||
template<
|
||||
typename MessageT,
|
||||
typename CallbackT,
|
||||
typename Alloc = std::allocator<void>,
|
||||
typename SubscriptionT = rclcpp::subscription::Subscription<MessageT, Alloc>>
|
||||
std::shared_ptr<SubscriptionT>
|
||||
create_subscription(
|
||||
const std::string & topic_name,
|
||||
CallbackT && callback,
|
||||
@@ -182,8 +177,12 @@ public:
|
||||
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 rclcpp::subscription::Subscription<MessageT, Alloc>::SharedPtr
|
||||
template<
|
||||
typename MessageT,
|
||||
typename CallbackT,
|
||||
typename Alloc = std::allocator<void>,
|
||||
typename SubscriptionT = rclcpp::subscription::Subscription<MessageT, Alloc>>
|
||||
std::shared_ptr<SubscriptionT>
|
||||
create_subscription(
|
||||
const std::string & topic_name,
|
||||
size_t qos_history_depth,
|
||||
@@ -200,30 +199,13 @@ public:
|
||||
* \param[in] callback User-defined callback function.
|
||||
* \param[in] group Callback group to execute this timer's callback in.
|
||||
*/
|
||||
template<typename CallbackType>
|
||||
typename rclcpp::timer::WallTimer<CallbackType>::SharedPtr
|
||||
template<typename DurationT = std::milli, typename CallbackT>
|
||||
typename rclcpp::timer::WallTimer<CallbackT>::SharedPtr
|
||||
create_wall_timer(
|
||||
std::chrono::nanoseconds period,
|
||||
CallbackType callback,
|
||||
std::chrono::duration<int64_t, DurationT> period,
|
||||
CallbackT callback,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr);
|
||||
|
||||
/// Create a timer.
|
||||
/**
|
||||
* \param[in] period Time interval between triggers of the callback.
|
||||
* \param[in] callback User-defined callback function.
|
||||
* \param[in] group Callback group to execute this timer's callback in.
|
||||
*/
|
||||
// TODO(wjwwood): reenable this once I figure out why the demo doesn't build with it.
|
||||
// rclcpp::timer::WallTimer::SharedPtr
|
||||
// create_wall_timer(
|
||||
// std::chrono::duration<long double, std::nano> period,
|
||||
// rclcpp::timer::CallbackType callback,
|
||||
// rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr);
|
||||
|
||||
using CallbackGroup = rclcpp::callback_group::CallbackGroup;
|
||||
using CallbackGroupWeakPtr = std::weak_ptr<CallbackGroup>;
|
||||
using CallbackGroupWeakPtrList = std::list<CallbackGroupWeakPtr>;
|
||||
|
||||
/* Create and return a Client. */
|
||||
template<typename ServiceT>
|
||||
typename rclcpp::client::Client<ServiceT>::SharedPtr
|
||||
@@ -253,6 +235,20 @@ public:
|
||||
std::vector<rclcpp::parameter::ParameterVariant>
|
||||
get_parameters(const std::vector<std::string> & names) const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::parameter::ParameterVariant
|
||||
get_parameter(const std::string & name) const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
get_parameter(
|
||||
const std::string & name,
|
||||
rclcpp::parameter::ParameterVariant & parameter) const;
|
||||
|
||||
template<typename ParameterT>
|
||||
bool
|
||||
get_parameter(const std::string & name, ParameterT & parameter) const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
std::vector<rcl_interfaces::msg::ParameterDescriptor>
|
||||
describe_parameters(const std::vector<std::string> & names) const;
|
||||
@@ -265,6 +261,15 @@ public:
|
||||
rcl_interfaces::msg::ListParametersResult
|
||||
list_parameters(const std::vector<std::string> & prefixes, uint64_t depth) const;
|
||||
|
||||
/// Register the callback for parameter changes
|
||||
/**
|
||||
* \param[in] User defined callback function, It is expected to atomically set parameters.
|
||||
* \note Repeated invocations of this function will overwrite previous callbacks
|
||||
*/
|
||||
template<typename CallbackT>
|
||||
void
|
||||
register_param_change_callback(CallbackT && callback);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
std::map<std::string, std::string>
|
||||
get_topic_names_and_types() const;
|
||||
@@ -277,53 +282,6 @@ public:
|
||||
size_t
|
||||
count_subscribers(const std::string & topic_name) const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
const CallbackGroupWeakPtrList &
|
||||
get_callback_groups() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
const rcl_guard_condition_t *
|
||||
get_notify_guard_condition() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
const rcl_guard_condition_t *
|
||||
get_graph_guard_condition() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
const rcl_node_t *
|
||||
get_rcl_node_handle() const;
|
||||
|
||||
/// Return the rcl_node_t node handle (non-const version).
|
||||
RCLCPP_PUBLIC
|
||||
rcl_node_t *
|
||||
get_rcl_node_handle();
|
||||
|
||||
/// Return the rcl_node_t node handle in a std::shared_ptr.
|
||||
/* This handle remains valid after the Node is destroyed.
|
||||
* The actual rcl node is not finalized until it is out of scope everywhere.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
std::shared_ptr<rcl_node_t>
|
||||
get_shared_node_handle();
|
||||
|
||||
/// Notify threads waiting on graph changes.
|
||||
/* Affects threads waiting on the notify guard condition, see:
|
||||
* get_notify_guard_condition(), as well as the threads waiting on graph
|
||||
* changes using a graph Event, see: wait_for_graph_change().
|
||||
*
|
||||
* This is typically only used by the rclcpp::graph_listener::GraphListener.
|
||||
*
|
||||
* \throws RCLBaseError (a child of that exception) when an rcl error occurs
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
notify_graph_change();
|
||||
|
||||
/// Notify any and all blocking node actions that shutdown has occurred.
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
notify_shutdown();
|
||||
|
||||
/// Return a graph event, which will be set anytime a graph change occurs.
|
||||
/* The graph Event object is a loan which must be returned.
|
||||
* The Event object is scoped and therefore to return the load just let it go
|
||||
@@ -346,63 +304,51 @@ public:
|
||||
rclcpp::event::Event::SharedPtr event,
|
||||
std::chrono::nanoseconds timeout);
|
||||
|
||||
/// Return the number of on loan graph events, see get_graph_event().
|
||||
/* This is typically only used by the rclcpp::graph_listener::GraphListener.
|
||||
*/
|
||||
/// Return the Node's internal NodeBaseInterface implementation.
|
||||
RCLCPP_PUBLIC
|
||||
size_t
|
||||
count_graph_users();
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr
|
||||
get_node_base_interface();
|
||||
|
||||
std::atomic_bool has_executor;
|
||||
/// Return the Node's internal NodeGraphInterface implementation.
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr
|
||||
get_node_graph_interface();
|
||||
|
||||
/// Return the Node's internal NodeTimersInterface implementation.
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::node_interfaces::NodeTimersInterface::SharedPtr
|
||||
get_node_timers_interface();
|
||||
|
||||
/// Return the Node's internal NodeTopicsInterface implementation.
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr
|
||||
get_node_topics_interface();
|
||||
|
||||
/// Return the Node's internal NodeServicesInterface implementation.
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::node_interfaces::NodeServicesInterface::SharedPtr
|
||||
get_node_services_interface();
|
||||
|
||||
/// Return the Node's internal NodeParametersInterface implementation.
|
||||
RCLCPP_PUBLIC
|
||||
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr
|
||||
get_node_parameters_interface();
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(Node);
|
||||
RCLCPP_DISABLE_COPY(Node)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
bool
|
||||
group_in_node(callback_group::CallbackGroup::SharedPtr group);
|
||||
|
||||
std::string name_;
|
||||
|
||||
std::shared_ptr<rcl_node_t> node_handle_;
|
||||
|
||||
rclcpp::context::Context::SharedPtr context_;
|
||||
|
||||
CallbackGroup::SharedPtr default_callback_group_;
|
||||
CallbackGroupWeakPtrList callback_groups_;
|
||||
|
||||
size_t number_of_subscriptions_;
|
||||
size_t number_of_timers_;
|
||||
size_t number_of_services_;
|
||||
size_t number_of_clients_;
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_;
|
||||
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph_;
|
||||
rclcpp::node_interfaces::NodeTimersInterface::SharedPtr node_timers_;
|
||||
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics_;
|
||||
rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services_;
|
||||
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr node_parameters_;
|
||||
|
||||
bool use_intra_process_comms_;
|
||||
|
||||
mutable std::mutex mutex_;
|
||||
|
||||
/// Guard condition for notifying the Executor of changes to this node.
|
||||
mutable std::mutex notify_guard_condition_mutex_;
|
||||
rcl_guard_condition_t notify_guard_condition_ = rcl_get_zero_initialized_guard_condition();
|
||||
bool notify_guard_condition_is_valid_;
|
||||
|
||||
/// Graph Listener which waits on graph changes for the node and is shared across nodes.
|
||||
std::shared_ptr<rclcpp::graph_listener::GraphListener> graph_listener_;
|
||||
/// Whether or not this node needs to be added to the graph listener.
|
||||
std::atomic_bool should_add_to_graph_listener_;
|
||||
|
||||
/// Mutex to guard the graph event related data structures.
|
||||
std::mutex graph_mutex_;
|
||||
/// For notifying waiting threads (wait_for_graph_change()) on changes (notify_graph_change()).
|
||||
std::condition_variable graph_cv_;
|
||||
/// Weak references to graph events out on loan.
|
||||
std::vector<rclcpp::event::Event::WeakPtr> graph_events_;
|
||||
/// Number of graph events out on loan, used to determine if the graph should be monitored.
|
||||
/* graph_users_count_ is atomic so that it can be accessed without acquiring the graph_mutex_ */
|
||||
std::atomic_size_t graph_users_count_;
|
||||
|
||||
std::map<std::string, rclcpp::parameter::ParameterVariant> parameters_;
|
||||
|
||||
publisher::Publisher<rcl_interfaces::msg::ParameterEvent>::SharedPtr events_publisher_;
|
||||
};
|
||||
|
||||
} // namespace node
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
#include "rclcpp/contexts/default_context.hpp"
|
||||
#include "rclcpp/intra_process_manager.hpp"
|
||||
#include "rclcpp/parameter.hpp"
|
||||
#include "rclcpp/create_publisher.hpp"
|
||||
#include "rclcpp/create_subscription.hpp"
|
||||
#include "rclcpp/type_support_decl.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
@@ -50,8 +52,8 @@ namespace rclcpp
|
||||
namespace node
|
||||
{
|
||||
|
||||
template<typename MessageT, typename Alloc>
|
||||
typename rclcpp::publisher::Publisher<MessageT, Alloc>::SharedPtr
|
||||
template<typename MessageT, typename Alloc, typename PublisherT>
|
||||
std::shared_ptr<PublisherT>
|
||||
Node::create_publisher(
|
||||
const std::string & topic_name, size_t qos_history_depth,
|
||||
std::shared_ptr<Alloc> allocator)
|
||||
@@ -61,11 +63,11 @@ Node::create_publisher(
|
||||
}
|
||||
rmw_qos_profile_t qos = rmw_qos_profile_default;
|
||||
qos.depth = qos_history_depth;
|
||||
return this->create_publisher<MessageT, Alloc>(topic_name, qos, allocator);
|
||||
return this->create_publisher<MessageT, Alloc, PublisherT>(topic_name, qos, allocator);
|
||||
}
|
||||
|
||||
template<typename MessageT, typename Alloc>
|
||||
typename publisher::Publisher<MessageT, Alloc>::SharedPtr
|
||||
template<typename MessageT, typename Alloc, typename PublisherT>
|
||||
std::shared_ptr<PublisherT>
|
||||
Node::create_publisher(
|
||||
const std::string & topic_name, const rmw_qos_profile_t & qos_profile,
|
||||
std::shared_ptr<Alloc> allocator)
|
||||
@@ -73,67 +75,16 @@ Node::create_publisher(
|
||||
if (!allocator) {
|
||||
allocator = std::make_shared<Alloc>();
|
||||
}
|
||||
|
||||
auto publisher_options = rcl_publisher_get_default_options();
|
||||
publisher_options.qos = qos_profile;
|
||||
|
||||
auto message_alloc =
|
||||
std::make_shared<typename publisher::Publisher<MessageT, Alloc>::MessageAlloc>(
|
||||
*allocator.get());
|
||||
publisher_options.allocator = allocator::get_rcl_allocator<MessageT>(
|
||||
*message_alloc.get());
|
||||
|
||||
auto publisher = publisher::Publisher<MessageT, Alloc>::make_shared(
|
||||
node_handle_, topic_name, publisher_options, message_alloc);
|
||||
|
||||
if (use_intra_process_comms_) {
|
||||
auto intra_process_manager =
|
||||
context_->get_sub_context<rclcpp::intra_process_manager::IntraProcessManager>();
|
||||
uint64_t intra_process_publisher_id =
|
||||
intra_process_manager->add_publisher<MessageT, Alloc>(publisher);
|
||||
rclcpp::intra_process_manager::IntraProcessManager::WeakPtr weak_ipm = intra_process_manager;
|
||||
// *INDENT-OFF*
|
||||
auto shared_publish_callback =
|
||||
[weak_ipm](uint64_t publisher_id, void * msg, const std::type_info & type_info) -> uint64_t
|
||||
{
|
||||
auto ipm = weak_ipm.lock();
|
||||
if (!ipm) {
|
||||
// TODO(wjwwood): should this just return silently? Or maybe return with a logged warning?
|
||||
throw std::runtime_error(
|
||||
"intra process publish called after destruction of intra process manager");
|
||||
}
|
||||
if (!msg) {
|
||||
throw std::runtime_error("cannot publisher msg which is a null pointer");
|
||||
}
|
||||
auto & message_type_info = typeid(MessageT);
|
||||
if (message_type_info != type_info) {
|
||||
throw std::runtime_error(
|
||||
std::string("published type '") + type_info.name() +
|
||||
"' is incompatible from the publisher type '" + message_type_info.name() + "'");
|
||||
}
|
||||
MessageT * typed_message_ptr = static_cast<MessageT *>(msg);
|
||||
using MessageDeleter = typename publisher::Publisher<MessageT, Alloc>::MessageDeleter;
|
||||
std::unique_ptr<MessageT, MessageDeleter> unique_msg(typed_message_ptr);
|
||||
uint64_t message_seq =
|
||||
ipm->store_intra_process_message<MessageT, Alloc>(publisher_id, unique_msg);
|
||||
return message_seq;
|
||||
};
|
||||
// *INDENT-ON*
|
||||
publisher->setup_intra_process(
|
||||
intra_process_publisher_id,
|
||||
shared_publish_callback,
|
||||
publisher_options);
|
||||
}
|
||||
if (rcl_trigger_guard_condition(¬ify_guard_condition_) != RCL_RET_OK) {
|
||||
throw std::runtime_error(
|
||||
std::string(
|
||||
"Failed to notify waitset on publisher creation: ") + rmw_get_error_string());
|
||||
}
|
||||
return publisher;
|
||||
return rclcpp::create_publisher<MessageT, Alloc, PublisherT>(
|
||||
this->node_topics_.get(),
|
||||
topic_name,
|
||||
qos_profile,
|
||||
use_intra_process_comms_,
|
||||
allocator);
|
||||
}
|
||||
|
||||
template<typename MessageT, typename CallbackT, typename Alloc>
|
||||
typename rclcpp::subscription::Subscription<MessageT, Alloc>::SharedPtr
|
||||
template<typename MessageT, typename CallbackT, typename Alloc, typename SubscriptionT>
|
||||
std::shared_ptr<SubscriptionT>
|
||||
Node::create_subscription(
|
||||
const std::string & topic_name,
|
||||
CallbackT && callback,
|
||||
@@ -142,103 +93,31 @@ Node::create_subscription(
|
||||
bool ignore_local_publications,
|
||||
typename rclcpp::message_memory_strategy::MessageMemoryStrategy<MessageT, Alloc>::SharedPtr
|
||||
msg_mem_strat,
|
||||
typename std::shared_ptr<Alloc> allocator)
|
||||
std::shared_ptr<Alloc> allocator)
|
||||
{
|
||||
if (!allocator) {
|
||||
allocator = std::make_shared<Alloc>();
|
||||
}
|
||||
|
||||
rclcpp::subscription::AnySubscriptionCallback<MessageT,
|
||||
Alloc> any_subscription_callback(allocator);
|
||||
any_subscription_callback.set(std::forward<CallbackT>(callback));
|
||||
|
||||
if (!msg_mem_strat) {
|
||||
msg_mem_strat =
|
||||
rclcpp::message_memory_strategy::MessageMemoryStrategy<MessageT, Alloc>::create_default();
|
||||
using rclcpp::message_memory_strategy::MessageMemoryStrategy;
|
||||
msg_mem_strat = MessageMemoryStrategy<MessageT, Alloc>::create_default();
|
||||
}
|
||||
auto message_alloc =
|
||||
std::make_shared<typename subscription::Subscription<MessageT, Alloc>::MessageAlloc>();
|
||||
|
||||
auto subscription_options = rcl_subscription_get_default_options();
|
||||
subscription_options.qos = qos_profile;
|
||||
subscription_options.allocator = rclcpp::allocator::get_rcl_allocator<MessageT>(
|
||||
*message_alloc.get());
|
||||
subscription_options.ignore_local_publications = ignore_local_publications;
|
||||
|
||||
using rclcpp::subscription::Subscription;
|
||||
using rclcpp::subscription::SubscriptionBase;
|
||||
|
||||
auto sub = Subscription<MessageT, Alloc>::make_shared(
|
||||
node_handle_,
|
||||
return rclcpp::create_subscription<MessageT, CallbackT, Alloc, SubscriptionT>(
|
||||
this->node_topics_.get(),
|
||||
topic_name,
|
||||
subscription_options,
|
||||
any_subscription_callback,
|
||||
msg_mem_strat);
|
||||
auto sub_base_ptr = std::dynamic_pointer_cast<SubscriptionBase>(sub);
|
||||
// Setup intra process.
|
||||
if (use_intra_process_comms_) {
|
||||
auto intra_process_options = rcl_subscription_get_default_options();
|
||||
intra_process_options.allocator = rclcpp::allocator::get_rcl_allocator<MessageT>(
|
||||
*message_alloc.get());
|
||||
intra_process_options.qos = qos_profile;
|
||||
intra_process_options.ignore_local_publications = false;
|
||||
|
||||
auto intra_process_manager =
|
||||
context_->get_sub_context<rclcpp::intra_process_manager::IntraProcessManager>();
|
||||
rclcpp::intra_process_manager::IntraProcessManager::WeakPtr weak_ipm = intra_process_manager;
|
||||
uint64_t intra_process_subscription_id =
|
||||
intra_process_manager->add_subscription(sub_base_ptr);
|
||||
// *INDENT-OFF*
|
||||
sub->setup_intra_process(
|
||||
intra_process_subscription_id,
|
||||
[weak_ipm](
|
||||
uint64_t publisher_id,
|
||||
uint64_t message_sequence,
|
||||
uint64_t subscription_id,
|
||||
typename Subscription<MessageT, Alloc>::MessageUniquePtr & message)
|
||||
{
|
||||
auto ipm = weak_ipm.lock();
|
||||
if (!ipm) {
|
||||
// TODO(wjwwood): should this just return silently? Or maybe return with a logged warning?
|
||||
throw std::runtime_error(
|
||||
"intra process take called after destruction of intra process manager");
|
||||
}
|
||||
ipm->take_intra_process_message<MessageT, Alloc>(
|
||||
publisher_id, message_sequence, subscription_id, message);
|
||||
},
|
||||
[weak_ipm](const rmw_gid_t * sender_gid) -> bool {
|
||||
auto ipm = weak_ipm.lock();
|
||||
if (!ipm) {
|
||||
throw std::runtime_error(
|
||||
"intra process publisher check called after destruction of intra process manager");
|
||||
}
|
||||
return ipm->matches_any_publishers(sender_gid);
|
||||
},
|
||||
intra_process_options
|
||||
);
|
||||
// *INDENT-ON*
|
||||
}
|
||||
// Assign to a group.
|
||||
if (group) {
|
||||
if (!group_in_node(group)) {
|
||||
// TODO(jacquelinekay): use custom exception
|
||||
throw std::runtime_error("Cannot create subscription, group not in node.");
|
||||
}
|
||||
group->add_subscription(sub_base_ptr);
|
||||
} else {
|
||||
default_callback_group_->add_subscription(sub_base_ptr);
|
||||
}
|
||||
number_of_subscriptions_++;
|
||||
if (rcl_trigger_guard_condition(¬ify_guard_condition_) != RCL_RET_OK) {
|
||||
throw std::runtime_error(
|
||||
std::string(
|
||||
"Failed to notify waitset on subscription creation: ") + rmw_get_error_string());
|
||||
}
|
||||
return sub;
|
||||
std::forward<CallbackT>(callback),
|
||||
qos_profile,
|
||||
group,
|
||||
ignore_local_publications,
|
||||
use_intra_process_comms_,
|
||||
msg_mem_strat,
|
||||
allocator);
|
||||
}
|
||||
|
||||
template<typename MessageT, typename CallbackT, typename Alloc>
|
||||
typename rclcpp::subscription::Subscription<MessageT, Alloc>::SharedPtr
|
||||
template<typename MessageT, typename CallbackT, typename Alloc, typename SubscriptionT>
|
||||
std::shared_ptr<SubscriptionT>
|
||||
Node::create_subscription(
|
||||
const std::string & topic_name,
|
||||
size_t qos_history_depth,
|
||||
@@ -251,7 +130,7 @@ Node::create_subscription(
|
||||
{
|
||||
rmw_qos_profile_t qos = rmw_qos_profile_default;
|
||||
qos.depth = qos_history_depth;
|
||||
return this->create_subscription<MessageT, CallbackT, Alloc>(
|
||||
return this->create_subscription<MessageT, CallbackT, Alloc, SubscriptionT>(
|
||||
topic_name,
|
||||
std::forward<CallbackT>(callback),
|
||||
qos,
|
||||
@@ -261,30 +140,17 @@ Node::create_subscription(
|
||||
allocator);
|
||||
}
|
||||
|
||||
template<typename CallbackType>
|
||||
typename rclcpp::timer::WallTimer<CallbackType>::SharedPtr
|
||||
template<typename DurationT, typename CallbackT>
|
||||
typename rclcpp::timer::WallTimer<CallbackT>::SharedPtr
|
||||
Node::create_wall_timer(
|
||||
std::chrono::nanoseconds period,
|
||||
CallbackType callback,
|
||||
std::chrono::duration<int64_t, DurationT> period,
|
||||
CallbackT callback,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group)
|
||||
{
|
||||
auto timer = rclcpp::timer::WallTimer<CallbackType>::make_shared(
|
||||
period, std::move(callback));
|
||||
if (group) {
|
||||
if (!group_in_node(group)) {
|
||||
// TODO(jacquelinekay): use custom exception
|
||||
throw std::runtime_error("Cannot create timer, group not in node.");
|
||||
}
|
||||
group->add_timer(timer);
|
||||
} else {
|
||||
default_callback_group_->add_timer(timer);
|
||||
}
|
||||
number_of_timers_++;
|
||||
if (rcl_trigger_guard_condition(¬ify_guard_condition_) != RCL_RET_OK) {
|
||||
throw std::runtime_error(
|
||||
std::string(
|
||||
"Failed to notify waitset on timer creation: ") + rmw_get_error_string());
|
||||
}
|
||||
auto timer = rclcpp::timer::WallTimer<CallbackT>::make_shared(
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(period),
|
||||
std::move(callback));
|
||||
node_timers_->add_timer(timer, group);
|
||||
return timer;
|
||||
}
|
||||
|
||||
@@ -302,27 +168,13 @@ Node::create_client(
|
||||
using rclcpp::client::ClientBase;
|
||||
|
||||
auto cli = Client<ServiceT>::make_shared(
|
||||
shared_from_this(),
|
||||
node_base_.get(),
|
||||
node_graph_,
|
||||
service_name,
|
||||
options);
|
||||
|
||||
auto cli_base_ptr = std::dynamic_pointer_cast<ClientBase>(cli);
|
||||
if (group) {
|
||||
if (!group_in_node(group)) {
|
||||
// TODO(esteve): use custom exception
|
||||
throw std::runtime_error("Cannot create client, group not in node.");
|
||||
}
|
||||
group->add_client(cli_base_ptr);
|
||||
} else {
|
||||
default_callback_group_->add_client(cli_base_ptr);
|
||||
}
|
||||
number_of_clients_++;
|
||||
|
||||
if (rcl_trigger_guard_condition(¬ify_guard_condition_) != RCL_RET_OK) {
|
||||
throw std::runtime_error(
|
||||
std::string(
|
||||
"Failed to notify waitset on client creation: ") + rmw_get_error_string());
|
||||
}
|
||||
node_services_->add_client(cli_base_ptr, group);
|
||||
return cli;
|
||||
}
|
||||
|
||||
@@ -341,27 +193,31 @@ Node::create_service(
|
||||
service_options.qos = qos_profile;
|
||||
|
||||
auto serv = service::Service<ServiceT>::make_shared(
|
||||
node_handle_,
|
||||
node_base_->get_shared_rcl_node_handle(),
|
||||
service_name, any_service_callback, service_options);
|
||||
auto serv_base_ptr = std::dynamic_pointer_cast<service::ServiceBase>(serv);
|
||||
if (group) {
|
||||
if (!group_in_node(group)) {
|
||||
// TODO(jacquelinekay): use custom exception
|
||||
throw std::runtime_error("Cannot create service, group not in node.");
|
||||
}
|
||||
group->add_service(serv_base_ptr);
|
||||
} else {
|
||||
default_callback_group_->add_service(serv_base_ptr);
|
||||
}
|
||||
number_of_services_++;
|
||||
if (rcl_trigger_guard_condition(¬ify_guard_condition_) != RCL_RET_OK) {
|
||||
throw std::runtime_error(
|
||||
std::string(
|
||||
"Failed to notify waitset on service creation: ") + rmw_get_error_string());
|
||||
}
|
||||
node_services_->add_service(serv_base_ptr, group);
|
||||
return serv;
|
||||
}
|
||||
|
||||
template<typename CallbackT>
|
||||
void
|
||||
Node::register_param_change_callback(CallbackT && callback)
|
||||
{
|
||||
this->node_parameters_->register_param_change_callback(std::forward<CallbackT>(callback));
|
||||
}
|
||||
|
||||
template<typename ParameterT>
|
||||
bool
|
||||
Node::get_parameter(const std::string & name, ParameterT & parameter) const
|
||||
{
|
||||
rclcpp::parameter::ParameterVariant parameter_variant(name, parameter);
|
||||
bool result = get_parameter(name, parameter_variant);
|
||||
parameter = parameter_variant.get_value<ParameterT>();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace node
|
||||
} // namespace rclcpp
|
||||
|
||||
|
||||
131
rclcpp/include/rclcpp/node_interfaces/node_base.hpp
Normal file
131
rclcpp/include/rclcpp/node_interfaces/node_base.hpp
Normal file
@@ -0,0 +1,131 @@
|
||||
// Copyright 2016 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_BASE_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__NODE_BASE_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "rclcpp/context.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace node_interfaces
|
||||
{
|
||||
|
||||
/// Implementation of the NodeBase part of the Node API.
|
||||
class NodeBase : public NodeBaseInterface
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeBaseInterface)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
NodeBase(const std::string & node_name, rclcpp::context::Context::SharedPtr context);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
~NodeBase();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
const char *
|
||||
get_name() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
rclcpp::context::Context::SharedPtr
|
||||
get_context();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
rcl_node_t *
|
||||
get_rcl_node_handle();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
const rcl_node_t *
|
||||
get_rcl_node_handle() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
std::shared_ptr<rcl_node_t>
|
||||
get_shared_rcl_node_handle();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
std::shared_ptr<const rcl_node_t>
|
||||
get_shared_rcl_node_handle() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr
|
||||
create_callback_group(rclcpp::callback_group::CallbackGroupType group_type);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr
|
||||
get_default_callback_group();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
bool
|
||||
callback_group_in_node(rclcpp::callback_group::CallbackGroup::SharedPtr group);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
const std::vector<rclcpp::callback_group::CallbackGroup::WeakPtr> &
|
||||
get_callback_groups() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
std::atomic_bool &
|
||||
get_associated_with_executor_atomic();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
rcl_guard_condition_t *
|
||||
get_notify_guard_condition();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
std::unique_lock<std::recursive_mutex>
|
||||
acquire_notify_guard_condition_lock() const;
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(NodeBase)
|
||||
|
||||
rclcpp::context::Context::SharedPtr context_;
|
||||
|
||||
std::shared_ptr<rcl_node_t> node_handle_;
|
||||
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr default_callback_group_;
|
||||
std::vector<rclcpp::callback_group::CallbackGroup::WeakPtr> callback_groups_;
|
||||
|
||||
std::atomic_bool associated_with_executor_;
|
||||
|
||||
/// Guard condition for notifying the Executor of changes to this node.
|
||||
mutable std::recursive_mutex notify_guard_condition_mutex_;
|
||||
rcl_guard_condition_t notify_guard_condition_ = rcl_get_zero_initialized_guard_condition();
|
||||
bool notify_guard_condition_is_valid_;
|
||||
};
|
||||
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_BASE_HPP_
|
||||
136
rclcpp/include/rclcpp/node_interfaces/node_base_interface.hpp
Normal file
136
rclcpp/include/rclcpp/node_interfaces/node_base_interface.hpp
Normal file
@@ -0,0 +1,136 @@
|
||||
// Copyright 2016 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_BASE_INTERFACE_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__NODE_BASE_INTERFACE_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "rcl/node.h"
|
||||
|
||||
#include "rclcpp/callback_group.hpp"
|
||||
#include "rclcpp/context.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace node_interfaces
|
||||
{
|
||||
|
||||
/// Pure virtual interface class for the NodeBase part of the Node API.
|
||||
class NodeBaseInterface
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeBaseInterface)
|
||||
|
||||
/// Return the name of the node.
|
||||
// \return The name of the node.
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
const char *
|
||||
get_name() const = 0;
|
||||
|
||||
/// Return the context of the node.
|
||||
// \return SharedPtr to the node's context.
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
rclcpp::context::Context::SharedPtr
|
||||
get_context() = 0;
|
||||
|
||||
/// Return the rcl_node_t node handle (non-const version).
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
rcl_node_t *
|
||||
get_rcl_node_handle() = 0;
|
||||
|
||||
/// Return the rcl_node_t node handle (const version).
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
const rcl_node_t *
|
||||
get_rcl_node_handle() const = 0;
|
||||
|
||||
/// Return the rcl_node_t node handle in a std::shared_ptr.
|
||||
/* This handle remains valid after the Node is destroyed.
|
||||
* The actual rcl node is not finalized until it is out of scope everywhere.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
std::shared_ptr<rcl_node_t>
|
||||
get_shared_rcl_node_handle() = 0;
|
||||
|
||||
/// Return the rcl_node_t node handle in a std::shared_ptr.
|
||||
/* This handle remains valid after the Node is destroyed.
|
||||
* The actual rcl node is not finalized until it is out of scope everywhere.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
std::shared_ptr<const rcl_node_t>
|
||||
get_shared_rcl_node_handle() const = 0;
|
||||
|
||||
/// Create and return a callback group.
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr
|
||||
create_callback_group(rclcpp::callback_group::CallbackGroupType group_type) = 0;
|
||||
|
||||
/// Return the default callback group.
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr
|
||||
get_default_callback_group() = 0;
|
||||
|
||||
/// Return true if the given callback group is associated with this node.
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
bool
|
||||
callback_group_in_node(rclcpp::callback_group::CallbackGroup::SharedPtr group) = 0;
|
||||
|
||||
/// Return list of callback groups associated with this node.
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
const std::vector<rclcpp::callback_group::CallbackGroup::WeakPtr> &
|
||||
get_callback_groups() const = 0;
|
||||
|
||||
/// Return the atomic bool which is used to ensure only one executor is used.
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
std::atomic_bool &
|
||||
get_associated_with_executor_atomic() = 0;
|
||||
|
||||
/// Return guard condition that should be notified when the internal node state changes.
|
||||
/* For example, this should be notified when a publisher is added or removed.
|
||||
*
|
||||
* \return the rcl_guard_condition_t if it is valid, else nullptr
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
rcl_guard_condition_t *
|
||||
get_notify_guard_condition() = 0;
|
||||
|
||||
/// Acquire and return a scoped lock that protects the notify guard condition.
|
||||
/* This should be used when triggering the notify guard condition. */
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
std::unique_lock<std::recursive_mutex>
|
||||
acquire_notify_guard_condition_lock() const = 0;
|
||||
};
|
||||
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_BASE_INTERFACE_HPP_
|
||||
129
rclcpp/include/rclcpp/node_interfaces/node_graph.hpp
Normal file
129
rclcpp/include/rclcpp/node_interfaces/node_graph.hpp
Normal file
@@ -0,0 +1,129 @@
|
||||
// Copyright 2016 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_GRAPH_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__NODE_GRAPH_HPP_
|
||||
|
||||
#include <chrono>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "rcl/guard_condition.h"
|
||||
|
||||
#include "rclcpp/event.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_graph_interface.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
namespace graph_listener
|
||||
{
|
||||
class GraphListener;
|
||||
} // namespace graph_listener
|
||||
|
||||
namespace node_interfaces
|
||||
{
|
||||
|
||||
/// Implementation the NodeGraph part of the Node API.
|
||||
class NodeGraph : public NodeGraphInterface
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeGraph)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
explicit NodeGraph(rclcpp::node_interfaces::NodeBaseInterface * node_base);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
~NodeGraph();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
std::map<std::string, std::string>
|
||||
get_topic_names_and_types() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
size_t
|
||||
count_publishers(const std::string & topic_name) const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
size_t
|
||||
count_subscribers(const std::string & topic_name) const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
const rcl_guard_condition_t *
|
||||
get_graph_guard_condition() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
notify_graph_change();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
notify_shutdown();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
rclcpp::event::Event::SharedPtr
|
||||
get_graph_event();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
wait_for_graph_change(
|
||||
rclcpp::event::Event::SharedPtr event,
|
||||
std::chrono::nanoseconds timeout);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
size_t
|
||||
count_graph_users();
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(NodeGraph)
|
||||
|
||||
/// Handle to the NodeBaseInterface given in the constructor.
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base_;
|
||||
|
||||
/// Graph Listener which waits on graph changes for the node and is shared across nodes.
|
||||
std::shared_ptr<rclcpp::graph_listener::GraphListener> graph_listener_;
|
||||
/// Whether or not this node needs to be added to the graph listener.
|
||||
std::atomic_bool should_add_to_graph_listener_;
|
||||
|
||||
/// Mutex to guard the graph event related data structures.
|
||||
mutable std::mutex graph_mutex_;
|
||||
/// For notifying waiting threads (wait_for_graph_change()) on changes (notify_graph_change()).
|
||||
std::condition_variable graph_cv_;
|
||||
/// Weak references to graph events out on loan.
|
||||
std::vector<rclcpp::event::Event::WeakPtr> graph_events_;
|
||||
/// Number of graph events out on loan, used to determine if the graph should be monitored.
|
||||
/* graph_users_count_ is atomic so that it can be accessed without acquiring the graph_mutex_ */
|
||||
std::atomic_size_t graph_users_count_;
|
||||
};
|
||||
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_GRAPH_HPP_
|
||||
122
rclcpp/include/rclcpp/node_interfaces/node_graph_interface.hpp
Normal file
122
rclcpp/include/rclcpp/node_interfaces/node_graph_interface.hpp
Normal file
@@ -0,0 +1,122 @@
|
||||
// Copyright 2016 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_GRAPH_INTERFACE_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__NODE_GRAPH_INTERFACE_HPP_
|
||||
|
||||
#include <chrono>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "rcl/guard_condition.h"
|
||||
|
||||
#include "rclcpp/event.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace node_interfaces
|
||||
{
|
||||
|
||||
/// Pure virtual interface class for the NodeGraph part of the Node API.
|
||||
class NodeGraphInterface
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeGraphInterface)
|
||||
|
||||
/// Return a map of existing topic names (string) to topic types (string).
|
||||
/* A topic is considered to exist when at least one publisher or subscriber
|
||||
* exists for it, whether they be local or remote to this process.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
std::map<std::string, std::string>
|
||||
get_topic_names_and_types() const = 0;
|
||||
|
||||
/// Return the number of publishers that are advertised on a given topic.
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
size_t
|
||||
count_publishers(const std::string & topic_name) const = 0;
|
||||
|
||||
/// Return the number of subscribers who have created a subscription for a given topic.
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
size_t
|
||||
count_subscribers(const std::string & topic_name) const = 0;
|
||||
|
||||
/// Return the rcl guard condition which is triggered when the ROS graph changes.
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
const rcl_guard_condition_t *
|
||||
get_graph_guard_condition() const = 0;
|
||||
|
||||
/// Notify threads waiting on graph changes.
|
||||
/* Affects threads waiting on the notify guard condition, see:
|
||||
* get_notify_guard_condition(), as well as the threads waiting on graph
|
||||
* changes using a graph Event, see: wait_for_graph_change().
|
||||
*
|
||||
* This is typically only used by the rclcpp::graph_listener::GraphListener.
|
||||
*
|
||||
* \throws RCLBaseError (a child of that exception) when an rcl error occurs
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
notify_graph_change() = 0;
|
||||
|
||||
/// Notify any and all blocking node actions that shutdown has occurred.
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
notify_shutdown() = 0;
|
||||
|
||||
/// Return a graph event, which will be set anytime a graph change occurs.
|
||||
/* The graph Event object is a loan which must be returned.
|
||||
* The Event object is scoped and therefore to return the load just let it go
|
||||
* out of scope.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
rclcpp::event::Event::SharedPtr
|
||||
get_graph_event() = 0;
|
||||
|
||||
/// Wait for a graph event to occur by waiting on an Event to become set.
|
||||
/* The given Event must be acquire through the get_graph_event() method.
|
||||
*
|
||||
* \throws InvalidEventError if the given event is nullptr
|
||||
* \throws EventNotRegisteredError if the given event was not acquired with
|
||||
* get_graph_event().
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
wait_for_graph_change(
|
||||
rclcpp::event::Event::SharedPtr event,
|
||||
std::chrono::nanoseconds timeout) = 0;
|
||||
|
||||
/// Return the number of on loan graph events, see get_graph_event().
|
||||
/* This is typically only used by the rclcpp::graph_listener::GraphListener.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
size_t
|
||||
count_graph_users() = 0;
|
||||
};
|
||||
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_GRAPH_INTERFACE_HPP_
|
||||
122
rclcpp/include/rclcpp/node_interfaces/node_parameters.hpp
Normal file
122
rclcpp/include/rclcpp/node_interfaces/node_parameters.hpp
Normal file
@@ -0,0 +1,122 @@
|
||||
// Copyright 2016 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_HPP_
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "rcl_interfaces/msg/list_parameters_result.hpp"
|
||||
#include "rcl_interfaces/msg/parameter_descriptor.hpp"
|
||||
#include "rcl_interfaces/msg/parameter_event.hpp"
|
||||
#include "rcl_interfaces/msg/set_parameters_result.hpp"
|
||||
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_parameters_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_services_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
|
||||
#include "rclcpp/parameter.hpp"
|
||||
#include "rclcpp/publisher.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace node_interfaces
|
||||
{
|
||||
|
||||
/// Implementation of the NodeParameters part of the Node API.
|
||||
class NodeParameters : public NodeParametersInterface
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeParameters)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
NodeParameters(
|
||||
rclcpp::node_interfaces::NodeTopicsInterface * node_topics,
|
||||
bool use_intra_process);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
~NodeParameters();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
std::vector<rcl_interfaces::msg::SetParametersResult>
|
||||
set_parameters(
|
||||
const std::vector<rclcpp::parameter::ParameterVariant> & parameters);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
rcl_interfaces::msg::SetParametersResult
|
||||
set_parameters_atomically(
|
||||
const std::vector<rclcpp::parameter::ParameterVariant> & parameters);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
std::vector<rclcpp::parameter::ParameterVariant>
|
||||
get_parameters(const std::vector<std::string> & names) const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
rclcpp::parameter::ParameterVariant
|
||||
get_parameter(const std::string & name) const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
bool
|
||||
get_parameter(
|
||||
const std::string & name,
|
||||
rclcpp::parameter::ParameterVariant & parameter) const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
std::vector<rcl_interfaces::msg::ParameterDescriptor>
|
||||
describe_parameters(const std::vector<std::string> & names) const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
std::vector<uint8_t>
|
||||
get_parameter_types(const std::vector<std::string> & names) const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
rcl_interfaces::msg::ListParametersResult
|
||||
list_parameters(const std::vector<std::string> & prefixes, uint64_t depth) const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
register_param_change_callback(ParametersCallbackFunction callback);
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(NodeParameters)
|
||||
|
||||
rclcpp::node_interfaces::NodeTopicsInterface * node_topics_;
|
||||
|
||||
mutable std::mutex mutex_;
|
||||
|
||||
ParametersCallbackFunction parameters_callback_ = nullptr;
|
||||
|
||||
std::map<std::string, rclcpp::parameter::ParameterVariant> parameters_;
|
||||
|
||||
publisher::Publisher<rcl_interfaces::msg::ParameterEvent>::SharedPtr events_publisher_;
|
||||
};
|
||||
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_HPP_
|
||||
@@ -0,0 +1,97 @@
|
||||
// Copyright 2016 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_INTERFACE_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_INTERFACE_HPP_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "rcl_interfaces/msg/list_parameters_result.hpp"
|
||||
#include "rcl_interfaces/msg/parameter_descriptor.hpp"
|
||||
#include "rcl_interfaces/msg/set_parameters_result.hpp"
|
||||
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/parameter.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace node_interfaces
|
||||
{
|
||||
|
||||
/// Pure virtual interface class for the NodeParameters part of the Node API.
|
||||
class NodeParametersInterface
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeParametersInterface)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
std::vector<rcl_interfaces::msg::SetParametersResult>
|
||||
set_parameters(
|
||||
const std::vector<rclcpp::parameter::ParameterVariant> & parameters) = 0;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
rcl_interfaces::msg::SetParametersResult
|
||||
set_parameters_atomically(
|
||||
const std::vector<rclcpp::parameter::ParameterVariant> & parameters) = 0;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
std::vector<rclcpp::parameter::ParameterVariant>
|
||||
get_parameters(const std::vector<std::string> & names) const = 0;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
rclcpp::parameter::ParameterVariant
|
||||
get_parameter(const std::string & name) const = 0;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
bool
|
||||
get_parameter(
|
||||
const std::string & name,
|
||||
rclcpp::parameter::ParameterVariant & parameter) const = 0;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
std::vector<rcl_interfaces::msg::ParameterDescriptor>
|
||||
describe_parameters(const std::vector<std::string> & names) const = 0;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
std::vector<uint8_t>
|
||||
get_parameter_types(const std::vector<std::string> & names) const = 0;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
rcl_interfaces::msg::ListParametersResult
|
||||
list_parameters(const std::vector<std::string> & prefixes, uint64_t depth) const = 0;
|
||||
|
||||
using ParametersCallbackFunction =
|
||||
std::function<rcl_interfaces::msg::SetParametersResult(
|
||||
const std::vector<rclcpp::parameter::ParameterVariant> &)>;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
register_param_change_callback(ParametersCallbackFunction callback) = 0;
|
||||
};
|
||||
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_INTERFACE_HPP_
|
||||
67
rclcpp/include/rclcpp/node_interfaces/node_services.hpp
Normal file
67
rclcpp/include/rclcpp/node_interfaces/node_services.hpp
Normal file
@@ -0,0 +1,67 @@
|
||||
// Copyright 2016 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_SERVICES_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__NODE_SERVICES_HPP_
|
||||
|
||||
#include "rclcpp/callback_group.hpp"
|
||||
#include "rclcpp/client.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_services_interface.hpp"
|
||||
#include "rclcpp/service.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace node_interfaces
|
||||
{
|
||||
|
||||
/// Implementation of the NodeServices part of the Node API.
|
||||
class NodeServices : public NodeServicesInterface
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeServices)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
explicit NodeServices(rclcpp::node_interfaces::NodeBaseInterface * node_base);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
~NodeServices();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
add_client(
|
||||
rclcpp::client::ClientBase::SharedPtr client_base_ptr,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
add_service(
|
||||
rclcpp::service::ServiceBase::SharedPtr service_base_ptr,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group);
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(NodeServices)
|
||||
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base_;
|
||||
};
|
||||
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_SERVICES_HPP_
|
||||
@@ -0,0 +1,53 @@
|
||||
// Copyright 2016 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_SERVICES_INTERFACE_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__NODE_SERVICES_INTERFACE_HPP_
|
||||
|
||||
#include "rclcpp/callback_group.hpp"
|
||||
#include "rclcpp/client.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/service.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace node_interfaces
|
||||
{
|
||||
|
||||
/// Pure virtual interface class for the NodeServices part of the Node API.
|
||||
class NodeServicesInterface
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeServicesInterface)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
add_client(
|
||||
rclcpp::client::ClientBase::SharedPtr client_base_ptr,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group) = 0;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
add_service(
|
||||
rclcpp::service::ServiceBase::SharedPtr service_base_ptr,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group) = 0;
|
||||
};
|
||||
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_SERVICES_INTERFACE_HPP_
|
||||
60
rclcpp/include/rclcpp/node_interfaces/node_timers.hpp
Normal file
60
rclcpp/include/rclcpp/node_interfaces/node_timers.hpp
Normal file
@@ -0,0 +1,60 @@
|
||||
// Copyright 2016 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_TIMERS_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__NODE_TIMERS_HPP_
|
||||
|
||||
#include "rclcpp/callback_group.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_timers_interface.hpp"
|
||||
#include "rclcpp/timer.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace node_interfaces
|
||||
{
|
||||
|
||||
/// Implementation of the NodeTimers part of the Node API.
|
||||
class NodeTimers : public NodeTimersInterface
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeTimers)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
explicit NodeTimers(rclcpp::node_interfaces::NodeBaseInterface * node_base);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
~NodeTimers();
|
||||
|
||||
/// Add a timer to the node.
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
add_timer(
|
||||
rclcpp::timer::TimerBase::SharedPtr timer,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr callback_group);
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(NodeTimers)
|
||||
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base_;
|
||||
};
|
||||
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_TIMERS_HPP_
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright 2016 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_TIMERS_INTERFACE_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__NODE_TIMERS_INTERFACE_HPP_
|
||||
|
||||
#include "rclcpp/callback_group.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/timer.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace node_interfaces
|
||||
{
|
||||
|
||||
/// Pure virtual interface class for the NodeTimers part of the Node API.
|
||||
class NodeTimersInterface
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeTimersInterface)
|
||||
|
||||
/// Add a timer to the node.
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
add_timer(
|
||||
rclcpp::timer::TimerBase::SharedPtr timer,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr callback_group) = 0;
|
||||
};
|
||||
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_TIMERS_INTERFACE_HPP_
|
||||
88
rclcpp/include/rclcpp/node_interfaces/node_topics.hpp
Normal file
88
rclcpp/include/rclcpp/node_interfaces/node_topics.hpp
Normal file
@@ -0,0 +1,88 @@
|
||||
// Copyright 2016 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_TOPICS_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__NODE_TOPICS_HPP_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "rcl/publisher.h"
|
||||
#include "rcl/subscription.h"
|
||||
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
|
||||
#include "rclcpp/publisher.hpp"
|
||||
#include "rclcpp/publisher_factory.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace node_interfaces
|
||||
{
|
||||
|
||||
/// Implementation of the NodeTopics part of the Node API.
|
||||
class NodeTopics : public NodeTopicsInterface
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeTopicsInterface)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
explicit NodeTopics(rclcpp::node_interfaces::NodeBaseInterface * node_base);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
~NodeTopics();
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
rclcpp::publisher::PublisherBase::SharedPtr
|
||||
create_publisher(
|
||||
const std::string & topic_name,
|
||||
const rclcpp::PublisherFactory & publisher_factory,
|
||||
rcl_publisher_options_t & publisher_options,
|
||||
bool use_intra_process);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
add_publisher(
|
||||
rclcpp::publisher::PublisherBase::SharedPtr publisher);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
rclcpp::subscription::SubscriptionBase::SharedPtr
|
||||
create_subscription(
|
||||
const std::string & topic_name,
|
||||
const rclcpp::SubscriptionFactory & subscription_factory,
|
||||
rcl_subscription_options_t & subscription_options,
|
||||
bool use_intra_process);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
add_subscription(
|
||||
rclcpp::subscription::SubscriptionBase::SharedPtr subscription,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr callback_group);
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(NodeTopics)
|
||||
|
||||
NodeBaseInterface * node_base_;
|
||||
};
|
||||
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_TOPICS_HPP_
|
||||
@@ -0,0 +1,78 @@
|
||||
// Copyright 2016 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef RCLCPP__NODE_INTERFACES__NODE_TOPICS_INTERFACE_HPP_
|
||||
#define RCLCPP__NODE_INTERFACES__NODE_TOPICS_INTERFACE_HPP_
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "rcl/publisher.h"
|
||||
#include "rcl/subscription.h"
|
||||
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/publisher.hpp"
|
||||
#include "rclcpp/publisher_factory.hpp"
|
||||
#include "rclcpp/subscription.hpp"
|
||||
#include "rclcpp/subscription_factory.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
namespace node_interfaces
|
||||
{
|
||||
|
||||
/// Pure virtual interface class for the NodeTopics part of the Node API.
|
||||
class NodeTopicsInterface
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeTopicsInterface)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
rclcpp::publisher::PublisherBase::SharedPtr
|
||||
create_publisher(
|
||||
const std::string & topic_name,
|
||||
const rclcpp::PublisherFactory & publisher_factory,
|
||||
rcl_publisher_options_t & publisher_options,
|
||||
bool use_intra_process) = 0;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
add_publisher(
|
||||
rclcpp::publisher::PublisherBase::SharedPtr publisher) = 0;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
rclcpp::subscription::SubscriptionBase::SharedPtr
|
||||
create_subscription(
|
||||
const std::string & topic_name,
|
||||
const rclcpp::SubscriptionFactory & subscription_factory,
|
||||
rcl_subscription_options_t & subscription_options,
|
||||
bool use_intra_process) = 0;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual
|
||||
void
|
||||
add_subscription(
|
||||
rclcpp::subscription::SubscriptionBase::SharedPtr subscription,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr callback_group) = 0;
|
||||
};
|
||||
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__NODE_INTERFACES__NODE_TOPICS_INTERFACE_HPP_
|
||||
@@ -16,6 +16,7 @@
|
||||
#define RCLCPP__PARAMETER_CLIENT_HPP_
|
||||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "rcl_interfaces/msg/parameter.hpp"
|
||||
@@ -43,7 +44,7 @@ namespace parameter_client
|
||||
class AsyncParametersClient
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(AsyncParametersClient);
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(AsyncParametersClient)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
AsyncParametersClient(
|
||||
@@ -117,7 +118,7 @@ private:
|
||||
class SyncParametersClient
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(SyncParametersClient);
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(SyncParametersClient)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
explicit SyncParametersClient(
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace parameter_service
|
||||
class ParameterService
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(ParameterService);
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(ParameterService)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
explicit ParameterService(
|
||||
|
||||
@@ -28,43 +28,48 @@
|
||||
#include "rcl/publisher.h"
|
||||
|
||||
#include "rcl_interfaces/msg/intra_process_message.hpp"
|
||||
#include "rmw/impl/cpp/demangle.hpp"
|
||||
|
||||
#include "rclcpp/allocator/allocator_common.hpp"
|
||||
#include "rclcpp/allocator/allocator_deleter.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/type_support_decl.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
// Forward declaration for friend statement
|
||||
namespace node
|
||||
// Forward declaration is used for friend statement.
|
||||
namespace node_interfaces
|
||||
{
|
||||
class Node;
|
||||
} // namespace node
|
||||
class NodeTopicsInterface;
|
||||
}
|
||||
|
||||
namespace publisher
|
||||
{
|
||||
|
||||
class PublisherBase
|
||||
{
|
||||
friend rclcpp::node_interfaces::NodeTopicsInterface;
|
||||
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(PublisherBase);
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(PublisherBase)
|
||||
|
||||
/// Default constructor.
|
||||
/**
|
||||
* Typically, a publisher is not created through this method, but instead is created through a
|
||||
* call to `Node::create_publisher`.
|
||||
* \param[in] node_handle The corresponding rcl representation of the owner node.
|
||||
* \param[in] node_base A pointer to the NodeBaseInterface for the parent node.
|
||||
* \param[in] topic The topic that this publisher publishes on.
|
||||
* \param[in] queue_size The maximum number of unpublished messages to queue.
|
||||
* \param[in] type_support The type support structure for the type to be published.
|
||||
* \param[in] publisher_options QoS settings for this publisher.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
PublisherBase(
|
||||
std::shared_ptr<rcl_node_t> node_handle,
|
||||
std::string topic,
|
||||
size_t queue_size);
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||
const std::string & topic,
|
||||
const rosidl_message_type_support_t & type_support,
|
||||
const rcl_publisher_options_t & publisher_options);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual ~PublisherBase();
|
||||
@@ -72,7 +77,7 @@ public:
|
||||
/// Get the topic that this publisher publishes on.
|
||||
// \return The topic name.
|
||||
RCLCPP_PUBLIC
|
||||
const std::string &
|
||||
const char *
|
||||
get_topic_name() const;
|
||||
|
||||
/// Get the queue size for this publisher.
|
||||
@@ -113,9 +118,9 @@ public:
|
||||
bool
|
||||
operator==(const rmw_gid_t * gid) const;
|
||||
|
||||
typedef std::function<uint64_t(uint64_t, void *, const std::type_info &)> StoreMessageCallbackT;
|
||||
using StoreMessageCallbackT = std::function<uint64_t(uint64_t, void *, const std::type_info &)>;
|
||||
|
||||
protected:
|
||||
/// Implementation utility function used to setup intra process publishing after creation.
|
||||
RCLCPP_PUBLIC
|
||||
void
|
||||
setup_intra_process(
|
||||
@@ -123,14 +128,11 @@ protected:
|
||||
StoreMessageCallbackT callback,
|
||||
const rcl_publisher_options_t & intra_process_options);
|
||||
|
||||
std::shared_ptr<rcl_node_t> node_handle_;
|
||||
protected:
|
||||
std::shared_ptr<rcl_node_t> rcl_node_handle_;
|
||||
|
||||
rcl_publisher_t publisher_handle_ = rcl_get_zero_initialized_publisher();
|
||||
rcl_publisher_t intra_process_publisher_handle_ = rcl_get_zero_initialized_publisher();
|
||||
rcl_allocator_t rcl_allocator_ = rcl_get_default_allocator();
|
||||
|
||||
std::string topic_;
|
||||
size_t queue_size_;
|
||||
|
||||
uint64_t intra_process_publisher_id_;
|
||||
StoreMessageCallbackT store_intra_process_message_;
|
||||
@@ -143,74 +145,38 @@ protected:
|
||||
template<typename MessageT, typename Alloc = std::allocator<void>>
|
||||
class Publisher : public PublisherBase
|
||||
{
|
||||
friend rclcpp::node::Node;
|
||||
|
||||
public:
|
||||
using MessageAllocTraits = allocator::AllocRebind<MessageT, Alloc>;
|
||||
using MessageAlloc = typename MessageAllocTraits::allocator_type;
|
||||
using MessageDeleter = allocator::Deleter<MessageAlloc, MessageT>;
|
||||
using MessageUniquePtr = std::unique_ptr<MessageT, MessageDeleter>;
|
||||
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(Publisher<MessageT, Alloc>);
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(Publisher<MessageT, Alloc>)
|
||||
|
||||
Publisher(
|
||||
std::shared_ptr<rcl_node_t> node_handle,
|
||||
std::string topic,
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||
const std::string & topic,
|
||||
const rcl_publisher_options_t & publisher_options,
|
||||
std::shared_ptr<MessageAlloc> allocator)
|
||||
: PublisherBase(node_handle, topic, publisher_options.qos.depth), message_allocator_(allocator)
|
||||
const std::shared_ptr<MessageAlloc> & allocator)
|
||||
: PublisherBase(
|
||||
node_base,
|
||||
topic,
|
||||
*rosidl_typesupport_cpp::get_message_type_support_handle<MessageT>(),
|
||||
publisher_options),
|
||||
message_allocator_(allocator)
|
||||
{
|
||||
using rosidl_generator_cpp::get_message_type_support_handle;
|
||||
allocator::set_allocator_for_deleter(&message_deleter_, message_allocator_.get());
|
||||
|
||||
rcl_allocator_ = publisher_options.allocator;
|
||||
auto type_support_handle = get_message_type_support_handle<MessageT>();
|
||||
if (rcl_publisher_init(
|
||||
&publisher_handle_, node_handle_.get(), type_support_handle,
|
||||
topic.c_str(), &publisher_options) != RCL_RET_OK)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
std::string("could not create publisher: ") +
|
||||
rcl_get_error_string_safe());
|
||||
}
|
||||
// Life time of this object is tied to the publisher handle.
|
||||
rmw_publisher_t * publisher_rmw_handle = rcl_publisher_get_rmw_handle(&publisher_handle_);
|
||||
if (!publisher_rmw_handle) {
|
||||
throw std::runtime_error(
|
||||
std::string("failed to get rmw handle: ") + rcl_get_error_string_safe());
|
||||
}
|
||||
if (rmw_get_gid_for_publisher(publisher_rmw_handle, &rmw_gid_) != RMW_RET_OK) {
|
||||
// *INDENT-OFF* (prevent uncrustify from making unnecessary indents here)
|
||||
throw std::runtime_error(
|
||||
std::string("failed to get publisher gid: ") + rmw_get_error_string_safe());
|
||||
// *INDENT-ON*
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~Publisher()
|
||||
{
|
||||
if (rcl_publisher_fini(&intra_process_publisher_handle_, node_handle_.get()) != RCL_RET_OK) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"Error in destruction of intra process rcl publisher handle: %s\n",
|
||||
rcl_get_error_string_safe());
|
||||
}
|
||||
|
||||
if (rcl_publisher_fini(&publisher_handle_, node_handle_.get()) != RCL_RET_OK) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"Error in destruction of rcl publisher handle: %s\n",
|
||||
rcl_get_error_string_safe());
|
||||
}
|
||||
}
|
||||
|
||||
{}
|
||||
|
||||
/// Send a message to the topic for this publisher.
|
||||
/**
|
||||
* This function is templated on the input message type, MessageT.
|
||||
* \param[in] msg A shared pointer to the message to send.
|
||||
*/
|
||||
void
|
||||
virtual void
|
||||
publish(std::unique_ptr<MessageT, MessageDeleter> & msg)
|
||||
{
|
||||
this->do_inter_process_publish(msg.get());
|
||||
@@ -242,7 +208,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
virtual void
|
||||
publish(const std::shared_ptr<MessageT> & msg)
|
||||
{
|
||||
// Avoid allocating when not using intra process.
|
||||
@@ -261,7 +227,7 @@ public:
|
||||
return this->publish(unique_msg);
|
||||
}
|
||||
|
||||
void
|
||||
virtual void
|
||||
publish(std::shared_ptr<const MessageT> msg)
|
||||
{
|
||||
// Avoid allocating when not using intra process.
|
||||
@@ -280,7 +246,7 @@ public:
|
||||
return this->publish(unique_msg);
|
||||
}
|
||||
|
||||
void
|
||||
virtual void
|
||||
publish(const MessageT & msg)
|
||||
{
|
||||
// Avoid allocating when not using intra process.
|
||||
@@ -319,6 +285,7 @@ protected:
|
||||
};
|
||||
|
||||
} // namespace publisher
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__PUBLISHER_HPP_
|
||||
|
||||
147
rclcpp/include/rclcpp/publisher_factory.hpp
Normal file
147
rclcpp/include/rclcpp/publisher_factory.hpp
Normal file
@@ -0,0 +1,147 @@
|
||||
// Copyright 2016 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__PUBLISHER_FACTORY_HPP_
|
||||
#define RCLCPP__PUBLISHER_FACTORY_HPP_
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "rcl/publisher.h"
|
||||
|
||||
#include "rosidl_typesupport_cpp/message_type_support.hpp"
|
||||
|
||||
#include "rclcpp/publisher.hpp"
|
||||
#include "rclcpp/intra_process_manager.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
/// Factory with functions used to create a MessageT specific PublisherT.
|
||||
/* This factory class is used to encapsulate the template generated functions
|
||||
* which are used during the creation of a Message type specific publisher
|
||||
* within a non-templated class.
|
||||
*
|
||||
* It is created using the create_publisher_factory function, which is usually
|
||||
* 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.
|
||||
*/
|
||||
struct PublisherFactory
|
||||
{
|
||||
// Creates a PublisherT<MessageT, ...> publisher object and returns it as a PublisherBase.
|
||||
using PublisherFactoryFunction = std::function<
|
||||
rclcpp::publisher::PublisherBase::SharedPtr(
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||
const std::string & topic_name,
|
||||
rcl_publisher_options_t & publisher_options)>;
|
||||
|
||||
PublisherFactoryFunction create_typed_publisher;
|
||||
|
||||
// Adds the PublisherBase to the intraprocess manager with the correctly
|
||||
// templated call to IntraProcessManager::store_intra_process_message.
|
||||
using AddPublisherToIntraProcessManagerFunction = std::function<
|
||||
uint64_t(
|
||||
rclcpp::intra_process_manager::IntraProcessManager * ipm,
|
||||
rclcpp::publisher::PublisherBase::SharedPtr publisher)>;
|
||||
|
||||
AddPublisherToIntraProcessManagerFunction add_publisher_to_intra_process_manager;
|
||||
|
||||
// Creates the callback function which is called on each
|
||||
// PublisherT::publish() and which handles the intra process transmission of
|
||||
// the message being published.
|
||||
using SharedPublishCallbackFactoryFunction = std::function<
|
||||
rclcpp::publisher::PublisherBase::StoreMessageCallbackT(
|
||||
rclcpp::intra_process_manager::IntraProcessManager::SharedPtr ipm)>;
|
||||
|
||||
SharedPublishCallbackFactoryFunction create_shared_publish_callback;
|
||||
};
|
||||
|
||||
/// Return a PublisherFactory with functions setup for creating a PublisherT<MessageT, Alloc>.
|
||||
template<typename MessageT, typename Alloc, typename PublisherT>
|
||||
PublisherFactory
|
||||
create_publisher_factory(std::shared_ptr<Alloc> allocator)
|
||||
{
|
||||
PublisherFactory factory;
|
||||
|
||||
// factory function that creates a MessageT specific PublisherT
|
||||
factory.create_typed_publisher =
|
||||
[allocator](
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||
const std::string & topic_name,
|
||||
rcl_publisher_options_t & publisher_options) -> std::shared_ptr<PublisherT>
|
||||
{
|
||||
auto message_alloc = std::make_shared<typename PublisherT::MessageAlloc>(*allocator.get());
|
||||
publisher_options.allocator = allocator::get_rcl_allocator<MessageT>(*message_alloc.get());
|
||||
|
||||
return std::make_shared<PublisherT>(node_base, topic_name, publisher_options, message_alloc);
|
||||
};
|
||||
|
||||
// function to add a publisher to the intra process manager
|
||||
factory.add_publisher_to_intra_process_manager =
|
||||
[](
|
||||
rclcpp::intra_process_manager::IntraProcessManager * ipm,
|
||||
rclcpp::publisher::PublisherBase::SharedPtr publisher) -> uint64_t
|
||||
{
|
||||
return ipm->add_publisher<MessageT, Alloc>(std::dynamic_pointer_cast<PublisherT>(publisher));
|
||||
};
|
||||
|
||||
// function to create a shared publish callback std::function
|
||||
using StoreMessageCallbackT = rclcpp::publisher::PublisherBase::StoreMessageCallbackT;
|
||||
factory.create_shared_publish_callback =
|
||||
[](rclcpp::intra_process_manager::IntraProcessManager::SharedPtr ipm) -> StoreMessageCallbackT
|
||||
{
|
||||
rclcpp::intra_process_manager::IntraProcessManager::WeakPtr weak_ipm = ipm;
|
||||
|
||||
// this function is called on each call to publish() and handles storing
|
||||
// of the published message in the intra process manager
|
||||
auto shared_publish_callback =
|
||||
[weak_ipm](uint64_t publisher_id, void * msg, const std::type_info & type_info) -> uint64_t
|
||||
{
|
||||
auto ipm = weak_ipm.lock();
|
||||
if (!ipm) {
|
||||
// TODO(wjwwood): should this just return silently? Or maybe return with a warning?
|
||||
throw std::runtime_error(
|
||||
"intra process publish called after destruction of intra process manager");
|
||||
}
|
||||
if (!msg) {
|
||||
throw std::runtime_error("cannot publisher msg which is a null pointer");
|
||||
}
|
||||
auto & message_type_info = typeid(MessageT);
|
||||
if (message_type_info != type_info) {
|
||||
throw std::runtime_error(
|
||||
std::string("published type '") + type_info.name() +
|
||||
"' is incompatible from the publisher type '" + message_type_info.name() + "'");
|
||||
}
|
||||
MessageT * typed_message_ptr = static_cast<MessageT *>(msg);
|
||||
using MessageDeleter = typename publisher::Publisher<MessageT, Alloc>::MessageDeleter;
|
||||
std::unique_ptr<MessageT, MessageDeleter> unique_msg(typed_message_ptr);
|
||||
uint64_t message_seq =
|
||||
ipm->store_intra_process_message<MessageT, Alloc>(publisher_id, unique_msg);
|
||||
return message_seq;
|
||||
};
|
||||
|
||||
return shared_publish_callback;
|
||||
};
|
||||
|
||||
// return the factory now that it is populated
|
||||
return factory;
|
||||
}
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__PUBLISHER_FACTORY_HPP_
|
||||
@@ -31,7 +31,7 @@ namespace rate
|
||||
class RateBase
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(RateBase);
|
||||
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(RateBase)
|
||||
|
||||
virtual bool sleep() = 0;
|
||||
virtual bool is_steady() const = 0;
|
||||
@@ -46,7 +46,7 @@ template<class Clock = std::chrono::high_resolution_clock>
|
||||
class GenericRate : public RateBase
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(GenericRate);
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(GenericRate)
|
||||
|
||||
explicit GenericRate(double rate)
|
||||
: GenericRate<Clock>(
|
||||
@@ -106,7 +106,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(GenericRate);
|
||||
RCLCPP_DISABLE_COPY(GenericRate)
|
||||
|
||||
std::chrono::nanoseconds period_;
|
||||
using ClockDurationNano = std::chrono::duration<typename Clock::rep, std::nano>;
|
||||
|
||||
@@ -27,39 +27,6 @@
|
||||
#include "rclcpp/utilities.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
// NOLINTNEXTLINE(runtime/int)
|
||||
inline const std::chrono::seconds operator"" _s(unsigned long long s)
|
||||
{
|
||||
return std::chrono::seconds(s);
|
||||
}
|
||||
inline const std::chrono::nanoseconds operator"" _s(long double s)
|
||||
{
|
||||
return std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::duration<long double>(s));
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(runtime/int)
|
||||
inline const std::chrono::nanoseconds operator"" _ms(unsigned long long ms)
|
||||
{
|
||||
return std::chrono::milliseconds(ms);
|
||||
}
|
||||
inline const std::chrono::nanoseconds operator"" _ms(long double ms)
|
||||
{
|
||||
return std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::duration<long double, std::milli>(ms));
|
||||
}
|
||||
|
||||
// NOLINTNEXTLINE(runtime/int)
|
||||
inline const std::chrono::nanoseconds operator"" _ns(unsigned long long ns)
|
||||
{
|
||||
return std::chrono::nanoseconds(ns);
|
||||
}
|
||||
inline const std::chrono::nanoseconds operator"" _ns(long double ns)
|
||||
{
|
||||
return std::chrono::duration_cast<std::chrono::nanoseconds>(
|
||||
std::chrono::duration<long double, std::nano>(ns));
|
||||
}
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
|
||||
@@ -39,12 +39,16 @@ namespace service
|
||||
class ServiceBase
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(ServiceBase);
|
||||
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(ServiceBase)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
ServiceBase(
|
||||
std::shared_ptr<rcl_node_t> node_handle,
|
||||
const std::string service_name);
|
||||
const std::string & service_name);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
explicit ServiceBase(
|
||||
std::shared_ptr<rcl_node_t> node_handle);
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
virtual ~ServiceBase();
|
||||
@@ -64,12 +68,13 @@ public:
|
||||
std::shared_ptr<void> request) = 0;
|
||||
|
||||
protected:
|
||||
RCLCPP_DISABLE_COPY(ServiceBase);
|
||||
RCLCPP_DISABLE_COPY(ServiceBase)
|
||||
|
||||
std::shared_ptr<rcl_node_t> node_handle_;
|
||||
|
||||
rcl_service_t service_handle_ = rcl_get_zero_initialized_service();
|
||||
rcl_service_t * service_handle_ = nullptr;
|
||||
std::string service_name_;
|
||||
bool owns_rcl_handle_ = true;
|
||||
};
|
||||
|
||||
using any_service_callback::AnyServiceCallback;
|
||||
@@ -88,7 +93,7 @@ public:
|
||||
const std::shared_ptr<rmw_request_id_t>,
|
||||
const std::shared_ptr<typename ServiceT::Request>,
|
||||
std::shared_ptr<typename ServiceT::Response>)>;
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(Service);
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(Service)
|
||||
|
||||
Service(
|
||||
std::shared_ptr<rcl_node_t> node_handle,
|
||||
@@ -97,28 +102,56 @@ public:
|
||||
rcl_service_options_t & service_options)
|
||||
: ServiceBase(node_handle, service_name), any_callback_(any_callback)
|
||||
{
|
||||
using rosidl_generator_cpp::get_service_type_support_handle;
|
||||
using rosidl_typesupport_cpp::get_service_type_support_handle;
|
||||
auto service_type_support_handle = get_service_type_support_handle<ServiceT>();
|
||||
|
||||
// rcl does the static memory allocation here
|
||||
service_handle_ = new rcl_service_t;
|
||||
*service_handle_ = rcl_get_zero_initialized_service();
|
||||
|
||||
if (rcl_service_init(
|
||||
&service_handle_, node_handle.get(), service_type_support_handle, service_name.c_str(),
|
||||
service_handle_, node_handle.get(), service_type_support_handle, service_name.c_str(),
|
||||
&service_options) != RCL_RET_OK)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
std::string("could not create service: ") +
|
||||
throw std::runtime_error(std::string("could not create service: ") +
|
||||
rcl_get_error_string_safe());
|
||||
}
|
||||
}
|
||||
|
||||
Service(
|
||||
std::shared_ptr<rcl_node_t> node_handle,
|
||||
rcl_service_t * service_handle,
|
||||
AnyServiceCallback<ServiceT> any_callback)
|
||||
: ServiceBase(node_handle),
|
||||
any_callback_(any_callback)
|
||||
{
|
||||
// check if service handle was initialized
|
||||
// TODO(karsten1987): Take this verification
|
||||
// directly in rcl_*_t
|
||||
// see: https://github.com/ros2/rcl/issues/81
|
||||
if (!service_handle->impl) {
|
||||
// *INDENT-OFF* (prevent uncrustify from making unnecessary indents here)
|
||||
throw std::runtime_error(
|
||||
std::string("rcl_service_t in constructor argument must be initialized beforehand."));
|
||||
// *INDENT-ON*
|
||||
}
|
||||
service_handle_ = service_handle;
|
||||
service_name_ = std::string(rcl_service_get_service_name(service_handle));
|
||||
owns_rcl_handle_ = false;
|
||||
}
|
||||
|
||||
Service() = delete;
|
||||
|
||||
virtual ~Service()
|
||||
{
|
||||
if (rcl_service_fini(&service_handle_, node_handle_.get()) != RCL_RET_OK) {
|
||||
std::stringstream ss;
|
||||
ss << "Error in destruction of rcl service_handle_ handle: " <<
|
||||
rcl_get_error_string_safe() << '\n';
|
||||
(std::cerr << ss.str()).flush();
|
||||
// check if you have ownership of the handle
|
||||
if (owns_rcl_handle_) {
|
||||
if (rcl_service_fini(service_handle_, node_handle_.get()) != RCL_RET_OK) {
|
||||
std::stringstream ss;
|
||||
ss << "Error in destruction of rcl service_handle_ handle: " <<
|
||||
rcl_get_error_string_safe() << '\n';
|
||||
(std::cerr << ss.str()).flush();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,7 +191,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(Service);
|
||||
RCLCPP_DISABLE_COPY(Service)
|
||||
|
||||
AnyServiceCallback<ServiceT> any_callback_;
|
||||
};
|
||||
|
||||
@@ -44,7 +44,7 @@ template<typename Alloc = std::allocator<void>>
|
||||
class AllocatorMemoryStrategy : public memory_strategy::MemoryStrategy
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(AllocatorMemoryStrategy<Alloc>);
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(AllocatorMemoryStrategy<Alloc>)
|
||||
|
||||
using ExecAllocTraits = allocator::AllocRebind<executor::AnyExecutable, Alloc>;
|
||||
using ExecAlloc = typename ExecAllocTraits::allocator_type;
|
||||
@@ -52,8 +52,6 @@ public:
|
||||
using VoidAllocTraits = typename allocator::AllocRebind<void *, Alloc>;
|
||||
using VoidAlloc = typename VoidAllocTraits::allocator_type;
|
||||
|
||||
using WeakNodeVector = std::vector<std::weak_ptr<node::Node>>;
|
||||
|
||||
explicit AllocatorMemoryStrategy(std::shared_ptr<Alloc> allocator)
|
||||
{
|
||||
executable_allocator_ = std::make_shared<ExecAlloc>(*allocator.get());
|
||||
@@ -144,7 +142,7 @@ public:
|
||||
for (auto & weak_node : weak_nodes) {
|
||||
auto node = weak_node.lock();
|
||||
if (!node) {
|
||||
has_invalid_weak_nodes = false;
|
||||
has_invalid_weak_nodes = true;
|
||||
continue;
|
||||
}
|
||||
for (auto & weak_group : node->get_callback_groups()) {
|
||||
@@ -162,7 +160,8 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
for (auto & service : group->get_service_ptrs()) {
|
||||
for (auto & weak_service : group->get_service_ptrs()) {
|
||||
auto service = weak_service.lock();
|
||||
if (service) {
|
||||
service_handles_.push_back(service->get_service_handle());
|
||||
}
|
||||
@@ -265,7 +264,7 @@ public:
|
||||
any_exec->subscription = subscription;
|
||||
}
|
||||
any_exec->callback_group = group;
|
||||
any_exec->node = get_node_by_group(group, weak_nodes);
|
||||
any_exec->node_base = get_node_by_group(group, weak_nodes);
|
||||
subscription_handles_.erase(it);
|
||||
return;
|
||||
}
|
||||
@@ -299,7 +298,7 @@ public:
|
||||
// Otherwise it is safe to set and return the any_exec
|
||||
any_exec->service = service;
|
||||
any_exec->callback_group = group;
|
||||
any_exec->node = get_node_by_group(group, weak_nodes);
|
||||
any_exec->node_base = get_node_by_group(group, weak_nodes);
|
||||
service_handles_.erase(it);
|
||||
return;
|
||||
}
|
||||
@@ -332,7 +331,7 @@ public:
|
||||
// Otherwise it is safe to set and return the any_exec
|
||||
any_exec->client = client;
|
||||
any_exec->callback_group = group;
|
||||
any_exec->node = get_node_by_group(group, weak_nodes);
|
||||
any_exec->node_base = get_node_by_group(group, weak_nodes);
|
||||
client_handles_.erase(it);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#ifndef RCLCPP__STRATEGIES__MESSAGE_POOL_MEMORY_STRATEGY_HPP_
|
||||
#define RCLCPP__STRATEGIES__MESSAGE_POOL_MEMORY_STRATEGY_HPP_
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/message_memory_strategy.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
@@ -44,7 +46,7 @@ class MessagePoolMemoryStrategy
|
||||
: public message_memory_strategy::MessageMemoryStrategy<MessageT>
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(MessagePoolMemoryStrategy);
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(MessagePoolMemoryStrategy)
|
||||
|
||||
/// Default constructor
|
||||
MessagePoolMemoryStrategy()
|
||||
|
||||
@@ -38,10 +38,10 @@
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
namespace node
|
||||
namespace node_interfaces
|
||||
{
|
||||
class Node;
|
||||
} // namespace node
|
||||
class NodeTopicsInterface;
|
||||
} // namespace node_interfaces
|
||||
|
||||
namespace subscription
|
||||
{
|
||||
@@ -51,19 +51,21 @@ namespace subscription
|
||||
class SubscriptionBase
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(SubscriptionBase);
|
||||
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] 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] ignore_local_publications True to ignore local publications (unused).
|
||||
* \param[in] subscription_options options for the subscription.
|
||||
*/
|
||||
RCLCPP_PUBLIC
|
||||
SubscriptionBase(
|
||||
std::shared_ptr<rcl_node_t> node_handle,
|
||||
const rosidl_message_type_support_t & type_support_handle,
|
||||
const std::string & topic_name,
|
||||
bool ignore_local_publications);
|
||||
const rcl_subscription_options_t & subscription_options);
|
||||
|
||||
/// Default destructor.
|
||||
RCLCPP_PUBLIC
|
||||
@@ -71,7 +73,7 @@ public:
|
||||
|
||||
/// Get the topic that this subscription is subscribed on.
|
||||
RCLCPP_PUBLIC
|
||||
const std::string &
|
||||
const char *
|
||||
get_topic_name() const;
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
@@ -109,9 +111,7 @@ protected:
|
||||
std::shared_ptr<rcl_node_t> node_handle_;
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(SubscriptionBase);
|
||||
std::string topic_name_;
|
||||
bool ignore_local_publications_;
|
||||
RCLCPP_DISABLE_COPY(SubscriptionBase)
|
||||
};
|
||||
|
||||
using any_subscription_callback::AnySubscriptionCallback;
|
||||
@@ -120,7 +120,7 @@ using any_subscription_callback::AnySubscriptionCallback;
|
||||
template<typename MessageT, typename Alloc = std::allocator<void>>
|
||||
class Subscription : public SubscriptionBase
|
||||
{
|
||||
friend class rclcpp::node::Node;
|
||||
friend class rclcpp::node_interfaces::NodeTopicsInterface;
|
||||
|
||||
public:
|
||||
using MessageAllocTraits = allocator::AllocRebind<MessageT, Alloc>;
|
||||
@@ -128,7 +128,7 @@ public:
|
||||
using MessageDeleter = allocator::Deleter<MessageAlloc, MessageT>;
|
||||
using MessageUniquePtr = std::unique_ptr<MessageT, MessageDeleter>;
|
||||
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(Subscription);
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(Subscription)
|
||||
|
||||
/// Default constructor.
|
||||
/**
|
||||
@@ -136,8 +136,8 @@ public:
|
||||
* should be instantiated through Node::create_subscription.
|
||||
* \param[in] node_handle rcl representation of the node that owns this subscription.
|
||||
* \param[in] topic_name Name of the topic to subscribe to.
|
||||
* \param[in] ignore_local_publications True to ignore local publications (unused).
|
||||
* \param[in] callback User-defined callback to call when a message is received.
|
||||
* \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.
|
||||
*/
|
||||
Subscription(
|
||||
@@ -149,23 +149,15 @@ public:
|
||||
memory_strategy = message_memory_strategy::MessageMemoryStrategy<MessageT,
|
||||
Alloc>::create_default())
|
||||
: SubscriptionBase(
|
||||
node_handle, topic_name, subscription_options.ignore_local_publications),
|
||||
node_handle,
|
||||
*rosidl_typesupport_cpp::get_message_type_support_handle<MessageT>(),
|
||||
topic_name,
|
||||
subscription_options),
|
||||
any_callback_(callback),
|
||||
message_memory_strategy_(memory_strategy),
|
||||
get_intra_process_message_callback_(nullptr),
|
||||
matches_any_intra_process_publishers_(nullptr)
|
||||
{
|
||||
using rosidl_generator_cpp::get_message_type_support_handle;
|
||||
|
||||
auto type_support_handle = get_message_type_support_handle<MessageT>();
|
||||
if (rcl_subscription_init(
|
||||
&subscription_handle_, node_handle_.get(), type_support_handle, topic_name.c_str(),
|
||||
&subscription_options) != RCL_RET_OK)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
std::string("could not create subscription: ") + rcl_get_error_string_safe());
|
||||
}
|
||||
}
|
||||
{}
|
||||
|
||||
/// Support dynamically setting the message memory strategy.
|
||||
/**
|
||||
@@ -232,13 +224,11 @@ public:
|
||||
any_callback_.dispatch_intra_process(msg, message_info);
|
||||
}
|
||||
|
||||
private:
|
||||
typedef
|
||||
std::function<
|
||||
void (uint64_t, uint64_t, uint64_t, MessageUniquePtr &)
|
||||
> GetMessageCallbackType;
|
||||
typedef std::function<bool (const rmw_gid_t *)> MatchesAnyPublishersCallbackType;
|
||||
using GetMessageCallbackType =
|
||||
std::function<void(uint64_t, uint64_t, uint64_t, MessageUniquePtr &)>;
|
||||
using MatchesAnyPublishersCallbackType = std::function<bool(const rmw_gid_t *)>;
|
||||
|
||||
/// Implemenation detail.
|
||||
void setup_intra_process(
|
||||
uint64_t intra_process_subscription_id,
|
||||
GetMessageCallbackType get_message_callback,
|
||||
@@ -248,7 +238,7 @@ private:
|
||||
if (rcl_subscription_init(
|
||||
&intra_process_subscription_handle_, node_handle_.get(),
|
||||
rclcpp::type_support::get_intra_process_message_msg_type_support(),
|
||||
(get_topic_name() + "__intra").c_str(),
|
||||
(std::string(get_topic_name()) + "__intra").c_str(),
|
||||
&intra_process_options) != RCL_RET_OK)
|
||||
{
|
||||
// *INDENT-OFF* (prevent uncrustify from making unnecessary indents here)
|
||||
@@ -262,6 +252,7 @@ private:
|
||||
matches_any_intra_process_publishers_ = matches_any_publisher_callback;
|
||||
}
|
||||
|
||||
/// Implemenation detail.
|
||||
const rcl_subscription_t *
|
||||
get_intra_process_subscription_handle() const
|
||||
{
|
||||
@@ -271,7 +262,8 @@ private:
|
||||
return &intra_process_subscription_handle_;
|
||||
}
|
||||
|
||||
RCLCPP_DISABLE_COPY(Subscription);
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(Subscription)
|
||||
|
||||
AnySubscriptionCallback<MessageT, Alloc> any_callback_;
|
||||
typename message_memory_strategy::MessageMemoryStrategy<MessageT, Alloc>::SharedPtr
|
||||
|
||||
170
rclcpp/include/rclcpp/subscription_factory.hpp
Normal file
170
rclcpp/include/rclcpp/subscription_factory.hpp
Normal file
@@ -0,0 +1,170 @@
|
||||
// Copyright 2016 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__SUBSCRIPTION_FACTORY_HPP_
|
||||
#define RCLCPP__SUBSCRIPTION_FACTORY_HPP_
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "rcl/subscription.h"
|
||||
|
||||
#include "rosidl_typesupport_cpp/message_type_support.hpp"
|
||||
|
||||
#include "rclcpp/subscription.hpp"
|
||||
#include "rclcpp/intra_process_manager.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
namespace rclcpp
|
||||
{
|
||||
|
||||
/// Factory with functions used to create a Subscription<MessageT>.
|
||||
/* This factory class is used to encapsulate the template generated functions
|
||||
* which are used during the creation of a Message type specific subscription
|
||||
* within a non-templated class.
|
||||
*
|
||||
* It is created using the create_subscription_factory function, which is
|
||||
* 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.
|
||||
*/
|
||||
struct SubscriptionFactory
|
||||
{
|
||||
// Creates a Subscription<MessageT> object and returns it as a SubscriptionBase.
|
||||
using SubscriptionFactoryFunction = std::function<
|
||||
rclcpp::subscription::SubscriptionBase::SharedPtr(
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||
const std::string & topic_name,
|
||||
rcl_subscription_options_t & subscription_options)>;
|
||||
|
||||
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::subscription::SubscriptionBase::SharedPtr subscription,
|
||||
const rcl_subscription_options_t & subscription_options)>;
|
||||
|
||||
SetupIntraProcessFunction setup_intra_process;
|
||||
};
|
||||
|
||||
/// Return a SubscriptionFactory with functions for creating a SubscriptionT<MessageT, Alloc>.
|
||||
template<typename MessageT, typename CallbackT, typename Alloc, typename SubscriptionT>
|
||||
SubscriptionFactory
|
||||
create_subscription_factory(
|
||||
CallbackT && callback,
|
||||
typename rclcpp::message_memory_strategy::MessageMemoryStrategy<MessageT, Alloc>::SharedPtr
|
||||
msg_mem_strat,
|
||||
std::shared_ptr<Alloc> allocator)
|
||||
{
|
||||
SubscriptionFactory factory;
|
||||
|
||||
using rclcpp::subscription::AnySubscriptionCallback;
|
||||
AnySubscriptionCallback<MessageT, Alloc> any_subscription_callback(allocator);
|
||||
any_subscription_callback.set(std::forward<CallbackT>(callback));
|
||||
|
||||
auto message_alloc =
|
||||
std::make_shared<typename subscription::Subscription<MessageT, Alloc>::MessageAlloc>();
|
||||
|
||||
// factory function that creates a MessageT specific SubscriptionT
|
||||
factory.create_typed_subscription =
|
||||
[allocator, msg_mem_strat, any_subscription_callback, message_alloc](
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||
const std::string & topic_name,
|
||||
rcl_subscription_options_t & subscription_options
|
||||
) -> rclcpp::subscription::SubscriptionBase::SharedPtr
|
||||
{
|
||||
subscription_options.allocator =
|
||||
rclcpp::allocator::get_rcl_allocator<MessageT>(*message_alloc.get());
|
||||
|
||||
using rclcpp::subscription::Subscription;
|
||||
using rclcpp::subscription::SubscriptionBase;
|
||||
|
||||
auto sub = Subscription<MessageT, Alloc>::make_shared(
|
||||
node_base->get_shared_rcl_node_handle(),
|
||||
topic_name,
|
||||
subscription_options,
|
||||
any_subscription_callback,
|
||||
msg_mem_strat);
|
||||
auto sub_base_ptr = std::dynamic_pointer_cast<SubscriptionBase>(sub);
|
||||
return sub_base_ptr;
|
||||
};
|
||||
|
||||
// function that will setup intra process communications for the subscription
|
||||
factory.setup_intra_process =
|
||||
[message_alloc](
|
||||
rclcpp::intra_process_manager::IntraProcessManager::SharedPtr ipm,
|
||||
rclcpp::subscription::SubscriptionBase::SharedPtr subscription,
|
||||
const rcl_subscription_options_t & subscription_options)
|
||||
{
|
||||
rclcpp::intra_process_manager::IntraProcessManager::WeakPtr weak_ipm = ipm;
|
||||
uint64_t intra_process_subscription_id = ipm->add_subscription(subscription);
|
||||
|
||||
auto intra_process_options = rcl_subscription_get_default_options();
|
||||
intra_process_options.allocator = rclcpp::allocator::get_rcl_allocator<MessageT>(
|
||||
*message_alloc.get());
|
||||
intra_process_options.qos = subscription_options.qos;
|
||||
intra_process_options.ignore_local_publications = false;
|
||||
|
||||
// function that will be called to take a MessageT from the intra process manager
|
||||
auto take_intra_process_message_func =
|
||||
[weak_ipm](
|
||||
uint64_t publisher_id,
|
||||
uint64_t message_sequence,
|
||||
uint64_t subscription_id,
|
||||
typename rclcpp::subscription::Subscription<MessageT, Alloc>::MessageUniquePtr & message)
|
||||
{
|
||||
auto ipm = weak_ipm.lock();
|
||||
if (!ipm) {
|
||||
// TODO(wjwwood): should this just return silently? Or return with a logged warning?
|
||||
throw std::runtime_error(
|
||||
"intra process take called after destruction of intra process manager");
|
||||
}
|
||||
ipm->take_intra_process_message<MessageT, Alloc>(
|
||||
publisher_id, message_sequence, subscription_id, message);
|
||||
};
|
||||
|
||||
// function that is called to see if the publisher id matches any local publishers
|
||||
auto matches_any_publisher_func =
|
||||
[weak_ipm](const rmw_gid_t * sender_gid) -> bool
|
||||
{
|
||||
auto ipm = weak_ipm.lock();
|
||||
if (!ipm) {
|
||||
throw std::runtime_error(
|
||||
"intra process publisher check called "
|
||||
"after destruction of intra process manager");
|
||||
}
|
||||
return ipm->matches_any_publishers(sender_gid);
|
||||
};
|
||||
|
||||
auto typed_sub_ptr = std::dynamic_pointer_cast<SubscriptionT>(subscription);
|
||||
typed_sub_ptr->setup_intra_process(
|
||||
intra_process_subscription_id,
|
||||
take_intra_process_message_func,
|
||||
matches_any_publisher_func,
|
||||
intra_process_options
|
||||
);
|
||||
};
|
||||
// end definition of factory function to setup intra process
|
||||
|
||||
// return the factory now that it is populated
|
||||
return factory;
|
||||
}
|
||||
|
||||
} // namespace rclcpp
|
||||
|
||||
#endif // RCLCPP__SUBSCRIPTION_FACTORY_HPP_
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "rclcpp/function_traits.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
@@ -42,7 +43,7 @@ namespace timer
|
||||
class TimerBase
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(TimerBase);
|
||||
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(TimerBase)
|
||||
|
||||
RCLCPP_PUBLIC
|
||||
explicit TimerBase(std::chrono::nanoseconds period);
|
||||
@@ -102,7 +103,7 @@ template<
|
||||
class GenericTimer : public TimerBase
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(GenericTimer);
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(GenericTimer)
|
||||
|
||||
/// Default constructor.
|
||||
/**
|
||||
@@ -169,7 +170,7 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
RCLCPP_DISABLE_COPY(GenericTimer);
|
||||
RCLCPP_DISABLE_COPY(GenericTimer)
|
||||
|
||||
FunctorT callback_;
|
||||
};
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
#include "rosidl_generator_cpp/message_type_support_decl.hpp"
|
||||
#include "rosidl_generator_cpp/service_type_support_decl.hpp"
|
||||
|
||||
#include "rosidl_generator_cpp/message_type_support.hpp"
|
||||
#include "rosidl_generator_cpp/service_type_support.hpp"
|
||||
#include "rosidl_typesupport_cpp/message_type_support.hpp"
|
||||
#include "rosidl_typesupport_cpp/service_type_support.hpp"
|
||||
|
||||
#include "rclcpp/visibility_control.hpp"
|
||||
|
||||
|
||||
@@ -22,8 +22,6 @@
|
||||
#ifndef RCLCPP__VISIBILITY_CONTROL_HPP_
|
||||
#define RCLCPP__VISIBILITY_CONTROL_HPP_
|
||||
|
||||
#include "rmw/rmw.h"
|
||||
|
||||
// This logic was borrowed (then namespaced) from the examples on the gcc wiki:
|
||||
// https://gcc.gnu.org/wiki/Visibility
|
||||
|
||||
|
||||
@@ -14,8 +14,10 @@
|
||||
<build_depend>rcl_interfaces</build_depend>
|
||||
<build_depend>rmw_implementation_cmake</build_depend>
|
||||
<build_depend>rosidl_generator_cpp</build_depend>
|
||||
<build_depend>rosidl_typesupport_cpp</build_depend>
|
||||
<build_export_depend>rcl_interfaces</build_export_depend>
|
||||
<build_export_depend>rosidl_generator_cpp</build_export_depend>
|
||||
<build_export_depend>rosidl_typesupport_cpp</build_export_depend>
|
||||
|
||||
<depend>rcl</depend>
|
||||
<depend>rmw_implementation</depend>
|
||||
|
||||
@@ -14,16 +14,17 @@
|
||||
|
||||
# copied from rclcpp/rclcpp-extras.cmake
|
||||
|
||||
include("${rclcpp_DIR}/get_rclcpp_information.cmake")
|
||||
# register ament_package() hook for node plugins once
|
||||
macro(_rclcpp_register_package_hook)
|
||||
if(NOT DEFINED _RCLCPP_PACKAGE_HOOK_REGISTERED)
|
||||
set(_RCLCPP_PACKAGE_HOOK_REGISTERED TRUE)
|
||||
|
||||
set(rclcpp_node_main_SRC "${rclcpp_DIR}/../../../src/rclcpp/node_main.cpp")
|
||||
|
||||
function(rclcpp_create_node_main node_library_target)
|
||||
if(NOT TARGET ${node_library_target})
|
||||
message(FATAL_ERROR "rclcpp_create_node_main() the first argument must be a valid target name")
|
||||
find_package(ament_cmake_core QUIET REQUIRED)
|
||||
ament_register_extension("ament_package" "rclcpp"
|
||||
"rclcpp_package_hook.cmake")
|
||||
endif()
|
||||
set(executable_name_ ${node_library_target}_node)
|
||||
add_executable(${executable_name_} ${rclcpp_node_main_SRC})
|
||||
target_link_libraries(${executable_name_} ${node_library_target})
|
||||
install(TARGETS ${executable_name_} DESTINATION bin)
|
||||
endfunction()
|
||||
endmacro()
|
||||
|
||||
include("${rclcpp_DIR}/get_rclcpp_information.cmake")
|
||||
include("${rclcpp_DIR}/rclcpp_create_node_main.cmake")
|
||||
include("${rclcpp_DIR}/rclcpp_register_node_plugins.cmake")
|
||||
|
||||
@@ -23,7 +23,7 @@ AnyExecutable::AnyExecutable()
|
||||
service(nullptr),
|
||||
client(nullptr),
|
||||
callback_group(nullptr),
|
||||
node(nullptr)
|
||||
node_base(nullptr)
|
||||
{}
|
||||
|
||||
AnyExecutable::~AnyExecutable()
|
||||
|
||||
@@ -37,7 +37,7 @@ CallbackGroup::get_timer_ptrs() const
|
||||
return timer_ptrs_;
|
||||
}
|
||||
|
||||
const std::vector<rclcpp::service::ServiceBase::SharedPtr> &
|
||||
const std::vector<rclcpp::service::ServiceBase::WeakPtr> &
|
||||
CallbackGroup::get_service_ptrs() const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
|
||||
@@ -16,13 +16,15 @@
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "rcl/graph.h"
|
||||
#include "rcl/node.h"
|
||||
#include "rcl/wait.h"
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
#include "rclcpp/node.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_graph_interface.hpp"
|
||||
#include "rclcpp/utilities.hpp"
|
||||
|
||||
using rclcpp::client::ClientBase;
|
||||
@@ -30,9 +32,11 @@ using rclcpp::exceptions::InvalidNodeError;
|
||||
using rclcpp::exceptions::throw_from_rcl_error;
|
||||
|
||||
ClientBase::ClientBase(
|
||||
std::shared_ptr<rclcpp::node::Node> parent_node,
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph,
|
||||
const std::string & service_name)
|
||||
: node_(parent_node), node_handle_(parent_node->get_shared_node_handle()),
|
||||
: node_graph_(node_graph),
|
||||
node_handle_(node_base->get_shared_rcl_node_handle()),
|
||||
service_name_(service_name)
|
||||
{}
|
||||
|
||||
@@ -75,12 +79,13 @@ ClientBase::wait_for_service_nanoseconds(std::chrono::nanoseconds timeout)
|
||||
return false;
|
||||
}
|
||||
// make an event to reuse, rather than create a new one each time
|
||||
auto node_ptr = node_.lock();
|
||||
auto node_ptr = node_graph_.lock();
|
||||
if (!node_ptr) {
|
||||
throw InvalidNodeError();
|
||||
}
|
||||
auto event = node_ptr->get_graph_event();
|
||||
// update the time even on the first loop to account for time in first server_is_read()
|
||||
// update the time even on the first loop to account for time spent in the first call
|
||||
// to this->server_is_ready()
|
||||
std::chrono::nanoseconds time_to_wait = timeout - (std::chrono::steady_clock::now() - start);
|
||||
if (timeout > std::chrono::nanoseconds(0) && time_to_wait < std::chrono::nanoseconds(0)) {
|
||||
// Do not allow the time_to_wait to become negative when timeout was originally positive.
|
||||
@@ -94,10 +99,13 @@ ClientBase::wait_for_service_nanoseconds(std::chrono::nanoseconds timeout)
|
||||
return false;
|
||||
}
|
||||
node_ptr->wait_for_graph_change(event, time_to_wait);
|
||||
if (event->check_and_clear()) {
|
||||
if (this->service_is_ready()) {
|
||||
return true;
|
||||
}
|
||||
event->check_and_clear(); // reset the event
|
||||
|
||||
// always check if the service is ready, even if the graph event wasn't triggered
|
||||
// this is needed to avoid a race condition that is specific to the Connext RMW implementation
|
||||
// (see https://github.com/ros2/rmw_connext/issues/201)
|
||||
if (this->service_is_ready()) {
|
||||
return true;
|
||||
}
|
||||
// server is not ready, loop if there is time left
|
||||
time_to_wait = timeout - (std::chrono::steady_clock::now() - start);
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
// limitations under the License.
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
@@ -20,6 +21,7 @@
|
||||
#include "rcl/error_handling.h"
|
||||
|
||||
#include "rclcpp/executor.hpp"
|
||||
#include "rclcpp/node.hpp"
|
||||
#include "rclcpp/scope_exit.hpp"
|
||||
#include "rclcpp/utilities.hpp"
|
||||
|
||||
@@ -85,10 +87,11 @@ Executor::~Executor()
|
||||
}
|
||||
|
||||
void
|
||||
Executor::add_node(rclcpp::node::Node::SharedPtr node_ptr, bool notify)
|
||||
Executor::add_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr, bool notify)
|
||||
{
|
||||
// If the node already has an executor
|
||||
if (node_ptr->has_executor.exchange(true)) {
|
||||
std::atomic_bool & has_executor = node_ptr->get_associated_with_executor_atomic();
|
||||
if (has_executor.exchange(true)) {
|
||||
throw std::runtime_error("Node has already been added to an executor.");
|
||||
}
|
||||
// Check to ensure node not already added
|
||||
@@ -111,14 +114,20 @@ Executor::add_node(rclcpp::node::Node::SharedPtr node_ptr, bool notify)
|
||||
}
|
||||
|
||||
void
|
||||
Executor::remove_node(rclcpp::node::Node::SharedPtr node_ptr, bool notify)
|
||||
Executor::add_node(std::shared_ptr<rclcpp::node::Node> node_ptr, bool notify)
|
||||
{
|
||||
this->add_node(node_ptr->get_node_base_interface(), notify);
|
||||
}
|
||||
|
||||
void
|
||||
Executor::remove_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr, bool notify)
|
||||
{
|
||||
bool node_removed = false;
|
||||
weak_nodes_.erase(
|
||||
std::remove_if(
|
||||
weak_nodes_.begin(), weak_nodes_.end(),
|
||||
// *INDENT-OFF* (prevent uncrustify from making unnecessary indents here)
|
||||
[&](std::weak_ptr<rclcpp::node::Node> & i)
|
||||
[&](rclcpp::node_interfaces::NodeBaseInterface::WeakPtr & i)
|
||||
{
|
||||
bool matched = (i.lock() == node_ptr);
|
||||
node_removed |= matched;
|
||||
@@ -127,7 +136,8 @@ Executor::remove_node(rclcpp::node::Node::SharedPtr node_ptr, bool notify)
|
||||
// *INDENT-ON*
|
||||
)
|
||||
);
|
||||
node_ptr->has_executor.store(false);
|
||||
std::atomic_bool & has_executor = node_ptr->get_associated_with_executor_atomic();
|
||||
has_executor.store(false);
|
||||
if (notify) {
|
||||
// If the node was matched and removed, interrupt waiting
|
||||
if (node_removed) {
|
||||
@@ -139,9 +149,15 @@ Executor::remove_node(rclcpp::node::Node::SharedPtr node_ptr, bool notify)
|
||||
memory_strategy_->remove_guard_condition(node_ptr->get_notify_guard_condition());
|
||||
}
|
||||
|
||||
void
|
||||
Executor::remove_node(std::shared_ptr<rclcpp::node::Node> node_ptr, bool notify)
|
||||
{
|
||||
this->remove_node(node_ptr->get_node_base_interface(), notify);
|
||||
}
|
||||
|
||||
void
|
||||
Executor::spin_node_once_nanoseconds(
|
||||
rclcpp::node::Node::SharedPtr node,
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node,
|
||||
std::chrono::nanoseconds timeout)
|
||||
{
|
||||
this->add_node(node, false);
|
||||
@@ -151,13 +167,19 @@ Executor::spin_node_once_nanoseconds(
|
||||
}
|
||||
|
||||
void
|
||||
Executor::spin_node_some(rclcpp::node::Node::SharedPtr node)
|
||||
Executor::spin_node_some(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node)
|
||||
{
|
||||
this->add_node(node, false);
|
||||
spin_some();
|
||||
this->remove_node(node, false);
|
||||
}
|
||||
|
||||
void
|
||||
Executor::spin_node_some(std::shared_ptr<rclcpp::node::Node> node)
|
||||
{
|
||||
this->spin_node_some(node->get_node_base_interface());
|
||||
}
|
||||
|
||||
void
|
||||
Executor::spin_some()
|
||||
{
|
||||
@@ -247,7 +269,7 @@ Executor::execute_subscription(
|
||||
} else if (ret != RCL_RET_SUBSCRIPTION_TAKE_FAILED) {
|
||||
fprintf(stderr,
|
||||
"[rclcpp::error] take failed for subscription on topic '%s': %s\n",
|
||||
subscription->get_topic_name().c_str(), rcl_get_error_string_safe());
|
||||
subscription->get_topic_name(), rcl_get_error_string_safe());
|
||||
}
|
||||
subscription->return_message(message);
|
||||
}
|
||||
@@ -269,7 +291,7 @@ Executor::execute_intra_process_subscription(
|
||||
} else if (status != RCL_RET_SUBSCRIPTION_TAKE_FAILED) {
|
||||
fprintf(stderr,
|
||||
"[rclcpp::error] take failed for intra process subscription on topic '%s': %s\n",
|
||||
subscription->get_topic_name().c_str(), rcl_get_error_string_safe());
|
||||
subscription->get_topic_name(), rcl_get_error_string_safe());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -290,11 +312,9 @@ Executor::execute_service(
|
||||
service->get_service_handle(),
|
||||
request_header.get(),
|
||||
request.get());
|
||||
if (status != RCL_RET_SERVICE_TAKE_FAILED) {
|
||||
if (status == RCL_RET_OK) {
|
||||
service->handle_request(request_header, request);
|
||||
}
|
||||
} else {
|
||||
if (status == RCL_RET_OK) {
|
||||
service->handle_request(request_header, request);
|
||||
} else if (status != RCL_RET_SERVICE_TAKE_FAILED) {
|
||||
fprintf(stderr,
|
||||
"[rclcpp::error] take request failed for server of service '%s': %s\n",
|
||||
service->get_service_name().c_str(), rcl_get_error_string_safe());
|
||||
@@ -311,11 +331,9 @@ Executor::execute_client(
|
||||
client->get_client_handle(),
|
||||
request_header.get(),
|
||||
response.get());
|
||||
if (status != RCL_RET_SERVICE_TAKE_FAILED) {
|
||||
if (status == RCL_RET_OK) {
|
||||
client->handle_response(request_header, response);
|
||||
}
|
||||
} else {
|
||||
if (status == RCL_RET_OK) {
|
||||
client->handle_response(request_header, response);
|
||||
} else if (status != RCL_RET_SERVICE_TAKE_FAILED) {
|
||||
fprintf(stderr,
|
||||
"[rclcpp::error] take response failed for client of service '%s': %s\n",
|
||||
client->get_service_name().c_str(), rcl_get_error_string_safe());
|
||||
@@ -335,7 +353,7 @@ Executor::wait_for_work(std::chrono::nanoseconds timeout)
|
||||
remove_if(
|
||||
weak_nodes_.begin(), weak_nodes_.end(),
|
||||
// *INDENT-OFF* (prevent uncrustify from making unnecessary indents here)
|
||||
[](std::weak_ptr<rclcpp::node::Node> i)
|
||||
[](rclcpp::node_interfaces::NodeBaseInterface::WeakPtr i)
|
||||
{
|
||||
return i.expired();
|
||||
}
|
||||
@@ -415,11 +433,11 @@ Executor::wait_for_work(std::chrono::nanoseconds timeout)
|
||||
}
|
||||
}
|
||||
|
||||
rclcpp::node::Node::SharedPtr
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr
|
||||
Executor::get_node_by_group(rclcpp::callback_group::CallbackGroup::SharedPtr group)
|
||||
{
|
||||
if (!group) {
|
||||
return rclcpp::node::Node::SharedPtr();
|
||||
return nullptr;
|
||||
}
|
||||
for (auto & weak_node : weak_nodes_) {
|
||||
auto node = weak_node.lock();
|
||||
@@ -433,7 +451,7 @@ Executor::get_node_by_group(rclcpp::callback_group::CallbackGroup::SharedPtr gro
|
||||
}
|
||||
}
|
||||
}
|
||||
return rclcpp::node::Node::SharedPtr();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr
|
||||
|
||||
@@ -15,17 +15,29 @@
|
||||
#include "rclcpp/executors.hpp"
|
||||
|
||||
void
|
||||
rclcpp::spin_some(node::Node::SharedPtr node_ptr)
|
||||
rclcpp::spin_some(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr)
|
||||
{
|
||||
rclcpp::executors::SingleThreadedExecutor exec;
|
||||
exec.spin_node_some(node_ptr);
|
||||
}
|
||||
|
||||
void
|
||||
rclcpp::spin(node::Node::SharedPtr node_ptr)
|
||||
rclcpp::spin_some(rclcpp::node::Node::SharedPtr node_ptr)
|
||||
{
|
||||
rclcpp::spin_some(node_ptr->get_node_base_interface());
|
||||
}
|
||||
|
||||
void
|
||||
rclcpp::spin(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr)
|
||||
{
|
||||
rclcpp::executors::SingleThreadedExecutor exec;
|
||||
exec.add_node(node_ptr);
|
||||
exec.spin();
|
||||
exec.remove_node(node_ptr);
|
||||
}
|
||||
|
||||
void
|
||||
rclcpp::spin(rclcpp::node::Node::SharedPtr node_ptr)
|
||||
{
|
||||
rclcpp::spin(node_ptr->get_node_base_interface());
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include <cstdio>
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -114,17 +115,17 @@ GraphListener::run_loop()
|
||||
rcl_ret_t ret;
|
||||
{
|
||||
// This "barrier" lock ensures that other functions can acquire the
|
||||
// nodes_mutex_ after waking up rcl_wait.
|
||||
std::lock_guard<std::mutex> nodes_barrier_lock(nodes_barrier_mutex_);
|
||||
// node_graph_interfaces_mutex_ after waking up rcl_wait.
|
||||
std::lock_guard<std::mutex> nodes_barrier_lock(node_graph_interfaces_barrier_mutex_);
|
||||
// This is ownership is passed to nodes_lock in the next line.
|
||||
nodes_mutex_.lock();
|
||||
node_graph_interfaces_mutex_.lock();
|
||||
}
|
||||
// This lock is released when the loop continues or exits.
|
||||
std::lock_guard<std::mutex> nodes_lock(nodes_mutex_, std::adopt_lock);
|
||||
std::lock_guard<std::mutex> nodes_lock(node_graph_interfaces_mutex_, std::adopt_lock);
|
||||
|
||||
// Resize the wait set if necessary.
|
||||
if (wait_set_.size_of_guard_conditions < (nodes_.size() + 2)) {
|
||||
ret = rcl_wait_set_resize_guard_conditions(&wait_set_, nodes_.size() + 2);
|
||||
if (wait_set_.size_of_guard_conditions < (node_graph_interfaces_.size() + 2)) {
|
||||
ret = rcl_wait_set_resize_guard_conditions(&wait_set_, node_graph_interfaces_.size() + 2);
|
||||
if (RCL_RET_OK != ret) {
|
||||
throw_from_rcl_error(ret, "failed to resize wait set");
|
||||
}
|
||||
@@ -145,13 +146,13 @@ GraphListener::run_loop()
|
||||
throw_from_rcl_error(ret, "failed to add shutdown guard condition to wait set");
|
||||
}
|
||||
// Put graph guard conditions for each node into the wait set.
|
||||
for (const auto node_ptr : nodes_) {
|
||||
for (const auto node_ptr : node_graph_interfaces_) {
|
||||
// Only wait on graph changes if some user of the node is watching.
|
||||
if (node_ptr->count_graph_users() == 0) {
|
||||
continue;
|
||||
}
|
||||
// Add the graph guard condition for the node to the wait set.
|
||||
auto graph_gc = rcl_node_get_graph_guard_condition(node_ptr->get_rcl_node_handle());
|
||||
auto graph_gc = node_ptr->get_graph_guard_condition();
|
||||
if (!graph_gc) {
|
||||
throw_from_rcl_error(RCL_RET_ERROR, "failed to get graph guard condition");
|
||||
}
|
||||
@@ -178,8 +179,8 @@ GraphListener::run_loop()
|
||||
}
|
||||
}
|
||||
// Notify nodes who's guard conditions are set (triggered).
|
||||
for (const auto node_ptr : nodes_) {
|
||||
auto graph_gc = rcl_node_get_graph_guard_condition(node_ptr->get_rcl_node_handle());
|
||||
for (const auto node_ptr : node_graph_interfaces_) {
|
||||
auto graph_gc = node_ptr->get_graph_guard_condition();
|
||||
if (!graph_gc) {
|
||||
throw_from_rcl_error(RCL_RET_ERROR, "failed to get graph guard condition");
|
||||
}
|
||||
@@ -207,25 +208,27 @@ interrupt_(rcl_guard_condition_t * interrupt_guard_condition)
|
||||
|
||||
static void
|
||||
acquire_nodes_lock_(
|
||||
std::mutex * nodes_barrier_mutex,
|
||||
std::mutex * nodes_mutex,
|
||||
std::mutex * node_graph_interfaces_barrier_mutex,
|
||||
std::mutex * node_graph_interfaces_mutex,
|
||||
rcl_guard_condition_t * interrupt_guard_condition)
|
||||
{
|
||||
{
|
||||
// Acquire this lock to prevent the run loop from re-locking the
|
||||
// nodes_mutext_ after being woken up.
|
||||
std::lock_guard<std::mutex> nodes_barrier_lock(*nodes_barrier_mutex);
|
||||
std::lock_guard<std::mutex> nodes_barrier_lock(*node_graph_interfaces_barrier_mutex);
|
||||
// Trigger the interrupt guard condition to wake up rcl_wait.
|
||||
interrupt_(interrupt_guard_condition);
|
||||
nodes_mutex->lock();
|
||||
node_graph_interfaces_mutex->lock();
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
has_node_(std::vector<rclcpp::node::Node *> * nodes, rclcpp::node::Node * node)
|
||||
has_node_(
|
||||
std::vector<rclcpp::node_interfaces::NodeGraphInterface *> * node_graph_interfaces,
|
||||
rclcpp::node_interfaces::NodeGraphInterface * node_graph)
|
||||
{
|
||||
for (const auto node_ptr : (*nodes)) {
|
||||
if (node == node_ptr) {
|
||||
for (const auto node_ptr : (*node_graph_interfaces)) {
|
||||
if (node_graph == node_ptr) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -233,23 +236,26 @@ has_node_(std::vector<rclcpp::node::Node *> * nodes, rclcpp::node::Node * node)
|
||||
}
|
||||
|
||||
bool
|
||||
GraphListener::has_node(rclcpp::node::Node * node)
|
||||
GraphListener::has_node(rclcpp::node_interfaces::NodeGraphInterface * node_graph)
|
||||
{
|
||||
if (!node) {
|
||||
if (!node_graph) {
|
||||
return false;
|
||||
}
|
||||
// Acquire the nodes mutex using the barrier to prevent the run loop from
|
||||
// re-locking the nodes mutex after being interrupted.
|
||||
acquire_nodes_lock_(&nodes_barrier_mutex_, &nodes_mutex_, &interrupt_guard_condition_);
|
||||
// Store the now acquired nodes_mutex_ in the scoped lock using adopt_lock.
|
||||
std::lock_guard<std::mutex> nodes_lock(nodes_mutex_, std::adopt_lock);
|
||||
return has_node_(&nodes_, node);
|
||||
acquire_nodes_lock_(
|
||||
&node_graph_interfaces_barrier_mutex_,
|
||||
&node_graph_interfaces_mutex_,
|
||||
&interrupt_guard_condition_);
|
||||
// Store the now acquired node_graph_interfaces_mutex_ in the scoped lock using adopt_lock.
|
||||
std::lock_guard<std::mutex> nodes_lock(node_graph_interfaces_mutex_, std::adopt_lock);
|
||||
return has_node_(&node_graph_interfaces_, node_graph);
|
||||
}
|
||||
|
||||
void
|
||||
GraphListener::add_node(rclcpp::node::Node * node)
|
||||
GraphListener::add_node(rclcpp::node_interfaces::NodeGraphInterface * node_graph)
|
||||
{
|
||||
if (!node) {
|
||||
if (!node_graph) {
|
||||
throw std::invalid_argument("node is nullptr");
|
||||
}
|
||||
std::lock_guard<std::mutex> shutdown_lock(shutdown_mutex_);
|
||||
@@ -259,25 +265,30 @@ GraphListener::add_node(rclcpp::node::Node * node)
|
||||
|
||||
// Acquire the nodes mutex using the barrier to prevent the run loop from
|
||||
// re-locking the nodes mutex after being interrupted.
|
||||
acquire_nodes_lock_(&nodes_barrier_mutex_, &nodes_mutex_, &interrupt_guard_condition_);
|
||||
// Store the now acquired nodes_mutex_ in the scoped lock using adopt_lock.
|
||||
std::lock_guard<std::mutex> nodes_lock(nodes_mutex_, std::adopt_lock);
|
||||
if (has_node_(&nodes_, node)) {
|
||||
acquire_nodes_lock_(
|
||||
&node_graph_interfaces_barrier_mutex_,
|
||||
&node_graph_interfaces_mutex_,
|
||||
&interrupt_guard_condition_);
|
||||
// Store the now acquired node_graph_interfaces_mutex_ in the scoped lock using adopt_lock.
|
||||
std::lock_guard<std::mutex> nodes_lock(node_graph_interfaces_mutex_, std::adopt_lock);
|
||||
if (has_node_(&node_graph_interfaces_, node_graph)) {
|
||||
throw NodeAlreadyAddedError();
|
||||
}
|
||||
nodes_.push_back(node);
|
||||
node_graph_interfaces_.push_back(node_graph);
|
||||
// The run loop has already been interrupted by acquire_nodes_lock_() and
|
||||
// will evaluate the new node when nodes_lock releases the nodes_mutex_.
|
||||
// will evaluate the new node when nodes_lock releases the node_graph_interfaces_mutex_.
|
||||
}
|
||||
|
||||
static void
|
||||
remove_node_(std::vector<rclcpp::node::Node *> * nodes, rclcpp::node::Node * node)
|
||||
remove_node_(
|
||||
std::vector<rclcpp::node_interfaces::NodeGraphInterface *> * node_graph_interfaces,
|
||||
rclcpp::node_interfaces::NodeGraphInterface * node_graph)
|
||||
{
|
||||
// Remove the node if it is found.
|
||||
for (auto it = nodes->begin(); it != nodes->end(); ++it) {
|
||||
if (node == *it) {
|
||||
for (auto it = node_graph_interfaces->begin(); it != node_graph_interfaces->end(); ++it) {
|
||||
if (node_graph == *it) {
|
||||
// Found the node, remove it.
|
||||
nodes->erase(it);
|
||||
node_graph_interfaces->erase(it);
|
||||
// Now trigger the interrupt guard condition to make sure
|
||||
return;
|
||||
}
|
||||
@@ -287,23 +298,26 @@ remove_node_(std::vector<rclcpp::node::Node *> * nodes, rclcpp::node::Node * nod
|
||||
}
|
||||
|
||||
void
|
||||
GraphListener::remove_node(rclcpp::node::Node * node)
|
||||
GraphListener::remove_node(rclcpp::node_interfaces::NodeGraphInterface * node_graph)
|
||||
{
|
||||
if (!node) {
|
||||
if (!node_graph) {
|
||||
throw std::invalid_argument("node is nullptr");
|
||||
}
|
||||
std::lock_guard<std::mutex> shutdown_lock(shutdown_mutex_);
|
||||
if (is_shutdown()) {
|
||||
// If shutdown, then the run loop has been joined, so we can remove them directly.
|
||||
return remove_node_(&nodes_, node);
|
||||
return remove_node_(&node_graph_interfaces_, node_graph);
|
||||
}
|
||||
// Otherwise, first interrupt and lock against the run loop to safely remove the node.
|
||||
// Acquire the nodes mutex using the barrier to prevent the run loop from
|
||||
// re-locking the nodes mutex after being interrupted.
|
||||
acquire_nodes_lock_(&nodes_barrier_mutex_, &nodes_mutex_, &interrupt_guard_condition_);
|
||||
// Store the now acquired nodes_mutex_ in the scoped lock using adopt_lock.
|
||||
std::lock_guard<std::mutex> nodes_lock(nodes_mutex_, std::adopt_lock);
|
||||
remove_node_(&nodes_, node);
|
||||
acquire_nodes_lock_(
|
||||
&node_graph_interfaces_barrier_mutex_,
|
||||
&node_graph_interfaces_mutex_,
|
||||
&interrupt_guard_condition_);
|
||||
// Store the now acquired node_graph_interfaces_mutex_ in the scoped lock using adopt_lock.
|
||||
std::lock_guard<std::mutex> nodes_lock(node_graph_interfaces_mutex_, std::adopt_lock);
|
||||
remove_node_(&node_graph_interfaces_, node_graph);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
#include "rclcpp/memory_strategies.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "rclcpp/strategies/allocator_memory_strategy.hpp"
|
||||
|
||||
using rclcpp::memory_strategies::allocator_memory_strategy::AllocatorMemoryStrategy;
|
||||
|
||||
@@ -60,8 +60,9 @@ MemoryStrategy::get_service_by_handle(const rcl_service_t * service_handle,
|
||||
if (!group) {
|
||||
continue;
|
||||
}
|
||||
for (auto & service : group->get_service_ptrs()) {
|
||||
if (service->get_service_handle() == service_handle) {
|
||||
for (auto & weak_service : group->get_service_ptrs()) {
|
||||
auto service = weak_service.lock();
|
||||
if (service && service->get_service_handle() == service_handle) {
|
||||
return service;
|
||||
}
|
||||
}
|
||||
@@ -95,7 +96,7 @@ MemoryStrategy::get_client_by_handle(const rcl_client_t * client_handle,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
rclcpp::node::Node::SharedPtr
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr
|
||||
MemoryStrategy::get_node_by_group(rclcpp::callback_group::CallbackGroup::SharedPtr group,
|
||||
const WeakNodeVector & weak_nodes)
|
||||
{
|
||||
@@ -158,8 +159,9 @@ MemoryStrategy::get_group_by_service(
|
||||
if (!group) {
|
||||
continue;
|
||||
}
|
||||
for (auto & serv : group->get_service_ptrs()) {
|
||||
if (serv == service) {
|
||||
for (auto & weak_serv : group->get_service_ptrs()) {
|
||||
auto serv = weak_serv.lock();
|
||||
if (serv && serv == service) {
|
||||
return group;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,14 +15,20 @@
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "rcl_interfaces/srv/list_parameters.hpp"
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
#include "rclcpp/graph_listener.hpp"
|
||||
#include "rclcpp/node.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base.hpp"
|
||||
#include "rclcpp/node_interfaces/node_graph.hpp"
|
||||
#include "rclcpp/node_interfaces/node_parameters.hpp"
|
||||
#include "rclcpp/node_interfaces/node_services.hpp"
|
||||
#include "rclcpp/node_interfaces/node_timers.hpp"
|
||||
#include "rclcpp/node_interfaces/node_topics.hpp"
|
||||
|
||||
using rclcpp::node::Node;
|
||||
using rclcpp::exceptions::throw_from_rcl_error;
|
||||
@@ -38,443 +44,123 @@ Node::Node(
|
||||
const std::string & node_name,
|
||||
rclcpp::context::Context::SharedPtr context,
|
||||
bool use_intra_process_comms)
|
||||
: name_(node_name), context_(context),
|
||||
number_of_subscriptions_(0), number_of_timers_(0), number_of_services_(0),
|
||||
use_intra_process_comms_(use_intra_process_comms), notify_guard_condition_is_valid_(false),
|
||||
graph_listener_(context->get_sub_context<rclcpp::graph_listener::GraphListener>()),
|
||||
should_add_to_graph_listener_(true), graph_users_count_(0)
|
||||
: node_base_(new rclcpp::node_interfaces::NodeBase(node_name, context)),
|
||||
node_graph_(new rclcpp::node_interfaces::NodeGraph(node_base_.get())),
|
||||
node_timers_(new rclcpp::node_interfaces::NodeTimers(node_base_.get())),
|
||||
node_topics_(new rclcpp::node_interfaces::NodeTopics(node_base_.get())),
|
||||
node_services_(new rclcpp::node_interfaces::NodeServices(node_base_.get())),
|
||||
node_parameters_(new rclcpp::node_interfaces::NodeParameters(
|
||||
node_topics_.get(),
|
||||
use_intra_process_comms
|
||||
)),
|
||||
use_intra_process_comms_(use_intra_process_comms)
|
||||
{
|
||||
rcl_guard_condition_options_t guard_condition_options = rcl_guard_condition_get_default_options();
|
||||
rcl_ret_t ret = rcl_guard_condition_init(¬ify_guard_condition_, guard_condition_options);
|
||||
if (ret != RCL_RET_OK) {
|
||||
throw_from_rcl_error(ret, "failed to create interrupt guard condition");
|
||||
}
|
||||
|
||||
has_executor.store(false);
|
||||
size_t domain_id = 0;
|
||||
char * ros_domain_id = nullptr;
|
||||
const char * env_var = "ROS_DOMAIN_ID";
|
||||
#ifndef _WIN32
|
||||
ros_domain_id = getenv(env_var);
|
||||
#else
|
||||
size_t ros_domain_id_size;
|
||||
_dupenv_s(&ros_domain_id, &ros_domain_id_size, env_var);
|
||||
#endif
|
||||
if (ros_domain_id) {
|
||||
uint32_t number = strtoul(ros_domain_id, NULL, 0);
|
||||
if (number == (std::numeric_limits<uint32_t>::max)()) {
|
||||
// Finalize the interrupt guard condition.
|
||||
if (rcl_guard_condition_fini(¬ify_guard_condition_) != RCL_RET_OK) {
|
||||
fprintf(stderr,
|
||||
"[rclcpp::error] failed to destroy guard condition: %s\n", rcl_get_error_string_safe());
|
||||
}
|
||||
throw std::runtime_error("failed to interpret ROS_DOMAIN_ID as integral number");
|
||||
}
|
||||
domain_id = static_cast<size_t>(number);
|
||||
#ifdef _WIN32
|
||||
free(ros_domain_id);
|
||||
#endif
|
||||
}
|
||||
|
||||
rcl_node_t * rcl_node = new rcl_node_t(rcl_get_zero_initialized_node());
|
||||
node_handle_.reset(rcl_node, [](rcl_node_t * node) {
|
||||
if (rcl_node_fini(node) != RCL_RET_OK) {
|
||||
fprintf(
|
||||
stderr, "Error in destruction of rmw node handle: %s\n", rcl_get_error_string_safe());
|
||||
}
|
||||
delete node;
|
||||
});
|
||||
rcl_node_options_t options = rcl_node_get_default_options();
|
||||
// TODO(jacquelinekay): Allocator options
|
||||
options.domain_id = domain_id;
|
||||
ret = rcl_node_init(node_handle_.get(), name_.c_str(), &options);
|
||||
if (ret != RCL_RET_OK) {
|
||||
// Finalize the interrupt guard condition.
|
||||
if (rcl_guard_condition_fini(¬ify_guard_condition_) != RCL_RET_OK) {
|
||||
fprintf(stderr,
|
||||
"[rclcpp::error] failed to destroy guard condition: %s\n", rcl_get_error_string_safe());
|
||||
}
|
||||
|
||||
throw_from_rcl_error(ret, "failed to initialize rcl node");
|
||||
}
|
||||
|
||||
using rclcpp::callback_group::CallbackGroupType;
|
||||
default_callback_group_ = create_callback_group(
|
||||
CallbackGroupType::MutuallyExclusive);
|
||||
events_publisher_ = create_publisher<rcl_interfaces::msg::ParameterEvent>(
|
||||
"parameter_events", rmw_qos_profile_parameter_events);
|
||||
notify_guard_condition_is_valid_ = true;
|
||||
}
|
||||
|
||||
Node::~Node()
|
||||
{
|
||||
// Remove self from graph listener.
|
||||
// Exchange with false to prevent others from trying to add this node to the
|
||||
// graph listener after checking that it was not here.
|
||||
if (!should_add_to_graph_listener_.exchange(false)) {
|
||||
// If it was already false, then it needs to now be removed.
|
||||
graph_listener_->remove_node(this);
|
||||
}
|
||||
// Finalize the interrupt guard condition after removing self from graph listener.
|
||||
{
|
||||
std::lock_guard<std::mutex> notify_guard_condition_lock(notify_guard_condition_mutex_);
|
||||
notify_guard_condition_is_valid_ = false;
|
||||
if (rcl_guard_condition_fini(¬ify_guard_condition_) != RCL_RET_OK) {
|
||||
fprintf(stderr,
|
||||
"[rclcpp::error] failed to destroy guard condition: %s\n", rcl_get_error_string_safe());
|
||||
}
|
||||
}
|
||||
}
|
||||
{}
|
||||
|
||||
const std::string &
|
||||
const char *
|
||||
Node::get_name() const
|
||||
{
|
||||
return name_;
|
||||
return node_base_->get_name();
|
||||
}
|
||||
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr
|
||||
Node::create_callback_group(
|
||||
rclcpp::callback_group::CallbackGroupType group_type)
|
||||
{
|
||||
using rclcpp::callback_group::CallbackGroup;
|
||||
using rclcpp::callback_group::CallbackGroupType;
|
||||
auto group = CallbackGroup::SharedPtr(new CallbackGroup(group_type));
|
||||
callback_groups_.push_back(group);
|
||||
return group;
|
||||
return node_base_->create_callback_group(group_type);
|
||||
}
|
||||
|
||||
bool
|
||||
Node::group_in_node(rclcpp::callback_group::CallbackGroup::SharedPtr group)
|
||||
{
|
||||
bool group_belongs_to_this_node = false;
|
||||
for (auto & weak_group : this->callback_groups_) {
|
||||
auto cur_group = weak_group.lock();
|
||||
if (cur_group && (cur_group == group)) {
|
||||
group_belongs_to_this_node = true;
|
||||
}
|
||||
}
|
||||
return group_belongs_to_this_node;
|
||||
return node_base_->callback_group_in_node(group);
|
||||
}
|
||||
|
||||
// TODO(wjwwood): reenable this once I figure out why the demo doesn't build with it.
|
||||
// rclcpp::timer::WallTimer::SharedPtr
|
||||
// Node::create_wall_timer(
|
||||
// std::chrono::duration<long double, std::nano> period,
|
||||
// rclcpp::timer::CallbackType callback,
|
||||
// rclcpp::callback_group::CallbackGroup::SharedPtr group)
|
||||
// {
|
||||
// return create_wall_timer(
|
||||
// std::chrono::duration_cast<std::chrono::nanoseconds>(period),
|
||||
// callback,
|
||||
// group);
|
||||
// }
|
||||
|
||||
std::vector<rcl_interfaces::msg::SetParametersResult>
|
||||
Node::set_parameters(
|
||||
const std::vector<rclcpp::parameter::ParameterVariant> & parameters)
|
||||
{
|
||||
std::vector<rcl_interfaces::msg::SetParametersResult> results;
|
||||
for (auto p : parameters) {
|
||||
auto result = set_parameters_atomically({{p}});
|
||||
results.push_back(result);
|
||||
}
|
||||
return results;
|
||||
return node_parameters_->set_parameters(parameters);
|
||||
}
|
||||
|
||||
rcl_interfaces::msg::SetParametersResult
|
||||
Node::set_parameters_atomically(
|
||||
const std::vector<rclcpp::parameter::ParameterVariant> & parameters)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
std::map<std::string, rclcpp::parameter::ParameterVariant> tmp_map;
|
||||
auto parameter_event = std::make_shared<rcl_interfaces::msg::ParameterEvent>();
|
||||
|
||||
for (auto p : parameters) {
|
||||
if (parameters_.find(p.get_name()) == parameters_.end()) {
|
||||
if (p.get_type() != rclcpp::parameter::ParameterType::PARAMETER_NOT_SET) {
|
||||
parameter_event->new_parameters.push_back(p.to_parameter());
|
||||
}
|
||||
} else if (p.get_type() != rclcpp::parameter::ParameterType::PARAMETER_NOT_SET) {
|
||||
parameter_event->changed_parameters.push_back(p.to_parameter());
|
||||
} else {
|
||||
parameter_event->deleted_parameters.push_back(p.to_parameter());
|
||||
}
|
||||
tmp_map[p.get_name()] = p;
|
||||
}
|
||||
// std::map::insert will not overwrite elements, so we'll keep the new
|
||||
// ones and add only those that already exist in the Node's internal map
|
||||
tmp_map.insert(parameters_.begin(), parameters_.end());
|
||||
std::swap(tmp_map, parameters_);
|
||||
|
||||
// TODO(jacquelinekay): handle parameter constraints
|
||||
rcl_interfaces::msg::SetParametersResult result;
|
||||
result.successful = true;
|
||||
|
||||
events_publisher_->publish(parameter_event);
|
||||
|
||||
return result;
|
||||
return node_parameters_->set_parameters_atomically(parameters);
|
||||
}
|
||||
|
||||
std::vector<rclcpp::parameter::ParameterVariant>
|
||||
Node::get_parameters(
|
||||
const std::vector<std::string> & names) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
std::vector<rclcpp::parameter::ParameterVariant> results;
|
||||
return node_parameters_->get_parameters(names);
|
||||
}
|
||||
|
||||
for (auto & name : names) {
|
||||
if (std::any_of(parameters_.cbegin(), parameters_.cend(),
|
||||
[&name](const std::pair<std::string, rclcpp::parameter::ParameterVariant> & kv) {
|
||||
return name == kv.first;
|
||||
}))
|
||||
{
|
||||
results.push_back(parameters_.at(name));
|
||||
}
|
||||
}
|
||||
return results;
|
||||
rclcpp::parameter::ParameterVariant
|
||||
Node::get_parameter(const std::string & name) const
|
||||
{
|
||||
return node_parameters_->get_parameter(name);
|
||||
}
|
||||
|
||||
bool Node::get_parameter(const std::string & name,
|
||||
rclcpp::parameter::ParameterVariant & parameter) const
|
||||
{
|
||||
return node_parameters_->get_parameter(name, parameter);
|
||||
}
|
||||
|
||||
std::vector<rcl_interfaces::msg::ParameterDescriptor>
|
||||
Node::describe_parameters(
|
||||
const std::vector<std::string> & names) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
std::vector<rcl_interfaces::msg::ParameterDescriptor> results;
|
||||
for (auto & kv : parameters_) {
|
||||
if (std::any_of(names.cbegin(), names.cend(), [&kv](const std::string & name) {
|
||||
return name == kv.first;
|
||||
}))
|
||||
{
|
||||
rcl_interfaces::msg::ParameterDescriptor parameter_descriptor;
|
||||
parameter_descriptor.name = kv.first;
|
||||
parameter_descriptor.type = kv.second.get_type();
|
||||
results.push_back(parameter_descriptor);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
return node_parameters_->describe_parameters(names);
|
||||
}
|
||||
|
||||
std::vector<uint8_t>
|
||||
Node::get_parameter_types(
|
||||
const std::vector<std::string> & names) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
std::vector<uint8_t> results;
|
||||
for (auto & kv : parameters_) {
|
||||
if (std::any_of(names.cbegin(), names.cend(), [&kv](const std::string & name) {
|
||||
return name == kv.first;
|
||||
}))
|
||||
{
|
||||
results.push_back(kv.second.get_type());
|
||||
} else {
|
||||
results.push_back(rcl_interfaces::msg::ParameterType::PARAMETER_NOT_SET);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
return node_parameters_->get_parameter_types(names);
|
||||
}
|
||||
|
||||
rcl_interfaces::msg::ListParametersResult
|
||||
Node::list_parameters(
|
||||
const std::vector<std::string> & prefixes, uint64_t depth) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
rcl_interfaces::msg::ListParametersResult result;
|
||||
|
||||
// TODO(esteve): define parameter separator, use "." for now
|
||||
for (auto & kv : parameters_) {
|
||||
if (((prefixes.size() == 0) &&
|
||||
((depth == rcl_interfaces::srv::ListParameters::Request::DEPTH_RECURSIVE) ||
|
||||
(static_cast<uint64_t>(std::count(kv.first.begin(), kv.first.end(), '.')) < depth))) ||
|
||||
(std::any_of(prefixes.cbegin(), prefixes.cend(), [&kv, &depth](const std::string & prefix) {
|
||||
if (kv.first == prefix) {
|
||||
return true;
|
||||
} else if (kv.first.find(prefix + ".") == 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(), '.')) < depth);
|
||||
}
|
||||
return false;
|
||||
})))
|
||||
{
|
||||
result.names.push_back(kv.first);
|
||||
size_t last_separator = kv.first.find_last_of('.');
|
||||
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) ==
|
||||
result.prefixes.cend())
|
||||
{
|
||||
result.prefixes.push_back(prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return node_parameters_->list_parameters(prefixes, depth);
|
||||
}
|
||||
|
||||
std::map<std::string, std::string>
|
||||
Node::get_topic_names_and_types() const
|
||||
{
|
||||
rmw_topic_names_and_types_t topic_names_and_types;
|
||||
topic_names_and_types.topic_count = 0;
|
||||
topic_names_and_types.topic_names = nullptr;
|
||||
topic_names_and_types.type_names = nullptr;
|
||||
|
||||
auto ret = rmw_get_topic_names_and_types(rcl_node_get_rmw_handle(node_handle_.get()),
|
||||
&topic_names_and_types);
|
||||
if (ret != RMW_RET_OK) {
|
||||
// *INDENT-OFF*
|
||||
throw std::runtime_error(
|
||||
std::string("could not get topic names and types: ") + rmw_get_error_string_safe());
|
||||
// *INDENT-ON*
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> topics;
|
||||
for (size_t i = 0; i < topic_names_and_types.topic_count; ++i) {
|
||||
topics[topic_names_and_types.topic_names[i]] = topic_names_and_types.type_names[i];
|
||||
}
|
||||
|
||||
ret = rmw_destroy_topic_names_and_types(&topic_names_and_types);
|
||||
if (ret != RMW_RET_OK) {
|
||||
// *INDENT-OFF*
|
||||
throw std::runtime_error(
|
||||
std::string("could not destroy topic names and types: ") + rmw_get_error_string_safe());
|
||||
// *INDENT-ON*
|
||||
}
|
||||
|
||||
return topics;
|
||||
return node_graph_->get_topic_names_and_types();
|
||||
}
|
||||
|
||||
size_t
|
||||
Node::count_publishers(const std::string & topic_name) const
|
||||
{
|
||||
size_t count;
|
||||
auto ret = rmw_count_publishers(rcl_node_get_rmw_handle(node_handle_.get()),
|
||||
topic_name.c_str(), &count);
|
||||
if (ret != RMW_RET_OK) {
|
||||
// *INDENT-OFF*
|
||||
throw std::runtime_error(
|
||||
std::string("could not count publishers: ") + rmw_get_error_string_safe());
|
||||
// *INDENT-ON*
|
||||
}
|
||||
return count;
|
||||
return node_graph_->count_publishers(topic_name);
|
||||
}
|
||||
|
||||
size_t
|
||||
Node::count_subscribers(const std::string & topic_name) const
|
||||
{
|
||||
size_t count;
|
||||
auto ret = rmw_count_subscribers(rcl_node_get_rmw_handle(node_handle_.get()),
|
||||
topic_name.c_str(), &count);
|
||||
if (ret != RMW_RET_OK) {
|
||||
// *INDENT-OFF*
|
||||
throw std::runtime_error(
|
||||
std::string("could not count subscribers: ") + rmw_get_error_string_safe());
|
||||
// *INDENT-ON*
|
||||
}
|
||||
return count;
|
||||
return node_graph_->count_subscribers(topic_name);
|
||||
}
|
||||
|
||||
|
||||
const Node::CallbackGroupWeakPtrList &
|
||||
const std::vector<rclcpp::callback_group::CallbackGroup::WeakPtr> &
|
||||
Node::get_callback_groups() const
|
||||
{
|
||||
return callback_groups_;
|
||||
}
|
||||
|
||||
const rcl_guard_condition_t *
|
||||
Node::get_notify_guard_condition() const
|
||||
{
|
||||
std::lock_guard<std::mutex> notify_guard_condition_lock(notify_guard_condition_mutex_);
|
||||
if (!notify_guard_condition_is_valid_) {
|
||||
return nullptr;
|
||||
}
|
||||
return ¬ify_guard_condition_;
|
||||
}
|
||||
|
||||
const rcl_guard_condition_t *
|
||||
Node::get_graph_guard_condition() const
|
||||
{
|
||||
return rcl_node_get_graph_guard_condition(node_handle_.get());
|
||||
}
|
||||
|
||||
const rcl_node_t *
|
||||
Node::get_rcl_node_handle() const
|
||||
{
|
||||
return node_handle_.get();
|
||||
}
|
||||
|
||||
rcl_node_t *
|
||||
Node::get_rcl_node_handle()
|
||||
{
|
||||
return node_handle_.get();
|
||||
}
|
||||
|
||||
std::shared_ptr<rcl_node_t>
|
||||
Node::get_shared_node_handle()
|
||||
{
|
||||
return node_handle_;
|
||||
}
|
||||
|
||||
void
|
||||
Node::notify_graph_change()
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> graph_changed_lock(graph_mutex_);
|
||||
bool bad_ptr_encountered = false;
|
||||
for (auto & event_wptr : graph_events_) {
|
||||
auto event_ptr = event_wptr.lock();
|
||||
if (event_ptr) {
|
||||
event_ptr->set();
|
||||
} else {
|
||||
bad_ptr_encountered = true;
|
||||
}
|
||||
}
|
||||
if (bad_ptr_encountered) {
|
||||
// remove invalid pointers with the erase-remove idiom
|
||||
graph_events_.erase(
|
||||
std::remove_if(
|
||||
graph_events_.begin(),
|
||||
graph_events_.end(),
|
||||
[](const rclcpp::event::Event::WeakPtr & wptr) {
|
||||
return wptr.expired();
|
||||
}),
|
||||
graph_events_.end());
|
||||
// update graph_users_count_
|
||||
graph_users_count_.store(graph_events_.size());
|
||||
}
|
||||
}
|
||||
graph_cv_.notify_all();
|
||||
{
|
||||
std::lock_guard<std::mutex> notify_guard_condition_lock(notify_guard_condition_mutex_);
|
||||
rcl_ret_t ret = rcl_trigger_guard_condition(¬ify_guard_condition_);
|
||||
if (RCL_RET_OK != ret) {
|
||||
throw_from_rcl_error(ret, "failed to trigger notify guard condition");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Node::notify_shutdown()
|
||||
{
|
||||
// notify here anything that will not be woken up by ctrl-c or rclcpp::shutdown().
|
||||
graph_cv_.notify_all();
|
||||
return node_base_->get_callback_groups();
|
||||
}
|
||||
|
||||
rclcpp::event::Event::SharedPtr
|
||||
Node::get_graph_event()
|
||||
{
|
||||
auto event = rclcpp::event::Event::make_shared();
|
||||
std::lock_guard<std::mutex> graph_changed_lock(graph_mutex_);
|
||||
// on first call, add node to graph_listener_
|
||||
if (should_add_to_graph_listener_.exchange(false)) {
|
||||
graph_listener_->add_node(this);
|
||||
graph_listener_->start_if_not_started();
|
||||
}
|
||||
graph_events_.push_back(event);
|
||||
graph_users_count_++;
|
||||
return event;
|
||||
return node_graph_->get_graph_event();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -482,30 +168,41 @@ Node::wait_for_graph_change(
|
||||
rclcpp::event::Event::SharedPtr event,
|
||||
std::chrono::nanoseconds timeout)
|
||||
{
|
||||
if (!event) {
|
||||
throw InvalidEventError();
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> graph_changed_lock(graph_mutex_);
|
||||
bool event_in_graph_events = false;
|
||||
for (const auto & event_wptr : graph_events_) {
|
||||
if (event == event_wptr.lock()) {
|
||||
event_in_graph_events = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!event_in_graph_events) {
|
||||
throw EventNotRegisteredError();
|
||||
}
|
||||
}
|
||||
std::unique_lock<std::mutex> graph_lock(graph_mutex_);
|
||||
graph_cv_.wait_for(graph_lock, timeout, [&event]() {
|
||||
return event->check() || !rclcpp::utilities::ok();
|
||||
});
|
||||
node_graph_->wait_for_graph_change(event, timeout);
|
||||
}
|
||||
|
||||
size_t
|
||||
Node::count_graph_users()
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr
|
||||
Node::get_node_base_interface()
|
||||
{
|
||||
return graph_users_count_.load();
|
||||
return node_base_;
|
||||
}
|
||||
|
||||
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr
|
||||
Node::get_node_graph_interface()
|
||||
{
|
||||
return node_graph_;
|
||||
}
|
||||
|
||||
rclcpp::node_interfaces::NodeTimersInterface::SharedPtr
|
||||
Node::get_node_timers_interface()
|
||||
{
|
||||
return node_timers_;
|
||||
}
|
||||
|
||||
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr
|
||||
Node::get_node_topics_interface()
|
||||
{
|
||||
return node_topics_;
|
||||
}
|
||||
|
||||
rclcpp::node_interfaces::NodeServicesInterface::SharedPtr
|
||||
Node::get_node_services_interface()
|
||||
{
|
||||
return node_services_;
|
||||
}
|
||||
|
||||
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr
|
||||
Node::get_node_parameters_interface()
|
||||
{
|
||||
return node_parameters_;
|
||||
}
|
||||
|
||||
215
rclcpp/src/rclcpp/node_interfaces/node_base.cpp
Normal file
215
rclcpp/src/rclcpp/node_interfaces/node_base.cpp
Normal file
@@ -0,0 +1,215 @@
|
||||
// Copyright 2016 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 <string>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "rclcpp/node_interfaces/node_base.hpp"
|
||||
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
|
||||
using rclcpp::exceptions::throw_from_rcl_error;
|
||||
|
||||
using rclcpp::node_interfaces::NodeBase;
|
||||
|
||||
NodeBase::NodeBase(
|
||||
const std::string & node_name,
|
||||
rclcpp::context::Context::SharedPtr context)
|
||||
: context_(context),
|
||||
node_handle_(nullptr),
|
||||
default_callback_group_(nullptr),
|
||||
associated_with_executor_(false),
|
||||
notify_guard_condition_is_valid_(false)
|
||||
{
|
||||
// Setup the guard condition that is notified when changes occur in the graph.
|
||||
rcl_guard_condition_options_t guard_condition_options = rcl_guard_condition_get_default_options();
|
||||
rcl_ret_t ret = rcl_guard_condition_init(¬ify_guard_condition_, guard_condition_options);
|
||||
if (ret != RCL_RET_OK) {
|
||||
throw_from_rcl_error(ret, "failed to create interrupt guard condition");
|
||||
}
|
||||
|
||||
// Setup a safe exit lamda to clean up the guard condition in case of an error here.
|
||||
auto finalize_notify_guard_condition = [this]() {
|
||||
// Finalize the interrupt guard condition.
|
||||
if (rcl_guard_condition_fini(¬ify_guard_condition_) != RCL_RET_OK) {
|
||||
fprintf(stderr,
|
||||
"[rclcpp::error] failed to destroy guard condition: %s\n", rcl_get_error_string_safe());
|
||||
}
|
||||
};
|
||||
|
||||
// Determine the domain id based on the options and the ROS_DOMAIN_ID env variable.
|
||||
size_t domain_id = 0;
|
||||
char * ros_domain_id = nullptr;
|
||||
const char * env_var = "ROS_DOMAIN_ID";
|
||||
#ifndef _WIN32
|
||||
ros_domain_id = getenv(env_var);
|
||||
#else
|
||||
size_t ros_domain_id_size;
|
||||
_dupenv_s(&ros_domain_id, &ros_domain_id_size, env_var);
|
||||
#endif
|
||||
if (ros_domain_id) {
|
||||
uint32_t number = strtoul(ros_domain_id, NULL, 0);
|
||||
if (number == (std::numeric_limits<uint32_t>::max)()) {
|
||||
// Finalize the interrupt guard condition.
|
||||
finalize_notify_guard_condition();
|
||||
#ifdef _WIN32
|
||||
// free the ros_domain_id before throwing, if getenv was used on Windows
|
||||
free(ros_domain_id);
|
||||
#endif
|
||||
|
||||
throw std::runtime_error("failed to interpret ROS_DOMAIN_ID as integral number");
|
||||
}
|
||||
domain_id = static_cast<size_t>(number);
|
||||
#ifdef _WIN32
|
||||
free(ros_domain_id);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Create the rcl node and store it in a shared_ptr with a custom destructor.
|
||||
rcl_node_t * rcl_node = new rcl_node_t(rcl_get_zero_initialized_node());
|
||||
|
||||
rcl_node_options_t options = rcl_node_get_default_options();
|
||||
// TODO(wjwwood): pass the Allocator to the options
|
||||
options.domain_id = domain_id;
|
||||
ret = rcl_node_init(rcl_node, node_name.c_str(), &options);
|
||||
if (ret != RCL_RET_OK) {
|
||||
// Finalize the interrupt guard condition.
|
||||
finalize_notify_guard_condition();
|
||||
|
||||
throw_from_rcl_error(ret, "failed to initialize rcl node");
|
||||
}
|
||||
|
||||
node_handle_.reset(rcl_node, [](rcl_node_t * node) -> void {
|
||||
if (rcl_node_fini(node) != RCL_RET_OK) {
|
||||
fprintf(
|
||||
stderr, "Error in destruction of rcl node handle: %s\n", rcl_get_error_string_safe());
|
||||
}
|
||||
delete node;
|
||||
});
|
||||
|
||||
// Create the default callback group.
|
||||
using rclcpp::callback_group::CallbackGroupType;
|
||||
default_callback_group_ = create_callback_group(CallbackGroupType::MutuallyExclusive);
|
||||
|
||||
// Indicate the notify_guard_condition is now valid.
|
||||
notify_guard_condition_is_valid_ = true;
|
||||
}
|
||||
|
||||
NodeBase::~NodeBase()
|
||||
{
|
||||
// Finalize the interrupt guard condition after removing self from graph listener.
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> notify_condition_lock(notify_guard_condition_mutex_);
|
||||
notify_guard_condition_is_valid_ = false;
|
||||
if (rcl_guard_condition_fini(¬ify_guard_condition_) != RCL_RET_OK) {
|
||||
fprintf(stderr,
|
||||
"[rclcpp::error] failed to destroy guard condition: %s\n", rcl_get_error_string_safe());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char *
|
||||
NodeBase::get_name() const
|
||||
{
|
||||
return rcl_node_get_name(node_handle_.get());
|
||||
}
|
||||
|
||||
rclcpp::context::Context::SharedPtr
|
||||
NodeBase::get_context()
|
||||
{
|
||||
return context_;
|
||||
}
|
||||
|
||||
rcl_node_t *
|
||||
NodeBase::get_rcl_node_handle()
|
||||
{
|
||||
return node_handle_.get();
|
||||
}
|
||||
|
||||
const rcl_node_t *
|
||||
NodeBase::get_rcl_node_handle() const
|
||||
{
|
||||
return node_handle_.get();
|
||||
}
|
||||
|
||||
std::shared_ptr<rcl_node_t>
|
||||
NodeBase::get_shared_rcl_node_handle()
|
||||
{
|
||||
return node_handle_;
|
||||
}
|
||||
|
||||
std::shared_ptr<const rcl_node_t>
|
||||
NodeBase::get_shared_rcl_node_handle() const
|
||||
{
|
||||
return node_handle_;
|
||||
}
|
||||
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr
|
||||
NodeBase::create_callback_group(rclcpp::callback_group::CallbackGroupType group_type)
|
||||
{
|
||||
using rclcpp::callback_group::CallbackGroup;
|
||||
using rclcpp::callback_group::CallbackGroupType;
|
||||
auto group = CallbackGroup::SharedPtr(new CallbackGroup(group_type));
|
||||
callback_groups_.push_back(group);
|
||||
return group;
|
||||
}
|
||||
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr
|
||||
NodeBase::get_default_callback_group()
|
||||
{
|
||||
return default_callback_group_;
|
||||
}
|
||||
|
||||
bool
|
||||
NodeBase::callback_group_in_node(rclcpp::callback_group::CallbackGroup::SharedPtr group)
|
||||
{
|
||||
bool group_belongs_to_this_node = false;
|
||||
for (auto & weak_group : this->callback_groups_) {
|
||||
auto cur_group = weak_group.lock();
|
||||
if (cur_group && (cur_group == group)) {
|
||||
group_belongs_to_this_node = true;
|
||||
}
|
||||
}
|
||||
return group_belongs_to_this_node;
|
||||
}
|
||||
|
||||
const std::vector<rclcpp::callback_group::CallbackGroup::WeakPtr> &
|
||||
NodeBase::get_callback_groups() const
|
||||
{
|
||||
return callback_groups_;
|
||||
}
|
||||
|
||||
std::atomic_bool &
|
||||
NodeBase::get_associated_with_executor_atomic()
|
||||
{
|
||||
return associated_with_executor_;
|
||||
}
|
||||
|
||||
rcl_guard_condition_t *
|
||||
NodeBase::get_notify_guard_condition()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> notify_condition_lock(notify_guard_condition_mutex_);
|
||||
if (!notify_guard_condition_is_valid_) {
|
||||
return nullptr;
|
||||
}
|
||||
return ¬ify_guard_condition_;
|
||||
}
|
||||
|
||||
std::unique_lock<std::recursive_mutex>
|
||||
NodeBase::acquire_notify_guard_condition_lock() const
|
||||
{
|
||||
return std::unique_lock<std::recursive_mutex>(notify_guard_condition_mutex_);
|
||||
}
|
||||
209
rclcpp/src/rclcpp/node_interfaces/node_graph.cpp
Normal file
209
rclcpp/src/rclcpp/node_interfaces/node_graph.cpp
Normal file
@@ -0,0 +1,209 @@
|
||||
// Copyright 2016 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "rclcpp/node_interfaces/node_graph.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "rcl/graph.h"
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
#include "rclcpp/event.hpp"
|
||||
#include "rclcpp/graph_listener.hpp"
|
||||
|
||||
using rclcpp::node_interfaces::NodeGraph;
|
||||
using rclcpp::exceptions::throw_from_rcl_error;
|
||||
using rclcpp::graph_listener::GraphListener;
|
||||
|
||||
NodeGraph::NodeGraph(rclcpp::node_interfaces::NodeBaseInterface * node_base)
|
||||
: node_base_(node_base),
|
||||
graph_listener_(node_base->get_context()->get_sub_context<GraphListener>()),
|
||||
should_add_to_graph_listener_(true),
|
||||
graph_users_count_(0)
|
||||
{}
|
||||
|
||||
NodeGraph::~NodeGraph()
|
||||
{
|
||||
// Remove self from graph listener.
|
||||
// Exchange with false to prevent others from trying to add this node to the
|
||||
// graph listener after checking that it was not here.
|
||||
if (!should_add_to_graph_listener_.exchange(false)) {
|
||||
// If it was already false, then it needs to now be removed.
|
||||
graph_listener_->remove_node(this);
|
||||
}
|
||||
}
|
||||
|
||||
std::map<std::string, std::string>
|
||||
NodeGraph::get_topic_names_and_types() const
|
||||
{
|
||||
rcl_topic_names_and_types_t topic_names_and_types =
|
||||
rcl_get_zero_initialized_topic_names_and_types();
|
||||
|
||||
auto ret = rcl_get_topic_names_and_types(node_base_->get_rcl_node_handle(),
|
||||
&topic_names_and_types);
|
||||
if (ret != RMW_RET_OK) {
|
||||
// *INDENT-OFF*
|
||||
throw std::runtime_error(
|
||||
std::string("could not get topic names and types: ") + rmw_get_error_string_safe());
|
||||
// *INDENT-ON*
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> topics;
|
||||
for (size_t i = 0; i < topic_names_and_types.topic_count; ++i) {
|
||||
topics[topic_names_and_types.topic_names[i]] = topic_names_and_types.type_names[i];
|
||||
}
|
||||
|
||||
ret = rmw_destroy_topic_names_and_types(&topic_names_and_types);
|
||||
if (ret != RMW_RET_OK) {
|
||||
// *INDENT-OFF*
|
||||
throw std::runtime_error(
|
||||
std::string("could not destroy topic names and types: ") + rmw_get_error_string_safe());
|
||||
// *INDENT-ON*
|
||||
}
|
||||
|
||||
return topics;
|
||||
}
|
||||
|
||||
size_t
|
||||
NodeGraph::count_publishers(const std::string & topic_name) const
|
||||
{
|
||||
size_t count;
|
||||
// TODO(wjwwood): use the rcl equivalent methods
|
||||
auto ret = rmw_count_publishers(rcl_node_get_rmw_handle(node_base_->get_rcl_node_handle()),
|
||||
topic_name.c_str(), &count);
|
||||
if (ret != RMW_RET_OK) {
|
||||
// *INDENT-OFF*
|
||||
throw std::runtime_error(
|
||||
std::string("could not count publishers: ") + rmw_get_error_string_safe());
|
||||
// *INDENT-ON*
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
size_t
|
||||
NodeGraph::count_subscribers(const std::string & topic_name) const
|
||||
{
|
||||
size_t count;
|
||||
// TODO(wjwwood): use the rcl equivalent methods
|
||||
auto ret = rmw_count_subscribers(rcl_node_get_rmw_handle(node_base_->get_rcl_node_handle()),
|
||||
topic_name.c_str(), &count);
|
||||
if (ret != RMW_RET_OK) {
|
||||
// *INDENT-OFF*
|
||||
throw std::runtime_error(
|
||||
std::string("could not count subscribers: ") + rmw_get_error_string_safe());
|
||||
// *INDENT-ON*
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
const rcl_guard_condition_t *
|
||||
NodeGraph::get_graph_guard_condition() const
|
||||
{
|
||||
return rcl_node_get_graph_guard_condition(node_base_->get_rcl_node_handle());
|
||||
}
|
||||
|
||||
void
|
||||
NodeGraph::notify_graph_change()
|
||||
{
|
||||
{
|
||||
std::lock_guard<std::mutex> graph_changed_lock(graph_mutex_);
|
||||
bool bad_ptr_encountered = false;
|
||||
for (auto & event_wptr : graph_events_) {
|
||||
auto event_ptr = event_wptr.lock();
|
||||
if (event_ptr) {
|
||||
event_ptr->set();
|
||||
} else {
|
||||
bad_ptr_encountered = true;
|
||||
}
|
||||
}
|
||||
if (bad_ptr_encountered) {
|
||||
// remove invalid pointers with the erase-remove idiom
|
||||
graph_events_.erase(
|
||||
std::remove_if(
|
||||
graph_events_.begin(),
|
||||
graph_events_.end(),
|
||||
[](const rclcpp::event::Event::WeakPtr & wptr) {
|
||||
return wptr.expired();
|
||||
}),
|
||||
graph_events_.end());
|
||||
// update graph_users_count_
|
||||
graph_users_count_.store(graph_events_.size());
|
||||
}
|
||||
}
|
||||
graph_cv_.notify_all();
|
||||
{
|
||||
auto notify_condition_lock = node_base_->acquire_notify_guard_condition_lock();
|
||||
rcl_ret_t ret = rcl_trigger_guard_condition(node_base_->get_notify_guard_condition());
|
||||
if (RCL_RET_OK != ret) {
|
||||
throw_from_rcl_error(ret, "failed to trigger notify guard condition");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
NodeGraph::notify_shutdown()
|
||||
{
|
||||
// notify here anything that will not be woken up by ctrl-c or rclcpp::shutdown().
|
||||
graph_cv_.notify_all();
|
||||
}
|
||||
|
||||
rclcpp::event::Event::SharedPtr
|
||||
NodeGraph::get_graph_event()
|
||||
{
|
||||
auto event = rclcpp::event::Event::make_shared();
|
||||
std::lock_guard<std::mutex> graph_changed_lock(graph_mutex_);
|
||||
// on first call, add node to graph_listener_
|
||||
if (should_add_to_graph_listener_.exchange(false)) {
|
||||
graph_listener_->add_node(this);
|
||||
graph_listener_->start_if_not_started();
|
||||
}
|
||||
graph_events_.push_back(event);
|
||||
graph_users_count_++;
|
||||
return event;
|
||||
}
|
||||
|
||||
void
|
||||
NodeGraph::wait_for_graph_change(
|
||||
rclcpp::event::Event::SharedPtr event,
|
||||
std::chrono::nanoseconds timeout)
|
||||
{
|
||||
using rclcpp::exceptions::InvalidEventError;
|
||||
using rclcpp::exceptions::EventNotRegisteredError;
|
||||
if (!event) {
|
||||
throw InvalidEventError();
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> graph_changed_lock(graph_mutex_);
|
||||
bool event_in_graph_events = false;
|
||||
for (const auto & event_wptr : graph_events_) {
|
||||
if (event == event_wptr.lock()) {
|
||||
event_in_graph_events = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!event_in_graph_events) {
|
||||
throw EventNotRegisteredError();
|
||||
}
|
||||
}
|
||||
std::unique_lock<std::mutex> graph_lock(graph_mutex_);
|
||||
graph_cv_.wait_for(graph_lock, timeout, [&event]() {
|
||||
return event->check() || !rclcpp::utilities::ok();
|
||||
});
|
||||
}
|
||||
|
||||
size_t
|
||||
NodeGraph::count_graph_users()
|
||||
{
|
||||
return graph_users_count_.load();
|
||||
}
|
||||
230
rclcpp/src/rclcpp/node_interfaces/node_parameters.cpp
Normal file
230
rclcpp/src/rclcpp/node_interfaces/node_parameters.cpp
Normal file
@@ -0,0 +1,230 @@
|
||||
// Copyright 2016 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "rclcpp/node_interfaces/node_parameters.hpp"
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "rcl_interfaces/srv/list_parameters.hpp"
|
||||
#include "rclcpp/create_publisher.hpp"
|
||||
#include "rmw/qos_profiles.h"
|
||||
|
||||
using rclcpp::node_interfaces::NodeParameters;
|
||||
|
||||
NodeParameters::NodeParameters(
|
||||
rclcpp::node_interfaces::NodeTopicsInterface * node_topics,
|
||||
bool use_intra_process)
|
||||
: node_topics_(node_topics)
|
||||
{
|
||||
using MessageT = rcl_interfaces::msg::ParameterEvent;
|
||||
using PublisherT = rclcpp::publisher::Publisher<MessageT>;
|
||||
using AllocatorT = std::allocator<void>;
|
||||
// TODO(wjwwood): expose this allocator through the Parameter interface.
|
||||
auto allocator = std::make_shared<AllocatorT>();
|
||||
|
||||
events_publisher_ = rclcpp::create_publisher<MessageT, AllocatorT, PublisherT>(
|
||||
node_topics_,
|
||||
"parameter_events",
|
||||
rmw_qos_profile_parameter_events,
|
||||
use_intra_process,
|
||||
allocator);
|
||||
}
|
||||
|
||||
NodeParameters::~NodeParameters()
|
||||
{}
|
||||
|
||||
std::vector<rcl_interfaces::msg::SetParametersResult>
|
||||
NodeParameters::set_parameters(
|
||||
const std::vector<rclcpp::parameter::ParameterVariant> & parameters)
|
||||
{
|
||||
std::vector<rcl_interfaces::msg::SetParametersResult> results;
|
||||
for (auto p : parameters) {
|
||||
auto result = set_parameters_atomically({{p}});
|
||||
results.push_back(result);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
rcl_interfaces::msg::SetParametersResult
|
||||
NodeParameters::set_parameters_atomically(
|
||||
const std::vector<rclcpp::parameter::ParameterVariant> & parameters)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
std::map<std::string, rclcpp::parameter::ParameterVariant> tmp_map;
|
||||
auto parameter_event = std::make_shared<rcl_interfaces::msg::ParameterEvent>();
|
||||
|
||||
// TODO(jacquelinekay): handle parameter constraints
|
||||
rcl_interfaces::msg::SetParametersResult result;
|
||||
if (parameters_callback_) {
|
||||
result = parameters_callback_(parameters);
|
||||
} else {
|
||||
result.successful = true;
|
||||
}
|
||||
|
||||
if (!result.successful) {
|
||||
return result;
|
||||
}
|
||||
|
||||
for (auto p : parameters) {
|
||||
if (parameters_.find(p.get_name()) == parameters_.end()) {
|
||||
if (p.get_type() != rclcpp::parameter::ParameterType::PARAMETER_NOT_SET) {
|
||||
parameter_event->new_parameters.push_back(p.to_parameter());
|
||||
}
|
||||
} else if (p.get_type() != rclcpp::parameter::ParameterType::PARAMETER_NOT_SET) {
|
||||
parameter_event->changed_parameters.push_back(p.to_parameter());
|
||||
} else {
|
||||
parameter_event->deleted_parameters.push_back(p.to_parameter());
|
||||
}
|
||||
tmp_map[p.get_name()] = p;
|
||||
}
|
||||
// std::map::insert will not overwrite elements, so we'll keep the new
|
||||
// ones and add only those that already exist in the Node's internal map
|
||||
tmp_map.insert(parameters_.begin(), parameters_.end());
|
||||
std::swap(tmp_map, parameters_);
|
||||
|
||||
events_publisher_->publish(parameter_event);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<rclcpp::parameter::ParameterVariant>
|
||||
NodeParameters::get_parameters(const std::vector<std::string> & names) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
std::vector<rclcpp::parameter::ParameterVariant> results;
|
||||
|
||||
for (auto & name : names) {
|
||||
if (std::any_of(parameters_.cbegin(), parameters_.cend(),
|
||||
[&name](const std::pair<std::string, rclcpp::parameter::ParameterVariant> & kv) {
|
||||
return name == kv.first;
|
||||
}))
|
||||
{
|
||||
results.push_back(parameters_.at(name));
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
rclcpp::parameter::ParameterVariant
|
||||
NodeParameters::get_parameter(const std::string & name) const
|
||||
{
|
||||
rclcpp::parameter::ParameterVariant parameter;
|
||||
|
||||
if (get_parameter(name, parameter)) {
|
||||
return parameter;
|
||||
} else {
|
||||
throw std::out_of_range("Parameter '" + name + "' not set");
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
NodeParameters::get_parameter(
|
||||
const std::string & name,
|
||||
rclcpp::parameter::ParameterVariant & parameter) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
|
||||
if (parameters_.count(name)) {
|
||||
parameter = parameters_.at(name);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<rcl_interfaces::msg::ParameterDescriptor>
|
||||
NodeParameters::describe_parameters(const std::vector<std::string> & names) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
std::vector<rcl_interfaces::msg::ParameterDescriptor> results;
|
||||
for (auto & kv : parameters_) {
|
||||
if (std::any_of(names.cbegin(), names.cend(), [&kv](const std::string & name) {
|
||||
return name == kv.first;
|
||||
}))
|
||||
{
|
||||
rcl_interfaces::msg::ParameterDescriptor parameter_descriptor;
|
||||
parameter_descriptor.name = kv.first;
|
||||
parameter_descriptor.type = kv.second.get_type();
|
||||
results.push_back(parameter_descriptor);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
std::vector<uint8_t>
|
||||
NodeParameters::get_parameter_types(const std::vector<std::string> & names) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
std::vector<uint8_t> results;
|
||||
for (auto & kv : parameters_) {
|
||||
if (std::any_of(names.cbegin(), names.cend(), [&kv](const std::string & name) {
|
||||
return name == kv.first;
|
||||
}))
|
||||
{
|
||||
results.push_back(kv.second.get_type());
|
||||
} else {
|
||||
results.push_back(rcl_interfaces::msg::ParameterType::PARAMETER_NOT_SET);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
rcl_interfaces::msg::ListParametersResult
|
||||
NodeParameters::list_parameters(const std::vector<std::string> & prefixes, uint64_t depth) const
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
rcl_interfaces::msg::ListParametersResult result;
|
||||
|
||||
// TODO(esteve): define parameter separator, use "." for now
|
||||
for (auto & kv : parameters_) {
|
||||
if (((prefixes.size() == 0) &&
|
||||
((depth == rcl_interfaces::srv::ListParameters::Request::DEPTH_RECURSIVE) ||
|
||||
(static_cast<uint64_t>(std::count(kv.first.begin(), kv.first.end(), '.')) < depth))) ||
|
||||
(std::any_of(prefixes.cbegin(), prefixes.cend(), [&kv, &depth](const std::string & prefix) {
|
||||
if (kv.first == prefix) {
|
||||
return true;
|
||||
} else if (kv.first.find(prefix + ".") == 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(), '.')) < depth);
|
||||
}
|
||||
return false;
|
||||
})))
|
||||
{
|
||||
result.names.push_back(kv.first);
|
||||
size_t last_separator = kv.first.find_last_of('.');
|
||||
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) ==
|
||||
result.prefixes.cend())
|
||||
{
|
||||
result.prefixes.push_back(prefix);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
NodeParameters::register_param_change_callback(ParametersCallbackFunction callback)
|
||||
{
|
||||
parameters_callback_ = callback;
|
||||
}
|
||||
78
rclcpp/src/rclcpp/node_interfaces/node_services.cpp
Normal file
78
rclcpp/src/rclcpp/node_interfaces/node_services.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
// Copyright 2016 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "rclcpp/node_interfaces/node_services.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
using rclcpp::node_interfaces::NodeServices;
|
||||
|
||||
NodeServices::NodeServices(rclcpp::node_interfaces::NodeBaseInterface * node_base)
|
||||
: node_base_(node_base)
|
||||
{}
|
||||
|
||||
NodeServices::~NodeServices()
|
||||
{}
|
||||
|
||||
void
|
||||
NodeServices::add_service(
|
||||
rclcpp::service::ServiceBase::SharedPtr service_base_ptr,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group)
|
||||
{
|
||||
if (group) {
|
||||
if (!node_base_->callback_group_in_node(group)) {
|
||||
// TODO(jacquelinekay): use custom exception
|
||||
throw std::runtime_error("Cannot create service, group not in node.");
|
||||
}
|
||||
group->add_service(service_base_ptr);
|
||||
} else {
|
||||
node_base_->get_default_callback_group()->add_service(service_base_ptr);
|
||||
}
|
||||
|
||||
// Notify the executor that a new service was created using the parent Node.
|
||||
{
|
||||
auto notify_guard_condition_lock = node_base_->acquire_notify_guard_condition_lock();
|
||||
if (rcl_trigger_guard_condition(node_base_->get_notify_guard_condition()) != RCL_RET_OK) {
|
||||
throw std::runtime_error(
|
||||
std::string("Failed to notify waitset on service creation: ") + rmw_get_error_string()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
NodeServices::add_client(
|
||||
rclcpp::client::ClientBase::SharedPtr client_base_ptr,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group)
|
||||
{
|
||||
if (group) {
|
||||
if (!node_base_->callback_group_in_node(group)) {
|
||||
// TODO(jacquelinekay): use custom exception
|
||||
throw std::runtime_error("Cannot create client, group not in node.");
|
||||
}
|
||||
group->add_client(client_base_ptr);
|
||||
} else {
|
||||
node_base_->get_default_callback_group()->add_client(client_base_ptr);
|
||||
}
|
||||
|
||||
// Notify the executor that a new client was created using the parent Node.
|
||||
{
|
||||
auto notify_guard_condition_lock = node_base_->acquire_notify_guard_condition_lock();
|
||||
if (rcl_trigger_guard_condition(node_base_->get_notify_guard_condition()) != RCL_RET_OK) {
|
||||
throw std::runtime_error(
|
||||
std::string("Failed to notify waitset on client creation: ") + rmw_get_error_string()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
47
rclcpp/src/rclcpp/node_interfaces/node_timers.cpp
Normal file
47
rclcpp/src/rclcpp/node_interfaces/node_timers.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright 2016 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "rclcpp/node_interfaces/node_timers.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
using rclcpp::node_interfaces::NodeTimers;
|
||||
|
||||
NodeTimers::NodeTimers(rclcpp::node_interfaces::NodeBaseInterface * node_base)
|
||||
: node_base_(node_base)
|
||||
{}
|
||||
|
||||
NodeTimers::~NodeTimers()
|
||||
{}
|
||||
|
||||
void
|
||||
NodeTimers::add_timer(
|
||||
rclcpp::timer::TimerBase::SharedPtr timer,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr callback_group)
|
||||
{
|
||||
if (callback_group) {
|
||||
if (!node_base_->callback_group_in_node(callback_group)) {
|
||||
// TODO(jacquelinekay): use custom exception
|
||||
throw std::runtime_error("Cannot create timer, group not in node.");
|
||||
}
|
||||
callback_group->add_timer(timer);
|
||||
} else {
|
||||
node_base_->get_default_callback_group()->add_timer(timer);
|
||||
}
|
||||
if (rcl_trigger_guard_condition(node_base_->get_notify_guard_condition()) != RCL_RET_OK) {
|
||||
throw std::runtime_error(
|
||||
std::string(
|
||||
"Failed to notify waitset on timer creation: ") + rmw_get_error_string());
|
||||
}
|
||||
}
|
||||
131
rclcpp/src/rclcpp/node_interfaces/node_topics.cpp
Normal file
131
rclcpp/src/rclcpp/node_interfaces/node_topics.cpp
Normal file
@@ -0,0 +1,131 @@
|
||||
// Copyright 2016 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "rclcpp/node_interfaces/node_topics.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "rclcpp/intra_process_manager.hpp"
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
|
||||
using rclcpp::exceptions::throw_from_rcl_error;
|
||||
|
||||
using rclcpp::node_interfaces::NodeTopics;
|
||||
|
||||
NodeTopics::NodeTopics(rclcpp::node_interfaces::NodeBaseInterface * node_base)
|
||||
: node_base_(node_base)
|
||||
{}
|
||||
|
||||
NodeTopics::~NodeTopics()
|
||||
{}
|
||||
|
||||
rclcpp::publisher::PublisherBase::SharedPtr
|
||||
NodeTopics::create_publisher(
|
||||
const std::string & topic_name,
|
||||
const rclcpp::PublisherFactory & publisher_factory,
|
||||
rcl_publisher_options_t & publisher_options,
|
||||
bool use_intra_process)
|
||||
{
|
||||
// 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.
|
||||
uint64_t intra_process_publisher_id =
|
||||
publisher_factory.add_publisher_to_intra_process_manager(ipm.get(), publisher);
|
||||
// Create a function to be called when publisher to do the intra process publish.
|
||||
auto shared_publish_callback = publisher_factory.create_shared_publish_callback(ipm);
|
||||
publisher->setup_intra_process(
|
||||
intra_process_publisher_id,
|
||||
shared_publish_callback,
|
||||
publisher_options);
|
||||
}
|
||||
|
||||
// Return the completed publisher.
|
||||
return publisher;
|
||||
}
|
||||
|
||||
void
|
||||
NodeTopics::add_publisher(
|
||||
rclcpp::publisher::PublisherBase::SharedPtr publisher)
|
||||
{
|
||||
// The publisher is not added to a callback group or anthing like that for now.
|
||||
// It may be stored within the NodeTopics class or the NodeBase class in the future.
|
||||
(void)publisher;
|
||||
// Notify the executor that a new publisher was created using the parent Node.
|
||||
{
|
||||
auto notify_guard_condition_lock = node_base_->acquire_notify_guard_condition_lock();
|
||||
if (rcl_trigger_guard_condition(node_base_->get_notify_guard_condition()) != RCL_RET_OK) {
|
||||
throw std::runtime_error(
|
||||
std::string(
|
||||
"Failed to notify waitset on publisher creation: ") + rmw_get_error_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rclcpp::subscription::SubscriptionBase::SharedPtr
|
||||
NodeTopics::create_subscription(
|
||||
const std::string & topic_name,
|
||||
const rclcpp::SubscriptionFactory & subscription_factory,
|
||||
rcl_subscription_options_t & subscription_options,
|
||||
bool use_intra_process)
|
||||
{
|
||||
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 intra_process_manager =
|
||||
context->get_sub_context<rclcpp::intra_process_manager::IntraProcessManager>();
|
||||
subscription_factory.setup_intra_process(
|
||||
intra_process_manager, subscription, subscription_options);
|
||||
}
|
||||
|
||||
// Return the completed subscription.
|
||||
return subscription;
|
||||
}
|
||||
|
||||
void
|
||||
NodeTopics::add_subscription(
|
||||
rclcpp::subscription::SubscriptionBase::SharedPtr subscription,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr callback_group)
|
||||
{
|
||||
// Assign to a group.
|
||||
if (callback_group) {
|
||||
if (!node_base_->callback_group_in_node(callback_group)) {
|
||||
// TODO(jacquelinekay): use custom exception
|
||||
throw std::runtime_error("Cannot create subscription, callback group not in node.");
|
||||
}
|
||||
callback_group->add_subscription(subscription);
|
||||
} else {
|
||||
node_base_->get_default_callback_group()->add_subscription(subscription);
|
||||
}
|
||||
|
||||
// Notify the executor that a new subscription was created using the parent Node.
|
||||
{
|
||||
auto notify_guard_condition_lock = node_base_->acquire_notify_guard_condition_lock();
|
||||
if (rcl_trigger_guard_condition(node_base_->get_notify_guard_condition()) != RCL_RET_OK) {
|
||||
throw std::runtime_error(
|
||||
std::string(
|
||||
"Failed to notify waitset on subscription creation: ") + rmw_get_error_string()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "rclcpp/parameter_client.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -250,7 +251,8 @@ std::vector<rclcpp::parameter::ParameterVariant>
|
||||
SyncParametersClient::get_parameters(const std::vector<std::string> & parameter_names)
|
||||
{
|
||||
auto f = async_parameters_client_->get_parameters(parameter_names);
|
||||
if (rclcpp::executors::spin_node_until_future_complete(*executor_, node_, f) ==
|
||||
using rclcpp::executors::spin_node_until_future_complete;
|
||||
if (spin_node_until_future_complete(*executor_, node_->get_node_base_interface(), f) ==
|
||||
rclcpp::executor::FutureReturnCode::SUCCESS)
|
||||
{
|
||||
return f.get();
|
||||
@@ -273,7 +275,8 @@ SyncParametersClient::get_parameter_types(const std::vector<std::string> & param
|
||||
{
|
||||
auto f = async_parameters_client_->get_parameter_types(parameter_names);
|
||||
|
||||
if (rclcpp::executors::spin_node_until_future_complete(*executor_, node_, f) ==
|
||||
using rclcpp::executors::spin_node_until_future_complete;
|
||||
if (spin_node_until_future_complete(*executor_, node_->get_node_base_interface(), f) ==
|
||||
rclcpp::executor::FutureReturnCode::SUCCESS)
|
||||
{
|
||||
return f.get();
|
||||
@@ -287,7 +290,8 @@ SyncParametersClient::set_parameters(
|
||||
{
|
||||
auto f = async_parameters_client_->set_parameters(parameters);
|
||||
|
||||
if (rclcpp::executors::spin_node_until_future_complete(*executor_, node_, f) ==
|
||||
using rclcpp::executors::spin_node_until_future_complete;
|
||||
if (spin_node_until_future_complete(*executor_, node_->get_node_base_interface(), f) ==
|
||||
rclcpp::executor::FutureReturnCode::SUCCESS)
|
||||
{
|
||||
return f.get();
|
||||
@@ -301,7 +305,8 @@ SyncParametersClient::set_parameters_atomically(
|
||||
{
|
||||
auto f = async_parameters_client_->set_parameters_atomically(parameters);
|
||||
|
||||
if (rclcpp::executors::spin_node_until_future_complete(*executor_, node_, f) ==
|
||||
using rclcpp::executors::spin_node_until_future_complete;
|
||||
if (spin_node_until_future_complete(*executor_, node_->get_node_base_interface(), f) ==
|
||||
rclcpp::executor::FutureReturnCode::SUCCESS)
|
||||
{
|
||||
return f.get();
|
||||
@@ -317,7 +322,8 @@ SyncParametersClient::list_parameters(
|
||||
{
|
||||
auto f = async_parameters_client_->list_parameters(parameter_prefixes, depth);
|
||||
|
||||
if (rclcpp::executors::spin_node_until_future_complete(*executor_, node_, f) ==
|
||||
using rclcpp::executors::spin_node_until_future_complete;
|
||||
if (spin_node_until_future_complete(*executor_, node_->get_node_base_interface(), f) ==
|
||||
rclcpp::executor::FutureReturnCode::SUCCESS)
|
||||
{
|
||||
return f.get();
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#include "rclcpp/parameter_service.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using rclcpp::parameter_service::ParameterService;
|
||||
@@ -27,7 +29,7 @@ ParameterService::ParameterService(
|
||||
std::weak_ptr<rclcpp::node::Node> captured_node = node_;
|
||||
// *INDENT-OFF* (prevent uncrustify from making unnecessary indents here)
|
||||
get_parameters_service_ = node_->create_service<rcl_interfaces::srv::GetParameters>(
|
||||
node_->get_name() + "__get_parameters",
|
||||
std::string(node_->get_name()) + "__get_parameters",
|
||||
[captured_node](
|
||||
const std::shared_ptr<rmw_request_id_t>,
|
||||
const std::shared_ptr<rcl_interfaces::srv::GetParameters::Request> request,
|
||||
@@ -46,7 +48,7 @@ ParameterService::ParameterService(
|
||||
);
|
||||
|
||||
get_parameter_types_service_ = node_->create_service<rcl_interfaces::srv::GetParameterTypes>(
|
||||
node_->get_name() + "__get_parameter_types",
|
||||
std::string(node_->get_name()) + "__get_parameter_types",
|
||||
[captured_node](
|
||||
const std::shared_ptr<rmw_request_id_t>,
|
||||
const std::shared_ptr<rcl_interfaces::srv::GetParameterTypes::Request> request,
|
||||
@@ -66,7 +68,7 @@ ParameterService::ParameterService(
|
||||
);
|
||||
|
||||
set_parameters_service_ = node_->create_service<rcl_interfaces::srv::SetParameters>(
|
||||
node_->get_name() + "__set_parameters",
|
||||
std::string(node_->get_name()) + "__set_parameters",
|
||||
[captured_node](
|
||||
const std::shared_ptr<rmw_request_id_t>,
|
||||
const std::shared_ptr<rcl_interfaces::srv::SetParameters::Request> request,
|
||||
@@ -88,7 +90,7 @@ ParameterService::ParameterService(
|
||||
|
||||
set_parameters_atomically_service_ =
|
||||
node_->create_service<rcl_interfaces::srv::SetParametersAtomically>(
|
||||
node_->get_name() + "__set_parameters_atomically",
|
||||
std::string(node_->get_name()) + "__set_parameters_atomically",
|
||||
[captured_node](
|
||||
const std::shared_ptr<rmw_request_id_t>,
|
||||
const std::shared_ptr<rcl_interfaces::srv::SetParametersAtomically::Request> request,
|
||||
@@ -112,7 +114,7 @@ ParameterService::ParameterService(
|
||||
);
|
||||
|
||||
describe_parameters_service_ = node_->create_service<rcl_interfaces::srv::DescribeParameters>(
|
||||
node_->get_name() + "__describe_parameters",
|
||||
std::string(node_->get_name()) + "__describe_parameters",
|
||||
[captured_node](
|
||||
const std::shared_ptr<rmw_request_id_t>,
|
||||
const std::shared_ptr<rcl_interfaces::srv::DescribeParameters::Request> request,
|
||||
@@ -129,7 +131,7 @@ ParameterService::ParameterService(
|
||||
);
|
||||
|
||||
list_parameters_service_ = node_->create_service<rcl_interfaces::srv::ListParameters>(
|
||||
node_->get_name() + "__list_parameters",
|
||||
std::string(node_->get_name()) + "__list_parameters",
|
||||
[captured_node](
|
||||
const std::shared_ptr<rmw_request_id_t>,
|
||||
const std::shared_ptr<rcl_interfaces::srv::ListParameters::Request> request,
|
||||
|
||||
@@ -29,33 +29,72 @@
|
||||
#include "rclcpp/allocator/allocator_common.hpp"
|
||||
#include "rclcpp/allocator/allocator_deleter.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/node.hpp"
|
||||
|
||||
using rclcpp::publisher::PublisherBase;
|
||||
|
||||
PublisherBase::PublisherBase(
|
||||
std::shared_ptr<rcl_node_t> node_handle,
|
||||
std::string topic,
|
||||
size_t queue_size)
|
||||
: node_handle_(node_handle),
|
||||
topic_(topic), queue_size_(queue_size),
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||
const std::string & topic,
|
||||
const rosidl_message_type_support_t & type_support,
|
||||
const rcl_publisher_options_t & publisher_options)
|
||||
: rcl_node_handle_(node_base->get_shared_rcl_node_handle()),
|
||||
intra_process_publisher_id_(0), store_intra_process_message_(nullptr)
|
||||
{
|
||||
if (rcl_publisher_init(
|
||||
&publisher_handle_, rcl_node_handle_.get(), &type_support,
|
||||
topic.c_str(), &publisher_options) != RCL_RET_OK)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
std::string("could not create publisher: ") +
|
||||
rcl_get_error_string_safe());
|
||||
}
|
||||
// Life time of this object is tied to the publisher handle.
|
||||
rmw_publisher_t * publisher_rmw_handle = rcl_publisher_get_rmw_handle(&publisher_handle_);
|
||||
if (!publisher_rmw_handle) {
|
||||
throw std::runtime_error(
|
||||
std::string("failed to get rmw handle: ") + rcl_get_error_string_safe());
|
||||
}
|
||||
if (rmw_get_gid_for_publisher(publisher_rmw_handle, &rmw_gid_) != RMW_RET_OK) {
|
||||
// *INDENT-OFF* (prevent uncrustify from making unnecessary indents here)
|
||||
throw std::runtime_error(
|
||||
std::string("failed to get publisher gid: ") + rmw_get_error_string_safe());
|
||||
// *INDENT-ON*
|
||||
}
|
||||
}
|
||||
|
||||
PublisherBase::~PublisherBase()
|
||||
{
|
||||
if (rcl_publisher_fini(&intra_process_publisher_handle_, rcl_node_handle_.get()) != RCL_RET_OK) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"Error in destruction of intra process rcl publisher handle: %s\n",
|
||||
rcl_get_error_string_safe());
|
||||
}
|
||||
|
||||
if (rcl_publisher_fini(&publisher_handle_, rcl_node_handle_.get()) != RCL_RET_OK) {
|
||||
fprintf(
|
||||
stderr,
|
||||
"Error in destruction of rcl publisher handle: %s\n",
|
||||
rcl_get_error_string_safe());
|
||||
}
|
||||
}
|
||||
|
||||
const std::string &
|
||||
const char *
|
||||
PublisherBase::get_topic_name() const
|
||||
{
|
||||
return topic_;
|
||||
return rcl_publisher_get_topic_name(&publisher_handle_);
|
||||
}
|
||||
|
||||
size_t
|
||||
PublisherBase::get_queue_size() const
|
||||
{
|
||||
return queue_size_;
|
||||
const rcl_publisher_options_t * publisher_options = rcl_publisher_get_options(&publisher_handle_);
|
||||
if (!publisher_options) {
|
||||
throw std::runtime_error(
|
||||
std::string("failed to get publisher options: ") + rcl_get_error_string_safe());
|
||||
}
|
||||
return publisher_options->qos.depth;
|
||||
}
|
||||
|
||||
const rmw_gid_t &
|
||||
@@ -101,10 +140,11 @@ PublisherBase::setup_intra_process(
|
||||
StoreMessageCallbackT callback,
|
||||
const rcl_publisher_options_t & intra_process_options)
|
||||
{
|
||||
auto intra_process_topic_name = std::string(this->get_topic_name()) + "__intra";
|
||||
if (rcl_publisher_init(
|
||||
&intra_process_publisher_handle_, node_handle_.get(),
|
||||
&intra_process_publisher_handle_, rcl_node_handle_.get(),
|
||||
rclcpp::type_support::get_intra_process_message_msg_type_support(),
|
||||
(topic_ + "__intra").c_str(), &intra_process_options) != RCL_RET_OK)
|
||||
intra_process_topic_name.c_str(), &intra_process_options) != RCL_RET_OK)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
std::string("could not create intra process publisher: ") +
|
||||
|
||||
@@ -29,10 +29,14 @@ using rclcpp::service::ServiceBase;
|
||||
|
||||
ServiceBase::ServiceBase(
|
||||
std::shared_ptr<rcl_node_t> node_handle,
|
||||
const std::string service_name)
|
||||
const std::string & service_name)
|
||||
: node_handle_(node_handle), service_name_(service_name)
|
||||
{}
|
||||
|
||||
ServiceBase::ServiceBase(std::shared_ptr<rcl_node_t> node_handle)
|
||||
: node_handle_(node_handle)
|
||||
{}
|
||||
|
||||
ServiceBase::~ServiceBase()
|
||||
{}
|
||||
|
||||
@@ -45,5 +49,5 @@ ServiceBase::get_service_name()
|
||||
const rcl_service_t *
|
||||
ServiceBase::get_service_handle()
|
||||
{
|
||||
return &service_handle_;
|
||||
return service_handle_;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "rclcpp/subscription.hpp"
|
||||
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "rmw/error_handling.h"
|
||||
@@ -25,14 +26,21 @@ using rclcpp::subscription::SubscriptionBase;
|
||||
|
||||
SubscriptionBase::SubscriptionBase(
|
||||
std::shared_ptr<rcl_node_t> node_handle,
|
||||
const rosidl_message_type_support_t & type_support_handle,
|
||||
const std::string & topic_name,
|
||||
bool ignore_local_publications)
|
||||
: node_handle_(node_handle),
|
||||
topic_name_(topic_name),
|
||||
ignore_local_publications_(ignore_local_publications)
|
||||
const rcl_subscription_options_t & subscription_options)
|
||||
: node_handle_(node_handle)
|
||||
{
|
||||
// To avoid unused private member warnings.
|
||||
(void)ignore_local_publications_;
|
||||
rcl_ret_t ret = rcl_subscription_init(
|
||||
&subscription_handle_,
|
||||
node_handle_.get(),
|
||||
&type_support_handle,
|
||||
topic_name.c_str(),
|
||||
&subscription_options);
|
||||
if (ret != RCL_RET_OK) {
|
||||
throw std::runtime_error(
|
||||
std::string("could not create subscription: ") + rcl_get_error_string_safe());
|
||||
}
|
||||
}
|
||||
|
||||
SubscriptionBase::~SubscriptionBase()
|
||||
@@ -53,10 +61,10 @@ SubscriptionBase::~SubscriptionBase()
|
||||
}
|
||||
}
|
||||
|
||||
const std::string &
|
||||
const char *
|
||||
SubscriptionBase::get_topic_name() const
|
||||
{
|
||||
return this->topic_name_;
|
||||
return rcl_subscription_get_topic_name(&subscription_handle_);
|
||||
}
|
||||
|
||||
const rcl_subscription_t *
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
const rosidl_message_type_support_t *
|
||||
rclcpp::type_support::get_intra_process_message_msg_type_support()
|
||||
{
|
||||
return rosidl_generator_cpp::get_message_type_support_handle<
|
||||
return rosidl_typesupport_cpp::get_message_type_support_handle<
|
||||
rcl_interfaces::msg::IntraProcessMessage
|
||||
>();
|
||||
}
|
||||
@@ -38,7 +38,7 @@ rclcpp::type_support::get_intra_process_message_msg_type_support()
|
||||
const rosidl_message_type_support_t *
|
||||
rclcpp::type_support::get_parameter_event_msg_type_support()
|
||||
{
|
||||
return rosidl_generator_cpp::get_message_type_support_handle<
|
||||
return rosidl_typesupport_cpp::get_message_type_support_handle<
|
||||
rcl_interfaces::msg::ParameterEvent
|
||||
>();
|
||||
}
|
||||
@@ -46,7 +46,7 @@ rclcpp::type_support::get_parameter_event_msg_type_support()
|
||||
const rosidl_message_type_support_t *
|
||||
rclcpp::type_support::get_set_parameters_result_msg_type_support()
|
||||
{
|
||||
return rosidl_generator_cpp::get_message_type_support_handle<
|
||||
return rosidl_typesupport_cpp::get_message_type_support_handle<
|
||||
rcl_interfaces::msg::SetParametersResult
|
||||
>();
|
||||
}
|
||||
@@ -54,7 +54,7 @@ rclcpp::type_support::get_set_parameters_result_msg_type_support()
|
||||
const rosidl_message_type_support_t *
|
||||
rclcpp::type_support::get_parameter_descriptor_msg_type_support()
|
||||
{
|
||||
return rosidl_generator_cpp::get_message_type_support_handle<
|
||||
return rosidl_typesupport_cpp::get_message_type_support_handle<
|
||||
rcl_interfaces::msg::ParameterDescriptor
|
||||
>();
|
||||
}
|
||||
@@ -62,7 +62,7 @@ rclcpp::type_support::get_parameter_descriptor_msg_type_support()
|
||||
const rosidl_message_type_support_t *
|
||||
rclcpp::type_support::get_list_parameters_result_msg_type_support()
|
||||
{
|
||||
return rosidl_generator_cpp::get_message_type_support_handle<
|
||||
return rosidl_typesupport_cpp::get_message_type_support_handle<
|
||||
rcl_interfaces::msg::ListParametersResult
|
||||
>();
|
||||
}
|
||||
@@ -70,7 +70,7 @@ rclcpp::type_support::get_list_parameters_result_msg_type_support()
|
||||
const rosidl_service_type_support_t *
|
||||
rclcpp::type_support::get_get_parameters_srv_type_support()
|
||||
{
|
||||
return rosidl_generator_cpp::get_service_type_support_handle<
|
||||
return rosidl_typesupport_cpp::get_service_type_support_handle<
|
||||
rcl_interfaces::srv::GetParameters
|
||||
>();
|
||||
}
|
||||
@@ -78,7 +78,7 @@ rclcpp::type_support::get_get_parameters_srv_type_support()
|
||||
const rosidl_service_type_support_t *
|
||||
rclcpp::type_support::get_get_parameter_types_srv_type_support()
|
||||
{
|
||||
return rosidl_generator_cpp::get_service_type_support_handle<
|
||||
return rosidl_typesupport_cpp::get_service_type_support_handle<
|
||||
rcl_interfaces::srv::GetParameterTypes
|
||||
>();
|
||||
}
|
||||
@@ -86,7 +86,7 @@ rclcpp::type_support::get_get_parameter_types_srv_type_support()
|
||||
const rosidl_service_type_support_t *
|
||||
rclcpp::type_support::get_set_parameters_srv_type_support()
|
||||
{
|
||||
return rosidl_generator_cpp::get_service_type_support_handle<
|
||||
return rosidl_typesupport_cpp::get_service_type_support_handle<
|
||||
rcl_interfaces::srv::SetParameters
|
||||
>();
|
||||
}
|
||||
@@ -94,7 +94,7 @@ rclcpp::type_support::get_set_parameters_srv_type_support()
|
||||
const rosidl_service_type_support_t *
|
||||
rclcpp::type_support::get_list_parameters_srv_type_support()
|
||||
{
|
||||
return rosidl_generator_cpp::get_service_type_support_handle<
|
||||
return rosidl_typesupport_cpp::get_service_type_support_handle<
|
||||
rcl_interfaces::srv::ListParameters
|
||||
>();
|
||||
}
|
||||
@@ -102,7 +102,7 @@ rclcpp::type_support::get_list_parameters_srv_type_support()
|
||||
const rosidl_service_type_support_t *
|
||||
rclcpp::type_support::get_describe_parameters_srv_type_support()
|
||||
{
|
||||
return rosidl_generator_cpp::get_service_type_support_handle<
|
||||
return rosidl_typesupport_cpp::get_service_type_support_handle<
|
||||
rcl_interfaces::srv::DescribeParameters
|
||||
>();
|
||||
}
|
||||
@@ -110,7 +110,7 @@ rclcpp::type_support::get_describe_parameters_srv_type_support()
|
||||
const rosidl_service_type_support_t *
|
||||
rclcpp::type_support::get_set_parameters_atomically_srv_type_support()
|
||||
{
|
||||
return rosidl_generator_cpp::get_service_type_support_handle<
|
||||
return rosidl_typesupport_cpp::get_service_type_support_handle<
|
||||
rcl_interfaces::srv::SetParametersAtomically
|
||||
>();
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ signal_handler(int signal_value)
|
||||
g_signal_status = signal_value;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_sigint_guard_cond_handles_mutex);
|
||||
for (auto const & kv : g_sigint_guard_cond_handles) {
|
||||
for (auto & kv : g_sigint_guard_cond_handles) {
|
||||
rcl_ret_t status = rcl_trigger_guard_condition(&(kv.second));
|
||||
if (status != RCL_RET_OK) {
|
||||
fprintf(stderr,
|
||||
@@ -164,7 +164,7 @@ rclcpp::utilities::shutdown()
|
||||
g_signal_status = SIGINT;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(g_sigint_guard_cond_handles_mutex);
|
||||
for (auto const & kv : g_sigint_guard_cond_handles) {
|
||||
for (auto & kv : g_sigint_guard_cond_handles) {
|
||||
if (rcl_trigger_guard_condition(&(kv.second)) != RCL_RET_OK) {
|
||||
fprintf(stderr,
|
||||
"[rclcpp::error] failed to trigger sigint guard condition: %s\n",
|
||||
|
||||
3
rclcpp/test/mock_msgs/srv/Mock.srv
Normal file
3
rclcpp/test/mock_msgs/srv/Mock.srv
Normal file
@@ -0,0 +1,3 @@
|
||||
bool request
|
||||
---
|
||||
bool response
|
||||
142
rclcpp/test/test_externally_defined_services.cpp
Normal file
142
rclcpp/test/test_externally_defined_services.cpp
Normal file
@@ -0,0 +1,142 @@
|
||||
// Copyright 2016 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
#include "rclcpp/node.hpp"
|
||||
#include "rclcpp/any_service_callback.hpp"
|
||||
#include "rclcpp/service.hpp"
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
|
||||
#include "rcl/service.h"
|
||||
|
||||
#include "rclcpp/srv/mock.hpp"
|
||||
#include "rclcpp/srv/mock.h"
|
||||
|
||||
class TestExternallyDefinedServices : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
rclcpp::init(0, nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
callback(const std::shared_ptr<rclcpp::srv::Mock::Request>/*req*/,
|
||||
std::shared_ptr<rclcpp::srv::Mock::Response>/*resp*/)
|
||||
{}
|
||||
|
||||
TEST_F(TestExternallyDefinedServices, default_behavior) {
|
||||
auto node_handle = rclcpp::node::Node::make_shared("base_node");
|
||||
|
||||
try {
|
||||
auto srv = node_handle->create_service<rclcpp::srv::Mock>("test",
|
||||
callback);
|
||||
} catch (const std::exception &) {
|
||||
FAIL();
|
||||
return;
|
||||
}
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
TEST_F(TestExternallyDefinedServices, extern_defined_uninitialized) {
|
||||
auto node_handle = rclcpp::node::Node::make_shared("base_node");
|
||||
|
||||
// mock for externally defined service
|
||||
rcl_service_t service_handle = rcl_get_zero_initialized_service();
|
||||
|
||||
rclcpp::any_service_callback::AnyServiceCallback<rclcpp::srv::Mock> cb;
|
||||
|
||||
// don't initialize the service
|
||||
// expect fail
|
||||
try {
|
||||
rclcpp::service::Service<rclcpp::srv::Mock>(
|
||||
node_handle->get_node_base_interface()->get_shared_rcl_node_handle(),
|
||||
&service_handle, cb);
|
||||
} catch (const std::runtime_error &) {
|
||||
SUCCEED();
|
||||
return;
|
||||
}
|
||||
|
||||
FAIL();
|
||||
}
|
||||
|
||||
TEST_F(TestExternallyDefinedServices, extern_defined_initialized) {
|
||||
auto node_handle = rclcpp::node::Node::make_shared("base_node");
|
||||
|
||||
// mock for externally defined service
|
||||
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_GET_TYPE_SUPPORT(
|
||||
rclcpp, srv, Mock);
|
||||
rcl_ret_t ret = rcl_service_init(
|
||||
&service_handle,
|
||||
node_handle->get_node_base_interface()->get_rcl_node_handle(),
|
||||
ts, "base_node_service", &service_options);
|
||||
if (ret != RCL_RET_OK) {
|
||||
FAIL();
|
||||
return;
|
||||
}
|
||||
|
||||
rclcpp::any_service_callback::AnyServiceCallback<rclcpp::srv::Mock> cb;
|
||||
|
||||
try {
|
||||
rclcpp::service::Service<rclcpp::srv::Mock>(
|
||||
node_handle->get_node_base_interface()->get_shared_rcl_node_handle(),
|
||||
&service_handle, cb);
|
||||
} catch (const std::runtime_error &) {
|
||||
FAIL();
|
||||
return;
|
||||
}
|
||||
|
||||
SUCCEED();
|
||||
}
|
||||
|
||||
TEST_F(TestExternallyDefinedServices, extern_defined_destructor) {
|
||||
auto node_handle = rclcpp::node::Node::make_shared("base_node");
|
||||
|
||||
// mock for externally defined service
|
||||
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_GET_TYPE_SUPPORT(
|
||||
rclcpp, srv, Mock);
|
||||
rcl_ret_t ret = rcl_service_init(
|
||||
&service_handle,
|
||||
node_handle->get_node_base_interface()->get_rcl_node_handle(),
|
||||
ts, "base_node_service", &service_options);
|
||||
if (ret != RCL_RET_OK) {
|
||||
FAIL();
|
||||
return;
|
||||
}
|
||||
rclcpp::any_service_callback::AnyServiceCallback<rclcpp::srv::Mock> cb;
|
||||
|
||||
{
|
||||
// Call constructor
|
||||
rclcpp::service::Service<rclcpp::srv::Mock> srv_cpp(
|
||||
node_handle->get_node_base_interface()->get_shared_rcl_node_handle(),
|
||||
&service_handle, cb);
|
||||
// Call destructor
|
||||
}
|
||||
|
||||
if (!service_handle.impl) {
|
||||
FAIL();
|
||||
return;
|
||||
}
|
||||
SUCCEED();
|
||||
}
|
||||
76
rclcpp/test/test_find_weak_nodes.cpp
Normal file
76
rclcpp/test/test_find_weak_nodes.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
// Copyright 2016 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <memory>
|
||||
|
||||
#include "rclcpp/strategies/allocator_memory_strategy.hpp"
|
||||
#include "rclcpp/memory_strategy.hpp"
|
||||
#include "rclcpp/node.hpp"
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
|
||||
class TestFindWeakNodes : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
rclcpp::init(0, nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(TestFindWeakNodes, allocator_strategy_with_weak_nodes) {
|
||||
// GIVEN
|
||||
// A vector of weak pointers to nodes
|
||||
auto memory_strategy = std::make_shared<
|
||||
rclcpp::memory_strategies::allocator_memory_strategy::AllocatorMemoryStrategy<>>();
|
||||
auto existing_node = rclcpp::node::Node::make_shared("existing_node");
|
||||
auto dead_node = rclcpp::node::Node::make_shared("dead_node");
|
||||
rclcpp::memory_strategy::MemoryStrategy::WeakNodeVector weak_nodes;
|
||||
weak_nodes.push_back(existing_node->get_node_base_interface());
|
||||
weak_nodes.push_back(dead_node->get_node_base_interface());
|
||||
|
||||
// AND
|
||||
// Delete dead_node, creating a dangling pointer in weak_nodes
|
||||
dead_node.reset();
|
||||
ASSERT_FALSE(weak_nodes[0].expired());
|
||||
ASSERT_TRUE(weak_nodes[1].expired());
|
||||
|
||||
// WHEN
|
||||
bool has_invalid_weak_nodes = memory_strategy->collect_entities(weak_nodes);
|
||||
|
||||
// THEN
|
||||
// The result of finding dangling node pointers should be true
|
||||
ASSERT_TRUE(has_invalid_weak_nodes);
|
||||
}
|
||||
|
||||
TEST_F(TestFindWeakNodes, allocator_strategy_no_weak_nodes) {
|
||||
// GIVEN
|
||||
// A vector of weak pointers to nodes, all valid
|
||||
auto memory_strategy = std::make_shared<
|
||||
rclcpp::memory_strategies::allocator_memory_strategy::AllocatorMemoryStrategy<>>();
|
||||
auto existing_node1 = rclcpp::node::Node::make_shared("existing_node1");
|
||||
auto existing_node2 = rclcpp::node::Node::make_shared("existing_node2");
|
||||
rclcpp::memory_strategy::MemoryStrategy::WeakNodeVector weak_nodes;
|
||||
weak_nodes.push_back(existing_node1->get_node_base_interface());
|
||||
weak_nodes.push_back(existing_node2->get_node_base_interface());
|
||||
ASSERT_FALSE(weak_nodes[0].expired());
|
||||
ASSERT_FALSE(weak_nodes[1].expired());
|
||||
|
||||
// WHEN
|
||||
bool has_invalid_weak_nodes = memory_strategy->collect_entities(weak_nodes);
|
||||
|
||||
// THEN
|
||||
// The result of finding dangling node pointers should be false
|
||||
ASSERT_FALSE(has_invalid_weak_nodes);
|
||||
}
|
||||
@@ -31,14 +31,14 @@ namespace mock
|
||||
class PublisherBase
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(PublisherBase);
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(PublisherBase)
|
||||
|
||||
PublisherBase()
|
||||
: mock_topic_name(""), mock_queue_size(0) {}
|
||||
|
||||
const std::string & get_topic_name() const
|
||||
const char * get_topic_name() const
|
||||
{
|
||||
return mock_topic_name;
|
||||
return mock_topic_name.c_str();
|
||||
}
|
||||
size_t get_queue_size() const
|
||||
{
|
||||
@@ -66,7 +66,7 @@ public:
|
||||
using MessageUniquePtr = std::unique_ptr<T, MessageDeleter>;
|
||||
std::shared_ptr<MessageAlloc> allocator_;
|
||||
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(Publisher<T, Alloc>);
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(Publisher<T, Alloc>)
|
||||
|
||||
Publisher()
|
||||
{
|
||||
@@ -93,14 +93,14 @@ namespace mock
|
||||
class SubscriptionBase
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(SubscriptionBase);
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(SubscriptionBase)
|
||||
|
||||
SubscriptionBase()
|
||||
: mock_topic_name(""), mock_queue_size(0) {}
|
||||
|
||||
const std::string & get_topic_name() const
|
||||
const char * get_topic_name() const
|
||||
{
|
||||
return mock_topic_name;
|
||||
return mock_topic_name.c_str();
|
||||
}
|
||||
size_t get_queue_size() const
|
||||
{
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
#define RCLCPP_BUILDING_LIBRARY 1 // Prevent including unavailable symbols
|
||||
#include <rclcpp/mapped_ring_buffer.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
/*
|
||||
Tests get_copy and pop on an empty mrb.
|
||||
*/
|
||||
|
||||
99
rclcpp_lifecycle/CMakeLists.txt
Normal file
99
rclcpp_lifecycle/CMakeLists.txt
Normal file
@@ -0,0 +1,99 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
project(rclcpp_lifecycle)
|
||||
|
||||
if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang")
|
||||
set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} "-std=c++14")
|
||||
add_compile_options(-Wall -Wextra -Wpedantic)
|
||||
endif()
|
||||
|
||||
find_package(ament_cmake REQUIRED)
|
||||
find_package(rclcpp REQUIRED)
|
||||
find_package(rcl_lifecycle REQUIRED)
|
||||
find_package(rmw_implementation_cmake REQUIRED)
|
||||
find_package(std_msgs REQUIRED)
|
||||
find_package(lifecycle_msgs REQUIRED)
|
||||
|
||||
include_directories(include)
|
||||
|
||||
macro(targets)
|
||||
get_rclcpp_information("${rmw_implementation}" "rclcpp${target_suffix}")
|
||||
get_rcl_lifecycle_information("${rmw_implementation}" "rcl_lifecycle${target_suffix}")
|
||||
|
||||
### CPP High level library
|
||||
add_library(rclcpp_lifecycle${target_suffix}
|
||||
SHARED
|
||||
src/lifecycle_node.cpp
|
||||
src/node_interfaces/lifecycle_node_interface.cpp
|
||||
src/state.cpp
|
||||
src/transition.cpp
|
||||
)
|
||||
ament_target_dependencies(rclcpp_lifecycle${target_suffix}
|
||||
"rclcpp${target_suffix}"
|
||||
"rcl_lifecycle${target_suffix}"
|
||||
"lifecycle_msgs")
|
||||
|
||||
# Causes the visibility macros to use dllexport rather than dllimport,
|
||||
# which is appropriate when building the dll but not consuming it.
|
||||
target_compile_definitions(rclcpp_lifecycle${target_suffix} PRIVATE "RCLCPP_LIFECYCLE_BUILDING_DLL")
|
||||
|
||||
install(TARGETS
|
||||
rclcpp_lifecycle${target_suffix}
|
||||
ARCHIVE DESTINATION lib
|
||||
LIBRARY DESTINATION lib
|
||||
RUNTIME DESTINATION bin)
|
||||
endmacro()
|
||||
|
||||
call_for_each_rmw_implementation(targets GENERATE_DEFAULT)
|
||||
|
||||
if(BUILD_TESTING)
|
||||
find_package(ament_lint_auto REQUIRED)
|
||||
ament_lint_auto_find_test_dependencies()
|
||||
|
||||
ament_add_gtest(test_lifecycle_node test/test_lifecycle_node.cpp)
|
||||
if(TARGET test_lifecycle_node)
|
||||
target_include_directories(test_lifecycle_node PUBLIC
|
||||
${rcl_lifecycle_INCLUDE_DIRS}
|
||||
${rclcpp_INCLUDE_DIRS}
|
||||
${rclcpp_lifecycle_INCLUDE_DIRS}
|
||||
)
|
||||
target_link_libraries(test_lifecycle_node ${PROJECT_NAME})
|
||||
endif()
|
||||
ament_add_gtest(test_state_machine_info test/test_state_machine_info.cpp)
|
||||
if(TARGET test_state_machine_info)
|
||||
target_include_directories(test_state_machine_info PUBLIC
|
||||
${rcl_lifecycle_INCLUDE_DIRS}
|
||||
${rclcpp_INCLUDE_DIRS}
|
||||
${rclcpp_lifecycle_INCLUDE_DIRS}
|
||||
)
|
||||
target_link_libraries(test_state_machine_info ${PROJECT_NAME})
|
||||
endif()
|
||||
ament_add_gtest(test_register_custom_callbacks test/test_register_custom_callbacks.cpp)
|
||||
if(TARGET test_register_custom_callbacks)
|
||||
target_include_directories(test_register_custom_callbacks PUBLIC
|
||||
${rcl_lifecycle_INCLUDE_DIRS}
|
||||
${rclcpp_INCLUDE_DIRS}
|
||||
${rclcpp_lifecycle_INCLUDE_DIRS}
|
||||
)
|
||||
target_link_libraries(test_register_custom_callbacks ${PROJECT_NAME})
|
||||
endif()
|
||||
ament_add_gtest(test_callback_exceptions test/test_callback_exceptions.cpp)
|
||||
if(TARGET test_callback_exceptions)
|
||||
target_include_directories(test_callback_exceptions PUBLIC
|
||||
${rcl_lifecycle_INCLUDE_DIRS}
|
||||
${rclcpp_INCLUDE_DIRS}
|
||||
${rclcpp_lifecycle_INCLUDE_DIRS}
|
||||
)
|
||||
target_link_libraries(test_callback_exceptions ${PROJECT_NAME})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
ament_export_dependencies(rclcpp)
|
||||
ament_export_dependencies(rcl_lifecycle)
|
||||
ament_export_dependencies(lifecycle_msgs)
|
||||
ament_export_include_directories(include)
|
||||
ament_export_libraries(${PROJECT_NAME})
|
||||
ament_package()
|
||||
|
||||
install(DIRECTORY include/
|
||||
DESTINATION include)
|
||||
416
rclcpp_lifecycle/include/rclcpp_lifecycle/lifecycle_node.hpp
Normal file
416
rclcpp_lifecycle/include/rclcpp_lifecycle/lifecycle_node.hpp
Normal file
@@ -0,0 +1,416 @@
|
||||
// Copyright 2016 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_LIFECYCLE__LIFECYCLE_NODE_HPP_
|
||||
#define RCLCPP_LIFECYCLE__LIFECYCLE_NODE_HPP_
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include "rcl/error_handling.h"
|
||||
#include "rcl/node.h"
|
||||
|
||||
#include "rcl_interfaces/msg/list_parameters_result.hpp"
|
||||
#include "rcl_interfaces/msg/parameter_descriptor.hpp"
|
||||
#include "rcl_interfaces/msg/parameter_event.hpp"
|
||||
#include "rcl_interfaces/msg/set_parameters_result.hpp"
|
||||
|
||||
#include "rclcpp/callback_group.hpp"
|
||||
#include "rclcpp/client.hpp"
|
||||
#include "rclcpp/context.hpp"
|
||||
#include "rclcpp/event.hpp"
|
||||
#include "rclcpp/macros.hpp"
|
||||
#include "rclcpp/message_memory_strategy.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_graph_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_parameters_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_services_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_timers_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
|
||||
#include "rclcpp/parameter.hpp"
|
||||
#include "rclcpp/publisher.hpp"
|
||||
#include "rclcpp/service.hpp"
|
||||
#include "rclcpp/subscription.hpp"
|
||||
#include "rclcpp/timer.hpp"
|
||||
|
||||
#include "rclcpp_lifecycle/node_interfaces/lifecycle_node_interface.hpp"
|
||||
#include "rclcpp_lifecycle/lifecycle_publisher.hpp"
|
||||
#include "rclcpp_lifecycle/state.hpp"
|
||||
#include "rclcpp_lifecycle/transition.hpp"
|
||||
#include "rclcpp_lifecycle/visibility_control.h"
|
||||
|
||||
namespace rclcpp_lifecycle
|
||||
{
|
||||
|
||||
/// LifecycleNode for creating lifecycle components
|
||||
/**
|
||||
* has lifecycle nodeinterface for configuring this node.
|
||||
*/
|
||||
class LifecycleNode : public node_interfaces::LifecycleNodeInterface,
|
||||
public std::enable_shared_from_this<LifecycleNode>
|
||||
{
|
||||
public:
|
||||
RCLCPP_SMART_PTR_DEFINITIONS(LifecycleNode)
|
||||
|
||||
/// Create a new lifecycle node with the specified name.
|
||||
/**
|
||||
* \param[in] node_name Name of the node.
|
||||
* \param[in] use_intra_process_comms True to use the optimized intra-process communication
|
||||
* pipeline to pass messages between nodes in the same process using shared memory.
|
||||
*/
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
explicit LifecycleNode(const std::string & node_name, bool use_intra_process_comms = false);
|
||||
|
||||
/// Create a node based on the node name and a rclcpp::context::Context.
|
||||
/**
|
||||
* \param[in] node_name Name of the node.
|
||||
* \param[in] context The context for the node (usually represents the state of a process).
|
||||
* \param[in] use_intra_process_comms True to use the optimized intra-process communication
|
||||
* pipeline to pass messages between nodes in the same process using shared memory.
|
||||
*/
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
LifecycleNode(
|
||||
const std::string & node_name, rclcpp::context::Context::SharedPtr context,
|
||||
bool use_intra_process_comms = false);
|
||||
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
virtual ~LifecycleNode();
|
||||
|
||||
/// Get the name of the node.
|
||||
// \return The name of the node.
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
const char *
|
||||
get_name() const;
|
||||
|
||||
/// Create and return a callback group.
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr
|
||||
create_callback_group(rclcpp::callback_group::CallbackGroupType group_type);
|
||||
|
||||
/// Return the list of callback groups in the node.
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
const std::vector<rclcpp::callback_group::CallbackGroup::WeakPtr> &
|
||||
get_callback_groups() const;
|
||||
|
||||
/// 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.
|
||||
* \return Shared pointer to the created publisher.
|
||||
*/
|
||||
template<typename MessageT, typename Alloc = std::allocator<void>>
|
||||
std::shared_ptr<rclcpp_lifecycle::LifecyclePublisher<MessageT, Alloc>>
|
||||
create_publisher(
|
||||
const std::string & topic_name, size_t qos_history_depth,
|
||||
std::shared_ptr<Alloc> allocator = nullptr);
|
||||
|
||||
/// Create and return a LifecyclePublisher.
|
||||
/**
|
||||
* \param[in] topic_name The topic for this publisher to publish on.
|
||||
* \param[in] qos_history_depth The depth of the publisher message queue.
|
||||
* \return Shared pointer to the created publisher.
|
||||
*/
|
||||
template<typename MessageT, typename Alloc = std::allocator<void>>
|
||||
std::shared_ptr<rclcpp_lifecycle::LifecyclePublisher<MessageT, Alloc>>
|
||||
create_publisher(
|
||||
const std::string & topic_name,
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_default,
|
||||
std::shared_ptr<Alloc> allocator = 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.
|
||||
* \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::Subscription<MessageT, Alloc>>
|
||||
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<MessageT, 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.
|
||||
* \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::Subscription<MessageT, Alloc>>
|
||||
std::shared_ptr<SubscriptionT>
|
||||
create_subscription(
|
||||
const std::string & topic_name,
|
||||
size_t qos_history_depth,
|
||||
CallbackT && callback,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr,
|
||||
bool ignore_local_publications = false,
|
||||
typename rclcpp::message_memory_strategy::MessageMemoryStrategy<MessageT, Alloc>::SharedPtr
|
||||
msg_mem_strat = nullptr,
|
||||
std::shared_ptr<Alloc> allocator = nullptr);
|
||||
|
||||
/// Create a timer.
|
||||
/**
|
||||
* \param[in] period Time interval between triggers of the callback.
|
||||
* \param[in] callback User-defined callback function.
|
||||
* \param[in] group Callback group to execute this timer's callback in.
|
||||
*/
|
||||
template<typename DurationT = std::milli, typename CallbackT>
|
||||
typename rclcpp::timer::WallTimer<CallbackT>::SharedPtr
|
||||
create_wall_timer(
|
||||
std::chrono::duration<int64_t, DurationT> period,
|
||||
CallbackT callback,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr);
|
||||
|
||||
/* Create and return a Client. */
|
||||
template<typename ServiceT>
|
||||
typename rclcpp::client::Client<ServiceT>::SharedPtr
|
||||
create_client(
|
||||
const std::string & service_name,
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_services_default,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr);
|
||||
|
||||
/* Create and return a Service. */
|
||||
template<typename ServiceT, typename CallbackT>
|
||||
typename rclcpp::service::Service<ServiceT>::SharedPtr
|
||||
create_service(
|
||||
const std::string & service_name,
|
||||
CallbackT && callback,
|
||||
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_services_default,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr);
|
||||
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
std::vector<rcl_interfaces::msg::SetParametersResult>
|
||||
set_parameters(const std::vector<rclcpp::parameter::ParameterVariant> & parameters);
|
||||
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
rcl_interfaces::msg::SetParametersResult
|
||||
set_parameters_atomically(const std::vector<rclcpp::parameter::ParameterVariant> & parameters);
|
||||
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
std::vector<rclcpp::parameter::ParameterVariant>
|
||||
get_parameters(const std::vector<std::string> & names) const;
|
||||
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
rclcpp::parameter::ParameterVariant
|
||||
get_parameter(const std::string & name) const;
|
||||
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
bool
|
||||
get_parameter(
|
||||
const std::string & name,
|
||||
rclcpp::parameter::ParameterVariant & parameter) const;
|
||||
|
||||
template<typename ParameterT>
|
||||
bool
|
||||
get_parameter(const std::string & name, ParameterT & parameter) const;
|
||||
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
std::vector<rcl_interfaces::msg::ParameterDescriptor>
|
||||
describe_parameters(const std::vector<std::string> & names) const;
|
||||
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
std::vector<uint8_t>
|
||||
get_parameter_types(const std::vector<std::string> & names) const;
|
||||
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
rcl_interfaces::msg::ListParametersResult
|
||||
list_parameters(const std::vector<std::string> & prefixes, uint64_t depth) const;
|
||||
|
||||
/// Register the callback for parameter changes
|
||||
/**
|
||||
* \param[in] User defined callback function, It is expected to atomically set parameters.
|
||||
* \note Repeated invocations of this function will overwrite previous callbacks
|
||||
*/
|
||||
template<typename CallbackT>
|
||||
void
|
||||
register_param_change_callback(CallbackT && callback);
|
||||
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
std::map<std::string, std::string>
|
||||
get_topic_names_and_types() const;
|
||||
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
size_t
|
||||
count_publishers(const std::string & topic_name) const;
|
||||
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
size_t
|
||||
count_subscribers(const std::string & topic_name) const;
|
||||
|
||||
/// Return a graph event, which will be set anytime a graph change occurs.
|
||||
/* The graph Event object is a loan which must be returned.
|
||||
* The Event object is scoped and therefore to return the load just let it go
|
||||
* out of scope.
|
||||
*/
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
rclcpp::event::Event::SharedPtr
|
||||
get_graph_event();
|
||||
|
||||
/// Wait for a graph event to occur by waiting on an Event to become set.
|
||||
/* The given Event must be acquire through the get_graph_event() method.
|
||||
*
|
||||
* \throws InvalidEventError if the given event is nullptr
|
||||
* \throws EventNotRegisteredError if the given event was not acquired with
|
||||
* get_graph_event().
|
||||
*/
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
void
|
||||
wait_for_graph_change(
|
||||
rclcpp::event::Event::SharedPtr event,
|
||||
std::chrono::nanoseconds timeout);
|
||||
|
||||
/// Return the Node's internal NodeBaseInterface implementation.
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr
|
||||
get_node_base_interface();
|
||||
|
||||
/// Return the Node's internal NodeGraphInterface implementation.
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr
|
||||
get_node_graph_interface();
|
||||
|
||||
/// Return the Node's internal NodeTimersInterface implementation.
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
rclcpp::node_interfaces::NodeTimersInterface::SharedPtr
|
||||
get_node_timers_interface();
|
||||
|
||||
/// Return the Node's internal NodeTopicsInterface implementation.
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr
|
||||
get_node_topics_interface();
|
||||
|
||||
/// Return the Node's internal NodeServicesInterface implementation.
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
rclcpp::node_interfaces::NodeServicesInterface::SharedPtr
|
||||
get_node_services_interface();
|
||||
|
||||
/// Return the Node's internal NodeParametersInterface implementation.
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr
|
||||
get_node_parameters_interface();
|
||||
|
||||
//
|
||||
// LIFECYCLE COMPONENTS
|
||||
//
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
const State &
|
||||
get_current_state();
|
||||
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
std::vector<State>
|
||||
get_available_states();
|
||||
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
std::vector<Transition>
|
||||
get_available_transitions();
|
||||
|
||||
/// trigger the specified transition
|
||||
/*
|
||||
* return the new state after this transition
|
||||
*/
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
const State &
|
||||
trigger_transition(const Transition & transition);
|
||||
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
const State &
|
||||
trigger_transition(unsigned int transition_id);
|
||||
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
bool
|
||||
register_on_configure(std::function<rcl_lifecycle_ret_t(const State &)> fcn);
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
bool
|
||||
register_on_cleanup(std::function<rcl_lifecycle_ret_t(const State &)> fcn);
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
bool
|
||||
register_on_shutdown(std::function<rcl_lifecycle_ret_t(const State &)> fcn);
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
bool
|
||||
register_on_activate(std::function<rcl_lifecycle_ret_t(const State &)> fcn);
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
bool
|
||||
register_on_deactivate(std::function<rcl_lifecycle_ret_t(const State &)> fcn);
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
bool
|
||||
register_on_error(std::function<rcl_lifecycle_ret_t(const State &)> fcn);
|
||||
|
||||
protected:
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
void
|
||||
add_publisher_handle(std::shared_ptr<rclcpp_lifecycle::LifecyclePublisherInterface> pub);
|
||||
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
void
|
||||
add_timer_handle(std::shared_ptr<rclcpp::timer::TimerBase> timer);
|
||||
|
||||
private:
|
||||
RCLCPP_DISABLE_COPY(LifecycleNode)
|
||||
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
bool
|
||||
group_in_node(rclcpp::callback_group::CallbackGroup::SharedPtr group);
|
||||
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_;
|
||||
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph_;
|
||||
rclcpp::node_interfaces::NodeTimersInterface::SharedPtr node_timers_;
|
||||
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics_;
|
||||
rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services_;
|
||||
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr node_parameters_;
|
||||
|
||||
bool use_intra_process_comms_;
|
||||
|
||||
class LifecycleNodeInterfaceImpl;
|
||||
std::unique_ptr<LifecycleNodeInterfaceImpl> impl_;
|
||||
};
|
||||
|
||||
} // namespace rclcpp_lifecycle
|
||||
|
||||
#ifndef RCLCPP_LIFECYCLE__LIFECYCLE_NODE_IMPL_HPP_
|
||||
// Template implementations
|
||||
#include "rclcpp_lifecycle/lifecycle_node_impl.hpp"
|
||||
#endif
|
||||
|
||||
#endif // RCLCPP_LIFECYCLE__LIFECYCLE_NODE_HPP_
|
||||
@@ -0,0 +1,212 @@
|
||||
// Copyright 2016 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_LIFECYCLE__LIFECYCLE_NODE_IMPL_HPP_
|
||||
#define RCLCPP_LIFECYCLE__LIFECYCLE_NODE_IMPL_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "rclcpp/contexts/default_context.hpp"
|
||||
#include "rclcpp/intra_process_manager.hpp"
|
||||
#include "rclcpp/parameter.hpp"
|
||||
#include "rclcpp/create_publisher.hpp"
|
||||
#include "rclcpp/create_subscription.hpp"
|
||||
#include "rclcpp/type_support_decl.hpp"
|
||||
|
||||
#include "lifecycle_publisher.hpp"
|
||||
#include "rclcpp_lifecycle/visibility_control.h"
|
||||
|
||||
#include "rclcpp_lifecycle/lifecycle_node.hpp"
|
||||
|
||||
namespace rclcpp_lifecycle
|
||||
{
|
||||
|
||||
template<typename MessageT, typename Alloc>
|
||||
std::shared_ptr<rclcpp_lifecycle::LifecyclePublisher<MessageT, Alloc>>
|
||||
LifecycleNode::create_publisher(
|
||||
const std::string & topic_name, size_t qos_history_depth,
|
||||
std::shared_ptr<Alloc> allocator)
|
||||
{
|
||||
if (!allocator) {
|
||||
allocator = std::make_shared<Alloc>();
|
||||
}
|
||||
rmw_qos_profile_t qos = rmw_qos_profile_default;
|
||||
qos.depth = qos_history_depth;
|
||||
return this->create_publisher<MessageT, Alloc>(topic_name, qos, allocator);
|
||||
}
|
||||
|
||||
template<typename MessageT, typename Alloc>
|
||||
std::shared_ptr<rclcpp_lifecycle::LifecyclePublisher<MessageT, Alloc>>
|
||||
LifecycleNode::create_publisher(
|
||||
const std::string & topic_name,
|
||||
const rmw_qos_profile_t & qos_profile,
|
||||
std::shared_ptr<Alloc> allocator)
|
||||
{
|
||||
using PublisherT = rclcpp_lifecycle::LifecyclePublisher<MessageT, Alloc>;
|
||||
|
||||
// create regular publisher in rclcpp::Node
|
||||
return rclcpp::create_publisher<MessageT, Alloc, PublisherT>(
|
||||
this->node_topics_.get(),
|
||||
topic_name,
|
||||
qos_profile,
|
||||
use_intra_process_comms_,
|
||||
allocator);
|
||||
}
|
||||
|
||||
// TODO(karsten1987): Create LifecycleSubscriber
|
||||
template<typename MessageT, typename CallbackT, typename Alloc, typename SubscriptionT>
|
||||
std::shared_ptr<SubscriptionT>
|
||||
LifecycleNode::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<MessageT, Alloc>::SharedPtr
|
||||
msg_mem_strat,
|
||||
std::shared_ptr<Alloc> allocator)
|
||||
{
|
||||
if (!allocator) {
|
||||
allocator = std::make_shared<Alloc>();
|
||||
}
|
||||
|
||||
if (!msg_mem_strat) {
|
||||
using rclcpp::message_memory_strategy::MessageMemoryStrategy;
|
||||
msg_mem_strat = MessageMemoryStrategy<MessageT, Alloc>::create_default();
|
||||
}
|
||||
|
||||
return rclcpp::create_subscription<
|
||||
MessageT, CallbackT, Alloc,
|
||||
rclcpp::subscription::Subscription<MessageT, Alloc>>(
|
||||
this->node_topics_.get(),
|
||||
topic_name,
|
||||
std::forward<CallbackT>(callback),
|
||||
qos_profile,
|
||||
group,
|
||||
ignore_local_publications,
|
||||
use_intra_process_comms_,
|
||||
msg_mem_strat,
|
||||
allocator);
|
||||
}
|
||||
|
||||
template<
|
||||
typename MessageT,
|
||||
typename CallbackT,
|
||||
typename Alloc,
|
||||
typename SubscriptionT>
|
||||
std::shared_ptr<SubscriptionT>
|
||||
LifecycleNode::create_subscription(
|
||||
const std::string & topic_name,
|
||||
size_t qos_history_depth,
|
||||
CallbackT && callback,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group,
|
||||
bool ignore_local_publications,
|
||||
typename rclcpp::message_memory_strategy::MessageMemoryStrategy<MessageT, Alloc>::SharedPtr
|
||||
msg_mem_strat,
|
||||
std::shared_ptr<Alloc> allocator)
|
||||
{
|
||||
rmw_qos_profile_t qos = rmw_qos_profile_default;
|
||||
qos.depth = qos_history_depth;
|
||||
return this->create_subscription<MessageT, CallbackT, Alloc>(
|
||||
topic_name,
|
||||
std::forward<CallbackT>(callback),
|
||||
qos,
|
||||
group,
|
||||
ignore_local_publications,
|
||||
msg_mem_strat,
|
||||
allocator);
|
||||
}
|
||||
|
||||
template<typename DurationT, typename CallbackT>
|
||||
typename rclcpp::timer::WallTimer<CallbackT>::SharedPtr
|
||||
LifecycleNode::create_wall_timer(
|
||||
std::chrono::duration<int64_t, DurationT> period,
|
||||
CallbackT callback,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group)
|
||||
{
|
||||
auto timer = rclcpp::timer::WallTimer<CallbackT>::make_shared(
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(period),
|
||||
std::move(callback));
|
||||
node_timers_->add_timer(timer, group);
|
||||
return timer;
|
||||
}
|
||||
|
||||
template<typename ServiceT>
|
||||
typename rclcpp::client::Client<ServiceT>::SharedPtr
|
||||
LifecycleNode::create_client(
|
||||
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;
|
||||
|
||||
using rclcpp::client::Client;
|
||||
using rclcpp::client::ClientBase;
|
||||
|
||||
auto cli = Client<ServiceT>::make_shared(
|
||||
node_base_.get(),
|
||||
node_graph_,
|
||||
service_name,
|
||||
options);
|
||||
|
||||
auto cli_base_ptr = std::dynamic_pointer_cast<ClientBase>(cli);
|
||||
node_services_->add_client(cli_base_ptr, group);
|
||||
return cli;
|
||||
}
|
||||
|
||||
template<typename ServiceT, typename CallbackT>
|
||||
typename rclcpp::service::Service<ServiceT>::SharedPtr
|
||||
LifecycleNode::create_service(
|
||||
const std::string & service_name,
|
||||
CallbackT && callback,
|
||||
const rmw_qos_profile_t & qos_profile,
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr group)
|
||||
{
|
||||
rclcpp::service::AnyServiceCallback<ServiceT> any_service_callback;
|
||||
any_service_callback.set(std::forward<CallbackT>(callback));
|
||||
|
||||
rcl_service_options_t service_options = rcl_service_get_default_options();
|
||||
service_options.qos = qos_profile;
|
||||
|
||||
auto serv = rclcpp::service::Service<ServiceT>::make_shared(
|
||||
node_base_->get_shared_rcl_node_handle(),
|
||||
service_name, any_service_callback, service_options);
|
||||
auto serv_base_ptr = std::dynamic_pointer_cast<rclcpp::service::ServiceBase>(serv);
|
||||
node_services_->add_service(serv_base_ptr, group);
|
||||
return serv;
|
||||
}
|
||||
|
||||
template<typename ParameterT>
|
||||
bool
|
||||
LifecycleNode::get_parameter(const std::string & name, ParameterT & parameter) const
|
||||
{
|
||||
rclcpp::parameter::ParameterVariant parameter_variant(name, parameter);
|
||||
bool result = get_parameter(name, parameter_variant);
|
||||
parameter = parameter_variant.get_value<ParameterT>();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename CallbackT>
|
||||
void
|
||||
LifecycleNode::register_param_change_callback(CallbackT && callback)
|
||||
{
|
||||
this->node_parameters_->register_param_change_callback(std::forward<CallbackT>(callback));
|
||||
}
|
||||
|
||||
} // namespace rclcpp_lifecycle
|
||||
#endif // RCLCPP_LIFECYCLE__LIFECYCLE_NODE_IMPL_HPP_
|
||||
@@ -0,0 +1,167 @@
|
||||
// Copyright 2016 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_LIFECYCLE__LIFECYCLE_PUBLISHER_HPP_
|
||||
#define RCLCPP_LIFECYCLE__LIFECYCLE_PUBLISHER_HPP_
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "rclcpp/publisher.hpp"
|
||||
|
||||
namespace rclcpp_lifecycle
|
||||
{
|
||||
/// base class with only
|
||||
/**
|
||||
* pure virtual functions. A managed
|
||||
* node can then deactivate or activate
|
||||
* the publishing.
|
||||
* It is more a convenient interface class
|
||||
* than a necessary base class.
|
||||
*/
|
||||
class LifecyclePublisherInterface
|
||||
{
|
||||
public:
|
||||
virtual void on_activate() = 0;
|
||||
virtual void on_deactivate() = 0;
|
||||
virtual bool is_activated() = 0;
|
||||
};
|
||||
|
||||
/// brief child class of rclcpp Publisher class.
|
||||
/**
|
||||
* Overrides all publisher functions to check for
|
||||
* enabled/disabled state.
|
||||
*/
|
||||
template<typename MessageT, typename Alloc = std::allocator<void>>
|
||||
class LifecyclePublisher : public LifecyclePublisherInterface,
|
||||
public rclcpp::publisher::Publisher<MessageT, Alloc>
|
||||
{
|
||||
public:
|
||||
using MessageAllocTraits = rclcpp::allocator::AllocRebind<MessageT, Alloc>;
|
||||
using MessageAlloc = typename MessageAllocTraits::allocator_type;
|
||||
using MessageDeleter = rclcpp::allocator::Deleter<MessageAlloc, MessageT>;
|
||||
using MessageUniquePtr = std::unique_ptr<MessageT, MessageDeleter>;
|
||||
|
||||
LifecyclePublisher(
|
||||
rclcpp::node_interfaces::NodeBaseInterface * node_base,
|
||||
const std::string & topic,
|
||||
const rcl_publisher_options_t & publisher_options,
|
||||
std::shared_ptr<MessageAlloc> allocator)
|
||||
: rclcpp::publisher::Publisher<MessageT, Alloc>(
|
||||
node_base, topic, publisher_options, allocator),
|
||||
enabled_(false)
|
||||
{}
|
||||
|
||||
~LifecyclePublisher() {}
|
||||
|
||||
/// LifecyclePublisher pulish function
|
||||
/**
|
||||
* The publish function checks whether the communication
|
||||
* was enabled or disabled and forwards the message
|
||||
* to the actual rclcpp Publisher base class
|
||||
*/
|
||||
virtual void
|
||||
publish(std::unique_ptr<MessageT, MessageDeleter> & msg)
|
||||
{
|
||||
if (!enabled_) {
|
||||
return;
|
||||
}
|
||||
rclcpp::publisher::Publisher<MessageT, Alloc>::publish(msg);
|
||||
}
|
||||
|
||||
/// LifecyclePublisher pulish function
|
||||
/**
|
||||
* The publish function checks whether the communication
|
||||
* was enabled or disabled and forwards the message
|
||||
* to the actual rclcpp Publisher base class
|
||||
*/
|
||||
virtual void
|
||||
publish(const std::shared_ptr<MessageT> & msg)
|
||||
{
|
||||
if (!enabled_) {
|
||||
return;
|
||||
}
|
||||
rclcpp::publisher::Publisher<MessageT, Alloc>::publish(msg);
|
||||
}
|
||||
|
||||
/// LifecyclePublisher pulish function
|
||||
/**
|
||||
* The publish function checks whether the communication
|
||||
* was enabled or disabled and forwards the message
|
||||
* to the actual rclcpp Publisher base class
|
||||
*/
|
||||
virtual void
|
||||
publish(std::shared_ptr<const MessageT> msg)
|
||||
{
|
||||
if (!enabled_) {
|
||||
return;
|
||||
}
|
||||
rclcpp::publisher::Publisher<MessageT, Alloc>::publish(msg);
|
||||
}
|
||||
|
||||
/// LifecyclePublisher pulish function
|
||||
/**
|
||||
* The publish function checks whether the communication
|
||||
* was enabled or disabled and forwards the message
|
||||
* to the actual rclcpp Publisher base class
|
||||
*/
|
||||
virtual void
|
||||
publish(const MessageT & msg)
|
||||
{
|
||||
if (!enabled_) {
|
||||
return;
|
||||
}
|
||||
rclcpp::publisher::Publisher<MessageT, Alloc>::publish(msg);
|
||||
}
|
||||
|
||||
/// LifecyclePublisher pulish function
|
||||
/**
|
||||
* The publish function checks whether the communication
|
||||
* was enabled or disabled and forwards the message
|
||||
* to the actual rclcpp Publisher base class
|
||||
*/
|
||||
virtual void
|
||||
publish(std::shared_ptr<const MessageT> & msg)
|
||||
{
|
||||
if (!enabled_) {
|
||||
return;
|
||||
}
|
||||
rclcpp::publisher::Publisher<MessageT, Alloc>::publish(msg);
|
||||
}
|
||||
|
||||
virtual void
|
||||
on_activate()
|
||||
{
|
||||
enabled_ = true;
|
||||
}
|
||||
|
||||
virtual void
|
||||
on_deactivate()
|
||||
{
|
||||
enabled_ = false;
|
||||
}
|
||||
|
||||
virtual bool
|
||||
is_activated()
|
||||
{
|
||||
return enabled_;
|
||||
}
|
||||
|
||||
private:
|
||||
bool enabled_ = false;
|
||||
};
|
||||
|
||||
} // namespace rclcpp_lifecycle
|
||||
|
||||
#endif // RCLCPP_LIFECYCLE__LIFECYCLE_PUBLISHER_HPP_
|
||||
@@ -0,0 +1,98 @@
|
||||
// Copyright 2016 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_LIFECYCLE__NODE_INTERFACES__LIFECYCLE_NODE_INTERFACE_HPP_
|
||||
#define RCLCPP_LIFECYCLE__NODE_INTERFACES__LIFECYCLE_NODE_INTERFACE_HPP_
|
||||
|
||||
#include "rcl_lifecycle/data_types.h"
|
||||
|
||||
#include "rclcpp_lifecycle/state.hpp"
|
||||
#include "rclcpp_lifecycle/visibility_control.h"
|
||||
|
||||
namespace rclcpp_lifecycle
|
||||
{
|
||||
namespace node_interfaces
|
||||
{
|
||||
/// Interface class for a managed node.
|
||||
/** Virtual functions as defined in
|
||||
* http://design.ros2.org/articles/node_lifecycle.html
|
||||
*
|
||||
* If the callback function returns successfully,
|
||||
* the specified transition is completed.
|
||||
* If the callback function fails or throws an
|
||||
* uncaught exception, the on_error function is
|
||||
* called.
|
||||
* By default, all functions remain optional to overwrite
|
||||
* and return true. Except the on_error function, which
|
||||
* returns false and thus goes to shutdown/finalize state.
|
||||
*/
|
||||
class LifecycleNodeInterface
|
||||
{
|
||||
protected:
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
LifecycleNodeInterface() {}
|
||||
|
||||
public:
|
||||
/// Callback function for configure transition
|
||||
/*
|
||||
* \return true by default
|
||||
*/
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
virtual rcl_lifecycle_ret_t
|
||||
on_configure(const State & previous_state);
|
||||
|
||||
/// Callback function for cleanup transition
|
||||
/*
|
||||
* \return true by default
|
||||
*/
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
virtual rcl_lifecycle_ret_t
|
||||
on_cleanup(const State & previous_state);
|
||||
|
||||
/// Callback function for shutdown transition
|
||||
/*
|
||||
* \return true by default
|
||||
*/
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
virtual rcl_lifecycle_ret_t
|
||||
on_shutdown(const State & previous_state);
|
||||
|
||||
/// Callback function for activate transition
|
||||
/*
|
||||
* \return true by default
|
||||
*/
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
virtual rcl_lifecycle_ret_t
|
||||
on_activate(const State & previous_state);
|
||||
|
||||
/// Callback function for deactivate transition
|
||||
/*
|
||||
* \return true by default
|
||||
*/
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
virtual rcl_lifecycle_ret_t
|
||||
on_deactivate(const State & previous_state);
|
||||
|
||||
/// Callback function for errorneous transition
|
||||
/*
|
||||
* \return false by default
|
||||
*/
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
virtual rcl_lifecycle_ret_t
|
||||
on_error(const State & previous_state);
|
||||
};
|
||||
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp_lifecycle
|
||||
#endif // RCLCPP_LIFECYCLE__NODE_INTERFACES__LIFECYCLE_NODE_INTERFACE_HPP_
|
||||
57
rclcpp_lifecycle/include/rclcpp_lifecycle/state.hpp
Normal file
57
rclcpp_lifecycle/include/rclcpp_lifecycle/state.hpp
Normal file
@@ -0,0 +1,57 @@
|
||||
// Copyright 2016 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_LIFECYCLE__STATE_HPP_
|
||||
#define RCLCPP_LIFECYCLE__STATE_HPP_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "rclcpp_lifecycle/visibility_control.h"
|
||||
|
||||
// forward declare rcl_state_t
|
||||
typedef struct rcl_lifecycle_state_t rcl_lifecycle_state_t;
|
||||
|
||||
namespace rclcpp_lifecycle
|
||||
{
|
||||
|
||||
class State
|
||||
{
|
||||
public:
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
State();
|
||||
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
State(unsigned int id, const std::string & label);
|
||||
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
explicit State(const rcl_lifecycle_state_t * rcl_lifecycle_state_handle);
|
||||
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
virtual ~State();
|
||||
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
unsigned int
|
||||
id() const;
|
||||
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
std::string
|
||||
label() const;
|
||||
|
||||
protected:
|
||||
bool owns_rcl_state_handle_;
|
||||
const rcl_lifecycle_state_t * state_handle_;
|
||||
};
|
||||
|
||||
} // namespace rclcpp_lifecycle
|
||||
#endif // RCLCPP_LIFECYCLE__STATE_HPP_
|
||||
72
rclcpp_lifecycle/include/rclcpp_lifecycle/transition.hpp
Normal file
72
rclcpp_lifecycle/include/rclcpp_lifecycle/transition.hpp
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright 2016 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_LIFECYCLE__TRANSITION_HPP_
|
||||
#define RCLCPP_LIFECYCLE__TRANSITION_HPP_
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "rclcpp_lifecycle/state.hpp"
|
||||
#include "rclcpp_lifecycle/visibility_control.h"
|
||||
|
||||
// forward declare rcl_transition_t
|
||||
typedef struct rcl_lifecycle_transition_t rcl_lifecycle_transition_t;
|
||||
|
||||
namespace rclcpp_lifecycle
|
||||
{
|
||||
|
||||
class Transition
|
||||
{
|
||||
public:
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
Transition() = delete;
|
||||
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
explicit Transition(unsigned int id, const std::string & label = "");
|
||||
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
Transition(
|
||||
unsigned int id, const std::string & label,
|
||||
State && start, State && goal);
|
||||
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
explicit Transition(const rcl_lifecycle_transition_t * rcl_lifecycle_transition_handle);
|
||||
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
virtual ~Transition();
|
||||
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
unsigned int
|
||||
id() const;
|
||||
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
std::string
|
||||
label() const;
|
||||
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
State
|
||||
start_state() const;
|
||||
|
||||
RCLCPP_LIFECYCLE_PUBLIC
|
||||
State
|
||||
goal_state() const;
|
||||
|
||||
protected:
|
||||
bool owns_rcl_transition_handle_;
|
||||
|
||||
const rcl_lifecycle_transition_t * transition_handle_;
|
||||
};
|
||||
|
||||
} // namespace rclcpp_lifecycle
|
||||
#endif // RCLCPP_LIFECYCLE__TRANSITION_HPP_
|
||||
@@ -0,0 +1,56 @@
|
||||
// Copyright 2016 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_LIFECYCLE__TYPE_TRAITS__IS_MANAGEABLE_NODE_HPP_
|
||||
#define RCLCPP_LIFECYCLE__TYPE_TRAITS__IS_MANAGEABLE_NODE_HPP_
|
||||
|
||||
#include <utility>
|
||||
#include <type_traits>
|
||||
|
||||
template<class T, typename = void>
|
||||
struct has_on_activate
|
||||
{
|
||||
static constexpr bool value = false;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct has_on_activate<T, typename std::enable_if<
|
||||
std::is_same<void, decltype(std::declval<T>().on_activate())>::value>::type>
|
||||
{
|
||||
static constexpr bool value = true;
|
||||
};
|
||||
|
||||
template<class T, typename = void>
|
||||
struct has_on_deactivate
|
||||
{
|
||||
static constexpr bool value = false;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct has_on_deactivate<T, typename std::enable_if<
|
||||
std::is_same<void, decltype(std::declval<T>().on_deactivate())>::value>::type>
|
||||
{
|
||||
static constexpr bool value = true;
|
||||
};
|
||||
|
||||
template<class T, typename = void>
|
||||
struct is_manageable_node : std::false_type
|
||||
{};
|
||||
|
||||
template<class T>
|
||||
struct is_manageable_node<T, typename std::enable_if<
|
||||
has_on_activate<T>::value && has_on_deactivate<T>::value>::type>: std::true_type
|
||||
{};
|
||||
|
||||
#endif // RCLCPP_LIFECYCLE__TYPE_TRAITS__IS_MANAGEABLE_NODE_HPP_
|
||||
@@ -0,0 +1,56 @@
|
||||
// Copyright 2016 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.
|
||||
|
||||
/* This header must be included by all rclcpp headers which declare symbols
|
||||
* which are defined in the rclcpp library. When not building the rclcpp
|
||||
* library, i.e. when using the headers in other package's code, the contents
|
||||
* of this header change the visibility of certain symbols which the rclcpp
|
||||
* library cannot have, but the consuming code must have inorder to link.
|
||||
*/
|
||||
|
||||
#ifndef RCLCPP_LIFECYCLE__VISIBILITY_CONTROL_H_
|
||||
#define RCLCPP_LIFECYCLE__VISIBILITY_CONTROL_H_
|
||||
|
||||
// This logic was borrowed (then namespaced) from the examples on the gcc wiki:
|
||||
// https://gcc.gnu.org/wiki/Visibility
|
||||
|
||||
#if defined _WIN32 || defined __CYGWIN__
|
||||
#ifdef __GNUC__
|
||||
#define RCLCPP_LIFECYCLE_EXPORT __attribute__ ((dllexport))
|
||||
#define RCLCPP_LIFECYCLE_IMPORT __attribute__ ((dllimport))
|
||||
#else
|
||||
#define RCLCPP_LIFECYCLE_EXPORT __declspec(dllexport)
|
||||
#define RCLCPP_LIFECYCLE_IMPORT __declspec(dllimport)
|
||||
#endif
|
||||
#ifdef RCLCPP_LIFECYCLE_BUILDING_DLL
|
||||
#define RCLCPP_LIFECYCLE_PUBLIC RCLCPP_LIFECYCLE_EXPORT
|
||||
#else
|
||||
#define RCLCPP_LIFECYCLE_PUBLIC RCLCPP_LIFECYCLE_IMPORT
|
||||
#endif
|
||||
#define RCLCPP_LIFECYCLE_PUBLIC_TYPE RCLCPP_LIFECYCLE_PUBLIC
|
||||
#define RCLCPP_LIFECYCLE_LOCAL
|
||||
#else
|
||||
#define RCLCPP_LIFECYCLE_EXPORT __attribute__ ((visibility("default")))
|
||||
#define RCLCPP_LIFECYCLE_IMPORT
|
||||
#if __GNUC__ >= 4
|
||||
#define RCLCPP_LIFECYCLE_PUBLIC __attribute__ ((visibility("default")))
|
||||
#define RCLCPP_LIFECYCLE_LOCAL __attribute__ ((visibility("hidden")))
|
||||
#else
|
||||
#define RCLCPP_LIFECYCLE_PUBLIC
|
||||
#define RCLCPP_LIFECYCLE_LOCAL
|
||||
#endif
|
||||
#define RCLCPP_LIFECYCLE_PUBLIC_TYPE
|
||||
#endif
|
||||
|
||||
#endif // RCLCPP_LIFECYCLE__VISIBILITY_CONTROL_H_
|
||||
36
rclcpp_lifecycle/package.xml
Normal file
36
rclcpp_lifecycle/package.xml
Normal file
@@ -0,0 +1,36 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-model href="http://download.ros.org/schema/package_format2.xsd" schematypens="http://www.w3.org/2001/XMLSchema"?>
|
||||
<package format="2">
|
||||
<name>rclcpp_lifecycle</name>
|
||||
<version>0.0.0</version>
|
||||
<description>Package containing a prototype for lifecycle implementation</description>
|
||||
<maintainer email="karsten@osrfoundation.org">Karsten Knese</maintainer>
|
||||
<license>Apache License 2.0</license>
|
||||
|
||||
<buildtool_depend>ament_cmake</buildtool_depend>
|
||||
<buildtool_depend>rosidl_default_generators</buildtool_depend>
|
||||
|
||||
<build_depend>rclcpp</build_depend>
|
||||
<build_depend>rcl_lifecycle</build_depend>
|
||||
<build_depend>rmw_implementation</build_depend>
|
||||
<build_depend>rmw_implementation_cmake</build_depend>
|
||||
<build_depend>rosidl_default_generators</build_depend>
|
||||
<build_depend>std_msgs</build_depend>
|
||||
<build_depend>lifecycle_msgs</build_depend>
|
||||
|
||||
<exec_depend>rclcpp</exec_depend>
|
||||
<exec_depend>rcl_lifecycle</exec_depend>
|
||||
<exec_depend>rclpy</exec_depend>
|
||||
<exec_depend>rmw_implementation</exec_depend>
|
||||
<exec_depend>rosidl_default_runtime</exec_depend>
|
||||
<exec_depend>std_msgs</exec_depend>
|
||||
<exec_depend>lifecycle_msgs</exec_depend>
|
||||
|
||||
<test_depend>ament_cmake_gtest</test_depend>
|
||||
<test_depend>ament_lint_auto</test_depend>
|
||||
<test_depend>ament_lint_common</test_depend>
|
||||
|
||||
<export>
|
||||
<build_type>ament_cmake</build_type>
|
||||
</export>
|
||||
</package>
|
||||
310
rclcpp_lifecycle/src/lifecycle_node.cpp
Normal file
310
rclcpp_lifecycle/src/lifecycle_node.cpp
Normal file
@@ -0,0 +1,310 @@
|
||||
// Copyright 2016 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "rclcpp_lifecycle/lifecycle_node.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
#include "lifecycle_msgs/msg/state.hpp"
|
||||
#include "lifecycle_msgs/msg/transition.hpp"
|
||||
|
||||
#include "rclcpp/exceptions.hpp"
|
||||
#include "rclcpp/graph_listener.hpp"
|
||||
#include "rclcpp/node.hpp"
|
||||
#include "rclcpp/node_interfaces/node_base.hpp"
|
||||
#include "rclcpp/node_interfaces/node_graph.hpp"
|
||||
#include "rclcpp/node_interfaces/node_parameters.hpp"
|
||||
#include "rclcpp/node_interfaces/node_services.hpp"
|
||||
#include "rclcpp/node_interfaces/node_timers.hpp"
|
||||
#include "rclcpp/node_interfaces/node_topics.hpp"
|
||||
|
||||
#include "lifecycle_node_interface_impl.hpp" // implementation
|
||||
|
||||
namespace rclcpp_lifecycle
|
||||
{
|
||||
|
||||
LifecycleNode::LifecycleNode(const std::string & node_name, bool use_intra_process_comms)
|
||||
: LifecycleNode(
|
||||
node_name,
|
||||
rclcpp::contexts::default_context::get_global_default_context(),
|
||||
use_intra_process_comms)
|
||||
{}
|
||||
|
||||
LifecycleNode::LifecycleNode(
|
||||
const std::string & node_name,
|
||||
rclcpp::context::Context::SharedPtr context,
|
||||
bool use_intra_process_comms)
|
||||
: node_base_(new rclcpp::node_interfaces::NodeBase(node_name, context)),
|
||||
node_graph_(new rclcpp::node_interfaces::NodeGraph(node_base_.get())),
|
||||
node_timers_(new rclcpp::node_interfaces::NodeTimers(node_base_.get())),
|
||||
node_topics_(new rclcpp::node_interfaces::NodeTopics(node_base_.get())),
|
||||
node_services_(new rclcpp::node_interfaces::NodeServices(node_base_.get())),
|
||||
node_parameters_(new rclcpp::node_interfaces::NodeParameters(
|
||||
node_topics_.get(),
|
||||
use_intra_process_comms
|
||||
)),
|
||||
use_intra_process_comms_(use_intra_process_comms),
|
||||
impl_(new LifecycleNodeInterfaceImpl(node_base_, node_services_))
|
||||
{
|
||||
impl_->init();
|
||||
|
||||
register_on_configure(std::bind(&LifecycleNodeInterface::on_configure, this,
|
||||
std::placeholders::_1));
|
||||
register_on_cleanup(std::bind(&LifecycleNodeInterface::on_cleanup, this, std::placeholders::_1));
|
||||
register_on_shutdown(std::bind(&LifecycleNodeInterface::on_shutdown, this,
|
||||
std::placeholders::_1));
|
||||
register_on_activate(std::bind(&LifecycleNodeInterface::on_activate, this,
|
||||
std::placeholders::_1));
|
||||
register_on_deactivate(std::bind(&LifecycleNodeInterface::on_deactivate, this,
|
||||
std::placeholders::_1));
|
||||
register_on_error(std::bind(&LifecycleNodeInterface::on_error, this, std::placeholders::_1));
|
||||
}
|
||||
|
||||
LifecycleNode::~LifecycleNode()
|
||||
{}
|
||||
|
||||
const char *
|
||||
LifecycleNode::get_name() const
|
||||
{
|
||||
return node_base_->get_name();
|
||||
}
|
||||
|
||||
rclcpp::callback_group::CallbackGroup::SharedPtr
|
||||
LifecycleNode::create_callback_group(
|
||||
rclcpp::callback_group::CallbackGroupType group_type)
|
||||
{
|
||||
return node_base_->create_callback_group(group_type);
|
||||
}
|
||||
|
||||
bool
|
||||
LifecycleNode::group_in_node(rclcpp::callback_group::CallbackGroup::SharedPtr group)
|
||||
{
|
||||
return node_base_->callback_group_in_node(group);
|
||||
}
|
||||
|
||||
std::vector<rcl_interfaces::msg::SetParametersResult>
|
||||
LifecycleNode::set_parameters(
|
||||
const std::vector<rclcpp::parameter::ParameterVariant> & parameters)
|
||||
{
|
||||
return node_parameters_->set_parameters(parameters);
|
||||
}
|
||||
|
||||
rcl_interfaces::msg::SetParametersResult
|
||||
LifecycleNode::set_parameters_atomically(
|
||||
const std::vector<rclcpp::parameter::ParameterVariant> & parameters)
|
||||
{
|
||||
return node_parameters_->set_parameters_atomically(parameters);
|
||||
}
|
||||
|
||||
std::vector<rclcpp::parameter::ParameterVariant>
|
||||
LifecycleNode::get_parameters(
|
||||
const std::vector<std::string> & names) const
|
||||
{
|
||||
return node_parameters_->get_parameters(names);
|
||||
}
|
||||
|
||||
rclcpp::parameter::ParameterVariant
|
||||
LifecycleNode::get_parameter(const std::string & name) const
|
||||
{
|
||||
return node_parameters_->get_parameter(name);
|
||||
}
|
||||
|
||||
bool LifecycleNode::get_parameter(const std::string & name,
|
||||
rclcpp::parameter::ParameterVariant & parameter) const
|
||||
{
|
||||
return node_parameters_->get_parameter(name, parameter);
|
||||
}
|
||||
|
||||
std::vector<rcl_interfaces::msg::ParameterDescriptor>
|
||||
LifecycleNode::describe_parameters(
|
||||
const std::vector<std::string> & names) const
|
||||
{
|
||||
return node_parameters_->describe_parameters(names);
|
||||
}
|
||||
|
||||
std::vector<uint8_t>
|
||||
LifecycleNode::get_parameter_types(
|
||||
const std::vector<std::string> & names) const
|
||||
{
|
||||
return node_parameters_->get_parameter_types(names);
|
||||
}
|
||||
|
||||
rcl_interfaces::msg::ListParametersResult
|
||||
LifecycleNode::list_parameters(
|
||||
const std::vector<std::string> & prefixes, uint64_t depth) const
|
||||
{
|
||||
return node_parameters_->list_parameters(prefixes, depth);
|
||||
}
|
||||
|
||||
std::map<std::string, std::string>
|
||||
LifecycleNode::get_topic_names_and_types() const
|
||||
{
|
||||
return node_graph_->get_topic_names_and_types();
|
||||
}
|
||||
|
||||
size_t
|
||||
LifecycleNode::count_publishers(const std::string & topic_name) const
|
||||
{
|
||||
return node_graph_->count_publishers(topic_name);
|
||||
}
|
||||
|
||||
size_t
|
||||
LifecycleNode::count_subscribers(const std::string & topic_name) const
|
||||
{
|
||||
return node_graph_->count_subscribers(topic_name);
|
||||
}
|
||||
|
||||
const std::vector<rclcpp::callback_group::CallbackGroup::WeakPtr> &
|
||||
LifecycleNode::get_callback_groups() const
|
||||
{
|
||||
return node_base_->get_callback_groups();
|
||||
}
|
||||
|
||||
rclcpp::event::Event::SharedPtr
|
||||
LifecycleNode::get_graph_event()
|
||||
{
|
||||
return node_graph_->get_graph_event();
|
||||
}
|
||||
|
||||
void
|
||||
LifecycleNode::wait_for_graph_change(
|
||||
rclcpp::event::Event::SharedPtr event,
|
||||
std::chrono::nanoseconds timeout)
|
||||
{
|
||||
node_graph_->wait_for_graph_change(event, timeout);
|
||||
}
|
||||
|
||||
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr
|
||||
LifecycleNode::get_node_base_interface()
|
||||
{
|
||||
return node_base_;
|
||||
}
|
||||
|
||||
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr
|
||||
LifecycleNode::get_node_graph_interface()
|
||||
{
|
||||
return node_graph_;
|
||||
}
|
||||
|
||||
rclcpp::node_interfaces::NodeTimersInterface::SharedPtr
|
||||
LifecycleNode::get_node_timers_interface()
|
||||
{
|
||||
return node_timers_;
|
||||
}
|
||||
|
||||
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr
|
||||
LifecycleNode::get_node_topics_interface()
|
||||
{
|
||||
return node_topics_;
|
||||
}
|
||||
|
||||
rclcpp::node_interfaces::NodeServicesInterface::SharedPtr
|
||||
LifecycleNode::get_node_services_interface()
|
||||
{
|
||||
return node_services_;
|
||||
}
|
||||
|
||||
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr
|
||||
LifecycleNode::get_node_parameters_interface()
|
||||
{
|
||||
return node_parameters_;
|
||||
}
|
||||
|
||||
|
||||
////
|
||||
bool
|
||||
LifecycleNode::register_on_configure(std::function<rcl_lifecycle_ret_t(const State &)> fcn)
|
||||
{
|
||||
return impl_->register_callback(lifecycle_msgs::msg::State::TRANSITION_STATE_CONFIGURING, fcn);
|
||||
}
|
||||
|
||||
bool
|
||||
LifecycleNode::register_on_cleanup(std::function<rcl_lifecycle_ret_t(const State &)> fcn)
|
||||
{
|
||||
return impl_->register_callback(lifecycle_msgs::msg::State::TRANSITION_STATE_CLEANINGUP, fcn);
|
||||
}
|
||||
|
||||
bool
|
||||
LifecycleNode::register_on_shutdown(std::function<rcl_lifecycle_ret_t(const State &)> fcn)
|
||||
{
|
||||
return impl_->register_callback(lifecycle_msgs::msg::State::TRANSITION_STATE_SHUTTINGDOWN, fcn);
|
||||
}
|
||||
|
||||
bool
|
||||
LifecycleNode::register_on_activate(std::function<rcl_lifecycle_ret_t(const State &)> fcn)
|
||||
{
|
||||
return impl_->register_callback(lifecycle_msgs::msg::State::TRANSITION_STATE_ACTIVATING, fcn);
|
||||
}
|
||||
|
||||
bool
|
||||
LifecycleNode::register_on_deactivate(std::function<rcl_lifecycle_ret_t(const State &)> fcn)
|
||||
{
|
||||
return impl_->register_callback(lifecycle_msgs::msg::State::TRANSITION_STATE_DEACTIVATING, fcn);
|
||||
}
|
||||
|
||||
bool
|
||||
LifecycleNode::register_on_error(std::function<rcl_lifecycle_ret_t(const State &)> fcn)
|
||||
{
|
||||
return impl_->register_callback(lifecycle_msgs::msg::State::TRANSITION_STATE_ERRORPROCESSING,
|
||||
fcn);
|
||||
}
|
||||
|
||||
const State &
|
||||
LifecycleNode::get_current_state()
|
||||
{
|
||||
return impl_->get_current_state();
|
||||
}
|
||||
|
||||
std::vector<State>
|
||||
LifecycleNode::get_available_states()
|
||||
{
|
||||
return impl_->get_available_states();
|
||||
}
|
||||
|
||||
std::vector<Transition>
|
||||
LifecycleNode::get_available_transitions()
|
||||
{
|
||||
return impl_->get_available_transitions();
|
||||
}
|
||||
|
||||
const State &
|
||||
LifecycleNode::trigger_transition(const Transition & transition)
|
||||
{
|
||||
return trigger_transition(transition.id());
|
||||
}
|
||||
|
||||
const State &
|
||||
LifecycleNode::trigger_transition(unsigned int transition_id)
|
||||
{
|
||||
return impl_->trigger_transition(transition_id);
|
||||
}
|
||||
|
||||
void
|
||||
LifecycleNode::add_publisher_handle(
|
||||
std::shared_ptr<rclcpp_lifecycle::LifecyclePublisherInterface> pub)
|
||||
{
|
||||
impl_->add_publisher_handle(pub);
|
||||
}
|
||||
|
||||
void
|
||||
LifecycleNode::add_timer_handle(std::shared_ptr<rclcpp::timer::TimerBase> timer)
|
||||
{
|
||||
impl_->add_timer_handle(timer);
|
||||
}
|
||||
|
||||
} // namespace rclcpp_lifecycle
|
||||
397
rclcpp_lifecycle/src/lifecycle_node_interface_impl.hpp
Normal file
397
rclcpp_lifecycle/src/lifecycle_node_interface_impl.hpp
Normal file
@@ -0,0 +1,397 @@
|
||||
// Copyright 2016 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 LIFECYCLE_NODE_INTERFACE_IMPL_HPP_
|
||||
#define LIFECYCLE_NODE_INTERFACE_IMPL_HPP_
|
||||
|
||||
#include "rclcpp_lifecycle/lifecycle_node.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
#include "lifecycle_msgs/msg/transition_description.hpp"
|
||||
#include "lifecycle_msgs/msg/transition_event.h" // for getting the c-typesupport
|
||||
#include "lifecycle_msgs/msg/transition_event.hpp"
|
||||
#include "lifecycle_msgs/srv/change_state.hpp"
|
||||
#include "lifecycle_msgs/srv/get_state.hpp"
|
||||
#include "lifecycle_msgs/srv/get_available_states.hpp"
|
||||
#include "lifecycle_msgs/srv/get_available_transitions.hpp"
|
||||
|
||||
#include "rcl/error_handling.h"
|
||||
|
||||
#include "rcl_lifecycle/rcl_lifecycle.h"
|
||||
|
||||
#include "rclcpp/node_interfaces/node_base_interface.hpp"
|
||||
#include "rclcpp/node_interfaces/node_services_interface.hpp"
|
||||
|
||||
namespace rclcpp_lifecycle
|
||||
{
|
||||
|
||||
class LifecycleNode::LifecycleNodeInterfaceImpl
|
||||
{
|
||||
using ChangeStateSrv = lifecycle_msgs::srv::ChangeState;
|
||||
using GetStateSrv = lifecycle_msgs::srv::GetState;
|
||||
using GetAvailableStatesSrv = lifecycle_msgs::srv::GetAvailableStates;
|
||||
using GetAvailableTransitionsSrv = lifecycle_msgs::srv::GetAvailableTransitions;
|
||||
using TransitionEventMsg = lifecycle_msgs::msg::TransitionEvent;
|
||||
|
||||
public:
|
||||
LifecycleNodeInterfaceImpl(
|
||||
std::shared_ptr<rclcpp::node_interfaces::NodeBaseInterface> node_base_interface,
|
||||
std::shared_ptr<rclcpp::node_interfaces::NodeServicesInterface> node_services_interface)
|
||||
: node_base_interface_(node_base_interface),
|
||||
node_services_interface_(node_services_interface)
|
||||
{}
|
||||
|
||||
~LifecycleNodeInterfaceImpl()
|
||||
{
|
||||
if (rcl_lifecycle_state_machine_is_initialized(&state_machine_) != RCL_RET_OK) {
|
||||
fprintf(stderr, "%s:%u, FATAL: rcl_state_machine got destroyed externally.\n",
|
||||
__FILE__, __LINE__);
|
||||
} else {
|
||||
rcl_lifecycle_state_machine_fini(&state_machine_,
|
||||
node_base_interface_->get_rcl_node_handle());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
init()
|
||||
{
|
||||
state_machine_ = rcl_lifecycle_get_zero_initialized_state_machine();
|
||||
// The call to initialize the state machine takes
|
||||
// currently five different typesupports for all publishers/services
|
||||
// created within the RCL_LIFECYCLE structure.
|
||||
// The publisher takes a C-Typesupport since the publishing (i.e. creating
|
||||
// the message) is done fully in RCL.
|
||||
// Services are handled in C++, so that it needs a C++ typesupport structure.
|
||||
rcl_ret_t ret = rcl_lifecycle_state_machine_init(
|
||||
&state_machine_, node_base_interface_->get_rcl_node_handle(),
|
||||
ROSIDL_GET_TYPE_SUPPORT(lifecycle_msgs, msg, TransitionEvent),
|
||||
rosidl_typesupport_cpp::get_service_type_support_handle<ChangeStateSrv>(),
|
||||
rosidl_typesupport_cpp::get_service_type_support_handle<GetStateSrv>(),
|
||||
rosidl_typesupport_cpp::get_service_type_support_handle<GetAvailableStatesSrv>(),
|
||||
rosidl_typesupport_cpp::get_service_type_support_handle<GetAvailableTransitionsSrv>(),
|
||||
true);
|
||||
if (ret != RCL_RET_OK) {
|
||||
throw std::runtime_error(
|
||||
std::string(
|
||||
"Couldn't initialize state machine for node ") + node_base_interface_->get_name());
|
||||
}
|
||||
|
||||
{ // change_state
|
||||
auto cb = std::bind(&LifecycleNodeInterfaceImpl::on_change_state, this,
|
||||
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
|
||||
rclcpp::any_service_callback::AnyServiceCallback<ChangeStateSrv> any_cb;
|
||||
any_cb.set(cb);
|
||||
|
||||
srv_change_state_ = std::make_shared<rclcpp::service::Service<ChangeStateSrv>>(
|
||||
node_base_interface_->get_shared_rcl_node_handle(),
|
||||
&state_machine_.com_interface.srv_change_state,
|
||||
any_cb);
|
||||
node_services_interface_->add_service(
|
||||
std::dynamic_pointer_cast<rclcpp::service::ServiceBase>(srv_change_state_),
|
||||
nullptr);
|
||||
}
|
||||
|
||||
{ // get_state
|
||||
auto cb = std::bind(&LifecycleNodeInterfaceImpl::on_get_state, this,
|
||||
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
|
||||
rclcpp::any_service_callback::AnyServiceCallback<GetStateSrv> any_cb;
|
||||
any_cb.set(std::move(cb));
|
||||
|
||||
srv_get_state_ = std::make_shared<rclcpp::service::Service<GetStateSrv>>(
|
||||
node_base_interface_->get_shared_rcl_node_handle(),
|
||||
&state_machine_.com_interface.srv_get_state,
|
||||
any_cb);
|
||||
node_services_interface_->add_service(
|
||||
std::dynamic_pointer_cast<rclcpp::service::ServiceBase>(srv_get_state_),
|
||||
nullptr);
|
||||
}
|
||||
|
||||
{ // get_available_states
|
||||
auto cb = std::bind(&LifecycleNodeInterfaceImpl::on_get_available_states, this,
|
||||
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
|
||||
rclcpp::any_service_callback::AnyServiceCallback<GetAvailableStatesSrv> any_cb;
|
||||
any_cb.set(std::move(cb));
|
||||
|
||||
srv_get_available_states_ = std::make_shared<rclcpp::service::Service<GetAvailableStatesSrv>>(
|
||||
node_base_interface_->get_shared_rcl_node_handle(),
|
||||
&state_machine_.com_interface.srv_get_available_states,
|
||||
any_cb);
|
||||
node_services_interface_->add_service(
|
||||
std::dynamic_pointer_cast<rclcpp::service::ServiceBase>(srv_get_available_states_),
|
||||
nullptr);
|
||||
}
|
||||
|
||||
{ // get_available_transitions
|
||||
auto cb = std::bind(&LifecycleNodeInterfaceImpl::on_get_available_transitions, this,
|
||||
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
|
||||
rclcpp::any_service_callback::AnyServiceCallback<GetAvailableTransitionsSrv> any_cb;
|
||||
any_cb.set(std::move(cb));
|
||||
|
||||
srv_get_available_transitions_ =
|
||||
std::make_shared<rclcpp::service::Service<GetAvailableTransitionsSrv>>(
|
||||
node_base_interface_->get_shared_rcl_node_handle(),
|
||||
&state_machine_.com_interface.srv_get_available_transitions,
|
||||
any_cb);
|
||||
node_services_interface_->add_service(
|
||||
std::dynamic_pointer_cast<rclcpp::service::ServiceBase>(srv_get_available_transitions_),
|
||||
nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
register_callback(std::uint8_t lifecycle_transition, std::function<rcl_lifecycle_ret_t(
|
||||
const State &)> & cb)
|
||||
{
|
||||
cb_map_[lifecycle_transition] = cb;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
on_change_state(const std::shared_ptr<rmw_request_id_t> header,
|
||||
const std::shared_ptr<ChangeStateSrv::Request> req,
|
||||
std::shared_ptr<ChangeStateSrv::Response> resp)
|
||||
{
|
||||
(void)header;
|
||||
if (rcl_lifecycle_state_machine_is_initialized(&state_machine_) != RCL_RET_OK) {
|
||||
throw std::runtime_error(
|
||||
"Can't get state. State machine is not initialized.");
|
||||
}
|
||||
resp->success = change_state(req->transition.id);
|
||||
}
|
||||
|
||||
void
|
||||
on_get_state(const std::shared_ptr<rmw_request_id_t> header,
|
||||
const std::shared_ptr<GetStateSrv::Request> req,
|
||||
std::shared_ptr<GetStateSrv::Response> resp)
|
||||
{
|
||||
(void)header;
|
||||
(void)req;
|
||||
if (rcl_lifecycle_state_machine_is_initialized(&state_machine_) != RCL_RET_OK) {
|
||||
throw std::runtime_error(
|
||||
"Can't get state. State machine is not initialized.");
|
||||
}
|
||||
resp->current_state.id = static_cast<uint8_t>(state_machine_.current_state->id);
|
||||
resp->current_state.label = state_machine_.current_state->label;
|
||||
}
|
||||
|
||||
void
|
||||
on_get_available_states(const std::shared_ptr<rmw_request_id_t> header,
|
||||
const std::shared_ptr<GetAvailableStatesSrv::Request> req,
|
||||
std::shared_ptr<GetAvailableStatesSrv::Response> resp)
|
||||
{
|
||||
(void)header;
|
||||
(void)req;
|
||||
if (rcl_lifecycle_state_machine_is_initialized(&state_machine_) != RCL_RET_OK) {
|
||||
throw std::runtime_error(
|
||||
"Can't get available states. State machine is not initialized.");
|
||||
}
|
||||
for (unsigned int i = 0; i < state_machine_.transition_map.states_size; ++i) {
|
||||
lifecycle_msgs::msg::State state;
|
||||
state.id = static_cast<uint8_t>(state_machine_.transition_map.states[i].id);
|
||||
state.label = static_cast<std::string>(state_machine_.transition_map.states[i].label);
|
||||
resp->available_states.push_back(state);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
on_get_available_transitions(const std::shared_ptr<rmw_request_id_t> header,
|
||||
const std::shared_ptr<GetAvailableTransitionsSrv::Request> req,
|
||||
std::shared_ptr<GetAvailableTransitionsSrv::Response> resp)
|
||||
{
|
||||
(void)header;
|
||||
(void)req;
|
||||
if (rcl_lifecycle_state_machine_is_initialized(&state_machine_) != RCL_RET_OK) {
|
||||
throw std::runtime_error(
|
||||
"Can't get available transitions. State machine is not initialized.");
|
||||
return;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < state_machine_.transition_map.transitions_size; ++i) {
|
||||
rcl_lifecycle_transition_t & rcl_transition = state_machine_.transition_map.transitions[i];
|
||||
lifecycle_msgs::msg::TransitionDescription trans_desc;
|
||||
trans_desc.transition.id = rcl_transition.id;
|
||||
trans_desc.transition.label = rcl_transition.label;
|
||||
trans_desc.start_state.id = rcl_transition.start->id;
|
||||
trans_desc.start_state.label = rcl_transition.start->label;
|
||||
trans_desc.goal_state.id = rcl_transition.goal->id;
|
||||
trans_desc.goal_state.label = rcl_transition.goal->label;
|
||||
resp->available_transitions.push_back(trans_desc);
|
||||
}
|
||||
}
|
||||
|
||||
const State &
|
||||
get_current_state()
|
||||
{
|
||||
current_state_ = State(state_machine_.current_state);
|
||||
return current_state_;
|
||||
}
|
||||
|
||||
std::vector<State>
|
||||
get_available_states()
|
||||
{
|
||||
std::vector<State> states;
|
||||
for (unsigned int i = 0; i < state_machine_.transition_map.states_size; ++i) {
|
||||
State state(&state_machine_.transition_map.states[i]);
|
||||
states.push_back(state);
|
||||
}
|
||||
return states;
|
||||
}
|
||||
|
||||
std::vector<Transition>
|
||||
get_available_transitions()
|
||||
{
|
||||
std::vector<Transition> transitions;
|
||||
|
||||
for (unsigned int i = 0; i < state_machine_.transition_map.transitions_size; ++i) {
|
||||
Transition transition(
|
||||
&state_machine_.transition_map.transitions[i]);
|
||||
transitions.push_back(transition);
|
||||
}
|
||||
return transitions;
|
||||
}
|
||||
|
||||
bool
|
||||
change_state(std::uint8_t lifecycle_transition)
|
||||
{
|
||||
if (rcl_lifecycle_state_machine_is_initialized(&state_machine_) != RCL_RET_OK) {
|
||||
fprintf(stderr, "%s:%d, Unable to change state for state machine for %s: %s \n",
|
||||
__FILE__, __LINE__, node_base_interface_->get_name(), rcl_get_error_string_safe());
|
||||
return false;
|
||||
}
|
||||
|
||||
// keep the initial state to pass to a transition callback
|
||||
State initial_state(state_machine_.current_state);
|
||||
|
||||
unsigned int transition_id = static_cast<unsigned int>(lifecycle_transition);
|
||||
if (rcl_lifecycle_trigger_transition(&state_machine_, transition_id, true) != RCL_RET_OK) {
|
||||
fprintf(stderr, "%s:%d, Unable to start transition %u from current state %s: %s\n",
|
||||
__FILE__, __LINE__, transition_id,
|
||||
state_machine_.current_state->label, rcl_get_error_string_safe());
|
||||
return false;
|
||||
}
|
||||
|
||||
rcl_lifecycle_ret_t cb_success = execute_callback(
|
||||
state_machine_.current_state->id, initial_state);
|
||||
|
||||
if (rcl_lifecycle_trigger_transition(
|
||||
&state_machine_, cb_success, true) != RCL_RET_OK)
|
||||
{
|
||||
fprintf(stderr, "Failed to finish transition %u. Current state is now: %s\n",
|
||||
transition_id, state_machine_.current_state->label);
|
||||
return false;
|
||||
}
|
||||
|
||||
// error handling ?!
|
||||
// TODO(karsten1987): iterate over possible ret value
|
||||
if (cb_success == RCL_LIFECYCLE_RET_ERROR) {
|
||||
rcl_lifecycle_ret_t error_resolved = execute_callback(state_machine_.current_state->id,
|
||||
initial_state);
|
||||
if (error_resolved == RCL_RET_OK) {
|
||||
fprintf(stderr, "Exception handling was successful\n");
|
||||
// We call cleanup on the error state
|
||||
rcl_lifecycle_trigger_transition(
|
||||
&state_machine_, error_resolved, true);
|
||||
fprintf(stderr, "current state after error callback%s\n",
|
||||
state_machine_.current_state->label);
|
||||
} else {
|
||||
// We call shutdown on the error state
|
||||
rcl_lifecycle_trigger_transition(
|
||||
&state_machine_, error_resolved, true);
|
||||
}
|
||||
}
|
||||
// This true holds in both cases where the actual callback
|
||||
// was successful or not, since at this point we have a valid transistion
|
||||
// to either a new primary state or error state
|
||||
return true;
|
||||
}
|
||||
|
||||
rcl_lifecycle_ret_t
|
||||
execute_callback(unsigned int cb_id, const State & previous_state)
|
||||
{
|
||||
// in case no callback was attached, we forward directly
|
||||
auto cb_success = RCL_LIFECYCLE_RET_OK;
|
||||
|
||||
auto it = cb_map_.find(cb_id);
|
||||
if (it != cb_map_.end()) {
|
||||
auto callback = it->second;
|
||||
try {
|
||||
cb_success = callback(State(previous_state));
|
||||
} catch (const std::exception &) {
|
||||
// TODO(karsten1987): Windows CI doens't let me print the msg here
|
||||
// the todo is to forward the exception to the on_error callback
|
||||
// fprintf(stderr, "Caught exception in callback for transition %d\n",
|
||||
// it->first);
|
||||
// fprintf(stderr, "Original error msg: %s\n", e.what());
|
||||
// maybe directly go for error handling here
|
||||
// and pass exception along with it
|
||||
cb_success = RCL_LIFECYCLE_RET_ERROR;
|
||||
}
|
||||
}
|
||||
return cb_success;
|
||||
}
|
||||
|
||||
const State &
|
||||
trigger_transition(unsigned int transition_id)
|
||||
{
|
||||
change_state(transition_id);
|
||||
return get_current_state();
|
||||
}
|
||||
|
||||
void
|
||||
add_publisher_handle(std::shared_ptr<rclcpp_lifecycle::LifecyclePublisherInterface> pub)
|
||||
{
|
||||
weak_pubs_.push_back(pub);
|
||||
}
|
||||
|
||||
void
|
||||
add_timer_handle(std::shared_ptr<rclcpp::timer::TimerBase> timer)
|
||||
{
|
||||
weak_timers_.push_back(timer);
|
||||
}
|
||||
|
||||
rcl_lifecycle_state_machine_t state_machine_;
|
||||
State current_state_;
|
||||
std::map<
|
||||
std::uint8_t,
|
||||
std::function<rcl_lifecycle_ret_t(const State &)>> cb_map_;
|
||||
|
||||
using NodeBasePtr = std::shared_ptr<rclcpp::node_interfaces::NodeBaseInterface>;
|
||||
using NodeServicesPtr = std::shared_ptr<rclcpp::node_interfaces::NodeServicesInterface>;
|
||||
using ChangeStateSrvPtr = std::shared_ptr<rclcpp::service::Service<ChangeStateSrv>>;
|
||||
using GetStateSrvPtr = std::shared_ptr<rclcpp::service::Service<GetStateSrv>>;
|
||||
using GetAvailableStatesSrvPtr =
|
||||
std::shared_ptr<rclcpp::service::Service<GetAvailableStatesSrv>>;
|
||||
using GetAvailableTransitionsSrvPtr =
|
||||
std::shared_ptr<rclcpp::service::Service<GetAvailableTransitionsSrv>>;
|
||||
|
||||
NodeBasePtr node_base_interface_;
|
||||
NodeServicesPtr node_services_interface_;
|
||||
ChangeStateSrvPtr srv_change_state_;
|
||||
GetStateSrvPtr srv_get_state_;
|
||||
GetAvailableStatesSrvPtr srv_get_available_states_;
|
||||
GetAvailableTransitionsSrvPtr srv_get_available_transitions_;
|
||||
|
||||
// to controllable things
|
||||
std::vector<std::weak_ptr<rclcpp_lifecycle::LifecyclePublisherInterface>> weak_pubs_;
|
||||
std::vector<std::weak_ptr<rclcpp::timer::TimerBase>> weak_timers_;
|
||||
};
|
||||
|
||||
} // namespace rclcpp_lifecycle
|
||||
#endif // LIFECYCLE_NODE_INTERFACE_IMPL_HPP_
|
||||
@@ -0,0 +1,58 @@
|
||||
// Copyright 2016 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "rclcpp_lifecycle/node_interfaces/lifecycle_node_interface.hpp"
|
||||
|
||||
namespace rclcpp_lifecycle
|
||||
{
|
||||
namespace node_interfaces
|
||||
{
|
||||
rcl_lifecycle_ret_t
|
||||
LifecycleNodeInterface::on_configure(const State &)
|
||||
{
|
||||
return RCL_LIFECYCLE_RET_OK;
|
||||
}
|
||||
|
||||
rcl_lifecycle_ret_t
|
||||
LifecycleNodeInterface::on_cleanup(const State &)
|
||||
{
|
||||
return RCL_LIFECYCLE_RET_OK;
|
||||
}
|
||||
|
||||
rcl_lifecycle_ret_t
|
||||
LifecycleNodeInterface::on_shutdown(const State &)
|
||||
{
|
||||
return RCL_LIFECYCLE_RET_OK;
|
||||
}
|
||||
|
||||
rcl_lifecycle_ret_t
|
||||
LifecycleNodeInterface::on_activate(const State &)
|
||||
{
|
||||
return RCL_LIFECYCLE_RET_OK;
|
||||
}
|
||||
|
||||
rcl_lifecycle_ret_t
|
||||
LifecycleNodeInterface::on_deactivate(const State &)
|
||||
{
|
||||
return RCL_LIFECYCLE_RET_OK;
|
||||
}
|
||||
|
||||
rcl_lifecycle_ret_t
|
||||
LifecycleNodeInterface::on_error(const State &)
|
||||
{
|
||||
return RCL_LIFECYCLE_RET_FAILURE;
|
||||
}
|
||||
|
||||
} // namespace node_interfaces
|
||||
} // namespace rclcpp_lifecycle
|
||||
68
rclcpp_lifecycle/src/state.cpp
Normal file
68
rclcpp_lifecycle/src/state.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright 2016 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "rclcpp_lifecycle/state.hpp"
|
||||
|
||||
#include <lifecycle_msgs/msg/state.hpp>
|
||||
#include <rcl_lifecycle/data_types.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace rclcpp_lifecycle
|
||||
{
|
||||
|
||||
State::State()
|
||||
: State(lifecycle_msgs::msg::State::PRIMARY_STATE_UNKNOWN, "unknown")
|
||||
{}
|
||||
|
||||
State::State(unsigned int id, const std::string & label)
|
||||
: owns_rcl_state_handle_(true)
|
||||
{
|
||||
if (label.empty()) {
|
||||
throw std::runtime_error("Lifecycle State cannot have an empty label.");
|
||||
}
|
||||
|
||||
auto state_handle = new rcl_lifecycle_state_t;
|
||||
state_handle->id = id;
|
||||
state_handle->label = label.c_str();
|
||||
|
||||
state_handle_ = state_handle;
|
||||
}
|
||||
|
||||
State::State(const rcl_lifecycle_state_t * rcl_lifecycle_state_handle)
|
||||
: owns_rcl_state_handle_(false)
|
||||
{
|
||||
state_handle_ = rcl_lifecycle_state_handle;
|
||||
}
|
||||
|
||||
State::~State()
|
||||
{
|
||||
if (owns_rcl_state_handle_) {
|
||||
delete state_handle_;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int
|
||||
State::id() const
|
||||
{
|
||||
return state_handle_->id;
|
||||
}
|
||||
|
||||
std::string
|
||||
State::label() const
|
||||
{
|
||||
return state_handle_->label;
|
||||
}
|
||||
|
||||
} // namespace rclcpp_lifecycle
|
||||
106
rclcpp_lifecycle/src/transition.cpp
Normal file
106
rclcpp_lifecycle/src/transition.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
// Copyright 2016 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "rclcpp_lifecycle/transition.hpp"
|
||||
|
||||
#include <lifecycle_msgs/msg/transition.hpp>
|
||||
#include <rcl_lifecycle/data_types.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace rclcpp_lifecycle
|
||||
{
|
||||
|
||||
Transition::Transition(unsigned int id, const std::string & label)
|
||||
: owns_rcl_transition_handle_(true)
|
||||
{
|
||||
auto transition_handle = new rcl_lifecycle_transition_t;
|
||||
transition_handle->id = id;
|
||||
transition_handle->label = label.c_str();
|
||||
|
||||
transition_handle->start = nullptr;
|
||||
transition_handle->goal = nullptr;
|
||||
transition_handle_ = transition_handle;
|
||||
}
|
||||
|
||||
Transition::Transition(
|
||||
unsigned int id, const std::string & label,
|
||||
State && start, State && goal)
|
||||
: owns_rcl_transition_handle_(true)
|
||||
{
|
||||
auto transition_handle = new rcl_lifecycle_transition_t;
|
||||
transition_handle->id = id;
|
||||
transition_handle->label = label.c_str();
|
||||
|
||||
auto start_state = new rcl_lifecycle_state_t;
|
||||
start_state->id = start.id();
|
||||
start_state->label = start.label().c_str();
|
||||
|
||||
auto goal_state = new rcl_lifecycle_state_t;
|
||||
goal_state->id = goal.id();
|
||||
goal_state->label = start.label().c_str();
|
||||
|
||||
transition_handle->start = start_state;
|
||||
transition_handle->goal = goal_state;
|
||||
transition_handle_ = transition_handle;
|
||||
}
|
||||
|
||||
Transition::Transition(const rcl_lifecycle_transition_t * rcl_lifecycle_transition_handle)
|
||||
: owns_rcl_transition_handle_(false)
|
||||
{
|
||||
transition_handle_ = rcl_lifecycle_transition_handle;
|
||||
}
|
||||
|
||||
Transition::~Transition()
|
||||
{
|
||||
if (owns_rcl_transition_handle_) {
|
||||
if (transition_handle_->start) {
|
||||
delete transition_handle_->start;
|
||||
}
|
||||
if (transition_handle_->goal) {
|
||||
delete transition_handle_->goal;
|
||||
}
|
||||
delete transition_handle_;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int
|
||||
Transition::id() const
|
||||
{
|
||||
return transition_handle_->id;
|
||||
}
|
||||
|
||||
std::string
|
||||
Transition::label() const
|
||||
{
|
||||
return transition_handle_->label;
|
||||
}
|
||||
|
||||
State
|
||||
Transition::start_state() const
|
||||
{
|
||||
return State(
|
||||
transition_handle_->start->id,
|
||||
transition_handle_->start->label);
|
||||
}
|
||||
|
||||
State
|
||||
Transition::goal_state() const
|
||||
{
|
||||
return State(
|
||||
transition_handle_->goal->id,
|
||||
transition_handle_->goal->label);
|
||||
}
|
||||
|
||||
} // namespace rclcpp_lifecycle
|
||||
102
rclcpp_lifecycle/test/test_callback_exceptions.cpp
Normal file
102
rclcpp_lifecycle/test/test_callback_exceptions.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
// Copyright 2015 Open Source Robotics Foundation, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "lifecycle_msgs/msg/state.hpp"
|
||||
#include "lifecycle_msgs/msg/transition.hpp"
|
||||
|
||||
#include "rclcpp/rclcpp.hpp"
|
||||
#include "rclcpp_lifecycle/lifecycle_node.hpp"
|
||||
|
||||
using lifecycle_msgs::msg::State;
|
||||
using lifecycle_msgs::msg::Transition;
|
||||
|
||||
class TestCallbackExceptions : public ::testing::Test
|
||||
{
|
||||
protected:
|
||||
static void SetUpTestCase()
|
||||
{
|
||||
rclcpp::init(0, nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
class PositiveCallbackExceptionNode : public rclcpp_lifecycle::LifecycleNode
|
||||
{
|
||||
public:
|
||||
explicit PositiveCallbackExceptionNode(std::string node_name)
|
||||
: rclcpp_lifecycle::LifecycleNode(std::move(node_name))
|
||||
{}
|
||||
|
||||
size_t number_of_callbacks = 0;
|
||||
|
||||
protected:
|
||||
rcl_lifecycle_ret_t on_configure(const rclcpp_lifecycle::State &)
|
||||
{
|
||||
++number_of_callbacks;
|
||||
throw std::runtime_error("custom exception raised in configure callback");
|
||||
}
|
||||
|
||||
rcl_lifecycle_ret_t on_error(const rclcpp_lifecycle::State &)
|
||||
{
|
||||
++number_of_callbacks;
|
||||
return RCL_LIFECYCLE_RET_OK;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(TestCallbackExceptions, positive_on_error) {
|
||||
auto test_node = std::make_shared<PositiveCallbackExceptionNode>("testnode");
|
||||
|
||||
EXPECT_EQ(State::PRIMARY_STATE_UNCONFIGURED, test_node->get_current_state().id());
|
||||
EXPECT_EQ(State::PRIMARY_STATE_UNCONFIGURED, test_node->trigger_transition(
|
||||
rclcpp_lifecycle::Transition(Transition::TRANSITION_CONFIGURE)).id());
|
||||
// check if all callbacks were successfully overwritten
|
||||
EXPECT_EQ(static_cast<size_t>(2), test_node->number_of_callbacks);
|
||||
}
|
||||
|
||||
class NegativeCallbackExceptionNode : public rclcpp_lifecycle::LifecycleNode
|
||||
{
|
||||
public:
|
||||
explicit NegativeCallbackExceptionNode(std::string node_name)
|
||||
: rclcpp_lifecycle::LifecycleNode(std::move(node_name))
|
||||
{}
|
||||
|
||||
size_t number_of_callbacks = 0;
|
||||
|
||||
protected:
|
||||
rcl_lifecycle_ret_t on_configure(const rclcpp_lifecycle::State &)
|
||||
{
|
||||
++number_of_callbacks;
|
||||
throw std::runtime_error("custom exception raised in configure callback");
|
||||
}
|
||||
|
||||
rcl_lifecycle_ret_t on_error(const rclcpp_lifecycle::State &)
|
||||
{
|
||||
++number_of_callbacks;
|
||||
return RCL_LIFECYCLE_RET_FAILURE;
|
||||
}
|
||||
};
|
||||
TEST_F(TestCallbackExceptions, negative_on_error) {
|
||||
auto test_node = std::make_shared<NegativeCallbackExceptionNode>("testnode");
|
||||
|
||||
EXPECT_EQ(State::PRIMARY_STATE_UNCONFIGURED, test_node->get_current_state().id());
|
||||
EXPECT_EQ(State::PRIMARY_STATE_FINALIZED, test_node->trigger_transition(
|
||||
rclcpp_lifecycle::Transition(Transition::TRANSITION_CONFIGURE)).id());
|
||||
// check if all callbacks were successfully overwritten
|
||||
EXPECT_EQ(static_cast<size_t>(2), test_node->number_of_callbacks);
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user