Compare commits

..

2 Commits

Author SHA1 Message Date
Michel Hidalgo
d2db11b74e Do not BinPackParameters.
Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
2019-09-06 21:34:27 -03:00
Michel Hidalgo
4bb5e2ee54 Apply default GSG-based ROS2 format.
Signed-off-by: Michel Hidalgo <michel@ekumenlabs.com>
2019-09-06 21:27:34 -03:00
321 changed files with 9899 additions and 22780 deletions

View File

@@ -1,17 +0,0 @@
# rclcpp
This repository contains the source code for the ROS Client Library for C++ package, included with a standard install of any ROS 2 distro.
rclcpp provides the standard C++ API for interacting with ROS 2.
## Usage
`#include "rclcpp/rclcpp.hpp"` allows use of the most common elements of the ROS 2 system.
Visit the [rclcpp API documentation](http://docs.ros2.org/eloquent/api/rclcpp/) for a complete list of its main components.
### Examples
The ROS 2 tutorials [Writing a simple publisher and subscriber](https://index.ros.org/doc/ros2/Tutorials/Writing-A-Simple-Cpp-Publisher-And-Subscriber/)
and [Writing a simple service and client](https://index.ros.org/doc/ros2/Tutorials/Writing-A-Simple-Cpp-Service-And-Client/)
contain some examples of rclcpp APIs in use.

View File

@@ -2,75 +2,6 @@
Changelog for package rclcpp
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
0.8.3 (2019-11-19)
------------------
0.8.2 (2019-11-18)
------------------
* Updated tracing logic to match changes in rclcpp's intra-process system (`#918 <https://github.com/ros2/rclcpp/issues/918>`_)
* Fixed a bug that prevented the ``shutdown_on_sigint`` option to not work correctly (`#850 <https://github.com/ros2/rclcpp/issues/850>`_)
* Added support for STREAM logging macros (`#926 <https://github.com/ros2/rclcpp/issues/926>`_)
* Relaxed multithreaded test constraint (`#907 <https://github.com/ros2/rclcpp/issues/907>`_)
* Contributors: Anas Abou Allaban, Christophe Bedard, Dirk Thomas, alexfneves
0.8.1 (2019-10-23)
------------------
* De-flake tests for rmw_connext (`#899 <https://github.com/ros2/rclcpp/issues/899>`_)
* rename return functions for loaned messages (`#896 <https://github.com/ros2/rclcpp/issues/896>`_)
* Enable throttling logs (`#879 <https://github.com/ros2/rclcpp/issues/879>`_)
* New Intra-Process Communication (`#778 <https://github.com/ros2/rclcpp/issues/778>`_)
* Instrumentation update (`#789 <https://github.com/ros2/rclcpp/issues/789>`_)
* Zero copy api (`#864 <https://github.com/ros2/rclcpp/issues/864>`_)
* Drop rclcpp remove_ros_arguments_null test case. (`#894 <https://github.com/ros2/rclcpp/issues/894>`_)
* add mechanism to pass rmw impl specific payloads during pub/sub creation (`#882 <https://github.com/ros2/rclcpp/issues/882>`_)
* make get_actual_qos return a rclcpp::QoS (`#883 <https://github.com/ros2/rclcpp/issues/883>`_)
* Fix Compiler Warning (`#881 <https://github.com/ros2/rclcpp/issues/881>`_)
* Add callback handler for use_sim_time parameter `#802 <https://github.com/ros2/rclcpp/issues/802>`_ (`#875 <https://github.com/ros2/rclcpp/issues/875>`_)
* Contributors: Alberto Soragna, Brian Marchi, Hunter L. Allen, Ingo Lütkebohle, Karsten Knese, Michael Carroll, Michel Hidalgo, William Woodall
0.8.0 (2019-09-26)
------------------
* clean up publisher and subscription creation logic (`#867 <https://github.com/ros2/rclcpp/issues/867>`_)
* Take parameter overrides provided through the CLI. (`#865 <https://github.com/ros2/rclcpp/issues/865>`_)
* add more context to exception message (`#858 <https://github.com/ros2/rclcpp/issues/858>`_)
* remove features and related code which were deprecated in dashing (`#852 <https://github.com/ros2/rclcpp/issues/852>`_)
* check valid timer handler 1st to reduce the time window for scan. (`#841 <https://github.com/ros2/rclcpp/issues/841>`_)
* Add throwing parameter name if parameter is not set (`#833 <https://github.com/ros2/rclcpp/issues/833>`_)
* Fix typo in deprecated warning. (`#848 <https://github.com/ros2/rclcpp/issues/848>`_)
* Fail on invalid and unknown ROS specific arguments (`#842 <https://github.com/ros2/rclcpp/issues/842>`_)
* Force explicit --ros-args in NodeOptions::arguments(). (`#845 <https://github.com/ros2/rclcpp/issues/845>`_)
* Use of -r/--remap flags where appropriate. (`#834 <https://github.com/ros2/rclcpp/issues/834>`_)
* Fix hang with timers in MultiThreadedExecutor (`#835 <https://github.com/ros2/rclcpp/issues/835>`_) (`#836 <https://github.com/ros2/rclcpp/issues/836>`_)
* add mutex in add/remove_node and wait_for_work to protect concurrent use/change of memory_strategy\_ (`#837 <https://github.com/ros2/rclcpp/issues/837>`_)
* Crash in callback group pointer vector iterator (`#814 <https://github.com/ros2/rclcpp/issues/814>`_)
* Wrap documentation examples in code blocks (`#830 <https://github.com/ros2/rclcpp/issues/830>`_)
* add callback group as member variable and constructor arg (`#811 <https://github.com/ros2/rclcpp/issues/811>`_)
* Fix get_node_interfaces functions taking a pointer (`#821 <https://github.com/ros2/rclcpp/issues/821>`_)
* Delete unnecessary call for get_node_by_group (`#823 <https://github.com/ros2/rclcpp/issues/823>`_)
* Allow passing logger by const ref (`#820 <https://github.com/ros2/rclcpp/issues/820>`_)
* Explain return value of spin_until_future_complete (`#792 <https://github.com/ros2/rclcpp/issues/792>`_)
* Adapt to '--ros-args ... [--]'-based ROS args extraction (`#816 <https://github.com/ros2/rclcpp/issues/816>`_)
* Add line break after first open paren in multiline function call (`#785 <https://github.com/ros2/rclcpp/issues/785>`_)
* remove mock msgs from rclcpp (`#800 <https://github.com/ros2/rclcpp/issues/800>`_)
* Make TimeSource ignore use_sim_time events coming from other nodes. (`#799 <https://github.com/ros2/rclcpp/issues/799>`_)
* Allow registering multiple on_parameters_set_callback (`#772 <https://github.com/ros2/rclcpp/issues/772>`_)
* Add free function for creating service clients (`#788 <https://github.com/ros2/rclcpp/issues/788>`_)
* Include missing rcl headers in use. (`#782 <https://github.com/ros2/rclcpp/issues/782>`_)
* Switch the NodeParameters lock to recursive. (`#781 <https://github.com/ros2/rclcpp/issues/781>`_)
* changed on_parameter_event qos profile to rmw_qos_profile_parameter_events (`#774 <https://github.com/ros2/rclcpp/issues/774>`_)
* Adding a factory method to create a Duration from seconds (`#567 <https://github.com/ros2/rclcpp/issues/567>`_)
* Fix a comparison with a sign mismatch (`#771 <https://github.com/ros2/rclcpp/issues/771>`_)
* delete superfluous spaces (`#770 <https://github.com/ros2/rclcpp/issues/770>`_)
* Use params from node '/\*\*' from parameter YAML file (`#762 <https://github.com/ros2/rclcpp/issues/762>`_)
* Add ignore override argument to declare parameter (`#767 <https://github.com/ros2/rclcpp/issues/767>`_)
* use default parameter descriptor in parameters interface (`#765 <https://github.com/ros2/rclcpp/issues/765>`_)
* Added support for const member functions (`#763 <https://github.com/ros2/rclcpp/issues/763>`_)
* add get_actual_qos() feature to subscriptions (`#754 <https://github.com/ros2/rclcpp/issues/754>`_)
* Ignore parameters overrides in set parameter methods when allowing undeclared parameters (`#756 <https://github.com/ros2/rclcpp/issues/756>`_)
* Add rclcpp::create_timer() (`#757 <https://github.com/ros2/rclcpp/issues/757>`_)
* checking origin of intra-process msg before taking them (`#753 <https://github.com/ros2/rclcpp/issues/753>`_)
* Contributors: Alberto Soragna, Carl Delsey, Chris Lalancette, Dan Rose, Dirk Thomas, Esteve Fernandez, Guillaume Autran, Jacob Perron, Karsten Knese, Luca Della Vedova, M. M, Michel Hidalgo, Scott K Logan, Shane Loretz, Todd Malsbary, William Woodall, bpwilcox, fujitatomoya, ivanpauno
0.7.5 (2019-05-30)
------------------
* Avoid 'Intra process message no longer being stored when trying to handle it' warning (`#749 <https://github.com/ros2/rclcpp/issues/749>`_)

View File

@@ -4,19 +4,16 @@ project(rclcpp)
find_package(ament_cmake_ros REQUIRED)
find_package(builtin_interfaces REQUIRED)
find_package(libstatistics_collector REQUIRED)
find_package(rcl REQUIRED)
find_package(rcl_interfaces REQUIRED)
find_package(rcl_yaml_param_parser REQUIRED)
find_package(rcpputils REQUIRED)
find_package(rcutils REQUIRED)
find_package(rmw REQUIRED)
find_package(rmw_implementation REQUIRED)
find_package(rosgraph_msgs REQUIRED)
find_package(rosidl_runtime_cpp REQUIRED)
find_package(rosidl_generator_cpp REQUIRED)
find_package(rosidl_typesupport_c REQUIRED)
find_package(rosidl_typesupport_cpp REQUIRED)
find_package(statistics_msgs REQUIRED)
find_package(tracetools REQUIRED)
# Default to C++14
if(NOT CMAKE_CXX_STANDARD)
@@ -35,30 +32,21 @@ set(${PROJECT_NAME}_SRCS
src/rclcpp/clock.cpp
src/rclcpp/context.cpp
src/rclcpp/contexts/default_context.cpp
src/rclcpp/detail/rmw_implementation_specific_payload.cpp
src/rclcpp/detail/rmw_implementation_specific_publisher_payload.cpp
src/rclcpp/detail/rmw_implementation_specific_subscription_payload.cpp
src/rclcpp/detail/utilities.cpp
src/rclcpp/duration.cpp
src/rclcpp/event.cpp
src/rclcpp/exceptions/exceptions.cpp
src/rclcpp/executable_list.cpp
src/rclcpp/exceptions.cpp
src/rclcpp/executor.cpp
src/rclcpp/executors.cpp
src/rclcpp/expand_topic_or_service_name.cpp
src/rclcpp/executors/multi_threaded_executor.cpp
src/rclcpp/executors/single_threaded_executor.cpp
src/rclcpp/executors/static_executor_entities_collector.cpp
src/rclcpp/executors/static_single_threaded_executor.cpp
src/rclcpp/future_return_code.cpp
src/rclcpp/graph_listener.cpp
src/rclcpp/guard_condition.cpp
src/rclcpp/init_options.cpp
src/rclcpp/intra_process_manager.cpp
src/rclcpp/intra_process_manager_impl.cpp
src/rclcpp/logger.cpp
src/rclcpp/memory_strategies.cpp
src/rclcpp/memory_strategy.cpp
src/rclcpp/message_info.cpp
src/rclcpp/node.cpp
src/rclcpp/node_options.cpp
src/rclcpp/node_interfaces/node_base.cpp
@@ -80,18 +68,14 @@ set(${PROJECT_NAME}_SRCS
src/rclcpp/publisher_base.cpp
src/rclcpp/qos.cpp
src/rclcpp/qos_event.cpp
src/rclcpp/serialization.cpp
src/rclcpp/serialized_message.cpp
src/rclcpp/service.cpp
src/rclcpp/signal_handler.cpp
src/rclcpp/subscription_base.cpp
src/rclcpp/subscription_intra_process_base.cpp
src/rclcpp/time.cpp
src/rclcpp/time_source.cpp
src/rclcpp/timer.cpp
src/rclcpp/type_support.cpp
src/rclcpp/utilities.cpp
src/rclcpp/wait_set_policies/detail/write_preferring_read_write_lock.cpp
src/rclcpp/waitable.cpp
)
@@ -121,18 +105,13 @@ add_library(${PROJECT_NAME}
${${PROJECT_NAME}_SRCS})
# specific order: dependents before dependencies
ament_target_dependencies(${PROJECT_NAME}
"libstatistics_collector"
"rcl"
"rcl_yaml_param_parser"
"rcpputils"
"rcutils"
"builtin_interfaces"
"rosgraph_msgs"
"rosidl_typesupport_cpp"
"rosidl_runtime_cpp"
"statistics_msgs"
"tracetools"
)
"rosidl_generator_cpp")
# Causes the visibility macros to use dllexport rather than dllimport,
# which is appropriate when building the dll but not consuming it.
@@ -150,18 +129,15 @@ install(
ament_export_include_directories(include)
ament_export_libraries(${PROJECT_NAME})
ament_export_dependencies(libstatistics_collector)
ament_export_dependencies(ament_cmake)
ament_export_dependencies(rcl)
ament_export_dependencies(rcpputils)
ament_export_dependencies(rcutils)
ament_export_dependencies(builtin_interfaces)
ament_export_dependencies(rosgraph_msgs)
ament_export_dependencies(rosidl_typesupport_cpp)
ament_export_dependencies(rosidl_typesupport_c)
ament_export_dependencies(rosidl_runtime_cpp)
ament_export_dependencies(rosidl_generator_cpp)
ament_export_dependencies(rcl_yaml_param_parser)
ament_export_dependencies(statistics_msgs)
ament_export_dependencies(tracetools)
if(BUILD_TESTING)
find_package(ament_cmake_gtest REQUIRED)
@@ -174,14 +150,12 @@ if(BUILD_TESTING)
include(cmake/rclcpp_add_build_failure_test.cmake)
add_definitions(-DTEST_RESOURCES_DIRECTORY="${CMAKE_CURRENT_BINARY_DIR}/test/resources")
ament_add_gtest(test_client test/test_client.cpp)
if(TARGET test_client)
ament_target_dependencies(test_client
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_generator_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_client ${PROJECT_NAME})
@@ -192,7 +166,7 @@ if(BUILD_TESTING)
"rcl_interfaces"
"rmw"
"rcl"
"rosidl_runtime_cpp"
"rosidl_generator_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_create_timer ${PROJECT_NAME})
@@ -203,7 +177,7 @@ if(BUILD_TESTING)
ament_target_dependencies(test_expand_topic_or_service_name
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_generator_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_expand_topic_or_service_name ${PROJECT_NAME})
@@ -213,57 +187,37 @@ if(BUILD_TESTING)
ament_target_dependencies(test_function_traits
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_generator_cpp"
"rosidl_typesupport_cpp"
)
endif()
ament_add_gmock(test_intra_process_manager test/test_intra_process_manager.cpp)
ament_add_gtest(test_mapped_ring_buffer test/test_mapped_ring_buffer.cpp)
if(TARGET test_mapped_ring_buffer)
ament_target_dependencies(test_mapped_ring_buffer
"rcl"
"rcl_interfaces"
"rmw"
"rosidl_generator_cpp"
"rosidl_typesupport_cpp"
)
endif()
ament_add_gtest(test_intra_process_manager test/test_intra_process_manager.cpp)
if(TARGET test_intra_process_manager)
ament_target_dependencies(test_intra_process_manager
"rcl"
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_generator_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_intra_process_manager ${PROJECT_NAME})
endif()
ament_add_gtest(test_ring_buffer_implementation test/test_ring_buffer_implementation.cpp)
if(TARGET test_ring_buffer_implementation)
ament_target_dependencies(test_ring_buffer_implementation
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_ring_buffer_implementation ${PROJECT_NAME})
endif()
ament_add_gtest(test_intra_process_buffer test/test_intra_process_buffer.cpp)
if(TARGET test_intra_process_buffer)
ament_target_dependencies(test_intra_process_buffer
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_intra_process_buffer ${PROJECT_NAME})
endif()
ament_add_gtest(test_loaned_message test/test_loaned_message.cpp)
ament_target_dependencies(test_loaned_message
"test_msgs"
)
target_link_libraries(test_loaned_message ${PROJECT_NAME})
ament_add_gtest(test_node test/test_node.cpp TIMEOUT 240)
ament_add_gtest(test_node test/test_node.cpp)
if(TARGET test_node)
ament_target_dependencies(test_node
"rcl_interfaces"
"rcpputils"
"rmw"
"rosidl_runtime_cpp"
"rosidl_generator_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_node ${PROJECT_NAME})
endif()
@@ -300,7 +254,7 @@ if(BUILD_TESTING)
ament_target_dependencies(test_node_global_args
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_generator_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_node_global_args ${PROJECT_NAME})
@@ -322,7 +276,7 @@ if(BUILD_TESTING)
ament_target_dependencies(test_parameter_events_filter
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_generator_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_parameter_events_filter ${PROJECT_NAME})
@@ -332,7 +286,7 @@ if(BUILD_TESTING)
ament_target_dependencies(test_parameter
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_generator_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_parameter ${PROJECT_NAME})
@@ -344,10 +298,10 @@ if(BUILD_TESTING)
ament_add_gtest(test_publisher test/test_publisher.cpp)
if(TARGET test_publisher)
ament_target_dependencies(test_publisher
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_generator_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_publisher ${PROJECT_NAME})
endif()
@@ -356,37 +310,17 @@ if(BUILD_TESTING)
ament_target_dependencies(test_publisher_subscription_count_api
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_generator_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_publisher_subscription_count_api ${PROJECT_NAME})
endif()
ament_add_gtest(test_qos test/test_qos.cpp)
if(TARGET test_qos)
ament_target_dependencies(test_qos
"rmw"
)
target_link_libraries(test_qos
${PROJECT_NAME}
)
endif()
ament_add_gtest(test_qos_event test/test_qos_event.cpp)
if(TARGET test_qos_event)
ament_target_dependencies(test_qos_event
"rmw"
"test_msgs"
)
target_link_libraries(test_qos_event
${PROJECT_NAME}
)
endif()
ament_add_gtest(test_rate test/test_rate.cpp)
if(TARGET test_rate)
ament_target_dependencies(test_rate
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_generator_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_rate
@@ -402,21 +336,12 @@ if(BUILD_TESTING)
${PROJECT_NAME}
)
endif()
ament_add_gtest(test_serialized_message test/test_serialized_message.cpp)
if(TARGET test_serialized_message)
ament_target_dependencies(test_serialized_message
test_msgs
)
target_link_libraries(test_serialized_message
${PROJECT_NAME}
)
endif()
ament_add_gtest(test_service test/test_service.cpp)
if(TARGET test_service)
ament_target_dependencies(test_service
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_generator_cpp"
"rosidl_typesupport_cpp"
)
target_link_libraries(test_service ${PROJECT_NAME})
@@ -426,9 +351,8 @@ if(BUILD_TESTING)
ament_target_dependencies(test_subscription
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_generator_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_subscription ${PROJECT_NAME})
endif()
@@ -437,9 +361,8 @@ if(BUILD_TESTING)
ament_target_dependencies(test_subscription_publisher_count_api
"rcl_interfaces"
"rmw"
"rosidl_runtime_cpp"
"rosidl_generator_cpp"
"rosidl_typesupport_cpp"
"test_msgs"
)
target_link_libraries(test_subscription_publisher_count_api ${PROJECT_NAME})
endif()
@@ -449,7 +372,6 @@ if(BUILD_TESTING)
"rcl"
"test_msgs"
)
target_link_libraries(test_subscription_traits ${PROJECT_NAME})
endif()
ament_add_gtest(test_find_weak_nodes test/test_find_weak_nodes.cpp)
if(TARGET test_find_weak_nodes)
@@ -541,43 +463,16 @@ if(BUILD_TESTING)
target_link_libraries(test_multi_threaded_executor ${PROJECT_NAME})
endif()
ament_add_gtest(test_guard_condition test/test_guard_condition.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_guard_condition)
target_link_libraries(test_guard_condition ${PROJECT_NAME})
endif()
ament_add_gtest(test_wait_set test/test_wait_set.cpp
APPEND_LIBRARY_DIRS "${append_library_dirs}")
if(TARGET test_wait_set)
ament_target_dependencies(test_wait_set "test_msgs")
target_link_libraries(test_wait_set ${PROJECT_NAME})
endif()
ament_add_gtest(test_subscription_topic_statistics test/topic_statistics/test_subscription_topic_statistics.cpp)
if(TARGET test_subscription_topic_statistics)
ament_target_dependencies(test_subscription_topic_statistics
"libstatistics_collector"
ament_add_gtest(test_local_parameters test/test_local_parameters.cpp)
if(TARGET test_local_parameters)
ament_target_dependencies(test_local_parameters
"rcl_interfaces"
"rcutils"
"rmw"
"rosidl_runtime_cpp"
"rosidl_generator_cpp"
"rosidl_typesupport_cpp"
"statistics_msgs"
"test_msgs")
target_link_libraries(test_subscription_topic_statistics ${PROJECT_NAME})
)
target_link_libraries(test_local_parameters ${PROJECT_NAME})
endif()
ament_add_gtest(test_subscription_options test/test_subscription_options.cpp)
if(TARGET test_subscription_options)
ament_target_dependencies(test_subscription_options "rcl")
target_link_libraries(test_subscription_options ${PROJECT_NAME})
endif()
# Install test resources
install(
DIRECTORY test/resources
DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/test)
endif()
ament_package()

View File

@@ -25,11 +25,10 @@ namespace rclcpp
{
namespace allocator
{
template<typename T, typename Alloc>
template <typename T, typename Alloc>
using AllocRebind = typename std::allocator_traits<Alloc>::template rebind_traits<T>;
template<typename Alloc>
template <typename Alloc>
void * retyped_allocate(size_t size, void * untyped_allocator)
{
auto typed_allocator = static_cast<Alloc *>(untyped_allocator);
@@ -39,7 +38,7 @@ void * retyped_allocate(size_t size, void * untyped_allocator)
return std::allocator_traits<Alloc>::allocate(*typed_allocator, size);
}
template<typename T, typename Alloc>
template <typename T, typename Alloc>
void retyped_deallocate(void * untyped_pointer, void * untyped_allocator)
{
auto typed_allocator = static_cast<Alloc *>(untyped_allocator);
@@ -50,7 +49,7 @@ void retyped_deallocate(void * untyped_pointer, void * untyped_allocator)
std::allocator_traits<Alloc>::deallocate(*typed_allocator, typed_ptr, 1);
}
template<typename T, typename Alloc>
template <typename T, typename Alloc>
void * retyped_reallocate(void * untyped_pointer, size_t size, void * untyped_allocator)
{
auto typed_allocator = static_cast<Alloc *>(untyped_allocator);
@@ -62,9 +61,8 @@ void * retyped_reallocate(void * untyped_pointer, size_t size, void * untyped_al
return std::allocator_traits<Alloc>::allocate(*typed_allocator, size);
}
// Convert a std::allocator_traits-formatted Allocator into an rcl allocator
template<
template <
typename T,
typename Alloc,
typename std::enable_if<!std::is_same<Alloc, std::allocator<void>>::value>::type * = nullptr>
@@ -83,7 +81,7 @@ rcl_allocator_t get_rcl_allocator(Alloc & allocator)
}
// TODO(jacquelinekay) Workaround for an incomplete implementation of std::allocator<void>
template<
template <
typename T,
typename Alloc,
typename std::enable_if<std::is_same<Alloc, std::allocator<void>>::value>::type * = nullptr>

View File

@@ -22,31 +22,24 @@ namespace rclcpp
{
namespace allocator
{
template<typename Allocator>
template <typename Allocator>
class AllocatorDeleter
{
template<typename T>
template <typename T>
using AllocRebind = typename std::allocator_traits<Allocator>::template rebind_alloc<T>;
public:
AllocatorDeleter()
: allocator_(nullptr)
{
}
AllocatorDeleter() : allocator_(nullptr) {}
explicit AllocatorDeleter(Allocator * a)
: allocator_(a)
{
}
explicit AllocatorDeleter(Allocator * a) : allocator_(a) {}
template<typename T>
template <typename T>
AllocatorDeleter(const AllocatorDeleter<T> & a)
{
allocator_ = a.get_allocator();
}
template<typename T>
template <typename T>
void operator()(T * ptr)
{
std::allocator_traits<AllocRebind<T>>::destroy(*allocator_, ptr);
@@ -54,36 +47,30 @@ public:
ptr = nullptr;
}
Allocator * get_allocator() const
{
return allocator_;
}
Allocator * get_allocator() const { return allocator_; }
void set_allocator(Allocator * alloc)
{
allocator_ = alloc;
}
void set_allocator(Allocator * alloc) { allocator_ = alloc; }
private:
Allocator * allocator_;
};
template<typename Alloc, typename T, typename D>
template <typename Alloc, typename T, typename D>
void set_allocator_for_deleter(D * deleter, Alloc * alloc)
{
(void) alloc;
(void) deleter;
(void)alloc;
(void)deleter;
throw std::runtime_error("Reached unexpected template specialization");
}
template<typename T, typename U>
template <typename T, typename U>
void set_allocator_for_deleter(std::default_delete<T> * deleter, std::allocator<U> * alloc)
{
(void) deleter;
(void) alloc;
(void)deleter;
(void)alloc;
}
template<typename Alloc, typename T>
template <typename Alloc, typename T>
void set_allocator_for_deleter(AllocatorDeleter<T> * deleter, Alloc * alloc)
{
if (!deleter || !alloc) {
@@ -92,13 +79,13 @@ void set_allocator_for_deleter(AllocatorDeleter<T> * deleter, Alloc * alloc)
deleter->set_allocator(alloc);
}
template<typename Alloc, typename T>
template <typename Alloc, typename T>
using Deleter = typename std::conditional<
std::is_same<typename std::allocator_traits<Alloc>::template rebind_alloc<T>,
typename std::allocator<void>::template rebind<T>::other>::value,
std::is_same<
typename std::allocator_traits<Alloc>::template rebind_alloc<T>,
typename std::allocator<void>::template rebind<T>::other>::value,
std::default_delete<T>,
AllocatorDeleter<Alloc>
>::type;
AllocatorDeleter<Alloc>>::type;
} // namespace allocator
} // namespace rclcpp

View File

@@ -29,7 +29,8 @@
namespace rclcpp
{
namespace executor
{
struct AnyExecutable
{
RCLCPP_PUBLIC
@@ -40,20 +41,16 @@ struct AnyExecutable
// Only one of the following pointers will be set.
rclcpp::SubscriptionBase::SharedPtr subscription;
rclcpp::SubscriptionBase::SharedPtr subscription_intra_process;
rclcpp::TimerBase::SharedPtr timer;
rclcpp::ServiceBase::SharedPtr service;
rclcpp::ClientBase::SharedPtr client;
rclcpp::Waitable::SharedPtr waitable;
// These are used to keep the scope on the containing items
rclcpp::CallbackGroup::SharedPtr callback_group;
rclcpp::callback_group::CallbackGroup::SharedPtr callback_group;
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base;
};
namespace executor
{
using AnyExecutable [[deprecated("use rclcpp::AnyExecutable instead")]] = AnyExecutable;
} // namespace executor
} // namespace rclcpp

View File

@@ -23,27 +23,20 @@
#include "rclcpp/function_traits.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rmw/types.h"
#include "tracetools/tracetools.h"
#include "tracetools/utils.hpp"
namespace rclcpp
{
template<typename ServiceT>
template <typename ServiceT>
class AnyServiceCallback
{
private:
using SharedPtrCallback = std::function<
void (
const std::shared_ptr<typename ServiceT::Request>,
std::shared_ptr<typename ServiceT::Response>
)>;
using SharedPtrWithRequestHeaderCallback = std::function<
void (
const std::shared_ptr<rmw_request_id_t>,
const std::shared_ptr<typename ServiceT::Request>,
std::shared_ptr<typename ServiceT::Response>
)>;
using SharedPtrCallback = std::function<void(
const std::shared_ptr<typename ServiceT::Request>,
std::shared_ptr<typename ServiceT::Response>)>;
using SharedPtrWithRequestHeaderCallback = std::function<void(
const std::shared_ptr<rmw_request_id_t>,
const std::shared_ptr<typename ServiceT::Request>,
std::shared_ptr<typename ServiceT::Response>)>;
SharedPtrCallback shared_ptr_callback_;
SharedPtrWithRequestHeaderCallback shared_ptr_with_request_header_callback_;
@@ -51,33 +44,26 @@ private:
public:
AnyServiceCallback()
: shared_ptr_callback_(nullptr), shared_ptr_with_request_header_callback_(nullptr)
{}
{
}
AnyServiceCallback(const AnyServiceCallback &) = default;
template<
template <
typename CallbackT,
typename std::enable_if<
rclcpp::function_traits::same_arguments<
CallbackT,
SharedPtrCallback
>::value
>::type * = nullptr
>
rclcpp::function_traits::same_arguments<CallbackT, SharedPtrCallback>::value>::type * =
nullptr>
void set(CallbackT callback)
{
shared_ptr_callback_ = callback;
}
template<
template <
typename CallbackT,
typename std::enable_if<
rclcpp::function_traits::same_arguments<
CallbackT,
SharedPtrWithRequestHeaderCallback
>::value
>::type * = nullptr
>
typename std::enable_if<rclcpp::function_traits::same_arguments<
CallbackT,
SharedPtrWithRequestHeaderCallback>::value>::type * = nullptr>
void set(CallbackT callback)
{
shared_ptr_with_request_header_callback_ = callback;
@@ -88,7 +74,6 @@ public:
std::shared_ptr<typename ServiceT::Request> request,
std::shared_ptr<typename ServiceT::Response> response)
{
TRACEPOINT(callback_start, (const void *)this, false);
if (shared_ptr_callback_ != nullptr) {
(void)request_header;
shared_ptr_callback_(request, response);
@@ -97,24 +82,6 @@ public:
} else {
throw std::runtime_error("unexpected request without any callback set");
}
TRACEPOINT(callback_end, (const void *)this);
}
void register_callback_for_tracing()
{
#ifndef TRACETOOLS_DISABLED
if (shared_ptr_callback_) {
TRACEPOINT(
rclcpp_callback_register,
(const void *)this,
get_symbol(shared_ptr_callback_));
} else if (shared_ptr_with_request_header_callback_) {
TRACEPOINT(
rclcpp_callback_register,
(const void *)this,
get_symbol(shared_ptr_with_request_header_callback_));
}
#endif // TRACETOOLS_DISABLED
}
};

View File

@@ -25,15 +25,11 @@
#include "rclcpp/allocator/allocator_common.hpp"
#include "rclcpp/function_traits.hpp"
#include "rclcpp/message_info.hpp"
#include "rclcpp/visibility_control.hpp"
#include "tracetools/tracetools.h"
#include "tracetools/utils.hpp"
namespace rclcpp
{
template<typename MessageT, typename Alloc>
template <typename MessageT, typename Alloc>
class AnySubscriptionCallback
{
using MessageAllocTraits = allocator::AllocRebind<MessageT, Alloc>;
@@ -42,15 +38,15 @@ class AnySubscriptionCallback
using ConstMessageSharedPtr = std::shared_ptr<const MessageT>;
using MessageUniquePtr = std::unique_ptr<MessageT, MessageDeleter>;
using SharedPtrCallback = std::function<void (const std::shared_ptr<MessageT>)>;
using SharedPtrCallback = std::function<void(const std::shared_ptr<MessageT>)>;
using SharedPtrWithInfoCallback =
std::function<void (const std::shared_ptr<MessageT>, const rclcpp::MessageInfo &)>;
using ConstSharedPtrCallback = std::function<void (const std::shared_ptr<const MessageT>)>;
std::function<void(const std::shared_ptr<MessageT>, const rmw_message_info_t &)>;
using ConstSharedPtrCallback = std::function<void(const std::shared_ptr<const MessageT>)>;
using ConstSharedPtrWithInfoCallback =
std::function<void (const std::shared_ptr<const MessageT>, const rclcpp::MessageInfo &)>;
using UniquePtrCallback = std::function<void (MessageUniquePtr)>;
std::function<void(const std::shared_ptr<const MessageT>, const rmw_message_info_t &)>;
using UniquePtrCallback = std::function<void(MessageUniquePtr)>;
using UniquePtrWithInfoCallback =
std::function<void (MessageUniquePtr, const rclcpp::MessageInfo &)>;
std::function<void(MessageUniquePtr, const rmw_message_info_t &)>;
SharedPtrCallback shared_ptr_callback_;
SharedPtrWithInfoCallback shared_ptr_with_info_callback_;
@@ -61,9 +57,12 @@ class AnySubscriptionCallback
public:
explicit AnySubscriptionCallback(std::shared_ptr<Alloc> allocator)
: shared_ptr_callback_(nullptr), shared_ptr_with_info_callback_(nullptr),
const_shared_ptr_callback_(nullptr), const_shared_ptr_with_info_callback_(nullptr),
unique_ptr_callback_(nullptr), unique_ptr_with_info_callback_(nullptr)
: shared_ptr_callback_(nullptr),
shared_ptr_with_info_callback_(nullptr),
const_shared_ptr_callback_(nullptr),
const_shared_ptr_with_info_callback_(nullptr),
unique_ptr_callback_(nullptr),
unique_ptr_with_info_callback_(nullptr)
{
message_allocator_ = std::make_shared<MessageAlloc>(*allocator.get());
allocator::set_allocator_for_deleter(&message_deleter_, message_allocator_.get());
@@ -71,94 +70,68 @@ public:
AnySubscriptionCallback(const AnySubscriptionCallback &) = default;
template<
template <
typename CallbackT,
typename std::enable_if<
rclcpp::function_traits::same_arguments<
CallbackT,
SharedPtrCallback
>::value
>::type * = nullptr
>
rclcpp::function_traits::same_arguments<CallbackT, SharedPtrCallback>::value>::type * =
nullptr>
void set(CallbackT callback)
{
shared_ptr_callback_ = callback;
}
template<
template <
typename CallbackT,
typename std::enable_if<
rclcpp::function_traits::same_arguments<
CallbackT,
SharedPtrWithInfoCallback
>::value
>::type * = nullptr
>
rclcpp::function_traits::same_arguments<CallbackT, SharedPtrWithInfoCallback>::value>::
type * = nullptr>
void set(CallbackT callback)
{
shared_ptr_with_info_callback_ = callback;
}
template<
template <
typename CallbackT,
typename std::enable_if<
rclcpp::function_traits::same_arguments<
CallbackT,
ConstSharedPtrCallback
>::value
>::type * = nullptr
>
rclcpp::function_traits::same_arguments<CallbackT, ConstSharedPtrCallback>::value>::type * =
nullptr>
void set(CallbackT callback)
{
const_shared_ptr_callback_ = callback;
}
template<
template <
typename CallbackT,
typename std::enable_if<
rclcpp::function_traits::same_arguments<
CallbackT,
ConstSharedPtrWithInfoCallback
>::value
>::type * = nullptr
>
rclcpp::function_traits::same_arguments<CallbackT, ConstSharedPtrWithInfoCallback>::value>::
type * = nullptr>
void set(CallbackT callback)
{
const_shared_ptr_with_info_callback_ = callback;
}
template<
template <
typename CallbackT,
typename std::enable_if<
rclcpp::function_traits::same_arguments<
CallbackT,
UniquePtrCallback
>::value
>::type * = nullptr
>
rclcpp::function_traits::same_arguments<CallbackT, UniquePtrCallback>::value>::type * =
nullptr>
void set(CallbackT callback)
{
unique_ptr_callback_ = callback;
}
template<
template <
typename CallbackT,
typename std::enable_if<
rclcpp::function_traits::same_arguments<
CallbackT,
UniquePtrWithInfoCallback
>::value
>::type * = nullptr
>
rclcpp::function_traits::same_arguments<CallbackT, UniquePtrWithInfoCallback>::value>::
type * = nullptr>
void set(CallbackT callback)
{
unique_ptr_with_info_callback_ = callback;
}
void dispatch(
std::shared_ptr<MessageT> message, const rclcpp::MessageInfo & message_info)
void dispatch(std::shared_ptr<MessageT> message, const rmw_message_info_t & message_info)
{
TRACEPOINT(callback_start, (const void *)this, false);
if (shared_ptr_callback_) {
shared_ptr_callback_(message);
} else if (shared_ptr_with_info_callback_) {
@@ -178,36 +151,30 @@ public:
} else {
throw std::runtime_error("unexpected message without any callback set");
}
TRACEPOINT(callback_end, (const void *)this);
}
void dispatch_intra_process(
ConstMessageSharedPtr message, const rclcpp::MessageInfo & message_info)
ConstMessageSharedPtr message, const rmw_message_info_t & message_info)
{
TRACEPOINT(callback_start, (const void *)this, true);
if (const_shared_ptr_callback_) {
const_shared_ptr_callback_(message);
} else if (const_shared_ptr_with_info_callback_) {
const_shared_ptr_with_info_callback_(message, message_info);
} else {
if (
unique_ptr_callback_ || unique_ptr_with_info_callback_ ||
shared_ptr_callback_ || shared_ptr_with_info_callback_)
{
unique_ptr_callback_ || unique_ptr_with_info_callback_ || shared_ptr_callback_ ||
shared_ptr_with_info_callback_) {
throw std::runtime_error(
"unexpected dispatch_intra_process const shared "
"message call with no const shared_ptr callback");
"unexpected dispatch_intra_process const shared "
"message call with no const shared_ptr callback");
} else {
throw std::runtime_error("unexpected message without any callback set");
}
}
TRACEPOINT(callback_end, (const void *)this);
}
void dispatch_intra_process(
MessageUniquePtr message, const rclcpp::MessageInfo & message_info)
void dispatch_intra_process(MessageUniquePtr message, const rmw_message_info_t & message_info)
{
TRACEPOINT(callback_start, (const void *)this, true);
if (shared_ptr_callback_) {
typename std::shared_ptr<MessageT> shared_message = std::move(message);
shared_ptr_callback_(shared_message);
@@ -220,46 +187,18 @@ public:
unique_ptr_with_info_callback_(std::move(message), message_info);
} else if (const_shared_ptr_callback_ || const_shared_ptr_with_info_callback_) {
throw std::runtime_error(
"unexpected dispatch_intra_process unique message call"
" with const shared_ptr callback");
"unexpected dispatch_intra_process unique message call"
" with const shared_ptr callback");
} else {
throw std::runtime_error("unexpected message without any callback set");
}
TRACEPOINT(callback_end, (const void *)this);
}
bool use_take_shared_method() const
bool use_take_shared_method()
{
return const_shared_ptr_callback_ || const_shared_ptr_with_info_callback_;
}
void register_callback_for_tracing()
{
#ifndef TRACETOOLS_DISABLED
if (shared_ptr_callback_) {
TRACEPOINT(
rclcpp_callback_register,
(const void *)this,
get_symbol(shared_ptr_callback_));
} else if (shared_ptr_with_info_callback_) {
TRACEPOINT(
rclcpp_callback_register,
(const void *)this,
get_symbol(shared_ptr_with_info_callback_));
} else if (unique_ptr_callback_) {
TRACEPOINT(
rclcpp_callback_register,
(const void *)this,
get_symbol(unique_ptr_callback_));
} else if (unique_ptr_with_info_callback_) {
TRACEPOINT(
rclcpp_callback_register,
(const void *)this,
get_symbol(unique_ptr_with_info_callback_));
}
#endif // TRACETOOLS_DISABLED
}
private:
std::shared_ptr<MessageAlloc> message_allocator_;
MessageDeleter message_deleter_;

View File

@@ -21,16 +21,15 @@
#include <vector>
#include "rclcpp/client.hpp"
#include "rclcpp/publisher_base.hpp"
#include "rclcpp/publisher.hpp"
#include "rclcpp/service.hpp"
#include "rclcpp/subscription_base.hpp"
#include "rclcpp/subscription.hpp"
#include "rclcpp/timer.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rclcpp/waitable.hpp"
namespace rclcpp
{
// Forward declarations for friend statement in class CallbackGroup
namespace node_interfaces
{
@@ -40,11 +39,9 @@ class NodeTopics;
class NodeWaitables;
} // namespace node_interfaces
enum class CallbackGroupType
namespace callback_group
{
MutuallyExclusive,
Reentrant
};
enum class CallbackGroupType { MutuallyExclusive, Reentrant };
class CallbackGroup
{
@@ -59,79 +56,65 @@ public:
RCLCPP_PUBLIC
explicit CallbackGroup(CallbackGroupType group_type);
template<typename Function>
rclcpp::SubscriptionBase::SharedPtr
find_subscription_ptrs_if(Function func) const
template <typename Function>
rclcpp::SubscriptionBase::SharedPtr find_subscription_ptrs_if(Function func) const
{
return _find_ptrs_if_impl<rclcpp::SubscriptionBase, Function>(func, subscription_ptrs_);
}
template<typename Function>
rclcpp::TimerBase::SharedPtr
find_timer_ptrs_if(Function func) const
template <typename Function>
rclcpp::TimerBase::SharedPtr find_timer_ptrs_if(Function func) const
{
return _find_ptrs_if_impl<rclcpp::TimerBase, Function>(func, timer_ptrs_);
}
template<typename Function>
rclcpp::ServiceBase::SharedPtr
find_service_ptrs_if(Function func) const
template <typename Function>
rclcpp::ServiceBase::SharedPtr find_service_ptrs_if(Function func) const
{
return _find_ptrs_if_impl<rclcpp::ServiceBase, Function>(func, service_ptrs_);
}
template<typename Function>
rclcpp::ClientBase::SharedPtr
find_client_ptrs_if(Function func) const
template <typename Function>
rclcpp::ClientBase::SharedPtr find_client_ptrs_if(Function func) const
{
return _find_ptrs_if_impl<rclcpp::ClientBase, Function>(func, client_ptrs_);
}
template<typename Function>
rclcpp::Waitable::SharedPtr
find_waitable_ptrs_if(Function func) const
template <typename Function>
rclcpp::Waitable::SharedPtr find_waitable_ptrs_if(Function func) const
{
return _find_ptrs_if_impl<rclcpp::Waitable, Function>(func, waitable_ptrs_);
}
RCLCPP_PUBLIC
std::atomic_bool &
can_be_taken_from();
std::atomic_bool & can_be_taken_from();
RCLCPP_PUBLIC
const CallbackGroupType &
type() const;
const CallbackGroupType & type() const;
protected:
RCLCPP_DISABLE_COPY(CallbackGroup)
RCLCPP_PUBLIC
void
add_publisher(const rclcpp::PublisherBase::SharedPtr publisher_ptr);
void add_publisher(const rclcpp::PublisherBase::SharedPtr publisher_ptr);
RCLCPP_PUBLIC
void
add_subscription(const rclcpp::SubscriptionBase::SharedPtr subscription_ptr);
void add_subscription(const rclcpp::SubscriptionBase::SharedPtr subscription_ptr);
RCLCPP_PUBLIC
void
add_timer(const rclcpp::TimerBase::SharedPtr timer_ptr);
void add_timer(const rclcpp::TimerBase::SharedPtr timer_ptr);
RCLCPP_PUBLIC
void
add_service(const rclcpp::ServiceBase::SharedPtr service_ptr);
void add_service(const rclcpp::ServiceBase::SharedPtr service_ptr);
RCLCPP_PUBLIC
void
add_client(const rclcpp::ClientBase::SharedPtr client_ptr);
void add_client(const rclcpp::ClientBase::SharedPtr client_ptr);
RCLCPP_PUBLIC
void
add_waitable(const rclcpp::Waitable::SharedPtr waitable_ptr);
void add_waitable(const rclcpp::Waitable::SharedPtr waitable_ptr);
RCLCPP_PUBLIC
void
remove_waitable(const rclcpp::Waitable::SharedPtr waitable_ptr) noexcept;
void remove_waitable(const rclcpp::Waitable::SharedPtr waitable_ptr) noexcept;
CallbackGroupType type_;
// Mutex to protect the subsequent vectors of pointers.
@@ -144,7 +127,7 @@ protected:
std::atomic_bool can_be_taken_from_;
private:
template<typename TypeT, typename Function>
template <typename TypeT, typename Function>
typename TypeT::SharedPtr _find_ptrs_if_impl(
Function func, const std::vector<typename TypeT::WeakPtr> & vect_ptrs) const
{
@@ -159,12 +142,6 @@ private:
}
};
namespace callback_group
{
using CallbackGroupType [[deprecated("use rclcpp::CallbackGroupType instead")]] = CallbackGroupType;
using CallbackGroup [[deprecated("use rclcpp::CallbackGroup instead")]] = CallbackGroup;
} // namespace callback_group
} // namespace rclcpp

View File

@@ -15,7 +15,6 @@
#ifndef RCLCPP__CLIENT_HPP_
#define RCLCPP__CLIENT_HPP_
#include <atomic>
#include <future>
#include <map>
#include <memory>
@@ -29,12 +28,12 @@
#include "rcl/wait.h"
#include "rclcpp/exceptions.hpp"
#include "rclcpp/expand_topic_or_service_name.hpp"
#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/expand_topic_or_service_name.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rcutils/logging_macros.h"
@@ -44,7 +43,6 @@
namespace rclcpp
{
namespace node_interfaces
{
class NodeBaseInterface;
@@ -63,51 +61,24 @@ public:
RCLCPP_PUBLIC
virtual ~ClientBase();
/// Take the next response for this client as a type erased pointer.
/**
* The type erased pointer allows for this method to be used in a type
* agnostic way along with ClientBase::create_response(),
* ClientBase::create_request_header(), and ClientBase::handle_response().
* The typed version of this can be used if the Service type is known,
* \sa Client::take_response().
*
* \param[out] response_out The type erased pointer to a Service Response into
* which the middleware will copy the response being taken.
* \param[out] request_header_out The request header to be filled by the
* middleware when taking, and which can be used to associte the response
* to a specific request.
* \returns true if the response was taken, otherwise false.
* \throws rclcpp::exceptions::RCLError based exceptions if the underlying
* rcl function fail.
*/
RCLCPP_PUBLIC
bool
take_type_erased_response(void * response_out, rmw_request_id_t & request_header_out);
const char * get_service_name() const;
RCLCPP_PUBLIC
const char *
get_service_name() const;
std::shared_ptr<rcl_client_t> get_client_handle();
RCLCPP_PUBLIC
std::shared_ptr<rcl_client_t>
get_client_handle();
std::shared_ptr<const rcl_client_t> get_client_handle() const;
RCLCPP_PUBLIC
std::shared_ptr<const rcl_client_t>
get_client_handle() const;
bool service_is_ready() const;
RCLCPP_PUBLIC
bool
service_is_ready() const;
template<typename RepT = int64_t, typename RatioT = std::milli>
bool
wait_for_service(
template <typename RepT = int64_t, typename RatioT = std::milli>
bool wait_for_service(
std::chrono::duration<RepT, RatioT> timeout = std::chrono::duration<RepT, RatioT>(-1))
{
return wait_for_service_nanoseconds(
std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
);
std::chrono::duration_cast<std::chrono::nanoseconds>(timeout));
}
virtual std::shared_ptr<void> create_response() = 0;
@@ -115,45 +86,26 @@ public:
virtual void handle_response(
std::shared_ptr<rmw_request_id_t> request_header, std::shared_ptr<void> response) = 0;
/// Exchange the "in use by wait set" state for this client.
/**
* This is used to ensure this client is not used by multiple
* wait sets at the same time.
*
* \param[in] in_use_state the new state to exchange into the state, true
* indicates it is now in use by a wait set, and false is that it is no
* longer in use by a wait set.
* \returns the previous state.
*/
RCLCPP_PUBLIC
bool
exchange_in_use_by_wait_set_state(bool in_use_state);
protected:
RCLCPP_DISABLE_COPY(ClientBase)
RCLCPP_PUBLIC
bool
wait_for_service_nanoseconds(std::chrono::nanoseconds timeout);
bool wait_for_service_nanoseconds(std::chrono::nanoseconds timeout);
RCLCPP_PUBLIC
rcl_node_t *
get_rcl_node_handle();
rcl_node_t * get_rcl_node_handle();
RCLCPP_PUBLIC
const rcl_node_t *
get_rcl_node_handle() const;
const rcl_node_t * get_rcl_node_handle() const;
rclcpp::node_interfaces::NodeGraphInterface::WeakPtr node_graph_;
std::shared_ptr<rcl_node_t> node_handle_;
std::shared_ptr<rclcpp::Context> context_;
std::shared_ptr<rcl_client_t> client_handle_;
std::atomic<bool> in_use_by_wait_set_{false};
};
template<typename ServiceT>
template <typename ServiceT>
class Client : public ClientBase
{
public:
@@ -169,8 +121,8 @@ public:
using SharedFuture = std::shared_future<SharedResponse>;
using SharedFutureWithRequest = std::shared_future<std::pair<SharedRequest, SharedResponse>>;
using CallbackType = std::function<void (SharedFuture)>;
using CallbackWithRequestType = std::function<void (SharedFutureWithRequest)>;
using CallbackType = std::function<void(SharedFuture)>;
using CallbackWithRequestType = std::function<void(SharedFutureWithRequest)>;
RCLCPP_SMART_PTR_DEFINITIONS(Client)
@@ -182,79 +134,46 @@ public:
: ClientBase(node_base, node_graph)
{
using rosidl_typesupport_cpp::get_service_type_support_handle;
auto service_type_support_handle =
get_service_type_support_handle<ServiceT>();
auto service_type_support_handle = get_service_type_support_handle<ServiceT>();
rcl_ret_t ret = rcl_client_init(
this->get_client_handle().get(),
this->get_rcl_node_handle(),
service_type_support_handle,
service_name.c_str(),
&client_options);
this->get_client_handle().get(), this->get_rcl_node_handle(), service_type_support_handle,
service_name.c_str(), &client_options);
if (ret != RCL_RET_OK) {
if (ret == RCL_RET_SERVICE_NAME_INVALID) {
auto rcl_node_handle = this->get_rcl_node_handle();
// this will throw on any validation problem
rcl_reset_error();
expand_topic_or_service_name(
service_name,
rcl_node_get_name(rcl_node_handle),
rcl_node_get_namespace(rcl_node_handle),
service_name, rcl_node_get_name(rcl_node_handle), rcl_node_get_namespace(rcl_node_handle),
true);
}
rclcpp::exceptions::throw_from_rcl_error(ret, "could not create client");
}
}
virtual ~Client()
{
}
virtual ~Client() {}
/// Take the next response for this client.
/**
* \sa ClientBase::take_type_erased_response().
*
* \param[out] response_out The reference to a Service Response into
* which the middleware will copy the response being taken.
* \param[out] request_header_out The request header to be filled by the
* middleware when taking, and which can be used to associte the response
* to a specific request.
* \returns true if the response was taken, otherwise false.
* \throws rclcpp::exceptions::RCLError based exceptions if the underlying
* rcl function fail.
*/
bool
take_response(typename ServiceT::Response & response_out, rmw_request_id_t & request_header_out)
{
return this->take_type_erased_response(&response_out, request_header_out);
}
std::shared_ptr<void>
create_response() override
std::shared_ptr<void> create_response() override
{
return std::shared_ptr<void>(new typename ServiceT::Response());
}
std::shared_ptr<rmw_request_id_t>
create_request_header() override
std::shared_ptr<rmw_request_id_t> create_request_header() override
{
// TODO(wjwwood): This should probably use rmw_request_id's allocator.
// (since it is a C type)
return std::shared_ptr<rmw_request_id_t>(new rmw_request_id_t);
}
void
handle_response(
std::shared_ptr<rmw_request_id_t> request_header,
std::shared_ptr<void> response) override
void handle_response(
std::shared_ptr<rmw_request_id_t> request_header, std::shared_ptr<void> response) override
{
std::unique_lock<std::mutex> lock(pending_requests_mutex_);
auto typed_response = std::static_pointer_cast<typename ServiceT::Response>(response);
int64_t sequence_number = request_header->sequence_number;
// TODO(esteve) this should throw instead since it is not expected to happen in the first place
if (this->pending_requests_.count(sequence_number) == 0) {
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"Received invalid sequence number. Ignoring...");
RCUTILS_LOG_ERROR_NAMED("rclcpp", "Received invalid sequence number. Ignoring...");
return;
}
auto tuple = this->pending_requests_[sequence_number];
@@ -269,23 +188,16 @@ public:
callback(future);
}
SharedFuture
async_send_request(SharedRequest request)
SharedFuture async_send_request(SharedRequest request)
{
return async_send_request(request, [](SharedFuture) {});
}
template<
template <
typename CallbackT,
typename std::enable_if<
rclcpp::function_traits::same_arguments<
CallbackT,
CallbackType
>::value
>::type * = nullptr
>
SharedFuture
async_send_request(SharedRequest request, CallbackT && cb)
rclcpp::function_traits::same_arguments<CallbackT, CallbackType>::value>::type * = nullptr>
SharedFuture async_send_request(SharedRequest request, CallbackT && cb)
{
std::lock_guard<std::mutex> lock(pending_requests_mutex_);
int64_t sequence_number;
@@ -301,26 +213,21 @@ public:
return f;
}
template<
template <
typename CallbackT,
typename std::enable_if<
rclcpp::function_traits::same_arguments<
CallbackT,
CallbackWithRequestType
>::value
>::type * = nullptr
>
SharedFutureWithRequest
async_send_request(SharedRequest request, CallbackT && cb)
rclcpp::function_traits::same_arguments<CallbackT, CallbackWithRequestType>::value>::type * =
nullptr>
SharedFutureWithRequest async_send_request(SharedRequest request, CallbackT && cb)
{
SharedPromiseWithRequest promise = std::make_shared<PromiseWithRequest>();
SharedFutureWithRequest future_with_request(promise->get_future());
auto wrapping_cb = [future_with_request, promise, request, &cb](SharedFuture future) {
auto response = future.get();
promise->set_value(std::make_pair(request, response));
cb(future_with_request);
};
auto response = future.get();
promise->set_value(std::make_pair(request, response));
cb(future_with_request);
};
async_send_request(request, wrapping_cb);

View File

@@ -16,20 +16,15 @@
#define RCLCPP__CLOCK_HPP_
#include <functional>
#include <memory>
#include <mutex>
#include "rclcpp/macros.hpp"
#include "rclcpp/time.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rcl/time.h"
#include "rcutils/time.h"
#include "rcutils/types/rcutils_ret.h"
namespace rclcpp
{
class TimeSource;
class JumpHandler
@@ -37,8 +32,8 @@ class JumpHandler
public:
RCLCPP_SMART_PTR_DEFINITIONS(JumpHandler)
using pre_callback_t = std::function<void ()>;
using post_callback_t = std::function<void (const rcl_time_jump_t &)>;
using pre_callback_t = std::function<void()>;
using post_callback_t = std::function<void(const rcl_time_jump_t &)>;
JumpHandler(
pre_callback_t pre_callback,
@@ -75,8 +70,7 @@ public:
* \throws anything rclcpp::exceptions::throw_from_rcl_error can throw.
*/
RCLCPP_PUBLIC
Time
now();
Time now();
/**
* Returns the clock of the type `RCL_ROS_TIME` is active.
@@ -86,20 +80,13 @@ public:
* the current clock does not have the clock_type `RCL_ROS_TIME`.
*/
RCLCPP_PUBLIC
bool
ros_time_is_active();
bool ros_time_is_active();
RCLCPP_PUBLIC
rcl_clock_t *
get_clock_handle() noexcept;
rcl_clock_t * get_clock_handle() noexcept;
RCLCPP_PUBLIC
rcl_clock_type_t
get_clock_type() const noexcept;
RCLCPP_PUBLIC
std::mutex &
get_clock_mutex() noexcept;
rcl_clock_type_t get_clock_type() const noexcept;
// Add a callback to invoke if the jump threshold is exceeded.
/**
@@ -123,8 +110,7 @@ public:
* JumpHandler.
*/
RCLCPP_PUBLIC
JumpHandler::SharedPtr
create_jump_callback(
JumpHandler::SharedPtr create_jump_callback(
JumpHandler::pre_callback_t pre_callback,
JumpHandler::post_callback_t post_callback,
const rcl_jump_threshold_t & threshold);
@@ -132,16 +118,13 @@ public:
private:
// Invoke time jump callback
RCLCPP_PUBLIC
static void
on_time_jump(
const struct rcl_time_jump_t * time_jump,
bool before_jump,
void * user_data);
static void on_time_jump(
const struct rcl_time_jump_t * time_jump, bool before_jump, void * user_data);
/// Private internal storage
class Impl;
std::shared_ptr<Impl> impl_;
/// Internal storage backed by rcl
rcl_clock_t rcl_clock_;
friend TimeSource; /// Allow TimeSource to access the rcl_clock_ datatype.
rcl_allocator_t allocator_;
};
} // namespace rclcpp

View File

@@ -35,13 +35,11 @@
namespace rclcpp
{
/// Thrown when init is called on an already initialized context.
class ContextAlreadyInitialized : public std::runtime_error
{
public:
ContextAlreadyInitialized()
: std::runtime_error("context is already initialized") {}
ContextAlreadyInitialized() : std::runtime_error("context is already initialized") {}
};
/// Context which encapsulates shared state between nodes and other similar entities.
@@ -66,8 +64,7 @@ public:
Context();
RCLCPP_PUBLIC
virtual
~Context();
virtual ~Context();
/// Initialize the context, and the underlying elements like the rcl context.
/**
@@ -102,9 +99,7 @@ public:
* \throw ContextAlreadyInitialized if called if init is called more than once
*/
RCLCPP_PUBLIC
virtual
void
init(
virtual void init(
int argc,
char const * const argv[],
const rclcpp::InitOptions & init_options = rclcpp::InitOptions());
@@ -120,26 +115,22 @@ public:
* \return true if valid, otherwise false
*/
RCLCPP_PUBLIC
bool
is_valid() const;
bool is_valid() const;
/// Return the init options used during init.
RCLCPP_PUBLIC
const rclcpp::InitOptions &
get_init_options() const;
const rclcpp::InitOptions & get_init_options() const;
/// Return a copy of the init options used during init.
RCLCPP_PUBLIC
rclcpp::InitOptions
get_init_options();
rclcpp::InitOptions get_init_options();
/// Return the shutdown reason, or empty string if not shutdown.
/**
* This function is thread-safe.
*/
RCLCPP_PUBLIC
std::string
shutdown_reason();
std::string shutdown_reason();
/// Shutdown the context, making it uninitialized and therefore invalid for derived entities.
/**
@@ -159,14 +150,12 @@ public:
*
* \param[in] reason the description of why shutdown happened
* \return true if shutdown was successful, false if context was already shutdown
* \throw various exceptions derived from rclcpp::exceptions::RCLError, if rcl_shutdown fails
* \throw various exceptions derived from RCLErrorBase, if rcl_shutdown fails
*/
RCLCPP_PUBLIC
virtual
bool
shutdown(const std::string & reason);
virtual bool shutdown(const std::string & reason);
using OnShutdownCallback = std::function<void ()>;
using OnShutdownCallback = std::function<void()>;
/// Add a on_shutdown callback to be called when shutdown is called for this context.
/**
@@ -188,9 +177,7 @@ public:
* \return the callback passed, for convenience when storing a passed lambda
*/
RCLCPP_PUBLIC
virtual
OnShutdownCallback
on_shutdown(OnShutdownCallback callback);
virtual OnShutdownCallback on_shutdown(OnShutdownCallback callback);
/// Return the shutdown callbacks as const.
/**
@@ -198,8 +185,7 @@ public:
* the list of "on shutdown" callbacks, i.e. on_shutdown().
*/
RCLCPP_PUBLIC
const std::vector<OnShutdownCallback> &
get_on_shutdown_callbacks() const;
const std::vector<OnShutdownCallback> & get_on_shutdown_callbacks() const;
/// Return the shutdown callbacks.
/**
@@ -207,13 +193,11 @@ public:
* the list of "on shutdown" callbacks, i.e. on_shutdown().
*/
RCLCPP_PUBLIC
std::vector<OnShutdownCallback> &
get_on_shutdown_callbacks();
std::vector<OnShutdownCallback> & get_on_shutdown_callbacks();
/// Return the internal rcl context.
RCLCPP_PUBLIC
std::shared_ptr<rcl_context_t>
get_rcl_context();
std::shared_ptr<rcl_context_t> get_rcl_context();
/// Sleep for a given period of time or until shutdown() is called.
/**
@@ -228,14 +212,11 @@ public:
* \return true if the condition variable did not timeout, i.e. you were interrupted.
*/
RCLCPP_PUBLIC
bool
sleep_for(const std::chrono::nanoseconds & nanoseconds);
bool sleep_for(const std::chrono::nanoseconds & nanoseconds);
/// Interrupt any blocking sleep_for calls, causing them to return immediately and return true.
RCLCPP_PUBLIC
virtual
void
interrupt_all_sleep_for();
virtual void interrupt_all_sleep_for();
/// Get a handle to the guard condition which is triggered when interrupted.
/**
@@ -262,8 +243,7 @@ public:
* \return Pointer to the guard condition.
*/
RCLCPP_PUBLIC
rcl_guard_condition_t *
get_interrupt_guard_condition(rcl_wait_set_t * wait_set);
rcl_guard_condition_t * get_interrupt_guard_condition(rcl_wait_set_t * wait_set);
/// Release the previously allocated guard condition which is triggered when interrupted.
/**
@@ -281,24 +261,20 @@ public:
* resulting guard condition.
*/
RCLCPP_PUBLIC
void
release_interrupt_guard_condition(rcl_wait_set_t * wait_set);
void release_interrupt_guard_condition(rcl_wait_set_t * wait_set);
/// Nothrow version of release_interrupt_guard_condition(), logs to RCLCPP_ERROR instead.
RCLCPP_PUBLIC
void
release_interrupt_guard_condition(rcl_wait_set_t * wait_set, const std::nothrow_t &) noexcept;
void release_interrupt_guard_condition(
rcl_wait_set_t * wait_set, const std::nothrow_t &) noexcept;
/// Interrupt any blocking executors, or wait sets associated with this context.
RCLCPP_PUBLIC
virtual
void
interrupt_all_wait_sets();
virtual void interrupt_all_wait_sets();
/// Return a singleton instance for the SubContext type, constructing one if necessary.
template<typename SubContext, typename ... Args>
std::shared_ptr<SubContext>
get_sub_context(Args && ... args)
template <typename SubContext, typename... Args>
std::shared_ptr<SubContext> get_sub_context(Args &&... args)
{
std::lock_guard<std::recursive_mutex> lock(sub_contexts_mutex_);
@@ -308,10 +284,8 @@ public:
if (it == sub_contexts_.end()) {
// It doesn't exist yet, make it
sub_context = std::shared_ptr<SubContext>(
new SubContext(std::forward<Args>(args) ...),
[](SubContext * sub_context_ptr) {
delete sub_context_ptr;
});
new SubContext(std::forward<Args>(args)...),
[](SubContext * sub_context_ptr) { delete sub_context_ptr; });
sub_contexts_[type_i] = sub_context;
} else {
// It exists, get it out and cast it.
@@ -324,9 +298,7 @@ protected:
// Called by constructor and destructor to clean up by finalizing the
// shutdown rcl context and preparing for a new init cycle.
RCLCPP_PUBLIC
virtual
void
clean_up();
virtual void clean_up();
private:
RCLCPP_DISABLE_COPY(Context)
@@ -362,8 +334,7 @@ private:
* This function is thread-safe.
*/
RCLCPP_PUBLIC
std::vector<Context::SharedPtr>
get_contexts();
std::vector<Context::SharedPtr> get_contexts();
} // namespace rclcpp

View File

@@ -22,7 +22,8 @@ namespace rclcpp
{
namespace contexts
{
namespace default_context
{
class DefaultContext : public rclcpp::Context
{
public:
@@ -33,23 +34,7 @@ public:
};
RCLCPP_PUBLIC
DefaultContext::SharedPtr
get_global_default_context();
namespace default_context
{
using DefaultContext
[[deprecated("use rclcpp::contexts::DefaultContext instead")]] = DefaultContext;
[[deprecated("use rclcpp::contexts::get_global_default_context() instead")]]
RCLCPP_PUBLIC
inline
DefaultContext::SharedPtr
get_global_default_context()
{
return rclcpp::contexts::get_global_default_context();
}
DefaultContext::SharedPtr get_global_default_context();
} // namespace default_context
} // namespace contexts

View File

@@ -24,27 +24,22 @@
namespace rclcpp
{
/// Create a service client with a given type.
/// \internal
template<typename ServiceT>
typename rclcpp::Client<ServiceT>::SharedPtr
create_client(
template <typename ServiceT>
typename rclcpp::Client<ServiceT>::SharedPtr create_client(
std::shared_ptr<node_interfaces::NodeBaseInterface> node_base,
std::shared_ptr<node_interfaces::NodeGraphInterface> node_graph,
std::shared_ptr<node_interfaces::NodeServicesInterface> node_services,
const std::string & service_name,
const rmw_qos_profile_t & qos_profile,
rclcpp::CallbackGroup::SharedPtr group)
rclcpp::callback_group::CallbackGroup::SharedPtr group)
{
rcl_client_options_t options = rcl_client_get_default_options();
options.qos = qos_profile;
auto cli = rclcpp::Client<ServiceT>::make_shared(
node_base.get(),
node_graph,
service_name,
options);
auto cli =
rclcpp::Client<ServiceT>::make_shared(node_base.get(), node_graph, service_name, options);
auto cli_base_ptr = std::dynamic_pointer_cast<rclcpp::ClientBase>(cli);
node_services->add_client(cli_base_ptr, group);

View File

@@ -28,41 +28,81 @@
namespace rclcpp
{
template <
typename MessageT,
typename AllocatorT = std::allocator<void>,
typename PublisherT = ::rclcpp::Publisher<MessageT, AllocatorT>>
// cppcheck-suppress syntaxError // bug in cppcheck 1.82 for [[deprecated]] on templated function
[[deprecated("use alternative rclcpp::create_publisher() signatures")]] std::shared_ptr<PublisherT>
create_publisher(
rclcpp::node_interfaces::NodeTopicsInterface * node_topics,
const std::string & topic_name,
const rmw_qos_profile_t & qos_profile,
const PublisherEventCallbacks & event_callbacks,
rclcpp::callback_group::CallbackGroup::SharedPtr group,
bool use_intra_process_comms,
std::shared_ptr<AllocatorT> allocator) {
auto publisher_options = rcl_publisher_get_default_options();
publisher_options.qos = qos_profile;
auto pub = node_topics->create_publisher(
topic_name,
rclcpp::create_publisher_factory<MessageT, AllocatorT, PublisherT>(event_callbacks, allocator),
publisher_options, use_intra_process_comms);
node_topics->add_publisher(pub, group);
return std::dynamic_pointer_cast<PublisherT>(pub);
}
/// Create and return a publisher of the given MessageT type.
/**
* The NodeT type only needs to have a method called get_node_topics_interface()
* which returns a shared_ptr to a NodeTopicsInterface.
*/
template<
template <
typename MessageT,
typename AllocatorT = std::allocator<void>,
typename PublisherT = rclcpp::Publisher<MessageT, AllocatorT>,
typename PublisherT = ::rclcpp::Publisher<MessageT, AllocatorT>,
typename NodeT>
std::shared_ptr<PublisherT>
create_publisher(
std::shared_ptr<PublisherT> create_publisher(
NodeT & node,
const std::string & topic_name,
const rclcpp::QoS & qos,
const rclcpp::PublisherOptionsWithAllocator<AllocatorT> & options = (
rclcpp::PublisherOptionsWithAllocator<AllocatorT>()
)
)
const rclcpp::PublisherOptionsWithAllocator<AllocatorT> & options =
(rclcpp::PublisherOptionsWithAllocator<AllocatorT>()))
{
// Extract the NodeTopicsInterface from the NodeT.
using rclcpp::node_interfaces::get_node_topics_interface;
auto node_topics = get_node_topics_interface(node);
// Create the publisher.
std::shared_ptr<AllocatorT> allocator = options.allocator;
if (!allocator) {
allocator = std::make_shared<AllocatorT>();
}
bool use_intra_process;
switch (options.use_intra_process_comm) {
case IntraProcessSetting::Enable:
use_intra_process = true;
break;
case IntraProcessSetting::Disable:
use_intra_process = false;
break;
case IntraProcessSetting::NodeDefault:
use_intra_process = node_topics->get_node_base_interface()->get_use_intra_process_default();
break;
default:
throw std::runtime_error("Unrecognized IntraProcessSetting value");
break;
}
// TODO(wjwwood): convert all of the interfaces to use QoS and PublisherOptionsBase
auto pub = node_topics->create_publisher(
topic_name,
rclcpp::create_publisher_factory<MessageT, AllocatorT, PublisherT>(options),
qos
);
// Add the publisher to the node topics interface.
rclcpp::create_publisher_factory<MessageT, AllocatorT, PublisherT>(
options.event_callbacks, allocator),
options.template to_rcl_publisher_options<MessageT>(qos), use_intra_process);
node_topics->add_publisher(pub, options.callback_group);
return std::dynamic_pointer_cast<PublisherT>(pub);
}

View File

@@ -26,18 +26,16 @@
namespace rclcpp
{
/// Create a service with a given type.
/// \internal
template<typename ServiceT, typename CallbackT>
typename rclcpp::Service<ServiceT>::SharedPtr
create_service(
template <typename ServiceT, typename CallbackT>
typename rclcpp::Service<ServiceT>::SharedPtr create_service(
std::shared_ptr<node_interfaces::NodeBaseInterface> node_base,
std::shared_ptr<node_interfaces::NodeServicesInterface> node_services,
const std::string & service_name,
CallbackT && callback,
const rmw_qos_profile_t & qos_profile,
rclcpp::CallbackGroup::SharedPtr group)
rclcpp::callback_group::CallbackGroup::SharedPtr group)
{
rclcpp::AnyServiceCallback<ServiceT> any_service_callback;
any_service_callback.set(std::forward<CallbackT>(callback));
@@ -46,8 +44,7 @@ create_service(
service_options.qos = qos_profile;
auto serv = Service<ServiceT>::make_shared(
node_base->get_shared_rcl_node_handle(),
service_name, any_service_callback, service_options);
node_base->get_shared_rcl_node_handle(), service_name, any_service_callback, service_options);
auto serv_base_ptr = std::dynamic_pointer_cast<ServiceBase>(serv);
node_services->add_service(serv_base_ptr, group);
return serv;

View File

@@ -21,13 +21,48 @@
#include "rclcpp/node_interfaces/get_node_topics_interface.hpp"
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/subscription_factory.hpp"
#include "rclcpp/subscription_options.hpp"
#include "rclcpp/qos.hpp"
#include "rmw/qos_profiles.h"
namespace rclcpp
{
template <
typename MessageT,
typename CallbackT,
typename AllocatorT,
typename CallbackMessageT,
typename SubscriptionT = rclcpp::Subscription<CallbackMessageT, AllocatorT>>
// cppcheck-suppress syntaxError // bug in cppcheck 1.82 for [[deprecated]] on templated function
[[deprecated("use alternative rclcpp::create_subscription() signatures")]]
typename std::shared_ptr<SubscriptionT>
create_subscription(
rclcpp::node_interfaces::NodeTopicsInterface * node_topics,
const std::string & topic_name,
CallbackT && callback,
const rmw_qos_profile_t & qos_profile,
const SubscriptionEventCallbacks & event_callbacks,
rclcpp::callback_group::CallbackGroup::SharedPtr group,
bool ignore_local_publications,
bool use_intra_process_comms,
typename rclcpp::message_memory_strategy::MessageMemoryStrategy<CallbackMessageT, AllocatorT>::
SharedPtr msg_mem_strat,
typename std::shared_ptr<AllocatorT> allocator)
{
auto subscription_options = rcl_subscription_get_default_options();
subscription_options.qos = qos_profile;
subscription_options.ignore_local_publications = ignore_local_publications;
auto factory = rclcpp::create_subscription_factory<
MessageT, CallbackT, AllocatorT, CallbackMessageT, SubscriptionT>(
std::forward<CallbackT>(callback), event_callbacks, msg_mem_strat, allocator);
auto sub = node_topics->create_subscription(
topic_name, factory, subscription_options, use_intra_process_comms);
node_topics->add_subscription(sub, group);
return std::dynamic_pointer_cast<SubscriptionT>(sub);
}
/// Create and return a subscription of the given MessageT type.
/**
@@ -35,44 +70,61 @@ namespace rclcpp
* which returns a shared_ptr to a NodeTopicsInterface, or be a
* NodeTopicsInterface pointer itself.
*/
template<
template <
typename MessageT,
typename CallbackT,
typename AllocatorT = std::allocator<void>,
typename CallbackMessageT =
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type,
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type,
typename SubscriptionT = rclcpp::Subscription<CallbackMessageT, AllocatorT>,
typename MessageMemoryStrategyT = rclcpp::message_memory_strategy::MessageMemoryStrategy<
CallbackMessageT,
AllocatorT
>,
typename NodeT>
typename std::shared_ptr<SubscriptionT>
create_subscription(
typename std::shared_ptr<SubscriptionT> create_subscription(
NodeT && node,
const std::string & topic_name,
const rclcpp::QoS & qos,
CallbackT && callback,
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options = (
rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>()
),
typename MessageMemoryStrategyT::SharedPtr msg_mem_strat = (
MessageMemoryStrategyT::create_default()
)
)
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options =
(rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>()),
typename rclcpp::message_memory_strategy::MessageMemoryStrategy<CallbackMessageT, AllocatorT>::
SharedPtr msg_mem_strat = nullptr)
{
using rclcpp::node_interfaces::get_node_topics_interface;
auto node_topics = get_node_topics_interface(std::forward<NodeT>(node));
auto factory = rclcpp::create_subscription_factory<MessageT>(
std::forward<CallbackT>(callback),
options,
msg_mem_strat
);
if (!msg_mem_strat) {
using rclcpp::message_memory_strategy::MessageMemoryStrategy;
msg_mem_strat = MessageMemoryStrategy<CallbackMessageT, AllocatorT>::create_default();
}
auto sub = node_topics->create_subscription(topic_name, factory, qos);
std::shared_ptr<AllocatorT> allocator = options.allocator;
if (!allocator) {
allocator = std::make_shared<AllocatorT>();
}
auto factory = rclcpp::create_subscription_factory<
MessageT, CallbackT, AllocatorT, CallbackMessageT, SubscriptionT>(
std::forward<CallbackT>(callback), options.event_callbacks, msg_mem_strat, allocator);
bool use_intra_process;
switch (options.use_intra_process_comm) {
case IntraProcessSetting::Enable:
use_intra_process = true;
break;
case IntraProcessSetting::Disable:
use_intra_process = false;
break;
case IntraProcessSetting::NodeDefault:
use_intra_process = node_topics->get_node_base_interface()->get_use_intra_process_default();
break;
default:
throw std::runtime_error("Unrecognized IntraProcessSetting value");
break;
}
// TODO(wjwwood): convert all of the interfaces to use QoS and SubscriptionOptionsBase
auto sub = node_topics->create_subscription(
topic_name, factory, options.template to_rcl_subscription_options<MessageT>(qos),
use_intra_process);
node_topics->add_subscription(sub, options.callback_group);
return std::dynamic_pointer_cast<SubscriptionT>(sub);
}

View File

@@ -29,20 +29,17 @@ namespace rclcpp
{
/// Create a timer with a given clock
/// \internal
template<typename CallbackT>
typename rclcpp::TimerBase::SharedPtr
create_timer(
template <typename CallbackT>
typename rclcpp::TimerBase::SharedPtr create_timer(
node_interfaces::NodeBaseInterface * node_base,
node_interfaces::NodeTimersInterface * node_timers,
rclcpp::Clock::SharedPtr clock,
rclcpp::Duration period,
CallbackT && callback,
rclcpp::CallbackGroup::SharedPtr group = nullptr)
rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr)
{
auto timer = rclcpp::GenericTimer<CallbackT>::make_shared(
clock,
period.to_chrono<std::chrono::nanoseconds>(),
std::forward<CallbackT>(callback),
clock, period.to_chrono<std::chrono::nanoseconds>(), std::forward<CallbackT>(callback),
node_base->get_context());
node_timers->add_timer(timer, group);
@@ -50,22 +47,18 @@ create_timer(
}
/// Create a timer with a given clock
template<typename NodeT, typename CallbackT>
typename rclcpp::TimerBase::SharedPtr
create_timer(
template <typename NodeT, typename CallbackT>
typename rclcpp::TimerBase::SharedPtr create_timer(
NodeT node,
rclcpp::Clock::SharedPtr clock,
rclcpp::Duration period,
CallbackT && callback,
rclcpp::CallbackGroup::SharedPtr group = nullptr)
rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr)
{
return create_timer(
rclcpp::node_interfaces::get_node_base_interface(node),
rclcpp::node_interfaces::get_node_timers_interface(node),
clock,
period,
std::forward<CallbackT>(callback),
group);
rclcpp::node_interfaces::get_node_timers_interface(node), clock, period,
std::forward<CallbackT>(callback), group);
}
} // namespace rclcpp

View File

@@ -1,3 +0,0 @@
Notice that headers in this folder should only provide symbols in the rclcpp::detail namespace.
Also that these headers are not considered part of the public API and are subject to change without notice.

View File

@@ -1,54 +0,0 @@
// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__DETAIL__RESOLVE_ENABLE_TOPIC_STATISTICS_HPP_
#define RCLCPP__DETAIL__RESOLVE_ENABLE_TOPIC_STATISTICS_HPP_
#include <stdexcept>
#include "rclcpp/topic_statistics_state.hpp"
namespace rclcpp
{
namespace detail
{
/// Return whether or not topic statistics is enabled, resolving "NodeDefault" if needed.
template<typename OptionsT, typename NodeBaseT>
bool
resolve_enable_topic_statistics(const OptionsT & options, const NodeBaseT & node_base)
{
bool topic_stats_enabled;
switch (options.topic_stats_options.state) {
case TopicStatisticsState::Enable:
topic_stats_enabled = true;
break;
case TopicStatisticsState::Disable:
topic_stats_enabled = false;
break;
case TopicStatisticsState::NodeDefault:
topic_stats_enabled = node_base.get_enable_topic_statistics_default();
break;
default:
throw std::runtime_error("Unrecognized EnableTopicStatistics value");
break;
}
return topic_stats_enabled;
}
} // namespace detail
} // namespace rclcpp
#endif // RCLCPP__DETAIL__RESOLVE_ENABLE_TOPIC_STATISTICS_HPP_

View File

@@ -1,54 +0,0 @@
// Copyright 2019 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__DETAIL__RESOLVE_INTRA_PROCESS_BUFFER_TYPE_HPP_
#define RCLCPP__DETAIL__RESOLVE_INTRA_PROCESS_BUFFER_TYPE_HPP_
#include <stdexcept>
#include "rclcpp/any_subscription_callback.hpp"
#include "rclcpp/intra_process_buffer_type.hpp"
namespace rclcpp
{
namespace detail
{
/// Return the buffer type, resolving the "CallbackDefault" type to an actual type if needed.
template<typename CallbackMessageT, typename AllocatorT>
rclcpp::IntraProcessBufferType
resolve_intra_process_buffer_type(
const rclcpp::IntraProcessBufferType buffer_type,
const rclcpp::AnySubscriptionCallback<CallbackMessageT, AllocatorT> & any_subscription_callback)
{
rclcpp::IntraProcessBufferType resolved_buffer_type = buffer_type;
// If the user has not specified a type for the intra-process buffer, use the callback's type.
if (resolved_buffer_type == IntraProcessBufferType::CallbackDefault) {
if (any_subscription_callback.use_take_shared_method()) {
resolved_buffer_type = IntraProcessBufferType::SharedPtr;
} else {
resolved_buffer_type = IntraProcessBufferType::UniquePtr;
}
}
return resolved_buffer_type;
}
} // namespace detail
} // namespace rclcpp
#endif // RCLCPP__DETAIL__RESOLVE_INTRA_PROCESS_BUFFER_TYPE_HPP_

View File

@@ -1,56 +0,0 @@
// Copyright 2019 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__DETAIL__RESOLVE_USE_INTRA_PROCESS_HPP_
#define RCLCPP__DETAIL__RESOLVE_USE_INTRA_PROCESS_HPP_
#include <stdexcept>
#include "rclcpp/intra_process_setting.hpp"
namespace rclcpp
{
namespace detail
{
/// Return whether or not intra process is enabled, resolving "NodeDefault" if needed.
template<typename OptionsT, typename NodeBaseT>
bool
resolve_use_intra_process(const OptionsT & options, const NodeBaseT & node_base)
{
bool use_intra_process;
switch (options.use_intra_process_comm) {
case IntraProcessSetting::Enable:
use_intra_process = true;
break;
case IntraProcessSetting::Disable:
use_intra_process = false;
break;
case IntraProcessSetting::NodeDefault:
use_intra_process = node_base.get_use_intra_process_default();
break;
default:
throw std::runtime_error("Unrecognized IntraProcessSetting value");
break;
}
return use_intra_process;
}
} // namespace detail
} // namespace rclcpp
#endif // RCLCPP__DETAIL__RESOLVE_USE_INTRA_PROCESS_HPP_

View File

@@ -1,51 +0,0 @@
// Copyright 2019 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__DETAIL__RMW_IMPLEMENTATION_SPECIFIC_PAYLOAD_HPP_
#define RCLCPP__DETAIL__RMW_IMPLEMENTATION_SPECIFIC_PAYLOAD_HPP_
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
namespace detail
{
/// Mechanism for passing rmw implementation specific settings through the ROS interfaces.
class RCLCPP_PUBLIC RMWImplementationSpecificPayload
{
public:
virtual
~RMWImplementationSpecificPayload() = default;
/// Return false if this class has not been customized, otherwise true.
/**
* It does this based on the value of the rmw implementation identifier that
* this class reports, and so it is important for a specialization of this
* class to override the get_rmw_implementation_identifier() method to return
* something other than nullptr.
*/
bool
has_been_customized() const;
/// Derrived classes should override this and return the identifier of its rmw implementation.
virtual
const char *
get_implementation_identifier() const;
};
} // namespace detail
} // namespace rclcpp
#endif // RCLCPP__DETAIL__RMW_IMPLEMENTATION_SPECIFIC_PAYLOAD_HPP_

View File

@@ -1,52 +0,0 @@
// Copyright 2019 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__DETAIL__RMW_IMPLEMENTATION_SPECIFIC_PUBLISHER_PAYLOAD_HPP_
#define RCLCPP__DETAIL__RMW_IMPLEMENTATION_SPECIFIC_PUBLISHER_PAYLOAD_HPP_
#include "rcl/publisher.h"
#include "rclcpp/detail/rmw_implementation_specific_payload.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
namespace detail
{
class RCLCPP_PUBLIC RMWImplementationSpecificPublisherPayload
: public RMWImplementationSpecificPayload
{
public:
~RMWImplementationSpecificPublisherPayload() override = default;
/// Opportunity for a derived class to inject information into the rcl options.
/**
* This is called after the rcl_publisher_options_t has been prepared by
* rclcpp, but before rcl_publisher_init() is called.
*
* The passed option is the rmw_publisher_options field of the
* rcl_publisher_options_t that will be passed to rcl_publisher_init().
*
* By default the options are unmodified.
*/
virtual
void
modify_rmw_publisher_options(rmw_publisher_options_t & rmw_publisher_options) const;
};
} // namespace detail
} // namespace rclcpp
#endif // RCLCPP__DETAIL__RMW_IMPLEMENTATION_SPECIFIC_PUBLISHER_PAYLOAD_HPP_

View File

@@ -1,53 +0,0 @@
// Copyright 2019 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__DETAIL__RMW_IMPLEMENTATION_SPECIFIC_SUBSCRIPTION_PAYLOAD_HPP_
#define RCLCPP__DETAIL__RMW_IMPLEMENTATION_SPECIFIC_SUBSCRIPTION_PAYLOAD_HPP_
#include "rcl/subscription.h"
#include "rclcpp/detail/rmw_implementation_specific_payload.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
namespace detail
{
/// Subscription payload that may be rmw implementation specific.
class RCLCPP_PUBLIC RMWImplementationSpecificSubscriptionPayload
: public RMWImplementationSpecificPayload
{
public:
~RMWImplementationSpecificSubscriptionPayload() override = default;
/// Opportunity for a derived class to inject information into the rcl options.
/**
* This is called after the rcl_subscription_options_t has been prepared by
* rclcpp, but before rcl_subscription_init() is called.
*
* The passed option is the rmw_subscription_options field of the
* rcl_subscription_options_t that will be passed to rcl_subscription_init().
*
* By default the options are unmodified.
*/
virtual
void
modify_rmw_subscription_options(rmw_subscription_options_t & rmw_subscription_options) const;
};
} // namespace detail
} // namespace rclcpp
#endif // RCLCPP__DETAIL__RMW_IMPLEMENTATION_SPECIFIC_SUBSCRIPTION_PAYLOAD_HPP_

View File

@@ -1,40 +0,0 @@
// Copyright 2019 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__DETAIL__UTILITIES_HPP_
#define RCLCPP__DETAIL__UTILITIES_HPP_
#include "rclcpp/detail/utilities.hpp"
#include <string>
#include <vector>
#include "rcl/allocator.h"
#include "rcl/arguments.h"
namespace rclcpp
{
namespace detail
{
std::vector<std::string>
get_unparsed_ros_arguments(
int argc, char const * const argv[],
rcl_arguments_t * arguments,
rcl_allocator_t allocator);
} // namespace detail
} // namespace rclcpp
#endif // RCLCPP__DETAIL__UTILITIES_HPP_

View File

@@ -35,11 +35,12 @@ public:
// This constructor matches any std::chrono value other than nanoseconds
// intentionally not using explicit to create a conversion constructor
template<class Rep, class Period>
template <class Rep, class Period>
// cppcheck-suppress noExplicitConstructor
Duration(const std::chrono::duration<Rep, Period> & duration) // NOLINT(runtime/explicit)
: Duration(std::chrono::duration_cast<std::chrono::nanoseconds>(duration))
{}
{
}
// cppcheck-suppress noExplicitConstructor
Duration(const builtin_interfaces::msg::Duration & duration_msg); // NOLINT(runtime/explicit)
@@ -53,62 +54,45 @@ public:
operator builtin_interfaces::msg::Duration() const;
// cppcheck-suppress operatorEq // this is a false positive from cppcheck
Duration &
operator=(const Duration & rhs);
Duration & operator=(const Duration & rhs);
Duration &
operator=(const builtin_interfaces::msg::Duration & Duration_msg);
Duration & operator=(const builtin_interfaces::msg::Duration & Duration_msg);
bool
operator==(const rclcpp::Duration & rhs) const;
bool operator==(const rclcpp::Duration & rhs) const;
bool
operator<(const rclcpp::Duration & rhs) const;
bool operator<(const rclcpp::Duration & rhs) const;
bool
operator<=(const rclcpp::Duration & rhs) const;
bool operator<=(const rclcpp::Duration & rhs) const;
bool
operator>=(const rclcpp::Duration & rhs) const;
bool operator>=(const rclcpp::Duration & rhs) const;
bool
operator>(const rclcpp::Duration & rhs) const;
bool operator>(const rclcpp::Duration & rhs) const;
Duration
operator+(const rclcpp::Duration & rhs) const;
Duration operator+(const rclcpp::Duration & rhs) const;
Duration
operator-(const rclcpp::Duration & rhs) const;
Duration operator-(const rclcpp::Duration & rhs) const;
static
Duration
max();
static Duration max();
Duration
operator*(double scale) const;
Duration operator*(double scale) const;
rcl_duration_value_t
nanoseconds() const;
rcl_duration_value_t nanoseconds() const;
/// \return the duration in seconds as a floating point number.
/// \warning Depending on sizeof(double) there could be significant precision loss.
/// When an exact time is required use nanoseconds() instead.
double
seconds() const;
double seconds() const;
// Create a duration object from a floating point number representing seconds
static Duration
from_seconds(double seconds);
static Duration from_seconds(double seconds);
template<class DurationT>
DurationT
to_chrono() const
template <class DurationT>
DurationT to_chrono() const
{
return std::chrono::duration_cast<DurationT>(std::chrono::nanoseconds(this->nanoseconds()));
}
rmw_time_t
to_rmw_time() const;
rmw_time_t to_rmw_time() const;
private:
rcl_duration_t rcl_duration_;

View File

@@ -23,7 +23,6 @@
namespace rclcpp
{
class Event
{
public:
@@ -33,16 +32,13 @@ public:
Event();
RCLCPP_PUBLIC
bool
set();
bool set();
RCLCPP_PUBLIC
bool
check();
bool check();
RCLCPP_PUBLIC
bool
check_and_clear();
bool check_and_clear();
private:
RCLCPP_DISABLE_COPY(Event)

View File

@@ -15,6 +15,240 @@
#ifndef RCLCPP__EXCEPTIONS_HPP_
#define RCLCPP__EXCEPTIONS_HPP_
#include "rclcpp/exceptions/exceptions.hpp"
#include <stdexcept>
#include <string>
#include <vector>
#include "rcl/error_handling.h"
#include "rcl/types.h"
#include "rclcpp/visibility_control.hpp"
#include "rcpputils/join.hpp"
namespace rclcpp
{
namespace exceptions
{
/// Thrown when a method is trying to use a node, but it is invalid.
class InvalidNodeError : public std::runtime_error
{
public:
InvalidNodeError() : std::runtime_error("node is invalid") {}
};
/// Thrown when a any kind of name (node, namespace, topic, etc.) is invalid.
class NameValidationError : public std::invalid_argument
{
public:
NameValidationError(
const char * name_type_, const char * name_, const char * error_msg_, size_t invalid_index_)
: std::invalid_argument(format_error(name_type_, name_, error_msg_, invalid_index_)),
name_type(name_type_),
name(name_),
error_msg(error_msg_),
invalid_index(invalid_index_)
{
}
static std::string format_error(
const char * name_type, const char * name, const char * error_msg, size_t invalid_index);
const std::string name_type;
const std::string name;
const std::string error_msg;
const size_t invalid_index;
};
/// Thrown when a node name is invalid.
class InvalidNodeNameError : public NameValidationError
{
public:
InvalidNodeNameError(const char * node_name, const char * error_msg, size_t invalid_index)
: NameValidationError("node name", node_name, error_msg, invalid_index)
{
}
};
/// Thrown when a node namespace is invalid.
class InvalidNamespaceError : public NameValidationError
{
public:
InvalidNamespaceError(const char * namespace_, const char * error_msg, size_t invalid_index)
: NameValidationError("namespace", namespace_, error_msg, invalid_index)
{
}
};
/// Thrown when a topic name is invalid.
class InvalidTopicNameError : public NameValidationError
{
public:
InvalidTopicNameError(const char * namespace_, const char * error_msg, size_t invalid_index)
: NameValidationError("topic name", namespace_, error_msg, invalid_index)
{
}
};
/// Thrown when a service name is invalid.
class InvalidServiceNameError : public NameValidationError
{
public:
InvalidServiceNameError(const char * namespace_, const char * error_msg, size_t invalid_index)
: NameValidationError("service name", namespace_, error_msg, invalid_index)
{
}
};
/// Throw a C++ std::exception which was created based on an rcl error.
/**
* Passing nullptr for reset_error is safe and will avoid calling any function
* to reset the error.
*
* \param ret the return code for the current error state
* \param prefix string to prefix to the error if applicable (not all errors have custom messages)
* \param error_state error state to create exception from, if nullptr rcl_get_error_state is used
* \param reset_error function to be called before throwing which whill clear the error state
* \throws std::invalid_argument if ret is RCL_RET_OK
* \throws std::runtime_error if the rcl_get_error_state returns 0
* \throws RCLErrorBase some child class exception based on ret
*/
/* *INDENT-OFF* */ // Uncrustify cannot yet understand [[noreturn]] properly
RCLCPP_PUBLIC
void throw_from_rcl_error[[noreturn]](
rcl_ret_t ret,
const std::string & prefix = "",
const rcl_error_state_t * error_state = nullptr,
void (*reset_error)() = rcl_reset_error);
/* *INDENT-ON* */
class RCLErrorBase
{
public:
RCLCPP_PUBLIC
RCLErrorBase(rcl_ret_t ret, const rcl_error_state_t * error_state);
virtual ~RCLErrorBase() {}
rcl_ret_t ret;
std::string message;
std::string file;
size_t line;
std::string formatted_message;
};
/// Created when the return code does not match one of the other specialized exceptions.
class RCLError : public RCLErrorBase, public std::runtime_error
{
public:
RCLCPP_PUBLIC
RCLError(rcl_ret_t ret, const rcl_error_state_t * error_state, const std::string & prefix);
RCLCPP_PUBLIC
RCLError(const RCLErrorBase & base_exc, const std::string & prefix);
};
/// Created when the ret is RCL_RET_BAD_ALLOC.
class RCLBadAlloc : public RCLErrorBase, public std::bad_alloc
{
public:
RCLCPP_PUBLIC
RCLBadAlloc(rcl_ret_t ret, const rcl_error_state_t * error_state);
RCLCPP_PUBLIC
explicit RCLBadAlloc(const RCLErrorBase & base_exc);
};
/// Created when the ret is RCL_RET_INVALID_ARGUMENT.
class RCLInvalidArgument : public RCLErrorBase, public std::invalid_argument
{
public:
RCLCPP_PUBLIC
RCLInvalidArgument(
rcl_ret_t ret, const rcl_error_state_t * error_state, const std::string & prefix);
RCLCPP_PUBLIC
RCLInvalidArgument(const RCLErrorBase & base_exc, const std::string & prefix);
};
/// Created when the ret is RCL_RET_INVALID_ROS_ARGS.
class RCLInvalidROSArgsError : public RCLErrorBase, public std::runtime_error
{
public:
RCLCPP_PUBLIC
RCLInvalidROSArgsError(
rcl_ret_t ret, const rcl_error_state_t * error_state, const std::string & prefix);
RCLCPP_PUBLIC
RCLInvalidROSArgsError(const RCLErrorBase & base_exc, const std::string & prefix);
};
/// Thrown when unparsed ROS specific arguments are found.
class UnknownROSArgsError : public std::runtime_error
{
public:
explicit UnknownROSArgsError(std::vector<std::string> && unknown_ros_args_in)
: std::runtime_error(
"found unknown ROS arguments: '" + rcpputils::join(unknown_ros_args_in, "', '") + "'"),
unknown_ros_args(unknown_ros_args_in)
{
}
const std::vector<std::string> unknown_ros_args;
};
/// Thrown when an invalid rclcpp::Event object or SharedPtr is encountered.
class InvalidEventError : public std::runtime_error
{
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") {}
};
/// Thrown if passed parameters are inconsistent or invalid
class InvalidParametersException : public std::runtime_error
{
public:
// Inherit constructors from runtime_error.
using std::runtime_error::runtime_error;
};
/// Thrown if passed parameter value is invalid.
class InvalidParameterValueException : public std::runtime_error
{
// Inherit constructors from runtime_error.
using std::runtime_error::runtime_error;
};
/// Thrown if parameter is already declared.
class ParameterAlreadyDeclaredException : public std::runtime_error
{
// Inherit constructors from runtime_error.
using std::runtime_error::runtime_error;
};
/// Thrown if parameter is not declared, e.g. either set or get was called without first declaring.
class ParameterNotDeclaredException : public std::runtime_error
{
// Inherit constructors from runtime_error.
using std::runtime_error::runtime_error;
};
/// Thrown if parameter is immutable and therefore cannot be undeclared.
class ParameterImmutableException : public std::runtime_error
{
// Inherit constructors from runtime_error.
using std::runtime_error::runtime_error;
};
/// Thrown if parameter is modified while in a set callback.
class ParameterModifiedInCallbackException : public std::runtime_error
{
// Inherit constructors from runtime_error.
using std::runtime_error::runtime_error;
};
} // namespace exceptions
} // namespace rclcpp
#endif // RCLCPP__EXCEPTIONS_HPP_

View File

@@ -1,279 +0,0 @@
// 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__EXCEPTIONS__EXCEPTIONS_HPP_
#define RCLCPP__EXCEPTIONS__EXCEPTIONS_HPP_
#include <stdexcept>
#include <string>
#include <vector>
#include "rcl/error_handling.h"
#include "rcl/types.h"
#include "rclcpp/visibility_control.hpp"
#include "rcpputils/join.hpp"
namespace rclcpp
{
namespace exceptions
{
/// Thrown when a method is trying to use a node, but it is invalid.
class InvalidNodeError : public std::runtime_error
{
public:
InvalidNodeError()
: std::runtime_error("node is invalid") {}
};
/// Thrown when a any kind of name (node, namespace, topic, etc.) is invalid.
class NameValidationError : public std::invalid_argument
{
public:
NameValidationError(
const char * name_type_,
const char * name_,
const char * error_msg_,
size_t invalid_index_)
: std::invalid_argument(format_error(name_type_, name_, error_msg_, invalid_index_)),
name_type(name_type_), name(name_), error_msg(error_msg_), invalid_index(invalid_index_)
{}
static std::string
format_error(
const char * name_type,
const char * name,
const char * error_msg,
size_t invalid_index);
const std::string name_type;
const std::string name;
const std::string error_msg;
const size_t invalid_index;
};
/// Thrown when a node name is invalid.
class InvalidNodeNameError : public NameValidationError
{
public:
InvalidNodeNameError(const char * node_name, const char * error_msg, size_t invalid_index)
: NameValidationError("node name", node_name, error_msg, invalid_index)
{}
};
/// Thrown when a node namespace is invalid.
class InvalidNamespaceError : public NameValidationError
{
public:
InvalidNamespaceError(const char * namespace_, const char * error_msg, size_t invalid_index)
: NameValidationError("namespace", namespace_, error_msg, invalid_index)
{}
};
/// Thrown when a topic name is invalid.
class InvalidTopicNameError : public NameValidationError
{
public:
InvalidTopicNameError(const char * namespace_, const char * error_msg, size_t invalid_index)
: NameValidationError("topic name", namespace_, error_msg, invalid_index)
{}
};
/// Thrown when a service name is invalid.
class InvalidServiceNameError : public NameValidationError
{
public:
InvalidServiceNameError(const char * namespace_, const char * error_msg, size_t invalid_index)
: NameValidationError("service name", namespace_, error_msg, invalid_index)
{}
};
/// Throw a C++ std::exception which was created based on an rcl error.
/**
* Passing nullptr for reset_error is safe and will avoid calling any function
* to reset the error.
*
* \param ret the return code for the current error state
* \param prefix string to prefix to the error if applicable (not all errors have custom messages)
* \param error_state error state to create exception from, if nullptr rcl_get_error_state is used
* \param reset_error function to be called before throwing which whill clear the error state
* \throws std::invalid_argument if ret is RCL_RET_OK
* \throws std::runtime_error if the rcl_get_error_state returns 0
* \throws RCLErrorBase some child class exception based on ret
*/
/* *INDENT-OFF* */ // Uncrustify cannot yet understand [[noreturn]] properly
RCLCPP_PUBLIC
void
throw_from_rcl_error [[noreturn]] (
rcl_ret_t ret,
const std::string & prefix = "",
const rcl_error_state_t * error_state = nullptr,
void (* reset_error)() = rcl_reset_error);
/* *INDENT-ON* */
class RCLErrorBase
{
public:
RCLCPP_PUBLIC
RCLErrorBase(rcl_ret_t ret, const rcl_error_state_t * error_state);
virtual ~RCLErrorBase() {}
rcl_ret_t ret;
std::string message;
std::string file;
size_t line;
std::string formatted_message;
};
/// Created when the return code does not match one of the other specialized exceptions.
class RCLError : public RCLErrorBase, public std::runtime_error
{
public:
RCLCPP_PUBLIC
RCLError(rcl_ret_t ret, const rcl_error_state_t * error_state, const std::string & prefix);
RCLCPP_PUBLIC
RCLError(const RCLErrorBase & base_exc, const std::string & prefix);
};
/// Created when the ret is RCL_RET_BAD_ALLOC.
class RCLBadAlloc : public RCLErrorBase, public std::bad_alloc
{
public:
RCLCPP_PUBLIC
RCLBadAlloc(rcl_ret_t ret, const rcl_error_state_t * error_state);
RCLCPP_PUBLIC
explicit RCLBadAlloc(const RCLErrorBase & base_exc);
};
/// Created when the ret is RCL_RET_INVALID_ARGUMENT.
class RCLInvalidArgument : public RCLErrorBase, public std::invalid_argument
{
public:
RCLCPP_PUBLIC
RCLInvalidArgument(
rcl_ret_t ret,
const rcl_error_state_t * error_state,
const std::string & prefix);
RCLCPP_PUBLIC
RCLInvalidArgument(const RCLErrorBase & base_exc, const std::string & prefix);
};
/// Created when the ret is RCL_RET_INVALID_ROS_ARGS.
class RCLInvalidROSArgsError : public RCLErrorBase, public std::runtime_error
{
public:
RCLCPP_PUBLIC
RCLInvalidROSArgsError(
rcl_ret_t ret, const rcl_error_state_t * error_state, const std::string & prefix);
RCLCPP_PUBLIC
RCLInvalidROSArgsError(const RCLErrorBase & base_exc, const std::string & prefix);
};
/// Thrown when unparsed ROS specific arguments are found.
class UnknownROSArgsError : public std::runtime_error
{
public:
explicit UnknownROSArgsError(std::vector<std::string> && unknown_ros_args_in)
: std::runtime_error(
"found unknown ROS arguments: '" + rcpputils::join(unknown_ros_args_in, "', '") + "'"),
unknown_ros_args(unknown_ros_args_in)
{
}
const std::vector<std::string> unknown_ros_args;
};
/// Thrown when an invalid rclcpp::Event object or SharedPtr is encountered.
class InvalidEventError : public std::runtime_error
{
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") {}
};
/// Thrown if passed parameters are inconsistent or invalid
class InvalidParametersException : public std::runtime_error
{
public:
// Inherit constructors from runtime_error.
using std::runtime_error::runtime_error;
};
/// Thrown if passed parameter value is invalid.
class InvalidParameterValueException : public std::runtime_error
{
// Inherit constructors from runtime_error.
using std::runtime_error::runtime_error;
};
/// Thrown if requested parameter type is invalid.
/**
* Essentially the same as rclcpp::ParameterTypeException, but with parameter
* name in the error message.
*/
class InvalidParameterTypeException : public std::runtime_error
{
public:
/// Construct an instance.
/**
* \param[in] name the name of the parameter.
* \param[in] message custom exception message.
*/
RCLCPP_PUBLIC
InvalidParameterTypeException(const std::string & name, const std::string message)
: std::runtime_error("parameter '" + name + "' has invalid type: " + message)
{}
};
/// Thrown if parameter is already declared.
class ParameterAlreadyDeclaredException : public std::runtime_error
{
// Inherit constructors from runtime_error.
using std::runtime_error::runtime_error;
};
/// Thrown if parameter is not declared, e.g. either set or get was called without first declaring.
class ParameterNotDeclaredException : public std::runtime_error
{
// Inherit constructors from runtime_error.
using std::runtime_error::runtime_error;
};
/// Thrown if parameter is immutable and therefore cannot be undeclared.
class ParameterImmutableException : public std::runtime_error
{
// Inherit constructors from runtime_error.
using std::runtime_error::runtime_error;
};
/// Thrown if parameter is modified while in a set callback.
class ParameterModifiedInCallbackException : public std::runtime_error
{
// Inherit constructors from runtime_error.
using std::runtime_error::runtime_error;
};
} // namespace exceptions
} // namespace rclcpp
#endif // RCLCPP__EXCEPTIONS__EXCEPTIONS_HPP_

View File

@@ -29,277 +29,151 @@
#include "rcl/guard_condition.h"
#include "rcl/wait.h"
#include "rclcpp/callback_group.hpp"
#include "rclcpp/executor_options.hpp"
#include "rclcpp/executor_policies/timer_favoring_priority_queue.hpp"
#include "rclcpp/future_return_code.hpp"
#include "rclcpp/guard_condition.hpp"
#include "rclcpp/contexts/default_context.hpp"
#include "rclcpp/memory_strategies.hpp"
#include "rclcpp/memory_strategy.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/utilities.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rclcpp/wait_set.hpp"
namespace rclcpp
{
// Forward declaration is used in convenience method signature.
class Node;
/// Base class for Executor providing the common interface for adding items, spinning, etc.
class ExecutorBase
namespace executor
{
/// Return codes to be used with spin_until_future_complete.
/**
* SUCCESS: The future is complete and can be accessed with "get" without blocking.
* This does not indicate that the operation succeeded; "get" may still throw an exception.
* INTERRUPTED: The future is not complete, spinning was interrupted by Ctrl-C or another error.
* TIMEOUT: Spinning timed out.
*/
enum class FutureReturnCode { SUCCESS, INTERRUPTED, TIMEOUT };
RCLCPP_PUBLIC
std::ostream & operator<<(std::ostream & os, const FutureReturnCode & future_return_code);
RCLCPP_PUBLIC
std::string to_string(const FutureReturnCode & future_return_code);
///
/**
* Options to be passed to the executor constructor.
*/
struct ExecutorArgs
{
ExecutorArgs()
: memory_strategy(memory_strategies::create_default_strategy()),
context(rclcpp::contexts::default_context::get_global_default_context()),
max_conditions(0)
{
}
memory_strategy::MemoryStrategy::SharedPtr memory_strategy;
std::shared_ptr<rclcpp::Context> context;
size_t max_conditions;
};
static inline ExecutorArgs create_default_executor_arguments() { return ExecutorArgs(); }
/// Coordinate the order and timing of available communication tasks.
/**
* Executor provides spin functions (including spin_node_once and spin_some).
* It coordinates the nodes and callback groups by looking for available work and completing it,
* based on the threading or concurrency scheme provided by the subclass implementation.
* An example of available work is executing a subscription callback, or a timer callback.
* The executor structure allows for a decoupling of the communication graph and the execution
* model.
* See SingleThreadedExecutor and MultiThreadedExecutor for examples of execution paradigms.
*/
class Executor
{
public:
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(ExecutorBase)
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(Executor)
/// Default constructor.
/**
* \param[in] options Options for the executor.
*/
// \param[in] ms The memory strategy to be used with this executor.
RCLCPP_PUBLIC
explicit ExecutorBase(const ExecutorOptions & options = ExecutorOptions());
explicit Executor(const ExecutorArgs & args = ExecutorArgs());
/// Default destructor.
RCLCPP_PUBLIC
virtual ~ExecutorBase();
virtual ~Executor();
/// Execution loop which waits for work, executes work, and repeats until canceled.
/// Do work periodically as it becomes available to us. Blocking call, may block indefinitely.
// It is up to the implementation of Executor to implement spin.
virtual void spin() = 0;
/// Add a node to the executor.
/**
* This will block, continuing to wait for work and then execute it, until
* canceled, either by the cancel() method or by the associated context being
* shutdown, either explicitly or due to a SIGINT (perhaps due to ctrl-c).
*/
virtual
void
spin() = 0;
/// Add all of a node's callback groups to the executor.
/**
* Add all of the callback groups of a node to this executor.
*
* If any callback groups are associated with another executor, this method
* will throw a std::runtime_error.
*
* It will also trigger the interrupt guard condition which will cause the
* executor to wake up and consider the changes, then go back to waiting.
* Unless the notify parameter is passed false, in which case it will not
* interrupt the executor, and the changes may not be considered immediately.
*
* \param[in] node_ptr Shared pointer to the node which will have callback groups added.
* \param[in] notify If true, notfiy the executor of changes, otherwise do not.
* \throws std::runtime_error if any callback groups are associated with another executor.
*/
template<class NodeT>
void
add_node(const std::shared_ptr<NodeT> & node_ptr, bool notify = true)
{
this->add_node(
node_ptr->get_node_base_interface(),
notify,
false // raise on encountering already associated callback groups
);
}
/// Overload that takes the NodeBaseInterface directly.
template<class NodeT>
void
add_node(
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr & node_ptr,
bool notify = true)
{
this->add_node(
node_ptr,
notify,
false // raise on encountering already associated callback groups
);
}
/// Add all unassociated callback groups of the given node to this executor.
/**
* Same as add_node(), but instead of throwing if a callback group is already
* associated with another exector (already added to it) it will just ignore
* it rather than throwing.
*
* \param[in] node_ptr Shared pointer to the node which will have callback groups added.
* \param[in] notify If true, notfiy the executor of changes, otherwise do not.
*/
template<class NodeT>
void
add_unassociated_callback_groups_from_node(
const std::shared_ptr<NodeT> & node_ptr,
bool notify = true)
{
this->add_node(
node_ptr->get_node_base_interface(),
notify,
true // ignore already associated callback groups
);
}
/// Overload that takes the NodeBaseInterface directly.
template<class NodeT>
void
add_unassociated_callback_groups_from_node(
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr & node_ptr,
bool notify = true)
{
this->add_node(
node_ptr,
notify,
true // ignore already associated callback groups
);
}
/// Remove all of a node's callback groups from the executor.
/**
* Remove all of the callback groups of a node from this executor.
*
* It will also trigger the interrupt guard condition which will cause the
* executor to wake up and consider the changes, then go back to waiting.
* Unless the notify parameter is passed false, in which case it will not
* interrupt the executor, and the changes may not be considered immediately.
*
* \param[in] node Node which will have callback groups removed.
* \param[in] notify If true, notfiy the executor of changes, otherwise do not.
*/
template<class NodeT>
void
remove_node(const NodeT & node, bool notify = true)
{
this->remove_node(*node.get_node_base_interface(), notify);
}
/// Overload that takes a shared pointer to the node.
/**
* This is kept for backwards compatibility from when executors shared
* ownership of Nodes.
*/
template<class NodeT>
void
remove_node(const std::shared_ptr<NodeT> & node_ptr, bool notify = true)
{
this->remove_node(*node_ptr->get_node_base_interface(), notify);
}
/// Placeholder used to indicate that a method overload should not notify the executor.
struct DoNotNotify {};
/// Add a callback group to this executor.
/**
* If the given callback group is already associated with another executor,
* this method will throw a std::runtime_error.
*
* This overload of add_callback_group() will notify the executor so it will
* wake up if waiting and consider the changes.
*
* Weak ownership of the callback group is kept by the executor all of the
* time, but while waiting the weak ownership is periodically elevated to
* shared ownership.
* Therefore, if you let the callback group shared pointer go out of scope
* then it will stay in scope until this executor is done using it, at which
* point the callback group will be destructed and automatically removed from
* this executor in the next pass.
*
* \param[in] callback_group_ptr The callback group to be added.
* \throws std::runtime_error if the callback group is associated with another
* executor already.
* \throws std::invalid_argument if the callback group pointer is nullptr.
* An executor can have zero or more nodes which provide work during `spin` functions.
* \param[in] node_ptr Shared pointer to the node to be added.
* \param[in] notify True to trigger the interrupt guard condition during this function. If
* the executor is blocked at the rmw layer while waiting for work and it is notified that a new
* node was added, it will wake up.
*/
RCLCPP_PUBLIC
virtual
void
add_callback_group(rclcpp::CallbackGroup::SharedPtr callback_group_ptr) = 0;
virtual void add_node(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr, bool notify = true);
/// Add a callback group to this executor without notifying the executor.
/// Convenience function which takes Node and forwards NodeBaseInterface.
RCLCPP_PUBLIC
virtual void add_node(std::shared_ptr<rclcpp::Node> node_ptr, bool notify = true);
/// Remove a node from the executor.
/**
* The same as the other overload of add_callback_group(), except it does not
* notify the executor, so it will not wake up and these changes may not be
* considered immediately.
*
* Note, a bool with a default value would be preferable for controlling the
* notify behavior, and we're using it in the add/remove node above, but
* in order to keep this function virtual, and to avoid using default values
* in conjunction with virtual methods, we use an overload instead, in the
* spirit of std::nothrow_t, e.g.:
* https://en.cppreference.com/w/cpp/memory/new/nothrow
* \param[in] node_ptr Shared pointer to the node to remove.
* \param[in] notify True to trigger the interrupt guard condition and wake up the executor.
* This is useful if the last node was removed from the executor while the executor was blocked
* waiting for work in another thread, because otherwise the executor would never be notified.
*/
RCLCPP_PUBLIC
virtual
void
add_callback_group(rclcpp::CallbackGroup::SharedPtr callback_group_ptr, DoNotNotify) = 0;
virtual void remove_node(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr, bool notify = true);
/// Remove a callback group from this executor.
/**
* If the given callback group is not associated with this executor, this
* method will throw a std::runtime_error.
*
* This overload of add_callback_group() will notify the executor so it will
* wake up if waiting and consider the changes.
*
* \param[in] callback_group The callback group to be removed.
* \throws std::runtime_error if the callback group is not associated with
* this executor.
* \throws std::invalid_argument if the callback group pointer is nullptr.
*/
/// Convenience function which takes Node and forwards NodeBaseInterface.
RCLCPP_PUBLIC
virtual
void
remove_callback_group(const rclcpp::CallbackGroup & callback_group) = 0;
/// Remove a callback group from this executor without notifying the executor.
/**
* The same as the other overload of remove_callback_group(), except it does not
* notify the executor, so it will not wake up and these changes may not be
* considered immediately.
*
* See add_callback_group() for a note about the use of DoNotNotify.
*/
RCLCPP_PUBLIC
virtual
void
remove_callback_group(const rclcpp::CallbackGroup & callback_group, DoNotNotify) = 0;
virtual void remove_node(std::shared_ptr<rclcpp::Node> node_ptr, bool notify = true);
/// Add a node to executor, execute the next available unit of work, and remove the node.
/**
* \param[in] node Shared pointer to the node to add.
* \param[in] timeout How long to wait for work to become available.
* Negative values cause spin_node_once to block indefinitely (the default
* behavior).
* A timeout of 0 causes this function to be non-blocking.
* \param[in] timeout How long to wait for work to become available. Negative values cause
* spin_node_once to block indefinitely (the default behavior). A timeout of 0 causes this
* function to be non-blocking.
*/
template<typename RepT = int64_t, typename T = std::milli>
void
spin_node_once(
template <typename RepT = int64_t, typename T = std::milli>
void spin_node_once(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node,
std::chrono::duration<RepT, T> timeout = std::chrono::duration<RepT, T>(-1))
{
return spin_node_once_nanoseconds(
node,
std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
);
node, std::chrono::duration_cast<std::chrono::nanoseconds>(timeout));
}
/// Convenience function which takes Node and forwards NodeBaseInterface.
template<typename NodeT, typename RepT = int64_t, typename T = std::milli>
void
spin_node_once(
template <typename NodeT = rclcpp::Node, typename RepT = int64_t, typename T = std::milli>
void spin_node_once(
std::shared_ptr<NodeT> node,
std::chrono::duration<RepT, T> timeout = std::chrono::duration<RepT, T>(-1))
{
return spin_node_once_nanoseconds(
node->get_node_base_interface(),
std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
);
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 spin some.
* \param[in] node Shared pointer to the node to add.
*/
template<class NodeT>
void
spin_node_some(const std::shared_ptr<NodeT> & node)
{
this->spin_node_some(node->get_node_base_interface());
}
RCLCPP_PUBLIC
void 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);
/// Complete all available queued work without blocking.
/**
@@ -313,14 +187,10 @@ public:
* been exceeded.
*/
RCLCPP_PUBLIC
virtual
void
spin_some(std::chrono::nanoseconds max_duration = std::chrono::nanoseconds(0)) = 0;
virtual void spin_some(std::chrono::nanoseconds max_duration = std::chrono::nanoseconds(0));
RCLCPP_PUBLIC
virtual
void
spin_once(std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1)) = 0;
virtual void spin_once(std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));
/// Spin (blocking) until the future is complete, it times out waiting, or rclcpp is interrupted.
/**
@@ -332,10 +202,9 @@ public:
* code.
* \return The return code, one of `SUCCESS`, `INTERRUPTED`, or `TIMEOUT`.
*/
template<typename ResponseT, typename TimeRepT = int64_t, typename TimeT = std::milli>
FutureReturnCode
spin_until_future_complete(
const std::shared_future<ResponseT> & future,
template <typename ResponseT, typename TimeRepT = int64_t, typename TimeT = std::milli>
FutureReturnCode spin_until_future_complete(
std::shared_future<ResponseT> & future,
std::chrono::duration<TimeRepT, TimeT> timeout = std::chrono::duration<TimeRepT, TimeT>(-1))
{
// TODO(wjwwood): does not work recursively; can't call spin_node_until_future_complete
@@ -349,8 +218,8 @@ public:
}
auto end_time = std::chrono::steady_clock::now();
std::chrono::nanoseconds timeout_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(
timeout);
std::chrono::nanoseconds timeout_ns =
std::chrono::duration_cast<std::chrono::nanoseconds>(timeout);
if (timeout_ns > std::chrono::nanoseconds::zero()) {
end_time += timeout_ns;
}
@@ -382,183 +251,93 @@ public:
}
/// Cancel any running spin* function, causing it to return.
/* This function can be called asynchonously from any thread. */
RCLCPP_PUBLIC
void cancel();
/// Support dynamic switching of the memory strategy.
/**
* This function can be called asynchronously from any thread.
* Switching the memory strategy while the executor is spinning in another threading could have
* unintended consequences.
* \param[in] memory_strategy Shared pointer to the memory strategy to set.
*/
RCLCPP_PUBLIC
virtual
void
cancel() = 0;
void set_memory_strategy(memory_strategy::MemoryStrategy::SharedPtr memory_strategy);
protected:
/// Implementation of add_node().
/**
* \param[in] node_ptr The node which will have its callback groups added.
* \param[in] notify If true, the executor is interrupted to consider the
* changes, otherwise it is not interrupted.
* \param[in] ignore_associated_callback_groups If true, then when a callback
* group which is already been added to another executor is encountered
* it will be ignored, if false then std::runtime_error is thrown instead.
* \throws std::runtime_error if ignore_associated_callback_groups is false
* and a callback group which is already associated with another executor
* is encountered.
* \throws std::invalid_argument if node_ptr is nullptr.
*/
RCLCPP_PUBLIC
virtual
void
add_node(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
bool notify,
bool ignore_associated_callback_groups) = 0;
RCLCPP_PUBLIC
virtual
void
remove_node(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr, bool notify) = 0;
RCLCPP_PUBLIC
void
spin_node_once_nanoseconds(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node,
std::chrono::nanoseconds timeout);
RCLCPP_PUBLIC
virtual
void
spin_node_some(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node);
void 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,
* service, client).
*/
RCLCPP_PUBLIC
void
execute_any_executable(rclcpp::AnyExecutable & any_exec);
void execute_any_executable(AnyExecutable & any_exec);
RCLCPP_PUBLIC
static
void
execute_subscription(
rclcpp::SubscriptionBase::SharedPtr subscription);
static void execute_subscription(rclcpp::SubscriptionBase::SharedPtr subscription);
RCLCPP_PUBLIC
static
void
execute_timer(rclcpp::TimerBase::SharedPtr timer);
static void execute_intra_process_subscription(rclcpp::SubscriptionBase::SharedPtr subscription);
RCLCPP_PUBLIC
static
void
execute_service(rclcpp::ServiceBase::SharedPtr service);
static void execute_timer(rclcpp::TimerBase::SharedPtr timer);
RCLCPP_PUBLIC
static
void
execute_client(rclcpp::ClientBase::SharedPtr client);
static void execute_service(rclcpp::ServiceBase::SharedPtr service);
RCLCPP_PUBLIC
void
wait_for_work(std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));
static void execute_client(rclcpp::ClientBase::SharedPtr client);
RCLCPP_PUBLIC
rclcpp::CallbackGroup::SharedPtr
get_group_by_timer(rclcpp::TimerBase::SharedPtr timer);
void wait_for_work(std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));
RCLCPP_PUBLIC
bool
get_next_ready_executable(rclcpp::AnyExecutable & any_executable);
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr get_node_by_group(
rclcpp::callback_group::CallbackGroup::SharedPtr group);
RCLCPP_PUBLIC
bool
get_next_executable(
rclcpp::AnyExecutable & any_executable,
rclcpp::callback_group::CallbackGroup::SharedPtr get_group_by_timer(
rclcpp::TimerBase::SharedPtr timer);
RCLCPP_PUBLIC
void get_next_timer(AnyExecutable & any_exec);
RCLCPP_PUBLIC
bool get_next_ready_executable(AnyExecutable & any_executable);
RCLCPP_PUBLIC
bool get_next_executable(
AnyExecutable & any_executable,
std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));
RCLCPP_DISABLE_COPY(ExecutorBase)
/// Spinning state, used to prevent multi threaded calls to spin and to cancel blocking spins.
std::atomic_bool spinning;
/// Guard condition for signaling the rmw layer to wake up for special events.
rclcpp::GuardCondition interrupt_guard_condition_;
// rcl_guard_condition_t interrupt_guard_condition_ = rcl_get_zero_initialized_guard_condition();
rcl_guard_condition_t interrupt_guard_condition_ = rcl_get_zero_initialized_guard_condition();
// /// Wait set for managing entities that the rmw layer waits on.
// rcl_wait_set_t wait_set_ = rcl_get_zero_initialized_wait_set();
/// Wait set for managing entities that the rmw layer waits on.
rcl_wait_set_t wait_set_ = rcl_get_zero_initialized_wait_set();
// // Mutex to protect the subsequent memory_strategy_.
// std::mutex memory_strategy_mutex_;
// Mutex to protect the subsequent memory_strategy_.
std::mutex memory_strategy_mutex_;
// /// The memory strategy: an interface for handling user-defined memory allocation strategies.
// memory_strategy::MemoryStrategy::SharedPtr memory_strategy_;
/// The memory strategy: an interface for handling user-defined memory allocation strategies.
memory_strategy::MemoryStrategy::SharedPtr memory_strategy_;
/// The context associated with this executor.
rclcpp::Context::SharedPtr context_;
std::shared_ptr<rclcpp::Context> context_;
// std::list<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr> weak_nodes_;
// std::list<const rcl_guard_condition_t *> guard_conditions_;
std::vector<rclcpp::CallbackGroup::WeakPtr> weak_guard_conditions_;
private:
RCLCPP_DISABLE_COPY(Executor)
std::list<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr> weak_nodes_;
std::list<const rcl_guard_condition_t *> guard_conditions_;
};
/// Template class which serves as the foundation of actual executors.
/**
* This class combines the wait set, scheduling policy, and the ExecutorBase
* class, and implements all of the pure virtual functions of ExecutorBase
* making it a concrete class.
*/
template<class WaitSetT, class SchedulingPolicy>
class ExecutorTemplate : public ExecutorBase, public SchedulingPolicy
{
public:
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(ExecutorTemplate)
/// Default constructor.
/**
* \param[in] options Options for the executor.
*/
explicit ExecutorTemplate(const ExecutorOptions & options = ExecutorOptions())
: ExecutorBase(options), SchedulingPolicy(options), WaitSetT(options.context)
{}
/// Default virtual destructor.
RCLCPP_PUBLIC
virtual
~ExecutorTemplate() = default;
protected:
WaitSetT wait_set_;
};
/// Executor concept which waits for work and coordinates execution of user callbacks.
/**
* Executor provides spin functions (including spin_node_once and spin_some).
* It coordinates the nodes and callback groups by looking for available work
* and completing it, based on the threading or concurrency scheme provided by
* the subclass implementation.
* An example of available work is executing a subscription callback, or a
* timer callback.
* The executor structure allows for a decoupling of the communication graph
* and the execution model.
* See SingleThreadedExecutor and MultiThreadedExecutor for examples of
* different execution paradigms.
*
* By default this alias provides a foundation based on specific wait set type
* and a scheduling policy.
* The wait set is expected to be dynamic, i.e. items can be added or removed
* after creation, and thread-safe, i.e. items can be added or removed while
* also waiting concurrently.
*/
using Executor = ExecutorTemplate<
rclcpp::ThreadSafeWaitSet,
rclcpp::executor_policies::TimerFavoringPriorityQueue>;
namespace executor
{
using Executor [[deprecated("use rclcpp::Executor instead")]] = Executor;
} // namespace executor
} // namespace rclcpp

View File

@@ -1,49 +0,0 @@
// Copyright 2014 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__EXECUTOR_OPTIONS_HPP_
#define RCLCPP__EXECUTOR_OPTIONS_HPP_
#include "rclcpp/context.hpp"
#include "rclcpp/contexts/default_context.hpp"
#include "rclcpp/memory_strategies.hpp"
#include "rclcpp/memory_strategy.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
/// Options to be passed to the executor constructor.
struct ExecutorOptions
{
ExecutorOptions()
: memory_strategy(rclcpp::memory_strategies::create_default_strategy()),
context(rclcpp::contexts::get_global_default_context()),
max_conditions(0)
{}
rclcpp::memory_strategy::MemoryStrategy::SharedPtr memory_strategy;
rclcpp::Context::SharedPtr context;
size_t max_conditions;
};
namespace executor
{
using ExecutorArgs [[deprecated("use rclcpp::ExecutorOptions instead")]] = ExecutorOptions;
} // namespace executor
} // namespace rclcpp
#endif // RCLCPP__EXECUTOR_OPTIONS_HPP_

View File

@@ -1,35 +0,0 @@
// Copyright 2020 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__EXECUTOR_POLICIES__SCHEDULING_RESULT_HPP_
#define RCLCPP__EXECUTOR_POLICIES__SCHEDULING_RESULT_HPP_
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
namespace executor_policies
{
/// Represents the directions a SchedulingPolicy can give to an Executor.
enum RCLCPP_PUBLIC SchedulingResult
{
ContinueExecuting, //<! Indicates more work should be done before waiting.
WaitForWork, //<! Indicates that the executor should wait on the wait set again.
};
} // namespace executor_policies
} // namespace rclcpp
#endif // RCLCPP__EXECUTOR_POLICIES__SCHEDULING_RESULT_HPP_

View File

@@ -1,77 +0,0 @@
// Copyright 2020 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__EXECUTOR_POLICIES__TIMER_FAVORING_PRIORITY_QUEUE_HPP_
#define RCLCPP__EXECUTOR_POLICIES__TIMER_FAVORING_PRIORITY_QUEUE_HPP_
#include "rclcpp/any_executable.hpp"
#include "rclcpp/executor_options.hpp"
#include "rclcpp/executor_policies/scheduling_result.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rclcpp/wait_result.hpp"
namespace rclcpp
{
namespace executor_policies
{
/// A naive scheduling policy which selects Timers first, then Subscriptions and other items.
/**
* Items are executed in the order they were added, favoring Timers, then
* Subscriptions, Service Servers, Service Clients, and finally Waitables.
* All Timers are executed before any Subscriptions, and all Subscriptions
* before any Service Servers, and so on.
*
* User guard conditions are not yet supported by the Executor and so all guard
* condition are used by the executor itself and are handled before this policy
* is consulted.
* Therefore, guard conditions are ignored for the purposes of scheduling.
*
* This is a naive policy, but is the default until a better one is implemented.
*/
class TimerFavoringPriorityQueue
{
public:
explicit TimerFavoringPriorityQueue(const rclcpp::ExecutorOptions &) {}
/// Select which item should next be executed, and indicate if waiting should resume.
/**
* Selects which item to be executed next, assign it to the any_executable, or
* assigning nullptr if no work should be done right now.
*
* This method is called by the executor after waiting on a wait set, in
* order to determine what to execute next based on the result.
*
* Additionally, if returning SchedulingResult::ContinueExecuting then the
* executor will call this function again without waiting on the wait set, or
* if returning SchedulingResult::WaitForWork then the executor will wait on
* the wait set again after executing the selected any_executable, or
* immediately if any_executable was assigned nullptr.
*/
template<class WaitSetT>
rclcpp::executor_policies::SchedulingResult
schedule_next_any_executable(
const WaitResult<WaitSetT> & wait_result,
rclcpp::AnyExecutable & any_executable)
{
// Explicitly ignore guard conditions.
// Check Timers for being ready.
}
};
} // namespace executor_policies
} // namespace rclcpp
#endif // RCLCPP__EXECUTOR_POLICIES__TIMER_FAVORING_PRIORITY_QUEUE_HPP_

View File

@@ -20,37 +20,30 @@
#include "rclcpp/executors/multi_threaded_executor.hpp"
#include "rclcpp/executors/single_threaded_executor.hpp"
#include "rclcpp/executors/static_single_threaded_executor.hpp"
#include "rclcpp/node.hpp"
#include "rclcpp/utilities.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
/// Create a default single-threaded executor and execute any immediately available work.
/** \param[in] node_ptr Shared pointer to the node to spin. */
RCLCPP_PUBLIC
void
spin_some(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr);
void spin_some(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr);
RCLCPP_PUBLIC
void
spin_some(rclcpp::Node::SharedPtr node_ptr);
void spin_some(rclcpp::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(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr);
void spin(rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr);
RCLCPP_PUBLIC
void
spin(rclcpp::Node::SharedPtr node_ptr);
void spin(rclcpp::Node::SharedPtr node_ptr);
namespace executors
{
using rclcpp::executors::MultiThreadedExecutor;
using rclcpp::executors::SingleThreadedExecutor;
@@ -66,12 +59,11 @@ using rclcpp::executors::SingleThreadedExecutor;
* If the time spent inside the blocking loop exceeds this timeout, return a `TIMEOUT` return code.
* \return The return code, one of `SUCCESS`, `INTERRUPTED`, or `TIMEOUT`.
*/
template<typename ResponseT, typename TimeRepT = int64_t, typename TimeT = std::milli>
rclcpp::FutureReturnCode
spin_node_until_future_complete(
rclcpp::Executor & executor,
template <typename ResponseT, typename TimeRepT = int64_t, typename TimeT = std::milli>
rclcpp::executor::FutureReturnCode spin_node_until_future_complete(
rclcpp::executor::Executor & executor,
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
const std::shared_future<ResponseT> & future,
std::shared_future<ResponseT> & future,
std::chrono::duration<TimeRepT, TimeT> timeout = std::chrono::duration<TimeRepT, TimeT>(-1))
{
// TODO(wjwwood): does not work recursively; can't call spin_node_until_future_complete
@@ -82,41 +74,41 @@ spin_node_until_future_complete(
return retcode;
}
template<typename NodeT = rclcpp::Node, typename ResponseT, typename TimeRepT = int64_t,
template <
typename NodeT = rclcpp::Node,
typename ResponseT,
typename TimeRepT = int64_t,
typename TimeT = std::milli>
rclcpp::FutureReturnCode
spin_node_until_future_complete(
rclcpp::Executor & executor,
rclcpp::executor::FutureReturnCode spin_node_until_future_complete(
rclcpp::executor::Executor & executor,
std::shared_ptr<NodeT> node_ptr,
const std::shared_future<ResponseT> & future,
std::shared_future<ResponseT> & future,
std::chrono::duration<TimeRepT, TimeT> timeout = std::chrono::duration<TimeRepT, TimeT>(-1))
{
return rclcpp::executors::spin_node_until_future_complete(
executor,
node_ptr->get_node_base_interface(),
future,
timeout);
executor, node_ptr->get_node_base_interface(), future, timeout);
}
} // namespace executors
template<typename FutureT, typename TimeRepT = int64_t, typename TimeT = std::milli>
rclcpp::FutureReturnCode
spin_until_future_complete(
template <typename FutureT, typename TimeRepT = int64_t, typename TimeT = std::milli>
rclcpp::executor::FutureReturnCode spin_until_future_complete(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
const std::shared_future<FutureT> & future,
std::shared_future<FutureT> & future,
std::chrono::duration<TimeRepT, TimeT> timeout = std::chrono::duration<TimeRepT, TimeT>(-1))
{
rclcpp::executors::SingleThreadedExecutor executor;
return executors::spin_node_until_future_complete<FutureT>(executor, node_ptr, future, timeout);
}
template<typename NodeT = rclcpp::Node, typename FutureT, typename TimeRepT = int64_t,
template <
typename NodeT = rclcpp::Node,
typename FutureT,
typename TimeRepT = int64_t,
typename TimeT = std::milli>
rclcpp::FutureReturnCode
spin_until_future_complete(
rclcpp::executor::FutureReturnCode spin_until_future_complete(
std::shared_ptr<NodeT> node_ptr,
const std::shared_future<FutureT> & future,
std::shared_future<FutureT> & future,
std::chrono::duration<TimeRepT, TimeT> timeout = std::chrono::duration<TimeRepT, TimeT>(-1))
{
return rclcpp::spin_until_future_complete(node_ptr->get_node_base_interface(), future, timeout);

View File

@@ -31,8 +31,7 @@ namespace rclcpp
{
namespace executors
{
class MultiThreadedExecutor : public rclcpp::Executor
class MultiThreadedExecutor : public executor::Executor
{
public:
RCLCPP_SMART_PTR_DEFINITIONS(MultiThreadedExecutor)
@@ -45,14 +44,14 @@ public:
* This is useful for reproducing some bugs related to taking work more than
* once.
*
* \param options common options for all executors
* \param args common arguments for all executors
* \param number_of_threads number of threads to have in the thread pool,
* the default 0 will use the number of cpu cores found instead
* \param yield_before_execute if true std::this_thread::yield() is called
*/
RCLCPP_PUBLIC
MultiThreadedExecutor(
const rclcpp::ExecutorOptions & options = rclcpp::ExecutorOptions(),
const executor::ExecutorArgs & args = executor::ExecutorArgs(),
size_t number_of_threads = 0,
bool yield_before_execute = false,
std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));
@@ -61,17 +60,14 @@ public:
virtual ~MultiThreadedExecutor();
RCLCPP_PUBLIC
void
spin() override;
void spin();
RCLCPP_PUBLIC
size_t
get_number_of_threads();
size_t get_number_of_threads();
protected:
RCLCPP_PUBLIC
void
run(size_t this_thread_number);
void run(size_t this_thread_number);
private:
RCLCPP_DISABLE_COPY(MultiThreadedExecutor)

View File

@@ -26,43 +26,34 @@
#include "rclcpp/macros.hpp"
#include "rclcpp/memory_strategies.hpp"
#include "rclcpp/node.hpp"
#include "rclcpp/utilities.hpp"
#include "rclcpp/rate.hpp"
#include "rclcpp/utilities.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
namespace executors
{
/// Single-threaded executor implementation.
/**
* This is the default executor created by rclcpp::spin.
*/
class SingleThreadedExecutor : public rclcpp::Executor
/// Single-threaded executor implementation
// This is the default executor created by rclcpp::spin.
class SingleThreadedExecutor : public executor::Executor
{
public:
RCLCPP_SMART_PTR_DEFINITIONS(SingleThreadedExecutor)
/// Default constructor. See the default constructor for Executor.
RCLCPP_PUBLIC
explicit SingleThreadedExecutor(
const rclcpp::ExecutorOptions & options = rclcpp::ExecutorOptions());
SingleThreadedExecutor(const executor::ExecutorArgs & args = executor::ExecutorArgs());
/// Default destructor.
/// Default destrcutor.
RCLCPP_PUBLIC
virtual ~SingleThreadedExecutor();
/// Single-threaded implementation of spin.
/**
* This function will block until work comes in, execute it, and then repeat
* the process until canceled.
* It may be interrupt by a call to rclcpp::Executor::cancel() or by ctrl-c
* if the associated context is configured to shutdown on SIGINT.
*/
// This function will block until work comes in, execute it, and keep blocking.
// It will only be interrupt by a CTRL-C (managed by the global signal handler).
RCLCPP_PUBLIC
void
spin() override;
void spin();
private:
RCLCPP_DISABLE_COPY(SingleThreadedExecutor)

View File

@@ -1,168 +0,0 @@
// Copyright 2020 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__EXECUTORS__STATIC_EXECUTOR_ENTITIES_COLLECTOR_HPP_
#define RCLCPP__EXECUTORS__STATIC_EXECUTOR_ENTITIES_COLLECTOR_HPP_
#include <chrono>
#include <list>
#include <memory>
#include "rcl/guard_condition.h"
#include "rcl/wait.h"
#include "rclcpp/experimental/executable_list.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/memory_strategy.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rclcpp/waitable.hpp"
namespace rclcpp
{
namespace executors
{
class StaticExecutorEntitiesCollector final
: public rclcpp::Waitable,
public std::enable_shared_from_this<StaticExecutorEntitiesCollector>
{
public:
RCLCPP_SMART_PTR_DEFINITIONS(StaticExecutorEntitiesCollector)
// Constructor
RCLCPP_PUBLIC
StaticExecutorEntitiesCollector() = default;
// Destructor
~StaticExecutorEntitiesCollector();
RCLCPP_PUBLIC
void
init(
rcl_wait_set_t * p_wait_set,
rclcpp::memory_strategy::MemoryStrategy::SharedPtr & memory_strategy,
rcl_guard_condition_t * executor_guard_condition);
RCLCPP_PUBLIC
void
execute() override;
RCLCPP_PUBLIC
void
fill_memory_strategy();
RCLCPP_PUBLIC
void
fill_executable_list();
/// Function to reallocate space for entities in the wait set.
RCLCPP_PUBLIC
void
prepare_wait_set();
/// Function to add_handles_to_wait_set and wait for work and
// block until the wait set is ready or until the timeout has been exceeded.
RCLCPP_PUBLIC
void
refresh_wait_set(std::chrono::nanoseconds timeout = std::chrono::nanoseconds(-1));
RCLCPP_PUBLIC
bool
add_to_wait_set(rcl_wait_set_t * wait_set) override;
RCLCPP_PUBLIC
size_t
get_number_of_ready_guard_conditions() override;
RCLCPP_PUBLIC
void
add_node(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr);
RCLCPP_PUBLIC
bool
remove_node(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr);
/// Complete all available queued work without blocking.
/**
* This function checks if after the guard condition was triggered
* (or a spurious wakeup happened) we are really ready to execute
* i.e. re-collect entities
*/
RCLCPP_PUBLIC
bool
is_ready(rcl_wait_set_t * wait_set) override;
RCLCPP_PUBLIC
size_t
get_number_of_timers() {return exec_list_.number_of_timers;}
RCLCPP_PUBLIC
size_t
get_number_of_subscriptions() {return exec_list_.number_of_subscriptions;}
RCLCPP_PUBLIC
size_t
get_number_of_services() {return exec_list_.number_of_services;}
RCLCPP_PUBLIC
size_t
get_number_of_clients() {return exec_list_.number_of_clients;}
RCLCPP_PUBLIC
size_t
get_number_of_waitables() {return exec_list_.number_of_waitables;}
RCLCPP_PUBLIC
rclcpp::SubscriptionBase::SharedPtr
get_subscription(size_t i) {return exec_list_.subscription[i];}
RCLCPP_PUBLIC
rclcpp::TimerBase::SharedPtr
get_timer(size_t i) {return exec_list_.timer[i];}
RCLCPP_PUBLIC
rclcpp::ServiceBase::SharedPtr
get_service(size_t i) {return exec_list_.service[i];}
RCLCPP_PUBLIC
rclcpp::ClientBase::SharedPtr
get_client(size_t i) {return exec_list_.client[i];}
RCLCPP_PUBLIC
rclcpp::Waitable::SharedPtr
get_waitable(size_t i) {return exec_list_.waitable[i];}
private:
/// Nodes guard conditions which trigger this waitable
std::list<const rcl_guard_condition_t *> guard_conditions_;
/// Memory strategy: an interface for handling user-defined memory allocation strategies.
rclcpp::memory_strategy::MemoryStrategy::SharedPtr memory_strategy_;
/// List of weak nodes registered in the static executor
std::list<rclcpp::node_interfaces::NodeBaseInterface::WeakPtr> weak_nodes_;
/// Wait set for managing entities that the rmw layer waits on.
rcl_wait_set_t * p_wait_set_ = nullptr;
/// Executable list: timers, subscribers, clients, services and waitables
rclcpp::experimental::ExecutableList exec_list_;
};
} // namespace executors
} // namespace rclcpp
#endif // RCLCPP__EXECUTORS__STATIC_EXECUTOR_ENTITIES_COLLECTOR_HPP_

View File

@@ -1,200 +0,0 @@
// Copyright 2019 Nobleo Technology
//
// 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__EXECUTORS__STATIC_SINGLE_THREADED_EXECUTOR_HPP_
#define RCLCPP__EXECUTORS__STATIC_SINGLE_THREADED_EXECUTOR_HPP_
#include <cassert>
#include <cstdlib>
#include <memory>
#include <vector>
#include <string>
#include "rmw/rmw.h"
#include "rclcpp/executor.hpp"
#include "rclcpp/executors/static_executor_entities_collector.hpp"
#include "rclcpp/experimental/executable_list.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/memory_strategies.hpp"
#include "rclcpp/node.hpp"
#include "rclcpp/rate.hpp"
#include "rclcpp/utilities.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
namespace executors
{
/// Static executor implementation
/**
* This executor is a static version of the original single threaded executor.
* It's static because it doesn't reconstruct the executable list for every iteration.
* All nodes, callbackgroups, timers, subscriptions etc. are created before
* spin() is called, and modified only when an entity is added/removed to/from a node.
*
* To run this executor instead of SingleThreadedExecutor replace:
* rclcpp::executors::SingleThreadedExecutor exec;
* by
* rclcpp::executors::StaticSingleThreadedExecutor exec;
* in your source code and spin node(s) in the following way:
* exec.add_node(node);
* exec.spin();
* exec.remove_node(node);
*/
class StaticSingleThreadedExecutor : public rclcpp::Executor
{
public:
RCLCPP_SMART_PTR_DEFINITIONS(StaticSingleThreadedExecutor)
/// Default constructor. See the default constructor for Executor.
RCLCPP_PUBLIC
explicit StaticSingleThreadedExecutor(
const rclcpp::ExecutorOptions & options = rclcpp::ExecutorOptions());
/// Default destrcutor.
RCLCPP_PUBLIC
virtual ~StaticSingleThreadedExecutor();
/// Static executor implementation of spin.
// This function will block until work comes in, execute it, and keep blocking.
// It will only be interrupt by a CTRL-C (managed by the global signal handler).
RCLCPP_PUBLIC
void
spin() override;
/// Add a node to the executor.
/**
* An executor can have zero or more nodes which provide work during `spin` functions.
* \param[in] node_ptr Shared pointer to the node to be added.
* \param[in] notify True to trigger the interrupt guard condition during this function. If
* the executor is blocked at the rmw layer while waiting for work and it is notified that a new
* node was added, it will wake up.
*/
RCLCPP_PUBLIC
void
add_node(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
bool notify = true) override;
/// Convenience function which takes Node and forwards NodeBaseInterface.
RCLCPP_PUBLIC
void
add_node(std::shared_ptr<rclcpp::Node> node_ptr, bool notify = true) override;
/// Remove a node from the executor.
/**
* \param[in] node_ptr Shared pointer to the node to remove.
* \param[in] notify True to trigger the interrupt guard condition and wake up the executor.
* This is useful if the last node was removed from the executor while the executor was blocked
* waiting for work in another thread, because otherwise the executor would never be notified.
*/
RCLCPP_PUBLIC
void
remove_node(
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_ptr,
bool notify = true) override;
/// Convenience function which takes Node and forwards NodeBaseInterface.
RCLCPP_PUBLIC
void
remove_node(std::shared_ptr<rclcpp::Node> node_ptr, bool notify = true) override;
/// Spin (blocking) until the future is complete, it times out waiting, or rclcpp is interrupted.
/**
* \param[in] future The future to wait on. If this function returns SUCCESS, the future can be
* accessed without blocking (though it may still throw an exception).
* \param[in] timeout Optional timeout parameter, which gets passed to
* Executor::execute_ready_executables.
* `-1` is block forever, `0` is non-blocking.
* If the time spent inside the blocking loop exceeds this timeout, return a TIMEOUT return
* code.
* \return The return code, one of `SUCCESS`, `INTERRUPTED`, or `TIMEOUT`.
*
* Example usage:
* rclcpp::executors::StaticSingleThreadedExecutor exec;
* // ... other part of code like creating node
* // define future
* exec.add_node(node);
* exec.spin_until_future_complete(future);
*/
template<typename ResponseT, typename TimeRepT = int64_t, typename TimeT = std::milli>
rclcpp::FutureReturnCode
spin_until_future_complete(
std::shared_future<ResponseT> & future,
std::chrono::duration<TimeRepT, TimeT> timeout = std::chrono::duration<TimeRepT, TimeT>(-1))
{
std::future_status status = future.wait_for(std::chrono::seconds(0));
if (status == std::future_status::ready) {
return rclcpp::FutureReturnCode::SUCCESS;
}
auto end_time = std::chrono::steady_clock::now();
std::chrono::nanoseconds timeout_ns = std::chrono::duration_cast<std::chrono::nanoseconds>(
timeout);
if (timeout_ns > std::chrono::nanoseconds::zero()) {
end_time += timeout_ns;
}
std::chrono::nanoseconds timeout_left = timeout_ns;
entities_collector_ = std::make_shared<StaticExecutorEntitiesCollector>();
entities_collector_->init(&wait_set_, memory_strategy_, &interrupt_guard_condition_);
while (rclcpp::ok(this->context_)) {
// Do one set of work.
entities_collector_->refresh_wait_set(timeout_left);
execute_ready_executables();
// Check if the future is set, return SUCCESS if it is.
status = future.wait_for(std::chrono::seconds(0));
if (status == std::future_status::ready) {
return rclcpp::FutureReturnCode::SUCCESS;
}
// If the original timeout is < 0, then this is blocking, never TIMEOUT.
if (timeout_ns < std::chrono::nanoseconds::zero()) {
continue;
}
// Otherwise check if we still have time to wait, return TIMEOUT if not.
auto now = std::chrono::steady_clock::now();
if (now >= end_time) {
return rclcpp::FutureReturnCode::TIMEOUT;
}
// Subtract the elapsed time from the original timeout.
timeout_left = std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - now);
}
// The future did not complete before ok() returned false, return INTERRUPTED.
return rclcpp::FutureReturnCode::INTERRUPTED;
}
protected:
/// Check which executables in ExecutableList struct are ready from wait_set and execute them.
/**
* \param[in] exec_list Structure that can hold subscriptionbases, timerbases, etc
* \param[in] timeout Optional timeout parameter.
*/
RCLCPP_PUBLIC
void
execute_ready_executables();
private:
RCLCPP_DISABLE_COPY(StaticSingleThreadedExecutor)
StaticExecutorEntitiesCollector::SharedPtr entities_collector_;
};
} // namespace executors
} // namespace rclcpp
#endif // RCLCPP__EXECUTORS__STATIC_SINGLE_THREADED_EXECUTOR_HPP_

View File

@@ -21,7 +21,6 @@
namespace rclcpp
{
/// Expand a topic or service name and throw if it is not valid.
/**
* This function can be used to "just" validate a topic or service name too,
@@ -51,8 +50,7 @@ namespace rclcpp
* \throws RCLError if an unexpect error occurs
*/
RCLCPP_PUBLIC
std::string
expand_topic_or_service_name(
std::string expand_topic_or_service_name(
const std::string & name,
const std::string & node_name,
const std::string & namespace_,

View File

@@ -1,4 +0,0 @@
Notice that headers in this folder should only provide symbols in the rclcpp::experimental namespace.
Also notice that these headers are not considered part of the public API as they have not yet been stabilized.
And therefore they are subject to change without notice.

View File

@@ -1,42 +0,0 @@
// Copyright 2019 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__EXPERIMENTAL__BUFFERS__BUFFER_IMPLEMENTATION_BASE_HPP_
#define RCLCPP__EXPERIMENTAL__BUFFERS__BUFFER_IMPLEMENTATION_BASE_HPP_
namespace rclcpp
{
namespace experimental
{
namespace buffers
{
template<typename BufferT>
class BufferImplementationBase
{
public:
virtual ~BufferImplementationBase() {}
virtual BufferT dequeue() = 0;
virtual void enqueue(BufferT request) = 0;
virtual void clear() = 0;
virtual bool has_data() const = 0;
};
} // namespace buffers
} // namespace experimental
} // namespace rclcpp
#endif // RCLCPP__EXPERIMENTAL__BUFFERS__BUFFER_IMPLEMENTATION_BASE_HPP_

View File

@@ -1,241 +0,0 @@
// Copyright 2019 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__EXPERIMENTAL__BUFFERS__INTRA_PROCESS_BUFFER_HPP_
#define RCLCPP__EXPERIMENTAL__BUFFERS__INTRA_PROCESS_BUFFER_HPP_
#include <memory>
#include <type_traits>
#include <utility>
#include "rclcpp/allocator/allocator_common.hpp"
#include "rclcpp/allocator/allocator_deleter.hpp"
#include "rclcpp/experimental/buffers/buffer_implementation_base.hpp"
#include "rclcpp/macros.hpp"
namespace rclcpp
{
namespace experimental
{
namespace buffers
{
class IntraProcessBufferBase
{
public:
RCLCPP_SMART_PTR_ALIASES_ONLY(IntraProcessBufferBase)
virtual ~IntraProcessBufferBase() {}
virtual void clear() = 0;
virtual bool has_data() const = 0;
virtual bool use_take_shared_method() const = 0;
};
template<
typename MessageT,
typename Alloc = std::allocator<void>,
typename MessageDeleter = std::default_delete<MessageT>>
class IntraProcessBuffer : public IntraProcessBufferBase
{
public:
RCLCPP_SMART_PTR_ALIASES_ONLY(IntraProcessBuffer)
virtual ~IntraProcessBuffer() {}
using MessageUniquePtr = std::unique_ptr<MessageT, MessageDeleter>;
using MessageSharedPtr = std::shared_ptr<const MessageT>;
virtual void add_shared(MessageSharedPtr msg) = 0;
virtual void add_unique(MessageUniquePtr msg) = 0;
virtual MessageSharedPtr consume_shared() = 0;
virtual MessageUniquePtr consume_unique() = 0;
};
template<
typename MessageT,
typename Alloc = std::allocator<void>,
typename MessageDeleter = std::default_delete<MessageT>,
typename BufferT = std::unique_ptr<MessageT>>
class TypedIntraProcessBuffer : public IntraProcessBuffer<MessageT, Alloc, MessageDeleter>
{
public:
RCLCPP_SMART_PTR_DEFINITIONS(TypedIntraProcessBuffer)
using MessageAllocTraits = allocator::AllocRebind<MessageT, Alloc>;
using MessageAlloc = typename MessageAllocTraits::allocator_type;
using MessageUniquePtr = std::unique_ptr<MessageT, MessageDeleter>;
using MessageSharedPtr = std::shared_ptr<const MessageT>;
explicit
TypedIntraProcessBuffer(
std::unique_ptr<BufferImplementationBase<BufferT>> buffer_impl,
std::shared_ptr<Alloc> allocator = nullptr)
{
bool valid_type = (std::is_same<BufferT, MessageSharedPtr>::value ||
std::is_same<BufferT, MessageUniquePtr>::value);
if (!valid_type) {
throw std::runtime_error("Creating TypedIntraProcessBuffer with not valid BufferT");
}
buffer_ = std::move(buffer_impl);
if (!allocator) {
message_allocator_ = std::make_shared<MessageAlloc>();
} else {
message_allocator_ = std::make_shared<MessageAlloc>(*allocator.get());
}
}
virtual ~TypedIntraProcessBuffer() {}
void add_shared(MessageSharedPtr msg) override
{
add_shared_impl<BufferT>(std::move(msg));
}
void add_unique(MessageUniquePtr msg) override
{
buffer_->enqueue(std::move(msg));
}
MessageSharedPtr consume_shared() override
{
return consume_shared_impl<BufferT>();
}
MessageUniquePtr consume_unique() override
{
return consume_unique_impl<BufferT>();
}
bool has_data() const override
{
return buffer_->has_data();
}
void clear() override
{
buffer_->clear();
}
bool use_take_shared_method() const override
{
return std::is_same<BufferT, MessageSharedPtr>::value;
}
private:
std::unique_ptr<BufferImplementationBase<BufferT>> buffer_;
std::shared_ptr<MessageAlloc> message_allocator_;
// MessageSharedPtr to MessageSharedPtr
template<typename DestinationT>
typename std::enable_if<
std::is_same<DestinationT, MessageSharedPtr>::value
>::type
add_shared_impl(MessageSharedPtr shared_msg)
{
buffer_->enqueue(std::move(shared_msg));
}
// MessageSharedPtr to MessageUniquePtr
template<typename DestinationT>
typename std::enable_if<
std::is_same<DestinationT, MessageUniquePtr>::value
>::type
add_shared_impl(MessageSharedPtr shared_msg)
{
// This should not happen: here a copy is unconditionally made, while the intra-process manager
// can decide whether a copy is needed depending on the number and the type of buffers
MessageUniquePtr unique_msg;
MessageDeleter * deleter = std::get_deleter<MessageDeleter, const MessageT>(shared_msg);
auto ptr = MessageAllocTraits::allocate(*message_allocator_.get(), 1);
MessageAllocTraits::construct(*message_allocator_.get(), ptr, *shared_msg);
if (deleter) {
unique_msg = MessageUniquePtr(ptr, *deleter);
} else {
unique_msg = MessageUniquePtr(ptr);
}
buffer_->enqueue(std::move(unique_msg));
}
// MessageSharedPtr to MessageSharedPtr
template<typename OriginT>
typename std::enable_if<
std::is_same<OriginT, MessageSharedPtr>::value,
MessageSharedPtr
>::type
consume_shared_impl()
{
return buffer_->dequeue();
}
// MessageUniquePtr to MessageSharedPtr
template<typename OriginT>
typename std::enable_if<
(std::is_same<OriginT, MessageUniquePtr>::value),
MessageSharedPtr
>::type
consume_shared_impl()
{
// automatic cast from unique ptr to shared ptr
return buffer_->dequeue();
}
// MessageSharedPtr to MessageUniquePtr
template<typename OriginT>
typename std::enable_if<
(std::is_same<OriginT, MessageSharedPtr>::value),
MessageUniquePtr
>::type
consume_unique_impl()
{
MessageSharedPtr buffer_msg = buffer_->dequeue();
MessageUniquePtr unique_msg;
MessageDeleter * deleter = std::get_deleter<MessageDeleter, const MessageT>(buffer_msg);
auto ptr = MessageAllocTraits::allocate(*message_allocator_.get(), 1);
MessageAllocTraits::construct(*message_allocator_.get(), ptr, *buffer_msg);
if (deleter) {
unique_msg = MessageUniquePtr(ptr, *deleter);
} else {
unique_msg = MessageUniquePtr(ptr);
}
return unique_msg;
}
// MessageUniquePtr to MessageUniquePtr
template<typename OriginT>
typename std::enable_if<
(std::is_same<OriginT, MessageUniquePtr>::value),
MessageUniquePtr
>::type
consume_unique_impl()
{
return buffer_->dequeue();
}
};
} // namespace buffers
} // namespace experimental
} // namespace rclcpp
#endif // RCLCPP__EXPERIMENTAL__BUFFERS__INTRA_PROCESS_BUFFER_HPP_

View File

@@ -1,122 +0,0 @@
// Copyright 2019 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__EXPERIMENTAL__BUFFERS__RING_BUFFER_IMPLEMENTATION_HPP_
#define RCLCPP__EXPERIMENTAL__BUFFERS__RING_BUFFER_IMPLEMENTATION_HPP_
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <mutex>
#include <stdexcept>
#include <utility>
#include <vector>
#include "rclcpp/experimental/buffers/buffer_implementation_base.hpp"
#include "rclcpp/logger.hpp"
#include "rclcpp/logging.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
namespace experimental
{
namespace buffers
{
template<typename BufferT>
class RingBufferImplementation : public BufferImplementationBase<BufferT>
{
public:
explicit RingBufferImplementation(size_t capacity)
: capacity_(capacity),
ring_buffer_(capacity),
write_index_(capacity_ - 1),
read_index_(0),
size_(0)
{
if (capacity == 0) {
throw std::invalid_argument("capacity must be a positive, non-zero value");
}
}
virtual ~RingBufferImplementation() {}
void enqueue(BufferT request)
{
std::lock_guard<std::mutex> lock(mutex_);
write_index_ = next(write_index_);
ring_buffer_[write_index_] = std::move(request);
if (is_full()) {
read_index_ = next(read_index_);
} else {
size_++;
}
}
BufferT dequeue()
{
std::lock_guard<std::mutex> lock(mutex_);
if (!has_data()) {
RCLCPP_ERROR(rclcpp::get_logger("rclcpp"), "Calling dequeue on empty intra-process buffer");
throw std::runtime_error("Calling dequeue on empty intra-process buffer");
}
auto request = std::move(ring_buffer_[read_index_]);
read_index_ = next(read_index_);
size_--;
return request;
}
inline size_t next(size_t val)
{
return (val + 1) % capacity_;
}
inline bool has_data() const
{
return size_ != 0;
}
inline bool is_full()
{
return size_ == capacity_;
}
void clear() {}
private:
size_t capacity_;
std::vector<BufferT> ring_buffer_;
size_t write_index_;
size_t read_index_;
size_t size_;
std::mutex mutex_;
};
} // namespace buffers
} // namespace experimental
} // namespace rclcpp
#endif // RCLCPP__EXPERIMENTAL__BUFFERS__RING_BUFFER_IMPLEMENTATION_HPP_

View File

@@ -1,99 +0,0 @@
// Copyright 2019 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__EXPERIMENTAL__CREATE_INTRA_PROCESS_BUFFER_HPP_
#define RCLCPP__EXPERIMENTAL__CREATE_INTRA_PROCESS_BUFFER_HPP_
#include <memory>
#include <type_traits>
#include <utility>
#include "rcl/subscription.h"
#include "rclcpp/experimental/buffers/intra_process_buffer.hpp"
#include "rclcpp/experimental/buffers/ring_buffer_implementation.hpp"
#include "rclcpp/intra_process_buffer_type.hpp"
namespace rclcpp
{
namespace experimental
{
template<
typename MessageT,
typename Alloc = std::allocator<void>,
typename Deleter = std::default_delete<MessageT>>
typename rclcpp::experimental::buffers::IntraProcessBuffer<MessageT, Alloc, Deleter>::UniquePtr
create_intra_process_buffer(
IntraProcessBufferType buffer_type,
rmw_qos_profile_t qos,
std::shared_ptr<Alloc> allocator)
{
using MessageSharedPtr = std::shared_ptr<const MessageT>;
using MessageUniquePtr = std::unique_ptr<MessageT, Deleter>;
size_t buffer_size = qos.depth;
using rclcpp::experimental::buffers::IntraProcessBuffer;
typename IntraProcessBuffer<MessageT, Alloc, Deleter>::UniquePtr buffer;
switch (buffer_type) {
case IntraProcessBufferType::SharedPtr:
{
using BufferT = MessageSharedPtr;
auto buffer_implementation =
std::make_unique<rclcpp::experimental::buffers::RingBufferImplementation<BufferT>>(
buffer_size);
// Construct the intra_process_buffer
buffer =
std::make_unique<rclcpp::experimental::buffers::TypedIntraProcessBuffer<MessageT, Alloc,
Deleter, BufferT>>(
std::move(buffer_implementation),
allocator);
break;
}
case IntraProcessBufferType::UniquePtr:
{
using BufferT = MessageUniquePtr;
auto buffer_implementation =
std::make_unique<rclcpp::experimental::buffers::RingBufferImplementation<BufferT>>(
buffer_size);
// Construct the intra_process_buffer
buffer =
std::make_unique<rclcpp::experimental::buffers::TypedIntraProcessBuffer<MessageT, Alloc,
Deleter, BufferT>>(
std::move(buffer_implementation),
allocator);
break;
}
default:
{
throw std::runtime_error("Unrecognized IntraProcessBufferType value");
break;
}
}
return buffer;
}
} // namespace experimental
} // namespace rclcpp
#endif // RCLCPP__EXPERIMENTAL__CREATE_INTRA_PROCESS_BUFFER_HPP_

View File

@@ -1,92 +0,0 @@
// Copyright 2019 Nobleo Technology
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__EXPERIMENTAL__EXECUTABLE_LIST_HPP_
#define RCLCPP__EXPERIMENTAL__EXECUTABLE_LIST_HPP_
#include <memory>
#include <vector>
#include "rclcpp/client.hpp"
#include "rclcpp/service.hpp"
#include "rclcpp/subscription_base.hpp"
#include "rclcpp/timer.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rclcpp/waitable.hpp"
namespace rclcpp
{
namespace experimental
{
/// This class contains subscriptionbase, timerbase, etc. which can be used to run callbacks.
class ExecutableList final
{
public:
RCLCPP_PUBLIC
ExecutableList();
RCLCPP_PUBLIC
~ExecutableList();
RCLCPP_PUBLIC
void
clear();
RCLCPP_PUBLIC
void
add_subscription(rclcpp::SubscriptionBase::SharedPtr subscription);
RCLCPP_PUBLIC
void
add_timer(rclcpp::TimerBase::SharedPtr timer);
RCLCPP_PUBLIC
void
add_service(rclcpp::ServiceBase::SharedPtr service);
RCLCPP_PUBLIC
void
add_client(rclcpp::ClientBase::SharedPtr client);
RCLCPP_PUBLIC
void
add_waitable(rclcpp::Waitable::SharedPtr waitable);
// Vector containing the SubscriptionBase of all the subscriptions added to the executor.
std::vector<rclcpp::SubscriptionBase::SharedPtr> subscription;
// Contains the count of added subscriptions
size_t number_of_subscriptions;
// Vector containing the TimerBase of all the timers added to the executor.
std::vector<rclcpp::TimerBase::SharedPtr> timer;
// Contains the count of added timers
size_t number_of_timers;
// Vector containing the ServiceBase of all the services added to the executor.
std::vector<rclcpp::ServiceBase::SharedPtr> service;
// Contains the count of added services
size_t number_of_services;
// Vector containing the ClientBase of all the clients added to the executor.
std::vector<rclcpp::ClientBase::SharedPtr> client;
// Contains the count of added clients
size_t number_of_clients;
// Vector containing all the waitables added to the executor.
std::vector<rclcpp::Waitable::SharedPtr> waitable;
// Contains the count of added waitables
size_t number_of_waitables;
};
} // namespace experimental
} // namespace rclcpp
#endif // RCLCPP__EXPERIMENTAL__EXECUTABLE_LIST_HPP_

View File

@@ -1,424 +0,0 @@
// Copyright 2019 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__EXPERIMENTAL__INTRA_PROCESS_MANAGER_HPP_
#define RCLCPP__EXPERIMENTAL__INTRA_PROCESS_MANAGER_HPP_
#include <rmw/types.h>
#include <shared_mutex>
#include <algorithm>
#include <atomic>
#include <cstdint>
#include <exception>
#include <map>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
#include "rclcpp/allocator/allocator_deleter.hpp"
#include "rclcpp/experimental/subscription_intra_process.hpp"
#include "rclcpp/experimental/subscription_intra_process_base.hpp"
#include "rclcpp/logger.hpp"
#include "rclcpp/logging.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/publisher_base.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
namespace experimental
{
/// This class performs intra process communication between nodes.
/**
* This class is used in the creation of publishers and subscriptions.
* A singleton instance of this class is owned by a rclcpp::Context and a
* rclcpp::Node can use an associated Context to get an instance of this class.
* Nodes which do not have a common Context will not exchange intra process
* messages because they do not share access to the same instance of this class.
*
* When a Node creates a subscription, it can also create a helper class,
* called SubscriptionIntraProcess, meant to receive intra process messages.
* It can be registered with this class.
* It is also allocated an id which is unique among all publishers
* and subscriptions in this process and that is associated to the subscription.
*
* When a Node creates a publisher, as with subscriptions, a helper class can
* be registered with this class.
* This is required in order to publish intra-process messages.
* It is also allocated an id which is unique among all publishers
* and subscriptions in this process and that is associated to the publisher.
*
* When a publisher or a subscription are registered, this class checks to see
* which other subscriptions or publishers it will communicate with,
* i.e. they have the same topic and compatible QoS.
*
* When the user publishes a message, if intra-process communication is enabled
* on the publisher, the message is given to this class.
* Using the publisher id, a list of recipients for the message is selected.
* For each subscription in the list, this class stores the message, whether
* sharing ownership or making a copy, in a buffer associated with the
* subscription helper class.
*
* The subscription helper class contains a buffer where published
* intra-process messages are stored until they are taken from the subscription.
* Depending on the data type stored in the buffer, the subscription helper
* class can request either shared or exclusive ownership on the message.
*
* Thus, when an intra-process message is published, this class knows how many
* intra-process subscriptions needs it and how many require ownership.
* This information allows this class to operate efficiently by performing the
* fewest number of copies of the message required.
*
* This class is neither CopyConstructable nor CopyAssignable.
*/
class IntraProcessManager
{
private:
RCLCPP_DISABLE_COPY(IntraProcessManager)
public:
RCLCPP_SMART_PTR_DEFINITIONS(IntraProcessManager)
RCLCPP_PUBLIC
IntraProcessManager();
RCLCPP_PUBLIC
virtual ~IntraProcessManager();
/// Register a subscription with the manager, returns subscriptions unique id.
/**
* This method stores the subscription intra process object, together with
* the information of its wrapped subscription (i.e. topic name and QoS).
*
* In addition this generates a unique intra process id for the subscription.
*
* \param subscription the SubscriptionIntraProcess to register.
* \return an unsigned 64-bit integer which is the subscription's unique id.
*/
RCLCPP_PUBLIC
uint64_t
add_subscription(rclcpp::experimental::SubscriptionIntraProcessBase::SharedPtr subscription);
/// Unregister a subscription using the subscription's unique id.
/**
* This method does not allocate memory.
*
* \param intra_process_subscription_id id of the subscription to remove.
*/
RCLCPP_PUBLIC
void
remove_subscription(uint64_t intra_process_subscription_id);
/// Register a publisher with the manager, returns the publisher unique id.
/**
* This method stores the publisher intra process object, together with
* the information of its wrapped publisher (i.e. topic name and QoS).
*
* In addition this generates a unique intra process id for the publisher.
*
* \param publisher publisher to be registered with the manager.
* \return an unsigned 64-bit integer which is the publisher's unique id.
*/
RCLCPP_PUBLIC
uint64_t
add_publisher(rclcpp::PublisherBase::SharedPtr publisher);
/// Unregister a publisher using the publisher's unique id.
/**
* This method does not allocate memory.
*
* \param intra_process_publisher_id id of the publisher to remove.
*/
RCLCPP_PUBLIC
void
remove_publisher(uint64_t intra_process_publisher_id);
/// Publishes an intra-process message, passed as a unique pointer.
/**
* This is one of the two methods for publishing intra-process.
*
* Using the intra-process publisher id, a list of recipients is obtained.
* This list is split in half, depending whether they require ownership or not.
*
* This particular method takes a unique pointer as input.
* The pointer can be promoted to a shared pointer and passed to all the subscriptions
* that do not require ownership.
* In case of subscriptions requiring ownership, the message will be copied for all of
* them except the last one, when ownership can be transferred.
*
* This method can save an additional copy compared to the shared pointer one.
*
* This method can throw an exception if the publisher id is not found or
* if the publisher shared_ptr given to add_publisher has gone out of scope.
*
* This method does allocate memory.
*
* \param intra_process_publisher_id the id of the publisher of this message.
* \param message the message that is being stored.
*/
template<
typename MessageT,
typename Alloc = std::allocator<void>,
typename Deleter = std::default_delete<MessageT>>
void
do_intra_process_publish(
uint64_t intra_process_publisher_id,
std::unique_ptr<MessageT, Deleter> message,
std::shared_ptr<typename allocator::AllocRebind<MessageT, Alloc>::allocator_type> allocator)
{
using MessageAllocTraits = allocator::AllocRebind<MessageT, Alloc>;
using MessageAllocatorT = typename MessageAllocTraits::allocator_type;
std::shared_lock<std::shared_timed_mutex> lock(mutex_);
auto publisher_it = pub_to_subs_.find(intra_process_publisher_id);
if (publisher_it == pub_to_subs_.end()) {
// Publisher is either invalid or no longer exists.
RCLCPP_WARN(
rclcpp::get_logger("rclcpp"),
"Calling do_intra_process_publish for invalid or no longer existing publisher id");
return;
}
const auto & sub_ids = publisher_it->second;
if (sub_ids.take_ownership_subscriptions.empty()) {
// None of the buffers require ownership, so we promote the pointer
std::shared_ptr<MessageT> msg = std::move(message);
this->template add_shared_msg_to_buffers<MessageT>(msg, sub_ids.take_shared_subscriptions);
} else if (!sub_ids.take_ownership_subscriptions.empty() && // NOLINT
sub_ids.take_shared_subscriptions.size() <= 1)
{
// There is at maximum 1 buffer that does not require ownership.
// So we this case is equivalent to all the buffers requiring ownership
// Merge the two vector of ids into a unique one
std::vector<uint64_t> concatenated_vector(sub_ids.take_shared_subscriptions);
concatenated_vector.insert(
concatenated_vector.end(),
sub_ids.take_ownership_subscriptions.begin(),
sub_ids.take_ownership_subscriptions.end());
this->template add_owned_msg_to_buffers<MessageT, Alloc, Deleter>(
std::move(message),
concatenated_vector,
allocator);
} else if (!sub_ids.take_ownership_subscriptions.empty() && // NOLINT
sub_ids.take_shared_subscriptions.size() > 1)
{
// Construct a new shared pointer from the message
// for the buffers that do not require ownership
auto shared_msg = std::allocate_shared<MessageT, MessageAllocatorT>(*allocator, *message);
this->template add_shared_msg_to_buffers<MessageT>(
shared_msg, sub_ids.take_shared_subscriptions);
this->template add_owned_msg_to_buffers<MessageT, Alloc, Deleter>(
std::move(message), sub_ids.take_ownership_subscriptions, allocator);
}
}
template<
typename MessageT,
typename Alloc = std::allocator<void>,
typename Deleter = std::default_delete<MessageT>>
std::shared_ptr<const MessageT>
do_intra_process_publish_and_return_shared(
uint64_t intra_process_publisher_id,
std::unique_ptr<MessageT, Deleter> message,
std::shared_ptr<typename allocator::AllocRebind<MessageT, Alloc>::allocator_type> allocator)
{
using MessageAllocTraits = allocator::AllocRebind<MessageT, Alloc>;
using MessageAllocatorT = typename MessageAllocTraits::allocator_type;
std::shared_lock<std::shared_timed_mutex> lock(mutex_);
auto publisher_it = pub_to_subs_.find(intra_process_publisher_id);
if (publisher_it == pub_to_subs_.end()) {
// Publisher is either invalid or no longer exists.
RCLCPP_WARN(
rclcpp::get_logger("rclcpp"),
"Calling do_intra_process_publish for invalid or no longer existing publisher id");
return nullptr;
}
const auto & sub_ids = publisher_it->second;
if (sub_ids.take_ownership_subscriptions.empty()) {
// If there are no owning, just convert to shared.
std::shared_ptr<MessageT> shared_msg = std::move(message);
if (!sub_ids.take_shared_subscriptions.empty()) {
this->template add_shared_msg_to_buffers<MessageT>(
shared_msg, sub_ids.take_shared_subscriptions);
}
return shared_msg;
} else {
// Construct a new shared pointer from the message for the buffers that
// do not require ownership and to return.
auto shared_msg = std::allocate_shared<MessageT, MessageAllocatorT>(*allocator, *message);
if (!sub_ids.take_shared_subscriptions.empty()) {
this->template add_shared_msg_to_buffers<MessageT>(
shared_msg,
sub_ids.take_shared_subscriptions);
}
if (!sub_ids.take_ownership_subscriptions.empty()) {
this->template add_owned_msg_to_buffers<MessageT, Alloc, Deleter>(
std::move(message),
sub_ids.take_ownership_subscriptions,
allocator);
}
return shared_msg;
}
}
/// Return true if the given rmw_gid_t matches any stored Publishers.
RCLCPP_PUBLIC
bool
matches_any_publishers(const rmw_gid_t * id) const;
/// Return the number of intraprocess subscriptions that are matched with a given publisher id.
RCLCPP_PUBLIC
size_t
get_subscription_count(uint64_t intra_process_publisher_id) const;
RCLCPP_PUBLIC
rclcpp::experimental::SubscriptionIntraProcessBase::SharedPtr
get_subscription_intra_process(uint64_t intra_process_subscription_id);
private:
struct SubscriptionInfo
{
SubscriptionInfo() = default;
rclcpp::experimental::SubscriptionIntraProcessBase::SharedPtr subscription;
rmw_qos_profile_t qos;
const char * topic_name;
bool use_take_shared_method;
};
struct PublisherInfo
{
PublisherInfo() = default;
rclcpp::PublisherBase::WeakPtr publisher;
rmw_qos_profile_t qos;
const char * topic_name;
};
struct SplittedSubscriptions
{
std::vector<uint64_t> take_shared_subscriptions;
std::vector<uint64_t> take_ownership_subscriptions;
};
using SubscriptionMap =
std::unordered_map<uint64_t, SubscriptionInfo>;
using PublisherMap =
std::unordered_map<uint64_t, PublisherInfo>;
using PublisherToSubscriptionIdsMap =
std::unordered_map<uint64_t, SplittedSubscriptions>;
RCLCPP_PUBLIC
static
uint64_t
get_next_unique_id();
RCLCPP_PUBLIC
void
insert_sub_id_for_pub(uint64_t sub_id, uint64_t pub_id, bool use_take_shared_method);
RCLCPP_PUBLIC
bool
can_communicate(PublisherInfo pub_info, SubscriptionInfo sub_info) const;
template<typename MessageT>
void
add_shared_msg_to_buffers(
std::shared_ptr<const MessageT> message,
std::vector<uint64_t> subscription_ids)
{
for (auto id : subscription_ids) {
auto subscription_it = subscriptions_.find(id);
if (subscription_it == subscriptions_.end()) {
throw std::runtime_error("subscription has unexpectedly gone out of scope");
}
auto subscription_base = subscription_it->second.subscription;
auto subscription = std::static_pointer_cast<
rclcpp::experimental::SubscriptionIntraProcess<MessageT>
>(subscription_base);
subscription->provide_intra_process_message(message);
}
}
template<
typename MessageT,
typename Alloc = std::allocator<void>,
typename Deleter = std::default_delete<MessageT>>
void
add_owned_msg_to_buffers(
std::unique_ptr<MessageT, Deleter> message,
std::vector<uint64_t> subscription_ids,
std::shared_ptr<typename allocator::AllocRebind<MessageT, Alloc>::allocator_type> allocator)
{
using MessageAllocTraits = allocator::AllocRebind<MessageT, Alloc>;
using MessageUniquePtr = std::unique_ptr<MessageT, Deleter>;
for (auto it = subscription_ids.begin(); it != subscription_ids.end(); it++) {
auto subscription_it = subscriptions_.find(*it);
if (subscription_it == subscriptions_.end()) {
throw std::runtime_error("subscription has unexpectedly gone out of scope");
}
auto subscription_base = subscription_it->second.subscription;
auto subscription = std::static_pointer_cast<
rclcpp::experimental::SubscriptionIntraProcess<MessageT>
>(subscription_base);
if (std::next(it) == subscription_ids.end()) {
// If this is the last subscription, give up ownership
subscription->provide_intra_process_message(std::move(message));
} else {
// Copy the message since we have additional subscriptions to serve
MessageUniquePtr copy_message;
Deleter deleter = message.get_deleter();
auto ptr = MessageAllocTraits::allocate(*allocator.get(), 1);
MessageAllocTraits::construct(*allocator.get(), ptr, *message);
copy_message = MessageUniquePtr(ptr, deleter);
subscription->provide_intra_process_message(std::move(copy_message));
}
}
}
PublisherToSubscriptionIdsMap pub_to_subs_;
SubscriptionMap subscriptions_;
PublisherMap publishers_;
mutable std::shared_timed_mutex mutex_;
};
} // namespace experimental
} // namespace rclcpp
#endif // RCLCPP__EXPERIMENTAL__INTRA_PROCESS_MANAGER_HPP_

View File

@@ -1,176 +0,0 @@
// Copyright 2019 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_HPP_
#define RCLCPP__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_HPP_
#include <rmw/rmw.h>
#include <functional>
#include <memory>
#include <string>
#include <utility>
#include "rcl/error_handling.h"
#include "rclcpp/any_subscription_callback.hpp"
#include "rclcpp/experimental/buffers/intra_process_buffer.hpp"
#include "rclcpp/experimental/create_intra_process_buffer.hpp"
#include "rclcpp/experimental/subscription_intra_process_base.hpp"
#include "rclcpp/type_support_decl.hpp"
#include "rclcpp/waitable.hpp"
#include "tracetools/tracetools.h"
namespace rclcpp
{
namespace experimental
{
template<
typename MessageT,
typename Alloc = std::allocator<void>,
typename Deleter = std::default_delete<MessageT>,
typename CallbackMessageT = MessageT>
class SubscriptionIntraProcess : public SubscriptionIntraProcessBase
{
public:
RCLCPP_SMART_PTR_DEFINITIONS(SubscriptionIntraProcess)
using MessageAllocTraits = allocator::AllocRebind<MessageT, Alloc>;
using MessageAlloc = typename MessageAllocTraits::allocator_type;
using ConstMessageSharedPtr = std::shared_ptr<const MessageT>;
using MessageUniquePtr = std::unique_ptr<MessageT, Deleter>;
using BufferUniquePtr = typename rclcpp::experimental::buffers::IntraProcessBuffer<
MessageT,
Alloc,
Deleter
>::UniquePtr;
SubscriptionIntraProcess(
AnySubscriptionCallback<CallbackMessageT, Alloc> callback,
std::shared_ptr<Alloc> allocator,
rclcpp::Context::SharedPtr context,
const std::string & topic_name,
rmw_qos_profile_t qos_profile,
rclcpp::IntraProcessBufferType buffer_type)
: SubscriptionIntraProcessBase(topic_name, qos_profile),
any_callback_(callback)
{
if (!std::is_same<MessageT, CallbackMessageT>::value) {
throw std::runtime_error("SubscriptionIntraProcess wrong callback type");
}
// Create the intra-process buffer.
buffer_ = rclcpp::experimental::create_intra_process_buffer<MessageT, Alloc, Deleter>(
buffer_type,
qos_profile,
allocator);
// Create the guard condition.
rcl_guard_condition_options_t guard_condition_options =
rcl_guard_condition_get_default_options();
gc_ = rcl_get_zero_initialized_guard_condition();
rcl_ret_t ret = rcl_guard_condition_init(
&gc_, context->get_rcl_context().get(), guard_condition_options);
if (RCL_RET_OK != ret) {
throw std::runtime_error("SubscriptionIntraProcess init error initializing guard condition");
}
TRACEPOINT(
rclcpp_subscription_callback_added,
(const void *)this,
(const void *)&any_callback_);
// The callback object gets copied, so if registration is done too early/before this point
// (e.g. in `AnySubscriptionCallback::set()`), its address won't match any address used later
// in subsequent tracepoints.
#ifndef TRACETOOLS_DISABLED
any_callback_.register_callback_for_tracing();
#endif
}
bool
is_ready(rcl_wait_set_t * wait_set)
{
(void)wait_set;
return buffer_->has_data();
}
void execute()
{
execute_impl<CallbackMessageT>();
}
void
provide_intra_process_message(ConstMessageSharedPtr message)
{
buffer_->add_shared(std::move(message));
trigger_guard_condition();
}
void
provide_intra_process_message(MessageUniquePtr message)
{
buffer_->add_unique(std::move(message));
trigger_guard_condition();
}
bool
use_take_shared_method() const
{
return buffer_->use_take_shared_method();
}
private:
void
trigger_guard_condition()
{
rcl_ret_t ret = rcl_trigger_guard_condition(&gc_);
(void)ret;
}
template<typename T>
typename std::enable_if<std::is_same<T, rcl_serialized_message_t>::value, void>::type
execute_impl()
{
throw std::runtime_error("Subscription intra-process can't handle serialized messages");
}
template<class T>
typename std::enable_if<!std::is_same<T, rcl_serialized_message_t>::value, void>::type
execute_impl()
{
rmw_message_info_t msg_info;
msg_info.publisher_gid = {0, {0}};
msg_info.from_intra_process = true;
if (any_callback_.use_take_shared_method()) {
ConstMessageSharedPtr msg = buffer_->consume_shared();
any_callback_.dispatch_intra_process(msg, msg_info);
} else {
MessageUniquePtr msg = buffer_->consume_unique();
any_callback_.dispatch_intra_process(std::move(msg), msg_info);
}
}
AnySubscriptionCallback<CallbackMessageT, Alloc> any_callback_;
BufferUniquePtr buffer_;
};
} // namespace experimental
} // namespace rclcpp
#endif // RCLCPP__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_HPP_

View File

@@ -1,88 +0,0 @@
// Copyright 2019 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_BASE_HPP_
#define RCLCPP__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_BASE_HPP_
#include <rmw/rmw.h>
#include <functional>
#include <memory>
#include <mutex>
#include <string>
#include <utility>
#include "rcl/error_handling.h"
#include "rclcpp/type_support_decl.hpp"
#include "rclcpp/waitable.hpp"
namespace rclcpp
{
namespace experimental
{
class SubscriptionIntraProcessBase : public rclcpp::Waitable
{
public:
RCLCPP_SMART_PTR_ALIASES_ONLY(SubscriptionIntraProcessBase)
RCLCPP_PUBLIC
SubscriptionIntraProcessBase(const std::string & topic_name, rmw_qos_profile_t qos_profile)
: topic_name_(topic_name), qos_profile_(qos_profile)
{}
virtual ~SubscriptionIntraProcessBase() = default;
RCLCPP_PUBLIC
size_t
get_number_of_ready_guard_conditions() {return 1;}
RCLCPP_PUBLIC
bool
add_to_wait_set(rcl_wait_set_t * wait_set);
virtual bool
is_ready(rcl_wait_set_t * wait_set) = 0;
virtual void
execute() = 0;
virtual bool
use_take_shared_method() const = 0;
RCLCPP_PUBLIC
const char *
get_topic_name() const;
RCLCPP_PUBLIC
rmw_qos_profile_t
get_actual_qos() const;
protected:
std::recursive_mutex reentrant_mutex_;
rcl_guard_condition_t gc_;
private:
virtual void
trigger_guard_condition() = 0;
std::string topic_name_;
rmw_qos_profile_t qos_profile_;
};
} // namespace experimental
} // namespace rclcpp
#endif // RCLCPP__EXPERIMENTAL__SUBSCRIPTION_INTRA_PROCESS_BASE_HPP_

View File

@@ -21,10 +21,8 @@
namespace rclcpp
{
namespace function_traits
{
/* NOTE(esteve):
* We support service callbacks that can optionally take the request id,
* which should be possible with two overloaded create_service methods,
@@ -35,132 +33,139 @@ namespace function_traits
*/
// Remove the first item in a tuple
template<typename T>
template <typename T>
struct tuple_tail;
template<typename Head, typename ... Tail>
struct tuple_tail<std::tuple<Head, Tail ...>>
template <typename Head, typename... Tail>
struct tuple_tail<std::tuple<Head, Tail...>>
{
using type = std::tuple<Tail ...>;
using type = std::tuple<Tail...>;
};
// std::function
template<typename FunctionT>
template <typename FunctionT>
struct function_traits
{
using arguments = typename tuple_tail<
typename function_traits<decltype( &FunctionT::operator())>::arguments>::type;
typename function_traits<decltype(&FunctionT::operator())>::arguments>::type;
static constexpr std::size_t arity = std::tuple_size<arguments>::value;
template<std::size_t N>
template <std::size_t N>
using argument_type = typename std::tuple_element<N, arguments>::type;
using return_type = typename function_traits<decltype( &FunctionT::operator())>::return_type;
using return_type = typename function_traits<decltype(&FunctionT::operator())>::return_type;
};
// Free functions
template<typename ReturnTypeT, typename ... Args>
struct function_traits<ReturnTypeT(Args ...)>
template <typename ReturnTypeT, typename... Args>
struct function_traits<ReturnTypeT(Args...)>
{
using arguments = std::tuple<Args ...>;
using arguments = std::tuple<Args...>;
static constexpr std::size_t arity = std::tuple_size<arguments>::value;
template<std::size_t N>
template <std::size_t N>
using argument_type = typename std::tuple_element<N, arguments>::type;
using return_type = ReturnTypeT;
};
// Function pointers
template<typename ReturnTypeT, typename ... Args>
struct function_traits<ReturnTypeT (*)(Args ...)>: function_traits<ReturnTypeT(Args ...)>
{};
template <typename ReturnTypeT, typename... Args>
struct function_traits<ReturnTypeT (*)(Args...)> : function_traits<ReturnTypeT(Args...)>
{
};
// std::bind for object methods
template<typename ClassT, typename ReturnTypeT, typename ... Args, typename ... FArgs>
template <typename ClassT, typename ReturnTypeT, typename... Args, typename... FArgs>
#if defined _LIBCPP_VERSION // libc++ (Clang)
struct function_traits<std::__bind<ReturnTypeT (ClassT::*)(Args ...), FArgs ...>>
struct function_traits<std::__bind<ReturnTypeT (ClassT::*)(Args...), FArgs...>>
#elif defined _GLIBCXX_RELEASE // glibc++ (GNU C++ >= 7.1)
struct function_traits<std::_Bind<ReturnTypeT(ClassT::*(FArgs ...))(Args ...)>>
#elif defined __GLIBCXX__ // glibc++ (GNU C++)
struct function_traits<std::_Bind<std::_Mem_fn<ReturnTypeT (ClassT::*)(Args ...)>(FArgs ...)>>
#elif defined _MSC_VER // MS Visual Studio
struct function_traits<std::_Bind<ReturnTypeT (ClassT::*(FArgs...))(Args...)>>
#elif defined __GLIBCXX__ // glibc++ (GNU C++)
struct function_traits<std::_Bind<std::_Mem_fn<ReturnTypeT (ClassT::*)(Args...)>(FArgs...)>>
#elif defined _MSC_VER // MS Visual Studio
struct function_traits<
std::_Binder<std::_Unforced, ReturnTypeT (ClassT::*)(Args ...), FArgs ...>>
std::_Binder<std::_Unforced, ReturnTypeT (__cdecl ClassT::*)(Args...), FArgs...>>
#else
#error "Unsupported C++ compiler / standard library"
#endif
: function_traits<ReturnTypeT(Args ...)>
{};
: function_traits<ReturnTypeT(Args...)>
{
};
// std::bind for object const methods
template<typename ClassT, typename ReturnTypeT, typename ... Args, typename ... FArgs>
template <typename ClassT, typename ReturnTypeT, typename... Args, typename... FArgs>
#if defined _LIBCPP_VERSION // libc++ (Clang)
struct function_traits<std::__bind<ReturnTypeT (ClassT::*)(Args ...) const, FArgs ...>>
struct function_traits<std::__bind<ReturnTypeT (ClassT::*)(Args...) const, FArgs...>>
#elif defined _GLIBCXX_RELEASE // glibc++ (GNU C++ >= 7.1)
struct function_traits<std::_Bind<ReturnTypeT(ClassT::*(FArgs ...))(Args ...) const>>
#elif defined __GLIBCXX__ // glibc++ (GNU C++)
struct function_traits<std::_Bind<std::_Mem_fn<ReturnTypeT (ClassT::*)(Args ...) const>(FArgs ...)>>
#elif defined _MSC_VER // MS Visual Studio
struct function_traits<std::_Bind<ReturnTypeT (ClassT::*(FArgs...))(Args...) const>>
#elif defined __GLIBCXX__ // glibc++ (GNU C++)
struct function_traits<std::_Bind<std::_Mem_fn<ReturnTypeT (ClassT::*)(Args...) const>(FArgs...)>>
#elif defined _MSC_VER // MS Visual Studio
struct function_traits<
std::_Binder<std::_Unforced, ReturnTypeT (ClassT::*)(Args ...) const, FArgs ...>>
std::_Binder<std::_Unforced, ReturnTypeT (__cdecl ClassT::*)(Args...) const, FArgs...>>
#else
#error "Unsupported C++ compiler / standard library"
#endif
: function_traits<ReturnTypeT(Args ...)>
{};
: function_traits<ReturnTypeT(Args...)>
{
};
// std::bind for free functions
template<typename ReturnTypeT, typename ... Args, typename ... FArgs>
template <typename ReturnTypeT, typename... Args, typename... FArgs>
#if defined _LIBCPP_VERSION // libc++ (Clang)
struct function_traits<std::__bind<ReturnTypeT( &)(Args ...), FArgs ...>>
struct function_traits<std::__bind<ReturnTypeT (&)(Args...), FArgs...>>
#elif defined __GLIBCXX__ // glibc++ (GNU C++)
struct function_traits<std::_Bind<ReturnTypeT(*(FArgs ...))(Args ...)>>
#elif defined _MSC_VER // MS Visual Studio
struct function_traits<std::_Binder<std::_Unforced, ReturnTypeT( &)(Args ...), FArgs ...>>
struct function_traits<std::_Bind<ReturnTypeT (*(FArgs...))(Args...)>>
#elif defined _MSC_VER // MS Visual Studio
struct function_traits<std::_Binder<std::_Unforced, ReturnTypeT(__cdecl &)(Args...), FArgs...>>
#else
#error "Unsupported C++ compiler / standard library"
#endif
: function_traits<ReturnTypeT(Args ...)>
{};
: function_traits<ReturnTypeT(Args...)>
{
};
// Lambdas
template<typename ClassT, typename ReturnTypeT, typename ... Args>
struct function_traits<ReturnTypeT (ClassT::*)(Args ...) const>
: function_traits<ReturnTypeT(ClassT &, Args ...)>
{};
template <typename ClassT, typename ReturnTypeT, typename... Args>
struct function_traits<ReturnTypeT (ClassT::*)(Args...) const>
: function_traits<ReturnTypeT(ClassT &, Args...)>
{
};
template<typename FunctionT>
struct function_traits<FunctionT &>: function_traits<FunctionT>
{};
template <typename FunctionT>
struct function_traits<FunctionT &> : function_traits<FunctionT>
{
};
template<typename FunctionT>
struct function_traits<FunctionT &&>: function_traits<FunctionT>
{};
template <typename FunctionT>
struct function_traits<FunctionT &&> : function_traits<FunctionT>
{
};
/* NOTE(esteve):
* VS2015 does not support expression SFINAE, so we're using this template to evaluate
* the arity of a function.
*/
template<std::size_t Arity, typename FunctorT>
struct arity_comparator : std::integral_constant<
bool, (Arity == function_traits<FunctorT>::arity)> {};
template <std::size_t Arity, typename FunctorT>
struct arity_comparator : std::integral_constant<bool, (Arity == function_traits<FunctorT>::arity)>
{
};
template<typename FunctorT, typename ... Args>
struct check_arguments : std::is_same<
typename function_traits<FunctorT>::arguments,
std::tuple<Args ...>
>
{};
template <typename FunctorT, typename... Args>
struct check_arguments
: std::is_same<typename function_traits<FunctorT>::arguments, std::tuple<Args...>>
{
};
template<typename FunctorAT, typename FunctorBT>
template <typename FunctorAT, typename FunctorBT>
struct same_arguments : std::is_same<
typename function_traits<FunctorAT>::arguments,
typename function_traits<FunctorBT>::arguments
>
{};
typename function_traits<FunctorAT>::arguments,
typename function_traits<FunctorBT>::arguments>
{
};
} // namespace function_traits

View File

@@ -1,53 +0,0 @@
// Copyright 2014 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__FUTURE_RETURN_CODE_HPP_
#define RCLCPP__FUTURE_RETURN_CODE_HPP_
#include <iostream>
#include <string>
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
/// Return codes to be used with spin_until_future_complete.
/**
* SUCCESS: The future is complete and can be accessed with "get" without blocking.
* This does not indicate that the operation succeeded; "get" may still throw an exception.
* INTERRUPTED: The future is not complete, spinning was interrupted by Ctrl-C or another error.
* TIMEOUT: Spinning timed out.
*/
enum class FutureReturnCode {SUCCESS, INTERRUPTED, TIMEOUT};
/// Stream operator for FutureReturnCode.
RCLCPP_PUBLIC
std::ostream &
operator<<(std::ostream & os, const FutureReturnCode & future_return_code);
/// String conversion function for FutureReturnCode.
RCLCPP_PUBLIC
std::string
to_string(const FutureReturnCode & future_return_code);
namespace executor
{
using FutureReturnCode [[deprecated("use rclcpp::FutureReturnCode instead")]] = FutureReturnCode;
} // namespace executor
} // namespace rclcpp
#endif // RCLCPP__FUTURE_RETURN_CODE_HPP_

View File

@@ -30,32 +30,27 @@
namespace rclcpp
{
namespace graph_listener
{
/// Thrown when a function is called on a GraphListener that is already shutdown.
class GraphListenerShutdownError : public std::runtime_error
{
public:
GraphListenerShutdownError()
: std::runtime_error("GraphListener already shutdown") {}
GraphListenerShutdownError() : std::runtime_error("GraphListener already shutdown") {}
};
/// Thrown when a node has already been added to the GraphListener.
class NodeAlreadyAddedError : public std::runtime_error
{
public:
NodeAlreadyAddedError()
: std::runtime_error("node already added") {}
NodeAlreadyAddedError() : std::runtime_error("node already added") {}
};
/// Thrown when the given node is not in the GraphListener.
class NodeNotFoundError : public std::runtime_error
{
public:
NodeNotFoundError()
: std::runtime_error("node not found") {}
NodeNotFoundError() : std::runtime_error("node not found") {}
};
/// Notifies many nodes of graph changes by listening in a thread.
@@ -75,9 +70,7 @@ public:
* \throws GraphListenerShutdownError if the GraphListener is shutdown
*/
RCLCPP_PUBLIC
virtual
void
start_if_not_started();
virtual void start_if_not_started();
/// Add a node to the graph listener's list of nodes.
/**
@@ -87,9 +80,7 @@ public:
* \throws std::system_error anything std::mutex::lock() throws
*/
RCLCPP_PUBLIC
virtual
void
add_node(rclcpp::node_interfaces::NodeGraphInterface * node_graph);
virtual void add_node(rclcpp::node_interfaces::NodeGraphInterface * node_graph);
/// Return true if the given node is in the graph listener's list of nodes.
/**
@@ -98,9 +89,7 @@ public:
* \throws std::system_error anything std::mutex::lock() throws
*/
RCLCPP_PUBLIC
virtual
bool
has_node(rclcpp::node_interfaces::NodeGraphInterface * node_graph);
virtual bool has_node(rclcpp::node_interfaces::NodeGraphInterface * node_graph);
/// Remove a node from the graph listener's list of nodes.
/**
@@ -110,9 +99,7 @@ public:
* \throws std::system_error anything std::mutex::lock() throws
*/
RCLCPP_PUBLIC
virtual
void
remove_node(rclcpp::node_interfaces::NodeGraphInterface * node_graph);
virtual void remove_node(rclcpp::node_interfaces::NodeGraphInterface * node_graph);
/// Stop the listening thread.
/**
@@ -130,42 +117,31 @@ public:
* \throws std::system_error anything std::mutex::lock() throws
*/
RCLCPP_PUBLIC
virtual
void
shutdown();
virtual void shutdown();
/// Nothrow version of shutdown(), logs to RCLCPP_ERROR instead.
RCLCPP_PUBLIC
virtual
void
shutdown(const std::nothrow_t &) noexcept;
virtual void shutdown(const std::nothrow_t &) noexcept;
/// Return true if shutdown() has been called, else false.
RCLCPP_PUBLIC
virtual
bool
is_shutdown();
virtual bool is_shutdown();
protected:
/// Main function for the listening thread.
RCLCPP_PUBLIC
virtual
void
run();
virtual void run();
RCLCPP_PUBLIC
virtual
void
run_loop();
virtual void run_loop();
private:
RCLCPP_DISABLE_COPY(GraphListener)
/** \internal */
void
__shutdown(bool);
void __shutdown(bool);
rclcpp::Context::WeakPtr parent_context_;
rclcpp::Context::SharedPtr parent_context_;
std::thread listener_thread_;
bool is_started_;
@@ -177,6 +153,7 @@ private:
std::vector<rclcpp::node_interfaces::NodeGraphInterface *> node_graph_interfaces_;
rcl_guard_condition_t interrupt_guard_condition_ = rcl_get_zero_initialized_guard_condition();
std::shared_ptr<rcl_context_t> interrupt_guard_condition_context_;
rcl_guard_condition_t * shutdown_guard_condition_;
rcl_wait_set_t wait_set_ = rcl_get_zero_initialized_wait_set();
};

View File

@@ -1,100 +0,0 @@
// Copyright 2020 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__GUARD_CONDITION_HPP_
#define RCLCPP__GUARD_CONDITION_HPP_
#include <atomic>
#include "rcl/guard_condition.h"
#include "rclcpp/context.hpp"
#include "rclcpp/contexts/default_context.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
/// A condition that can be waited on in a single wait set and asynchronously triggered.
class GuardCondition
{
public:
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(GuardCondition)
// TODO(wjwwood): support custom allocator, maybe restrict to polymorphic allocator
/// Construct the guard condition, optionally specifying which Context to use.
/**
* \param[in] context Optional custom context to be used.
* Defaults to using the global default context singleton.
* Shared ownership of the context is held with the guard condition until
* destruction.
* \throws std::invalid_argument if the context is nullptr.
* \throws rclcpp::exceptions::RCLError based exceptions when underlying
* rcl functions fail.
*/
RCLCPP_PUBLIC
explicit GuardCondition(
rclcpp::Context::SharedPtr context =
rclcpp::contexts::get_global_default_context());
RCLCPP_PUBLIC
virtual
~GuardCondition();
/// Return the context used when creating this guard condition.
RCLCPP_PUBLIC
rclcpp::Context::SharedPtr
get_context() const;
/// Return the underlying rcl guard condition structure.
RCLCPP_PUBLIC
const rcl_guard_condition_t &
get_rcl_guard_condition() const;
/// Notify the wait set waiting on this condition, if any, that the condition had been met.
/**
* This function is thread-safe, and may be called concurrently with waiting
* on this guard condition in a wait set.
*
* \throws rclcpp::exceptions::RCLError based exceptions when underlying
* rcl functions fail.
*/
RCLCPP_PUBLIC
void
trigger();
/// Exchange the "in use by wait set" state for this guard condition.
/**
* This is used to ensure this guard condition is not used by multiple
* wait sets at the same time.
*
* \param[in] in_use_state the new state to exchange into the state, true
* indicates it is now in use by a wait set, and false is that it is no
* longer in use by a wait set.
* \returns the previous state.
*/
RCLCPP_PUBLIC
bool
exchange_in_use_by_wait_set_state(bool in_use_state);
protected:
rclcpp::Context::SharedPtr context_;
rcl_guard_condition_t rcl_guard_condition_;
std::atomic<bool> in_use_by_wait_set_{false};
};
} // namespace rclcpp
#endif // RCLCPP__GUARD_CONDITION_HPP_

View File

@@ -22,7 +22,6 @@
namespace rclcpp
{
/// Encapsulation of options for initializing rclcpp.
class InitOptions
{
@@ -44,21 +43,17 @@ public:
/// Assignment operator.
RCLCPP_PUBLIC
InitOptions &
operator=(const InitOptions & other);
InitOptions & operator=(const InitOptions & other);
RCLCPP_PUBLIC
virtual
~InitOptions();
virtual ~InitOptions();
/// Return the rcl init options.
RCLCPP_PUBLIC
const rcl_init_options_t *
get_rcl_init_options() const;
const rcl_init_options_t * get_rcl_init_options() const;
protected:
void
finalize_init_options();
void finalize_init_options();
private:
std::unique_ptr<rcl_init_options_t> init_options_;

View File

@@ -1,35 +0,0 @@
// Copyright 2019 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__INTRA_PROCESS_BUFFER_TYPE_HPP_
#define RCLCPP__INTRA_PROCESS_BUFFER_TYPE_HPP_
namespace rclcpp
{
/// Used as argument in create_publisher and create_subscriber
/// when intra-process communication is enabled
enum class IntraProcessBufferType
{
/// Set the data type used in the intra-process buffer as std::shared_ptr<MessageT>
SharedPtr,
/// Set the data type used in the intra-process buffer as std::unique_ptr<MessageT>
UniquePtr,
/// Set the data type used in the intra-process buffer as the same used in the callback
CallbackDefault
};
} // namespace rclcpp
#endif // RCLCPP__INTRA_PROCESS_BUFFER_TYPE_HPP_

View File

@@ -0,0 +1,398 @@
// 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.
#ifndef RCLCPP__INTRA_PROCESS_MANAGER_HPP_
#define RCLCPP__INTRA_PROCESS_MANAGER_HPP_
#include <rmw/types.h>
#include <algorithm>
#include <atomic>
#include <cstdint>
#include <exception>
#include <map>
#include <memory>
#include <mutex>
#include <set>
#include <unordered_map>
#include <utility>
#include "rclcpp/allocator/allocator_deleter.hpp"
#include "rclcpp/intra_process_manager_impl.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/mapped_ring_buffer.hpp"
#include "rclcpp/publisher_base.hpp"
#include "rclcpp/subscription_base.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
namespace intra_process_manager
{
/// This class facilitates intra process communication between nodes.
/**
* This class is used in the creation of publishers and subscriptions.
* A singleton instance of this class is owned by a rclcpp::Context and a
* rclcpp::Node can use an associated Context to get an instance of this class.
* Nodes which do not have a common Context will not exchange intra process
* messages because they will not share access to an instance of this class.
*
* When a Node creates a publisher or subscription, it will register them
* with this class.
* The node will also hook into the publisher's publish call
* in order to do intra process related work.
*
* When a publisher is created, it advertises on the topic the user provided,
* as well as a "shadowing" topic of type rcl_interfaces/IntraProcessMessage.
* For instance, if the user specified the topic '/namespace/chatter', then the
* corresponding intra process topic might be '/namespace/chatter/_intra'.
* The publisher is also allocated an id which is unique among all publishers
* and subscriptions in this process.
* Additionally, when registered with this class a ring buffer is created and
* owned by this class as a temporary place to hold messages destined for intra
* process subscriptions.
*
* When a subscription is created, it subscribes to the topic provided by the
* user as well as to the corresponding intra process topic.
* It is also gets a unique id from the singleton instance of this class which
* is unique among publishers and subscriptions.
*
* When the user publishes a message, the message is stored by calling
* store_intra_process_message on this class.
* The instance of that message is uniquely identified by a publisher id and a
* message sequence number.
* The publisher id, message sequence pair is unique with in the process.
* At that point a list of the id's of intra process subscriptions which have
* been registered with the singleton instance of this class are stored with
* the message instance so that delivery is only made to those subscriptions.
* Then an instance of rcl_interfaces/IntraProcessMessage is published to the
* intra process topic which is specific to the topic specified by the user.
*
* When an instance of rcl_interfaces/IntraProcessMessage is received by a
* subscription, then it is handled by calling take_intra_process_message
* on a singleton of this class.
* The subscription passes a publisher id, message sequence pair which
* uniquely identifies the message instance it was suppose to receive as well
* as the subscriptions unique id.
* If the message is still being held by this class and the subscription's id
* is in the list of intended subscriptions then the message is returned.
* If either of those predicates are not satisfied then the message is not
* returned and the subscription does not call the users callback.
*
* Since the publisher builds a list of destined subscriptions on publish, and
* other requests are ignored, this class knows how many times a message
* instance should be requested.
* The final time a message is requested, the ownership is passed out of this
* class and passed to the final subscription, effectively freeing space in
* this class's internal storage.
*
* Since a topic is being used to ferry notifications about new intra process
* messages between publishers and subscriptions, it is possible for that
* notification to be lost.
* It is also possible that a subscription which was available when publish was
* called will no longer exist once the notification gets posted.
* In both cases this might result in a message instance getting requested
* fewer times than expected.
* This is why the internal storage of this class is a ring buffer.
* That way if a message is orphaned it will eventually be dropped from storage
* when a new message instance is stored and will not result in a memory leak.
*
* However, since the storage system is finite, this also means that a message
* instance might get displaced by an incoming message instance before all
* interested parties have called take_intra_process_message.
* Because of this the size of the internal storage should be carefully
* considered.
*
* /TODO(wjwwood): update to include information about handling latching.
* /TODO(wjwwood): consider thread safety of the class.
*
* This class is neither CopyConstructable nor CopyAssignable.
*/
class IntraProcessManager
{
private:
RCLCPP_DISABLE_COPY(IntraProcessManager)
public:
RCLCPP_SMART_PTR_DEFINITIONS(IntraProcessManager)
RCLCPP_PUBLIC
explicit IntraProcessManager(
IntraProcessManagerImplBase::SharedPtr state = create_default_impl());
RCLCPP_PUBLIC
virtual ~IntraProcessManager();
/// Register a subscription with the manager, returns subscriptions unique id.
/**
* In addition to generating a unique intra process id for the subscription,
* this method also stores the topic name of the subscription.
*
* This method is normally called during the creation of a subscription,
* but after it creates the internal intra process rmw_subscription_t.
*
* This method will allocate memory.
*
* \param subscription the Subscription to register.
* \return an unsigned 64-bit integer which is the subscription's unique id.
*/
RCLCPP_PUBLIC
uint64_t add_subscription(SubscriptionBase::SharedPtr subscription);
/// Unregister a subscription using the subscription's unique id.
/**
* This method does not allocate memory.
*
* \param intra_process_subscription_id id of the subscription to remove.
*/
RCLCPP_PUBLIC
void remove_subscription(uint64_t intra_process_subscription_id);
/// Register a publisher with the manager, returns the publisher unique id.
/**
* In addition to generating and returning a unique id for the publisher,
* this method creates internal ring buffer storage for "in-flight" intra
* process messages which are stored when store_intra_process_message is
* called with this publisher's unique id.
*
* The buffer_size must be less than or equal to the max uint64_t value.
* If the buffer_size is 0 then a buffer size is calculated using the
* publisher's QoS settings.
* The default is to use the depth field of the publisher's QoS.
* TODO(wjwwood): Consider doing depth *= 1.2, round up, or similar.
* TODO(wjwwood): Consider what to do for keep all.
*
* This method is templated on the publisher's message type so that internal
* storage of the same type can be allocated.
*
* This method will allocate memory.
*
* \param publisher publisher to be registered with the manager.
* \param buffer_size if 0 (default) a size is calculated based on the QoS.
* \return an unsigned 64-bit integer which is the publisher's unique id.
*/
RCLCPP_PUBLIC
uint64_t add_publisher(rclcpp::PublisherBase::SharedPtr publisher, size_t buffer_size = 0);
/// Unregister a publisher using the publisher's unique id.
/**
* This method does not allocate memory.
*
* \param intra_process_publisher_id id of the publisher to remove.
*/
RCLCPP_PUBLIC
void remove_publisher(uint64_t intra_process_publisher_id);
/// Store a message in the manager, and return the message sequence number.
/**
* The given message is stored in internal storage using the given publisher
* id and the newly generated message sequence, which is also returned.
* The combination of publisher id and message sequence number can later
* be used with a subscription id to retrieve the message by calling
* take_intra_process_message.
* The number of times take_intra_process_message can be called with this
* unique pair of id's is determined by the number of subscriptions currently
* subscribed to the same topic and which share the same Context, i.e. once
* for each subscription which should receive the intra process message.
*
* The ownership of the incoming message is transfered to the internal
* storage in order to avoid copying the message data.
* Therefore, the message parameter will no longer contain the original
* message after calling this method.
* Instead it will either be a nullptr or it will contain the ownership of
* the message instance which was displaced.
* If the message parameter is not equal to nullptr after calling this method
* then a message was prematurely displaced, i.e. take_intra_process_message
* had not been called on it as many times as was expected.
*
* This method can throw an exception if the publisher id is not found or
* if the publisher shared_ptr given to add_publisher has gone out of scope.
*
* This method does allocate memory.
*
* \param intra_process_publisher_id the id of the publisher of this message.
* \param message the message that is being stored.
* \return the message sequence number.
*/
template <typename MessageT, typename Alloc = std::allocator<void>>
uint64_t store_intra_process_message(
uint64_t intra_process_publisher_id, std::shared_ptr<const MessageT> message)
{
using MRBMessageAlloc = typename std::allocator_traits<Alloc>::template rebind_alloc<MessageT>;
using TypedMRB = typename mapped_ring_buffer::MappedRingBuffer<MessageT, MRBMessageAlloc>;
uint64_t message_seq = 0;
mapped_ring_buffer::MappedRingBufferBase::SharedPtr buffer =
impl_->get_publisher_info_for_id(intra_process_publisher_id, message_seq);
typename TypedMRB::SharedPtr typed_buffer = std::static_pointer_cast<TypedMRB>(buffer);
if (!typed_buffer) {
throw std::runtime_error("Typecast failed due to incorrect message type");
}
// Insert the message into the ring buffer using the message_seq to identify it.
bool did_replace = typed_buffer->push_and_replace(message_seq, message);
// TODO(wjwwood): do something when a message was displaced. log debug?
(void)did_replace; // Avoid unused variable warning.
impl_->store_intra_process_message(intra_process_publisher_id, message_seq);
// Return the message sequence which is sent to the subscription.
return message_seq;
}
template <
typename MessageT,
typename Alloc = std::allocator<void>,
typename Deleter = std::default_delete<MessageT>>
uint64_t store_intra_process_message(
uint64_t intra_process_publisher_id, std::unique_ptr<MessageT, Deleter> message)
{
using MRBMessageAlloc = typename std::allocator_traits<Alloc>::template rebind_alloc<MessageT>;
using TypedMRB = typename mapped_ring_buffer::MappedRingBuffer<MessageT, MRBMessageAlloc>;
uint64_t message_seq = 0;
mapped_ring_buffer::MappedRingBufferBase::SharedPtr buffer =
impl_->get_publisher_info_for_id(intra_process_publisher_id, message_seq);
typename TypedMRB::SharedPtr typed_buffer = std::static_pointer_cast<TypedMRB>(buffer);
if (!typed_buffer) {
throw std::runtime_error("Typecast failed due to incorrect message type");
}
// Insert the message into the ring buffer using the message_seq to identify it.
bool did_replace = typed_buffer->push_and_replace(message_seq, std::move(message));
// TODO(wjwwood): do something when a message was displaced. log debug?
(void)did_replace; // Avoid unused variable warning.
impl_->store_intra_process_message(intra_process_publisher_id, message_seq);
// Return the message sequence which is sent to the subscription.
return message_seq;
}
/// Take an intra process message.
/**
* The intra_process_publisher_id and message_sequence_number parameters
* uniquely identify a message instance, which should be taken.
*
* The requesting_subscriptions_intra_process_id parameter is used to make
* sure the requesting subscription was intended to receive this message
* instance.
* This check is made because it could happen that the requester
* comes up after the publish event, so it still receives the notification of
* a new intra process message, but it wasn't registered with the manager at
* the time of publishing, causing it to take when it wasn't intended.
* This should be avioded unless latching-like behavior is involved.
*
* The message parameter is used to store the taken message.
* On the last expected call to this method, the ownership is transfered out
* of internal storage and into the message parameter.
* On all previous calls a copy of the internally stored message is made and
* the ownership of the copy is transfered to the message parameter.
* TODO(wjwwood): update this documentation when latching is supported.
*
* The message parameter can be set to nullptr if:
*
* - The publisher id is not found.
* - The message sequence is not found for the given publisher id.
* - The requesting subscription's id is not in the list of intended takers.
* - The requesting subscription's id has been used before with this message.
*
* This method may allocate memory to copy the stored message.
*
* \param intra_process_publisher_id the id of the message's publisher.
* \param message_sequence_number the sequence number of the message.
* \param requesting_subscriptions_intra_process_id the subscription's id.
* \param message the message typed unique_ptr used to return the message.
*/
template <
typename MessageT,
typename Alloc = std::allocator<void>,
typename Deleter = std::default_delete<MessageT>>
void take_intra_process_message(
uint64_t intra_process_publisher_id,
uint64_t message_sequence_number,
uint64_t requesting_subscriptions_intra_process_id,
std::unique_ptr<MessageT, Deleter> & message)
{
using MRBMessageAlloc = typename std::allocator_traits<Alloc>::template rebind_alloc<MessageT>;
using TypedMRB = mapped_ring_buffer::MappedRingBuffer<MessageT, MRBMessageAlloc>;
message = nullptr;
size_t target_subs_size = 0;
std::lock_guard<std::mutex> lock(take_mutex_);
mapped_ring_buffer::MappedRingBufferBase::SharedPtr buffer = impl_->take_intra_process_message(
intra_process_publisher_id, message_sequence_number,
requesting_subscriptions_intra_process_id, target_subs_size);
typename TypedMRB::SharedPtr typed_buffer = std::static_pointer_cast<TypedMRB>(buffer);
if (!typed_buffer) {
return;
}
// Return a copy or the unique_ptr (ownership) depending on how many subscriptions are left.
if (target_subs_size) {
// There are more subscriptions to serve, return a copy.
typed_buffer->get(message_sequence_number, message);
} else {
// This is the last one to be returned, transfer ownership.
typed_buffer->pop(message_sequence_number, message);
}
}
template <typename MessageT, typename Alloc = std::allocator<void>>
void take_intra_process_message(
uint64_t intra_process_publisher_id,
uint64_t message_sequence_number,
uint64_t requesting_subscriptions_intra_process_id,
std::shared_ptr<const MessageT> & message)
{
using MRBMessageAlloc = typename std::allocator_traits<Alloc>::template rebind_alloc<MessageT>;
using TypedMRB = mapped_ring_buffer::MappedRingBuffer<MessageT, MRBMessageAlloc>;
message = nullptr;
size_t target_subs_size = 0;
std::lock_guard<std::mutex> lock(take_mutex_);
mapped_ring_buffer::MappedRingBufferBase::SharedPtr buffer = impl_->take_intra_process_message(
intra_process_publisher_id, message_sequence_number,
requesting_subscriptions_intra_process_id, target_subs_size);
typename TypedMRB::SharedPtr typed_buffer = std::static_pointer_cast<TypedMRB>(buffer);
if (!typed_buffer) {
return;
}
// Return a copy or the unique_ptr (ownership) depending on how many subscriptions are left.
if (target_subs_size) {
// There are more subscriptions to serve, return a copy.
typed_buffer->get(message_sequence_number, message);
} else {
// This is the last one to be returned, transfer ownership.
typed_buffer->pop(message_sequence_number, message);
}
}
/// Return true if the given rmw_gid_t matches any stored Publishers.
RCLCPP_PUBLIC
bool matches_any_publishers(const rmw_gid_t * id) const;
/// Return the number of intraprocess subscriptions to a topic, given the publisher id.
RCLCPP_PUBLIC
size_t get_subscription_count(uint64_t intra_process_publisher_id) const;
private:
RCLCPP_PUBLIC
static uint64_t get_next_unique_id();
IntraProcessManagerImplBase::SharedPtr impl_;
std::mutex take_mutex_;
};
} // namespace intra_process_manager
} // namespace rclcpp
#endif // RCLCPP__INTRA_PROCESS_MANAGER_HPP_

View File

@@ -0,0 +1,339 @@
// 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.
#ifndef RCLCPP__INTRA_PROCESS_MANAGER_IMPL_HPP_
#define RCLCPP__INTRA_PROCESS_MANAGER_IMPL_HPP_
#include <algorithm>
#include <array>
#include <atomic>
#include <cstring>
#include <functional>
#include <limits>
#include <map>
#include <memory>
#include <mutex>
#include <set>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include <utility>
#include "rmw/validate_full_topic_name.h"
#include "rclcpp/macros.hpp"
#include "rclcpp/mapped_ring_buffer.hpp"
#include "rclcpp/publisher_base.hpp"
#include "rclcpp/subscription_base.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
namespace intra_process_manager
{
class IntraProcessManagerImplBase
{
public:
RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(IntraProcessManagerImplBase)
IntraProcessManagerImplBase() = default;
virtual ~IntraProcessManagerImplBase() = default;
virtual void add_subscription(uint64_t id, SubscriptionBase::SharedPtr subscription) = 0;
virtual void remove_subscription(uint64_t intra_process_subscription_id) = 0;
virtual void add_publisher(
uint64_t id,
PublisherBase::WeakPtr publisher,
mapped_ring_buffer::MappedRingBufferBase::SharedPtr mrb,
size_t size) = 0;
virtual void remove_publisher(uint64_t intra_process_publisher_id) = 0;
virtual mapped_ring_buffer::MappedRingBufferBase::SharedPtr get_publisher_info_for_id(
uint64_t intra_process_publisher_id, uint64_t & message_seq) = 0;
virtual void store_intra_process_message(
uint64_t intra_process_publisher_id, uint64_t message_seq) = 0;
virtual mapped_ring_buffer::MappedRingBufferBase::SharedPtr take_intra_process_message(
uint64_t intra_process_publisher_id,
uint64_t message_sequence_number,
uint64_t requesting_subscriptions_intra_process_id,
size_t & size) = 0;
virtual bool matches_any_publishers(const rmw_gid_t * id) const = 0;
virtual size_t get_subscription_count(uint64_t intra_process_publisher_id) const = 0;
private:
RCLCPP_DISABLE_COPY(IntraProcessManagerImplBase)
};
template <typename Allocator = std::allocator<void>>
class IntraProcessManagerImpl : public IntraProcessManagerImplBase
{
public:
IntraProcessManagerImpl() = default;
~IntraProcessManagerImpl() = default;
void add_subscription(uint64_t id, SubscriptionBase::SharedPtr subscription)
{
subscriptions_[id] = subscription;
subscription_ids_by_topic_[fixed_size_string(subscription->get_topic_name())].insert(id);
}
void remove_subscription(uint64_t intra_process_subscription_id)
{
subscriptions_.erase(intra_process_subscription_id);
for (auto & pair : subscription_ids_by_topic_) {
pair.second.erase(intra_process_subscription_id);
}
// Iterate over all publisher infos and all stored subscription id's and
// remove references to this subscription's id.
for (auto & publisher_pair : publishers_) {
for (auto & sub_pair : publisher_pair.second.target_subscriptions_by_message_sequence) {
sub_pair.second.erase(intra_process_subscription_id);
}
}
}
void add_publisher(
uint64_t id,
PublisherBase::WeakPtr publisher,
mapped_ring_buffer::MappedRingBufferBase::SharedPtr mrb,
size_t size)
{
publishers_[id].publisher = publisher;
// As long as the size of the ring buffer is less than the max sequence number, we're safe.
if (size > std::numeric_limits<uint64_t>::max()) {
throw std::invalid_argument("the calculated buffer size is too large");
}
publishers_[id].sequence_number.store(0);
publishers_[id].buffer = mrb;
publishers_[id].target_subscriptions_by_message_sequence.reserve(size);
}
void remove_publisher(uint64_t intra_process_publisher_id)
{
publishers_.erase(intra_process_publisher_id);
}
// return message_seq and mrb
mapped_ring_buffer::MappedRingBufferBase::SharedPtr get_publisher_info_for_id(
uint64_t intra_process_publisher_id, uint64_t & message_seq)
{
std::lock_guard<std::mutex> lock(runtime_mutex_);
auto it = publishers_.find(intra_process_publisher_id);
if (it == publishers_.end()) {
throw std::runtime_error("get_publisher_info_for_id called with invalid publisher id");
}
PublisherInfo & info = it->second;
// Calculate the next message sequence number.
message_seq = info.sequence_number.fetch_add(1);
return info.buffer;
}
void store_intra_process_message(uint64_t intra_process_publisher_id, uint64_t message_seq)
{
std::lock_guard<std::mutex> lock(runtime_mutex_);
auto it = publishers_.find(intra_process_publisher_id);
if (it == publishers_.end()) {
throw std::runtime_error("store_intra_process_message called with invalid publisher id");
}
PublisherInfo & info = it->second;
auto publisher = info.publisher.lock();
if (!publisher) {
throw std::runtime_error("publisher has unexpectedly gone out of scope");
}
// Figure out what subscriptions should receive the message.
auto & destined_subscriptions =
subscription_ids_by_topic_[fixed_size_string(publisher->get_topic_name())];
// Store the list for later comparison.
if (info.target_subscriptions_by_message_sequence.count(message_seq) == 0) {
info.target_subscriptions_by_message_sequence.emplace(
message_seq, AllocSet(std::less<uint64_t>(), uint64_allocator));
} else {
info.target_subscriptions_by_message_sequence[message_seq].clear();
}
std::copy(
destined_subscriptions.begin(), destined_subscriptions.end(),
// Memory allocation occurs in info.target_subscriptions_by_message_sequence[message_seq]
std::inserter(
info.target_subscriptions_by_message_sequence[message_seq],
// This ends up only being a hint to std::set, could also be .begin().
info.target_subscriptions_by_message_sequence[message_seq].end()));
}
mapped_ring_buffer::MappedRingBufferBase::SharedPtr take_intra_process_message(
uint64_t intra_process_publisher_id,
uint64_t message_sequence_number,
uint64_t requesting_subscriptions_intra_process_id,
size_t & size)
{
std::lock_guard<std::mutex> lock(runtime_mutex_);
PublisherInfo * info;
{
auto it = publishers_.find(intra_process_publisher_id);
if (it == publishers_.end()) {
// Publisher is either invalid or no longer exists.
return 0;
}
info = &it->second;
}
// Figure out how many subscriptions are left.
AllocSet * target_subs;
{
auto it = info->target_subscriptions_by_message_sequence.find(message_sequence_number);
if (it == info->target_subscriptions_by_message_sequence.end()) {
// Message is no longer being stored by this publisher.
return 0;
}
target_subs = &it->second;
}
{
auto it = std::find(
target_subs->begin(), target_subs->end(), requesting_subscriptions_intra_process_id);
if (it == target_subs->end()) {
// This publisher id/message seq pair was not intended for this subscription.
return 0;
}
target_subs->erase(it);
}
size = target_subs->size();
return info->buffer;
}
bool matches_any_publishers(const rmw_gid_t * id) const
{
for (auto & publisher_pair : publishers_) {
auto publisher = publisher_pair.second.publisher.lock();
if (!publisher) {
continue;
}
if (*publisher.get() == id) {
return true;
}
}
return false;
}
size_t get_subscription_count(uint64_t intra_process_publisher_id) const
{
auto publisher_it = publishers_.find(intra_process_publisher_id);
if (publisher_it == publishers_.end()) {
// Publisher is either invalid or no longer exists.
return 0;
}
auto publisher = publisher_it->second.publisher.lock();
if (!publisher) {
throw std::runtime_error("publisher has unexpectedly gone out of scope");
}
auto sub_map_it =
subscription_ids_by_topic_.find(fixed_size_string(publisher->get_topic_name()));
if (sub_map_it == subscription_ids_by_topic_.end()) {
// No intraprocess subscribers
return 0;
}
return sub_map_it->second.size();
}
private:
RCLCPP_DISABLE_COPY(IntraProcessManagerImpl)
using FixedSizeString = std::array<char, RMW_TOPIC_MAX_NAME_LENGTH + 1>;
FixedSizeString fixed_size_string(const char * str) const
{
FixedSizeString ret;
size_t size = std::strlen(str) + 1;
if (size > ret.size()) {
throw std::runtime_error("failed to copy topic name");
}
std::memcpy(ret.data(), str, size);
return ret;
}
struct strcmp_wrapper
{
bool operator()(const FixedSizeString lhs, const FixedSizeString rhs) const
{
return std::strcmp(lhs.data(), rhs.data()) < 0;
}
};
template <typename T>
using RebindAlloc = typename std::allocator_traits<Allocator>::template rebind_alloc<T>;
RebindAlloc<uint64_t> uint64_allocator;
using AllocSet = std::set<uint64_t, std::less<uint64_t>, RebindAlloc<uint64_t>>;
using SubscriptionMap = std::unordered_map<
uint64_t,
SubscriptionBase::WeakPtr,
std::hash<uint64_t>,
std::equal_to<uint64_t>,
RebindAlloc<std::pair<const uint64_t, SubscriptionBase::WeakPtr>>>;
using IDTopicMap = std::map<
FixedSizeString,
AllocSet,
strcmp_wrapper,
RebindAlloc<std::pair<const FixedSizeString, AllocSet>>>;
SubscriptionMap subscriptions_;
IDTopicMap subscription_ids_by_topic_;
struct PublisherInfo
{
RCLCPP_DISABLE_COPY(PublisherInfo)
PublisherInfo() = default;
PublisherBase::WeakPtr publisher;
std::atomic<uint64_t> sequence_number;
mapped_ring_buffer::MappedRingBufferBase::SharedPtr buffer;
using TargetSubscriptionsMap = std::unordered_map<
uint64_t,
AllocSet,
std::hash<uint64_t>,
std::equal_to<uint64_t>,
RebindAlloc<std::pair<const uint64_t, AllocSet>>>;
TargetSubscriptionsMap target_subscriptions_by_message_sequence;
};
using PublisherMap = std::unordered_map<
uint64_t,
PublisherInfo,
std::hash<uint64_t>,
std::equal_to<uint64_t>,
RebindAlloc<std::pair<const uint64_t, PublisherInfo>>>;
PublisherMap publishers_;
std::mutex runtime_mutex_;
};
RCLCPP_PUBLIC
IntraProcessManagerImplBase::SharedPtr create_default_impl();
} // namespace intra_process_manager
} // namespace rclcpp
#endif // RCLCPP__INTRA_PROCESS_MANAGER_IMPL_HPP_

View File

@@ -17,10 +17,8 @@
namespace rclcpp
{
/// Used as argument in create_publisher and create_subscriber.
enum class IntraProcessSetting
{
enum class IntraProcessSetting {
/// Explicitly enable intraprocess comm at publisher/subscription level.
Enable,
/// Explicitly disable intraprocess comm at publisher/subscription level.

View File

@@ -1,207 +0,0 @@
// Copyright 2019 Open Source Robotics Foundation, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef RCLCPP__LOANED_MESSAGE_HPP_
#define RCLCPP__LOANED_MESSAGE_HPP_
#include <memory>
#include <utility>
#include "rclcpp/allocator/allocator_common.hpp"
#include "rclcpp/logging.hpp"
#include "rclcpp/publisher_base.hpp"
#include "rcl/allocator.h"
#include "rcl/publisher.h"
namespace rclcpp
{
template<typename MessageT, typename AllocatorT = std::allocator<void>>
class LoanedMessage
{
using MessageAllocatorTraits = rclcpp::allocator::AllocRebind<MessageT, AllocatorT>;
using MessageAllocator = typename MessageAllocatorTraits::allocator_type;
public:
/// Constructor of the LoanedMessage class.
/**
* The constructor of this class allocates memory for a given message type
* and associates this with a given publisher.
*
* Given the publisher instance, a case differentiation is being performaned
* which decides whether the underlying middleware is able to allocate the appropriate
* memory for this message type or not.
* In the case that the middleware can not loan messages, the passed in allocator instance
* is being used to allocate the message within the scope of this class.
* Otherwise, the allocator is being ignored and the allocation is solely performaned
* in the underlying middleware with its appropriate allocation strategy.
* The need for this arises as the user code can be written explicitly targeting a middleware
* capable of loaning messages.
* However, this user code is ought to be usable even when dynamically linked against
* a middleware which doesn't support message loaning in which case the allocator will be used.
*
* \param pub rclcpp::Publisher instance to which the memory belongs
* \param allocator Allocator instance in case middleware can not allocate messages
*/
LoanedMessage(
const rclcpp::PublisherBase & pub,
std::allocator<MessageT> allocator)
: pub_(pub),
message_(nullptr),
message_allocator_(std::move(allocator))
{
if (pub_.can_loan_messages()) {
void * message_ptr = nullptr;
auto ret = rcl_borrow_loaned_message(
pub_.get_publisher_handle(),
rosidl_typesupport_cpp::get_message_type_support_handle<MessageT>(),
&message_ptr);
if (RCL_RET_OK != ret) {
rclcpp::exceptions::throw_from_rcl_error(ret);
}
message_ = static_cast<MessageT *>(message_ptr);
} else {
RCLCPP_INFO_ONCE(
rclcpp::get_logger("rclcpp"),
"Currently used middleware can't loan messages. Local allocator will be used.");
message_ = message_allocator_.allocate(1);
new (message_) MessageT();
}
}
/// Constructor of the LoanedMessage class.
/**
* The constructor of this class allocates memory for a given message type
* and associates this with a given publisher.
*
* Given the publisher instance, a case differentiation is being performaned
* which decides whether the underlying middleware is able to allocate the appropriate
* memory for this message type or not.
* In the case that the middleware can not loan messages, the passed in allocator instance
* is being used to allocate the message within the scope of this class.
* Otherwise, the allocator is being ignored and the allocation is solely performaned
* in the underlying middleware with its appropriate allocation strategy.
* The need for this arises as the user code can be written explicitly targeting a middleware
* capable of loaning messages.
* However, this user code is ought to be usable even when dynamically linked against
* a middleware which doesn't support message loaning in which case the allocator will be used.
*
* \param pub rclcpp::Publisher instance to which the memory belongs
* \param allocator Allocator instance in case middleware can not allocate messages
*/
LoanedMessage(
const rclcpp::PublisherBase * pub,
std::shared_ptr<std::allocator<MessageT>> allocator)
: LoanedMessage(*pub, *allocator)
{}
/// Move semantic for RVO
LoanedMessage(LoanedMessage<MessageT> && other)
: pub_(std::move(other.pub_)),
message_(std::move(other.message_)),
message_allocator_(std::move(other.message_allocator_))
{}
/// Destructor of the LoanedMessage class.
/**
* The destructor has the explicit task to return the allocated memory for its message
* instance.
* If the message was previously allocated via the middleware, the message is getting
* returned to the middleware to cleanly destroy the allocation.
* In the case that the local allocator instance was used, the same instance is then
* being used to destroy the allocated memory.
*
* The contract here is that the memory for this message is valid as long as this instance
* of the LoanedMessage class is alive.
*/
virtual ~LoanedMessage()
{
auto error_logger = rclcpp::get_logger("LoanedMessage");
if (message_ == nullptr) {
return;
}
if (pub_.can_loan_messages()) {
// return allocated memory to the middleware
auto ret =
rcl_return_loaned_message_from_publisher(pub_.get_publisher_handle(), message_);
if (ret != RCL_RET_OK) {
RCLCPP_ERROR(
error_logger, "rcl_deallocate_loaned_message failed: %s", rcl_get_error_string().str);
rcl_reset_error();
}
} else {
// call destructor before deallocating
message_->~MessageT();
message_allocator_.deallocate(message_, 1);
}
message_ = nullptr;
}
/// Validate if the message was correctly allocated.
/**
* The allocated memory might not be always consistent and valid.
* Reasons why this could fail is that an allocation step was failing,
* e.g. just like malloc could fail or a maximum amount of previously allocated
* messages is exceeded in which case the loaned messages have to be returned
* to the middleware prior to be able to allocate a new one.
*/
bool is_valid() const
{
return message_ != nullptr;
}
/// Access the ROS message instance.
/**
* A call to `get()` will return a mutable reference to the underlying ROS message instance.
* This allows a user to modify the content of the message prior to publishing it.
*
* If this reference is copied, the memory for this copy is no longer managed
* by the LoanedMessage instance and has to be cleanup individually.
*/
MessageT & get() const
{
return *message_;
}
/// Release ownership of the ROS message instance.
/**
* A call to `release()` will unmanage the memory for the ROS message.
* That means that the destructor of this class will not free the memory on scope exit.
*
* \return Raw pointer to the message instance.
*/
MessageT * release()
{
auto msg = message_;
message_ = nullptr;
return msg;
}
protected:
const rclcpp::PublisherBase & pub_;
MessageT * message_;
MessageAllocator message_allocator_;
/// Deleted copy constructor to preserve memory integrity.
LoanedMessage(const LoanedMessage<MessageT> & other) = delete;
};
} // namespace rclcpp
#endif // RCLCPP__LOANED_MESSAGE_HPP_

View File

@@ -38,7 +38,6 @@
namespace rclcpp
{
// Forward declaration is used for friend statement.
namespace node_interfaces
{
@@ -59,8 +58,7 @@ class Logger;
* \return a dummy logger if logging is disabled.
*/
RCLCPP_PUBLIC
Logger
get_logger(const std::string & name);
Logger get_logger(const std::string & name);
/// Return a named logger using an rcl_node_t.
/**
@@ -71,8 +69,7 @@ get_logger(const std::string & name);
* \return a logger based on the node name, or "rclcpp" if there's an error
*/
RCLCPP_PUBLIC
Logger
get_node_logger(const rcl_node_t * node);
Logger get_node_logger(const rcl_node_t * node);
class Logger
{
@@ -85,15 +82,13 @@ private:
* This is used when logging is disabled: see `RCLCPP_LOGGING_ENABLED`.
* This cannot be called directly, see `rclcpp::get_logger` instead.
*/
Logger()
: name_(nullptr) {}
Logger() : name_(nullptr) {}
/// Constructor of a named logger.
/**
* This cannot be called directly, see `rclcpp::get_logger` instead.
*/
explicit Logger(const std::string & name)
: name_(new std::string(name)) {}
explicit Logger(const std::string & name) : name_(new std::string(name)) {}
std::shared_ptr<const std::string> name_;
@@ -108,8 +103,7 @@ public:
* disabled).
*/
RCLCPP_PUBLIC
const char *
get_name() const
const char * get_name() const
{
if (!name_) {
return nullptr;
@@ -130,8 +124,7 @@ public:
* disabled).
*/
RCLCPP_PUBLIC
Logger
get_child(const std::string & suffix)
Logger get_child(const std::string & suffix)
{
if (!name_) {
return Logger();

View File

@@ -23,7 +23,7 @@
*
* Use in the private section of the class.
*/
#define RCLCPP_DISABLE_COPY(...) \
#define RCLCPP_DISABLE_COPY(...) \
__VA_ARGS__(const __VA_ARGS__ &) = delete; \
__VA_ARGS__ & operator=(const __VA_ARGS__ &) = delete;
@@ -33,9 +33,9 @@
* Use in the public section of the class.
* Make sure to include `<memory>` in the header when using this.
*/
#define RCLCPP_SMART_PTR_DEFINITIONS(...) \
#define RCLCPP_SMART_PTR_DEFINITIONS(...) \
RCLCPP_SHARED_PTR_DEFINITIONS(__VA_ARGS__) \
RCLCPP_WEAK_PTR_DEFINITIONS(__VA_ARGS__) \
RCLCPP_WEAK_PTR_DEFINITIONS(__VA_ARGS__) \
RCLCPP_UNIQUE_PTR_DEFINITIONS(__VA_ARGS__)
/**
@@ -49,8 +49,8 @@
* Make sure to include `<memory>` in the header when using this.
*/
#define RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(...) \
RCLCPP_SHARED_PTR_DEFINITIONS(__VA_ARGS__) \
RCLCPP_WEAK_PTR_DEFINITIONS(__VA_ARGS__) \
RCLCPP_SHARED_PTR_DEFINITIONS(__VA_ARGS__) \
RCLCPP_WEAK_PTR_DEFINITIONS(__VA_ARGS__) \
__RCLCPP_UNIQUE_PTR_ALIAS(__VA_ARGS__)
/**
@@ -64,29 +64,27 @@
* 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_UNIQUE_PTR_ALIAS(__VA_ARGS__) \
__RCLCPP_SHARED_PTR_ALIAS(__VA_ARGS__) \
__RCLCPP_WEAK_PTR_ALIAS(__VA_ARGS__) \
__RCLCPP_MAKE_SHARED_DEFINITION(__VA_ARGS__)
#define __RCLCPP_SHARED_PTR_ALIAS(...) \
#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> \
static std::shared_ptr<__VA_ARGS__> \
make_shared(Args && ... args) \
{ \
return std::make_shared<__VA_ARGS__>(std::forward<Args>(args) ...); \
#define __RCLCPP_MAKE_SHARED_DEFINITION(...) \
template <typename... Args> \
static std::shared_ptr<__VA_ARGS__> make_shared(Args &&... args) \
{ \
return std::make_shared<__VA_ARGS__>(std::forward<Args>(args)...); \
}
/// Defines aliases and static functions for using the Class with shared_ptrs.
#define RCLCPP_SHARED_PTR_DEFINITIONS(...) \
__RCLCPP_SHARED_PTR_ALIAS(__VA_ARGS__) \
__RCLCPP_SHARED_PTR_ALIAS(__VA_ARGS__) \
__RCLCPP_MAKE_SHARED_DEFINITION(__VA_ARGS__)
#define __RCLCPP_WEAK_PTR_ALIAS(...) \
#define __RCLCPP_WEAK_PTR_ALIAS(...) \
using WeakPtr = std::weak_ptr<__VA_ARGS__>; \
using ConstWeakPtr = std::weak_ptr<const __VA_ARGS__>;
@@ -95,20 +93,19 @@
#define __RCLCPP_UNIQUE_PTR_ALIAS(...) using UniquePtr = std::unique_ptr<__VA_ARGS__>;
#define __RCLCPP_MAKE_UNIQUE_DEFINITION(...) \
template<typename ... Args> \
static std::unique_ptr<__VA_ARGS__> \
make_unique(Args && ... args) \
{ \
return std::unique_ptr<__VA_ARGS__>(new __VA_ARGS__(std::forward<Args>(args) ...)); \
#define __RCLCPP_MAKE_UNIQUE_DEFINITION(...) \
template <typename... Args> \
static std::unique_ptr<__VA_ARGS__> make_unique(Args &&... args) \
{ \
return std::unique_ptr<__VA_ARGS__>(new __VA_ARGS__(std::forward<Args>(args)...)); \
}
/// Defines aliases and static functions for using the Class with unique_ptrs.
#define RCLCPP_UNIQUE_PTR_DEFINITIONS(...) \
__RCLCPP_UNIQUE_PTR_ALIAS(__VA_ARGS__) \
__RCLCPP_UNIQUE_PTR_ALIAS(__VA_ARGS__) \
__RCLCPP_MAKE_UNIQUE_DEFINITION(__VA_ARGS__)
#define RCLCPP_STRING_JOIN(arg1, arg2) RCLCPP_DO_STRING_JOIN(arg1, arg2)
#define RCLCPP_DO_STRING_JOIN(arg1, arg2) arg1 ## arg2
#define RCLCPP_DO_STRING_JOIN(arg1, arg2) arg1##arg2
#endif // RCLCPP__MACROS_HPP_

View File

@@ -0,0 +1,308 @@
// 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.
#ifndef RCLCPP__MAPPED_RING_BUFFER_HPP_
#define RCLCPP__MAPPED_RING_BUFFER_HPP_
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <mutex>
#include <stdexcept>
#include <utility>
#include <vector>
#include "rclcpp/allocator/allocator_common.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
namespace mapped_ring_buffer
{
class RCLCPP_PUBLIC MappedRingBufferBase
{
public:
RCLCPP_SMART_PTR_DEFINITIONS(MappedRingBufferBase)
};
/// Ring buffer container of shared_ptr's or unique_ptr's of T, which can be accessed by a key.
/**
* T must be a CopyConstructable and CopyAssignable.
* This class can be used in a container by using the base class MappedRingBufferBase.
* This class must have a positive, non-zero size.
* This class cannot be resized nor can it reserve additional space after construction.
* This class is not CopyConstructable nor CopyAssignable.
*
* The key's are not guaranteed to be unique because push_and_replace does not
* check for colliding keys.
* It is up to the user to only use unique keys.
* A side effect of this is that when get_copy_at_key or pop_at_key are called,
* they return the first encountered instance of the key.
* But iteration does not begin with the ring buffer's head, and therefore
* there is no guarantee on which value is returned if a key is used multiple
* times.
*/
template <typename T, typename Alloc = std::allocator<void>>
class MappedRingBuffer : public MappedRingBufferBase
{
public:
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>;
using ConstElemSharedPtr = std::shared_ptr<const T>;
using ElemUniquePtr = std::unique_ptr<T, ElemDeleter>;
/// Constructor.
/**
* The constructor will allocate memory while reserving space.
*
* \param size size of the ring buffer; must be positive and non-zero.
* \param allocator optional custom allocator
*/
explicit MappedRingBuffer(size_t size, std::shared_ptr<Alloc> allocator = nullptr)
: elements_(size), head_(0)
{
if (size == 0) {
throw std::invalid_argument("size must be a positive, non-zero value");
}
if (!allocator) {
allocator_ = std::make_shared<ElemAlloc>();
} else {
allocator_ = std::make_shared<ElemAlloc>(*allocator.get());
}
}
virtual ~MappedRingBuffer() {}
/// Return a copy of the value stored in the ring buffer at the given key.
/**
* The key is matched if an element in the ring buffer has a matching key.
* This method will allocate in order to return a copy.
*
* The key is not guaranteed to be unique, see the class docs for more.
*
* The contents of value before the method is called are discarded.
*
* \param key the key associated with the stored value
* \param value if the key is found, the value is stored in this parameter
*/
void get(uint64_t key, ElemUniquePtr & value)
{
std::lock_guard<std::mutex> lock(data_mutex_);
auto it = get_iterator_of_key(key);
value = nullptr;
if (it != elements_.end() && it->in_use) {
if (it->unique_value) {
ElemDeleter deleter = it->unique_value.get_deleter();
auto ptr = ElemAllocTraits::allocate(*allocator_.get(), 1);
ElemAllocTraits::construct(*allocator_.get(), ptr, *it->unique_value);
value = ElemUniquePtr(ptr, deleter);
} else if (it->shared_value) {
ElemDeleter * deleter = std::get_deleter<ElemDeleter, const T>(it->shared_value);
auto ptr = ElemAllocTraits::allocate(*allocator_.get(), 1);
ElemAllocTraits::construct(*allocator_.get(), ptr, *it->shared_value);
if (deleter) {
value = ElemUniquePtr(ptr, *deleter);
} else {
value = ElemUniquePtr(ptr);
}
} else {
throw std::runtime_error("Unexpected empty MappedRingBuffer element.");
}
}
}
/// Share ownership of the value stored in the ring buffer at the given key.
/**
* The key is matched if an element in the ring buffer has a matching key.
*
* The key is not guaranteed to be unique, see the class docs for more.
*
* The contents of value before the method is called are discarded.
*
* \param key the key associated with the stored value
* \param value if the key is found, the value is stored in this parameter
*/
void get(uint64_t key, ConstElemSharedPtr & value)
{
std::lock_guard<std::mutex> lock(data_mutex_);
auto it = get_iterator_of_key(key);
value.reset();
if (it != elements_.end() && it->in_use) {
if (!it->shared_value) {
// The stored unique_ptr is upgraded to a shared_ptr here.
// All the remaining get and pop calls done with unique_ptr
// signature will receive a copy.
if (!it->unique_value) {
throw std::runtime_error("Unexpected empty MappedRingBuffer element.");
}
it->shared_value = std::move(it->unique_value);
}
value = it->shared_value;
}
}
/// Give the ownership of the stored value to the caller if possible, or copy and release.
/**
* The key is matched if an element in the ring buffer has a matching key.
* This method may allocate in order to return a copy.
*
* If the stored value is a shared_ptr, it is not possible to downgrade it to a unique_ptr.
* In that case, a copy is returned and the stored value is released.
*
* The key is not guaranteed to be unique, see the class docs for more.
*
* The contents of value before the method is called are discarded.
*
* \param key the key associated with the stored value
* \param value if the key is found, the value is stored in this parameter
*/
void pop(uint64_t key, ElemUniquePtr & value)
{
std::lock_guard<std::mutex> lock(data_mutex_);
auto it = get_iterator_of_key(key);
value = nullptr;
if (it != elements_.end() && it->in_use) {
if (it->unique_value) {
value = std::move(it->unique_value);
} else if (it->shared_value) {
auto ptr = ElemAllocTraits::allocate(*allocator_.get(), 1);
ElemAllocTraits::construct(*allocator_.get(), ptr, *it->shared_value);
auto deleter = std::get_deleter<ElemDeleter, const T>(it->shared_value);
if (deleter) {
value = ElemUniquePtr(ptr, *deleter);
} else {
value = ElemUniquePtr(ptr);
}
it->shared_value.reset();
} else {
throw std::runtime_error("Unexpected empty MappedRingBuffer element.");
}
it->in_use = false;
}
}
/// Give the ownership of the stored value to the caller, at the given key.
/**
* The key is matched if an element in the ring buffer has a matching key.
*
* The key is not guaranteed to be unique, see the class docs for more.
*
* The contents of value before the method is called are discarded.
*
* \param key the key associated with the stored value
* \param value if the key is found, the value is stored in this parameter
*/
void pop(uint64_t key, ConstElemSharedPtr & value)
{
std::lock_guard<std::mutex> lock(data_mutex_);
auto it = get_iterator_of_key(key);
if (it != elements_.end() && it->in_use) {
if (it->shared_value) {
value = std::move(it->shared_value);
} else if (it->unique_value) {
value = std::move(it->unique_value);
} else {
throw std::runtime_error("Unexpected empty MappedRingBuffer element.");
}
it->in_use = false;
}
}
/// Insert a key-value pair, displacing an existing pair if necessary.
/**
* The key's uniqueness is not checked on insertion.
* It is up to the user to ensure the key is unique.
* This method should not allocate memory.
*
* After insertion the value will be a nullptr.
* If a pair were replaced, its smart pointer is reset.
*
* \param key the key associated with the value to be stored
* \param value the value to store, and optionally the value displaced
*/
bool push_and_replace(uint64_t key, ConstElemSharedPtr value)
{
std::lock_guard<std::mutex> lock(data_mutex_);
bool did_replace = elements_[head_].in_use;
Element & element = elements_[head_];
element.key = key;
element.unique_value.reset();
element.shared_value.reset();
element.shared_value = value;
element.in_use = true;
head_ = (head_ + 1) % elements_.size();
return did_replace;
}
/// Insert a key-value pair, displacing an existing pair if necessary.
/**
* See `bool push_and_replace(uint64_t key, const ConstElemSharedPtr & value)`.
*/
bool push_and_replace(uint64_t key, ElemUniquePtr value)
{
std::lock_guard<std::mutex> lock(data_mutex_);
bool did_replace = elements_[head_].in_use;
Element & element = elements_[head_];
element.key = key;
element.unique_value.reset();
element.shared_value.reset();
element.unique_value = std::move(value);
element.in_use = true;
head_ = (head_ + 1) % elements_.size();
return did_replace;
}
/// Return true if the key is found in the ring buffer, otherwise false.
bool has_key(uint64_t key)
{
std::lock_guard<std::mutex> lock(data_mutex_);
return elements_.end() != get_iterator_of_key(key);
}
private:
RCLCPP_DISABLE_COPY(MappedRingBuffer<T, Alloc>)
struct Element
{
uint64_t key;
ElemUniquePtr unique_value;
ConstElemSharedPtr shared_value;
bool in_use;
};
using VectorAlloc = typename std::allocator_traits<Alloc>::template rebind_alloc<Element>;
typename std::vector<Element, VectorAlloc>::iterator get_iterator_of_key(uint64_t key)
{
auto it = std::find_if(elements_.begin(), elements_.end(), [key](Element & e) -> bool {
return e.key == key && e.in_use;
});
return it;
}
std::vector<Element, VectorAlloc> elements_;
size_t head_;
std::shared_ptr<ElemAlloc> allocator_;
std::mutex data_mutex_;
};
} // namespace mapped_ring_buffer
} // namespace rclcpp
#endif // RCLCPP__MAPPED_RING_BUFFER_HPP_

View File

@@ -22,10 +22,8 @@ namespace rclcpp
{
namespace memory_strategies
{
RCLCPP_PUBLIC
memory_strategy::MemoryStrategy::SharedPtr
create_default_strategy();
memory_strategy::MemoryStrategy::SharedPtr create_default_strategy();
} // namespace memory_strategies
} // namespace rclcpp

View File

@@ -31,7 +31,6 @@ namespace rclcpp
{
namespace memory_strategy
{
/// Delegate for handling memory allocations while the Executor is executing.
/**
* By default, the memory strategy dynamically allocates memory for structures that come in from
@@ -56,7 +55,6 @@ public:
virtual size_t number_of_guard_conditions() const = 0;
virtual size_t number_of_waitables() const = 0;
virtual void add_waitable_handle(const rclcpp::Waitable::SharedPtr & waitable) = 0;
virtual bool add_handles_to_wait_set(rcl_wait_set_t * wait_set) = 0;
virtual void clear_handles() = 0;
virtual void remove_null_handles(rcl_wait_set_t * wait_set) = 0;
@@ -65,83 +63,43 @@ public:
virtual void remove_guard_condition(const rcl_guard_condition_t * guard_condition) = 0;
virtual void
get_next_subscription(
rclcpp::AnyExecutable & any_exec,
const WeakNodeList & weak_nodes) = 0;
virtual void get_next_subscription(
rclcpp::executor::AnyExecutable & any_exec, const WeakNodeList & weak_nodes) = 0;
virtual void
get_next_service(
rclcpp::AnyExecutable & any_exec,
const WeakNodeList & weak_nodes) = 0;
virtual void get_next_service(
rclcpp::executor::AnyExecutable & any_exec, const WeakNodeList & weak_nodes) = 0;
virtual void
get_next_client(
rclcpp::AnyExecutable & any_exec,
const WeakNodeList & weak_nodes) = 0;
virtual void get_next_client(
rclcpp::executor::AnyExecutable & any_exec, const WeakNodeList & weak_nodes) = 0;
virtual void
get_next_timer(
rclcpp::AnyExecutable & any_exec,
const WeakNodeList & weak_nodes) = 0;
virtual void get_next_waitable(
rclcpp::executor::AnyExecutable & any_exec, const WeakNodeList & weak_nodes) = 0;
virtual void
get_next_waitable(
rclcpp::AnyExecutable & any_exec,
const WeakNodeList & weak_nodes) = 0;
virtual rcl_allocator_t get_allocator() = 0;
virtual rcl_allocator_t
get_allocator() = 0;
static rclcpp::SubscriptionBase::SharedPtr get_subscription_by_handle(
std::shared_ptr<const rcl_subscription_t> subscriber_handle, const WeakNodeList & weak_nodes);
static rclcpp::SubscriptionBase::SharedPtr
get_subscription_by_handle(
std::shared_ptr<const rcl_subscription_t> subscriber_handle,
const WeakNodeList & weak_nodes);
static rclcpp::ServiceBase::SharedPtr get_service_by_handle(
std::shared_ptr<const rcl_service_t> service_handle, const WeakNodeList & weak_nodes);
static rclcpp::ServiceBase::SharedPtr
get_service_by_handle(
std::shared_ptr<const rcl_service_t> service_handle,
const WeakNodeList & weak_nodes);
static rclcpp::ClientBase::SharedPtr get_client_by_handle(
std::shared_ptr<const rcl_client_t> client_handle, const WeakNodeList & weak_nodes);
static rclcpp::ClientBase::SharedPtr
get_client_by_handle(
std::shared_ptr<const rcl_client_t> client_handle,
const WeakNodeList & weak_nodes);
static rclcpp::node_interfaces::NodeBaseInterface::SharedPtr get_node_by_group(
rclcpp::callback_group::CallbackGroup::SharedPtr group, const WeakNodeList & weak_nodes);
static rclcpp::TimerBase::SharedPtr
get_timer_by_handle(
std::shared_ptr<const rcl_timer_t> timer_handle,
const WeakNodeList & weak_nodes);
static rclcpp::callback_group::CallbackGroup::SharedPtr get_group_by_subscription(
rclcpp::SubscriptionBase::SharedPtr subscription, const WeakNodeList & weak_nodes);
static rclcpp::node_interfaces::NodeBaseInterface::SharedPtr
get_node_by_group(
rclcpp::CallbackGroup::SharedPtr group,
const WeakNodeList & weak_nodes);
static rclcpp::callback_group::CallbackGroup::SharedPtr get_group_by_service(
rclcpp::ServiceBase::SharedPtr service, const WeakNodeList & weak_nodes);
static rclcpp::CallbackGroup::SharedPtr
get_group_by_subscription(
rclcpp::SubscriptionBase::SharedPtr subscription,
const WeakNodeList & weak_nodes);
static rclcpp::callback_group::CallbackGroup::SharedPtr get_group_by_client(
rclcpp::ClientBase::SharedPtr client, const WeakNodeList & weak_nodes);
static rclcpp::CallbackGroup::SharedPtr
get_group_by_service(
rclcpp::ServiceBase::SharedPtr service,
const WeakNodeList & weak_nodes);
static rclcpp::CallbackGroup::SharedPtr
get_group_by_client(
rclcpp::ClientBase::SharedPtr client,
const WeakNodeList & weak_nodes);
static rclcpp::CallbackGroup::SharedPtr
get_group_by_timer(
rclcpp::TimerBase::SharedPtr timer,
const WeakNodeList & weak_nodes);
static rclcpp::CallbackGroup::SharedPtr
get_group_by_waitable(
rclcpp::Waitable::SharedPtr waitable,
const WeakNodeList & weak_nodes);
static rclcpp::callback_group::CallbackGroup::SharedPtr get_group_by_waitable(
rclcpp::Waitable::SharedPtr waitable, const WeakNodeList & weak_nodes);
};
} // namespace memory_strategy

View File

@@ -1,52 +0,0 @@
// Copyright 2020 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__MESSAGE_INFO_HPP_
#define RCLCPP__MESSAGE_INFO_HPP_
#include "rmw/types.h"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
/// Additional meta data about messages taken from subscriptions.
class RCLCPP_PUBLIC MessageInfo
{
public:
/// Default empty constructor.
MessageInfo() = default;
/// Conversion constructor, which is intentionally not marked as explicit.
// cppcheck-suppress noExplicitConstructor
MessageInfo(const rmw_message_info_t & rmw_message_info); // NOLINT(runtime/explicit)
virtual ~MessageInfo();
/// Return the message info as the underlying rmw message info type.
const rmw_message_info_t &
get_rmw_message_info() const;
/// Return the message info as the underlying rmw message info type.
rmw_message_info_t &
get_rmw_message_info();
private:
rmw_message_info_t rmw_message_info_;
};
} // namespace rclcpp
#endif // RCLCPP__MESSAGE_INFO_HPP_

View File

@@ -33,10 +33,9 @@ namespace rclcpp
{
namespace message_memory_strategy
{
/// Default allocation strategy for messages received by subscriptions.
/** A message memory strategy must be templated on the type of the subscription it belongs to. */
template<typename MessageT, typename Alloc = std::allocator<void>>
template <typename MessageT, typename Alloc = std::allocator<void>>
class MessageMemoryStrategy
{
public:
@@ -95,15 +94,13 @@ public:
rclcpp::exceptions::throw_from_rcl_error(ret);
}
auto serialized_msg = std::shared_ptr<rcl_serialized_message_t>(
msg,
[](rmw_serialized_message_t * msg) {
auto fini_ret = rmw_serialized_message_fini(msg);
auto serialized_msg =
std::shared_ptr<rcl_serialized_message_t>(msg, [](rmw_serialized_message_t * msg) {
auto ret = rmw_serialized_message_fini(msg);
delete msg;
if (fini_ret != RCL_RET_OK) {
if (ret != RCL_RET_OK) {
RCUTILS_LOG_ERROR_NAMED(
"rclcpp",
"failed to destroy serialized message: %s", rcl_get_error_string().str);
"rclcpp", "failed to destroy serialized message: %s", rcl_get_error_string().str);
}
});
@@ -115,17 +112,11 @@ public:
return borrow_serialized_message(default_buffer_capacity_);
}
virtual void set_default_buffer_capacity(size_t capacity)
{
default_buffer_capacity_ = capacity;
}
virtual void set_default_buffer_capacity(size_t capacity) { default_buffer_capacity_ = capacity; }
/// Release ownership of the message, which will deallocate it if it has no more owners.
/** \param[in] msg Shared pointer to the message we are returning. */
virtual void return_message(std::shared_ptr<MessageT> & msg)
{
msg.reset();
}
virtual void return_message(std::shared_ptr<MessageT> & msg) { msg.reset(); }
virtual void return_serialized_message(std::shared_ptr<rcl_serialized_message_t> & serialized_msg)
{

View File

@@ -67,7 +67,6 @@
namespace rclcpp
{
/// Node is the single point of entry for creating publishers and subscribers.
class Node : public std::enable_shared_from_this<Node>
{
@@ -80,9 +79,7 @@ public:
* \param[in] options Additional options to control creation of the node.
*/
RCLCPP_PUBLIC
explicit Node(
const std::string & node_name,
const NodeOptions & options = NodeOptions());
explicit Node(const std::string & node_name, const NodeOptions & options = NodeOptions());
/// Create a new node with the specified name.
/**
@@ -102,8 +99,7 @@ public:
/// Get the name of the node.
/** \return The name of the node. */
RCLCPP_PUBLIC
const char *
get_name() const;
const char * get_name() const;
/// Get the namespace of the node.
/**
@@ -116,32 +112,28 @@ public:
* \return The namespace of the node.
*/
RCLCPP_PUBLIC
const char *
get_namespace() const;
const char * get_namespace() const;
/// Get the fully-qualified name of the node.
/**
* The fully-qualified name includes the local namespace and name of the node.
*/
RCLCPP_PUBLIC
const char *
get_fully_qualified_name() const;
const char * get_fully_qualified_name() const;
/// Get the logger of the node.
/** \return The logger of the node. */
RCLCPP_PUBLIC
rclcpp::Logger
get_logger() const;
rclcpp::Logger get_logger() const;
/// Create and return a callback group.
RCLCPP_PUBLIC
rclcpp::CallbackGroup::SharedPtr
create_callback_group(rclcpp::CallbackGroupType group_type);
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::CallbackGroup::WeakPtr> &
get_callback_groups() const;
const std::vector<rclcpp::callback_group::CallbackGroup::WeakPtr> & get_callback_groups() const;
/// Create and return a Publisher.
/**
@@ -171,17 +163,55 @@ public:
* \param[in] options Additional options for the created Publisher.
* \return Shared pointer to the created publisher.
*/
template<
template <
typename MessageT,
typename AllocatorT = std::allocator<void>,
typename PublisherT = rclcpp::Publisher<MessageT, AllocatorT>>
std::shared_ptr<PublisherT>
create_publisher(
typename PublisherT = ::rclcpp::Publisher<MessageT, AllocatorT>>
std::shared_ptr<PublisherT> create_publisher(
const std::string & topic_name,
const rclcpp::QoS & qos,
const PublisherOptionsWithAllocator<AllocatorT> & options =
PublisherOptionsWithAllocator<AllocatorT>()
);
PublisherOptionsWithAllocator<AllocatorT>());
/// Create and return a Publisher.
/**
* \param[in] topic_name The topic for this publisher to publish on.
* \param[in] qos_history_depth The depth of the publisher message queue.
* \param[in] allocator Custom allocator.
* \return Shared pointer to the created publisher.
*/
template <
typename MessageT,
typename AllocatorT = std::allocator<void>,
typename PublisherT = ::rclcpp::Publisher<MessageT, AllocatorT>>
// cppcheck-suppress syntaxError // bug in cppcheck 1.82 for [[deprecated]] on templated function
[[deprecated(
"use create_publisher(const std::string &, const rclcpp::QoS &, ...) instead")]] std::
shared_ptr<PublisherT>
create_publisher(
const std::string & topic_name,
size_t qos_history_depth,
std::shared_ptr<AllocatorT> allocator);
/// Create and return a Publisher.
/**
* \param[in] topic_name The topic for this publisher to publish on.
* \param[in] qos_profile The quality of service profile to pass on to the rmw implementation.
* \param[in] allocator Optional custom allocator.
* \return Shared pointer to the created publisher.
*/
template <
typename MessageT,
typename AllocatorT = std::allocator<void>,
typename PublisherT = ::rclcpp::Publisher<MessageT, AllocatorT>>
// cppcheck-suppress syntaxError // bug in cppcheck 1.82 for [[deprecated]] on templated function
[[deprecated(
"use create_publisher(const std::string &, const rclcpp::QoS &, ...) instead")]] std::
shared_ptr<PublisherT>
create_publisher(
const std::string & topic_name,
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_default,
std::shared_ptr<AllocatorT> allocator = nullptr);
/// Create and return a Subscription.
/**
@@ -192,29 +222,98 @@ public:
* \param[in] msg_mem_strat The message memory strategy to use for allocating messages.
* \return Shared pointer to the created subscription.
*/
template<
/* TODO(jacquelinekay):
Windows build breaks when static member function passed as default
argument to msg_mem_strat, nullptr is a workaround.
*/
template <
typename MessageT,
typename CallbackT,
typename AllocatorT = std::allocator<void>,
typename CallbackMessageT =
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type,
typename SubscriptionT = rclcpp::Subscription<CallbackMessageT, AllocatorT>,
typename MessageMemoryStrategyT = rclcpp::message_memory_strategy::MessageMemoryStrategy<
CallbackMessageT,
AllocatorT
>
>
std::shared_ptr<SubscriptionT>
create_subscription(
typename SubscriptionT = rclcpp::Subscription<
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type,
AllocatorT>>
std::shared_ptr<SubscriptionT> create_subscription(
const std::string & topic_name,
const rclcpp::QoS & qos,
CallbackT && callback,
const SubscriptionOptionsWithAllocator<AllocatorT> & options =
SubscriptionOptionsWithAllocator<AllocatorT>(),
typename MessageMemoryStrategyT::SharedPtr msg_mem_strat = (
MessageMemoryStrategyT::create_default()
)
);
SubscriptionOptionsWithAllocator<AllocatorT>(),
typename rclcpp::message_memory_strategy::MessageMemoryStrategy<
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type,
AllocatorT>::SharedPtr msg_mem_strat = nullptr);
/// Create and return a Subscription.
/**
* \param[in] topic_name The topic to subscribe on.
* \param[in] callback The user-defined callback function.
* \param[in] qos_profile The quality of service profile to pass on to the rmw implementation.
* \param[in] group The callback group for this subscription. NULL for no callback group.
* \param[in] ignore_local_publications True to ignore local publications.
* \param[in] msg_mem_strat The message memory strategy to use for allocating messages.
* \param[in] allocator Optional custom allocator.
* \return Shared pointer to the created subscription.
*/
/* TODO(jacquelinekay):
Windows build breaks when static member function passed as default
argument to msg_mem_strat, nullptr is a workaround.
*/
template <
typename MessageT,
typename CallbackT,
typename Alloc = std::allocator<void>,
typename SubscriptionT = rclcpp::
Subscription<typename rclcpp::subscription_traits::has_message_type<CallbackT>::type, Alloc>>
// cppcheck-suppress syntaxError // bug in cppcheck 1.82 for [[deprecated]] on templated function
[
[deprecated("use create_subscription(const std::string &, const rclcpp::QoS &, CallbackT, ...) "
"instead")]] std::shared_ptr<SubscriptionT>
create_subscription(
const std::string & topic_name,
CallbackT && callback,
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_default,
rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr,
bool ignore_local_publications = false,
typename rclcpp::message_memory_strategy::MessageMemoryStrategy<
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type,
Alloc>::SharedPtr msg_mem_strat = nullptr,
std::shared_ptr<Alloc> allocator = nullptr);
/// Create and return a Subscription.
/**
* \param[in] topic_name The topic to subscribe on.
* \param[in] qos_history_depth The depth of the subscription's incoming message queue.
* \param[in] callback The user-defined callback function.
* \param[in] group The callback group for this subscription. NULL for no callback group.
* \param[in] ignore_local_publications True to ignore local publications.
* \param[in] msg_mem_strat The message memory strategy to use for allocating messages.
* \param[in] allocator Optional custom allocator.
* \return Shared pointer to the created subscription.
*/
/* TODO(jacquelinekay):
Windows build breaks when static member function passed as default
argument to msg_mem_strat, nullptr is a workaround.
*/
template <
typename MessageT,
typename CallbackT,
typename Alloc = std::allocator<void>,
typename SubscriptionT = rclcpp::
Subscription<typename rclcpp::subscription_traits::has_message_type<CallbackT>::type, Alloc>>
// cppcheck-suppress syntaxError // bug in cppcheck 1.82 for [[deprecated]] on templated function
[
[deprecated("use create_subscription(const std::string &, const rclcpp::QoS &, CallbackT, ...) "
"instead")]] std::shared_ptr<SubscriptionT>
create_subscription(
const std::string & topic_name,
CallbackT && callback,
size_t qos_history_depth,
rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr,
bool ignore_local_publications = false,
typename rclcpp::message_memory_strategy::MessageMemoryStrategy<
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type,
Alloc>::SharedPtr msg_mem_strat = nullptr,
std::shared_ptr<Alloc> allocator = nullptr);
/// Create a timer.
/**
@@ -222,29 +321,26 @@ public:
* \param[in] callback User-defined callback function.
* \param[in] group Callback group to execute this timer's callback in.
*/
template<typename DurationRepT = int64_t, typename DurationT = std::milli, typename CallbackT>
typename rclcpp::WallTimer<CallbackT>::SharedPtr
create_wall_timer(
template <typename DurationRepT = int64_t, typename DurationT = std::milli, typename CallbackT>
typename rclcpp::WallTimer<CallbackT>::SharedPtr create_wall_timer(
std::chrono::duration<DurationRepT, DurationT> period,
CallbackT callback,
rclcpp::CallbackGroup::SharedPtr group = nullptr);
rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr);
/* Create and return a Client. */
template<typename ServiceT>
typename rclcpp::Client<ServiceT>::SharedPtr
create_client(
template <typename ServiceT>
typename rclcpp::Client<ServiceT>::SharedPtr create_client(
const std::string & service_name,
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_services_default,
rclcpp::CallbackGroup::SharedPtr group = nullptr);
rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr);
/* Create and return a Service. */
template<typename ServiceT, typename CallbackT>
typename rclcpp::Service<ServiceT>::SharedPtr
create_service(
template <typename ServiceT, typename CallbackT>
typename rclcpp::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::CallbackGroup::SharedPtr group = nullptr);
rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr);
/// Declare and initialize a parameter, return the effective value.
/**
@@ -287,12 +383,11 @@ public:
* value fails to be set.
*/
RCLCPP_PUBLIC
const rclcpp::ParameterValue &
declare_parameter(
const rclcpp::ParameterValue & declare_parameter(
const std::string & name,
const rclcpp::ParameterValue & default_value = rclcpp::ParameterValue(),
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor =
rcl_interfaces::msg::ParameterDescriptor(),
rcl_interfaces::msg::ParameterDescriptor(),
bool ignore_override = false);
/// Declare and initialize a parameter with a type.
@@ -301,7 +396,7 @@ public:
*
* If the type of the default value, and therefore also the type of return
* value, differs from the initial value provided in the node options, then
* a rclcpp::exceptions::InvalidParameterTypeException may be thrown.
* a rclcpp::ParameterTypeException may be thrown.
* To avoid this, use the declare_parameter() method which returns an
* rclcpp::ParameterValue instead.
*
@@ -316,13 +411,12 @@ public:
* - https://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/
* - https://www.youtube.com/watch?v=uQyT-5iWUow (cppnow 2018 presentation)
*/
template<typename ParameterT>
auto
declare_parameter(
template <typename ParameterT>
auto declare_parameter(
const std::string & name,
const ParameterT & default_value,
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor =
rcl_interfaces::msg::ParameterDescriptor(),
rcl_interfaces::msg::ParameterDescriptor(),
bool ignore_override = false);
/// Declare and initialize several parameters with the same namespace and type.
@@ -361,9 +455,8 @@ public:
* \throws rclcpp::exceptions::InvalidParameterValueException if initial
* value fails to be set.
*/
template<typename ParameterT>
std::vector<ParameterT>
declare_parameters(
template <typename ParameterT>
std::vector<ParameterT> declare_parameters(
const std::string & namespace_,
const std::map<std::string, ParameterT> & parameters,
bool ignore_overrides = false);
@@ -375,14 +468,11 @@ public:
*
* See the simpler declare_parameters() on this class for more details.
*/
template<typename ParameterT>
std::vector<ParameterT>
declare_parameters(
template <typename ParameterT>
std::vector<ParameterT> declare_parameters(
const std::string & namespace_,
const std::map<
std::string,
std::pair<ParameterT, rcl_interfaces::msg::ParameterDescriptor>
> & parameters,
const std::map<std::string, std::pair<ParameterT, rcl_interfaces::msg::ParameterDescriptor>> &
parameters,
bool ignore_overrides = false);
/// Undeclare a previously declared parameter.
@@ -397,8 +487,7 @@ public:
* was create as read_only (immutable).
*/
RCLCPP_PUBLIC
void
undeclare_parameter(const std::string & name);
void undeclare_parameter(const std::string & name);
/// Return true if a given parameter is declared.
/**
@@ -406,8 +495,7 @@ public:
* \return true if the parameter name has been declared, otherwise false.
*/
RCLCPP_PUBLIC
bool
has_parameter(const std::string & name) const;
bool has_parameter(const std::string & name) const;
/// Set a single parameter.
/**
@@ -439,8 +527,7 @@ public:
* has not been declared and undeclared parameters are not allowed.
*/
RCLCPP_PUBLIC
rcl_interfaces::msg::SetParametersResult
set_parameter(const rclcpp::Parameter & parameter);
rcl_interfaces::msg::SetParametersResult set_parameter(const rclcpp::Parameter & parameter);
/// Set one or more parameters, one at a time.
/**
@@ -477,8 +564,8 @@ public:
* has not been declared and undeclared parameters are not allowed.
*/
RCLCPP_PUBLIC
std::vector<rcl_interfaces::msg::SetParametersResult>
set_parameters(const std::vector<rclcpp::Parameter> & parameters);
std::vector<rcl_interfaces::msg::SetParametersResult> set_parameters(
const std::vector<rclcpp::Parameter> & parameters);
/// Set one or more parameters, all at once.
/**
@@ -511,8 +598,36 @@ public:
* has not been declared and undeclared parameters are not allowed.
*/
RCLCPP_PUBLIC
rcl_interfaces::msg::SetParametersResult
set_parameters_atomically(const std::vector<rclcpp::Parameter> & parameters);
rcl_interfaces::msg::SetParametersResult set_parameters_atomically(
const std::vector<rclcpp::Parameter> & parameters);
/// Set one parameter, unless that parameter has already been set.
/**
* Set the given parameter unless already set.
*
* Deprecated, instead use declare_parameter().
*
* \param[in] parameters The vector of parameters to be set.
* \return The result of each set action as a vector.
*/
template <typename ParameterT>
// cppcheck-suppress syntaxError // bug in cppcheck 1.82 for [[deprecated]] on templated function
[[deprecated("use declare_parameter() instead")]] void set_parameter_if_not_set(
const std::string & name, const ParameterT & value);
/// Set a map of parameters with the same prefix.
/**
* For each key in the map, a parameter with a name of "name.key" will be set
* to the value in the map.
*
* Deprecated, instead use declare_parameters().
*
* \param[in] name The prefix of the parameters to set.
* \param[in] values The parameters to set in the given prefix.
*/
template <typename ParameterT>
[[deprecated("use declare_parameters() instead")]] void set_parameters_if_not_set(
const std::string & name, const std::map<std::string, ParameterT> & values);
/// Return the parameter by the given name.
/**
@@ -531,8 +646,7 @@ public:
* has not been declared and undeclared parameters are not allowed.
*/
RCLCPP_PUBLIC
rclcpp::Parameter
get_parameter(const std::string & name) const;
rclcpp::Parameter get_parameter(const std::string & name) const;
/// Get the value of a parameter by the given name, and return true if it was set.
/**
@@ -550,8 +664,7 @@ public:
* \return true if the parameter was previously declared, otherwise false.
*/
RCLCPP_PUBLIC
bool
get_parameter(const std::string & name, rclcpp::Parameter & parameter) const;
bool get_parameter(const std::string & name, rclcpp::Parameter & parameter) const;
/// Get the value of a parameter by the given name, and return true if it was set.
/**
@@ -566,9 +679,8 @@ public:
* \throws rclcpp::ParameterTypeException if the requested type does not
* match the value of the parameter which is stored.
*/
template<typename ParameterT>
bool
get_parameter(const std::string & name, ParameterT & parameter) const;
template <typename ParameterT>
bool get_parameter(const std::string & name, ParameterT & parameter) const;
/// Get the parameter value, or the "alternative_value" if not set, and assign it to "parameter".
/**
@@ -585,12 +697,9 @@ public:
* \param[in] alternative_value Value to be stored in output if the parameter was not set.
* \returns true if the parameter was set, false otherwise.
*/
template<typename ParameterT>
bool
get_parameter_or(
const std::string & name,
ParameterT & parameter,
const ParameterT & alternative_value) const;
template <typename ParameterT>
bool get_parameter_or(
const std::string & name, ParameterT & parameter, const ParameterT & alternative_value) const;
/// Return the parameters by the given parameter names.
/**
@@ -611,8 +720,7 @@ public:
* allowed.
*/
RCLCPP_PUBLIC
std::vector<rclcpp::Parameter>
get_parameters(const std::vector<std::string> & names) const;
std::vector<rclcpp::Parameter> get_parameters(const std::vector<std::string> & names) const;
/// Get the parameter values for all parameters that have a given prefix.
/**
@@ -651,11 +759,26 @@ public:
* \throws rclcpp::ParameterTypeException if the requested type does not
* match the value of the parameter which is stored.
*/
template<typename ParameterT>
bool
get_parameters(
const std::string & prefix,
std::map<std::string, ParameterT> & values) const;
template <typename ParameterT>
bool get_parameters(const std::string & prefix, std::map<std::string, ParameterT> & values) const;
/// Get the parameter value; if not set, set the "alternative value" and store it in the node.
/**
* If the parameter is set, then the "value" argument is assigned the value
* in the parameter.
* If the parameter is not set, then the "value" argument is assigned the "alternative_value",
* and the parameter is set to the "alternative_value" on the node.
*
* Deprecated, instead use declare_parameter()'s return value, or use
* has_parameter() to ensure it exists before getting it.
*
* \param[in] name The name of the parameter to get.
* \param[out] value The output where the value of the parameter should be assigned.
* \param[in] alternative_value Value to be used if the parameter was not set.
*/
template <typename ParameterT>
[[deprecated("use declare_parameter() and it's return value instead")]] void get_parameter_or_set(
const std::string & name, ParameterT & value, const ParameterT & alternative_value);
/// Return the parameter descriptor for the given parameter name.
/**
@@ -674,8 +797,7 @@ public:
* allowed.
*/
RCLCPP_PUBLIC
rcl_interfaces::msg::ParameterDescriptor
describe_parameter(const std::string & name) const;
rcl_interfaces::msg::ParameterDescriptor describe_parameter(const std::string & name) const;
/// Return a vector of parameter descriptors, one for each of the given names.
/**
@@ -696,8 +818,8 @@ public:
* allowed.
*/
RCLCPP_PUBLIC
std::vector<rcl_interfaces::msg::ParameterDescriptor>
describe_parameters(const std::vector<std::string> & names) const;
std::vector<rcl_interfaces::msg::ParameterDescriptor> describe_parameters(
const std::vector<std::string> & names) const;
/// Return a vector of parameter types, one for each of the given names.
/**
@@ -716,19 +838,17 @@ public:
* allowed.
*/
RCLCPP_PUBLIC
std::vector<uint8_t>
get_parameter_types(const std::vector<std::string> & names) const;
std::vector<uint8_t> get_parameter_types(const std::vector<std::string> & names) const;
/// Return a list of parameters with any of the given prefixes, up to the given depth.
/**
* \todo: properly document and test this method.
*/
RCLCPP_PUBLIC
rcl_interfaces::msg::ListParametersResult
list_parameters(const std::vector<std::string> & prefixes, uint64_t depth) const;
rcl_interfaces::msg::ListParametersResult list_parameters(
const std::vector<std::string> & prefixes, uint64_t depth) const;
using OnSetParametersCallbackHandle =
rclcpp::node_interfaces::OnSetParametersCallbackHandle;
using OnSetParametersCallbackHandle = rclcpp::node_interfaces::OnSetParametersCallbackHandle;
using OnParametersSetCallbackType =
rclcpp::node_interfaces::NodeParametersInterface::OnParametersSetCallbackType;
@@ -794,8 +914,8 @@ public:
* \throws std::bad_alloc if the allocation of the OnSetParametersCallbackHandle fails.
*/
RCLCPP_PUBLIC
OnSetParametersCallbackHandle::SharedPtr
add_on_set_parameters_callback(OnParametersSetCallbackType callback);
OnSetParametersCallbackHandle::SharedPtr add_on_set_parameters_callback(
OnParametersSetCallbackType callback);
/// Remove a callback registered with `add_on_set_parameters_callback`.
/**
@@ -821,8 +941,7 @@ public:
* or if it has been removed before.
*/
RCLCPP_PUBLIC
void
remove_on_set_parameters_callback(const OnSetParametersCallbackHandle * const handler);
void remove_on_set_parameters_callback(const OnSetParametersCallbackHandle * const handler);
/// Register a callback to be called anytime a parameter is about to be changed.
/**
@@ -839,8 +958,18 @@ public:
* otherwise nullptr.
*/
RCLCPP_PUBLIC
OnParametersSetCallbackType
set_on_parameters_set_callback(rclcpp::Node::OnParametersSetCallbackType callback);
OnParametersSetCallbackType set_on_parameters_set_callback(
rclcpp::Node::OnParametersSetCallbackType callback);
/// Register the callback for parameter changes
/**
* \param[in] callback User defined callback function.
* It is expected to atomically set parameters.
* \note Repeated invocations of this function will overwrite previous callbacks.
*/
template <typename CallbackT>
[[deprecated("use set_on_parameters_set_callback() instead")]] void
register_param_change_callback(CallbackT && callback);
/// Get the fully-qualified names of all available nodes.
/**
@@ -848,76 +977,19 @@ public:
* \return A vector of fully-qualified names of nodes.
*/
RCLCPP_PUBLIC
std::vector<std::string>
get_node_names() const;
std::vector<std::string> get_node_names() const;
RCLCPP_PUBLIC
std::map<std::string, std::vector<std::string>>
get_topic_names_and_types() const;
std::map<std::string, std::vector<std::string>> get_topic_names_and_types() const;
RCLCPP_PUBLIC
std::map<std::string, std::vector<std::string>>
get_service_names_and_types() const;
std::map<std::string, std::vector<std::string>> get_service_names_and_types() const;
RCLCPP_PUBLIC
size_t
count_publishers(const std::string & topic_name) const;
size_t count_publishers(const std::string & topic_name) const;
RCLCPP_PUBLIC
size_t
count_subscribers(const std::string & topic_name) const;
/// Return the topic endpoint information about publishers on a given topic.
/**
* The returned parameter is a list of topic endpoint information, where each item will contain
* the node name, node namespace, topic type, endpoint type, topic endpoint's GID, and its QoS
* profile.
*
* When the `no_mangle` parameter is `true`, the provided `topic_name` should be a valid topic
* name for the middleware (useful when combining ROS with native middleware (e.g. DDS) apps).
* When the `no_mangle` parameter is `false`, the provided `topic_name` should follow
* ROS topic name conventions.
*
* `topic_name` may be a relative, private, or fully qualified topic name.
* A relative or private topic will be expanded using this node's namespace and name.
* The queried `topic_name` is not remapped.
*
* \param[in] topic_name the topic_name on which to find the publishers.
* \param[in] no_mangle if `true`, `topic_name` needs to be a valid middleware topic name,
* otherwise it should be a valid ROS topic name. Defaults to `false`.
* \return a list of TopicEndpointInfo representing all the publishers on this topic.
* \throws InvalidTopicNameError if the given topic_name is invalid.
* \throws std::runtime_error if internal error happens.
*/
RCLCPP_PUBLIC
std::vector<rclcpp::TopicEndpointInfo>
get_publishers_info_by_topic(const std::string & topic_name, bool no_mangle = false) const;
/// Return the topic endpoint information about subscriptions on a given topic.
/**
* The returned parameter is a list of topic endpoint information, where each item will contain
* the node name, node namespace, topic type, endpoint type, topic endpoint's GID, and its QoS
* profile.
*
* When the `no_mangle` parameter is `true`, the provided `topic_name` should be a valid topic
* name for the middleware (useful when combining ROS with native middleware (e.g. DDS) apps).
* When the `no_mangle` parameter is `false`, the provided `topic_name` should follow
* ROS topic name conventions.
*
* `topic_name` may be a relative, private, or fully qualified topic name.
* A relative or private topic will be expanded using this node's namespace and name.
* The queried `topic_name` is not remapped.
*
* \param[in] topic_name the topic_name on which to find the subscriptions.
* \param[in] no_mangle if `true`, `topic_name` needs to be a valid middleware topic name,
* otherwise it should be a valid ROS topic name. Defaults to `false`.
* \return a list of TopicEndpointInfo representing all the subscriptions on this topic.
* \throws InvalidTopicNameError if the given topic_name is invalid.
* \throws std::runtime_error if internal error happens.
*/
RCLCPP_PUBLIC
std::vector<rclcpp::TopicEndpointInfo>
get_subscriptions_info_by_topic(const std::string & topic_name, bool no_mangle = false) const;
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.
@@ -925,8 +997,7 @@ public:
* out of scope.
*/
RCLCPP_PUBLIC
rclcpp::Event::SharedPtr
get_graph_event();
rclcpp::Event::SharedPtr get_graph_event();
/// Wait for a graph event to occur by waiting on an Event to become set.
/**
@@ -937,72 +1008,53 @@ public:
* get_graph_event().
*/
RCLCPP_PUBLIC
void
wait_for_graph_change(
rclcpp::Event::SharedPtr event,
std::chrono::nanoseconds timeout);
void wait_for_graph_change(rclcpp::Event::SharedPtr event, std::chrono::nanoseconds timeout);
RCLCPP_PUBLIC
rclcpp::Clock::SharedPtr
get_clock();
rclcpp::Clock::SharedPtr get_clock();
RCLCPP_PUBLIC
rclcpp::Clock::ConstSharedPtr
get_clock() const;
RCLCPP_PUBLIC
Time
now() const;
Time now();
/// Return the Node's internal NodeBaseInterface implementation.
RCLCPP_PUBLIC
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr
get_node_base_interface();
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr get_node_base_interface();
/// Return the Node's internal NodeClockInterface implementation.
RCLCPP_PUBLIC
rclcpp::node_interfaces::NodeClockInterface::SharedPtr
get_node_clock_interface();
rclcpp::node_interfaces::NodeClockInterface::SharedPtr get_node_clock_interface();
/// Return the Node's internal NodeGraphInterface implementation.
RCLCPP_PUBLIC
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr
get_node_graph_interface();
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr get_node_graph_interface();
/// Return the Node's internal NodeLoggingInterface implementation.
RCLCPP_PUBLIC
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr
get_node_logging_interface();
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr get_node_logging_interface();
/// Return the Node's internal NodeTimersInterface implementation.
RCLCPP_PUBLIC
rclcpp::node_interfaces::NodeTimersInterface::SharedPtr
get_node_timers_interface();
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();
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();
rclcpp::node_interfaces::NodeServicesInterface::SharedPtr get_node_services_interface();
/// Return the Node's internal NodeWaitablesInterface implementation.
RCLCPP_PUBLIC
rclcpp::node_interfaces::NodeWaitablesInterface::SharedPtr
get_node_waitables_interface();
rclcpp::node_interfaces::NodeWaitablesInterface::SharedPtr get_node_waitables_interface();
/// Return the Node's internal NodeParametersInterface implementation.
RCLCPP_PUBLIC
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr
get_node_parameters_interface();
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr get_node_parameters_interface();
/// Return the Node's internal NodeParametersInterface implementation.
RCLCPP_PUBLIC
rclcpp::node_interfaces::NodeTimeSourceInterface::SharedPtr
get_node_time_source_interface();
rclcpp::node_interfaces::NodeTimeSourceInterface::SharedPtr get_node_time_source_interface();
/// Return the sub-namespace, if this is a sub-node, otherwise an empty string.
/**
@@ -1033,8 +1085,7 @@ public:
* \return the sub-namespace string, not including the node's original namespace
*/
RCLCPP_PUBLIC
const std::string &
get_sub_namespace() const;
const std::string & get_sub_namespace() const;
/// Return the effective namespace that is used when creating entities.
/**
@@ -1061,8 +1112,7 @@ public:
* \return the sub-namespace string, not including the node's original namespace
*/
RCLCPP_PUBLIC
const std::string &
get_effective_namespace() const;
const std::string & get_effective_namespace() const;
/// Create a sub-node, which will extend the namespace of all entities created with it.
/**
@@ -1103,13 +1153,11 @@ public:
* with a leading '/'.
*/
RCLCPP_PUBLIC
rclcpp::Node::SharedPtr
create_sub_node(const std::string & sub_namespace);
rclcpp::Node::SharedPtr create_sub_node(const std::string & sub_namespace);
/// Return the NodeOptions used when creating this node.
RCLCPP_PUBLIC
const rclcpp::NodeOptions &
get_node_options() const;
const rclcpp::NodeOptions & get_node_options() const;
/// Manually assert that this Node is alive (for RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_NODE).
/**
@@ -1121,8 +1169,7 @@ public:
*/
RCLCPP_PUBLIC
RCUTILS_WARN_UNUSED
bool
assert_liveliness() const;
bool assert_liveliness() const;
protected:
/// Construct a sub-node, which will extend the namespace of all entities created with it.
@@ -1133,16 +1180,13 @@ protected:
* \param[in] sub_namespace The sub-namespace of the sub-node.
*/
RCLCPP_PUBLIC
Node(
const Node & other,
const std::string & sub_namespace);
Node(const Node & other, const std::string & sub_namespace);
private:
RCLCPP_DISABLE_COPY(Node)
RCLCPP_PUBLIC
bool
group_in_node(CallbackGroup::SharedPtr group);
bool group_in_node(callback_group::CallbackGroup::SharedPtr group);
rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_;
rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph_;

View File

@@ -33,12 +33,14 @@
#include "rcl/publisher.h"
#include "rcl/subscription.h"
#include "rcl_interfaces/msg/intra_process_message.hpp"
#include "rclcpp/contexts/default_context.hpp"
#include "rclcpp/create_client.hpp"
#include "rclcpp/create_publisher.hpp"
#include "rclcpp/create_service.hpp"
#include "rclcpp/create_subscription.hpp"
#include "rclcpp/detail/resolve_enable_topic_statistics.hpp"
#include "rclcpp/intra_process_manager.hpp"
#include "rclcpp/parameter.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/type_support_decl.hpp"
@@ -50,11 +52,9 @@
namespace rclcpp
{
RCLCPP_LOCAL
inline
std::string
extend_name_with_sub_namespace(const std::string & name, const std::string & sub_namespace)
inline std::string extend_name_with_sub_namespace(
const std::string & name, const std::string & sub_namespace)
{
std::string name_with_sub_namespace(name);
if (sub_namespace != "" && name.front() != '/' && name.front() != '~') {
@@ -63,115 +63,153 @@ extend_name_with_sub_namespace(const std::string & name, const std::string & sub
return name_with_sub_namespace;
}
template<typename MessageT, typename AllocatorT, typename PublisherT>
std::shared_ptr<PublisherT>
Node::create_publisher(
template <typename MessageT, typename AllocatorT, typename PublisherT>
std::shared_ptr<PublisherT> Node::create_publisher(
const std::string & topic_name,
const rclcpp::QoS & qos,
const PublisherOptionsWithAllocator<AllocatorT> & options)
{
return rclcpp::create_publisher<MessageT, AllocatorT, PublisherT>(
*this,
extend_name_with_sub_namespace(topic_name, this->get_sub_namespace()),
qos,
options);
*this, extend_name_with_sub_namespace(topic_name, this->get_sub_namespace()), qos, options);
}
template<
typename MessageT,
typename CallbackT,
typename AllocatorT,
typename CallbackMessageT,
typename SubscriptionT,
typename MessageMemoryStrategyT>
std::shared_ptr<SubscriptionT>
Node::create_subscription(
template <typename MessageT, typename AllocatorT, typename PublisherT>
std::shared_ptr<PublisherT> Node::create_publisher(
const std::string & topic_name, size_t qos_history_depth, std::shared_ptr<AllocatorT> allocator)
{
PublisherOptionsWithAllocator<AllocatorT> pub_options;
pub_options.allocator = allocator;
return this->create_publisher<MessageT, AllocatorT, PublisherT>(
topic_name, rclcpp::QoS(rclcpp::KeepLast(qos_history_depth)), pub_options);
}
template <typename MessageT, typename AllocatorT, typename PublisherT>
std::shared_ptr<PublisherT> Node::create_publisher(
const std::string & topic_name,
const rmw_qos_profile_t & qos_profile,
std::shared_ptr<AllocatorT> allocator)
{
rclcpp::QoS qos(rclcpp::QoSInitialization::from_rmw(qos_profile));
qos.get_rmw_qos_profile() = qos_profile;
PublisherOptionsWithAllocator<AllocatorT> pub_options;
pub_options.allocator = allocator;
return this->create_publisher<MessageT, AllocatorT, PublisherT>(topic_name, qos, pub_options);
}
template <typename MessageT, typename CallbackT, typename AllocatorT, typename SubscriptionT>
std::shared_ptr<SubscriptionT> Node::create_subscription(
const std::string & topic_name,
const rclcpp::QoS & qos,
CallbackT && callback,
const SubscriptionOptionsWithAllocator<AllocatorT> & options,
typename MessageMemoryStrategyT::SharedPtr msg_mem_strat)
typename rclcpp::message_memory_strategy::MessageMemoryStrategy<
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type,
AllocatorT>::SharedPtr msg_mem_strat)
{
return rclcpp::create_subscription<MessageT>(
*this,
extend_name_with_sub_namespace(topic_name, this->get_sub_namespace()),
qos,
std::forward<CallbackT>(callback),
options,
msg_mem_strat);
*this, extend_name_with_sub_namespace(topic_name, this->get_sub_namespace()), qos,
std::forward<CallbackT>(callback), options, msg_mem_strat);
}
template<typename DurationRepT, typename DurationT, typename CallbackT>
typename rclcpp::WallTimer<CallbackT>::SharedPtr
Node::create_wall_timer(
template <typename MessageT, typename CallbackT, typename Alloc, typename SubscriptionT>
std::shared_ptr<SubscriptionT> Node::create_subscription(
const std::string & topic_name,
CallbackT && callback,
const rmw_qos_profile_t & qos_profile,
rclcpp::callback_group::CallbackGroup::SharedPtr group,
bool ignore_local_publications,
typename rclcpp::message_memory_strategy::MessageMemoryStrategy<
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type,
Alloc>::SharedPtr msg_mem_strat,
std::shared_ptr<Alloc> allocator)
{
rclcpp::QoS qos(rclcpp::QoSInitialization::from_rmw(qos_profile));
qos.get_rmw_qos_profile() = qos_profile;
SubscriptionOptionsWithAllocator<Alloc> sub_options;
sub_options.callback_group = group;
sub_options.ignore_local_publications = ignore_local_publications;
sub_options.allocator = allocator;
return this->create_subscription<MessageT, CallbackT, Alloc, SubscriptionT>(
topic_name, qos, std::forward<CallbackT>(callback), sub_options, msg_mem_strat);
}
template <typename MessageT, typename CallbackT, typename Alloc, typename SubscriptionT>
std::shared_ptr<SubscriptionT> Node::create_subscription(
const std::string & topic_name,
CallbackT && callback,
size_t qos_history_depth,
rclcpp::callback_group::CallbackGroup::SharedPtr group,
bool ignore_local_publications,
typename rclcpp::message_memory_strategy::MessageMemoryStrategy<
typename rclcpp::subscription_traits::has_message_type<CallbackT>::type,
Alloc>::SharedPtr msg_mem_strat,
std::shared_ptr<Alloc> allocator)
{
SubscriptionOptionsWithAllocator<Alloc> sub_options;
sub_options.callback_group = group;
sub_options.ignore_local_publications = ignore_local_publications;
sub_options.allocator = allocator;
return this->create_subscription<MessageT, CallbackT, Alloc, SubscriptionT>(
topic_name, rclcpp::QoS(rclcpp::KeepLast(qos_history_depth)), std::forward<CallbackT>(callback),
sub_options, msg_mem_strat);
}
template <typename DurationRepT, typename DurationT, typename CallbackT>
typename rclcpp::WallTimer<CallbackT>::SharedPtr Node::create_wall_timer(
std::chrono::duration<DurationRepT, DurationT> period,
CallbackT callback,
rclcpp::CallbackGroup::SharedPtr group)
rclcpp::callback_group::CallbackGroup::SharedPtr group)
{
auto timer = rclcpp::WallTimer<CallbackT>::make_shared(
std::chrono::duration_cast<std::chrono::nanoseconds>(period),
std::move(callback),
std::chrono::duration_cast<std::chrono::nanoseconds>(period), std::move(callback),
this->node_base_->get_context());
node_timers_->add_timer(timer, group);
return timer;
}
template<typename ServiceT>
typename Client<ServiceT>::SharedPtr
Node::create_client(
template <typename ServiceT>
typename Client<ServiceT>::SharedPtr Node::create_client(
const std::string & service_name,
const rmw_qos_profile_t & qos_profile,
rclcpp::CallbackGroup::SharedPtr group)
rclcpp::callback_group::CallbackGroup::SharedPtr group)
{
return rclcpp::create_client<ServiceT>(
node_base_,
node_graph_,
node_services_,
extend_name_with_sub_namespace(service_name, this->get_sub_namespace()),
qos_profile,
group);
node_base_, node_graph_, node_services_,
extend_name_with_sub_namespace(service_name, this->get_sub_namespace()), qos_profile, group);
}
template<typename ServiceT, typename CallbackT>
typename rclcpp::Service<ServiceT>::SharedPtr
Node::create_service(
template <typename ServiceT, typename CallbackT>
typename rclcpp::Service<ServiceT>::SharedPtr Node::create_service(
const std::string & service_name,
CallbackT && callback,
const rmw_qos_profile_t & qos_profile,
rclcpp::CallbackGroup::SharedPtr group)
rclcpp::callback_group::CallbackGroup::SharedPtr group)
{
return rclcpp::create_service<ServiceT, CallbackT>(
node_base_,
node_services_,
node_base_, node_services_,
extend_name_with_sub_namespace(service_name, this->get_sub_namespace()),
std::forward<CallbackT>(callback),
qos_profile,
group);
std::forward<CallbackT>(callback), qos_profile, group);
}
template<typename ParameterT>
auto
Node::declare_parameter(
template <typename ParameterT>
auto Node::declare_parameter(
const std::string & name,
const ParameterT & default_value,
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor,
bool ignore_override)
{
try {
return this->declare_parameter(
name,
rclcpp::ParameterValue(default_value),
parameter_descriptor,
ignore_override
).get<ParameterT>();
} catch (const ParameterTypeException & ex) {
throw exceptions::InvalidParameterTypeException(name, ex.what());
}
return this
->declare_parameter(
name, rclcpp::ParameterValue(default_value), parameter_descriptor, ignore_override)
.get<ParameterT>();
}
template<typename ParameterT>
std::vector<ParameterT>
Node::declare_parameters(
template <typename ParameterT>
std::vector<ParameterT> Node::declare_parameters(
const std::string & namespace_,
const std::map<std::string, ParameterT> & parameters,
bool ignore_overrides)
@@ -182,23 +220,17 @@ Node::declare_parameters(
parameters.begin(), parameters.end(), std::back_inserter(result),
[this, &normalized_namespace, ignore_overrides](auto element) {
return this->declare_parameter(
normalized_namespace + element.first,
element.second,
rcl_interfaces::msg::ParameterDescriptor(),
ignore_overrides);
}
);
normalized_namespace + element.first, element.second,
rcl_interfaces::msg::ParameterDescriptor(), ignore_overrides);
});
return result;
}
template<typename ParameterT>
std::vector<ParameterT>
Node::declare_parameters(
template <typename ParameterT>
std::vector<ParameterT> Node::declare_parameters(
const std::string & namespace_,
const std::map<
std::string,
std::pair<ParameterT, rcl_interfaces::msg::ParameterDescriptor>
> & parameters,
const std::map<std::string, std::pair<ParameterT, rcl_interfaces::msg::ParameterDescriptor> > &
parameters,
bool ignore_overrides)
{
std::vector<ParameterT> result;
@@ -206,21 +238,44 @@ Node::declare_parameters(
std::transform(
parameters.begin(), parameters.end(), std::back_inserter(result),
[this, &normalized_namespace, ignore_overrides](auto element) {
return static_cast<ParameterT>(
this->declare_parameter(
normalized_namespace + element.first,
element.second.first,
element.second.second,
ignore_overrides)
);
}
);
return static_cast<ParameterT>(this->declare_parameter(
normalized_namespace + element.first, element.second.first, element.second.second,
ignore_overrides));
});
return result;
}
template<typename ParameterT>
bool
Node::get_parameter(const std::string & name, ParameterT & parameter) const
template <typename ParameterT>
void Node::set_parameter_if_not_set(const std::string & name, const ParameterT & value)
{
if (!this->has_parameter(name) || this->describe_parameter(name).type == PARAMETER_NOT_SET) {
this->set_parameter(rclcpp::Parameter(name, value));
}
}
// this is a partially-specialized version of set_parameter_if_not_set above,
// where our concrete type for ParameterT is std::map, but the to-be-determined
// type is the value in the map.
template <typename ParameterT>
void Node::set_parameters_if_not_set(
const std::string & name, const std::map<std::string, ParameterT> & values)
{
std::vector<rclcpp::Parameter> params;
for (const auto & val : values) {
std::string parameter_name = name + "." + val.first;
if (
!this->has_parameter(parameter_name) ||
this->describe_parameter(parameter_name).type == PARAMETER_NOT_SET) {
params.push_back(rclcpp::Parameter(parameter_name, val.second));
}
}
this->set_parameters(params);
}
template <typename ParameterT>
bool Node::get_parameter(const std::string & name, ParameterT & parameter) const
{
std::string sub_name = extend_name_with_sub_namespace(name, this->get_sub_namespace());
@@ -234,12 +289,9 @@ Node::get_parameter(const std::string & name, ParameterT & parameter) const
return result;
}
template<typename ParameterT>
bool
Node::get_parameter_or(
const std::string & name,
ParameterT & parameter,
const ParameterT & alternative_value) const
template <typename ParameterT>
bool Node::get_parameter_or(
const std::string & name, ParameterT & parameter, const ParameterT & alternative_value) const
{
std::string sub_name = extend_name_with_sub_namespace(name, this->get_sub_namespace());
@@ -253,11 +305,9 @@ Node::get_parameter_or(
// this is a partially-specialized version of get_parameter above,
// where our concrete type for ParameterT is std::map, but the to-be-determined
// type is the value in the map.
template<typename ParameterT>
bool
Node::get_parameters(
const std::string & prefix,
std::map<std::string, ParameterT> & values) const
template <typename ParameterT>
bool Node::get_parameters(
const std::string & prefix, std::map<std::string, ParameterT> & values) const
{
std::map<std::string, rclcpp::Parameter> params;
bool result = node_parameters_->get_parameters_by_prefix(prefix, params);
@@ -270,6 +320,27 @@ Node::get_parameters(
return result;
}
template <typename ParameterT>
void Node::get_parameter_or_set(
const std::string & name, ParameterT & value, const ParameterT & alternative_value)
{
std::string sub_name = extend_name_with_sub_namespace(name, this->get_sub_namespace());
bool got_parameter = get_parameter(sub_name, value);
if (!got_parameter) {
this->set_parameters({
rclcpp::Parameter(sub_name, alternative_value),
});
value = alternative_value;
}
}
template <typename CallbackT>
void Node::register_param_change_callback(CallbackT && callback)
{
this->node_parameters_->register_param_change_callback(std::forward<CallbackT>(callback));
}
} // namespace rclcpp
#endif // RCLCPP__NODE_IMPL_HPP_

View File

@@ -16,8 +16,8 @@
#define RCLCPP__NODE_INTERFACES__GET_NODE_BASE_INTERFACE_HPP_
#include <memory>
#include <utility>
#include <type_traits>
#include <utility>
#include "rclcpp/node_interfaces/node_base_interface.hpp"
@@ -36,29 +36,21 @@ namespace rclcpp
{
namespace node_interfaces
{
namespace detail
{
// This is a meta-programming checker for if a given Node-like object has a
// getter called get_node_base_interface() which returns various types,
// e.g. const pointer or a shared pointer.
template<typename NodeType, typename ReturnType>
template <typename NodeType, typename ReturnType>
struct has_get_node_base_interface
{
private:
template<typename T>
static constexpr
auto
check(T *)->typename std::is_same<
decltype(std::declval<T>().get_node_base_interface()),
ReturnType
>::type;
template <typename T>
static constexpr auto check(T *) ->
typename std::is_same<decltype(std::declval<T>().get_node_base_interface()), ReturnType>::type;
template<typename>
static constexpr
std::false_type
check(...);
template <typename>
static constexpr std::false_type check(...);
public:
using type = decltype(check<NodeType>(nullptr));
@@ -66,51 +58,51 @@ public:
};
// If NodeType is a pointer to NodeBaseInterface already (just normal function overload).
inline
rclcpp::node_interfaces::NodeBaseInterface *
get_node_base_interface_from_pointer(rclcpp::node_interfaces::NodeBaseInterface * pointer)
inline rclcpp::node_interfaces::NodeBaseInterface * get_node_base_interface_from_pointer(
rclcpp::node_interfaces::NodeBaseInterface * pointer)
{
return pointer;
}
// If NodeType has a method called get_node_base_interface() which returns a shared pointer.
template<
template <
typename NodeType,
typename std::enable_if<has_get_node_base_interface<
typename std::remove_pointer<NodeType>::type,
std::shared_ptr<rclcpp::node_interfaces::NodeBaseInterface>
>::value, int>::type = 0
>
rclcpp::node_interfaces::NodeBaseInterface *
get_node_base_interface_from_pointer(NodeType node_pointer)
typename std::enable_if<
has_get_node_base_interface<
typename std::remove_pointer<NodeType>::type,
std::shared_ptr<rclcpp::node_interfaces::NodeBaseInterface> >::value,
int>::type = 0>
rclcpp::node_interfaces::NodeBaseInterface * get_node_base_interface_from_pointer(
NodeType node_pointer)
{
return node_pointer->get_node_base_interface().get();
}
// If NodeType has a method called get_node_base_interface() which returns a pointer.
template<
template <
typename NodeType,
typename std::enable_if<has_get_node_base_interface<
typename std::remove_pointer<NodeType>::type,
rclcpp::node_interfaces::NodeBaseInterface *
>::value, int>::type = 0
>
rclcpp::node_interfaces::NodeBaseInterface *
get_node_base_interface_from_pointer(NodeType node_pointer)
typename std::enable_if<
has_get_node_base_interface<
typename std::remove_pointer<NodeType>::type,
rclcpp::node_interfaces::NodeBaseInterface *>::value,
int>::type = 0>
rclcpp::node_interfaces::NodeBaseInterface * get_node_base_interface_from_pointer(
NodeType node_pointer)
{
return node_pointer->get_node_base_interface();
}
// Forward shared_ptr's to const node pointer signatures.
template<
template <
typename NodeType,
typename std::enable_if<std::is_same<
NodeType,
typename std::shared_ptr<typename std::remove_pointer<NodeType>::type::element_type> *
>::value, int>::type = 0
>
rclcpp::node_interfaces::NodeBaseInterface *
get_node_base_interface_from_pointer(NodeType node_shared_pointer)
typename std::enable_if<
std::is_same<
NodeType,
typename std::shared_ptr<typename std::remove_pointer<NodeType>::type::element_type> *>::
value,
int>::type = 0>
rclcpp::node_interfaces::NodeBaseInterface * get_node_base_interface_from_pointer(
NodeType node_shared_pointer)
{
return get_node_base_interface_from_pointer(node_shared_pointer->get());
}
@@ -118,26 +110,22 @@ get_node_base_interface_from_pointer(NodeType node_shared_pointer)
} // namespace detail
/// Get the NodeBaseInterface as a pointer from a pointer to a "Node like" object.
template<
template <
typename NodeType,
typename std::enable_if<std::is_pointer<NodeType>::value, int>::type = 0
>
rclcpp::node_interfaces::NodeBaseInterface *
get_node_base_interface(NodeType node_pointer)
typename std::enable_if<std::is_pointer<NodeType>::value, int>::type = 0>
rclcpp::node_interfaces::NodeBaseInterface * get_node_base_interface(NodeType node_pointer)
{
// Forward pointers to detail implmentation directly.
return detail::get_node_base_interface_from_pointer(node_pointer);
}
/// Get the NodeBaseInterface as a pointer from a "Node like" object.
template<
template <
typename NodeType,
typename std::enable_if<
!std::is_pointer<typename std::remove_reference<NodeType>::type>::value, int
>::type = 0
>
rclcpp::node_interfaces::NodeBaseInterface *
get_node_base_interface(NodeType && node_reference)
!std::is_pointer<typename std::remove_reference<NodeType>::type>::value,
int>::type = 0>
rclcpp::node_interfaces::NodeBaseInterface * get_node_base_interface(NodeType && node_reference)
{
// Forward references to detail implmentation as a pointer.
return detail::get_node_base_interface_from_pointer(&node_reference);

View File

@@ -16,8 +16,8 @@
#define RCLCPP__NODE_INTERFACES__GET_NODE_TIMERS_INTERFACE_HPP_
#include <memory>
#include <utility>
#include <type_traits>
#include <utility>
#include "rclcpp/node_interfaces/node_timers_interface.hpp"
@@ -36,29 +36,21 @@ namespace rclcpp
{
namespace node_interfaces
{
namespace detail
{
// This is a meta-programming checker for if a given Node-like object has a
// getter called get_node_timers_interface() which returns various types,
// e.g. const pointer or a shared pointer.
template<typename NodeType, typename ReturnType>
template <typename NodeType, typename ReturnType>
struct has_get_node_timers_interface
{
private:
template<typename T>
static constexpr
auto
check(T *)->typename std::is_same<
decltype(std::declval<T>().get_node_timers_interface()),
ReturnType
>::type;
template <typename T>
static constexpr auto check(T *) -> typename std::
is_same<decltype(std::declval<T>().get_node_timers_interface()), ReturnType>::type;
template<typename>
static constexpr
std::false_type
check(...);
template <typename>
static constexpr std::false_type check(...);
public:
using type = decltype(check<NodeType>(nullptr));
@@ -66,51 +58,51 @@ public:
};
// If NodeType is a pointer to NodeTimersInterface already (just normal function overload).
inline
rclcpp::node_interfaces::NodeTimersInterface *
get_node_timers_interface_from_pointer(rclcpp::node_interfaces::NodeTimersInterface * pointer)
inline rclcpp::node_interfaces::NodeTimersInterface * get_node_timers_interface_from_pointer(
rclcpp::node_interfaces::NodeTimersInterface * pointer)
{
return pointer;
}
// If NodeType has a method called get_node_timers_interface() which returns a shared pointer.
template<
template <
typename NodeType,
typename std::enable_if<has_get_node_timers_interface<
typename std::remove_pointer<NodeType>::type,
std::shared_ptr<rclcpp::node_interfaces::NodeTimersInterface>
>::value, int>::type = 0
>
rclcpp::node_interfaces::NodeTimersInterface *
get_node_timers_interface_from_pointer(NodeType node_pointer)
typename std::enable_if<
has_get_node_timers_interface<
typename std::remove_pointer<NodeType>::type,
std::shared_ptr<rclcpp::node_interfaces::NodeTimersInterface> >::value,
int>::type = 0>
rclcpp::node_interfaces::NodeTimersInterface * get_node_timers_interface_from_pointer(
NodeType node_pointer)
{
return node_pointer->get_node_timers_interface().get();
}
// If NodeType has a method called get_node_timers_interface() which returns a pointer.
template<
template <
typename NodeType,
typename std::enable_if<has_get_node_timers_interface<
typename std::remove_pointer<NodeType>::type,
rclcpp::node_interfaces::NodeTimersInterface *
>::value, int>::type = 0
>
rclcpp::node_interfaces::NodeTimersInterface *
get_node_timers_interface_from_pointer(NodeType node_pointer)
typename std::enable_if<
has_get_node_timers_interface<
typename std::remove_pointer<NodeType>::type,
rclcpp::node_interfaces::NodeTimersInterface *>::value,
int>::type = 0>
rclcpp::node_interfaces::NodeTimersInterface * get_node_timers_interface_from_pointer(
NodeType node_pointer)
{
return node_pointer->get_node_timers_interface();
}
// Forward shared_ptr's to const node pointer signatures.
template<
template <
typename NodeType,
typename std::enable_if<std::is_same<
NodeType,
typename std::shared_ptr<typename std::remove_pointer<NodeType>::type::element_type> *
>::value, int>::type = 0
>
rclcpp::node_interfaces::NodeTimersInterface *
get_node_timers_interface_from_pointer(NodeType node_shared_pointer)
typename std::enable_if<
std::is_same<
NodeType,
typename std::shared_ptr<typename std::remove_pointer<NodeType>::type::element_type> *>::
value,
int>::type = 0>
rclcpp::node_interfaces::NodeTimersInterface * get_node_timers_interface_from_pointer(
NodeType node_shared_pointer)
{
return get_node_timers_interface_from_pointer(node_shared_pointer->get());
}
@@ -118,26 +110,22 @@ get_node_timers_interface_from_pointer(NodeType node_shared_pointer)
} // namespace detail
/// Get the NodeTimersInterface as a pointer from a pointer to a "Node like" object.
template<
template <
typename NodeType,
typename std::enable_if<std::is_pointer<NodeType>::value, int>::type = 0
>
rclcpp::node_interfaces::NodeTimersInterface *
get_node_timers_interface(NodeType node_pointer)
typename std::enable_if<std::is_pointer<NodeType>::value, int>::type = 0>
rclcpp::node_interfaces::NodeTimersInterface * get_node_timers_interface(NodeType node_pointer)
{
// Forward pointers to detail implmentation directly.
return detail::get_node_timers_interface_from_pointer(node_pointer);
}
/// Get the NodeTimersInterface as a pointer from a "Node like" object.
template<
template <
typename NodeType,
typename std::enable_if<
!std::is_pointer<typename std::remove_reference<NodeType>::type>::value, int
>::type = 0
>
rclcpp::node_interfaces::NodeTimersInterface *
get_node_timers_interface(NodeType && node_reference)
!std::is_pointer<typename std::remove_reference<NodeType>::type>::value,
int>::type = 0>
rclcpp::node_interfaces::NodeTimersInterface * get_node_timers_interface(NodeType && node_reference)
{
// Forward references to detail implmentation as a pointer.
return detail::get_node_timers_interface_from_pointer(&node_reference);

View File

@@ -16,8 +16,8 @@
#define RCLCPP__NODE_INTERFACES__GET_NODE_TOPICS_INTERFACE_HPP_
#include <memory>
#include <utility>
#include <type_traits>
#include <utility>
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
@@ -36,29 +36,21 @@ namespace rclcpp
{
namespace node_interfaces
{
namespace detail
{
// This is a meta-programming checker for if a given Node-like object has a
// getter called get_node_topics_interface() which returns various types,
// e.g. const pointer or a shared pointer.
template<typename NodeType, typename ReturnType>
template <typename NodeType, typename ReturnType>
struct has_get_node_topics_interface
{
private:
template<typename T>
static constexpr
auto
check(T *)->typename std::is_same<
decltype(std::declval<T>().get_node_topics_interface()),
ReturnType
>::type;
template <typename T>
static constexpr auto check(T *) -> typename std::
is_same<decltype(std::declval<T>().get_node_topics_interface()), ReturnType>::type;
template<typename>
static constexpr
std::false_type
check(...);
template <typename>
static constexpr std::false_type check(...);
public:
using type = decltype(check<NodeType>(nullptr));
@@ -66,51 +58,51 @@ public:
};
// If NodeType is a pointer to NodeTopicsInterface already (just normal function overload).
inline
rclcpp::node_interfaces::NodeTopicsInterface *
get_node_topics_interface_from_pointer(rclcpp::node_interfaces::NodeTopicsInterface * pointer)
inline rclcpp::node_interfaces::NodeTopicsInterface * get_node_topics_interface_from_pointer(
rclcpp::node_interfaces::NodeTopicsInterface * pointer)
{
return pointer;
}
// If NodeType has a method called get_node_topics_interface() which returns a shared pointer.
template<
template <
typename NodeType,
typename std::enable_if<has_get_node_topics_interface<
typename std::remove_pointer<NodeType>::type,
std::shared_ptr<rclcpp::node_interfaces::NodeTopicsInterface>
>::value, int>::type = 0
>
rclcpp::node_interfaces::NodeTopicsInterface *
get_node_topics_interface_from_pointer(NodeType node_pointer)
typename std::enable_if<
has_get_node_topics_interface<
typename std::remove_pointer<NodeType>::type,
std::shared_ptr<rclcpp::node_interfaces::NodeTopicsInterface> >::value,
int>::type = 0>
rclcpp::node_interfaces::NodeTopicsInterface * get_node_topics_interface_from_pointer(
NodeType node_pointer)
{
return node_pointer->get_node_topics_interface().get();
}
// If NodeType has a method called get_node_topics_interface() which returns a pointer.
template<
template <
typename NodeType,
typename std::enable_if<has_get_node_topics_interface<
typename std::remove_pointer<NodeType>::type,
rclcpp::node_interfaces::NodeTopicsInterface *
>::value, int>::type = 0
>
rclcpp::node_interfaces::NodeTopicsInterface *
get_node_topics_interface_from_pointer(NodeType node_pointer)
typename std::enable_if<
has_get_node_topics_interface<
typename std::remove_pointer<NodeType>::type,
rclcpp::node_interfaces::NodeTopicsInterface *>::value,
int>::type = 0>
rclcpp::node_interfaces::NodeTopicsInterface * get_node_topics_interface_from_pointer(
NodeType node_pointer)
{
return node_pointer->get_node_topics_interface();
}
// Forward shared_ptr's to const node pointer signatures.
template<
template <
typename NodeType,
typename std::enable_if<std::is_same<
NodeType,
typename std::shared_ptr<typename std::remove_pointer<NodeType>::type::element_type> *
>::value, int>::type = 0
>
rclcpp::node_interfaces::NodeTopicsInterface *
get_node_topics_interface_from_pointer(NodeType node_shared_pointer)
typename std::enable_if<
std::is_same<
NodeType,
typename std::shared_ptr<typename std::remove_pointer<NodeType>::type::element_type> *>::
value,
int>::type = 0>
rclcpp::node_interfaces::NodeTopicsInterface * get_node_topics_interface_from_pointer(
NodeType node_shared_pointer)
{
return get_node_topics_interface_from_pointer(node_shared_pointer->get());
}
@@ -118,26 +110,22 @@ get_node_topics_interface_from_pointer(NodeType node_shared_pointer)
} // namespace detail
/// Get the NodeTopicsInterface as a pointer from a pointer to a "Node like" object.
template<
template <
typename NodeType,
typename std::enable_if<std::is_pointer<NodeType>::value, int>::type = 0
>
rclcpp::node_interfaces::NodeTopicsInterface *
get_node_topics_interface(NodeType node_pointer)
typename std::enable_if<std::is_pointer<NodeType>::value, int>::type = 0>
rclcpp::node_interfaces::NodeTopicsInterface * get_node_topics_interface(NodeType node_pointer)
{
// Forward pointers to detail implmentation directly.
return detail::get_node_topics_interface_from_pointer(node_pointer);
}
/// Get the NodeTopicsInterface as a pointer from a "Node like" object.
template<
template <
typename NodeType,
typename std::enable_if<
!std::is_pointer<typename std::remove_reference<NodeType>::type>::value, int
>::type = 0
>
rclcpp::node_interfaces::NodeTopicsInterface *
get_node_topics_interface(NodeType && node_reference)
!std::is_pointer<typename std::remove_reference<NodeType>::type>::value,
int>::type = 0>
rclcpp::node_interfaces::NodeTopicsInterface * get_node_topics_interface(NodeType && node_reference)
{
// Forward references to detail implmentation as a pointer.
return detail::get_node_topics_interface_from_pointer(&node_reference);

View File

@@ -23,13 +23,13 @@
#include "rclcpp/context.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/node_options.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
namespace node_interfaces
{
/// Implementation of the NodeBase part of the Node API.
class NodeBase : public NodeBaseInterface
{
@@ -42,112 +42,74 @@ public:
const std::string & namespace_,
rclcpp::Context::SharedPtr context,
const rcl_node_options_t & rcl_node_options,
bool use_intra_process_default,
bool enable_topic_statistics_default);
bool use_intra_process_default);
RCLCPP_PUBLIC
virtual
~NodeBase();
virtual ~NodeBase();
RCLCPP_PUBLIC
const char *
get_name() const override;
virtual const char * get_name() const;
RCLCPP_PUBLIC
const char *
get_namespace() const override;
virtual const char * get_namespace() const;
RCLCPP_PUBLIC
const char *
get_fully_qualified_name() const override;
virtual const char * get_fully_qualified_name() const;
RCLCPP_PUBLIC
rclcpp::Context::SharedPtr
get_context() override;
virtual rclcpp::Context::SharedPtr get_context();
RCLCPP_PUBLIC
rcl_node_t *
get_rcl_node_handle() override;
virtual rcl_node_t * get_rcl_node_handle();
RCLCPP_PUBLIC
const rcl_node_t *
get_rcl_node_handle() const override;
virtual const rcl_node_t * get_rcl_node_handle() const;
RCLCPP_PUBLIC
std::shared_ptr<rcl_node_t>
get_shared_rcl_node_handle() override;
virtual std::shared_ptr<rcl_node_t> get_shared_rcl_node_handle();
RCLCPP_PUBLIC
std::shared_ptr<const rcl_node_t>
get_shared_rcl_node_handle() const override;
virtual std::shared_ptr<const rcl_node_t> get_shared_rcl_node_handle() const;
RCLCPP_PUBLIC
bool
assert_liveliness() const override;
virtual bool assert_liveliness() const;
RCLCPP_PUBLIC
rclcpp::CallbackGroup::SharedPtr
create_callback_group(rclcpp::CallbackGroupType group_type) override;
virtual rclcpp::callback_group::CallbackGroup::SharedPtr create_callback_group(
rclcpp::callback_group::CallbackGroupType group_type);
RCLCPP_PUBLIC
rclcpp::CallbackGroup::SharedPtr
get_default_callback_group() override;
virtual rclcpp::callback_group::CallbackGroup::SharedPtr get_default_callback_group();
RCLCPP_PUBLIC
bool
callback_group_in_node(rclcpp::CallbackGroup::SharedPtr group) override;
virtual bool callback_group_in_node(rclcpp::callback_group::CallbackGroup::SharedPtr group);
RCLCPP_PUBLIC
const std::vector<rclcpp::CallbackGroup::WeakPtr> &
get_callback_groups() const override;
virtual const std::vector<rclcpp::callback_group::CallbackGroup::WeakPtr> & get_callback_groups()
const;
RCLCPP_PUBLIC
std::atomic_bool &
get_associated_with_executor_atomic() override;
virtual std::atomic_bool & get_associated_with_executor_atomic();
RCLCPP_PUBLIC
rcl_guard_condition_t *
get_notify_guard_condition() override;
virtual rcl_guard_condition_t * get_notify_guard_condition();
RCLCPP_PUBLIC
std::unique_lock<std::recursive_mutex>
acquire_notify_guard_condition_lock() const override;
virtual std::unique_lock<std::recursive_mutex> acquire_notify_guard_condition_lock() const;
RCLCPP_PUBLIC
bool
get_use_intra_process_default() const override;
bool
get_enable_topic_statistics_default() const override;
virtual bool get_use_intra_process_default() const;
private:
RCLCPP_DISABLE_COPY(NodeBase)
rclcpp::Context::SharedPtr context_;
bool use_intra_process_default_;
bool enable_topic_statistics_default_;
std::shared_ptr<rcl_node_t> node_handle_;
rclcpp::CallbackGroup::SharedPtr default_callback_group_;
std::vector<rclcpp::CallbackGroup::WeakPtr> callback_groups_;
rclcpp::callback_group::CallbackGroup::SharedPtr default_callback_group_;
std::vector<rclcpp::callback_group::CallbackGroup::WeakPtr> callback_groups_;
std::atomic_bool associated_with_executor_;

View File

@@ -31,7 +31,6 @@ namespace rclcpp
{
namespace node_interfaces
{
/// Pure virtual interface class for the NodeBase part of the Node API.
class NodeBaseInterface
{
@@ -39,48 +38,35 @@ public:
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeBaseInterface)
RCLCPP_PUBLIC
virtual
~NodeBaseInterface() = default;
virtual ~NodeBaseInterface() = default;
/// Return the name of the node.
/** \return The name of the node. */
RCLCPP_PUBLIC
virtual
const char *
get_name() const = 0;
virtual const char * get_name() const = 0;
/// Return the namespace of the node.
/** \return The namespace of the node. */
RCLCPP_PUBLIC
virtual
const char *
get_namespace() const = 0;
virtual const char * get_namespace() const = 0;
/// Return the fully qualified name of the node.
/** \return The fully qualified name of the node. */
RCLCPP_PUBLIC
virtual
const char *
get_fully_qualified_name() const = 0;
virtual const char * get_fully_qualified_name() const = 0;
/// Return the context of the node.
/** \return SharedPtr to the node's context. */
RCLCPP_PUBLIC
virtual
rclcpp::Context::SharedPtr
get_context() = 0;
virtual rclcpp::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;
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;
virtual const rcl_node_t * get_rcl_node_handle() const = 0;
/// Return the rcl_node_t node handle in a std::shared_ptr.
/**
@@ -88,9 +74,7 @@ public:
* 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;
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.
/**
@@ -98,45 +82,33 @@ public:
* 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;
virtual std::shared_ptr<const rcl_node_t> get_shared_rcl_node_handle() const = 0;
/// Manually assert that this Node is alive (for RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_NODE).
RCLCPP_PUBLIC
virtual
bool
assert_liveliness() const = 0;
virtual bool assert_liveliness() const = 0;
/// Create and return a callback group.
RCLCPP_PUBLIC
virtual
rclcpp::CallbackGroup::SharedPtr
create_callback_group(rclcpp::CallbackGroupType group_type) = 0;
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::CallbackGroup::SharedPtr
get_default_callback_group() = 0;
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::CallbackGroup::SharedPtr group) = 0;
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::CallbackGroup::WeakPtr> &
get_callback_groups() const = 0;
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;
virtual std::atomic_bool & get_associated_with_executor_atomic() = 0;
/// Return guard condition that should be notified when the internal node state changes.
/**
@@ -145,28 +117,16 @@ public:
* \return the rcl_guard_condition_t if it is valid, else nullptr
*/
RCLCPP_PUBLIC
virtual
rcl_guard_condition_t *
get_notify_guard_condition() = 0;
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;
virtual std::unique_lock<std::recursive_mutex> acquire_notify_guard_condition_lock() const = 0;
/// Return the default preference for using intra process communication.
RCLCPP_PUBLIC
virtual
bool
get_use_intra_process_default() const = 0;
/// Return the default preference for enabling topic statistics collection.
RCLCPP_PUBLIC
virtual
bool
get_enable_topic_statistics_default() const = 0;
virtual bool get_use_intra_process_default() const = 0;
};
} // namespace node_interfaces

View File

@@ -15,21 +15,20 @@
#ifndef RCLCPP__NODE_INTERFACES__NODE_CLOCK_HPP_
#define RCLCPP__NODE_INTERFACES__NODE_CLOCK_HPP_
#include "rclcpp/callback_group.hpp"
#include "rclcpp/clock.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/node_interfaces/node_clock_interface.hpp"
#include "rclcpp/node_interfaces/node_graph_interface.hpp"
#include "rclcpp/node_interfaces/node_logging_interface.hpp"
#include "rclcpp/node_interfaces/node_services_interface.hpp"
#include "rclcpp/node_interfaces/node_parameters_interface.hpp"
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
#include "rclcpp/time_source.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
namespace node_interfaces
{
/// Implementation of the NodeClock part of the Node API.
class NodeClock : public NodeClockInterface
{
@@ -45,18 +44,11 @@ public:
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging);
RCLCPP_PUBLIC
virtual
~NodeClock();
virtual ~NodeClock();
/// Get a clock which will be kept up to date by the node.
RCLCPP_PUBLIC
rclcpp::Clock::SharedPtr
get_clock() override;
/// Get a clock which will be kept up to date by the node.
RCLCPP_PUBLIC
rclcpp::Clock::ConstSharedPtr
get_clock() const override;
virtual rclcpp::Clock::SharedPtr get_clock();
private:
RCLCPP_DISABLE_COPY(NodeClock)

View File

@@ -15,6 +15,7 @@
#ifndef RCLCPP__NODE_INTERFACES__NODE_CLOCK_INTERFACE_HPP_
#define RCLCPP__NODE_INTERFACES__NODE_CLOCK_INTERFACE_HPP_
#include "rclcpp/callback_group.hpp"
#include "rclcpp/clock.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/visibility_control.hpp"
@@ -23,7 +24,6 @@ namespace rclcpp
{
namespace node_interfaces
{
/// Pure virtual interface class for the NodeClock part of the Node API.
class NodeClockInterface
{
@@ -31,20 +31,11 @@ public:
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeClockInterface)
RCLCPP_PUBLIC
virtual
~NodeClockInterface() = default;
virtual ~NodeClockInterface() = default;
/// Get a ROS clock which will be kept up to date by the node.
RCLCPP_PUBLIC
virtual
rclcpp::Clock::SharedPtr
get_clock() = 0;
/// Get a const ROS clock which will be kept up to date by the node.
RCLCPP_PUBLIC
virtual
rclcpp::Clock::ConstSharedPtr
get_clock() const = 0;
virtual rclcpp::Clock::SharedPtr get_clock() = 0;
};
} // namespace node_interfaces

View File

@@ -30,11 +30,9 @@
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/node_interfaces/node_graph_interface.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rmw/topic_endpoint_info_array.h"
namespace rclcpp
{
namespace graph_listener
{
class GraphListener;
@@ -42,7 +40,6 @@ class GraphListener;
namespace node_interfaces
{
/// Implementation the NodeGraph part of the Node API.
class NodeGraph : public NodeGraphInterface
{
@@ -53,82 +50,45 @@ public:
explicit NodeGraph(rclcpp::node_interfaces::NodeBaseInterface * node_base);
RCLCPP_PUBLIC
virtual
~NodeGraph();
virtual ~NodeGraph();
RCLCPP_PUBLIC
std::map<std::string, std::vector<std::string>>
get_topic_names_and_types(bool no_demangle = false) const override;
virtual std::map<std::string, std::vector<std::string>> get_topic_names_and_types(
bool no_demangle = false) const;
RCLCPP_PUBLIC
std::map<std::string, std::vector<std::string>>
get_service_names_and_types() const override;
virtual std::map<std::string, std::vector<std::string>> get_service_names_and_types() const;
RCLCPP_PUBLIC
std::vector<std::string>
get_node_names() const override;
virtual std::vector<std::string> get_node_names() const;
RCLCPP_PUBLIC
std::vector<std::pair<std::string, std::string>>
get_node_names_and_namespaces() const override;
virtual std::vector<std::pair<std::string, std::string>> get_node_names_and_namespaces() const;
RCLCPP_PUBLIC
size_t
count_publishers(const std::string & topic_name) const override;
virtual size_t count_publishers(const std::string & topic_name) const;
RCLCPP_PUBLIC
size_t
count_subscribers(const std::string & topic_name) const override;
virtual size_t count_subscribers(const std::string & topic_name) const;
RCLCPP_PUBLIC
const rcl_guard_condition_t *
get_graph_guard_condition() const override;
virtual const rcl_guard_condition_t * get_graph_guard_condition() const;
RCLCPP_PUBLIC
void
notify_graph_change() override;
virtual void notify_graph_change();
RCLCPP_PUBLIC
void
notify_shutdown() override;
virtual void notify_shutdown();
RCLCPP_PUBLIC
rclcpp::Event::SharedPtr
get_graph_event() override;
virtual rclcpp::Event::SharedPtr get_graph_event();
RCLCPP_PUBLIC
void
wait_for_graph_change(
rclcpp::Event::SharedPtr event,
std::chrono::nanoseconds timeout) override;
virtual void wait_for_graph_change(
rclcpp::Event::SharedPtr event, std::chrono::nanoseconds timeout);
RCLCPP_PUBLIC
size_t
count_graph_users() override;
RCLCPP_PUBLIC
std::vector<rclcpp::TopicEndpointInfo>
get_publishers_info_by_topic(
const std::string & topic_name,
bool no_mangle = false) const override;
RCLCPP_PUBLIC
std::vector<rclcpp::TopicEndpointInfo>
get_subscriptions_info_by_topic(
const std::string & topic_name,
bool no_mangle = false) const override;
virtual size_t count_graph_users();
private:
RCLCPP_DISABLE_COPY(NodeGraph)

View File

@@ -15,123 +15,22 @@
#ifndef RCLCPP__NODE_INTERFACES__NODE_GRAPH_INTERFACE_HPP_
#define RCLCPP__NODE_INTERFACES__NODE_GRAPH_INTERFACE_HPP_
#include <algorithm>
#include <array>
#include <chrono>
#include <map>
#include <string>
#include <utility>
#include <vector>
#include "rcl/graph.h"
#include "rcl/guard_condition.h"
#include "rclcpp/event.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
enum class EndpointType
{
Invalid = RMW_ENDPOINT_INVALID,
Publisher = RMW_ENDPOINT_PUBLISHER,
Subscription = RMW_ENDPOINT_SUBSCRIPTION
};
/**
* Struct that contains topic endpoint information like the associated node name, node namespace,
* topic type, endpoint type, endpoint GID, and its QoS.
*/
class TopicEndpointInfo
{
public:
/// Construct a TopicEndpointInfo from a rcl_topic_endpoint_info_t.
RCLCPP_PUBLIC
explicit TopicEndpointInfo(const rcl_topic_endpoint_info_t & info)
: node_name_(info.node_name),
node_namespace_(info.node_namespace),
topic_type_(info.topic_type),
endpoint_type_(static_cast<rclcpp::EndpointType>(info.endpoint_type)),
qos_profile_({info.qos_profile.history, info.qos_profile.depth}, info.qos_profile)
{
std::copy(info.endpoint_gid, info.endpoint_gid + RMW_GID_STORAGE_SIZE, endpoint_gid_.begin());
}
/// Get a mutable reference to the node name.
RCLCPP_PUBLIC
std::string &
node_name();
/// Get a const reference to the node name.
RCLCPP_PUBLIC
const std::string &
node_name() const;
/// Get a mutable reference to the node namespace.
RCLCPP_PUBLIC
std::string &
node_namespace();
/// Get a const reference to the node namespace.
RCLCPP_PUBLIC
const std::string &
node_namespace() const;
/// Get a mutable reference to the topic type string.
RCLCPP_PUBLIC
std::string &
topic_type();
/// Get a const reference to the topic type string.
RCLCPP_PUBLIC
const std::string &
topic_type() const;
/// Get a mutable reference to the topic endpoint type.
RCLCPP_PUBLIC
rclcpp::EndpointType &
endpoint_type();
/// Get a const reference to the topic endpoint type.
RCLCPP_PUBLIC
const rclcpp::EndpointType &
endpoint_type() const;
/// Get a mutable reference to the GID of the topic endpoint.
RCLCPP_PUBLIC
std::array<uint8_t, RMW_GID_STORAGE_SIZE> &
endpoint_gid();
/// Get a const reference to the GID of the topic endpoint.
RCLCPP_PUBLIC
const std::array<uint8_t, RMW_GID_STORAGE_SIZE> &
endpoint_gid() const;
/// Get a mutable reference to the QoS profile of the topic endpoint.
RCLCPP_PUBLIC
rclcpp::QoS &
qos_profile();
/// Get a const reference to the QoS profile of the topic endpoint.
RCLCPP_PUBLIC
const rclcpp::QoS &
qos_profile() const;
private:
std::string node_name_;
std::string node_namespace_;
std::string topic_type_;
rclcpp::EndpointType endpoint_type_;
std::array<uint8_t, RMW_GID_STORAGE_SIZE> endpoint_gid_;
rclcpp::QoS qos_profile_;
};
namespace node_interfaces
{
/// Pure virtual interface class for the NodeGraph part of the Node API.
class NodeGraphInterface
{
@@ -139,8 +38,7 @@ public:
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeGraphInterface)
RCLCPP_PUBLIC
virtual
~NodeGraphInterface() = default;
virtual ~NodeGraphInterface() = default;
/// Return a map of existing topic names to list of topic types.
/**
@@ -150,9 +48,8 @@ public:
* \param[in] no_demangle if true, topic names and types are not demangled
*/
RCLCPP_PUBLIC
virtual
std::map<std::string, std::vector<std::string>>
get_topic_names_and_types(bool no_demangle = false) const = 0;
virtual std::map<std::string, std::vector<std::string>> get_topic_names_and_types(
bool no_demangle = false) const = 0;
/// Return a map of existing service names to list of service types.
/**
@@ -161,39 +58,28 @@ public:
* process.
*/
RCLCPP_PUBLIC
virtual
std::map<std::string, std::vector<std::string>>
get_service_names_and_types() const = 0;
virtual std::map<std::string, std::vector<std::string>> get_service_names_and_types() const = 0;
/// Return a vector of existing node names (string).
RCLCPP_PUBLIC
virtual
std::vector<std::string>
get_node_names() const = 0;
virtual std::vector<std::string> get_node_names() const = 0;
/// Return a vector of existing node names and namespaces (pair of string).
RCLCPP_PUBLIC
virtual
std::vector<std::pair<std::string, std::string>>
get_node_names_and_namespaces() const = 0;
virtual std::vector<std::pair<std::string, std::string>> get_node_names_and_namespaces()
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;
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;
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;
virtual const rcl_guard_condition_t * get_graph_guard_condition() const = 0;
/// Notify threads waiting on graph changes.
/**
@@ -206,15 +92,11 @@ public:
* \throws RCLBaseError (a child of that exception) when an rcl error occurs
*/
RCLCPP_PUBLIC
virtual
void
notify_graph_change() = 0;
virtual void notify_graph_change() = 0;
/// Notify any and all blocking node actions that shutdown has occurred.
RCLCPP_PUBLIC
virtual
void
notify_shutdown() = 0;
virtual void notify_shutdown() = 0;
/// Return a graph event, which will be set anytime a graph change occurs.
/**
@@ -223,9 +105,7 @@ public:
* out of scope.
*/
RCLCPP_PUBLIC
virtual
rclcpp::Event::SharedPtr
get_graph_event() = 0;
virtual rclcpp::Event::SharedPtr get_graph_event() = 0;
/// Wait for a graph event to occur by waiting on an Event to become set.
/**
@@ -236,38 +116,15 @@ public:
* get_graph_event().
*/
RCLCPP_PUBLIC
virtual
void
wait_for_graph_change(
rclcpp::Event::SharedPtr event,
std::chrono::nanoseconds timeout) = 0;
virtual void wait_for_graph_change(
rclcpp::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;
/// Return the topic endpoint information about publishers on a given topic.
/**
* \sa rclcpp::Node::get_publishers_info_by_topic
*/
RCLCPP_PUBLIC
virtual
std::vector<rclcpp::TopicEndpointInfo>
get_publishers_info_by_topic(const std::string & topic_name, bool no_mangle = false) const = 0;
/// Return the topic endpoint information about subscriptions on a given topic.
/**
* \sa rclcpp::Node::get_subscriptions_info_by_topic
*/
RCLCPP_PUBLIC
virtual
std::vector<rclcpp::TopicEndpointInfo>
get_subscriptions_info_by_topic(const std::string & topic_name, bool no_mangle = false) const = 0;
virtual size_t count_graph_users() = 0;
};
} // namespace node_interfaces

View File

@@ -27,7 +27,6 @@ namespace rclcpp
{
namespace node_interfaces
{
/// Implementation of the NodeLogging part of the Node API.
class NodeLogging : public NodeLoggingInterface
{
@@ -38,18 +37,13 @@ public:
explicit NodeLogging(rclcpp::node_interfaces::NodeBaseInterface * node_base);
RCLCPP_PUBLIC
virtual
~NodeLogging();
virtual ~NodeLogging();
RCLCPP_PUBLIC
rclcpp::Logger
get_logger() const override;
virtual rclcpp::Logger get_logger() const;
RCLCPP_PUBLIC
const char *
get_logger_name() const override;
virtual const char * get_logger_name() const;
private:
RCLCPP_DISABLE_COPY(NodeLogging)

View File

@@ -19,13 +19,13 @@
#include "rclcpp/logger.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
namespace node_interfaces
{
/// Pure virtual interface class for the NodeLogging part of the Node API.
class NodeLoggingInterface
{
@@ -33,22 +33,17 @@ public:
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeLoggingInterface)
RCLCPP_PUBLIC
virtual
~NodeLoggingInterface() = default;
virtual ~NodeLoggingInterface() = default;
/// Return the logger of the node.
/** \return The logger of the node. */
RCLCPP_PUBLIC
virtual
rclcpp::Logger
get_logger() const = 0;
virtual rclcpp::Logger get_logger() const = 0;
/// Return the logger name associated with the node.
/** \return The logger name associated with the node. */
RCLCPP_PUBLIC
virtual
const char *
get_logger_name() const = 0;
virtual const char * get_logger_name() const = 0;
};
} // namespace node_interfaces

View File

@@ -15,9 +15,9 @@
#ifndef RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_HPP_
#define RCLCPP__NODE_INTERFACES__NODE_PARAMETERS_HPP_
#include <list>
#include <map>
#include <memory>
#include <list>
#include <string>
#include <vector>
@@ -28,7 +28,6 @@
#include "rclcpp/macros.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/node_interfaces/node_logging_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"
@@ -41,7 +40,6 @@ namespace rclcpp
{
namespace node_interfaces
{
// Internal struct for holding useful info about parameters
struct ParameterInfo
{
@@ -56,21 +54,17 @@ struct ParameterInfo
class ParameterMutationRecursionGuard
{
public:
explicit ParameterMutationRecursionGuard(bool & allow_mod)
: allow_modification_(allow_mod)
explicit ParameterMutationRecursionGuard(bool & allow_mod) : allow_modification_(allow_mod)
{
if (!allow_modification_) {
throw rclcpp::exceptions::ParameterModifiedInCallbackException(
"cannot set or declare a parameter, or change the callback from within set callback");
"cannot set or declare a parameter, or change the callback from within set callback");
}
allow_modification_ = false;
}
~ParameterMutationRecursionGuard()
{
allow_modification_ = true;
}
~ParameterMutationRecursionGuard() { allow_modification_ = true; }
private:
bool & allow_modification_;
@@ -98,82 +92,72 @@ public:
bool automatically_declare_parameters_from_overrides);
RCLCPP_PUBLIC
virtual
~NodeParameters();
virtual ~NodeParameters();
RCLCPP_PUBLIC
const rclcpp::ParameterValue &
declare_parameter(
const rclcpp::ParameterValue & declare_parameter(
const std::string & name,
const rclcpp::ParameterValue & default_value,
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor,
bool ignore_override) override;
RCLCPP_PUBLIC
void
undeclare_parameter(const std::string & name) override;
void undeclare_parameter(const std::string & name) override;
RCLCPP_PUBLIC
bool
has_parameter(const std::string & name) const override;
bool has_parameter(const std::string & name) const override;
RCLCPP_PUBLIC
std::vector<rcl_interfaces::msg::SetParametersResult>
set_parameters(
std::vector<rcl_interfaces::msg::SetParametersResult> set_parameters(
const std::vector<rclcpp::Parameter> & parameters) override;
RCLCPP_PUBLIC
rcl_interfaces::msg::SetParametersResult
set_parameters_atomically(
rcl_interfaces::msg::SetParametersResult set_parameters_atomically(
const std::vector<rclcpp::Parameter> & parameters) override;
RCLCPP_PUBLIC
std::vector<rclcpp::Parameter>
get_parameters(const std::vector<std::string> & names) const override;
std::vector<rclcpp::Parameter> get_parameters(
const std::vector<std::string> & names) const override;
RCLCPP_PUBLIC
rclcpp::Parameter
get_parameter(const std::string & name) const override;
rclcpp::Parameter get_parameter(const std::string & name) const override;
RCLCPP_PUBLIC
bool
get_parameter(
const std::string & name,
rclcpp::Parameter & parameter) const override;
bool get_parameter(const std::string & name, rclcpp::Parameter & parameter) const override;
RCLCPP_PUBLIC
bool
get_parameters_by_prefix(
bool get_parameters_by_prefix(
const std::string & prefix,
std::map<std::string, rclcpp::Parameter> & parameters) const override;
RCLCPP_PUBLIC
std::vector<rcl_interfaces::msg::ParameterDescriptor>
describe_parameters(const std::vector<std::string> & names) const override;
std::vector<rcl_interfaces::msg::ParameterDescriptor> describe_parameters(
const std::vector<std::string> & names) const override;
RCLCPP_PUBLIC
std::vector<uint8_t>
get_parameter_types(const std::vector<std::string> & names) const override;
std::vector<uint8_t> get_parameter_types(const std::vector<std::string> & names) const override;
RCLCPP_PUBLIC
rcl_interfaces::msg::ListParametersResult
list_parameters(const std::vector<std::string> & prefixes, uint64_t depth) const override;
rcl_interfaces::msg::ListParametersResult list_parameters(
const std::vector<std::string> & prefixes, uint64_t depth) const override;
RCLCPP_PUBLIC
OnSetParametersCallbackHandle::SharedPtr
add_on_set_parameters_callback(OnParametersSetCallbackType callback) override;
OnSetParametersCallbackHandle::SharedPtr add_on_set_parameters_callback(
OnParametersSetCallbackType callback) override;
RCLCPP_PUBLIC
void
remove_on_set_parameters_callback(const OnSetParametersCallbackHandle * const handler) override;
void remove_on_set_parameters_callback(
const OnSetParametersCallbackHandle * const handler) override;
RCLCPP_PUBLIC
OnParametersSetCallbackType
set_on_parameters_set_callback(OnParametersSetCallbackType callback) override;
OnParametersSetCallbackType set_on_parameters_set_callback(
OnParametersSetCallbackType callback) override;
[[deprecated("use set_on_parameters_set_callback() instead")]] RCLCPP_PUBLIC void
register_param_change_callback(OnParametersSetCallbackType callback) override;
RCLCPP_PUBLIC
const std::map<std::string, rclcpp::ParameterValue> &
get_parameter_overrides() const override;
const std::map<std::string, rclcpp::ParameterValue> & get_parameter_overrides() const override;
using CallbacksContainerType = std::list<OnSetParametersCallbackHandle::WeakPtr>;

View File

@@ -32,15 +32,12 @@ namespace rclcpp
{
namespace node_interfaces
{
struct OnSetParametersCallbackHandle
{
RCLCPP_SMART_PTR_DEFINITIONS(OnSetParametersCallbackHandle)
using OnParametersSetCallbackType =
std::function<
rcl_interfaces::msg::SetParametersResult(
const std::vector<rclcpp::Parameter> &)>;
std::function<rcl_interfaces::msg::SetParametersResult(const std::vector<rclcpp::Parameter> &)>;
OnParametersSetCallbackType callback;
};
@@ -52,21 +49,18 @@ public:
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeParametersInterface)
RCLCPP_PUBLIC
virtual
~NodeParametersInterface() = default;
virtual ~NodeParametersInterface() = default;
/// Declare and initialize a parameter.
/**
* \sa rclcpp::Node::declare_parameter
*/
RCLCPP_PUBLIC
virtual
const rclcpp::ParameterValue &
declare_parameter(
virtual const rclcpp::ParameterValue & declare_parameter(
const std::string & name,
const rclcpp::ParameterValue & default_value = rclcpp::ParameterValue(),
const rcl_interfaces::msg::ParameterDescriptor & parameter_descriptor =
rcl_interfaces::msg::ParameterDescriptor(),
rcl_interfaces::msg::ParameterDescriptor(),
bool ignore_override = false) = 0;
/// Undeclare a parameter.
@@ -74,36 +68,29 @@ public:
* \sa rclcpp::Node::undeclare_parameter
*/
RCLCPP_PUBLIC
virtual
void
undeclare_parameter(const std::string & name) = 0;
virtual void undeclare_parameter(const std::string & name) = 0;
/// Return true if the parameter has been declared, otherwise false.
/**
* \sa rclcpp::Node::has_parameter
*/
RCLCPP_PUBLIC
virtual
bool
has_parameter(const std::string & name) const = 0;
virtual bool has_parameter(const std::string & name) const = 0;
/// Set one or more parameters, one at a time.
/**
* \sa rclcpp::Node::set_parameters
*/
RCLCPP_PUBLIC
virtual
std::vector<rcl_interfaces::msg::SetParametersResult>
set_parameters(const std::vector<rclcpp::Parameter> & parameters) = 0;
virtual std::vector<rcl_interfaces::msg::SetParametersResult> set_parameters(
const std::vector<rclcpp::Parameter> & parameters) = 0;
/// Set and initialize a parameter, all at once.
/**
* \sa rclcpp::Node::set_parameters_atomically
*/
RCLCPP_PUBLIC
virtual
rcl_interfaces::msg::SetParametersResult
set_parameters_atomically(
virtual rcl_interfaces::msg::SetParametersResult set_parameters_atomically(
const std::vector<rclcpp::Parameter> & parameters) = 0;
/// Get descriptions of parameters given their names.
@@ -113,9 +100,8 @@ public:
* Any parameter not found is omitted from the returned list.
*/
RCLCPP_PUBLIC
virtual
std::vector<rclcpp::Parameter>
get_parameters(const std::vector<std::string> & names) const = 0;
virtual std::vector<rclcpp::Parameter> get_parameters(
const std::vector<std::string> & names) const = 0;
/// Get the description of one parameter given a name.
/*
@@ -124,9 +110,7 @@ public:
* \throws std::out_of_range if the parameter does not exist on the node.
*/
RCLCPP_PUBLIC
virtual
rclcpp::Parameter
get_parameter(const std::string & name) const = 0;
virtual rclcpp::Parameter get_parameter(const std::string & name) const = 0;
/// Get the description of one parameter given a name.
/*
@@ -136,11 +120,7 @@ public:
* \return false if the parameter does not exist.
*/
RCLCPP_PUBLIC
virtual
bool
get_parameter(
const std::string & name,
rclcpp::Parameter & parameter) const = 0;
virtual bool get_parameter(const std::string & name, rclcpp::Parameter & parameter) const = 0;
/// Get all parameters that have the specified prefix into the parameters map.
/*
@@ -150,61 +130,56 @@ public:
* \return false otherwise.
*/
RCLCPP_PUBLIC
virtual
bool
get_parameters_by_prefix(
const std::string & prefix,
std::map<std::string, rclcpp::Parameter> & parameters) const = 0;
virtual bool get_parameters_by_prefix(
const std::string & prefix, std::map<std::string, rclcpp::Parameter> & parameters) const = 0;
RCLCPP_PUBLIC
virtual
std::vector<rcl_interfaces::msg::ParameterDescriptor>
describe_parameters(const std::vector<std::string> & names) const = 0;
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;
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;
virtual rcl_interfaces::msg::ListParametersResult list_parameters(
const std::vector<std::string> & prefixes, uint64_t depth) const = 0;
using OnParametersSetCallbackType = OnSetParametersCallbackHandle::OnParametersSetCallbackType;
using ParametersCallbackFunction[[deprecated("use OnParametersSetCallbackType instead")]] =
OnParametersSetCallbackType;
/// Add a callback for when parameters are being set.
/**
* \sa rclcpp::Node::add_on_set_parameters_callback
*/
RCLCPP_PUBLIC
virtual
OnSetParametersCallbackHandle::SharedPtr
add_on_set_parameters_callback(OnParametersSetCallbackType callback) = 0;
virtual OnSetParametersCallbackHandle::SharedPtr add_on_set_parameters_callback(
OnParametersSetCallbackType callback) = 0;
/// Remove a callback registered with `add_on_set_parameters_callback`.
/**
* \sa rclcpp::Node::remove_on_set_parameters_callback
*/
RCLCPP_PUBLIC
virtual
void
remove_on_set_parameters_callback(const OnSetParametersCallbackHandle * const handler) = 0;
virtual void remove_on_set_parameters_callback(
const OnSetParametersCallbackHandle * const handler) = 0;
/// Register a callback for when parameters are being set, return an existing one.
/**
* \sa rclcpp::Node::set_on_parameters_set_callback
*/
RCLCPP_PUBLIC
virtual
OnParametersSetCallbackType
set_on_parameters_set_callback(OnParametersSetCallbackType callback) = 0;
virtual OnParametersSetCallbackType set_on_parameters_set_callback(
OnParametersSetCallbackType callback) = 0;
[[deprecated("use set_on_parameters_set_callback() instead")]] RCLCPP_PUBLIC virtual void
register_param_change_callback(OnParametersSetCallbackType callback) = 0;
/// Return the initial parameter values used by the NodeParameters to override default values.
RCLCPP_PUBLIC
virtual
const std::map<std::string, rclcpp::ParameterValue> &
get_parameter_overrides() const = 0;
virtual const std::map<std::string, rclcpp::ParameterValue> & get_parameter_overrides() const = 0;
};
} // namespace node_interfaces

View File

@@ -27,7 +27,6 @@ namespace rclcpp
{
namespace node_interfaces
{
/// Implementation of the NodeServices part of the Node API.
class NodeServices : public NodeServicesInterface
{
@@ -38,22 +37,17 @@ public:
explicit NodeServices(rclcpp::node_interfaces::NodeBaseInterface * node_base);
RCLCPP_PUBLIC
virtual
~NodeServices();
virtual ~NodeServices();
RCLCPP_PUBLIC
void
add_client(
virtual void add_client(
rclcpp::ClientBase::SharedPtr client_base_ptr,
rclcpp::CallbackGroup::SharedPtr group) override;
rclcpp::callback_group::CallbackGroup::SharedPtr group);
RCLCPP_PUBLIC
void
add_service(
virtual void add_service(
rclcpp::ServiceBase::SharedPtr service_base_ptr,
rclcpp::CallbackGroup::SharedPtr group) override;
rclcpp::callback_group::CallbackGroup::SharedPtr group);
private:
RCLCPP_DISABLE_COPY(NodeServices)

View File

@@ -25,7 +25,6 @@ namespace rclcpp
{
namespace node_interfaces
{
/// Pure virtual interface class for the NodeServices part of the Node API.
class NodeServicesInterface
{
@@ -33,22 +32,17 @@ public:
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeServicesInterface)
RCLCPP_PUBLIC
virtual
~NodeServicesInterface() = default;
virtual ~NodeServicesInterface() = default;
RCLCPP_PUBLIC
virtual
void
add_client(
virtual void add_client(
rclcpp::ClientBase::SharedPtr client_base_ptr,
rclcpp::CallbackGroup::SharedPtr group) = 0;
rclcpp::callback_group::CallbackGroup::SharedPtr group) = 0;
RCLCPP_PUBLIC
virtual
void
add_service(
virtual void add_service(
rclcpp::ServiceBase::SharedPtr service_base_ptr,
rclcpp::CallbackGroup::SharedPtr group) = 0;
rclcpp::callback_group::CallbackGroup::SharedPtr group) = 0;
};
} // namespace node_interfaces

View File

@@ -15,13 +15,12 @@
#ifndef RCLCPP__NODE_INTERFACES__NODE_TIME_SOURCE_HPP_
#define RCLCPP__NODE_INTERFACES__NODE_TIME_SOURCE_HPP_
#include "rclcpp/callback_group.hpp"
#include "rclcpp/clock.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/node_interfaces/node_clock_interface.hpp"
#include "rclcpp/node_interfaces/node_graph_interface.hpp"
#include "rclcpp/node_interfaces/node_logging_interface.hpp"
#include "rclcpp/node_interfaces/node_parameters_interface.hpp"
#include "rclcpp/node_interfaces/node_services_interface.hpp"
#include "rclcpp/node_interfaces/node_time_source_interface.hpp"
#include "rclcpp/node_interfaces/node_topics_interface.hpp"
#include "rclcpp/time_source.hpp"
@@ -31,7 +30,6 @@ namespace rclcpp
{
namespace node_interfaces
{
/// Implementation of the NodeTimeSource part of the Node API.
class NodeTimeSource : public NodeTimeSourceInterface
{
@@ -46,12 +44,10 @@ public:
rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services,
rclcpp::node_interfaces::NodeLoggingInterface::SharedPtr node_logging,
rclcpp::node_interfaces::NodeClockInterface::SharedPtr node_clock,
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr node_parameters
);
rclcpp::node_interfaces::NodeParametersInterface::SharedPtr node_parameters);
RCLCPP_PUBLIC
virtual
~NodeTimeSource();
virtual ~NodeTimeSource();
private:
RCLCPP_DISABLE_COPY(NodeTimeSource)

View File

@@ -15,6 +15,8 @@
#ifndef RCLCPP__NODE_INTERFACES__NODE_TIME_SOURCE_INTERFACE_HPP_
#define RCLCPP__NODE_INTERFACES__NODE_TIME_SOURCE_INTERFACE_HPP_
#include "rclcpp/callback_group.hpp"
#include "rclcpp/clock.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/visibility_control.hpp"
@@ -22,7 +24,6 @@ namespace rclcpp
{
namespace node_interfaces
{
/// Pure virtual interface class for the NodeTimeSource part of the Node API.
class NodeTimeSourceInterface
{
@@ -30,8 +31,7 @@ public:
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeTimeSourceInterface)
RCLCPP_PUBLIC
virtual
~NodeTimeSourceInterface() = default;
virtual ~NodeTimeSourceInterface() = default;
};
} // namespace node_interfaces

View File

@@ -26,7 +26,6 @@ namespace rclcpp
{
namespace node_interfaces
{
/// Implementation of the NodeTimers part of the Node API.
class NodeTimers : public NodeTimersInterface
{
@@ -37,16 +36,13 @@ public:
explicit NodeTimers(rclcpp::node_interfaces::NodeBaseInterface * node_base);
RCLCPP_PUBLIC
virtual
~NodeTimers();
virtual ~NodeTimers();
/// Add a timer to the node.
RCLCPP_PUBLIC
void
add_timer(
virtual void add_timer(
rclcpp::TimerBase::SharedPtr timer,
rclcpp::CallbackGroup::SharedPtr callback_group) override;
rclcpp::callback_group::CallbackGroup::SharedPtr callback_group);
private:
RCLCPP_DISABLE_COPY(NodeTimers)

View File

@@ -24,7 +24,6 @@ namespace rclcpp
{
namespace node_interfaces
{
/// Pure virtual interface class for the NodeTimers part of the Node API.
class NodeTimersInterface
{
@@ -32,16 +31,13 @@ public:
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeTimersInterface)
RCLCPP_PUBLIC
virtual
~NodeTimersInterface() = default;
virtual ~NodeTimersInterface() = default;
/// Add a timer to the node.
RCLCPP_PUBLIC
virtual
void
add_timer(
virtual void add_timer(
rclcpp::TimerBase::SharedPtr timer,
rclcpp::CallbackGroup::SharedPtr callback_group) = 0;
rclcpp::callback_group::CallbackGroup::SharedPtr callback_group) = 0;
};
} // namespace node_interfaces

View File

@@ -31,7 +31,6 @@ namespace rclcpp
{
namespace node_interfaces
{
/// Implementation of the NodeTopics part of the Node API.
class NodeTopics : public NodeTopicsInterface
{
@@ -45,34 +44,31 @@ public:
~NodeTopics() override;
RCLCPP_PUBLIC
rclcpp::PublisherBase::SharedPtr
create_publisher(
rclcpp::PublisherBase::SharedPtr create_publisher(
const std::string & topic_name,
const rclcpp::PublisherFactory & publisher_factory,
const rclcpp::QoS & qos) override;
const rcl_publisher_options_t & publisher_options,
bool use_intra_process) override;
RCLCPP_PUBLIC
void
add_publisher(
void add_publisher(
rclcpp::PublisherBase::SharedPtr publisher,
rclcpp::CallbackGroup::SharedPtr callback_group) override;
rclcpp::callback_group::CallbackGroup::SharedPtr callback_group) override;
RCLCPP_PUBLIC
rclcpp::SubscriptionBase::SharedPtr
create_subscription(
rclcpp::SubscriptionBase::SharedPtr create_subscription(
const std::string & topic_name,
const rclcpp::SubscriptionFactory & subscription_factory,
const rclcpp::QoS & qos) override;
const rcl_subscription_options_t & subscription_options,
bool use_intra_process) override;
RCLCPP_PUBLIC
void
add_subscription(
void add_subscription(
rclcpp::SubscriptionBase::SharedPtr subscription,
rclcpp::CallbackGroup::SharedPtr callback_group) override;
rclcpp::callback_group::CallbackGroup::SharedPtr callback_group) override;
RCLCPP_PUBLIC
rclcpp::node_interfaces::NodeBaseInterface *
get_node_base_interface() const override;
rclcpp::node_interfaces::NodeBaseInterface * get_node_base_interface() const override;
private:
RCLCPP_DISABLE_COPY(NodeTopics)

View File

@@ -22,9 +22,7 @@
#include "rcl/publisher.h"
#include "rcl/subscription.h"
#include "rclcpp/callback_group.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/publisher.hpp"
#include "rclcpp/publisher_factory.hpp"
#include "rclcpp/subscription.hpp"
@@ -35,7 +33,6 @@ namespace rclcpp
{
namespace node_interfaces
{
/// Pure virtual interface class for the NodeTopics part of the Node API.
class NodeTopicsInterface
{
@@ -43,43 +40,34 @@ public:
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeTopicsInterface)
RCLCPP_PUBLIC
virtual
~NodeTopicsInterface() = default;
virtual ~NodeTopicsInterface() = default;
RCLCPP_PUBLIC
virtual
rclcpp::PublisherBase::SharedPtr
create_publisher(
virtual rclcpp::PublisherBase::SharedPtr create_publisher(
const std::string & topic_name,
const rclcpp::PublisherFactory & publisher_factory,
const rclcpp::QoS & qos) = 0;
const rcl_publisher_options_t & publisher_options,
bool use_intra_process) = 0;
RCLCPP_PUBLIC
virtual
void
add_publisher(
virtual void add_publisher(
rclcpp::PublisherBase::SharedPtr publisher,
rclcpp::CallbackGroup::SharedPtr callback_group) = 0;
rclcpp::callback_group::CallbackGroup::SharedPtr callback_group) = 0;
RCLCPP_PUBLIC
virtual
rclcpp::SubscriptionBase::SharedPtr
create_subscription(
virtual rclcpp::SubscriptionBase::SharedPtr create_subscription(
const std::string & topic_name,
const rclcpp::SubscriptionFactory & subscription_factory,
const rclcpp::QoS & qos) = 0;
const rcl_subscription_options_t & subscription_options,
bool use_intra_process) = 0;
RCLCPP_PUBLIC
virtual
void
add_subscription(
virtual void add_subscription(
rclcpp::SubscriptionBase::SharedPtr subscription,
rclcpp::CallbackGroup::SharedPtr callback_group) = 0;
rclcpp::callback_group::CallbackGroup::SharedPtr callback_group) = 0;
RCLCPP_PUBLIC
virtual
rclcpp::node_interfaces::NodeBaseInterface *
get_node_base_interface() const = 0;
virtual rclcpp::node_interfaces::NodeBaseInterface * get_node_base_interface() const = 0;
};
} // namespace node_interfaces

View File

@@ -16,17 +16,17 @@
#define RCLCPP__NODE_INTERFACES__NODE_WAITABLES_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_waitables_interface.hpp"
#include "rclcpp/waitable.hpp"
#include "rclcpp/visibility_control.hpp"
#include "rclcpp/waitable.hpp"
namespace rclcpp
{
namespace node_interfaces
{
/// Implementation of the NodeWaitables part of the Node API.
class NodeWaitables : public NodeWaitablesInterface
{
@@ -37,22 +37,17 @@ public:
explicit NodeWaitables(rclcpp::node_interfaces::NodeBaseInterface * node_base);
RCLCPP_PUBLIC
virtual
~NodeWaitables();
virtual ~NodeWaitables();
RCLCPP_PUBLIC
void
add_waitable(
virtual void add_waitable(
rclcpp::Waitable::SharedPtr waitable_base_ptr,
rclcpp::CallbackGroup::SharedPtr group) override;
rclcpp::callback_group::CallbackGroup::SharedPtr group);
RCLCPP_PUBLIC
void
remove_waitable(
virtual void remove_waitable(
rclcpp::Waitable::SharedPtr waitable_ptr,
rclcpp::CallbackGroup::SharedPtr group) noexcept override;
rclcpp::callback_group::CallbackGroup::SharedPtr group) noexcept;
private:
RCLCPP_DISABLE_COPY(NodeWaitables)

View File

@@ -24,7 +24,6 @@ namespace rclcpp
{
namespace node_interfaces
{
/// Pure virtual interface class for the NodeWaitables part of the Node API.
class NodeWaitablesInterface
{
@@ -32,23 +31,18 @@ public:
RCLCPP_SMART_PTR_ALIASES_ONLY(NodeWaitablesInterface)
RCLCPP_PUBLIC
virtual
~NodeWaitablesInterface() = default;
virtual ~NodeWaitablesInterface() = default;
RCLCPP_PUBLIC
virtual
void
add_waitable(
virtual void add_waitable(
rclcpp::Waitable::SharedPtr waitable_ptr,
rclcpp::CallbackGroup::SharedPtr group) = 0;
rclcpp::callback_group::CallbackGroup::SharedPtr group) = 0;
/// \note this function should not throw because it may be called in destructors
RCLCPP_PUBLIC
virtual
void
remove_waitable(
virtual void remove_waitable(
rclcpp::Waitable::SharedPtr waitable_ptr,
rclcpp::CallbackGroup::SharedPtr group) noexcept = 0;
rclcpp::callback_group::CallbackGroup::SharedPtr group) noexcept = 0;
};
} // namespace node_interfaces

View File

@@ -29,7 +29,6 @@
namespace rclcpp
{
/// Encapsulation of options for node initialization.
class NodeOptions
{
@@ -38,12 +37,11 @@ public:
/**
* Default values for the node options:
*
* - context = rclcpp::contexts::get_global_default_context()
* - context = rclcpp::contexts::default_context::get_global_default_context()
* - arguments = {}
* - parameter_overrides = {}
* - use_global_arguments = true
* - use_intra_process_comms = false
* - enable_topic_statistics = false
* - start_parameter_services = true
* - start_parameter_event_publisher = true
* - parameter_event_qos = rclcpp::ParameterEventQoS
@@ -60,8 +58,7 @@ public:
/// Destructor.
RCLCPP_PUBLIC
virtual
~NodeOptions() = default;
virtual ~NodeOptions() = default;
/// Copy constructor.
RCLCPP_PUBLIC
@@ -69,8 +66,7 @@ public:
/// Assignment operator.
RCLCPP_PUBLIC
NodeOptions &
operator=(const NodeOptions & other);
NodeOptions & operator=(const NodeOptions & other);
/// Return the rcl_node_options used by the node.
/**
@@ -79,23 +75,19 @@ public:
* changed, like arguments, use_global_arguments, or the rcl allocator.
*/
RCLCPP_PUBLIC
const rcl_node_options_t *
get_rcl_node_options() const;
const rcl_node_options_t * get_rcl_node_options() const;
/// Return the context to be used by the node.
RCLCPP_PUBLIC
rclcpp::Context::SharedPtr
context() const;
rclcpp::Context::SharedPtr context() const;
/// Set the context, return this for parameter idiom.
RCLCPP_PUBLIC
NodeOptions &
context(rclcpp::Context::SharedPtr context);
NodeOptions & context(rclcpp::Context::SharedPtr context);
/// Return a reference to the list of arguments for the node.
RCLCPP_PUBLIC
const std::vector<std::string> &
arguments() const;
const std::vector<std::string> & arguments() const;
/// Set the arguments, return this for parameter idiom.
/**
@@ -105,17 +97,14 @@ public:
* This will cause the internal rcl_node_options_t struct to be invalidated.
*/
RCLCPP_PUBLIC
NodeOptions &
arguments(const std::vector<std::string> & arguments);
NodeOptions & arguments(const std::vector<std::string> & arguments);
/// Return a reference to the list of parameter overrides.
RCLCPP_PUBLIC
std::vector<rclcpp::Parameter> &
parameter_overrides();
std::vector<rclcpp::Parameter> & parameter_overrides();
RCLCPP_PUBLIC
const std::vector<rclcpp::Parameter> &
parameter_overrides() const;
const std::vector<rclcpp::Parameter> & parameter_overrides() const;
/// Set the parameters overrides, return this for parameter idiom.
/**
@@ -124,13 +113,11 @@ public:
* values if necessary.
*/
RCLCPP_PUBLIC
NodeOptions &
parameter_overrides(const std::vector<rclcpp::Parameter> & parameter_overrides);
NodeOptions & parameter_overrides(const std::vector<rclcpp::Parameter> & parameter_overrides);
/// Append a single parameter override, parameter idiom style.
template<typename ParameterT>
NodeOptions &
append_parameter_override(const std::string & name, const ParameterT & value)
template <typename ParameterT>
NodeOptions & append_parameter_override(const std::string & name, const ParameterT & value)
{
this->parameter_overrides().emplace_back(name, rclcpp::ParameterValue(value));
return *this;
@@ -138,8 +125,7 @@ public:
/// Return the use_global_arguments flag.
RCLCPP_PUBLIC
bool
use_global_arguments() const;
bool use_global_arguments() const;
/// Set the use_global_arguments flag, return this for parameter idiom.
/**
@@ -150,29 +136,11 @@ public:
* This will cause the internal rcl_node_options_t struct to be invalidated.
*/
RCLCPP_PUBLIC
NodeOptions &
use_global_arguments(bool use_global_arguments);
/// Return the enable_rosout flag.
RCLCPP_PUBLIC
bool
enable_rosout() const;
/// Set the enable_rosout flag, return this for parameter idiom.
/**
* If false this will cause the node not to use rosout logging.
*
* Defaults to true for now, as there are still some cases where it is
* desirable.
*/
RCLCPP_PUBLIC
NodeOptions &
enable_rosout(bool enable_rosout);
NodeOptions & use_global_arguments(bool use_global_arguments);
/// Return the use_intra_process_comms flag.
RCLCPP_PUBLIC
bool
use_intra_process_comms() const;
bool use_intra_process_comms() const;
/// Set the use_intra_process_comms flag, return this for parameter idiom.
/**
@@ -185,30 +153,11 @@ public:
* desirable.
*/
RCLCPP_PUBLIC
NodeOptions &
use_intra_process_comms(bool use_intra_process_comms);
/// Return the enable_topic_statistics flag.
RCLCPP_PUBLIC
bool
enable_topic_statistics() const;
/// Set the enable_topic_statistics flag, return this for parameter idiom.
/**
* If true, topic statistics collection and publication will be enabled
* for all subscriptions.
* This can be used to override the global topic statistics setting.
*
* Defaults to false.
*/
RCLCPP_PUBLIC
NodeOptions &
enable_topic_statistics(bool enable_topic_statistics);
NodeOptions & use_intra_process_comms(bool use_intra_process_comms);
/// Return the start_parameter_services flag.
RCLCPP_PUBLIC
bool
start_parameter_services() const;
bool start_parameter_services() const;
/// Set the start_parameter_services flag, return this for parameter idiom.
/**
@@ -221,13 +170,11 @@ public:
* \sa start_parameter_event_publisher()
*/
RCLCPP_PUBLIC
NodeOptions &
start_parameter_services(bool start_parameter_services);
NodeOptions & start_parameter_services(bool start_parameter_services);
/// Return the start_parameter_event_publisher flag.
RCLCPP_PUBLIC
bool
start_parameter_event_publisher() const;
bool start_parameter_event_publisher() const;
/// Set the start_parameter_event_publisher flag, return this for parameter idiom.
/**
@@ -237,26 +184,22 @@ public:
* separately from the other parameter services.
*/
RCLCPP_PUBLIC
NodeOptions &
start_parameter_event_publisher(bool start_parameter_event_publisher);
NodeOptions & start_parameter_event_publisher(bool start_parameter_event_publisher);
/// Return a reference to the parameter_event_qos QoS.
RCLCPP_PUBLIC
const rclcpp::QoS &
parameter_event_qos() const;
const rclcpp::QoS & parameter_event_qos() const;
/// Set the parameter_event_qos QoS, return this for parameter idiom.
/**
* The QoS settings to be used for the parameter event publisher, if enabled.
*/
RCLCPP_PUBLIC
NodeOptions &
parameter_event_qos(const rclcpp::QoS & parameter_event_qos);
NodeOptions & parameter_event_qos(const rclcpp::QoS & parameter_event_qos);
/// Return a reference to the parameter_event_publisher_options.
RCLCPP_PUBLIC
const rclcpp::PublisherOptionsBase &
parameter_event_publisher_options() const;
const rclcpp::PublisherOptionsBase & parameter_event_publisher_options() const;
/// Set the parameter_event_publisher_options, return this for parameter idiom.
/**
@@ -267,14 +210,12 @@ public:
* NodeOptions to also be templated based on the Allocator type.
*/
RCLCPP_PUBLIC
NodeOptions &
parameter_event_publisher_options(
NodeOptions & parameter_event_publisher_options(
const rclcpp::PublisherOptionsBase & parameter_event_publisher_options);
/// Return the allow_undeclared_parameters flag.
RCLCPP_PUBLIC
bool
allow_undeclared_parameters() const;
bool allow_undeclared_parameters() const;
/// Set the allow_undeclared_parameters, return this for parameter idiom.
/**
@@ -287,13 +228,11 @@ public:
* any parameter overrides.
*/
RCLCPP_PUBLIC
NodeOptions &
allow_undeclared_parameters(bool allow_undeclared_parameters);
NodeOptions & allow_undeclared_parameters(bool allow_undeclared_parameters);
/// Return the automatically_declare_parameters_from_overrides flag.
RCLCPP_PUBLIC
bool
automatically_declare_parameters_from_overrides() const;
bool automatically_declare_parameters_from_overrides() const;
/// Set the automatically_declare_parameters_from_overrides, return this.
/**
@@ -307,27 +246,23 @@ public:
* declared in this way will use the default constructed ParameterDescriptor.
*/
RCLCPP_PUBLIC
NodeOptions &
automatically_declare_parameters_from_overrides(
NodeOptions & automatically_declare_parameters_from_overrides(
bool automatically_declare_parameters_from_overrides);
/// Return the rcl_allocator_t to be used.
RCLCPP_PUBLIC
const rcl_allocator_t &
allocator() const;
const rcl_allocator_t & allocator() const;
/// Set the rcl_allocator_t to be used, may cause deallocation of existing rcl_node_options_t.
/**
* This will cause the internal rcl_node_options_t struct to be invalidated.
*/
RCLCPP_PUBLIC
NodeOptions &
allocator(rcl_allocator_t allocator);
NodeOptions & allocator(rcl_allocator_t allocator);
protected:
/// Retrieve the ROS_DOMAIN_ID environment variable and populate options.
size_t
get_domain_id_from_env() const;
size_t get_domain_id_from_env() const;
private:
// This is mutable to allow for a const accessor which lazily creates the node options instance.
@@ -337,36 +272,31 @@ private:
// IMPORTANT: if any of these default values are changed, please update the
// documentation in this class.
rclcpp::Context::SharedPtr context_ {
rclcpp::contexts::get_global_default_context()};
rclcpp::Context::SharedPtr context_{
rclcpp::contexts::default_context::get_global_default_context()};
std::vector<std::string> arguments_ {};
std::vector<std::string> arguments_{};
std::vector<rclcpp::Parameter> parameter_overrides_ {};
std::vector<rclcpp::Parameter> parameter_overrides_{};
bool use_global_arguments_ {true};
bool use_global_arguments_{true};
bool enable_rosout_ {true};
bool use_intra_process_comms_{false};
bool use_intra_process_comms_ {false};
bool start_parameter_services_{true};
bool enable_topic_statistics_ {false};
bool start_parameter_services_ {true};
bool start_parameter_event_publisher_ {true};
bool start_parameter_event_publisher_{true};
rclcpp::QoS parameter_event_qos_ = rclcpp::ParameterEventsQoS(
rclcpp::QoSInitialization::from_rmw(rmw_qos_profile_parameter_events)
);
rclcpp::QoSInitialization::from_rmw(rmw_qos_profile_parameter_events));
rclcpp::PublisherOptionsBase parameter_event_publisher_options_ = rclcpp::PublisherOptionsBase();
bool allow_undeclared_parameters_ {false};
bool allow_undeclared_parameters_{false};
bool automatically_declare_parameters_from_overrides_ {false};
bool automatically_declare_parameters_from_overrides_{false};
rcl_allocator_t allocator_ {rcl_get_default_allocator()};
rcl_allocator_t allocator_{rcl_get_default_allocator()};
};
} // namespace rclcpp

View File

@@ -22,13 +22,11 @@
#include <vector>
#include "rcl_interfaces/msg/parameter.hpp"
#include "rclcpp/exceptions.hpp"
#include "rclcpp/parameter_value.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
class Parameter;
namespace node_interfaces
@@ -38,13 +36,11 @@ struct ParameterInfo;
namespace detail
{
// This helper function is required because you cannot do specialization on a
// class method, so instead we specialize this template function and call it
// from the unspecialized, but dependent, class method.
template<typename T>
auto
get_value_helper(const rclcpp::Parameter * parameter);
template <typename T>
auto get_value_helper(const rclcpp::Parameter * parameter);
} // namespace detail
@@ -65,105 +61,84 @@ public:
Parameter(const std::string & name, const ParameterValue & value);
/// Construct with given name and given parameter value.
template<typename ValueTypeT>
Parameter(const std::string & name, ValueTypeT value)
: Parameter(name, ParameterValue(value))
{}
template <typename ValueTypeT>
Parameter(const std::string & name, ValueTypeT value) : Parameter(name, ParameterValue(value))
{
}
RCLCPP_PUBLIC
explicit Parameter(const rclcpp::node_interfaces::ParameterInfo & parameter_info);
/// Equal operator.
RCLCPP_PUBLIC
bool
operator==(const Parameter & rhs) const;
bool operator==(const Parameter & rhs) const;
/// Not equal operator.
RCLCPP_PUBLIC
bool
operator!=(const Parameter & rhs) const;
bool operator!=(const Parameter & rhs) const;
RCLCPP_PUBLIC
ParameterType
get_type() const;
ParameterType get_type() const;
RCLCPP_PUBLIC
std::string
get_type_name() const;
std::string get_type_name() const;
RCLCPP_PUBLIC
const std::string &
get_name() const;
const std::string & get_name() const;
RCLCPP_PUBLIC
rcl_interfaces::msg::ParameterValue
get_value_message() const;
rcl_interfaces::msg::ParameterValue get_value_message() const;
/// Get the internal storage for the parameter value.
RCLCPP_PUBLIC
const rclcpp::ParameterValue &
get_parameter_value() const;
const rclcpp::ParameterValue & get_parameter_value() const;
/// Get value of parameter using rclcpp::ParameterType as template argument.
template<ParameterType ParamT>
decltype(auto)
get_value() const
template <ParameterType ParamT>
decltype(auto) get_value() const
{
return value_.get<ParamT>();
}
/// Get value of parameter using c++ types as template argument.
template<typename T>
decltype(auto)
get_value() const;
template <typename T>
decltype(auto) get_value() const;
RCLCPP_PUBLIC
bool
as_bool() const;
bool as_bool() const;
RCLCPP_PUBLIC
int64_t
as_int() const;
int64_t as_int() const;
RCLCPP_PUBLIC
double
as_double() const;
double as_double() const;
RCLCPP_PUBLIC
const std::string &
as_string() const;
const std::string & as_string() const;
RCLCPP_PUBLIC
const std::vector<uint8_t> &
as_byte_array() const;
const std::vector<uint8_t> & as_byte_array() const;
RCLCPP_PUBLIC
const std::vector<bool> &
as_bool_array() const;
const std::vector<bool> & as_bool_array() const;
RCLCPP_PUBLIC
const std::vector<int64_t> &
as_integer_array() const;
const std::vector<int64_t> & as_integer_array() const;
RCLCPP_PUBLIC
const std::vector<double> &
as_double_array() const;
const std::vector<double> & as_double_array() const;
RCLCPP_PUBLIC
const std::vector<std::string> &
as_string_array() const;
const std::vector<std::string> & as_string_array() const;
RCLCPP_PUBLIC
static Parameter
from_parameter_msg(const rcl_interfaces::msg::Parameter & parameter);
static Parameter from_parameter_msg(const rcl_interfaces::msg::Parameter & parameter);
RCLCPP_PUBLIC
rcl_interfaces::msg::Parameter
to_parameter_msg() const;
rcl_interfaces::msg::Parameter to_parameter_msg() const;
RCLCPP_PUBLIC
std::string
value_to_string() const;
std::string value_to_string() const;
private:
std::string name_;
@@ -172,78 +147,58 @@ private:
/// Return a json encoded version of the parameter intended for a dict.
RCLCPP_PUBLIC
std::string
_to_json_dict_entry(const Parameter & param);
std::string _to_json_dict_entry(const Parameter & param);
RCLCPP_PUBLIC
std::ostream &
operator<<(std::ostream & os, const rclcpp::Parameter & pv);
std::ostream & operator<<(std::ostream & os, const rclcpp::Parameter & pv);
RCLCPP_PUBLIC
std::ostream &
operator<<(std::ostream & os, const std::vector<Parameter> & parameters);
std::ostream & operator<<(std::ostream & os, const std::vector<Parameter> & parameters);
namespace detail
{
template<typename T>
auto
get_value_helper(const rclcpp::Parameter * parameter)
template <typename T>
auto get_value_helper(const rclcpp::Parameter * parameter)
{
return parameter->get_parameter_value().get<T>();
}
// Specialization allowing Parameter::get() to return a const ref to the parameter value object.
template<>
inline
auto
get_value_helper<rclcpp::ParameterValue>(const rclcpp::Parameter * parameter)
template <>
inline auto get_value_helper<rclcpp::ParameterValue>(const rclcpp::Parameter * parameter)
{
return parameter->get_parameter_value();
}
// Specialization allowing Parameter::get() to return a const ref to the parameter itself.
template<>
inline
auto
get_value_helper<rclcpp::Parameter>(const rclcpp::Parameter * parameter)
template <>
inline auto get_value_helper<rclcpp::Parameter>(const rclcpp::Parameter * parameter)
{
// Use this lambda to ensure it's a const reference being returned (and not a copy).
auto type_enforcing_lambda =
[&parameter]() -> const rclcpp::Parameter & {
return *parameter;
};
auto type_enforcing_lambda = [&parameter]() -> const rclcpp::Parameter & { return *parameter; };
return type_enforcing_lambda();
}
} // namespace detail
template<typename T>
decltype(auto)
Parameter::get_value() const
template <typename T>
decltype(auto) Parameter::get_value() const
{
try {
// use the helper to specialize for the ParameterValue and Parameter cases.
return detail::get_value_helper<T>(this);
} catch (const ParameterTypeException & ex) {
throw exceptions::InvalidParameterTypeException(this->name_, ex.what());
}
// use the helper to specialize for the ParameterValue and Parameter cases.
return detail::get_value_helper<T>(this);
}
} // namespace rclcpp
namespace std
{
/// Return a json encoded version of the parameter intended for a list.
RCLCPP_PUBLIC
std::string
to_string(const rclcpp::Parameter & param);
std::string to_string(const rclcpp::Parameter & param);
/// Return a json encoded version of a vector of parameters, as a string.
RCLCPP_PUBLIC
std::string
to_string(const std::vector<rclcpp::Parameter> & parameters);
std::string to_string(const std::vector<rclcpp::Parameter> & parameters);
} // namespace std

View File

@@ -29,8 +29,8 @@
#include "rcl_interfaces/srv/list_parameters.hpp"
#include "rcl_interfaces/srv/set_parameters.hpp"
#include "rcl_interfaces/srv/set_parameters_atomically.hpp"
#include "rclcpp/executors.hpp"
#include "rclcpp/create_subscription.hpp"
#include "rclcpp/executors.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/node.hpp"
#include "rclcpp/parameter.hpp"
@@ -40,7 +40,6 @@
namespace rclcpp
{
class AsyncParametersClient
{
public:
@@ -54,81 +53,60 @@ public:
const rclcpp::node_interfaces::NodeServicesInterface::SharedPtr node_services_interface,
const std::string & remote_node_name = "",
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters,
rclcpp::CallbackGroup::SharedPtr group = nullptr);
rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr);
RCLCPP_PUBLIC
AsyncParametersClient(
const rclcpp::Node::SharedPtr node,
const std::string & remote_node_name = "",
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters,
rclcpp::CallbackGroup::SharedPtr group = nullptr);
rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr);
RCLCPP_PUBLIC
AsyncParametersClient(
rclcpp::Node * node,
const std::string & remote_node_name = "",
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters,
rclcpp::CallbackGroup::SharedPtr group = nullptr);
rclcpp::callback_group::CallbackGroup::SharedPtr group = nullptr);
RCLCPP_PUBLIC
std::shared_future<std::vector<rclcpp::Parameter>>
get_parameters(
std::shared_future<std::vector<rclcpp::Parameter>> get_parameters(
const std::vector<std::string> & names,
std::function<
void(std::shared_future<std::vector<rclcpp::Parameter>>)
> callback = nullptr);
std::function<void(std::shared_future<std::vector<rclcpp::Parameter>>)> callback = nullptr);
RCLCPP_PUBLIC
std::shared_future<std::vector<rclcpp::ParameterType>>
get_parameter_types(
std::shared_future<std::vector<rclcpp::ParameterType>> get_parameter_types(
const std::vector<std::string> & names,
std::function<
void(std::shared_future<std::vector<rclcpp::ParameterType>>)
> callback = nullptr);
std::function<void(std::shared_future<std::vector<rclcpp::ParameterType>>)> callback = nullptr);
RCLCPP_PUBLIC
std::shared_future<std::vector<rcl_interfaces::msg::SetParametersResult>>
set_parameters(
std::shared_future<std::vector<rcl_interfaces::msg::SetParametersResult>> set_parameters(
const std::vector<rclcpp::Parameter> & parameters,
std::function<
void(std::shared_future<std::vector<rcl_interfaces::msg::SetParametersResult>>)
> callback = nullptr);
std::function<void(std::shared_future<std::vector<rcl_interfaces::msg::SetParametersResult>>)>
callback = nullptr);
RCLCPP_PUBLIC
std::shared_future<rcl_interfaces::msg::SetParametersResult>
set_parameters_atomically(
std::shared_future<rcl_interfaces::msg::SetParametersResult> set_parameters_atomically(
const std::vector<rclcpp::Parameter> & parameters,
std::function<
void(std::shared_future<rcl_interfaces::msg::SetParametersResult>)
> callback = nullptr);
std::function<void(std::shared_future<rcl_interfaces::msg::SetParametersResult>)> callback =
nullptr);
RCLCPP_PUBLIC
std::shared_future<rcl_interfaces::msg::ListParametersResult>
list_parameters(
std::shared_future<rcl_interfaces::msg::ListParametersResult> list_parameters(
const std::vector<std::string> & prefixes,
uint64_t depth,
std::function<
void(std::shared_future<rcl_interfaces::msg::ListParametersResult>)
> callback = nullptr);
std::function<void(std::shared_future<rcl_interfaces::msg::ListParametersResult>)> callback =
nullptr);
template<
typename CallbackT,
typename AllocatorT = std::allocator<void>>
typename rclcpp::Subscription<rcl_interfaces::msg::ParameterEvent>::SharedPtr
on_parameter_event(
template <typename CallbackT, typename AllocatorT = std::allocator<void>>
typename rclcpp::Subscription<rcl_interfaces::msg::ParameterEvent>::SharedPtr on_parameter_event(
CallbackT && callback,
const rclcpp::QoS & qos = (
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(rmw_qos_profile_parameter_events))
),
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options = (
rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>()
))
const rclcpp::QoS & qos =
(rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(rmw_qos_profile_parameter_events))),
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options =
(rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>()))
{
return this->on_parameter_event(
this->node_topics_interface_,
callback,
qos,
options);
return this->on_parameter_event(this->node_topics_interface_, callback, qos, options);
}
/**
@@ -136,59 +114,44 @@ public:
* which returns a shared_ptr to a NodeTopicsInterface, or be a
* NodeTopicsInterface pointer itself.
*/
template<
typename CallbackT,
typename NodeT,
typename AllocatorT = std::allocator<void>>
template <typename CallbackT, typename NodeT, typename AllocatorT = std::allocator<void>>
static typename rclcpp::Subscription<rcl_interfaces::msg::ParameterEvent>::SharedPtr
on_parameter_event(
NodeT && node,
CallbackT && callback,
const rclcpp::QoS & qos = (
rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(rmw_qos_profile_parameter_events))
),
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options = (
rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>()
))
const rclcpp::QoS & qos =
(rclcpp::QoS(rclcpp::QoSInitialization::from_rmw(rmw_qos_profile_parameter_events))),
const rclcpp::SubscriptionOptionsWithAllocator<AllocatorT> & options =
(rclcpp::SubscriptionOptionsWithAllocator<AllocatorT>()))
{
return rclcpp::create_subscription<rcl_interfaces::msg::ParameterEvent>(
node,
"parameter_events",
qos,
std::forward<CallbackT>(callback),
options);
node, "parameter_events", qos, std::forward<CallbackT>(callback), options);
}
RCLCPP_PUBLIC
bool
service_is_ready() const;
bool service_is_ready() const;
template<typename RepT = int64_t, typename RatioT = std::milli>
bool
wait_for_service(
template <typename RepT = int64_t, typename RatioT = std::milli>
bool wait_for_service(
std::chrono::duration<RepT, RatioT> timeout = std::chrono::duration<RepT, RatioT>(-1))
{
return wait_for_service_nanoseconds(
std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
);
std::chrono::duration_cast<std::chrono::nanoseconds>(timeout));
}
protected:
RCLCPP_PUBLIC
bool
wait_for_service_nanoseconds(std::chrono::nanoseconds timeout);
bool wait_for_service_nanoseconds(std::chrono::nanoseconds timeout);
private:
rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics_interface_;
rclcpp::Client<rcl_interfaces::srv::GetParameters>::SharedPtr get_parameters_client_;
rclcpp::Client<rcl_interfaces::srv::GetParameterTypes>::SharedPtr
get_parameter_types_client_;
rclcpp::Client<rcl_interfaces::srv::GetParameterTypes>::SharedPtr get_parameter_types_client_;
rclcpp::Client<rcl_interfaces::srv::SetParameters>::SharedPtr set_parameters_client_;
rclcpp::Client<rcl_interfaces::srv::SetParametersAtomically>::SharedPtr
set_parameters_atomically_client_;
rclcpp::Client<rcl_interfaces::srv::ListParameters>::SharedPtr list_parameters_client_;
rclcpp::Client<rcl_interfaces::srv::DescribeParameters>::SharedPtr
describe_parameters_client_;
rclcpp::Client<rcl_interfaces::srv::DescribeParameters>::SharedPtr describe_parameters_client_;
std::string remote_node_name_;
};
@@ -205,7 +168,7 @@ public:
RCLCPP_PUBLIC
SyncParametersClient(
rclcpp::Executor::SharedPtr executor,
rclcpp::executor::Executor::SharedPtr executor,
rclcpp::Node::SharedPtr node,
const std::string & remote_node_name = "",
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters);
@@ -218,14 +181,14 @@ public:
RCLCPP_PUBLIC
SyncParametersClient(
rclcpp::Executor::SharedPtr executor,
rclcpp::executor::Executor::SharedPtr executor,
rclcpp::Node * node,
const std::string & remote_node_name = "",
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters);
RCLCPP_PUBLIC
SyncParametersClient(
rclcpp::Executor::SharedPtr executor,
rclcpp::executor::Executor::SharedPtr executor,
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_interface,
const rclcpp::node_interfaces::NodeTopicsInterface::SharedPtr node_topics_interface,
const rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph_interface,
@@ -234,16 +197,13 @@ public:
const rmw_qos_profile_t & qos_profile = rmw_qos_profile_parameters);
RCLCPP_PUBLIC
std::vector<rclcpp::Parameter>
get_parameters(const std::vector<std::string> & parameter_names);
std::vector<rclcpp::Parameter> get_parameters(const std::vector<std::string> & parameter_names);
RCLCPP_PUBLIC
bool
has_parameter(const std::string & parameter_name);
bool has_parameter(const std::string & parameter_name);
template<typename T>
T
get_parameter_impl(
template <typename T>
T get_parameter_impl(
const std::string & parameter_name, std::function<T()> parameter_not_found_handler)
{
std::vector<std::string> names;
@@ -256,53 +216,42 @@ public:
}
}
template<typename T>
T
get_parameter(const std::string & parameter_name, const T & default_value)
template <typename T>
T get_parameter(const std::string & parameter_name, const T & default_value)
{
return get_parameter_impl(
parameter_name,
std::function<T()>([&default_value]() -> T {return default_value;}));
parameter_name, std::function<T()>([&default_value]() -> T { return default_value; }));
}
template<typename T>
T
get_parameter(const std::string & parameter_name)
template <typename T>
T get_parameter(const std::string & parameter_name)
{
return get_parameter_impl(
parameter_name,
std::function<T()>(
[&parameter_name]() -> T
{
throw std::runtime_error("Parameter '" + parameter_name + "' is not set");
})
);
return get_parameter_impl(parameter_name, std::function<T()>([]() -> T {
throw std::runtime_error("Parameter not set");
}));
}
RCLCPP_PUBLIC
std::vector<rclcpp::ParameterType>
get_parameter_types(const std::vector<std::string> & parameter_names);
std::vector<rclcpp::ParameterType> get_parameter_types(
const std::vector<std::string> & parameter_names);
RCLCPP_PUBLIC
std::vector<rcl_interfaces::msg::SetParametersResult>
set_parameters(const std::vector<rclcpp::Parameter> & parameters);
std::vector<rcl_interfaces::msg::SetParametersResult> set_parameters(
const std::vector<rclcpp::Parameter> & parameters);
RCLCPP_PUBLIC
rcl_interfaces::msg::SetParametersResult
set_parameters_atomically(const std::vector<rclcpp::Parameter> & parameters);
rcl_interfaces::msg::SetParametersResult set_parameters_atomically(
const std::vector<rclcpp::Parameter> & parameters);
RCLCPP_PUBLIC
rcl_interfaces::msg::ListParametersResult
list_parameters(
const std::vector<std::string> & parameter_prefixes,
uint64_t depth);
rcl_interfaces::msg::ListParametersResult list_parameters(
const std::vector<std::string> & parameter_prefixes, uint64_t depth);
template<typename CallbackT>
typename rclcpp::Subscription<rcl_interfaces::msg::ParameterEvent>::SharedPtr
on_parameter_event(CallbackT && callback)
template <typename CallbackT>
typename rclcpp::Subscription<rcl_interfaces::msg::ParameterEvent>::SharedPtr on_parameter_event(
CallbackT && callback)
{
return async_parameters_client_->on_parameter_event(
std::forward<CallbackT>(callback));
return async_parameters_client_->on_parameter_event(std::forward<CallbackT>(callback));
}
/**
@@ -310,36 +259,25 @@ public:
* which returns a shared_ptr to a NodeTopicsInterface, or be a
* NodeTopicsInterface pointer itself.
*/
template<
typename CallbackT,
typename NodeT>
template <typename CallbackT, typename NodeT>
static typename rclcpp::Subscription<rcl_interfaces::msg::ParameterEvent>::SharedPtr
on_parameter_event(
NodeT && node,
CallbackT && callback)
on_parameter_event(NodeT && node, CallbackT && callback)
{
return AsyncParametersClient::on_parameter_event(
node,
std::forward<CallbackT>(callback));
return AsyncParametersClient::on_parameter_event(node, std::forward<CallbackT>(callback));
}
RCLCPP_PUBLIC
bool
service_is_ready() const
{
return async_parameters_client_->service_is_ready();
}
bool service_is_ready() const { return async_parameters_client_->service_is_ready(); }
template<typename RepT = int64_t, typename RatioT = std::milli>
bool
wait_for_service(
template <typename RepT = int64_t, typename RatioT = std::milli>
bool wait_for_service(
std::chrono::duration<RepT, RatioT> timeout = std::chrono::duration<RepT, RatioT>(-1))
{
return async_parameters_client_->wait_for_service(timeout);
}
private:
rclcpp::Executor::SharedPtr executor_;
rclcpp::executor::Executor::SharedPtr executor_;
const rclcpp::node_interfaces::NodeBaseInterface::SharedPtr node_base_interface_;
AsyncParametersClient::SharedPtr async_parameters_client_;
};

View File

@@ -30,12 +30,11 @@
namespace rclcpp
{
class ParameterEventsFilter
{
public:
RCLCPP_SMART_PTR_DEFINITIONS(ParameterEventsFilter)
enum class EventType {NEW, DELETED, CHANGED}; ///< An enum for the type of event.
enum class EventType { NEW, DELETED, CHANGED }; ///< An enum for the type of event.
/// Used for the listed results
using EventPair = std::pair<EventType, rcl_interfaces::msg::Parameter *>;
@@ -73,7 +72,7 @@ public:
private:
// access only allowed via const accessor.
std::vector<EventPair> result_; ///< Storage of the resultant vector
std::vector<EventPair> result_; ///< Storage of the resultant vector
rcl_interfaces::msg::ParameterEvent::SharedPtr event_; ///< Keep event in scope
};

View File

@@ -28,7 +28,6 @@
namespace rclcpp
{
/// A map of fully qualified node names to a list of parameters
using ParameterMap = std::unordered_map<std::string, std::vector<Parameter>>;
@@ -37,16 +36,14 @@ using ParameterMap = std::unordered_map<std::string, std::vector<Parameter>>;
/// \returns a map where the keys are fully qualified node names and values a list of parameters.
/// \throws InvalidParametersException if the `rcl_params_t` is inconsistent or invalid.
RCLCPP_PUBLIC
ParameterMap
parameter_map_from(const rcl_params_t * const c_params);
ParameterMap parameter_map_from(const rcl_params_t * const c_params);
/// Convert parameter value from rcl_yaml_param_parser into a C++ class instance.
/// \param[in] c_value C structure containing a value of a parameter.
/// \returns an instance of a parameter value
/// \throws InvalidParameterValueException if the `rcl_variant_t` is inconsistent or invalid.
RCLCPP_PUBLIC
ParameterValue
parameter_value_from(const rcl_variant_t * const c_value);
ParameterValue parameter_value_from(const rcl_variant_t * const c_value);
} // namespace rclcpp

View File

@@ -33,7 +33,6 @@
namespace rclcpp
{
class ParameterService
{
public:
@@ -48,13 +47,11 @@ public:
private:
rclcpp::Service<rcl_interfaces::srv::GetParameters>::SharedPtr get_parameters_service_;
rclcpp::Service<rcl_interfaces::srv::GetParameterTypes>::SharedPtr
get_parameter_types_service_;
rclcpp::Service<rcl_interfaces::srv::GetParameterTypes>::SharedPtr get_parameter_types_service_;
rclcpp::Service<rcl_interfaces::srv::SetParameters>::SharedPtr set_parameters_service_;
rclcpp::Service<rcl_interfaces::srv::SetParametersAtomically>::SharedPtr
set_parameters_atomically_service_;
rclcpp::Service<rcl_interfaces::srv::DescribeParameters>::SharedPtr
describe_parameters_service_;
rclcpp::Service<rcl_interfaces::srv::DescribeParameters>::SharedPtr describe_parameters_service_;
rclcpp::Service<rcl_interfaces::srv::ListParameters>::SharedPtr list_parameters_service_;
};

View File

@@ -28,9 +28,7 @@
namespace rclcpp
{
enum ParameterType : uint8_t
{
enum ParameterType : uint8_t {
PARAMETER_NOT_SET = rcl_interfaces::msg::ParameterType::PARAMETER_NOT_SET,
PARAMETER_BOOL = rcl_interfaces::msg::ParameterType::PARAMETER_BOOL,
PARAMETER_INTEGER = rcl_interfaces::msg::ParameterType::PARAMETER_INTEGER,
@@ -45,12 +43,10 @@ enum ParameterType : uint8_t
/// Return the name of a parameter type
RCLCPP_PUBLIC
std::string
to_string(ParameterType type);
std::string to_string(ParameterType type);
RCLCPP_PUBLIC
std::ostream &
operator<<(std::ostream & os, ParameterType type);
std::ostream & operator<<(std::ostream & os, ParameterType type);
/// Indicate the parameter type does not match the expected type.
class ParameterTypeException : public std::runtime_error
@@ -64,7 +60,8 @@ public:
RCLCPP_PUBLIC
ParameterTypeException(ParameterType expected, ParameterType actual)
: std::runtime_error("expected [" + to_string(expected) + "] got [" + to_string(actual) + "]")
{}
{
}
};
/// Store the type and value of a parameter.
@@ -122,30 +119,25 @@ public:
/// Return an enum indicating the type of the set value.
RCLCPP_PUBLIC
ParameterType
get_type() const;
ParameterType get_type() const;
/// Return a message populated with the parameter value
RCLCPP_PUBLIC
rcl_interfaces::msg::ParameterValue
to_value_msg() const;
rcl_interfaces::msg::ParameterValue to_value_msg() const;
/// Equal operator.
RCLCPP_PUBLIC
bool
operator==(const ParameterValue & rhs) const;
bool operator==(const ParameterValue & rhs) const;
/// Not equal operator.
RCLCPP_PUBLIC
bool
operator!=(const ParameterValue & rhs) const;
bool operator!=(const ParameterValue & rhs) const;
// The following get() variants require the use of ParameterType
template<ParameterType type>
constexpr
typename std::enable_if<type == ParameterType::PARAMETER_BOOL, const bool &>::type
get() const
template <ParameterType type>
constexpr typename std::enable_if<type == ParameterType::PARAMETER_BOOL, const bool &>::type get()
const
{
if (value_.type != rcl_interfaces::msg::ParameterType::PARAMETER_BOOL) {
throw ParameterTypeException(ParameterType::PARAMETER_BOOL, get_type());
@@ -153,9 +145,8 @@ public:
return value_.bool_value;
}
template<ParameterType type>
constexpr
typename std::enable_if<type == ParameterType::PARAMETER_INTEGER, const int64_t &>::type
template <ParameterType type>
constexpr typename std::enable_if<type == ParameterType::PARAMETER_INTEGER, const int64_t &>::type
get() const
{
if (value_.type != rcl_interfaces::msg::ParameterType::PARAMETER_INTEGER) {
@@ -164,9 +155,8 @@ public:
return value_.integer_value;
}
template<ParameterType type>
constexpr
typename std::enable_if<type == ParameterType::PARAMETER_DOUBLE, const double &>::type
template <ParameterType type>
constexpr typename std::enable_if<type == ParameterType::PARAMETER_DOUBLE, const double &>::type
get() const
{
if (value_.type != rcl_interfaces::msg::ParameterType::PARAMETER_DOUBLE) {
@@ -175,10 +165,10 @@ public:
return value_.double_value;
}
template<ParameterType type>
template <ParameterType type>
constexpr
typename std::enable_if<type == ParameterType::PARAMETER_STRING, const std::string &>::type
get() const
typename std::enable_if<type == ParameterType::PARAMETER_STRING, const std::string &>::type
get() const
{
if (value_.type != rcl_interfaces::msg::ParameterType::PARAMETER_STRING) {
throw ParameterTypeException(ParameterType::PARAMETER_STRING, get_type());
@@ -186,11 +176,10 @@ public:
return value_.string_value;
}
template<ParameterType type>
constexpr
typename std::enable_if<
type == ParameterType::PARAMETER_BYTE_ARRAY, const std::vector<uint8_t> &>::type
get() const
template <ParameterType type>
constexpr typename std::
enable_if<type == ParameterType::PARAMETER_BYTE_ARRAY, const std::vector<uint8_t> &>::type
get() const
{
if (value_.type != rcl_interfaces::msg::ParameterType::PARAMETER_BYTE_ARRAY) {
throw ParameterTypeException(ParameterType::PARAMETER_BYTE_ARRAY, get_type());
@@ -198,11 +187,10 @@ public:
return value_.byte_array_value;
}
template<ParameterType type>
constexpr
typename std::enable_if<
type == ParameterType::PARAMETER_BOOL_ARRAY, const std::vector<bool> &>::type
get() const
template <ParameterType type>
constexpr typename std::
enable_if<type == ParameterType::PARAMETER_BOOL_ARRAY, const std::vector<bool> &>::type
get() const
{
if (value_.type != rcl_interfaces::msg::ParameterType::PARAMETER_BOOL_ARRAY) {
throw ParameterTypeException(ParameterType::PARAMETER_BOOL_ARRAY, get_type());
@@ -210,11 +198,10 @@ public:
return value_.bool_array_value;
}
template<ParameterType type>
constexpr
typename std::enable_if<
type == ParameterType::PARAMETER_INTEGER_ARRAY, const std::vector<int64_t> &>::type
get() const
template <ParameterType type>
constexpr typename std::
enable_if<type == ParameterType::PARAMETER_INTEGER_ARRAY, const std::vector<int64_t> &>::type
get() const
{
if (value_.type != rcl_interfaces::msg::ParameterType::PARAMETER_INTEGER_ARRAY) {
throw ParameterTypeException(ParameterType::PARAMETER_INTEGER_ARRAY, get_type());
@@ -222,11 +209,10 @@ public:
return value_.integer_array_value;
}
template<ParameterType type>
constexpr
typename std::enable_if<
type == ParameterType::PARAMETER_DOUBLE_ARRAY, const std::vector<double> &>::type
get() const
template <ParameterType type>
constexpr typename std::
enable_if<type == ParameterType::PARAMETER_DOUBLE_ARRAY, const std::vector<double> &>::type
get() const
{
if (value_.type != rcl_interfaces::msg::ParameterType::PARAMETER_DOUBLE_ARRAY) {
throw ParameterTypeException(ParameterType::PARAMETER_DOUBLE_ARRAY, get_type());
@@ -234,11 +220,10 @@ public:
return value_.double_array_value;
}
template<ParameterType type>
constexpr
typename std::enable_if<
type == ParameterType::PARAMETER_STRING_ARRAY, const std::vector<std::string> &>::type
get() const
template <ParameterType type>
constexpr typename std::
enable_if<type == ParameterType::PARAMETER_STRING_ARRAY, const std::vector<std::string> &>::type
get() const
{
if (value_.type != rcl_interfaces::msg::ParameterType::PARAMETER_STRING_ARRAY) {
throw ParameterTypeException(ParameterType::PARAMETER_STRING_ARRAY, get_type());
@@ -248,84 +233,76 @@ public:
// The following get() variants allow the use of primitive types
template<typename type>
constexpr
typename std::enable_if<std::is_same<type, bool>::value, const bool &>::type
get() const
template <typename type>
constexpr typename std::enable_if<std::is_same<type, bool>::value, const bool &>::type get() const
{
return get<ParameterType::PARAMETER_BOOL>();
}
template<typename type>
constexpr
typename std::enable_if<
std::is_integral<type>::value && !std::is_same<type, bool>::value, const int64_t &>::type
template <typename type>
constexpr typename std::enable_if<
std::is_integral<type>::value && !std::is_same<type, bool>::value,
const int64_t &>::type
get() const
{
return get<ParameterType::PARAMETER_INTEGER>();
}
template<typename type>
constexpr
typename std::enable_if<std::is_floating_point<type>::value, const double &>::type
get() const
template <typename type>
constexpr typename std::enable_if<std::is_floating_point<type>::value, const double &>::type get()
const
{
return get<ParameterType::PARAMETER_DOUBLE>();
}
template<typename type>
constexpr
typename std::enable_if<std::is_convertible<type, std::string>::value, const std::string &>::type
get() const
template <typename type>
constexpr typename std::
enable_if<std::is_convertible<type, std::string>::value, const std::string &>::type
get() const
{
return get<ParameterType::PARAMETER_STRING>();
}
template<typename type>
constexpr
typename std::enable_if<
std::is_convertible<
type, const std::vector<uint8_t> &>::value, const std::vector<uint8_t> &>::type
template <typename type>
constexpr typename std::enable_if<
std::is_convertible<type, const std::vector<uint8_t> &>::value,
const std::vector<uint8_t> &>::type
get() const
{
return get<ParameterType::PARAMETER_BYTE_ARRAY>();
}
template<typename type>
constexpr
typename std::enable_if<
std::is_convertible<
type, const std::vector<bool> &>::value, const std::vector<bool> &>::type
template <typename type>
constexpr typename std::enable_if<
std::is_convertible<type, const std::vector<bool> &>::value,
const std::vector<bool> &>::type
get() const
{
return get<ParameterType::PARAMETER_BOOL_ARRAY>();
}
template<typename type>
constexpr
typename std::enable_if<
std::is_convertible<
type, const std::vector<int64_t> &>::value, const std::vector<int64_t> &>::type
template <typename type>
constexpr typename std::enable_if<
std::is_convertible<type, const std::vector<int64_t> &>::value,
const std::vector<int64_t> &>::type
get() const
{
return get<ParameterType::PARAMETER_INTEGER_ARRAY>();
}
template<typename type>
constexpr
typename std::enable_if<
std::is_convertible<
type, const std::vector<double> &>::value, const std::vector<double> &>::type
template <typename type>
constexpr typename std::enable_if<
std::is_convertible<type, const std::vector<double> &>::value,
const std::vector<double> &>::type
get() const
{
return get<ParameterType::PARAMETER_DOUBLE_ARRAY>();
}
template<typename type>
constexpr
typename std::enable_if<
std::is_convertible<
type, const std::vector<std::string> &>::value, const std::vector<std::string> &>::type
template <typename type>
constexpr typename std::enable_if<
std::is_convertible<type, const std::vector<std::string> &>::value,
const std::vector<std::string> &>::type
get() const
{
return get<ParameterType::PARAMETER_STRING_ARRAY>();
@@ -337,8 +314,7 @@ private:
/// Return the value of a parameter as a string
RCLCPP_PUBLIC
std::string
to_string(const ParameterValue & type);
std::string to_string(const ParameterValue & type);
} // namespace rclcpp

View File

@@ -28,141 +28,63 @@
#include "rcl/error_handling.h"
#include "rcl/publisher.h"
#include "rcl_interfaces/msg/intra_process_message.hpp"
#include "rclcpp/allocator/allocator_common.hpp"
#include "rclcpp/allocator/allocator_deleter.hpp"
#include "rclcpp/detail/resolve_use_intra_process.hpp"
#include "rclcpp/experimental/intra_process_manager.hpp"
#include "rclcpp/loaned_message.hpp"
#include "rclcpp/intra_process_manager.hpp"
#include "rclcpp/macros.hpp"
#include "rclcpp/node_interfaces/node_base_interface.hpp"
#include "rclcpp/publisher_base.hpp"
#include "rclcpp/publisher_options.hpp"
#include "rclcpp/type_support_decl.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
template<typename MessageT, typename AllocatorT>
class LoanedMessage;
/// A publisher publishes messages of any type to a topic.
template<typename MessageT, typename AllocatorT = std::allocator<void>>
template <typename MessageT, typename Alloc = std::allocator<void>>
class Publisher : public PublisherBase
{
public:
using MessageAllocatorTraits = allocator::AllocRebind<MessageT, AllocatorT>;
using MessageAllocator = typename MessageAllocatorTraits::allocator_type;
using MessageDeleter = allocator::Deleter<MessageAllocator, MessageT>;
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>;
using MessageSharedPtr = std::shared_ptr<const MessageT>;
RCLCPP_SMART_PTR_DEFINITIONS(Publisher<MessageT, AllocatorT>)
RCLCPP_SMART_PTR_DEFINITIONS(Publisher<MessageT, Alloc>)
Publisher(
rclcpp::node_interfaces::NodeBaseInterface * node_base,
const std::string & topic,
const rclcpp::QoS & qos,
const rclcpp::PublisherOptionsWithAllocator<AllocatorT> & options)
const rcl_publisher_options_t & publisher_options,
const PublisherEventCallbacks & event_callbacks,
const std::shared_ptr<MessageAlloc> & allocator)
: PublisherBase(
node_base,
topic,
*rosidl_typesupport_cpp::get_message_type_support_handle<MessageT>(),
options.template to_rcl_publisher_options<MessageT>(qos)),
options_(options),
message_allocator_(new MessageAllocator(*options.get_allocator().get()))
publisher_options),
message_allocator_(allocator)
{
allocator::set_allocator_for_deleter(&message_deleter_, message_allocator_.get());
if (options_.event_callbacks.deadline_callback) {
if (event_callbacks.deadline_callback) {
this->add_event_handler(
options_.event_callbacks.deadline_callback,
RCL_PUBLISHER_OFFERED_DEADLINE_MISSED);
event_callbacks.deadline_callback, RCL_PUBLISHER_OFFERED_DEADLINE_MISSED);
}
if (options_.event_callbacks.liveliness_callback) {
this->add_event_handler(
options_.event_callbacks.liveliness_callback,
RCL_PUBLISHER_LIVELINESS_LOST);
}
if (options_.event_callbacks.incompatible_qos_callback) {
this->add_event_handler(
options_.event_callbacks.incompatible_qos_callback,
RCL_PUBLISHER_OFFERED_INCOMPATIBLE_QOS);
} else if (options_.use_default_callbacks) {
// Register default callback when not specified
try {
this->add_event_handler(
[this](QOSOfferedIncompatibleQoSInfo & info) {
this->default_incompatible_qos_callback(info);
},
RCL_PUBLISHER_OFFERED_INCOMPATIBLE_QOS);
} catch (UnsupportedEventTypeException & /*exc*/) {
// pass
}
}
// Setup continues in the post construction method, post_init_setup().
}
/// Called post construction, so that construction may continue after shared_from_this() works.
virtual
void
post_init_setup(
rclcpp::node_interfaces::NodeBaseInterface * node_base,
const std::string & topic,
const rclcpp::QoS & qos,
const rclcpp::PublisherOptionsWithAllocator<AllocatorT> & options)
{
// Topic is unused for now.
(void)topic;
(void)options;
// If needed, setup intra process communication.
if (rclcpp::detail::resolve_use_intra_process(options_, *node_base)) {
auto context = node_base->get_context();
// Get the intra process manager instance for this context.
auto ipm = context->get_sub_context<rclcpp::experimental::IntraProcessManager>();
// Register the publisher with the intra process manager.
if (qos.get_rmw_qos_profile().history == RMW_QOS_POLICY_HISTORY_KEEP_ALL) {
throw std::invalid_argument(
"intraprocess communication is not allowed with keep all history qos policy");
}
if (qos.get_rmw_qos_profile().depth == 0) {
throw std::invalid_argument(
"intraprocess communication is not allowed with a zero qos history depth value");
}
if (qos.get_rmw_qos_profile().durability != RMW_QOS_POLICY_DURABILITY_VOLATILE) {
throw std::invalid_argument(
"intraprocess communication allowed only with volatile durability");
}
uint64_t intra_process_publisher_id = ipm->add_publisher(this->shared_from_this());
this->setup_intra_process(
intra_process_publisher_id,
ipm);
if (event_callbacks.liveliness_callback) {
this->add_event_handler(event_callbacks.liveliness_callback, RCL_PUBLISHER_LIVELINESS_LOST);
}
}
virtual ~Publisher()
{}
virtual ~Publisher() {}
/// Borrow a loaned ROS message from the middleware.
/**
* If the middleware is capable of loaning memory for a ROS message instance,
* the loaned message will be directly allocated in the middleware.
* If not, the message allocator of this rclcpp::Publisher instance is being used.
*
* With a call to \sa `publish` the LoanedMessage instance is being returned to the middleware
* or free'd accordingly to the allocator.
* If the message is not being published but processed differently, the destructor of this
* class will either return the message to the middleware or deallocate it via the internal
* allocator.
* \sa rclcpp::LoanedMessage for details of the LoanedMessage class.
*
* \return LoanedMessage containing memory for a ROS message of type MessageT
*/
rclcpp::LoanedMessage<MessageT, AllocatorT>
borrow_loaned_message()
mapped_ring_buffer::MappedRingBufferBase::SharedPtr make_mapped_ring_buffer(
size_t size) const override
{
return rclcpp::LoanedMessage<MessageT, AllocatorT>(this, this->get_allocator());
return mapped_ring_buffer::
MappedRingBuffer<MessageT, typename Publisher<MessageT, Alloc>::MessageAlloc>::make_shared(
size, this->get_allocator());
}
/// Send a message to the topic for this publisher.
@@ -170,11 +92,10 @@ public:
* This function is templated on the input message type, MessageT.
* \param[in] msg A shared pointer to the message to send.
*/
virtual void
publish(std::unique_ptr<MessageT, MessageDeleter> msg)
virtual void publish(std::unique_ptr<MessageT, MessageDeleter> msg)
{
if (!intra_process_is_enabled_) {
this->do_inter_process_publish(*msg);
this->do_inter_process_publish(msg.get());
return;
}
// If an interprocess subscription exist, then the unique_ptr is promoted
@@ -183,87 +104,93 @@ public:
// interprocess publish, resulting in lower publish-to-subscribe latency.
// It's not possible to do that with an unique_ptr,
// as do_intra_process_publish takes the ownership of the message.
uint64_t message_seq;
bool inter_process_publish_needed =
get_subscription_count() > get_intra_process_subscription_count();
MessageSharedPtr shared_msg;
if (inter_process_publish_needed) {
auto shared_msg = this->do_intra_process_publish_and_return_shared(std::move(msg));
this->do_inter_process_publish(*shared_msg);
shared_msg = std::move(msg);
message_seq = store_intra_process_message(intra_process_publisher_id_, shared_msg);
} else {
this->do_intra_process_publish(std::move(msg));
message_seq = store_intra_process_message(intra_process_publisher_id_, std::move(msg));
}
this->do_intra_process_publish(message_seq);
if (inter_process_publish_needed) {
this->do_inter_process_publish(shared_msg.get());
}
}
virtual void
publish(const MessageT & msg)
// Skip deprecated attribute in windows, as it raise a warning in template specialization.
#if !defined(_WIN32)
[
[deprecated("publishing an unique_ptr is prefered when using intra process communication."
" If using a shared_ptr, use publish(*msg).")]]
#endif
virtual void
publish(const std::shared_ptr<const MessageT> & msg)
{
publish(*msg);
}
virtual void publish(const MessageT & msg)
{
// Avoid allocating when not using intra process.
if (!intra_process_is_enabled_) {
// In this case we're not using intra process.
return this->do_inter_process_publish(msg);
return this->do_inter_process_publish(&msg);
}
// Otherwise we have to allocate memory in a unique_ptr and pass it along.
// As the message is not const, a copy should be made.
// A shared_ptr<const MessageT> could also be constructed here.
auto ptr = MessageAllocatorTraits::allocate(*message_allocator_.get(), 1);
MessageAllocatorTraits::construct(*message_allocator_.get(), ptr, msg);
auto ptr = MessageAllocTraits::allocate(*message_allocator_.get(), 1);
MessageAllocTraits::construct(*message_allocator_.get(), ptr, msg);
MessageUniquePtr unique_msg(ptr, message_deleter_);
this->publish(std::move(unique_msg));
}
void
publish(const rcl_serialized_message_t & serialized_msg)
// Skip deprecated attribute in windows, as it raise a warning in template specialization.
#if !defined(_WIN32)
[[deprecated("Use publish(*msg). Check against nullptr before calling if necessary.")]]
#endif
virtual void
publish(const MessageT * msg)
{
if (!msg) {
throw std::runtime_error("msg argument is nullptr");
}
return this->publish(*msg);
}
void publish(const rcl_serialized_message_t & serialized_msg)
{
return this->do_serialized_publish(&serialized_msg);
}
/// Publish an instance of a LoanedMessage.
/**
* When publishing a loaned message, the memory for this ROS message will be deallocated
* after being published.
* The instance of the loaned message is no longer valid after this call.
*
* \param loaned_msg The LoanedMessage instance to be published.
*/
void
publish(rclcpp::LoanedMessage<MessageT, AllocatorT> && loaned_msg)
{
if (!loaned_msg.is_valid()) {
throw std::runtime_error("loaned message is not valid");
}
if (intra_process_is_enabled_) {
// TODO(Karsten1987): support loaned message passed by intraprocess
throw std::runtime_error("storing loaned messages in intra process is not supported yet");
// Skip deprecated attribute in windows, as it raise a warning in template specialization.
#if !defined(_WIN32)
[[deprecated("Use publish(*serialized_msg). Check against nullptr before calling if necessary.")]]
#endif
void
publish(const rcl_serialized_message_t * serialized_msg) {
return this->do_serialized_publish(serialized_msg);
}
// verify that publisher supports loaned messages
// TODO(Karsten1987): This case separation has to be done in rclcpp
// otherwise we have to ensure that every middleware implements
// `rmw_publish_loaned_message` explicitly the same way as `rmw_publish`
// by taking a copy of the ros message.
if (this->can_loan_messages()) {
// we release the ownership from the rclpp::LoanedMessage instance
// and let the middleware clean up the memory.
this->do_loaned_message_publish(loaned_msg.release());
} else {
// we don't release the ownership, let the middleware copy the ros message
// and thus the destructor of rclcpp::LoanedMessage cleans up the memory.
this->do_inter_process_publish(loaned_msg.get());
}
// Skip deprecated attribute in windows, as it raise a warning in template specialization.
#if !defined(_WIN32)
[[deprecated(
"Use publish(*serialized_msg). Check against nullptr before calling if necessary.")]]
#endif
void publish(std::shared_ptr<const rcl_serialized_message_t> serialized_msg)
{
return this->do_serialized_publish(serialized_msg.get());
}
std::shared_ptr<MessageAllocator>
get_allocator() const
{
return message_allocator_;
}
std::shared_ptr<MessageAlloc> get_allocator() const { return message_allocator_; }
protected:
void
do_inter_process_publish(const MessageT & msg)
void do_inter_process_publish(const MessageT * msg)
{
auto status = rcl_publish(&publisher_handle_, &msg, nullptr);
auto status = rcl_publish(&publisher_handle_, msg, nullptr);
if (RCL_RET_PUBLISHER_INVALID == status) {
rcl_reset_error(); // next call will reset error message if not context
if (rcl_publisher_is_valid_except_context(&publisher_handle_)) {
@@ -279,8 +206,7 @@ protected:
}
}
void
do_serialized_publish(const rcl_serialized_message_t * serialized_msg)
void do_serialized_publish(const rcl_serialized_message_t * serialized_msg)
{
if (intra_process_is_enabled_) {
// TODO(Karsten1987): support serialized message passed by intraprocess
@@ -292,15 +218,16 @@ protected:
}
}
void
do_loaned_message_publish(MessageT * msg)
void do_intra_process_publish(uint64_t message_seq)
{
auto status = rcl_publish_loaned_message(&publisher_handle_, msg, nullptr);
rcl_interfaces::msg::IntraProcessMessage ipm;
ipm.publisher_id = intra_process_publisher_id_;
ipm.message_sequence = message_seq;
auto status = rcl_publish(&intra_process_publisher_handle_, &ipm, nullptr);
if (RCL_RET_PUBLISHER_INVALID == status) {
rcl_reset_error(); // next call will reset error message if not context
if (rcl_publisher_is_valid_except_context(&publisher_handle_)) {
rcl_context_t * context = rcl_publisher_get_context(&publisher_handle_);
if (rcl_publisher_is_valid_except_context(&intra_process_publisher_handle_)) {
rcl_context_t * context = rcl_publisher_get_context(&intra_process_publisher_handle_);
if (nullptr != context && !rcl_context_is_valid(context)) {
// publisher is invalid due to context being shutdown
return;
@@ -308,54 +235,42 @@ protected:
}
}
if (RCL_RET_OK != status) {
rclcpp::exceptions::throw_from_rcl_error(status, "failed to publish message");
rclcpp::exceptions::throw_from_rcl_error(status, "failed to publish intra process message");
}
}
void
do_intra_process_publish(std::unique_ptr<MessageT, MessageDeleter> msg)
uint64_t store_intra_process_message(uint64_t publisher_id, std::shared_ptr<const MessageT> msg)
{
auto ipm = weak_ipm_.lock();
if (!ipm) {
throw std::runtime_error(
"intra process publish called after destruction of intra process manager");
"intra process publish called after destruction of intra process manager");
}
if (!msg) {
throw std::runtime_error("cannot publish msg which is a null pointer");
throw std::runtime_error("cannot publisher msg which is a null pointer");
}
ipm->template do_intra_process_publish<MessageT, AllocatorT>(
intra_process_publisher_id_,
std::move(msg),
message_allocator_);
uint64_t message_seq =
ipm->template store_intra_process_message<MessageT, Alloc>(publisher_id, msg);
return message_seq;
}
std::shared_ptr<const MessageT>
do_intra_process_publish_and_return_shared(std::unique_ptr<MessageT, MessageDeleter> msg)
uint64_t store_intra_process_message(
uint64_t publisher_id, std::unique_ptr<MessageT, MessageDeleter> msg)
{
auto ipm = weak_ipm_.lock();
if (!ipm) {
throw std::runtime_error(
"intra process publish called after destruction of intra process manager");
"intra process publish called after destruction of intra process manager");
}
if (!msg) {
throw std::runtime_error("cannot publish msg which is a null pointer");
throw std::runtime_error("cannot publisher msg which is a null pointer");
}
return ipm->template do_intra_process_publish_and_return_shared<MessageT, AllocatorT>(
intra_process_publisher_id_,
std::move(msg),
message_allocator_);
uint64_t message_seq =
ipm->template store_intra_process_message<MessageT, Alloc>(publisher_id, std::move(msg));
return message_seq;
}
/// Copy of original options passed during construction.
/**
* It is important to save a copy of this so that the rmw payload which it
* may contain is kept alive for the duration of the publisher.
*/
const rclcpp::PublisherOptionsWithAllocator<AllocatorT> options_;
std::shared_ptr<MessageAllocator> message_allocator_;
std::shared_ptr<MessageAlloc> message_allocator_;
MessageDeleter message_deleter_;
};

View File

@@ -28,14 +28,13 @@
#include "rcl/publisher.h"
#include "rclcpp/macros.hpp"
#include "rclcpp/qos.hpp"
#include "rclcpp/mapped_ring_buffer.hpp"
#include "rclcpp/qos_event.hpp"
#include "rclcpp/type_support_decl.hpp"
#include "rclcpp/visibility_control.hpp"
namespace rclcpp
{
// Forward declaration is used for friend statement.
namespace node_interfaces
{
@@ -43,16 +42,16 @@ class NodeBaseInterface;
class NodeTopicsInterface;
} // namespace node_interfaces
namespace experimental
namespace intra_process_manager
{
/**
* IntraProcessManager is forward declared here, avoiding a circular inclusion between
* `intra_process_manager.hpp` and `publisher_base.hpp`.
*/
class IntraProcessManager;
} // namespace experimental
} // namespace intra_process_manager
class PublisherBase : public std::enable_shared_from_this<PublisherBase>
class PublisherBase
{
friend ::rclcpp::node_interfaces::NodeTopicsInterface;
@@ -81,50 +80,47 @@ public:
/// Get the topic that this publisher publishes on.
/** \return The topic name. */
RCLCPP_PUBLIC
const char *
get_topic_name() const;
const char * get_topic_name() const;
/// Get the queue size for this publisher.
/** \return The queue size. */
RCLCPP_PUBLIC
size_t
get_queue_size() const;
size_t get_queue_size() const;
/// Get the global identifier for this publisher (used in rmw and by DDS).
/** \return The gid. */
RCLCPP_PUBLIC
const rmw_gid_t &
get_gid() const;
const rmw_gid_t & get_gid() const;
/// Get the global identifier for this publisher used by intra-process communication.
/** \return The intra-process gid. */
RCLCPP_PUBLIC
const rmw_gid_t & get_intra_process_gid() const;
/// Get the rcl publisher handle.
/** \return The rcl publisher handle. */
RCLCPP_PUBLIC
rcl_publisher_t *
get_publisher_handle();
rcl_publisher_t * get_publisher_handle();
/// Get the rcl publisher handle.
/** \return The rcl publisher handle. */
RCLCPP_PUBLIC
const rcl_publisher_t *
get_publisher_handle() const;
const rcl_publisher_t * get_publisher_handle() const;
/// Get all the QoS event handlers associated with this publisher.
/** \return The vector of QoS event handlers. */
RCLCPP_PUBLIC
const std::vector<std::shared_ptr<rclcpp::QOSEventHandlerBase>> &
get_event_handlers() const;
const std::vector<std::shared_ptr<rclcpp::QOSEventHandlerBase>> & get_event_handlers() const;
/// Get subscription count
/** \return The number of subscriptions. */
RCLCPP_PUBLIC
size_t
get_subscription_count() const;
size_t get_subscription_count() const;
/// Get intraprocess subscription count
/** \return The number of intraprocess subscriptions. */
RCLCPP_PUBLIC
size_t
get_intra_process_subscription_count() const;
size_t get_intra_process_subscription_count() const;
/// Manually assert that this Publisher is alive (for RMW_QOS_POLICY_LIVELINESS_MANUAL_BY_TOPIC).
/**
@@ -136,8 +132,7 @@ public:
*/
RCLCPP_PUBLIC
RCUTILS_WARN_UNUSED
bool
assert_liveliness() const;
bool assert_liveliness() const;
/// Get the actual QoS settings, after the defaults have been determined.
/**
@@ -147,21 +142,10 @@ public:
* If the underlying setting in use can't be represented in ROS terms,
* it will be set to RMW_QOS_POLICY_*_UNKNOWN.
* May throw runtime_error when an unexpected error occurs.
*
* \return The actual qos settings.
*/
RCLCPP_PUBLIC
rclcpp::QoS
get_actual_qos() const;
/// Check if publisher instance can loan messages.
/**
* Depending on the middleware and the message type, this will return true if the middleware
* can allocate a ROS message instance.
*/
RCLCPP_PUBLIC
bool
can_loan_messages() const;
rmw_qos_profile_t get_actual_qos() const;
/// Compare this publisher to a gid.
/**
@@ -170,8 +154,7 @@ public:
* \return True if the publisher's gid matches the input.
*/
RCLCPP_PUBLIC
bool
operator==(const rmw_gid_t & gid) const;
bool operator==(const rmw_gid_t & gid) const;
/// Compare this publisher to a pointer gid.
/**
@@ -180,50 +163,48 @@ public:
* \return True if this publisher's gid matches the input.
*/
RCLCPP_PUBLIC
bool
operator==(const rmw_gid_t * gid) const;
bool operator==(const rmw_gid_t * gid) const;
using IntraProcessManagerSharedPtr =
std::shared_ptr<rclcpp::experimental::IntraProcessManager>;
std::shared_ptr<rclcpp::intra_process_manager::IntraProcessManager>;
/// Implementation utility function that creates a typed mapped ring buffer.
RCLCPP_PUBLIC
mapped_ring_buffer::MappedRingBufferBase::SharedPtr virtual make_mapped_ring_buffer(
size_t size) const;
/// Implementation utility function used to setup intra process publishing after creation.
RCLCPP_PUBLIC
void
setup_intra_process(
void setup_intra_process(
uint64_t intra_process_publisher_id,
IntraProcessManagerSharedPtr ipm);
IntraProcessManagerSharedPtr ipm,
const rcl_publisher_options_t & intra_process_options);
protected:
template<typename EventCallbackT>
void
add_event_handler(
const EventCallbackT & callback,
const rcl_publisher_event_type_t event_type)
template <typename EventCallbackT>
void add_event_handler(
const EventCallbackT & callback, const rcl_publisher_event_type_t event_type)
{
auto handler = std::make_shared<QOSEventHandler<EventCallbackT>>(
callback,
rcl_publisher_event_init,
&publisher_handle_,
event_type);
callback, rcl_publisher_event_init, &publisher_handle_, event_type);
event_handlers_.emplace_back(handler);
}
RCLCPP_PUBLIC
void default_incompatible_qos_callback(QOSOfferedIncompatibleQoSInfo & info) const;
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();
std::vector<std::shared_ptr<rclcpp::QOSEventHandlerBase>> event_handlers_;
using IntraProcessManagerWeakPtr =
std::weak_ptr<rclcpp::experimental::IntraProcessManager>;
std::weak_ptr<rclcpp::intra_process_manager::IntraProcessManager>;
bool intra_process_is_enabled_;
IntraProcessManagerWeakPtr weak_ipm_;
uint64_t intra_process_publisher_id_;
rmw_gid_t rmw_gid_;
rmw_gid_t intra_process_rmw_gid_;
};
} // namespace rclcpp

Some files were not shown because too many files have changed in this diff Show More